Do not use backslash-b to select backspaces.
[mp-5.x.git] / mp_spell.mpsl
blob8fab09025d26a8626137b05f64dbde3c24e496e0
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Spellchecking code.
8     Copyright (C) 1991-2009 Angel Ortega <angel@triptico.com>
10     This program is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License
12     as published by the Free Software Foundation; either version 2
13     of the License, or (at your option) any later version.
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24     http://www.triptico.com
28 /** editor actions **/
30 mp.actions['toggle_spellcheck'] = sub(d) { mp.ispell(-1); };
31 mp.actions['seek_misspelled']   = sub(d) { mp.long_op(mp.search_misspelled, d) ||
32                 mp.alert(L("Text not found."));
34 mp.actions['ignore_last_misspell'] = sub(d) { mp.ignore_last_misspell(); };
36 /** default key bindings **/
38 mp.keycodes['f5']       = 'seek_misspelled';
40 /** action descriptions **/
42 mp.actdesc['toggle_spellcheck']         = LL("Toggle spellchecking");
43 mp.actdesc['seek_misspelled']           = LL("Search misspelled word");
44 mp.actdesc['ignore_last_misspell']      = LL("Ignore last misspelled word");
46 /** data **/
48 /* spellchecking command */
49 mp.config.ispell_cmd = "ispell -a";
51 /* the spelling cache */
52 mp.spelling_cache = {};
54 /** code **/
56 sub mp.open_ispell_pipe
57 /* opens the pipe to ispell */
59         local p, l;
61         /* open the pipe */
62         if ((p = popen(mp.config.ispell_cmd, "r+")) == NULL)
63                 return NULL;
65         /* read the first line */
66         l = read(p);
68         /* check for the signature */
69         if (! regex(l, '/^@\(#\) International Ispell/')) {
70                 pclose(p);
71                 return NULL;
72         }
74         /* store the pipe */
75         mp.ispell_pipe = p;
79 sub mp.close_ispell_pipe
80 /* closes the pipe to ispell */
82         if (mp.ispell_pipe == NULL)
83                 return;
85         /* close and delete */
86         pclose(mp.ispell_pipe);
87         mp.ispell_pipe = NULL;
91 /**
92  * mp.is_word_misspelled - Tests if a word is misspelled.
93  * @w: the word
94  *
95  * Tests if a word is misspelled. Returns a negative value if
96  * there was an error when querying the external spelling program,
97  * 1 if the word is misspelled, or 0 if not.
98  */
99 sub mp.is_word_misspelled(w)
101         local l;
102         local ret = 0;
104         if (exists(mp.spelling_cache, w))
105                 return mp.spelling_cache[w];
107         if (mp.ispell_pipe == NULL) {
108                 if (mp.open_ispell_pipe() == NULL) {
109                         return -1;
110                 }
111         }
113         /* NULL is never misspelled */
114         if (w == NULL)
115                 return 0;
117         /* write the word */
118         write(mp.ispell_pipe, w ~ "\n");
120         /* wait for the response */
121         if ((l = read(mp.ispell_pipe)) == NULL) {
122                 mp.close_ispell_pipe();
123                 return -2;
124         }
126         local t = l;
128         /* drop all lines until an empty one */
129         while (t ne "\n")
130                 t = read(mp.ispell_pipe);
132         /* take first char of the response */
133         l = regex(l, '/^./');
135         /* if it's not a '*' nor a '+', it's misspelled */
136         if (l ne '*' && l ne '+')
137                 ret = 1;
139         mp.spelling_cache[w] = ret;
141         return ret;
145 sub mp.ispell_word_color_func(w)
146 /* mp.word_color_func() for ispell */
148         local l, a;
150         a = -1;
152         /* attributes must exist before entering here */
153         if (mp.colors.spell.attr != NULL) {
154                 ret = mp.is_word_misspelled(w);
156                 /* error? disable further misspelling color */
157                 if (ret < 0)
158                         mp.word_color_func = NULL;
159                 else
160                 if (ret > 0)
161                         a = mp.colors.spell.attr;
162         }
164         return a;
169  * mp.ispell - Changes spelling highlight.
170  * @b: boolean value
172  * Changes the status of the highlighting of misspelled words.
173  * If @b is 0, it's disabled (default value); if it's 1,
174  * misspelled words will be highlighted using a special
175  * attribute color. If @b is -1, the status is toggled.
176  */
177 sub mp.ispell(b)
179         if (b == -1)
180                 b = mp.word_color_func == NULL && 1 || 0;
182         if (b && mp.is_word_misspelled() != -1)
183                 mp.word_color_func = mp.ispell_word_color_func;
184         else
185                 mp.word_color_func = NULL;
190  * mp.search_misspelled - Searches for the next misspelled word.
191  * @doc: the document to search
193  * Searches the document for the next misspelled word. If no
194  * more misspelled words can be found, returns 0 and does nothing;
195  * otherwise, the cursor is moved just after that word and
196  * returns 1.
197  */
198 sub mp.search_misspelled(doc)
200         local txt = doc.txt;
201         local x = txt.x;
202         local y = txt.y;
204         while (y < size(txt.lines)) {
205                 local l = txt.lines[y];
206                 local w;
208                 while ((w = regex(l, mp.word_regex, x)) != NULL) {
209                         local n = regex();
210                         local r = mp.is_word_misspelled(w);
212                         /* error? fail immediately */
213                         if (r < 0)
214                                 return 0;
216                         x = n[0] + n[1];
218                         if (r == 1) {
219                                 /* store word for later */
220                                 mp.last_misspelled_word = w;
222                                 mp.set_y(doc, y);
223                                 mp.set_x(doc, x);
224                                 return 1;
225                         }
226                 }
228                 x = 0;
229                 y++;
230         }
232         return 0;
237  * mp.ignore_last_misspell - Ignores last misspelled word.
239  * Ignores the last misspelled word found by mp.search_misspelled()
240  * by adding it to a whitelist, so it won't be found again.
241  */
242 sub mp.ignore_last_misspell()
244         if (mp.last_misspelled_word)
245                 mp.spelling_cache[mp.last_misspelled_word] = 0;