More work in mp_vcs.mpsl.
[mp-5.x.git] / mp_writing.mpsl
blob3a04be5299dc36b84834d244d3b1a1a6aa865c60
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Tools for writing.
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['word_count'] = sub (d) {
32         mp.busy(1);
33         local c = mp.word_count(d);
34         mp.busy(0);
36         mp.alert(sprintf(L("Lines: %d Words: %d"),
37                 size(mp.get_active_area(d)), c));
41 mp.actions['repeated_words_options'] = sub (d) {
42         local r = mp.form( [
43                 { 'label'       => L("Number of letters at the start or end:"),
44                   'type'        => 'text',
45                   'value'       => mp.config.rw_num_chars,
46                   'history'     => 'num_char' },
47                 { 'label'       => L("Maximum distance between words:"),
48                   'type'        => 'text',
49                   'value'       => mp.config.rw_max_dist,
50                   'history'     => 'max_dist' }
51                 ]);
53         if (r != NULL) {
54                 mp.config.rw_num_chars = r[0];
55                 mp.config.rw_max_dist = r[1];
56         }
60 mp.actions['seek_repeated_word'] = sub (d) {
62         mp.busy(1);
63         local c = mp.repeated_words(d, mp.config.rw_num_chars, mp.config.rw_max_dist);
64         mp.busy(0);
66         if (!c)
67                 mp.alert(L("Text not found."));
70 /** default key bindings **/
72 mp.keycodes['f6']               = 'seek_repeated_word';
74 /** action descriptions **/
76 mp.actdesc['word_count']                = LL("Count words");
77 mp.actdesc['repeated_words_options']    = LL("Repeated words options...");
78 mp.actdesc['seek_repeated_word']        = LL("Search repeated word");
80 /** data **/
82 mp.config.rw_num_chars  = 4;
83 mp.config.rw_max_dist   = 40;
85 /** code **/
87 sub mp.word_count(doc)
88 /* counts the number of words in doc */
90         local w = 0;
92         foreach (l, mp.get_active_area(doc))
93                 w += size(mp.split_by_words(l, "/[^ \t]+/"));
95         return w;
99 /**
100  * mp.repeated_words - Finds words starting or ending the same in a range.
101  * @doc: the document
102  * @num_chars: minimum length for the word to be tested
103  * @max_dist: maximum distance the word must have
105  * Finds words starting or ending the same to a maximum of @num_chars
106  * and that are less than @max_dist words apart. If a pair of these words
107  * is found, 1 is returned, the cursor positioned over the first one
108  * and both highlighted as spelling errors. Otherwise, 0 is returned
109  * and nothing is done.
110  */
111 sub mp.repeated_words(doc, num_chars, max_dist)
113         local q = [];
114         local x = doc.txt.x;
115         local y = doc.txt.y;
116         local l;
118         /* build regexes */
119         local s_rx = sprintf('/^.{1,%d}/i', num_chars);
120         local e_rx = sprintf('/.{1,%d}$/i', num_chars);
122         /* if there were previous repeated words, no longer
123            consider them as 'typos' */
124         if (mp.last_repeated_words) {
125                 hdel(mp.word_color, mp.last_repeated_words[0]);
126                 hdel(mp.word_color, mp.last_repeated_words[1]);
127         }
129         while ((l = doc.txt.lines[y]) != NULL || size(q)) {
131                 local w, w1;
133                 if (l != NULL) {
134                         /* process another word in the line */
135                         if ((w = regex(l, mp.word_regex, x)) != NULL) {
136                                 /* get matching position */
137                                 local c = regex();
139                                 /* does the word measure at lest num_chars? */
140                                 if (size(w) >= num_chars) {
141                                         /* enqueue this word, and dequeue another */
142                                         w1 = queue(q, [
143                                                 w,
144                                                 c[0] + size(w),
145                                                 y,
146                                                 lc(regex(w, s_rx)),
147                                                 lc(regex(w, e_rx))
148                                         ], max_dist);
149                                 }
151                                 /* move offset to next word */
152                                 x = c[0] + c[1];
153                         }
154                         else {
155                                 /* try another line */
156                                 y++;
157                                 x = 0;
158                         }
159                 }
160                 else
161                         /* dequeue */
162                         w1 = shift(q);
164                 /* has a word been dequeued? */
165                 if (w1 != NULL) {
166                         /* seek each word in the queue */
167                         foreach (w2, q) {
168                                 /* does the word and any other in
169                                    the queue match the regexes? */
170                                 if ((w1[3] eq w2[3]) || (w1[4] eq w2[4])) {
172                                         /* add both to the word color hash */
173                                         mp.word_color[w1[0]] =
174                                         mp.word_color[w2[0]] =
175                                                 mp.colors.spell.attr;
177                                         /* store for later removal */
178                                         mp.last_repeated_words =
179                                                 [ w1[0], w2[0] ];
181                                         /* move cursor there */
182                                         mp.search_set_y(doc, w1[2]);
183                                         mp.set_x(doc, w1[1]);
185                                         /* trigger a redraw */
186                                         mp.redraw();
188                                         return 1;
189                                 }
190                         }
191                 }
192         }
194         return 0;