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