|
|
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.