The 'seek_misspelled' action has been assigned to ctrl-f7.
[mp-5.x.git] / mp_spell.mpsl
blob06f3c6bd0dc4ef519a2289ad4934a95a7ea06849
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['ctrl-f7']  = '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('/^@\(#\) International Ispell/', l)) {
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, lc(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         /* write the word */
114         write(mp.ispell_pipe, w ~ "\n");
116         /* wait for the response */
117         if ((l = read(mp.ispell_pipe)) == NULL) {
118                 mp.close_ispell_pipe();
119                 return -2;
120         }
122         local t = l;
124         /* drop all lines until an empty one */
125         while (t ne "\n")
126                 t = read(mp.ispell_pipe);
128         /* take first char of the response */
129         l = regex('/^./', l);
131         /* if it's not a '*' nor a '+', it's misspelled */
132         if (l ne '*' && l ne '+')
133                 ret = 1;
135         mp.spelling_cache[lc(w)] = ret;
137         return ret;
141 sub mp.ispell_word_color_func(w)
142 /* mp.word_color_func() for ispell */
144         local l, a;
146         a = -1;
148         /* attributes must exist before entering here */
149         if (mp.colors.spell.attr != NULL) {
150                 ret = mp.is_word_misspelled(w);
152                 /* error? disable further misspelling color */
153                 if (ret < 0)
154                         mp.word_color_func = NULL;
155                 else
156                 if (ret > 0)
157                         a = mp.colors.spell.attr;
158         }
160         return a;
165  * mp.ispell - Changes spelling highlight.
166  * @b: boolean value
168  * Changes the status of the highlighting of misspelled words.
169  * If @b is 0, it's disabled (default value); if it's 1,
170  * misspelled words will be highlighted using a special
171  * attribute color. If @b is -1, the status is toggled.
172  */
173 sub mp.ispell(b)
175         if (b == -1)
176                 b = mp.word_color_func == NULL && 1 || 0;
178         mp.word_color_func = b && mp.ispell_word_color_func || NULL;
183  * mp.search_misspelled - Searches for the next misspelled word.
184  * @doc: the document to search
186  * Searches the document for the next misspelled word. If no
187  * more misspelled words can be found, returns 0 and does nothing;
188  * otherwise, the cursor is moved just after that word and
189  * returns 1.
190  */
191 sub mp.search_misspelled(doc)
193         local txt = doc.txt;
194         local x = txt.x;
195         local y = txt.y;
197         while (y < size(txt.lines)) {
198                 local l = txt.lines[y];
199                 local w;
201                 while ((w = regex(mp.word_regex, l, x)) != NULL) {
202                         local n = regex();
203                         local r = mp.is_word_misspelled(w);
205                         /* error? fail immediately */
206                         if (r < 0)
207                                 return 0;
209                         x = n[0] + n[1];
211                         if (r == 1) {
212                                 /* store word for later */
213                                 mp.last_misspelled_word = lc(w);
215                                 mp.set_y(doc, y);
216                                 mp.set_x(doc, x);
217                                 return 1;
218                         }
219                 }
221                 x = 0;
222                 y++;
223         }
225         return 0;
230  * mp.ignore_last_misspell - Ignores last misspelled word.
232  * Ignores the last misspelled word found by mp.search_misspelled()
233  * by adding it to a whitelist, so it won't be found again.
234  */
235 sub mp.ignore_last_misspell()
237         if (mp.last_misspelled_word)
238                 mp.spelling_cache[mp.last_misspelled_word] = 0;