1 /* Primitives for word-abbrev mode.
2 Copyright (C) 1985, 1986, 1993, 1996, 1998, 2001
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
33 /* An abbrev table is an obarray.
34 Each defined abbrev is represented by a symbol in that obarray
35 whose print name is the abbreviation.
36 The symbol's value is a string which is the expansion.
37 If its function definition is non-nil, it is called
38 after the expansion is done.
39 The plist slot of the abbrev symbol is its usage count. */
41 /* List of all abbrev-table name symbols:
42 symbols whose values are abbrev tables. */
44 Lisp_Object Vabbrev_table_name_list
;
46 /* The table of global abbrevs. These are in effect
47 in any buffer in which abbrev mode is turned on. */
49 Lisp_Object Vglobal_abbrev_table
;
51 /* The local abbrev table used by default (in Fundamental Mode buffers) */
53 Lisp_Object Vfundamental_mode_abbrev_table
;
55 /* Set nonzero when an abbrev definition is changed */
61 /* Non-nil => use this location as the start of abbrev to expand
62 (rather than taking the word before point as the abbrev) */
64 Lisp_Object Vabbrev_start_location
;
66 /* Buffer that Vabbrev_start_location applies to */
67 Lisp_Object Vabbrev_start_location_buffer
;
69 /* The symbol representing the abbrev most recently expanded */
71 Lisp_Object Vlast_abbrev
;
73 /* A string for the actual text of the abbrev most recently expanded.
74 This has more info than Vlast_abbrev since case is significant. */
76 Lisp_Object Vlast_abbrev_text
;
78 /* Character address of start of last abbrev expanded */
80 int last_abbrev_point
;
82 /* Hook to run before expanding any abbrev. */
84 Lisp_Object Vpre_abbrev_expand_hook
, Qpre_abbrev_expand_hook
;
86 DEFUN ("make-abbrev-table", Fmake_abbrev_table
, Smake_abbrev_table
, 0, 0, 0,
87 doc
: /* Create a new, empty abbrev table object. */)
90 return Fmake_vector (make_number (59), make_number (0));
93 DEFUN ("clear-abbrev-table", Fclear_abbrev_table
, Sclear_abbrev_table
, 1, 1, 0,
94 doc
: /* Undefine all abbrevs in abbrev table TABLE, leaving it empty. */)
100 CHECK_VECTOR (table
, 0);
101 size
= XVECTOR (table
)->size
;
103 for (i
= 0; i
< size
; i
++)
104 XVECTOR (table
)->contents
[i
] = make_number (0);
108 DEFUN ("define-abbrev", Fdefine_abbrev
, Sdefine_abbrev
, 3, 5, 0,
109 doc
: /* Define an abbrev in TABLE named NAME, to expand to EXPANSION and call HOOK.
110 NAME must be a string.
111 EXPANSION should usually be a string.
112 To undefine an abbrev, define it with EXPANSION = nil.
113 If HOOK is non-nil, it should be a function of no arguments;
114 it is called after EXPANSION is inserted.
115 If EXPANSION is not a string, the abbrev is a special one,
116 which does not expand in the usual way but only runs HOOK.
117 COUNT, if specified, initializes the abbrev's usage-count
118 which is incremented each time the abbrev is used. */)
119 (table
, name
, expansion
, hook
, count
)
120 Lisp_Object table
, name
, expansion
, hook
, count
;
122 Lisp_Object sym
, oexp
, ohook
, tem
;
123 CHECK_VECTOR (table
, 0);
124 CHECK_STRING (name
, 1);
127 count
= make_number (0);
129 CHECK_NUMBER (count
, 0);
131 sym
= Fintern (name
, table
);
133 oexp
= SYMBOL_VALUE (sym
);
134 ohook
= XSYMBOL (sym
)->function
;
135 if (!((EQ (oexp
, expansion
)
136 || (STRINGP (oexp
) && STRINGP (expansion
)
137 && (tem
= Fstring_equal (oexp
, expansion
), !NILP (tem
))))
140 || (tem
= Fequal (ohook
, hook
), !NILP (tem
)))))
143 Fset (sym
, expansion
);
145 Fsetplist (sym
, count
);
150 DEFUN ("define-global-abbrev", Fdefine_global_abbrev
, Sdefine_global_abbrev
, 2, 2,
151 "sDefine global abbrev: \nsExpansion for %s: ",
152 doc
: /* Define ABBREV as a global abbreviation for EXPANSION. */)
154 Lisp_Object abbrev
, expansion
;
156 Fdefine_abbrev (Vglobal_abbrev_table
, Fdowncase (abbrev
),
157 expansion
, Qnil
, make_number (0));
161 DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev
, Sdefine_mode_abbrev
, 2, 2,
162 "sDefine mode abbrev: \nsExpansion for %s: ",
163 doc
: /* Define ABBREV as a mode-specific abbreviation for EXPANSION. */)
165 Lisp_Object abbrev
, expansion
;
167 if (NILP (current_buffer
->abbrev_table
))
168 error ("Major mode has no abbrev table");
170 Fdefine_abbrev (current_buffer
->abbrev_table
, Fdowncase (abbrev
),
171 expansion
, Qnil
, make_number (0));
175 DEFUN ("abbrev-symbol", Fabbrev_symbol
, Sabbrev_symbol
, 1, 2, 0,
176 doc
: /* Return the symbol representing abbrev named ABBREV.
177 This symbol's name is ABBREV, but it is not the canonical symbol of that name;
178 it is interned in an abbrev-table rather than the normal obarray.
179 The value is nil if that abbrev is not defined.
180 Optional second arg TABLE is abbrev table to look it up in.
181 The default is to try buffer's mode-specific abbrev table, then global table. */)
183 Lisp_Object abbrev
, table
;
186 CHECK_STRING (abbrev
, 0);
188 sym
= Fintern_soft (abbrev
, table
);
192 if (!NILP (current_buffer
->abbrev_table
))
193 sym
= Fintern_soft (abbrev
, current_buffer
->abbrev_table
);
194 if (NILP (SYMBOL_VALUE (sym
)))
197 sym
= Fintern_soft (abbrev
, Vglobal_abbrev_table
);
199 if (NILP (SYMBOL_VALUE (sym
)))
204 DEFUN ("abbrev-expansion", Fabbrev_expansion
, Sabbrev_expansion
, 1, 2, 0,
205 doc
: /* Return the string that ABBREV expands into in the current buffer.
206 Optionally specify an abbrev table as second arg;
207 then ABBREV is looked up in that table only. */)
209 Lisp_Object abbrev
, table
;
212 sym
= Fabbrev_symbol (abbrev
, table
);
213 if (NILP (sym
)) return sym
;
214 return Fsymbol_value (sym
);
217 /* Expand the word before point, if it is an abbrev.
218 Returns 1 if an expansion is done. */
220 DEFUN ("expand-abbrev", Fexpand_abbrev
, Sexpand_abbrev
, 0, 0, "",
221 doc
: /* Expand the abbrev before point, if there is an abbrev there.
222 Effective when explicitly called even when `abbrev-mode' is nil.
223 Returns the abbrev symbol, if expansion took place. */)
226 register char *buffer
, *p
;
227 int wordstart
, wordend
;
228 register int wordstart_byte
, wordend_byte
, idx
;
230 int uccount
= 0, lccount
= 0;
231 register Lisp_Object sym
;
232 Lisp_Object expansion
, hook
, tem
;
237 if (!NILP (Vrun_hooks
))
238 call1 (Vrun_hooks
, Qpre_abbrev_expand_hook
);
241 if (!(BUFFERP (Vabbrev_start_location_buffer
)
242 && XBUFFER (Vabbrev_start_location_buffer
) == current_buffer
))
243 Vabbrev_start_location
= Qnil
;
244 if (!NILP (Vabbrev_start_location
))
246 tem
= Vabbrev_start_location
;
247 CHECK_NUMBER_COERCE_MARKER (tem
, 0);
248 wordstart
= XINT (tem
);
249 Vabbrev_start_location
= Qnil
;
250 if (wordstart
< BEGV
|| wordstart
> ZV
)
252 if (wordstart
&& wordstart
!= ZV
)
254 wordstart_byte
= CHAR_TO_BYTE (wordstart
);
255 if (FETCH_BYTE (wordstart_byte
) == '-')
256 del_range (wordstart
, wordstart
+ 1);
260 wordstart
= scan_words (PT
, -1);
265 wordstart_byte
= CHAR_TO_BYTE (wordstart
);
266 wordend
= scan_words (wordstart
, 1);
273 wordend_byte
= CHAR_TO_BYTE (wordend
);
274 whitecnt
= PT
- wordend
;
275 if (wordend
<= wordstart
)
278 p
= buffer
= (char *) alloca (wordend_byte
- wordstart_byte
);
280 for (idx
= wordstart_byte
; idx
< wordend_byte
; idx
++)
282 /* ??? This loop needs to go by characters! */
283 register int c
= FETCH_BYTE (idx
);
285 c
= DOWNCASE (c
), uccount
++;
286 else if (! NOCASEP (c
))
291 if (VECTORP (current_buffer
->abbrev_table
))
292 sym
= oblookup (current_buffer
->abbrev_table
, buffer
,
293 wordend
- wordstart
, wordend_byte
- wordstart_byte
);
295 XSETFASTINT (sym
, 0);
296 if (INTEGERP (sym
) || NILP (SYMBOL_VALUE (sym
)))
297 sym
= oblookup (Vglobal_abbrev_table
, buffer
,
298 wordend
- wordstart
, wordend_byte
- wordstart_byte
);
299 if (INTEGERP (sym
) || NILP (SYMBOL_VALUE (sym
)))
302 if (INTERACTIVE
&& !EQ (minibuf_window
, selected_window
))
304 /* Add an undo boundary, in case we are doing this for
305 a self-inserting command which has avoided making one so far. */
311 = Fbuffer_substring (make_number (wordstart
), make_number (wordend
));
313 /* Now sym is the abbrev symbol. */
316 last_abbrev_point
= wordstart
;
318 if (INTEGERP (XSYMBOL (sym
)->plist
))
319 XSETINT (XSYMBOL (sym
)->plist
,
320 XINT (XSYMBOL (sym
)->plist
) + 1); /* Increment use count */
322 /* If this abbrev has an expansion, delete the abbrev
323 and insert the expansion. */
324 expansion
= SYMBOL_VALUE (sym
);
325 if (STRINGP (expansion
))
329 del_range_both (wordstart
, wordstart_byte
, wordend
, wordend_byte
, 1);
331 insert_from_string (expansion
, 0, 0, XSTRING (expansion
)->size
,
332 STRING_BYTES (XSTRING (expansion
)), 1);
333 SET_PT (PT
+ whitecnt
);
335 if (uccount
&& !lccount
)
337 /* Abbrev was all caps */
338 /* If expansion is multiple words, normally capitalize each word */
339 /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
340 but Megatest 68000 compiler can't handle that */
341 if (!abbrev_all_caps
)
342 if (scan_words (PT
, -1) > scan_words (wordstart
, 1))
344 Fupcase_initials_region (make_number (wordstart
),
348 /* If expansion is one word, or if user says so, upcase it all. */
349 Fupcase_region (make_number (wordstart
), make_number (PT
));
354 /* Abbrev included some caps. Cap first initial of expansion */
355 int pos
= wordstart_byte
;
357 /* Find the initial. */
359 && SYNTAX (*BUF_BYTE_ADDRESS (current_buffer
, pos
)) != Sword
)
362 /* Change just that. */
363 pos
= BYTE_TO_CHAR (pos
);
364 Fupcase_initials_region (make_number (pos
), make_number (pos
+ 1));
368 hook
= XSYMBOL (sym
)->function
;
371 Lisp_Object expanded
, prop
;
373 /* If the abbrev has a hook function, run it. */
374 expanded
= call0 (hook
);
376 /* In addition, if the hook function is a symbol with a a
377 non-nil `no-self-insert' property, let the value it returned
378 specify whether we consider that an expansion took place. If
379 it returns nil, no expansion has been done. */
383 && (prop
= Fget (hook
, intern ("no-self-insert")),
391 DEFUN ("unexpand-abbrev", Funexpand_abbrev
, Sunexpand_abbrev
, 0, 0, "",
392 doc
: /* Undo the expansion of the last abbrev that expanded.
393 This differs from ordinary undo in that other editing done since then
399 if (last_abbrev_point
< BEGV
400 || last_abbrev_point
> ZV
)
402 SET_PT (last_abbrev_point
);
403 if (STRINGP (Vlast_abbrev_text
))
405 /* This isn't correct if Vlast_abbrev->function was used
406 to do the expansion */
410 val
= SYMBOL_VALUE (Vlast_abbrev
);
412 error ("value of abbrev-symbol must be a string");
414 del_range_byte (PT_BYTE
, PT_BYTE
+ STRING_BYTES (XSTRING (val
)), 1);
415 /* Don't inherit properties here; just copy from old contents. */
416 insert_from_string (Vlast_abbrev_text
, 0, 0,
417 XSTRING (Vlast_abbrev_text
)->size
,
418 STRING_BYTES (XSTRING (Vlast_abbrev_text
)), 0);
419 Vlast_abbrev_text
= Qnil
;
420 /* Total number of characters deleted. */
421 adjust
= ZV
- zv_before
;
423 SET_PT (last_abbrev_point
< opoint
? opoint
+ adjust
: opoint
);
428 write_abbrev (sym
, stream
)
429 Lisp_Object sym
, stream
;
432 if (NILP (SYMBOL_VALUE (sym
)))
435 XSETSTRING (name
, XSYMBOL (sym
)->name
);
436 Fprin1 (name
, stream
);
438 Fprin1 (SYMBOL_VALUE (sym
), stream
);
440 Fprin1 (XSYMBOL (sym
)->function
, stream
);
442 Fprin1 (XSYMBOL (sym
)->plist
, stream
);
447 describe_abbrev (sym
, stream
)
448 Lisp_Object sym
, stream
;
452 if (NILP (SYMBOL_VALUE (sym
)))
454 one
= make_number (1);
455 Fprin1 (Fsymbol_name (sym
), stream
);
456 Findent_to (make_number (15), one
);
457 Fprin1 (XSYMBOL (sym
)->plist
, stream
);
458 Findent_to (make_number (20), one
);
459 Fprin1 (SYMBOL_VALUE (sym
), stream
);
460 if (!NILP (XSYMBOL (sym
)->function
))
462 Findent_to (make_number (45), one
);
463 Fprin1 (XSYMBOL (sym
)->function
, stream
);
468 DEFUN ("insert-abbrev-table-description", Finsert_abbrev_table_description
,
469 Sinsert_abbrev_table_description
, 1, 2, 0,
470 doc
: /* Insert before point a full description of abbrev table named NAME.
471 NAME is a symbol whose value is an abbrev table.
472 If optional 2nd arg READABLE is non-nil, a human-readable description
473 is inserted. Otherwise the description is an expression,
474 a call to `define-abbrev-table', which would
475 define the abbrev table NAME exactly as it is currently defined. */)
477 Lisp_Object name
, readable
;
482 CHECK_SYMBOL (name
, 0);
483 table
= Fsymbol_value (name
);
484 CHECK_VECTOR (table
, 0);
486 XSETBUFFER (stream
, current_buffer
);
488 if (!NILP (readable
))
491 Fprin1 (name
, stream
);
492 insert_string (")\n\n");
493 map_obarray (table
, describe_abbrev
, stream
);
494 insert_string ("\n\n");
498 insert_string ("(define-abbrev-table '");
499 Fprin1 (name
, stream
);
500 insert_string (" '(\n");
501 map_obarray (table
, write_abbrev
, stream
);
502 insert_string (" ))\n\n");
508 DEFUN ("define-abbrev-table", Fdefine_abbrev_table
, Sdefine_abbrev_table
,
510 doc
: /* Define TABLENAME (a symbol) as an abbrev table name.
511 Define abbrevs in it according to DEFINITIONS, which is a list of elements
512 of the form (ABBREVNAME EXPANSION HOOK USECOUNT). */)
513 (tablename
, definitions
)
514 Lisp_Object tablename
, definitions
;
516 Lisp_Object name
, exp
, hook
, count
;
517 Lisp_Object table
, elt
;
519 CHECK_SYMBOL (tablename
, 0);
520 table
= Fboundp (tablename
);
521 if (NILP (table
) || (table
= Fsymbol_value (tablename
), NILP (table
)))
523 table
= Fmake_abbrev_table ();
524 Fset (tablename
, table
);
525 Vabbrev_table_name_list
= Fcons (tablename
, Vabbrev_table_name_list
);
527 CHECK_VECTOR (table
, 0);
529 for (; !NILP (definitions
); definitions
= Fcdr (definitions
))
531 elt
= Fcar (definitions
);
532 name
= Fcar (elt
); elt
= Fcdr (elt
);
533 exp
= Fcar (elt
); elt
= Fcdr (elt
);
534 hook
= Fcar (elt
); elt
= Fcdr (elt
);
536 Fdefine_abbrev (table
, name
, exp
, hook
, count
);
544 DEFVAR_LISP ("abbrev-table-name-list", &Vabbrev_table_name_list
,
545 doc
: /* List of symbols whose values are abbrev tables. */);
546 Vabbrev_table_name_list
= Fcons (intern ("fundamental-mode-abbrev-table"),
547 Fcons (intern ("global-abbrev-table"),
550 DEFVAR_LISP ("global-abbrev-table", &Vglobal_abbrev_table
,
551 doc
: /* The abbrev table whose abbrevs affect all buffers.
552 Each buffer may also have a local abbrev table.
553 If it does, the local table overrides the global one
554 for any particular abbrev defined in both. */);
555 Vglobal_abbrev_table
= Fmake_abbrev_table ();
557 DEFVAR_LISP ("fundamental-mode-abbrev-table", &Vfundamental_mode_abbrev_table
,
558 doc
: /* The abbrev table of mode-specific abbrevs for Fundamental Mode. */);
559 Vfundamental_mode_abbrev_table
= Fmake_abbrev_table ();
560 current_buffer
->abbrev_table
= Vfundamental_mode_abbrev_table
;
561 buffer_defaults
.abbrev_table
= Vfundamental_mode_abbrev_table
;
563 DEFVAR_LISP ("last-abbrev", &Vlast_abbrev
,
564 doc
: /* The abbrev-symbol of the last abbrev expanded. See `abbrev-symbol'. */);
566 DEFVAR_LISP ("last-abbrev-text", &Vlast_abbrev_text
,
567 doc
: /* The exact text of the last abbrev expanded.
568 nil if the abbrev has already been unexpanded. */);
570 DEFVAR_INT ("last-abbrev-location", &last_abbrev_point
,
571 doc
: /* The location of the start of the last abbrev expanded. */);
574 Vlast_abbrev_text
= Qnil
;
575 last_abbrev_point
= 0;
577 DEFVAR_LISP ("abbrev-start-location", &Vabbrev_start_location
,
578 doc
: /* Buffer position for `expand-abbrev' to use as the start of the abbrev.
579 nil means use the word before point as the abbrev.
580 Calling `expand-abbrev' sets this to nil. */);
581 Vabbrev_start_location
= Qnil
;
583 DEFVAR_LISP ("abbrev-start-location-buffer", &Vabbrev_start_location_buffer
,
584 doc
: /* Buffer that `abbrev-start-location' has been set for.
585 Trying to expand an abbrev in any other buffer clears `abbrev-start-location'. */);
586 Vabbrev_start_location_buffer
= Qnil
;
588 DEFVAR_PER_BUFFER ("local-abbrev-table", ¤t_buffer
->abbrev_table
, Qnil
,
589 doc
: /* Local (mode-specific) abbrev table of current buffer. */);
591 DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed
,
592 doc
: /* Set non-nil by defining or altering any word abbrevs.
593 This causes `save-some-buffers' to offer to save the abbrevs. */);
596 DEFVAR_BOOL ("abbrev-all-caps", &abbrev_all_caps
,
597 doc
: /* *Set non-nil means expand multi-word abbrevs all caps if abbrev was so. */);
600 DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook
,
601 doc
: /* Function or functions to be called before abbrev expansion is done.
602 This is the first thing that `expand-abbrev' does, and so this may change
603 the current abbrev table before abbrev lookup happens. */);
604 Vpre_abbrev_expand_hook
= Qnil
;
605 Qpre_abbrev_expand_hook
= intern ("pre-abbrev-expand-hook");
606 staticpro (&Qpre_abbrev_expand_hook
);
608 defsubr (&Smake_abbrev_table
);
609 defsubr (&Sclear_abbrev_table
);
610 defsubr (&Sdefine_abbrev
);
611 defsubr (&Sdefine_global_abbrev
);
612 defsubr (&Sdefine_mode_abbrev
);
613 defsubr (&Sabbrev_expansion
);
614 defsubr (&Sabbrev_symbol
);
615 defsubr (&Sexpand_abbrev
);
616 defsubr (&Sunexpand_abbrev
);
617 defsubr (&Sinsert_abbrev_table_description
);
618 defsubr (&Sdefine_abbrev_table
);