*** empty log message ***
[bpt/emacs.git] / src / abbrev.c
CommitLineData
7942b8ae 1/* Primitives for word-abbrev mode.
a97569cb
GM
2 Copyright (C) 1985, 1986, 1993, 1996, 1998, 2001
3 Free Software Foundation, Inc.
7942b8ae
RS
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
c89475dc 9the Free Software Foundation; either version 2, or (at your option)
7942b8ae
RS
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
7942b8ae
RS
21
22
18160b98 23#include <config.h>
7942b8ae 24#include <stdio.h>
7ee72033 25
7942b8ae
RS
26#include "lisp.h"
27#include "commands.h"
28#include "buffer.h"
29#include "window.h"
83be827a 30#include "character.h"
7169beb1 31#include "syntax.h"
7942b8ae
RS
32
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. */
40
41/* List of all abbrev-table name symbols:
42 symbols whose values are abbrev tables. */
43
44Lisp_Object Vabbrev_table_name_list;
45
46/* The table of global abbrevs. These are in effect
47 in any buffer in which abbrev mode is turned on. */
48
49Lisp_Object Vglobal_abbrev_table;
50
51/* The local abbrev table used by default (in Fundamental Mode buffers) */
52
53Lisp_Object Vfundamental_mode_abbrev_table;
54
55/* Set nonzero when an abbrev definition is changed */
56
57int abbrevs_changed;
58
59int abbrev_all_caps;
60
61/* Non-nil => use this location as the start of abbrev to expand
62 (rather than taking the word before point as the abbrev) */
63
64Lisp_Object Vabbrev_start_location;
65
66/* Buffer that Vabbrev_start_location applies to */
67Lisp_Object Vabbrev_start_location_buffer;
68
69/* The symbol representing the abbrev most recently expanded */
70
71Lisp_Object Vlast_abbrev;
72
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. */
75
76Lisp_Object Vlast_abbrev_text;
77
78/* Character address of start of last abbrev expanded */
79
31ade731 80EMACS_INT last_abbrev_point;
7942b8ae 81
dbd7a969
RS
82/* Hook to run before expanding any abbrev. */
83
84Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook;
2d6c1fc0
RS
85
86Lisp_Object Qsystem_type, Qcount;
7942b8ae
RS
87\f
88DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
7ee72033
MB
89 doc: /* Create a new, empty abbrev table object. */)
90 ()
7942b8ae 91{
da2ba5c6 92 /* The value 59 is arbitrary chosen prime number. */
7942b8ae
RS
93 return Fmake_vector (make_number (59), make_number (0));
94}
95
96DEFUN ("clear-abbrev-table", Fclear_abbrev_table, Sclear_abbrev_table, 1, 1, 0,
7ee72033
MB
97 doc: /* Undefine all abbrevs in abbrev table TABLE, leaving it empty. */)
98 (table)
7942b8ae
RS
99 Lisp_Object table;
100{
101 int i, size;
102
b7826503 103 CHECK_VECTOR (table);
7942b8ae
RS
104 size = XVECTOR (table)->size;
105 abbrevs_changed = 1;
106 for (i = 0; i < size; i++)
107 XVECTOR (table)->contents[i] = make_number (0);
108 return Qnil;
109}
110\f
2d6c1fc0 111DEFUN ("define-abbrev", Fdefine_abbrev, Sdefine_abbrev, 3, 6, 0,
7ee72033 112 doc: /* Define an abbrev in TABLE named NAME, to expand to EXPANSION and call HOOK.
b39fb64b
PJ
113NAME must be a string.
114EXPANSION should usually be a string.
115To undefine an abbrev, define it with EXPANSION = nil.
116If HOOK is non-nil, it should be a function of no arguments;
117it is called after EXPANSION is inserted.
118If EXPANSION is not a string, the abbrev is a special one,
119 which does not expand in the usual way but only runs HOOK.
2d6c1fc0
RS
120
121COUNT, if specified, gives the initial value for the abbrev's
122usage-count, which is incremented each time the abbrev is used.
123\(The default is zero.)
124
125SYSTEM-FLAG, if non-nil, says that this is a "system" abbreviation
126which should not be saved in the user's abbreviation file. */)
127 (table, name, expansion, hook, count, system_flag)
128 Lisp_Object table, name, expansion, hook, count, system_flag;
7942b8ae
RS
129{
130 Lisp_Object sym, oexp, ohook, tem;
b7826503
PJ
131 CHECK_VECTOR (table);
132 CHECK_STRING (name);
b7734773 133
d427b66a 134 if (NILP (count))
7942b8ae
RS
135 count = make_number (0);
136 else
b7826503 137 CHECK_NUMBER (count);
7942b8ae
RS
138
139 sym = Fintern (name, table);
140
a97569cb 141 oexp = SYMBOL_VALUE (sym);
7942b8ae
RS
142 ohook = XSYMBOL (sym)->function;
143 if (!((EQ (oexp, expansion)
09e82d7c 144 || (STRINGP (oexp) && STRINGP (expansion)
d427b66a 145 && (tem = Fstring_equal (oexp, expansion), !NILP (tem))))
7942b8ae
RS
146 &&
147 (EQ (ohook, hook)
2d6c1fc0
RS
148 || (tem = Fequal (ohook, hook), !NILP (tem))))
149 && NILP (system_flag))
7942b8ae
RS
150 abbrevs_changed = 1;
151
152 Fset (sym, expansion);
153 Ffset (sym, hook);
2d6c1fc0
RS
154
155 if (! NILP (system_flag))
156 Fsetplist (sym, list4 (Qcount, count, Qsystem_type, system_flag));
157 else
158 Fsetplist (sym, count);
7942b8ae
RS
159
160 return name;
161}
162
163DEFUN ("define-global-abbrev", Fdefine_global_abbrev, Sdefine_global_abbrev, 2, 2,
b39fb64b 164 "sDefine global abbrev: \nsExpansion for %s: ",
7ee72033
MB
165 doc: /* Define ABBREV as a global abbreviation for EXPANSION. */)
166 (abbrev, expansion)
78ce396a 167 Lisp_Object abbrev, expansion;
7942b8ae 168{
78ce396a 169 Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (abbrev),
2d6c1fc0 170 expansion, Qnil, make_number (0), Qnil);
78ce396a 171 return abbrev;
7942b8ae
RS
172}
173
174DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev, Sdefine_mode_abbrev, 2, 2,
b39fb64b 175 "sDefine mode abbrev: \nsExpansion for %s: ",
7ee72033
MB
176 doc: /* Define ABBREV as a mode-specific abbreviation for EXPANSION. */)
177 (abbrev, expansion)
78ce396a 178 Lisp_Object abbrev, expansion;
7942b8ae 179{
d427b66a 180 if (NILP (current_buffer->abbrev_table))
7942b8ae
RS
181 error ("Major mode has no abbrev table");
182
78ce396a 183 Fdefine_abbrev (current_buffer->abbrev_table, Fdowncase (abbrev),
2d6c1fc0 184 expansion, Qnil, make_number (0), Qnil);
78ce396a 185 return abbrev;
7942b8ae
RS
186}
187
188DEFUN ("abbrev-symbol", Fabbrev_symbol, Sabbrev_symbol, 1, 2, 0,
7ee72033 189 doc: /* Return the symbol representing abbrev named ABBREV.
b39fb64b
PJ
190This symbol's name is ABBREV, but it is not the canonical symbol of that name;
191it is interned in an abbrev-table rather than the normal obarray.
192The value is nil if that abbrev is not defined.
193Optional second arg TABLE is abbrev table to look it up in.
7ee72033
MB
194The default is to try buffer's mode-specific abbrev table, then global table. */)
195 (abbrev, table)
7942b8ae
RS
196 Lisp_Object abbrev, table;
197{
198 Lisp_Object sym;
b7826503 199 CHECK_STRING (abbrev);
d427b66a 200 if (!NILP (table))
7942b8ae
RS
201 sym = Fintern_soft (abbrev, table);
202 else
203 {
204 sym = Qnil;
d427b66a 205 if (!NILP (current_buffer->abbrev_table))
7942b8ae 206 sym = Fintern_soft (abbrev, current_buffer->abbrev_table);
a97569cb 207 if (NILP (SYMBOL_VALUE (sym)))
7942b8ae 208 sym = Qnil;
d427b66a 209 if (NILP (sym))
7942b8ae
RS
210 sym = Fintern_soft (abbrev, Vglobal_abbrev_table);
211 }
a97569cb
GM
212 if (NILP (SYMBOL_VALUE (sym)))
213 return Qnil;
7942b8ae
RS
214 return sym;
215}
216
217DEFUN ("abbrev-expansion", Fabbrev_expansion, Sabbrev_expansion, 1, 2, 0,
7ee72033 218 doc: /* Return the string that ABBREV expands into in the current buffer.
b39fb64b 219Optionally specify an abbrev table as second arg;
7ee72033
MB
220then ABBREV is looked up in that table only. */)
221 (abbrev, table)
7942b8ae
RS
222 Lisp_Object abbrev, table;
223{
224 Lisp_Object sym;
225 sym = Fabbrev_symbol (abbrev, table);
d427b66a 226 if (NILP (sym)) return sym;
7942b8ae
RS
227 return Fsymbol_value (sym);
228}
229\f
230/* Expand the word before point, if it is an abbrev.
231 Returns 1 if an expansion is done. */
232
233DEFUN ("expand-abbrev", Fexpand_abbrev, Sexpand_abbrev, 0, 0, "",
7ee72033 234 doc: /* Expand the abbrev before point, if there is an abbrev there.
b39fb64b 235Effective when explicitly called even when `abbrev-mode' is nil.
7ee72033
MB
236Returns the abbrev symbol, if expansion took place. */)
237 ()
7942b8ae
RS
238{
239 register char *buffer, *p;
aa406bac 240 int wordstart, wordend;
530e0751 241 register int wordstart_byte, wordend_byte, idx, idx_byte;
7942b8ae
RS
242 int whitecnt;
243 int uccount = 0, lccount = 0;
244 register Lisp_Object sym;
245 Lisp_Object expansion, hook, tem;
ba70da8f 246 Lisp_Object value;
530e0751 247 int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
7942b8ae 248
f530ce27
RS
249 value = Qnil;
250
6a15331f 251 Frun_hooks (1, &Qpre_abbrev_expand_hook);
dbd7a969 252
dc7e2b30 253 wordstart = 0;
f530ce27
RS
254 if (!(BUFFERP (Vabbrev_start_location_buffer)
255 && XBUFFER (Vabbrev_start_location_buffer) == current_buffer))
7942b8ae 256 Vabbrev_start_location = Qnil;
d427b66a 257 if (!NILP (Vabbrev_start_location))
7942b8ae
RS
258 {
259 tem = Vabbrev_start_location;
b7826503 260 CHECK_NUMBER_COERCE_MARKER (tem);
7942b8ae
RS
261 wordstart = XINT (tem);
262 Vabbrev_start_location = Qnil;
dc7e2b30
KH
263 if (wordstart < BEGV || wordstart > ZV)
264 wordstart = 0;
aa406bac
RS
265 if (wordstart && wordstart != ZV)
266 {
267 wordstart_byte = CHAR_TO_BYTE (wordstart);
268 if (FETCH_BYTE (wordstart_byte) == '-')
269 del_range (wordstart, wordstart + 1);
270 }
7942b8ae 271 }
dc7e2b30 272 if (!wordstart)
6ec8bbd2 273 wordstart = scan_words (PT, -1);
7942b8ae
RS
274
275 if (!wordstart)
ba70da8f 276 return value;
7942b8ae 277
aa406bac 278 wordstart_byte = CHAR_TO_BYTE (wordstart);
7942b8ae
RS
279 wordend = scan_words (wordstart, 1);
280 if (!wordend)
ba70da8f 281 return value;
7942b8ae 282
6ec8bbd2
KH
283 if (wordend > PT)
284 wordend = PT;
aa406bac
RS
285
286 wordend_byte = CHAR_TO_BYTE (wordend);
6ec8bbd2 287 whitecnt = PT - wordend;
7942b8ae 288 if (wordend <= wordstart)
ba70da8f 289 return value;
7942b8ae 290
aa406bac 291 p = buffer = (char *) alloca (wordend_byte - wordstart_byte);
7942b8ae 292
530e0751 293 for (idx = wordstart, idx_byte = wordstart_byte; idx < wordend; )
7942b8ae 294 {
530e0751
KH
295 register int c;
296
297 if (multibyte)
298 {
299 FETCH_CHAR_ADVANCE (c, idx, idx_byte);
300 }
301 else
302 {
303 c = FETCH_BYTE (idx_byte);
304 idx++, idx_byte++;
305 }
177c0ea7 306
7942b8ae
RS
307 if (UPPERCASEP (c))
308 c = DOWNCASE (c), uccount++;
309 else if (! NOCASEP (c))
310 lccount++;
530e0751
KH
311 if (multibyte)
312 p += CHAR_STRING (c, p);
313 else
314 *p++ = c;
7942b8ae
RS
315 }
316
09e82d7c 317 if (VECTORP (current_buffer->abbrev_table))
fc412686 318 sym = oblookup (current_buffer->abbrev_table, buffer,
530e0751 319 wordend - wordstart, p - buffer);
7942b8ae 320 else
2a43e2bc 321 XSETFASTINT (sym, 0);
2d6c1fc0 322
a97569cb 323 if (INTEGERP (sym) || NILP (SYMBOL_VALUE (sym)))
fc412686 324 sym = oblookup (Vglobal_abbrev_table, buffer,
530e0751 325 wordend - wordstart, p - buffer);
a97569cb 326 if (INTEGERP (sym) || NILP (SYMBOL_VALUE (sym)))
ba70da8f 327 return value;
7942b8ae
RS
328
329 if (INTERACTIVE && !EQ (minibuf_window, selected_window))
330 {
aba686ed
RS
331 /* Add an undo boundary, in case we are doing this for
332 a self-inserting command which has avoided making one so far. */
7942b8ae
RS
333 SET_PT (wordend);
334 Fundo_boundary ();
335 }
b7734773 336
7942b8ae
RS
337 Vlast_abbrev_text
338 = Fbuffer_substring (make_number (wordstart), make_number (wordend));
7942b8ae 339
b7734773 340 /* Now sym is the abbrev symbol. */
7942b8ae 341 Vlast_abbrev = sym;
f530ce27 342 value = sym;
7942b8ae
RS
343 last_abbrev_point = wordstart;
344
2d6c1fc0 345 /* Increment use count. */
09e82d7c 346 if (INTEGERP (XSYMBOL (sym)->plist))
7942b8ae 347 XSETINT (XSYMBOL (sym)->plist,
2d6c1fc0 348 XINT (XSYMBOL (sym)->plist) + 1);
8d320872 349 else if (INTEGERP (tem = Fget (sym, Qcount)))
2d6c1fc0 350 Fput (sym, Qcount, make_number (XINT (tem) + 1));
7942b8ae 351
b7734773
RS
352 /* If this abbrev has an expansion, delete the abbrev
353 and insert the expansion. */
a97569cb 354 expansion = SYMBOL_VALUE (sym);
b7734773 355 if (STRINGP (expansion))
7942b8ae 356 {
b7734773
RS
357 SET_PT (wordstart);
358
463f5630
KH
359 del_range_both (wordstart, wordstart_byte, wordend, wordend_byte, 1);
360
d5db4077
KR
361 insert_from_string (expansion, 0, 0, SCHARS (expansion),
362 SBYTES (expansion), 1);
b7734773
RS
363 SET_PT (PT + whitecnt);
364
365 if (uccount && !lccount)
366 {
367 /* Abbrev was all caps */
368 /* If expansion is multiple words, normally capitalize each word */
369 /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
370 but Megatest 68000 compiler can't handle that */
371 if (!abbrev_all_caps)
372 if (scan_words (PT, -1) > scan_words (wordstart, 1))
373 {
374 Fupcase_initials_region (make_number (wordstart),
375 make_number (PT));
376 goto caped;
377 }
378 /* If expansion is one word, or if user says so, upcase it all. */
379 Fupcase_region (make_number (wordstart), make_number (PT));
380 caped: ;
381 }
382 else if (uccount)
383 {
384 /* Abbrev included some caps. Cap first initial of expansion */
aa406bac 385 int pos = wordstart_byte;
b7734773
RS
386
387 /* Find the initial. */
8f924df7
KH
388 if (multibyte)
389 while (pos < PT_BYTE
390 && SYNTAX (FETCH_MULTIBYTE_CHAR (pos)) != Sword)
391 INC_POS (pos);
392 else
393 while (pos < PT_BYTE
394 && (SYNTAX (*BUF_BYTE_ADDRESS (current_buffer, pos))
395 != Sword))
396 pos++;
b7734773
RS
397
398 /* Change just that. */
aa406bac 399 pos = BYTE_TO_CHAR (pos);
b7734773
RS
400 Fupcase_initials_region (make_number (pos), make_number (pos + 1));
401 }
7942b8ae
RS
402 }
403
404 hook = XSYMBOL (sym)->function;
d427b66a 405 if (!NILP (hook))
79d2af9c
GM
406 {
407 Lisp_Object expanded, prop;
408
c87dbfd0 409 /* If the abbrev has a hook function, run it. */
79d2af9c 410 expanded = call0 (hook);
c87dbfd0 411
ca70e62f
PJ
412 /* In addition, if the hook function is a symbol with
413 a non-nil `no-self-insert' property, let the value it returned
c87dbfd0
RS
414 specify whether we consider that an expansion took place. If
415 it returns nil, no expansion has been done. */
416
79d2af9c
GM
417 if (SYMBOLP (hook)
418 && NILP (expanded)
419 && (prop = Fget (hook, intern ("no-self-insert")),
420 !NILP (prop)))
421 value = Qnil;
422 }
7942b8ae 423
f530ce27 424 return value;
7942b8ae
RS
425}
426
427DEFUN ("unexpand-abbrev", Funexpand_abbrev, Sunexpand_abbrev, 0, 0, "",
7ee72033 428 doc: /* Undo the expansion of the last abbrev that expanded.
b39fb64b 429This differs from ordinary undo in that other editing done since then
7ee72033
MB
430is not undone. */)
431 ()
7942b8ae 432{
6ec8bbd2 433 int opoint = PT;
7942b8ae
RS
434 int adjust = 0;
435 if (last_abbrev_point < BEGV
436 || last_abbrev_point > ZV)
437 return Qnil;
438 SET_PT (last_abbrev_point);
09e82d7c 439 if (STRINGP (Vlast_abbrev_text))
7942b8ae
RS
440 {
441 /* This isn't correct if Vlast_abbrev->function was used
442 to do the expansion */
443 Lisp_Object val;
aa406bac
RS
444 int zv_before;
445
a97569cb 446 val = SYMBOL_VALUE (Vlast_abbrev);
09e82d7c 447 if (!STRINGP (val))
4458687c 448 error ("value of abbrev-symbol must be a string");
aa406bac 449 zv_before = ZV;
d5db4077 450 del_range_byte (PT_BYTE, PT_BYTE + SBYTES (val), 1);
0c287112 451 /* Don't inherit properties here; just copy from old contents. */
fc412686 452 insert_from_string (Vlast_abbrev_text, 0, 0,
d5db4077
KR
453 SCHARS (Vlast_abbrev_text),
454 SBYTES (Vlast_abbrev_text), 0);
7942b8ae 455 Vlast_abbrev_text = Qnil;
aa406bac
RS
456 /* Total number of characters deleted. */
457 adjust = ZV - zv_before;
7942b8ae 458 }
57522629 459 SET_PT (last_abbrev_point < opoint ? opoint + adjust : opoint);
7942b8ae
RS
460 return Qnil;
461}
462\f
aa406bac 463static void
7942b8ae
RS
464write_abbrev (sym, stream)
465 Lisp_Object sym, stream;
466{
2d6c1fc0
RS
467 Lisp_Object name, count, system_flag;
468
469 if (INTEGERP (XSYMBOL (sym)->plist))
470 {
471 count = XSYMBOL (sym)->plist;
472 system_flag = Qnil;
473 }
474 else
475 {
476 count = Fget (sym, Qcount);
477 system_flag = Fget (sym, Qsystem_type);
478 }
479
480 if (NILP (SYMBOL_VALUE (sym)) || ! NILP (system_flag))
7942b8ae 481 return;
2d6c1fc0 482
7942b8ae 483 insert (" (", 5);
caeead20 484 name = SYMBOL_NAME (sym);
7942b8ae
RS
485 Fprin1 (name, stream);
486 insert (" ", 1);
a97569cb 487 Fprin1 (SYMBOL_VALUE (sym), stream);
7942b8ae
RS
488 insert (" ", 1);
489 Fprin1 (XSYMBOL (sym)->function, stream);
490 insert (" ", 1);
2d6c1fc0 491 Fprin1 (count, stream);
7942b8ae
RS
492 insert (")\n", 2);
493}
494
aa406bac 495static void
7942b8ae
RS
496describe_abbrev (sym, stream)
497 Lisp_Object sym, stream;
498{
2d6c1fc0
RS
499 Lisp_Object one, count, system_flag;
500
501 if (INTEGERP (XSYMBOL (sym)->plist))
502 {
503 count = XSYMBOL (sym)->plist;
504 system_flag = Qnil;
505 }
506 else
507 {
508 count = Fget (sym, Qcount);
509 system_flag = Fget (sym, Qsystem_type);
510 }
7942b8ae 511
a97569cb 512 if (NILP (SYMBOL_VALUE (sym)))
7942b8ae 513 return;
2d6c1fc0 514
7942b8ae
RS
515 one = make_number (1);
516 Fprin1 (Fsymbol_name (sym), stream);
2d6c1fc0
RS
517
518 if (!NILP (system_flag))
519 {
520 insert_string (" (sys)");
521 Findent_to (make_number (20), one);
522 }
523 else
524 Findent_to (make_number (15), one);
525
526 Fprin1 (count, stream);
7942b8ae 527 Findent_to (make_number (20), one);
a97569cb 528 Fprin1 (SYMBOL_VALUE (sym), stream);
d427b66a 529 if (!NILP (XSYMBOL (sym)->function))
7942b8ae
RS
530 {
531 Findent_to (make_number (45), one);
532 Fprin1 (XSYMBOL (sym)->function, stream);
533 }
534 Fterpri (stream);
535}
536
a0d76c27 537DEFUN ("insert-abbrev-table-description", Finsert_abbrev_table_description,
03be2694 538 Sinsert_abbrev_table_description, 1, 2, 0,
7ee72033 539 doc: /* Insert before point a full description of abbrev table named NAME.
b39fb64b
PJ
540NAME is a symbol whose value is an abbrev table.
541If optional 2nd arg READABLE is non-nil, a human-readable description
542is inserted. Otherwise the description is an expression,
543a call to `define-abbrev-table', which would
2d6c1fc0
RS
544define the abbrev table NAME exactly as it is currently defined.
545
546Abbrevs marked as "system abbrevs" are omitted. */)
7ee72033 547 (name, readable)
7942b8ae
RS
548 Lisp_Object name, readable;
549{
550 Lisp_Object table;
551 Lisp_Object stream;
552
b7826503 553 CHECK_SYMBOL (name);
7942b8ae 554 table = Fsymbol_value (name);
b7826503 555 CHECK_VECTOR (table);
7942b8ae 556
6520d056 557 XSETBUFFER (stream, current_buffer);
7942b8ae 558
d427b66a 559 if (!NILP (readable))
7942b8ae
RS
560 {
561 insert_string ("(");
562 Fprin1 (name, stream);
563 insert_string (")\n\n");
564 map_obarray (table, describe_abbrev, stream);
565 insert_string ("\n\n");
566 }
567 else
568 {
569 insert_string ("(define-abbrev-table '");
570 Fprin1 (name, stream);
571 insert_string (" '(\n");
572 map_obarray (table, write_abbrev, stream);
573 insert_string (" ))\n\n");
574 }
575
576 return Qnil;
577}
578\f
579DEFUN ("define-abbrev-table", Fdefine_abbrev_table, Sdefine_abbrev_table,
580 2, 2, 0,
7ee72033 581 doc: /* Define TABLENAME (a symbol) as an abbrev table name.
b39fb64b 582Define abbrevs in it according to DEFINITIONS, which is a list of elements
2d6c1fc0
RS
583of the form (ABBREVNAME EXPANSION HOOK USECOUNT SYSTEMFLAG).
584\(If the list is shorter than that, omitted elements default to nil). */)
7ee72033 585 (tablename, definitions)
b9d613cc 586 Lisp_Object tablename, definitions;
7942b8ae
RS
587{
588 Lisp_Object name, exp, hook, count;
2d6c1fc0 589 Lisp_Object table, elt, sys;
7942b8ae 590
b7826503 591 CHECK_SYMBOL (tablename);
78ce396a
EN
592 table = Fboundp (tablename);
593 if (NILP (table) || (table = Fsymbol_value (tablename), NILP (table)))
7942b8ae
RS
594 {
595 table = Fmake_abbrev_table ();
78ce396a 596 Fset (tablename, table);
b9d613cc 597 Vabbrev_table_name_list = Fcons (tablename, Vabbrev_table_name_list);
7942b8ae 598 }
b7826503 599 CHECK_VECTOR (table);
7942b8ae 600
52ad5ecc 601 for (; CONSP (definitions); definitions = XCDR (definitions))
7942b8ae 602 {
52ad5ecc 603 elt = XCAR (definitions);
0292bcb1
JB
604 name = Fcar (elt); elt = Fcdr (elt);
605 exp = Fcar (elt); elt = Fcdr (elt);
606 hook = Fcar (elt); elt = Fcdr (elt);
2d6c1fc0
RS
607 count = Fcar (elt); elt = Fcdr (elt);
608 sys = Fcar (elt);
609 Fdefine_abbrev (table, name, exp, hook, count, sys);
7942b8ae
RS
610 }
611 return Qnil;
612}
613\f
dfcf069d 614void
7942b8ae
RS
615syms_of_abbrev ()
616{
2d6c1fc0
RS
617 Qsystem_type = intern ("system-type");
618 staticpro (&Qsystem_type);
619
620 Qcount = intern ("count");
621 staticpro (&Qcount);
622
7ee72033
MB
623 DEFVAR_LISP ("abbrev-table-name-list", &Vabbrev_table_name_list,
624 doc: /* List of symbols whose values are abbrev tables. */);
7942b8ae
RS
625 Vabbrev_table_name_list = Fcons (intern ("fundamental-mode-abbrev-table"),
626 Fcons (intern ("global-abbrev-table"),
627 Qnil));
628
7ee72033
MB
629 DEFVAR_LISP ("global-abbrev-table", &Vglobal_abbrev_table,
630 doc: /* The abbrev table whose abbrevs affect all buffers.
b39fb64b
PJ
631Each buffer may also have a local abbrev table.
632If it does, the local table overrides the global one
633for any particular abbrev defined in both. */);
7942b8ae
RS
634 Vglobal_abbrev_table = Fmake_abbrev_table ();
635
7ee72033
MB
636 DEFVAR_LISP ("fundamental-mode-abbrev-table", &Vfundamental_mode_abbrev_table,
637 doc: /* The abbrev table of mode-specific abbrevs for Fundamental Mode. */);
7942b8ae
RS
638 Vfundamental_mode_abbrev_table = Fmake_abbrev_table ();
639 current_buffer->abbrev_table = Vfundamental_mode_abbrev_table;
c8bb8167 640 buffer_defaults.abbrev_table = Vfundamental_mode_abbrev_table;
7942b8ae 641
7ee72033
MB
642 DEFVAR_LISP ("last-abbrev", &Vlast_abbrev,
643 doc: /* The abbrev-symbol of the last abbrev expanded. See `abbrev-symbol'. */);
7942b8ae 644
7ee72033
MB
645 DEFVAR_LISP ("last-abbrev-text", &Vlast_abbrev_text,
646 doc: /* The exact text of the last abbrev expanded.
b39fb64b 647nil if the abbrev has already been unexpanded. */);
7942b8ae 648
7ee72033
MB
649 DEFVAR_INT ("last-abbrev-location", &last_abbrev_point,
650 doc: /* The location of the start of the last abbrev expanded. */);
7942b8ae
RS
651
652 Vlast_abbrev = Qnil;
653 Vlast_abbrev_text = Qnil;
654 last_abbrev_point = 0;
655
7ee72033
MB
656 DEFVAR_LISP ("abbrev-start-location", &Vabbrev_start_location,
657 doc: /* Buffer position for `expand-abbrev' to use as the start of the abbrev.
ca70e62f 658When nil, use the word before point as the abbrev.
b39fb64b 659Calling `expand-abbrev' sets this to nil. */);
7942b8ae
RS
660 Vabbrev_start_location = Qnil;
661
7ee72033
MB
662 DEFVAR_LISP ("abbrev-start-location-buffer", &Vabbrev_start_location_buffer,
663 doc: /* Buffer that `abbrev-start-location' has been set for.
b39fb64b 664Trying to expand an abbrev in any other buffer clears `abbrev-start-location'. */);
7942b8ae
RS
665 Vabbrev_start_location_buffer = Qnil;
666
7ee72033
MB
667 DEFVAR_PER_BUFFER ("local-abbrev-table", &current_buffer->abbrev_table, Qnil,
668 doc: /* Local (mode-specific) abbrev table of current buffer. */);
7942b8ae 669
7ee72033
MB
670 DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed,
671 doc: /* Set non-nil by defining or altering any word abbrevs.
b39fb64b 672This causes `save-some-buffers' to offer to save the abbrevs. */);
7942b8ae
RS
673 abbrevs_changed = 0;
674
7ee72033
MB
675 DEFVAR_BOOL ("abbrev-all-caps", &abbrev_all_caps,
676 doc: /* *Set non-nil means expand multi-word abbrevs all caps if abbrev was so. */);
7942b8ae
RS
677 abbrev_all_caps = 0;
678
7ee72033
MB
679 DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook,
680 doc: /* Function or functions to be called before abbrev expansion is done.
b39fb64b
PJ
681This is the first thing that `expand-abbrev' does, and so this may change
682the current abbrev table before abbrev lookup happens. */);
dbd7a969
RS
683 Vpre_abbrev_expand_hook = Qnil;
684 Qpre_abbrev_expand_hook = intern ("pre-abbrev-expand-hook");
685 staticpro (&Qpre_abbrev_expand_hook);
686
7942b8ae
RS
687 defsubr (&Smake_abbrev_table);
688 defsubr (&Sclear_abbrev_table);
689 defsubr (&Sdefine_abbrev);
690 defsubr (&Sdefine_global_abbrev);
691 defsubr (&Sdefine_mode_abbrev);
692 defsubr (&Sabbrev_expansion);
693 defsubr (&Sabbrev_symbol);
694 defsubr (&Sexpand_abbrev);
695 defsubr (&Sunexpand_abbrev);
696 defsubr (&Sinsert_abbrev_table_description);
697 defsubr (&Sdefine_abbrev_table);
698}