4 A Programmer's Text Editor
8 Copyright (C) 1991-2008 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 /* successful searches will always be shown in this line */
29 mp.config.move_seek_to_line = 5;
33 mp.actions['seek'] = sub (d) {
35 { 'label' => L("Text to seek:"),
37 'history' => 'search' },
38 { 'label' => L("Case sensitive") ~ ':',
40 'value' => mp.config.case_sensitive_search }
44 mp.config.case_sensitive_search = t[1];
46 mp.long_op(mp.search, d, mp.backslash_codes(t[0])) ||
47 mp.alert(L("Text not found."));
51 mp.actions['seek_next'] = sub (d) { mp.long_op(mp.search, d, NULL) ||
52 mp.alert(L("Text not found."));
55 mp.actions['seek_prev'] = sub (d) { mp.long_op(mp.search_back, d, NULL) ||
56 mp.alert(L("Text not found."));
59 mp.actions['replace'] = sub (d) {
62 { 'label' => L("Replace text:"),
64 'history' => 'search'},
65 { 'label' => L("Replace with:"),
67 'history' => 'replace'},
68 { 'label' => L("Case sensitive") ~ ':',
70 'value' => mp.config.case_sensitive_search },
71 { 'label' => L("Global replace:"),
73 'value' => mp.config.global_replace }
77 mp.config.case_sensitive_search = r[2];
78 mp.config.global_replace = r[3];
81 mp.long_op(mp.replace, d, mp.backslash_codes(r[0]), mp.backslash_codes(r[1]));
85 mp.actions['seek_next_char'] = sub (d) { mp.seek_prev_or_next_char(d, mp.search); };
86 mp.actions['seek_prev_char'] = sub (d) { mp.seek_prev_or_next_char(d, mp.search_back); };
88 mp.actions['grep'] = sub (d) {
91 { 'label' => L("Text to seek:"),
93 'history' => 'search'},
94 { 'label' => L("Files to grep (empty, all):"),
99 if (r != NULL && r[0] ne '') {
101 local t = '<grep ' ~ r[0] ~ ' ' ~ r[1] ~ '>';
103 if ((r = mp.long_op(mp.grep, '/' ~ r[0] ~ '/', r[1])) == NULL)
104 mp.alert(L("File(s) not found."));
107 mp.alert(L("Text not found."));
109 local l = mp.open(t);
115 mp.insert(l, sprintf("%s:%d: %s\n",
116 e[0], e[1] + 1, e[2]));
126 /* default key bindings */
128 mp.keycodes['f3'] = 'seek_next';
129 mp.keycodes['ctrl-f3'] = 'seek_prev';
130 mp.keycodes['ctrl-f'] = 'seek';
131 mp.keycodes['ctrl-r'] = 'replace';
132 mp.keycodes['ctrl-page-down'] = 'seek_next_char';
133 mp.keycodes['ctrl-page-up'] = 'seek_prev_char';
135 /* action descriptions */
136 mp.actdesc['seek'] = LL("Search text...");
137 mp.actdesc['seek_next'] = LL("Search next");
138 mp.actdesc['seek_prev'] = LL("Search previous");
139 mp.actdesc['replace'] = LL("Replace...");
140 mp.actdesc['seek_next_char'] = LL("Move to next instance of current char");
141 mp.actdesc['seek_prev_char'] = LL("Move to previous instance of current char");
142 mp.actdesc['grep'] = LL("Grep (find inside) files...");
146 sub mp.prefix_regex(str)
147 /* set str to be a valid regex */
152 /* surround with / for the regex */
153 str = '/' ~ str ~ '/';
155 /* add optional case insensitivity flag */
156 if (! mp.config.case_sensitive_search)
163 sub mp.search_dir(doc, str, dir)
164 /* search str and put the current position there, with direction */
166 local txt, r, l, lines;
167 local bx, by, ex, ey;
170 str = mp.last_search;
172 str = mp.prefix_regex(str);
173 mp.last_search = str;
182 /* search backwards */
185 ex = txt.x && txt.x - 1 || 0;
189 if (ey >= txt.mark.ey) {
192 if (ex > txt.mark.ex)
210 if (by <= txt.mark.by) {
213 if (bx < txt.mark.bx)
221 ex = size(txt.lines[-1]);
222 ey = size(txt.lines);
226 lines = mp.get_range(doc, bx, by, ex, ey, 0);
229 local n = (dir == -1) && (size(lines) - 1) || 0;
230 while ((l = lines[n]) != NULL && regex(str, l) == NULL)
236 local x = r[0] + r[1];
241 mp.set_y(doc, by + n);
244 /* set always to the same line */
245 if (mp.config.move_seek_to_line != NULL &&
246 (doc.txt.vy = doc.txt.y - mp.config.move_seek_to_line) < 0)
254 sub mp.search(doc, str)
255 /* search str and put the current position there, downwards */
257 mp.search_dir(doc, str, 1);
261 sub mp.search_back(doc, str)
262 /* search str and put the current position there, backwards */
264 mp.search_dir(doc, str, -1);
268 sub mp.replace_1(doc, this, that)
269 /* searches 'this' and replaces it with 'that', once */
273 if ((c = mp.search(doc, this)) != NULL) {
279 txt.lines[txt.y] = sregex(mp.prefix_regex(this),
280 txt.lines[txt.y], that, c[0]);
282 /* move to correct position */
284 mp.set_x(doc, c[0] + c[1]);
293 sub mp.replace(doc, this, that)
294 /* replaces 'this' with 'that', may be globally */
298 while (mp.replace_1(doc, this, that)) {
301 if (!mp.config.global_replace)
306 'timeout' => time() + 4,
307 'string' => sprintf(L("%d replaces"), cnt)
312 sub mp.seek_prev_or_next_char(doc, func)
313 /* moves to next or previous occurent of current char */
317 /* get current char */
318 local w = splice(txt.lines[txt.y], NULL, txt.x, 1);
320 /* move one char right */
323 /* search for it (mp.search() or mp.search_back()) */
324 local t = mp.last_search;
325 func(doc, '\' ~ w[1]);
333 sub mp.grep(rx, spec)
334 /* Greps str in the files in spec. Returns NULL if no file matched the glob()
335 (or glob() is unsupported), an empty list if the string was not found or
336 an array with the matches, that are three-element arrays with the file name,
337 the line number and the line that matched */
341 /* if spec is empty, set as NULL (meaning "glob everything") */
347 /* spec globs to NULL or empty; abort */
356 if ((f = open(fn, "r")) != NULL) {
359 /* file open; now grep */
360 while (l = read(f)) {
364 /* found; store line, filename and linenum */
365 push(r, [ fn, n, l ]);