]> git.lyx.org Git - lyx.git/blobdiff - src/spellchecker.C
more keyboard/keysym changes
[lyx.git] / src / spellchecker.C
index f97e8e4c942d239e2fdd6f2dd2c5ce08a3949a82..04a578affd791a636bf98aca837ba5c9bff223dd 100644 (file)
 
 #include <config.h>
 
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
 #include <unistd.h>
 #include <fcntl.h>
 #include <cstdlib>
 #endif
 
 #ifdef HAVE_SYS_SELECT_H
+# ifdef HAVE_STRINGS_H
+   // <strings.h> is needed at least on AIX because FD_ZERO uses bzero().
+# include <strings.h> 
+# endif
 #include <sys/select.h>
 #endif
 
+#include <algorithm>
+
 #include "LString.h"
 #include "sp_form.h"
 #include "spellchecker.h"
 #include "lyx_gui_misc.h"
 #include "debug.h"
 #include "support/lstrings.h"
+#include "encoding.h"
 
-extern LyXRC *lyxrc;
-extern BufferView *current_view;
+using std::reverse;
+using std::endl;
 
 // Spellchecker status
 enum {
@@ -62,9 +73,9 @@ enum {
        ISP_IGNORE
 };
 
-static bool RunSpellChecker(string const &);
+static bool RunSpellChecker(BufferView * bv);
 
-static FILE *in, *out;  /* streams to communicate with ispell */
+static FILE * in, * out;  /* streams to communicate with ispell */
 pid_t isp_pid = -1; // pid for the `ispell' process. Also used (RO) in
                     // lyx_cb.C
 
@@ -87,14 +98,14 @@ struct isp_result {
        int flag;
        int count;
        string str;
-       char **misses;
+       char ** misses;
        isp_result() {
                flag = ISP_UNKNOWN;
                count = 0;
-               misses = (char**)0;
+               misses = static_cast<char**>(0);
        }
        ~isp_result() {
-               if (misses) delete[] misses;
+               delete[] misses;
        }
 };
 
@@ -108,13 +119,13 @@ struct isp_result {
 void SpellOptionsUpdate() 
 {
        // Alternate language
-       if (lyxrc->isp_alt_lang.empty()) {
-               lyxrc->isp_use_alt_lang = false;
+       if (lyxrc.isp_alt_lang.empty()) {
+               lyxrc.isp_use_alt_lang = false;
        } else {
                fl_set_input(fd_form_spell_options->altlang_input,
-                            lyxrc->isp_alt_lang.c_str());
+                            lyxrc.isp_alt_lang.c_str());
        }
-       if (lyxrc->isp_use_alt_lang) {
+       if (lyxrc.isp_use_alt_lang) {
                fl_set_button(fd_form_spell_options->buflang, 0);
                fl_set_button(fd_form_spell_options->altlang, 1);
        } else {
@@ -123,53 +134,53 @@ void SpellOptionsUpdate()
        }  
 
        // Personal dictionary
-       if (lyxrc->isp_pers_dict.empty()) {
-               lyxrc->isp_use_pers_dict = false;
+       if (lyxrc.isp_pers_dict.empty()) {
+               lyxrc.isp_use_pers_dict = false;
        } else {
                fl_set_input(fd_form_spell_options->perdict_input,
-                            lyxrc->isp_pers_dict.c_str());
+                            lyxrc.isp_pers_dict.c_str());
        }
        fl_set_button(fd_form_spell_options->perdict,
-                     lyxrc->isp_use_pers_dict ? 1:0);
+                     lyxrc.isp_use_pers_dict ? 1:0);
 
        // Escape chars
-       if (lyxrc->isp_esc_chars.empty()) {
-               lyxrc->isp_use_esc_chars = false;
+       if (lyxrc.isp_esc_chars.empty()) {
+               lyxrc.isp_use_esc_chars = false;
        } else {
                fl_set_input(fd_form_spell_options->esc_chars_input,
-                            lyxrc->isp_esc_chars.c_str());
+                            lyxrc.isp_esc_chars.c_str());
        }
        fl_set_button(fd_form_spell_options->esc_chars,
-                     lyxrc->isp_use_esc_chars ? 1:0);
+                     lyxrc.isp_use_esc_chars ? 1:0);
 
        // Options
        fl_set_button(fd_form_spell_options->compounds,
-                     lyxrc->isp_accept_compound ? 1 : 0);
+                     lyxrc.isp_accept_compound ? 1 : 0);
        fl_set_button(fd_form_spell_options->inpenc,
-                     lyxrc->isp_use_input_encoding ? 1 : 0);
+                     lyxrc.isp_use_input_encoding ? 1 : 0);
 }
 
 // Update spellchecker options
 void SpellOptionsApplyCB(FL_OBJECT *, long)
 {
        // Build new status from form data
-       lyxrc->isp_use_alt_lang = 
+       lyxrc.isp_use_alt_lang = 
                fl_get_button(fd_form_spell_options->altlang);
-       lyxrc->isp_use_pers_dict = 
+       lyxrc.isp_use_pers_dict = 
                fl_get_button(fd_form_spell_options->perdict);
-       lyxrc->isp_accept_compound = 
+       lyxrc.isp_accept_compound = 
                fl_get_button(fd_form_spell_options->compounds);
-       lyxrc->isp_use_esc_chars = 
+       lyxrc.isp_use_esc_chars = 
                fl_get_button(fd_form_spell_options->esc_chars);
-       lyxrc->isp_use_input_encoding = 
+       lyxrc.isp_use_input_encoding = 
                fl_get_button(fd_form_spell_options->inpenc);
 
        // Update strings with data from input fields
-       lyxrc->isp_alt_lang = 
+       lyxrc.isp_alt_lang = 
                fl_get_input(fd_form_spell_options->altlang_input);
-       lyxrc->isp_pers_dict = 
+       lyxrc.isp_pers_dict = 
                fl_get_input(fd_form_spell_options->perdict_input);
-       lyxrc->isp_esc_chars = 
+       lyxrc.isp_esc_chars = 
                fl_get_input(fd_form_spell_options->esc_chars_input);
 
        // Update form
@@ -224,7 +235,7 @@ void SpellCheckerOptions()
 // Could also use a clean up. (Asger Alstrup)
 
 static
-void create_ispell_pipe(string const & lang)
+void create_ispell_pipe(BufferParams const & params, string const & lang)
 {
        static char o_buf[BUFSIZ];  // jc: it could be smaller
        int pipein[2], pipeout[2];
@@ -272,9 +283,9 @@ void create_ispell_pipe(string const & lang)
                close(pipeout[1]);
 
                argc = 0;
-               char * tmp = new char[lyxrc->isp_command.length() + 1];
-               lyxrc->isp_command.copy(tmp, lyxrc->isp_command.length());
-               tmp[lyxrc->isp_command.length()] = '\0';
+               char * tmp = new char[lyxrc.isp_command.length() + 1];
+               lyxrc.isp_command.copy(tmp, lyxrc.isp_command.length());
+               tmp[lyxrc.isp_command.length()] = '\0';
                argv[argc++] = tmp;
                tmp = new char[3];
                string("-a").copy(tmp, 2); tmp[2] = '\0'; // pipe mode
@@ -289,7 +300,7 @@ void create_ispell_pipe(string const & lang)
                        argv[argc++] = tmp;
                }
 
-               if (lyxrc->isp_accept_compound) {
+               if (lyxrc.isp_accept_compound) {
                        // Consider run-together words as legal compounds
                        tmp = new char[3];
                        string("-C").copy(tmp, 2); tmp[2] = '\0';
@@ -301,47 +312,51 @@ void create_ispell_pipe(string const & lang)
                        string("-B").copy(tmp, 2); tmp[2] = '\0';
                        argv[argc++] = tmp; 
                }
-               if (lyxrc->isp_use_esc_chars) {
+               if (lyxrc.isp_use_esc_chars) {
                        // Specify additional characters that
                        // can be part of a word
                        tmp = new char[3];
                        string("-w").copy(tmp, 2); tmp[2] = '\0';
                        argv[argc++] = tmp; 
                        // Put the escape chars in ""s
-                       string tms = "\"" + lyxrc->isp_esc_chars + "\"";
+                       string tms = "\"" + lyxrc.isp_esc_chars + "\"";
                        tmp = new char[tms.length() + 1];
                        tms.copy(tmp, tms.length()); tmp[tms.length()] = '\0';
                        argv[argc++] = tmp;
                }
-               if (lyxrc->isp_use_pers_dict) {
+               if (lyxrc.isp_use_pers_dict) {
                        // Specify an alternate personal dictionary
                        tmp = new char[3];
                        string("-p").copy(tmp, 2);
                        tmp[2]= '\0';
                        argv[argc++] = tmp;
-                       tmp = new char[lyxrc->isp_pers_dict.length() + 1];
-                       lyxrc->isp_pers_dict.copy(tmp, lyxrc->isp_pers_dict.length());
-                       tmp[lyxrc->isp_pers_dict.length()] = '\0';
+                       tmp = new char[lyxrc.isp_pers_dict.length() + 1];
+                       lyxrc.isp_pers_dict.copy(tmp, lyxrc.isp_pers_dict.length());
+                       tmp[lyxrc.isp_pers_dict.length()] = '\0';
                        argv[argc++] = tmp;
                }
-               if (lyxrc->isp_use_input_encoding &&
-                   current_view->buffer()->params.inputenc != "default") {
+               if (lyxrc.isp_use_input_encoding &&
+                   params.inputenc != "default") {
+                       string enc = (params.inputenc == "auto")
+                               ? params.language_info->encoding()->LatexName()
+                               : params.inputenc;
+                       string::size_type n = enc.length();
                        tmp = new char[3];
                        string("-T").copy(tmp, 2); tmp[2] = '\0';
                        argv[argc++] = tmp; // Input encoding
-                       tmp = new char[current_view->buffer()->params.inputenc.length() + 1];
-                       current_view->buffer()->params.inputenc.copy(tmp, current_view->buffer()->params.inputenc.length());
-                       tmp[current_view->buffer()->params.inputenc.length()] = '\0';
+                       tmp = new char[n + 1];
+                       enc.copy(tmp, n);
+                       tmp[n] = '\0';
                        argv[argc++] = tmp;
                }
 
                argv[argc++] = 0;
 
-               execvp("ispell", (char * const *) argv);
+               execvp(argv[0], const_cast<char * const *>(argv));
 
                // free the memory used by string::copy in the
                // setup of argv
-               for (int i= 0; i < argc -1; i++)
+               for (int i= 0; i < argc -1; ++i)
                        delete[] argv[i];
                
                lyxerr << "LyX: Failed to start ispell!" << endl;
@@ -412,7 +427,7 @@ isp_result *ispell_check_word(char *word)
   
        /* I think we have to check if ispell is still alive here because
           the signal-handler could have disabled blocking on the fd */
-       if (isp_pid == -1) return (isp_result *) 0;
+       if (isp_pid == -1) return 0;
 
        result = new isp_result;
   
@@ -437,6 +452,9 @@ isp_result *ispell_check_word(char *word)
        {
                result->flag = ISP_MISSED;
                result->str = buf;
+               // nb is leaked! where should it be freed? I have to
+               // admit I do not understand the intent of the code :(
+               // (JMarc) 
                char * nb = new char[result->str.length() + 1];
                result->str.copy(nb, result->str.length());
                nb[result->str.length()]= '\0';
@@ -446,11 +464,11 @@ isp_result *ispell_check_word(char *word)
                if (count) result->misses = new char*[count];
                p = strpbrk(nb, ":");
                p += 2;
-               for (i = 0; i<count; i++) {
+               for (i = 0; i < count; ++i) {
                        result->misses[i] = p;
                        p = strpbrk(p, ",\n");
                        *p = 0;
-                       p+= 2;
+                       p += 2;
                }
                break;
        }
@@ -466,8 +484,8 @@ isp_result *ispell_check_word(char *word)
 }
 
 
-static
-inline void ispell_terminate()
+static inline
+void ispell_terminate()
 {
         // Note: If you decide to optimize this out when it is not 
         // needed please note that when Aspell is used this command 
@@ -481,15 +499,15 @@ inline void ispell_terminate()
 }
 
 
-static
-inline void ispell_terse_mode()
+static inline
+void ispell_terse_mode()
 {
        fputs("!\n", out); // Set terse mode (silently accept correct words)
 }
 
 
-static
-inline void ispell_insert_word(char const *word)
+static inline
+void ispell_insert_word(char const *word)
 {
        fputc('*', out); // Insert word in personal dictionary
        fputs(word, out);
@@ -497,16 +515,16 @@ inline void ispell_insert_word(char const *word)
 }
 
 
-static
-inline void ispell_accept_word(char const *word) 
+static inline
+void ispell_accept_word(char const *word) 
 {
        fputc('@', out); // Accept in this session
        fputs(word, out);
        fputc('\n', out);
 }
 
-static
-inline void ispell_store_replacement(char const *mis, string const & cor) {
+static inline
+void ispell_store_replacement(char const *mis, string const & cor) {
         if(actual_spell_checker == ASC_ASPELL) {
                 fputs("$$ra ", out);
                 fputs(mis, out);
@@ -517,19 +535,20 @@ inline void ispell_store_replacement(char const *mis, string const & cor) {
 }
 
 
-void ShowSpellChecker()
+void ShowSpellChecker(BufferView * bv)
 {
-       FL_OBJECT *obj;
+       FL_OBJECT * obj;
        int ret;
 
        // Exit if we don't have a document open
-       if (!current_view->getScreen())
+       if (!bv->available())
                return;
 
        if (fd_form_spell_check == 0) {
                fd_form_spell_check = create_form_form_spell_check();
                // Make sure pressing the close box does not kill LyX. (RvdK)
-               fl_set_form_atclose(fd_form_spell_check->form_spell_check, IgnoreCloseBoxCB, 0);
+               fl_set_form_atclose(fd_form_spell_check->form_spell_check, 
+                                   CancelCloseBoxCB, 0);
        }
 
        // Clear form
@@ -585,7 +604,7 @@ void ShowSpellChecker()
                        fl_set_object_lcol(fd_form_spell_check->input, FL_BLACK);
                        fl_set_object_lcol(fd_form_spell_check->browser, FL_BLACK);
                        // activate replace only if the file is not read-only
-                       if (!current_view->buffer()->isReadonly()) { 
+                       if (!bv->buffer()->isReadonly()) { 
                          fl_activate_object(fd_form_spell_check->replace);
                          fl_set_object_lcol(fd_form_spell_check->replace, FL_BLACK);
                        }
@@ -596,7 +615,7 @@ void ShowSpellChecker()
                        fl_set_object_lcol(fd_form_spell_check->options, FL_INACTIVE);
                        fl_set_object_lcol(fd_form_spell_check->start, FL_INACTIVE);
 
-                       ret = RunSpellChecker(current_view->buffer()->GetLanguage());
+                       ret = RunSpellChecker(bv);
 
                        // deactivate insert, accept, replace, and stop
                        fl_deactivate_object(fd_form_spell_check->insert);
@@ -626,29 +645,27 @@ void ShowSpellChecker()
                if (obj == fd_form_spell_check->done) break;
        }
        fl_hide_form(fd_form_spell_check->form_spell_check);
-       EndOfSpellCheck();
+       bv->endOfSpellCheck();
        return;
 }
 
 
 // Perform an ispell session
 static
-bool RunSpellChecker(string const & lang)
+bool RunSpellChecker(BufferView * bv)
 {
-       isp_result *result;
-       char *word;
-       int i, oldval, clickline, newvalue;
-       float newval;
-       FL_OBJECT *obj;
-       unsigned int word_count = 0;
+       isp_result * result;
+       int i, newvalue;
+       FL_OBJECT * obj;
 
-       string tmp = (lyxrc->isp_use_alt_lang) ? lyxrc->isp_alt_lang:lang;
+       string tmp = (lyxrc.isp_use_alt_lang) ? lyxrc.isp_alt_lang : bv->buffer()->GetLanguage();
+       bool rtl = tmp == "hebrew" || tmp == "arabic";
 
-       oldval = 0;  /* used for updating slider only when needed */
-       newval = 0.0;
+       int oldval = 0;  /* used for updating slider only when needed */
+       float newval = 0.0;
    
        /* create ispell process */
-       create_ispell_pipe(tmp);
+       create_ispell_pipe(bv->buffer()->params, tmp);
 
        if (isp_pid == -1) {
                fl_show_message(
@@ -659,56 +676,69 @@ bool RunSpellChecker(string const & lang)
                          "Check /usr/lib/ispell or set another\n"
                          "dictionary in the Spellchecker Options menu."), "", "");
                fclose(out);
-               return true;
+               return false;
        }
 
        // Put ispell in terse mode to improve speed
        ispell_terse_mode();
 
+       unsigned int word_count = 0;
        while (true) {
-               word = NextWord(newval);
+               char * word = bv->nextWord(newval);
                if (word == 0) break;
-               word_count++;
+               ++word_count;
                
                // Update slider if and only if value has changed
                newvalue = int(100.0*newval);
                if(newvalue!= oldval) {
                        oldval = newvalue;
                        fl_set_slider_value(fd_form_spell_check->slider, oldval);
+               }
+
+               if (word_count%1000 == 0) {
+                       obj =  fl_check_forms();
+                       if (obj == fd_form_spell_check->stop) {
+                               delete[] word;
+                               ispell_terminate();
+                               return true;
+                       }
+                       if (obj == fd_form_spell_check->done) {
+                               delete[] word;
+                               ispell_terminate(); 
+                               return false;
+                       }
                }
 
                result = ispell_check_word(word);
                if (isp_pid == -1) {
+                       delete result;
                        delete[] word;
                        break;
                }
 
-               obj =  fl_check_forms();
-               if (obj == fd_form_spell_check->stop) {
-                       delete result;
-                       delete[] word;
-                       ispell_terminate();
-                       return true;
-               }
-               if (obj == fd_form_spell_check->done) {
-                       delete result;
-                       delete[] word;
-                       ispell_terminate(); 
-                       return false;
-               }
-    
                switch (result->flag) {
                case ISP_UNKNOWN:
                case ISP_MISSED:
-                       SelectLastWord();
-                       fl_set_object_label(fd_form_spell_check->text, word);
+               {
+                       bv->selectLastWord();
+                       if (rtl) {
+                               string tmp = word;
+                               reverse(tmp.begin(),tmp.end());
+                               fl_set_object_label(fd_form_spell_check->text, tmp.c_str());
+                       } else
+                               fl_set_object_label(fd_form_spell_check->text, word);
                        fl_set_input(fd_form_spell_check->input, word);
                        fl_clear_browser(fd_form_spell_check->browser);
-                       for (i= 0; i<result->count; i++) {
-                               fl_add_browser_line(fd_form_spell_check->browser, result->misses[i]);
+                       for (i = 0; i < result->count; ++i) {
+                               if (rtl) {
+                                       string tmp = result->misses[i];
+                                       reverse(tmp.begin(),tmp.end());
+                                       fl_add_browser_line(fd_form_spell_check->browser, tmp.c_str());
+                               } else
+                                       fl_add_browser_line(fd_form_spell_check->browser, result->misses[i]);
                        }
 
-                       clickline = -1;
+                       int clickline = -1;
                        while (true) {
                                obj = fl_do_forms();
                                if (obj == fd_form_spell_check->insert) {
@@ -725,7 +755,7 @@ bool RunSpellChecker(string const & lang)
                                if (obj == fd_form_spell_check->replace || 
                                    obj == fd_form_spell_check->input) {
                                        ispell_store_replacement(word, fl_get_input(fd_form_spell_check->input));
-                                       ReplaceWord(fl_get_input(fd_form_spell_check->input));
+                                       bv->replaceWord(fl_get_input(fd_form_spell_check->input));
                                        break;
                                }
                                if (obj == fd_form_spell_check->browser) {
@@ -734,14 +764,21 @@ bool RunSpellChecker(string const & lang)
                                        if (clickline == 
                                            fl_get_browser(fd_form_spell_check->browser)) {
                                                ispell_store_replacement(word, fl_get_input(fd_form_spell_check->input));
-                                               ReplaceWord(fl_get_input(fd_form_spell_check->input));
+                                               bv->replaceWord(fl_get_input(fd_form_spell_check->input));
                                                break;
                                        }
                                        clickline = fl_get_browser(fd_form_spell_check->browser);
-                                       fl_set_input(fd_form_spell_check->input, 
-                                                    fl_get_browser_line(fd_form_spell_check->browser,
-                                                                        fl_get_browser(fd_form_spell_check->browser)));
-                                                    
+                                       /// Why not use
+                                       /// fl_set_input(fd_form_spell_check->input, result->misses[clickline-1]); ?
+                                       if (rtl) {
+                                               string tmp = fl_get_browser_line(fd_form_spell_check->browser,
+                                                                                clickline);
+                                               reverse(tmp.begin(),tmp.end());
+                                               fl_set_input(fd_form_spell_check->input, tmp.c_str());
+                                       } else
+                                               fl_set_input(fd_form_spell_check->input,
+                                                            fl_get_browser_line(fd_form_spell_check->browser,
+                                                                                clickline));
                                }
                                if (obj == fd_form_spell_check->stop) {
                                        delete result;
@@ -757,6 +794,7 @@ bool RunSpellChecker(string const & lang)
                                        return false;
                                }
                        }
+               }
                default:
                        delete result;
                        delete[] word;
@@ -765,8 +803,7 @@ bool RunSpellChecker(string const & lang)
    
        if(isp_pid!= -1) {
                ispell_terminate();
-               string word_msg;
-               word_msg += tostr(word_count);
+               string word_msg(tostr(word_count));
                if (word_count != 1) {
                        word_msg += _(" words checked.");
                } else {
@@ -784,19 +821,14 @@ bool RunSpellChecker(string const & lang)
 }
 
 
-//void sigchldhandler(int sig)
-void sigchldhandler(pid_t pid, int *status)
+void sigchldhandler(pid_t pid, int * status)
 { 
-       //int status ;
-
-       if (isp_pid>0)
-               //if (waitpid(isp_pid, &status, WNOHANG) == isp_pid) {
+       if (isp_pid > 0)
                if (pid == isp_pid) {
                        isp_pid= -1;
                        fcntl(isp_fd, F_SETFL, O_NONBLOCK); /* set the file descriptor
                                                               to nonblocking so we can 
                                                               continue */
                }
-       //sigchldchecker(sig);
        sigchldchecker(pid, status);
 }