|
|
1.1 root 1: /* Primitives for word-abbrev mode.
2: Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU Emacs General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU Emacs, but only under the conditions described in the
15: GNU Emacs General Public License. A copy of this license is
16: supposed to have been given to you along with GNU Emacs so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: #include "config.h"
23: #include <stdio.h>
24: #undef NULL
25: #include "lisp.h"
26: #include "commands.h"
27: #include "buffer.h"
28: #include "window.h"
29:
30: /* An abbrev table is an obarray.
31: Each defined abbrev is represented by a symbol in that obarray
32: whose print name is the abbreviation.
33: The symbol's value is a string which is the expansion.
34: If its function definition is non-nil, it is called
35: after the expansion is done.
36: The plist slot of the abbrev symbol is its usage count. */
37:
38: /* List of all abbrev-table name symbols:
39: symbols whose values are abbrev tables. */
40:
41: Lisp_Object Vabbrev_table_name_list;
42:
43: /* The table of global abbrevs. These are in effect
44: in any buffer in which abbrev mode is turned on. */
45:
46: Lisp_Object Vglobal_abbrev_table;
47:
48: /* The local abbrev table used by default (in Fundamental Mode buffers) */
49:
50: Lisp_Object Vfundamental_mode_abbrev_table;
51:
52: /* Set nonzero when an abbrev definition is changed */
53:
54: int abbrevs_changed;
55:
56: int abbrev_all_caps;
57:
58: /* Non-nil => use this location as the start of abbrev to expand
59: (rather than taking the word before point as the abbrev) */
60:
61: Lisp_Object Vabbrev_start_location;
62:
63: /* Buffer that Vabbrev_start_location applies to */
64: Lisp_Object Vabbrev_start_location_buffer;
65:
66: /* The symbol representing the abbrev most recently expanded */
67:
68: Lisp_Object Vlast_abbrev;
69:
70: /* A string for the actual text of the abbrev most recently expanded.
71: This has more info than Vlast_abbrev since case is significant. */
72:
73: Lisp_Object Vlast_abbrev_text;
74:
75: /* Character address of start of last abbrev expanded */
76:
77: int last_abbrev_point;
78:
79: extern Lisp_Object oblookup ();
80:
81: DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
82: "Create a new, empty abbrev table object.")
83: ()
84: {
85: return Fmake_vector (make_number (59), make_number (0));
86: }
87:
88: DEFUN ("clear-abbrev-table", Fclear_abbrev_table, Sclear_abbrev_table, 1, 1, 0,
89: "Undefine all abbrevs in abbrev table TABLE, leaving it empty.")
90: (table)
91: Lisp_Object table;
92: {
93: int i, size;
94:
95: CHECK_VECTOR (table, 0);
96: size = XVECTOR (table)->size;
97: abbrevs_changed = 1;
98: for (i = 0; i < size; i++)
99: XVECTOR (table)->contents[i] = make_number (0);
100: return Qnil;
101: }
102:
103: DEFUN ("define-abbrev", Fdefine_abbrev, Sdefine_abbrev, 3, 5, 0,
104: "Define an abbrev in TABLE named NAME, to expand to EXPANSION or call HOOK.\n\
105: NAME and EXPANSION are strings. HOOK is a function or nil.\n\
106: To undefine an abbrev, define it with EXPANSION = nil")
107: (table, name, expansion, hook, count)
108: Lisp_Object table, name, expansion, hook, count;
109: {
110: Lisp_Object sym, oexp, ohook, tem;
111: CHECK_VECTOR (table, 0);
112: CHECK_STRING (name, 1);
113: CHECK_STRING (expansion, 2);
114: if (NULL (count))
115: count = make_number (0);
116: else
117: CHECK_NUMBER (count, 0);
118:
119: sym = Fintern (name, table);
120:
121: oexp = XSYMBOL (sym)->value;
122: ohook = XSYMBOL (sym)->function;
123: if (!((EQ (oexp, expansion)
124: || (XTYPE (oexp) == Lisp_String
125: && (tem = Fstring_equal (oexp, expansion), !NULL (tem))))
126: &&
127: (EQ (ohook, hook)
128: || (tem = Fequal (ohook, hook), !NULL (tem)))))
129: abbrevs_changed = 1;
130:
131: Fset (sym, expansion);
132: Ffset (sym, hook);
133: Fsetplist (sym, count);
134:
135: return name;
136: }
137:
138: DEFUN ("define-global-abbrev", Fdefine_global_abbrev, Sdefine_global_abbrev, 2, 2,
139: "sDefine global abbrev: \nsExpansion for %s: ",
140: "Define ABBREV as a global abbreviation for EXPANSION.")
141: (name, expansion)
142: Lisp_Object name, expansion;
143: {
144: Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (name),
145: expansion, Qnil, make_number (0));
146: return name;
147: }
148:
149: DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev, Sdefine_mode_abbrev, 2, 2,
150: "sDefine mode abbrev: \nsExpansion for %s: ",
151: "Define ABBREV as a mode-specific abbreviation for EXPANSION.")
152: (name, expansion)
153: Lisp_Object name, expansion;
154: {
155: if (NULL (bf_cur->abbrev_table))
156: error ("No local abbrev table associated with this buffer");
157:
158: Fdefine_abbrev (bf_cur->abbrev_table, Fdowncase (name),
159: expansion, Qnil, make_number (0));
160: return name;
161: }
162:
163: DEFUN ("abbrev-symbol", Fabbrev_symbol, Sabbrev_symbol, 1, 2, 0,
164: "Return the symbol representing abbrev named ABBREV.\n\
165: Value is nil if that abbrev is not defined.\n\
166: Optional second arg TABLE is abbrev table to look it up in.\n\
167: Default is try buffer's mode-specific abbrev table, then global table.")
168: (abbrev, table)
169: Lisp_Object abbrev, table;
170: {
171: Lisp_Object sym;
172: CHECK_STRING (abbrev, 0);
173: if (!NULL (table))
174: sym = Fintern_soft (abbrev, table);
175: else
176: {
177: sym = Qnil;
178: if (!NULL (bf_cur->abbrev_table))
179: sym = Fintern_soft (abbrev, bf_cur->abbrev_table);
180: if (NULL (XSYMBOL (sym)->value))
181: sym = Qnil;
182: if (NULL (sym))
183: sym = Fintern_soft (abbrev, Vglobal_abbrev_table);
184: }
185: if (NULL (XSYMBOL (sym)->value)) return Qnil;
186: return sym;
187: }
188:
189: DEFUN ("abbrev-expansion", Fabbrev_expansion, Sabbrev_expansion, 1, 2, 0,
190: "Return the string that ABBREV expands into in the current buffer.\n\
191: Optionally specify an abbrev table; then ABBREV is looked up in that table only.")
192: (abbrev, table)
193: Lisp_Object abbrev, table;
194: {
195: Lisp_Object sym;
196: sym = Fabbrev_symbol (abbrev, table);
197: if (NULL (sym)) return sym;
198: return Fsymbol_value (sym);
199: }
200:
201: /* Expand the word before point, if it is an abbrev.
202: Returns 1 if an expansion is done. */
203:
204: DEFUN ("expand-abbrev", Fexpand_abbrev, Sexpand_abbrev, 0, 0, "",
205: "Expand the abbrev before point, if it is an abbrev.\n\
206: Effective when explicitly called even when abbrev-mode is not enabled.\n\
207: Returns t if expansion took place.")
208: ()
209: {
210: char buffer[200];
211: register char *p = buffer;
212: register int wordstart, idx;
213: int uccount = 0, lccount = 0;
214: register Lisp_Object sym;
215: Lisp_Object expansion, hook, tem;
216:
217: if (XBUFFER (Vabbrev_start_location_buffer) != bf_cur)
218: Vabbrev_start_location = Qnil;
219: if (!NULL (Vabbrev_start_location))
220: {
221: tem = Vabbrev_start_location;
222: CHECK_NUMBER_COERCE_MARKER (tem, 0);
223: wordstart = XINT (tem);
224: Vabbrev_start_location = Qnil;
225: if (CharAt (wordstart) == '-')
226: del_range (wordstart, wordstart + 1);
227: }
228: else
229: wordstart = scan_words (point, -1);
230:
231: if (!wordstart || point - wordstart >= sizeof buffer || point <= wordstart)
232: return Qnil;
233:
234: for (idx = wordstart; idx < point; idx++)
235: {
236: register int c = CharAt (idx);
237: if (UPPERCASEP (c))
238: c = DOWNCASE (c), uccount++;
239: else if (! NOCASEP (c))
240: lccount++;
241: *p++ = c;
242: }
243:
244: if (XTYPE (bf_cur->abbrev_table) == Lisp_Vector)
245: sym = oblookup (bf_cur->abbrev_table, buffer, p - buffer);
246: else
247: XFASTINT (sym) = 0;
248: if (XTYPE (sym) == Lisp_Int ||
249: NULL (XSYMBOL (sym)->value))
250: sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
251: if (XTYPE (sym) == Lisp_Int ||
252: NULL (XSYMBOL (sym)->value))
253: return Qnil;
254:
255: if (INTERACTIVE && !EQ (minibuf_window, selected_window))
256: {
257: SetPoint (wordstart + p - buffer);
258: Fundo_boundary ();
259: }
260: SetPoint (wordstart);
261: Vlast_abbrev_text
262: = Fbuffer_substring (make_number (point),
263: make_number (point + (p - buffer)));
264: del_range (point, point + (p - buffer));
265:
266: /* Now sym is the abbrev symbol. */
267: Vlast_abbrev = sym;
268: last_abbrev_point = point;
269:
270: if (XTYPE (XSYMBOL (sym)->plist) == Lisp_Int)
271: XSETINT (XSYMBOL (sym)->plist,
272: XINT (XSYMBOL (sym)->plist) + 1); /* Increment use count */
273:
274: expansion = XSYMBOL (sym)->value;
275: InsCStr (XSTRING (expansion)->data, XSTRING (expansion)->size);
276:
277: if (uccount && !lccount)
278: {
279: /* Abbrev was all caps */
280: /* If expansion is multiple words, normally capitalize each word */
281: /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
282: but Megatest 68000 compiler can't handle that */
283: if (!abbrev_all_caps)
284: if (scan_words (point, -1) > scan_words (wordstart, 1))
285: {
286: upcase_initials_region (make_number (wordstart),
287: make_number (point));
288: goto caped;
289: }
290: /* If expansion is one word, or if user says so, upcase it all. */
291: Fupcase_region (make_number (wordstart), make_number (point));
292: caped: ;
293: }
294: else if (uccount)
295: {
296: /* Abbrev included some caps. Cap first initial of expansion */
297: idx = point;
298: SetPoint (wordstart);
299: Fcapitalize_word (make_number (1));
300: SetPoint (idx);
301: }
302:
303: hook = XSYMBOL (sym)->function;
304: if (!NULL (hook))
305: call0 (hook);
306:
307: return Qt;
308: }
309:
310: DEFUN ("unexpand-abbrev", Funexpand_abbrev, Sunexpand_abbrev, 0, 0, "",
311: "Undo the expansion of the last abbrev that expanded.")
312: ()
313: {
314: int opoint = point;
315: int adjust = 0;
316: if (last_abbrev_point < FirstCharacter
317: || last_abbrev_point > NumCharacters)
318: return Qnil;
319: SetPoint (last_abbrev_point);
320: if (XTYPE (Vlast_abbrev_text) == Lisp_String)
321: {
322: /* This isn't correct if Vlast_abbrev->function was used
323: to do the expansion */
324: Lisp_Object val;
325: XSET (val, Lisp_String, XSYMBOL (Vlast_abbrev)->value);
326: adjust = XSTRING (val)->size;
327: del_range (point, point + adjust);
328: InsCStr (XSTRING (Vlast_abbrev_text)->data,
329: XSTRING (Vlast_abbrev_text)->size);
330: adjust -= XSTRING (Vlast_abbrev_text)->size;
331: Vlast_abbrev_text = Qnil;
332: }
333: SetPoint (last_abbrev_point < opoint ? opoint - adjust : opoint);
334: return Qnil;
335: }
336:
337: static
338: write_abbrev (sym, stream)
339: Lisp_Object sym, stream;
340: {
341: Lisp_Object name;
342: if (NULL (XSYMBOL (sym)->value))
343: return;
344: InsCStr (" (", 5);
345: XSET (name, Lisp_String, XSYMBOL (sym)->name);
346: Fprin1 (name, stream);
347: InsCStr (" ", 1);
348: Fprin1 (XSYMBOL (sym)->value, stream);
349: InsCStr (" ", 1);
350: Fprin1 (XSYMBOL (sym)->function, stream);
351: InsCStr (" ", 1);
352: Fprin1 (XSYMBOL (sym)->plist, stream);
353: InsCStr (")\n", 2);
354: }
355:
356: static
357: describe_abbrev (sym, stream)
358: Lisp_Object sym, stream;
359: {
360: Lisp_Object one;
361:
362: if (NULL (XSYMBOL (sym)->value))
363: return;
364: one = make_number (1);
365: Fprin1 (Fsymbol_name (sym), stream);
366: Findent_to (make_number (15), one);
367: Fprin1 (XSYMBOL (sym)->plist, stream);
368: Findent_to (make_number (20), one);
369: Fprin1 (XSYMBOL (sym)->value, stream);
370: if (!NULL (XSYMBOL (sym)->function))
371: {
372: Findent_to (make_number (45), one);
373: Fprin1 (XSYMBOL (sym)->function, stream);
374: }
375: Fterpri (stream);
376: }
377:
378: DEFUN ("insert-abbrev-table-description",
379: Finsert_abbrev_table_description, Sinsert_abbrev_table_description,
380: 2, 2, 0,
381: "Insert before point a description of abbrev table named NAME.\n\
382: NAME is a symbol whose value is an abbrev table.\n\
383: If 2nd arg READABLE is non-nil, a readable description is inserted.\n\
384: Otherwise description is an expression,\n\
385: a call to define-abbrev-table which would\n\
386: define NAME exactly as it is currently defined.")
387: (name, readable)
388: Lisp_Object name, readable;
389: {
390: Lisp_Object table;
391: Lisp_Object stream;
392:
393: CHECK_SYMBOL (name, 0);
394: table = Fsymbol_value (name);
395: CHECK_VECTOR (table, 0);
396:
397: XSET (stream, Lisp_Buffer, bf_cur);
398:
399: if (!NULL (readable))
400: {
401: InsStr ("(");
402: Fprin1 (name, stream);
403: InsStr (")\n\n");
404: map_obarray (table, describe_abbrev, stream);
405: InsStr ("\n\n");
406: }
407: else
408: {
409: InsStr ("(define-abbrev-table '");
410: Fprin1 (name, stream);
411: InsStr (" '(\n");
412: map_obarray (table, write_abbrev, stream);
413: InsStr (" ))\n\n");
414: }
415:
416: return Qnil;
417: }
418:
419: DEFUN ("define-abbrev-table", Fdefine_abbrev_table, Sdefine_abbrev_table,
420: 2, 2, 0,
421: "Define TABNAME (a symbol) as an abbrev table name.\n\
422: Define abbrevs in it according to DEFINITIONS, a list of elements\n\
423: of the form (ABBREVNAME EXPANSION HOOK USECOUNT).")
424: (tabname, defns)
425: Lisp_Object tabname, defns;
426: {
427: Lisp_Object name, exp, hook, count;
428: Lisp_Object table, elt;
429:
430: CHECK_SYMBOL (tabname, 0);
431: table = Fboundp (tabname);
432: if (NULL (table) || (table = Fsymbol_value (tabname), NULL (table)))
433: {
434: table = Fmake_abbrev_table ();
435: Fset (tabname, table);
436: Vabbrev_table_name_list =
437: Fcons (tabname, Vabbrev_table_name_list);
438: }
439: CHECK_VECTOR (table, 0);
440:
441: for (;!NULL (defns); defns = Fcdr (defns))
442: {
443: elt = Fcar (defns);
444: name = Fcar (elt);
445: elt = Fcdr (elt);
446: exp = Fcar (elt);
447: elt = Fcdr (elt);
448: hook = Fcar (elt);
449: elt = Fcdr (elt);
450: count = Fcar (elt);
451: Fdefine_abbrev (table, name, exp, hook, count);
452: }
453: return Qnil;
454: }
455:
456: syms_of_abbrev ()
457: {
458: DEFVAR_LISP ("abbrev-table-name-list", &Vabbrev_table_name_list,
459: "List of symbols whose values are abbrev tables.");
460: Vabbrev_table_name_list = Fcons (intern ("fundamental-mode-abbrev-table"),
461: Fcons (intern ("global-abbrev-table"),
462: Qnil));
463:
464: DEFVAR_LISP ("global-abbrev-table", &Vglobal_abbrev_table,
465: "The abbrev table whose abbrevs affect all buffers.\n\
466: Each buffer may also have a local abbrev table.\n\
467: If it does, the local table overrides the global one\n\
468: for any particular abbrev defined in both.");
469: Vglobal_abbrev_table = Fmake_abbrev_table ();
470:
471: DEFVAR_LISP ("fundamental-mode-abbrev-table", &Vfundamental_mode_abbrev_table,
472: "The abbrev table of mode-specific abbrevs for Fundamental Mode.");
473: Vfundamental_mode_abbrev_table = Fmake_abbrev_table ();
474: bf_cur->abbrev_table = Vfundamental_mode_abbrev_table;
475:
476: DEFVAR_LISP ("last-abbrev", &Vlast_abbrev,
477: "The abbrev-symbol of the last abbrev expanded.");
478:
479: DEFVAR_LISP ("last-abbrev-text", &Vlast_abbrev_text,
480: "The exact text of the last abbrev expanded.\n\
481: nil if the abbrev has already been unexpanded.");
482:
483: DEFVAR_INT ("last-abbrev-location", &last_abbrev_point,
484: "The location of the last abbrev expanded.");
485:
486: Vlast_abbrev = Qnil;
487: Vlast_abbrev_text = Qnil;
488: last_abbrev_point = 0;
489:
490: DEFVAR_LISP ("abbrev-start-location", &Vabbrev_start_location,
491: "Buffer position for expand-abbrev to use as the start of the abbrev.\n\
492: nil means use the word before point as the abbrev.\n\
493: Set to nil each time expand-abbrev is called.");
494: Vabbrev_start_location = Qnil;
495:
496: DEFVAR_LISP ("abbrev-start-location-buffer", &Vabbrev_start_location_buffer,
497: "Buffer that abbrev-start-location has been set for.\n\
498: Trying to expand an abbrev in any other buffer clears abbrev-start-location.");
499: Vabbrev_start_location_buffer = Qnil;
500:
501: DEFVAR_PER_BUFFER ("local-abbrev-table", &bf_cur->abbrev_table,
502: "Local (mode-specific) abbrev table of current buffer.");
503:
504: DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed,
505: "Set non-nil by defining or altering any word abbrevs.");
506: abbrevs_changed = 0;
507:
508: DEFVAR_BOOL ("abbrev-all-caps", &abbrev_all_caps,
509: "*Set non-nil means expand multi-word abbrevs all caps if abbrev was so.");
510: abbrev_all_caps = 0;
511:
512: defsubr (&Smake_abbrev_table);
513: defsubr (&Sclear_abbrev_table);
514: defsubr (&Sdefine_abbrev);
515: defsubr (&Sdefine_global_abbrev);
516: defsubr (&Sdefine_mode_abbrev);
517: defsubr (&Sabbrev_expansion);
518: defsubr (&Sabbrev_symbol);
519: defsubr (&Sexpand_abbrev);
520: defsubr (&Sunexpand_abbrev);
521: defsubr (&Sinsert_abbrev_table_description);
522: defsubr (&Sdefine_abbrev_table);
523: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.