Mercurial > hg > xemacs-beta
comparison src/abbrev.c @ 167:85ec50267440 r20-3b10
Import from CVS: tag r20-3b10
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:45:46 +0200 |
parents | 131b0175ea99 |
children | 8eaf7971accc |
comparison
equal
deleted
inserted
replaced
166:7a77eb660975 | 167:85ec50267440 |
---|---|
24 /* Authorship: | 24 /* Authorship: |
25 | 25 |
26 FSF: Original version; a long time ago. | 26 FSF: Original version; a long time ago. |
27 JWZ or Mly: Mostly moved into Lisp; maybe 1992. | 27 JWZ or Mly: Mostly moved into Lisp; maybe 1992. |
28 Ben Wing: Some changes for Mule for 19.12. | 28 Ben Wing: Some changes for Mule for 19.12. |
29 Hrvoje Niksic: Largely rewritten in June 1997. | |
29 */ | 30 */ |
30 | 31 |
31 /* This file has been Mule-ized. */ | 32 /* This file has been Mule-ized. */ |
32 | 33 |
33 #include <config.h> | 34 #include <config.h> |
68 Lisp_Object Vlast_abbrev_text; | 69 Lisp_Object Vlast_abbrev_text; |
69 | 70 |
70 /* Character address of start of last abbrev expanded */ | 71 /* Character address of start of last abbrev expanded */ |
71 int last_abbrev_point; | 72 int last_abbrev_point; |
72 | 73 |
74 Lisp_Object oblookup (Lisp_Object, CONST Bufbyte *, Bytecount); | |
75 | |
73 /* Hook to run before expanding any abbrev. */ | 76 /* Hook to run before expanding any abbrev. */ |
74 Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook; | 77 Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook; |
75 | 78 |
76 | 79 |
77 /* Expand the word before point, if it is an abbrev. | 80 /* Match the buffer text against names of symbols in obarray. Returns |
78 Returns Qt if an expansion is done. */ | 81 the matching symbol, or 0 if not found. */ |
82 | |
83 static struct Lisp_Symbol * | |
84 abbrev_match (struct buffer *buf, Lisp_Object obarray) | |
85 { | |
86 Bufpos point = BUF_PT (buf); | |
87 Bufpos maxlen = point - BUF_BEGV (buf); | |
88 Charcount idx; | |
89 | |
90 struct Lisp_Char_Table *chartab = XCHAR_TABLE (buf->mirror_syntax_table); | |
91 struct Lisp_String *abbrev; | |
92 struct Lisp_Vector *obvec; | |
93 struct Lisp_Symbol *sym; | |
94 Charcount abbrev_length; | |
95 Lisp_Object tail; | |
96 int i, found; | |
97 | |
98 CHECK_VECTOR (obarray); | |
99 obvec = XVECTOR (obarray); | |
100 | |
101 /* The obarray-traversing code is copied from `map_obarray'. */ | |
102 found = 0; | |
103 for (i = vector_length (obvec) - 1; i >= 0; i--) | |
104 { | |
105 tail = vector_data (obvec)[i]; | |
106 if (SYMBOLP (tail)) | |
107 while (1) | |
108 { | |
109 sym = XSYMBOL (tail); | |
110 if (UNBOUNDP (symbol_value (sym)) || NILP (symbol_value (sym))) | |
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 * | |
168 abbrev_oblookup (struct buffer *buf, Lisp_Object obarray) | |
169 { | |
170 Bufpos wordstart, wordend; | |
171 Bufbyte *word, *p; | |
172 Bytecount idx; | |
173 Lisp_Object lookup; | |
174 | |
175 CHECK_VECTOR (obarray); | |
176 | |
177 if (!NILP (Vabbrev_start_location)) | |
178 { | |
179 wordstart = get_buffer_pos_char (buf, Vabbrev_start_location, | |
180 GB_COERCE_RANGE); | |
181 Vabbrev_start_location = Qnil; | |
182 if (wordstart != BUF_ZV (buf) | |
183 && BUF_FETCH_CHAR (buf, wordstart) == '-') | |
184 { | |
185 buffer_delete_range (buf, wordstart, wordstart + 1, 0); | |
186 } | |
187 wordend = BUF_PT (buf); | |
188 } | |
189 else | |
190 { | |
191 Bufpos point = BUF_PT (buf); | |
192 | |
193 wordstart = scan_words (buf, point, -1); | |
194 if (!wordstart) | |
195 return 0; | |
196 | |
197 wordend = scan_words (buf, wordstart, 1); | |
198 if (!wordend) | |
199 return 0; | |
200 if (wordend > BUF_ZV (buf)) | |
201 wordend = BUF_ZV (buf); | |
202 if (wordend > point) | |
203 wordend = point; | |
204 /* Unlike the original function, we allow expansion only after | |
205 the abbrev, not preceded by a number of spaces. This is | |
206 because of consistency with abbrev_match. */ | |
207 if (wordend < point) | |
208 return 0; | |
209 if (wordend <= wordstart) | |
210 return 0; | |
211 } | |
212 | |
213 p = word = (Bufbyte *) alloca (MAX_EMCHAR_LEN * (wordend - wordstart)); | |
214 for (idx = wordstart; idx < wordend; idx++) | |
215 { | |
216 Emchar c = BUF_FETCH_CHAR (buf, idx); | |
217 if (UPPERCASEP (buf, c)) | |
218 c = DOWNCASE (buf, c); | |
219 p += set_charptr_emchar (p, c); | |
220 } | |
221 lookup = oblookup (obarray, word, p - word); | |
222 if (SYMBOLP (lookup) && !NILP (symbol_value (XSYMBOL (lookup)))) | |
223 return XSYMBOL (lookup); | |
224 else | |
225 return NULL; | |
226 } | |
227 | |
228 /* Return non-zero if OBARRAY contains an interned symbol ` '. */ | |
229 static int | |
230 obarray_has_blank_p (Lisp_Object obarray) | |
231 { | |
232 Lisp_Object lookup; | |
233 | |
234 lookup = oblookup (obarray, (Bufbyte *)" ", 1); | |
235 return SYMBOLP (lookup); | |
236 } | |
237 | |
238 /* Analyze case in the buffer substring, and report it. */ | |
239 static void | |
240 abbrev_count_case (struct buffer *buf, Bufpos pos, Charcount length, | |
241 int *lccount, int *uccount) | |
242 { | |
243 Emchar c; | |
244 | |
245 *lccount = *uccount = 0; | |
246 while (length--) | |
247 { | |
248 c = BUF_FETCH_CHAR (buf, pos); | |
249 if (UPPERCASEP (buf, c)) | |
250 ++*uccount; | |
251 else if (LOWERCASEP (buf, c)) | |
252 ++*lccount; | |
253 ++pos; | |
254 } | |
255 } | |
79 | 256 |
80 DEFUN ("expand-abbrev", Fexpand_abbrev, 0, 0, "", /* | 257 DEFUN ("expand-abbrev", Fexpand_abbrev, 0, 0, "", /* |
81 Expand the abbrev before point, if there is an abbrev there. | 258 Expand the abbrev before point, if any. |
82 Effective when explicitly called even when `abbrev-mode' is nil. | 259 Effective when explicitly called even when `abbrev-mode' is nil. |
83 Returns t if expansion took place. | 260 Returns t if expansion took place. |
84 */ | 261 */ |
85 ()) | 262 ()) |
86 { | 263 { |
87 /* This function can GC */ | 264 /* This function can GC */ |
88 REGISTER Bufbyte *buffer, *p; | |
89 REGISTER Bufpos wordstart, wordend, idx; | |
90 Charcount whitecnt; | |
91 Charcount uccount = 0, lccount = 0; | |
92 REGISTER Lisp_Object sym; | |
93 Lisp_Object expansion, hook, value; | |
94 struct buffer *buf = current_buffer; | 265 struct buffer *buf = current_buffer; |
95 Lisp_Object lbuf; | |
96 int oldmodiff = BUF_MODIFF (buf); | 266 int oldmodiff = BUF_MODIFF (buf); |
97 | 267 Lisp_Object pre_modiff_p; |
98 XSETBUFFER (lbuf, buf); | 268 Bufpos point; /* position of point */ |
269 Bufpos abbrev_start; /* position of abbreviation beginning */ | |
270 | |
271 struct Lisp_Symbol *(*fun) (struct buffer *, Lisp_Object); | |
272 | |
273 struct Lisp_Symbol *abbrev_symbol; | |
274 struct Lisp_String *abbrev_string; | |
275 Lisp_Object expansion, count, hook; | |
276 Charcount abbrev_length, idx; | |
277 int lccount, uccount; | |
278 | |
99 run_hook (Qpre_abbrev_expand_hook); | 279 run_hook (Qpre_abbrev_expand_hook); |
100 /* If the hook changes the buffer, treat that as having "done an | 280 /* If the hook changes the buffer, treat that as having "done an |
101 expansion". */ | 281 expansion". */ |
102 value = (BUF_MODIFF (buf) != oldmodiff ? Qt : Qnil); | 282 pre_modiff_p = (BUF_MODIFF (buf) != oldmodiff ? Qt : Qnil); |
103 | 283 |
104 wordstart = 0; | 284 abbrev_symbol = NULL; |
105 if (!BUFFERP (Vabbrev_start_location_buffer) || | 285 if (!BUFFERP (Vabbrev_start_location_buffer) || |
106 XBUFFER (Vabbrev_start_location_buffer) != buf) | 286 XBUFFER (Vabbrev_start_location_buffer) != buf) |
107 Vabbrev_start_location = Qnil; | 287 Vabbrev_start_location = Qnil; |
108 if (!NILP (Vabbrev_start_location)) | 288 /* We use the more general `abbrev_match' if the obarray blank flag |
109 { | 289 is not set, and Vabbrev_start_location is nil. Otherwise, use |
110 wordstart = get_buffer_pos_char (buf, Vabbrev_start_location, GB_COERCE_RANGE); | 290 `abbrev_oblookup'. */ |
111 Vabbrev_start_location = Qnil; | 291 #define MATCHFUN(tbl) ((obarray_has_blank_p (tbl) \ |
112 if (wordstart < BUF_BEGV (buf) || wordstart > BUF_ZV (buf)) | 292 && NILP (Vabbrev_start_location)) \ |
113 wordstart = 0; | 293 ? abbrev_match : abbrev_oblookup) |
114 if (wordstart && wordstart != BUF_ZV (buf) && | 294 if (!NILP (buf->abbrev_table)) |
115 BUF_FETCH_CHAR (buf, wordstart) == '-') | 295 { |
116 buffer_delete_range (buf, wordstart, wordstart + 1, 0); | 296 fun = MATCHFUN (buf->abbrev_table); |
117 } | 297 abbrev_symbol = fun (buf, buf->abbrev_table); |
118 if (!wordstart) | 298 } |
119 wordstart = scan_words (buf, BUF_PT (buf), -1); | 299 if (!abbrev_symbol && !NILP (Vglobal_abbrev_table)) |
120 | 300 { |
121 if (!wordstart) | 301 fun = MATCHFUN (Vglobal_abbrev_table); |
122 return value; | 302 abbrev_symbol = fun (buf, Vglobal_abbrev_table); |
123 | 303 } |
124 wordend = scan_words (buf, wordstart, 1); | 304 if (!abbrev_symbol) |
125 if (!wordend) | 305 return pre_modiff_p; |
126 return value; | 306 |
127 | 307 /* NOTE: we hope that `pre-abbrev-expand-hook' didn't do something |
128 if (wordend > BUF_PT (buf)) | 308 nasty, such as changed (or killed) the buffer. */ |
129 wordend = BUF_PT (buf); | 309 point = BUF_PT (buf); |
130 whitecnt = BUF_PT (buf) - wordend; | 310 |
131 if (wordend <= wordstart) | 311 /* OK, we're out of the must-be-fast part. An abbreviation matched. |
132 return value; | 312 Now find the parameters, insert the expansion, and make it all |
133 | 313 look pretty. */ |
134 p = buffer = (Bufbyte *) alloca (MAX_EMCHAR_LEN*(wordend - wordstart)); | 314 abbrev_string = symbol_name (abbrev_symbol); |
135 | 315 abbrev_length = string_char_length (abbrev_string); |
136 for (idx = wordstart; idx < wordend; idx++) | 316 abbrev_start = point - abbrev_length; |
137 { | 317 |
138 REGISTER Emchar c = BUF_FETCH_CHAR (buf, idx); | 318 expansion = symbol_value (abbrev_symbol); |
139 if (UPPERCASEP (buf, c)) | 319 CHECK_STRING (expansion); |
140 c = DOWNCASE (buf, c), uccount++; | 320 |
141 else if (! NOCASEP (buf, c)) | 321 count = symbol_plist (abbrev_symbol); /* Gag */ |
142 lccount++; | 322 if (NILP (count)) |
143 p += set_charptr_emchar (p, c); | 323 count = make_int (0); |
144 } | |
145 | |
146 if (VECTORP (buf->abbrev_table)) | |
147 sym = oblookup (buf->abbrev_table, | |
148 buffer, | |
149 p - buffer); | |
150 else | 324 else |
151 sym = Qzero; | 325 CHECK_NATNUM (count); |
152 if (INTP (sym) || NILP (XSYMBOL (sym)->value)) | 326 symbol_plist (abbrev_symbol) = make_int (1 + XINT (count)); |
153 sym = oblookup (Vglobal_abbrev_table, | 327 |
154 buffer, | 328 /* Count the case in the original text. */ |
155 p - buffer); | 329 abbrev_count_case (buf, abbrev_start, abbrev_length, &lccount, &uccount); |
156 if (INTP (sym) || NILP (XSYMBOL (sym)->value)) | 330 |
157 return value; | 331 /* Remember the last abbrev text, location, etc. */ |
158 | 332 XSETSYMBOL (Vlast_abbrev, abbrev_symbol); |
159 if (INTERACTIVE && !EQ (minibuf_window, Fselected_window (Qnil))) | |
160 { | |
161 /* Add an undo boundary, in case we are doing this for | |
162 a self-inserting command which has avoided making one so far. */ | |
163 BUF_SET_PT (buf, wordend); | |
164 Fundo_boundary (); | |
165 } | |
166 BUF_SET_PT (buf, wordstart); | |
167 Vlast_abbrev_text = | 333 Vlast_abbrev_text = |
168 make_string_from_buffer (buf, wordstart, wordend - wordstart); | 334 make_string_from_buffer (buf, abbrev_start, abbrev_length); |
169 buffer_delete_range (buf, wordstart, wordend, 0); | 335 last_abbrev_point = abbrev_start; |
170 | 336 |
171 /* Now sym is the abbrev symbol. */ | 337 /* Add an undo boundary, in case we are doing this for a |
172 Vlast_abbrev = sym; | 338 self-inserting command which has avoided making one so far. */ |
173 last_abbrev_point = wordstart; | 339 if (INTERACTIVE) |
174 | 340 Fundo_boundary (); |
175 if (INTP (XSYMBOL (sym)->plist)) | 341 |
176 XSETINT (XSYMBOL (sym)->plist, | 342 /* Remove the abbrev */ |
177 XINT (XSYMBOL (sym)->plist) + 1); /* Increment use count */ | 343 buffer_delete_range (buf, abbrev_start, point, 0); |
178 | 344 /* And insert the expansion. */ |
179 expansion = XSYMBOL (sym)->value; | |
180 buffer_insert_lisp_string (buf, expansion); | 345 buffer_insert_lisp_string (buf, expansion); |
181 BUF_SET_PT (buf, BUF_PT (buf) + whitecnt); | 346 point = BUF_PT (buf); |
182 | 347 |
348 /* Now fiddle with the case. */ | |
183 if (uccount && !lccount) | 349 if (uccount && !lccount) |
184 { | 350 { |
185 /* Abbrev was all caps */ | 351 /* Abbrev was all caps */ |
186 /* If expansion is multiple words, normally capitalize each word */ | 352 if (!abbrev_all_caps |
187 /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase | 353 && scan_words (buf, point, -1) > scan_words (buf, abbrev_start, 1)) |
188 but Megatest 68000 compiler can't handle that */ | 354 { |
189 if (!abbrev_all_caps) | 355 Fupcase_initials_region (make_int (abbrev_start), make_int (point), |
190 if (scan_words (buf, BUF_PT (buf), -1) > | 356 make_buffer (buf)); |
191 scan_words (buf, wordstart, 1)) | 357 } |
192 { | 358 else |
193 Fupcase_initials_region (make_int (wordstart), | 359 { |
194 make_int (BUF_PT (buf)), | 360 /* If expansion is one word, or if user says so, upcase it all. */ |
195 lbuf); | 361 Fupcase_region (make_int (abbrev_start), make_int (point), |
196 goto caped; | 362 make_buffer (buf)); |
197 } | 363 } |
198 /* If expansion is one word, or if user says so, upcase it all. */ | |
199 Fupcase_region (make_int (wordstart), make_int (BUF_PT (buf)), | |
200 lbuf); | |
201 caped: ; | |
202 } | 364 } |
203 else if (uccount) | 365 else if (uccount) |
204 { | 366 { |
205 /* Abbrev included some caps. Cap first initial of expansion */ | 367 /* Abbrev included some caps. Cap first initial of expansion */ |
206 Bufpos pos = wordstart; | 368 Bufpos pos = abbrev_start; |
207 | |
208 /* Find the initial. */ | 369 /* Find the initial. */ |
209 while (pos < BUF_PT (buf) | 370 while (pos < point |
210 && !WORD_SYNTAX_P (XCHAR_TABLE (buf->mirror_syntax_table), | 371 && !WORD_SYNTAX_P (XCHAR_TABLE (buf->mirror_syntax_table), |
211 BUF_FETCH_CHAR (buf, pos))) | 372 BUF_FETCH_CHAR (buf, pos))) |
212 pos++; | 373 pos++; |
213 | |
214 /* Change just that. */ | 374 /* Change just that. */ |
215 Fupcase_initials_region (make_int (pos), make_int (pos + 1), lbuf); | 375 Fupcase_initials_region (make_int (pos), make_int (pos + 1), |
216 } | 376 make_buffer (buf)); |
217 | 377 } |
218 hook = XSYMBOL (sym)->function; | 378 |
379 hook = symbol_function (abbrev_symbol); | |
219 if (!NILP (hook) && !UNBOUNDP (hook)) | 380 if (!NILP (hook) && !UNBOUNDP (hook)) |
220 call0 (hook); | 381 call0 (hook); |
221 | 382 |
222 return Qt; | 383 return Qt; |
223 } | 384 } |
385 | |
224 | 386 |
225 void | 387 void |
226 syms_of_abbrev (void) | 388 syms_of_abbrev (void) |
227 { | 389 { |
228 defsymbol (&Qpre_abbrev_expand_hook, "pre-abbrev-expand-hook"); | 390 defsymbol (&Qpre_abbrev_expand_hook, "pre-abbrev-expand-hook"); |
270 Trying to expand an abbrev in any other buffer clears `abbrev-start-location'. | 432 Trying to expand an abbrev in any other buffer clears `abbrev-start-location'. |
271 */ ); | 433 */ ); |
272 Vabbrev_start_location_buffer = Qnil; | 434 Vabbrev_start_location_buffer = Qnil; |
273 | 435 |
274 DEFVAR_BOOL ("abbrev-all-caps", &abbrev_all_caps /* | 436 DEFVAR_BOOL ("abbrev-all-caps", &abbrev_all_caps /* |
275 *Set non-nil means expand multi-word abbrevs all caps if abbrev was so. | 437 *Non-nil means expand multi-word abbrevs all caps if abbrev was so. |
276 */ ); | 438 */ ); |
277 abbrev_all_caps = 0; | 439 abbrev_all_caps = 0; |
278 | 440 |
279 DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook /* | 441 DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook /* |
280 Function or functions to be called before abbrev expansion is done. | 442 Function or functions to be called before abbrev expansion is done. |