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);