Mercurial > hg > xemacs-beta
comparison src/abbrev.c @ 227:0e522484dd2a r20-5b12
Import from CVS: tag r20-5b12
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:12:37 +0200 |
parents | 41ff10fd062f |
children | c5d627a313b1 |
comparison
equal
deleted
inserted
replaced
226:eea38c7ad7b4 | 227:0e522484dd2a |
---|---|
75 | 75 |
76 /* Hook to run before expanding any abbrev. */ | 76 /* Hook to run before expanding any abbrev. */ |
77 Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook; | 77 Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook; |
78 | 78 |
79 | 79 |
80 struct abbrev_match_mapper_closure { | |
81 struct buffer *buf; | |
82 struct Lisp_Char_Table *chartab; | |
83 Charcount point, maxlen; | |
84 struct Lisp_Symbol *found; | |
85 }; | |
86 | |
87 /* For use by abbrev_match(): Match SYMBOL's name against buffer text | |
88 before point, case-insensitively. When found, return non-zero, so | |
89 that map_obarray terminates mapping. */ | |
90 static int | |
91 abbrev_match_mapper (Lisp_Object symbol, void *arg) | |
92 { | |
93 struct abbrev_match_mapper_closure *closure = | |
94 (struct abbrev_match_mapper_closure *)arg; | |
95 Charcount abbrev_length; | |
96 struct Lisp_Symbol *sym = XSYMBOL (symbol); | |
97 struct Lisp_String *abbrev; | |
98 | |
99 /* symbol_value should be OK here, because abbrevs are not expected | |
100 to contain any SYMBOL_MAGIC stuff. */ | |
101 if (UNBOUNDP (symbol_value (sym)) || NILP (symbol_value (sym))) | |
102 { | |
103 /* The symbol value of nil means that abbrev got undefined. */ | |
104 return 0; | |
105 } | |
106 abbrev = symbol_name (sym); | |
107 abbrev_length = string_char_length (abbrev); | |
108 if (abbrev_length > closure->maxlen) | |
109 { | |
110 /* This abbrev is too large -- it wouldn't fit. */ | |
111 return 0; | |
112 } | |
113 /* If `bar' is an abbrev, and a user presses `fubar<SPC>', we don't | |
114 normally want to expand it. OTOH, if the abbrev begins with | |
115 non-word syntax (e.g. `#if'), it is OK to abbreviate it anywhere. */ | |
116 if (abbrev_length < closure->maxlen && abbrev_length > 0 | |
117 && (WORD_SYNTAX_P (closure->chartab, string_char (abbrev, 0))) | |
118 && (WORD_SYNTAX_P (closure->chartab, | |
119 BUF_FETCH_CHAR (closure->buf, | |
120 closure->point - (abbrev_length + 1))))) | |
121 { | |
122 return 0; | |
123 } | |
124 /* Match abbreviation string against buffer text. */ | |
125 { | |
126 Bufbyte *ptr = string_data (abbrev); | |
127 Charcount idx; | |
128 | |
129 for (idx = 0; idx < abbrev_length; idx++) | |
130 { | |
131 if (DOWNCASE (closure->buf, | |
132 BUF_FETCH_CHAR (closure->buf, | |
133 closure->point - abbrev_length + idx)) | |
134 != DOWNCASE (closure->buf, charptr_emchar (ptr))) | |
135 { | |
136 break; | |
137 } | |
138 INC_CHARPTR (ptr); | |
139 } | |
140 if (idx == abbrev_length) | |
141 { | |
142 /* This is the one. */ | |
143 closure->found = sym; | |
144 return 1; | |
145 } | |
146 } | |
147 return 0; | |
148 } | |
149 | |
80 /* Match the buffer text against names of symbols in obarray. Returns | 150 /* Match the buffer text against names of symbols in obarray. Returns |
81 the matching symbol, or 0 if not found. */ | 151 the matching symbol, or 0 if not found. */ |
82 | |
83 static struct Lisp_Symbol * | 152 static struct Lisp_Symbol * |
84 abbrev_match (struct buffer *buf, Lisp_Object obarray) | 153 abbrev_match (struct buffer *buf, Lisp_Object obarray) |
85 { | 154 { |
86 Bufpos point = BUF_PT (buf); | 155 struct abbrev_match_mapper_closure closure; |
87 Bufpos maxlen = point - BUF_BEGV (buf); | 156 |
88 Charcount idx; | 157 /* Precalculate some stuff, so mapper function needn't to it in each |
89 | 158 iteration. */ |
90 struct Lisp_Char_Table *chartab = XCHAR_TABLE (buf->mirror_syntax_table); | 159 closure.buf = buf; |
91 struct Lisp_String *abbrev; | 160 closure.point = BUF_PT (buf); |
92 struct Lisp_Vector *obvec; | 161 closure.maxlen = closure.point - BUF_BEGV (buf); |
93 struct Lisp_Symbol *sym = NULL; | 162 closure.chartab = XCHAR_TABLE (buf->mirror_syntax_table); |
94 Charcount abbrev_length; | 163 closure.found = 0; |
95 Lisp_Object tail; | 164 |
96 int i, found; | 165 map_obarray (obarray, abbrev_match_mapper, &closure); |
97 | 166 |
98 CHECK_VECTOR (obarray); | 167 return closure.found; |
99 obvec = XVECTOR (obarray); | 168 } |
100 | 169 |
101 /* The obarray-traversing code is copied from `map_obarray'. */ | 170 /* Take the word before point (or Vabbrev_start_location, if non-nil), |
102 found = 0; | 171 and look it up in OBARRAY, and return the symbol (or zero). This |
103 for (i = vector_length (obvec) - 1; i >= 0; i--) | 172 used to be the default method of searching, with the obvious |
104 { | 173 limitation that the abbrevs may consist only of word characters. |
105 tail = vector_data (obvec)[i]; | 174 It is an order of magnitude faster than the proper abbrev_match(), |
106 if (SYMBOLP (tail)) | 175 but then again, vi is an order of magnitude faster than Emacs. |
107 while (1) | 176 |
108 { | 177 This speed difference should be unnoticable, though. I have tested |
109 sym = XSYMBOL (tail); | 178 the degenerated cases of thousands of abbrevs being defined, and |
110 if (UNBOUNDP (symbol_value (sym)) || NILP (symbol_value (sym))) | 179 abbrev_match() was still fast enough for normal operation. */ |
111 { | |
112 /* The symbol value of nil means that abbrev got | |
113 undefined. */ | |
114 goto next; | |
115 } | |
116 abbrev = symbol_name (sym); | |
117 abbrev_length = string_char_length (abbrev); | |
118 if (abbrev_length > maxlen) | |
119 { | |
120 /* This abbrev is too large -- it wouldn't fit. */ | |
121 goto next; | |
122 } | |
123 /* If `bar' is an abbrev, and a user presses `fubar<SPC>', | |
124 we don't normally want to expand it. OTOH, if the | |
125 abbrev begins with non-word syntax, it is OK to | |
126 abbreviate it anywhere. */ | |
127 if (abbrev_length < maxlen && abbrev_length > 0 | |
128 && (WORD_SYNTAX_P (chartab, string_char (abbrev, 0))) | |
129 && (WORD_SYNTAX_P (chartab, | |
130 BUF_FETCH_CHAR (buf, point | |
131 - (abbrev_length + 1))))) | |
132 { | |
133 goto next; | |
134 } | |
135 /* Match abbreviation string against buffer text. */ | |
136 for (idx = abbrev_length - 1; idx >= 0; idx--) | |
137 { | |
138 if (DOWNCASE (buf, BUF_FETCH_CHAR (buf, point - | |
139 (abbrev_length - idx))) | |
140 != DOWNCASE (buf, string_char (abbrev, idx))) | |
141 break; | |
142 } | |
143 if (idx < 0) | |
144 { | |
145 found = 1; | |
146 break; | |
147 } | |
148 next: | |
149 sym = symbol_next (XSYMBOL (tail)); | |
150 if (!sym) | |
151 break; | |
152 XSETSYMBOL (tail, sym); | |
153 } /* while */ | |
154 if (found) | |
155 break; | |
156 } /* for */ | |
157 | |
158 return found ? sym : 0; | |
159 } | |
160 | |
161 /* Take the word before point, and look it up in OBARRAY, and return | |
162 the symbol (or nil). This used to be the default method of | |
163 searching, with the obvious limitation that the abbrevs may consist | |
164 only of word characters. It is an order of magnitued faster than | |
165 the proper `abbrev_match', but then again, vi is an order of | |
166 magnitude faster than Emacs. */ | |
167 static struct Lisp_Symbol * | 180 static struct Lisp_Symbol * |
168 abbrev_oblookup (struct buffer *buf, Lisp_Object obarray) | 181 abbrev_oblookup (struct buffer *buf, Lisp_Object obarray) |
169 { | 182 { |
170 Bufpos wordstart, wordend; | 183 Bufpos wordstart, wordend; |
171 Bufbyte *word, *p; | 184 Bufbyte *word, *p; |
177 if (!NILP (Vabbrev_start_location)) | 190 if (!NILP (Vabbrev_start_location)) |
178 { | 191 { |
179 wordstart = get_buffer_pos_char (buf, Vabbrev_start_location, | 192 wordstart = get_buffer_pos_char (buf, Vabbrev_start_location, |
180 GB_COERCE_RANGE); | 193 GB_COERCE_RANGE); |
181 Vabbrev_start_location = Qnil; | 194 Vabbrev_start_location = Qnil; |
182 /* | 195 /* Previously, abbrev-prefix-mark crockishly inserted a dash to |
183 * Previously, abbrev-prefix-mark inserted a dash to indicate the | 196 indicate the abbrev start point. It now uses an extent with |
184 * abbrev start point. It now uses an extent with a begin | 197 a begin glyph so there's no dash to remove. */ |
185 * glyph so there's no dash to remove. | 198 #if 0 |
186 */ | |
187 /* | |
188 if (wordstart != BUF_ZV (buf) | 199 if (wordstart != BUF_ZV (buf) |
189 && BUF_FETCH_CHAR (buf, wordstart) == '-') | 200 && BUF_FETCH_CHAR (buf, wordstart) == '-') |
190 { | 201 { |
191 buffer_delete_range (buf, wordstart, wordstart + 1, 0); | 202 buffer_delete_range (buf, wordstart, wordstart + 1, 0); |
192 } | 203 } |
193 */ | 204 #endif |
194 wordend = BUF_PT (buf); | 205 wordend = BUF_PT (buf); |
195 } | 206 } |
196 else | 207 else |
197 { | 208 { |
198 Bufpos point = BUF_PT (buf); | 209 Bufpos point = BUF_PT (buf); |
229 if (SYMBOLP (lookup) && !NILP (symbol_value (XSYMBOL (lookup)))) | 240 if (SYMBOLP (lookup) && !NILP (symbol_value (XSYMBOL (lookup)))) |
230 return XSYMBOL (lookup); | 241 return XSYMBOL (lookup); |
231 else | 242 else |
232 return NULL; | 243 return NULL; |
233 } | 244 } |
234 | 245 |
235 /* Return non-zero if OBARRAY contains an interned symbol ` '. */ | 246 /* Return non-zero if OBARRAY contains an interned symbol ` '. */ |
236 static int | 247 static int |
237 obarray_has_blank_p (Lisp_Object obarray) | 248 obarray_has_blank_p (Lisp_Object obarray) |
238 { | 249 { |
239 Lisp_Object lookup; | 250 Lisp_Object lookup; |
258 else if (LOWERCASEP (buf, c)) | 269 else if (LOWERCASEP (buf, c)) |
259 ++*lccount; | 270 ++*lccount; |
260 ++pos; | 271 ++pos; |
261 } | 272 } |
262 } | 273 } |
263 | 274 |
264 DEFUN ("expand-abbrev", Fexpand_abbrev, 0, 0, "", /* | 275 DEFUN ("expand-abbrev", Fexpand_abbrev, 0, 0, "", /* |
265 Expand the abbrev before point, if any. | 276 Expand the abbrev before point, if any. |
266 Effective when explicitly called even when `abbrev-mode' is nil. | 277 Effective when explicitly called even when `abbrev-mode' is nil. |
267 Returns t if expansion took place. | 278 Returns the abbrev symbol, if expansion took place. |
279 If no abbrev matched, but `pre-abbrev-expand-hook' changed the buffer, | |
280 returns t. | |
268 */ | 281 */ |
269 ()) | 282 ()) |
270 { | 283 { |
271 /* This function can GC */ | 284 /* This function can GC */ |
272 struct buffer *buf = current_buffer; | 285 struct buffer *buf = current_buffer; |
290 | 303 |
291 abbrev_symbol = NULL; | 304 abbrev_symbol = NULL; |
292 if (!BUFFERP (Vabbrev_start_location_buffer) || | 305 if (!BUFFERP (Vabbrev_start_location_buffer) || |
293 XBUFFER (Vabbrev_start_location_buffer) != buf) | 306 XBUFFER (Vabbrev_start_location_buffer) != buf) |
294 Vabbrev_start_location = Qnil; | 307 Vabbrev_start_location = Qnil; |
295 /* We use the more general `abbrev_match' if the obarray blank flag | 308 /* We use the more general abbrev_match() if the obarray blank flag |
296 is not set, and Vabbrev_start_location is nil. Otherwise, use | 309 is not set, and Vabbrev_start_location is nil. Otherwise, use |
297 `abbrev_oblookup'. */ | 310 abbrev_oblookup(). */ |
298 #define MATCHFUN(tbl) ((obarray_has_blank_p (tbl) \ | 311 #define MATCHFUN(tbl) ((obarray_has_blank_p (tbl) \ |
299 && NILP (Vabbrev_start_location)) \ | 312 && NILP (Vabbrev_start_location)) \ |
300 ? abbrev_match : abbrev_oblookup) | 313 ? abbrev_match : abbrev_oblookup) |
301 if (!NILP (buf->abbrev_table)) | 314 if (!NILP (buf->abbrev_table)) |
302 { | 315 { |
310 } | 323 } |
311 if (!abbrev_symbol) | 324 if (!abbrev_symbol) |
312 return pre_modiff_p; | 325 return pre_modiff_p; |
313 | 326 |
314 /* NOTE: we hope that `pre-abbrev-expand-hook' didn't do something | 327 /* NOTE: we hope that `pre-abbrev-expand-hook' didn't do something |
315 nasty, such as changed (or killed) the buffer. */ | 328 nasty, such as changed the buffer. Here we protect against the |
329 buffer getting killed. */ | |
330 if (! BUFFER_LIVE_P (buf)) | |
331 return Qnil; | |
316 point = BUF_PT (buf); | 332 point = BUF_PT (buf); |
317 | 333 |
318 /* OK, we're out of the must-be-fast part. An abbreviation matched. | 334 /* OK, we're out of the must-be-fast part. An abbreviation matched. |
319 Now find the parameters, insert the expansion, and make it all | 335 Now find the parameters, insert the expansion, and make it all |
320 look pretty. */ | 336 look pretty. */ |
321 abbrev_string = symbol_name (abbrev_symbol); | 337 abbrev_string = symbol_name (abbrev_symbol); |
322 abbrev_length = string_char_length (abbrev_string); | 338 abbrev_length = string_char_length (abbrev_string); |
323 abbrev_start = point - abbrev_length; | 339 abbrev_start = point - abbrev_length; |
324 | 340 |
325 expansion = symbol_value (abbrev_symbol); | 341 expansion = symbol_value (abbrev_symbol); |
326 CHECK_STRING (expansion); | 342 CHECK_STRING (expansion); |
327 | 343 |
328 count = symbol_plist (abbrev_symbol); /* Gag */ | 344 count = symbol_plist (abbrev_symbol); /* Gag */ |
329 if (NILP (count)) | 345 if (NILP (count)) |
330 count = make_int (0); | 346 count = Qzero; |
331 else | 347 else |
332 CHECK_NATNUM (count); | 348 CHECK_NATNUM (count); |
333 symbol_plist (abbrev_symbol) = make_int (1 + XINT (count)); | 349 symbol_plist (abbrev_symbol) = make_int (1 + XINT (count)); |
334 | 350 |
335 /* Count the case in the original text. */ | 351 /* Count the case in the original text. */ |
385 | 401 |
386 hook = symbol_function (abbrev_symbol); | 402 hook = symbol_function (abbrev_symbol); |
387 if (!NILP (hook) && !UNBOUNDP (hook)) | 403 if (!NILP (hook) && !UNBOUNDP (hook)) |
388 call0 (hook); | 404 call0 (hook); |
389 | 405 |
390 return Qt; | 406 return Vlast_abbrev; |
391 } | 407 } |
392 | 408 |
393 | 409 |
394 void | 410 void |
395 syms_of_abbrev (void) | 411 syms_of_abbrev (void) |
396 { | 412 { |
397 defsymbol (&Qpre_abbrev_expand_hook, "pre-abbrev-expand-hook"); | 413 defsymbol (&Qpre_abbrev_expand_hook, "pre-abbrev-expand-hook"); |
398 DEFSUBR (Fexpand_abbrev); | 414 DEFSUBR (Fexpand_abbrev); |