4 A Programmer's Text Editor
8 Copyright (C) 1991-2007 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 /* default ctags command */
29 mp.config.ctags_cmd = "ctags *";
31 /** editor actions **/
33 mp.actions['find_tag'] = sub(d) {
35 local tag = mp.get_word(d);
37 /* ask for it, taking the word under the cursor */
39 { 'label' => L("Tag to seek:"),
41 'history' => 'find_tag',
49 mp.actions['complete'] = sub(d) {
55 foreach (l, d.txt.lines)
56 foreach (w, mp.split_by_words(l))
61 /* if the current word happens only one time, delete it */
62 local w = mp.get_word(d);
66 mp.complete(d, keys(words));
69 mp.actions['complete_symbol'] = sub(d) {
71 mp.long_op(mp.load_tags, 1);
73 if (!mp.complete(d, keys(mp.tags), L("Select symbol:")))
74 mp.alert(L("No matching symbol found."));
77 /** default key bindings **/
79 mp.keycodes['ctrl-t'] = "find_tag";
80 mp.keycodes['ctrl-u'] = "complete";
82 /** action descriptions **/
84 mp.actdesc['find_tag'] = LL("Search tag...");
85 mp.actdesc['complete'] = LL("Complete...");
86 mp.actdesc['complete_symbol'] = LL("Symbol completion...");
90 sub mp.load_tags(force)
91 /* load a 'tags' file */
95 if ((f = open("tags", "r")) == NULL) {
96 /* if force is set, execute the ctags command */
97 if (!force || (f = popen(mp.config.ctags_cmd, "r")) == NULL)
100 /* read (and discard) a line from it */
105 if ((f = open("tags", "r")) == NULL)
109 /* deletes all currently stored tags from the word/color cache */
110 foreach (l, keys(mp.tags))
111 hdel(mp.word_color, l);
113 /* reset current tags */
116 /* get the attribute for tags */
117 a = mp.colors.tag.attr;
119 while ((l = read(f))) {
120 local t = split("\t", l);
123 /* clean the regex 'markup' for the label */
124 l = sregex('@^/\^@', t[2], '');
125 l = sregex('@\$/;"$@', l, '') ~ ' [' ~ t[1] ~ ']';
127 /* clean the regex itself */
128 r = sregex('@/;"$@', t[2], NULL);
129 r = sregex('@^/@', r, NULL);
131 /* escape all troublesome characters */
132 r = sregex("/([\(\)\*\?\[\{\}]|\])/g", r, sub (m) { '\' ~ m; });
134 /* store the tag information */
142 /* store the word as specially-colored */
143 mp.word_color[t[0]] = a;
151 /* opens a tag (uses GUI) */
155 /* force loading of the tags file */
156 mp.long_op(mp.load_tags, 1);
158 /* greps all tags containing the tag, and returns the
159 values from mp.tags */
160 if ((t = map(mp.tags, grep('/' ~ tag ~ '/', keys(mp.tags)))) == NULL) {
161 mp.alert(L("Tag not found."));
165 /* only one? get the first one */
169 /* build a list to ask the user */
170 local l = map(sub(e) { e.label; }, t);
173 { 'label' => L("Select tag:"),
186 doc = mp.long_op(mp.open, tag.file);
188 /* move up and search */
190 return mp.long_op(mp.search, doc, tag.regex);
194 sub mp.complete(d, list, label)
195 /* completes the current word given a list (uses GUI) */
198 local word = mp.get_word(d);
200 /* takes all list elements starting with word */
201 if ((l = sort(grep('/^' ~ word ~ '/', list))) == NULL)
207 /* more than one; ask user */
209 { 'label' => label || L("Select:"),
219 /* accepted; substitute current word */
222 /* split line by words to take the offset of current word */
223 local r = mp.split_line_by_words(d);
224 local offset = r[1][r[2]];
226 /* substitute current word with newly selected word */
227 local w = splice(d.txt.lines[d.txt.y], l[a], offset, size(word));
229 /* change line and x cursor */
230 d.txt.lines[d.txt.y] = w[0];
231 d.txt.x = offset + size(l[a]);