[gnu.emacs.bug] GNU Emacs abbrev bugs

GENTZEL@CPWSCU.PSC.EDU (Dave Gentzel) (07/28/89)

ABBREV.C FIXES (expand-abbrevs):

  1. Contrary to the documentation, define-abbrev blows up if passed nil for
     expansion.

  2. expand-abbrev refuses to expand any abbrev with > 199 characters in
     length.  Not a major restriction, but one of the few arbitrary limits in
     emacs and easy to fix.

     (While changing the code I've made a few other minor improvements...)

  3. There were several unnecessary checks such as
	point <= scan_word(point, -1)
     which is always false provided scan_word doesn't return 0 (it doesn't).
     These have been removed.

  4. Allow whitespace after the word to expand, i.e.
	tom
	    ^point here
     expand-abbrev will expand tom (assuming it is an abbrev, of course).

*** abbrev.c;-0	Fri May  5 15:43:53 1989
--- abbrev.c	Thu Jul 27 15:20:46 1989
***************
*** 110,116
    Lisp_Object sym, oexp, ohook, tem;
    CHECK_VECTOR (table, 0);
    CHECK_STRING (name, 1);
!   CHECK_STRING (expansion, 2);
    if (NULL (count))
      count = make_number (0);
    else
--- 110,117 -----
    Lisp_Object sym, oexp, ohook, tem;
    CHECK_VECTOR (table, 0);
    CHECK_STRING (name, 1);
!   if (!NULL (expansion))
!     CHECK_STRING (expansion, 2);
    if (NULL (count))
      count = make_number (0);
    else
***************
*** 207,215
  Returns t if expansion took place.")
    ()
  {
!   char buffer[200];
!   register char *p = buffer;
!   register int wordstart, idx;
    int uccount = 0, lccount = 0;
    register Lisp_Object sym;
    Lisp_Object expansion, hook, tem;
--- 208,216 -----
  Returns t if expansion took place.")
    ()
  {
!   register char *buffer, *p;
!   register int wordstart, wordend, idx;
!   int whitecnt;
    int uccount = 0, lccount = 0;
    register Lisp_Object sym;
    Lisp_Object expansion, hook, tem;
***************
*** 227,234
      }
    else
      wordstart = scan_words (point, -1);
! 
!   if (!wordstart || point - wordstart >= sizeof buffer || point <= wordstart)
      return Qnil;
  
    for (idx = wordstart; idx < point; idx++)
--- 228,235 -----
      }
    else
      wordstart = scan_words (point, -1);
! 
!   if (!wordstart)
      return Qnil;
  
    wordend = scan_words (wordstart, 1);
***************
*** 230,237
  
    if (!wordstart || point - wordstart >= sizeof buffer || point <= wordstart)
      return Qnil;
! 
!   for (idx = wordstart; idx < point; idx++)
      {
        register int c = CharAt (idx);
        if (UPPERCASEP (c))
--- 231,245 -----
  
    if (!wordstart)
      return Qnil;
! 
!   wordend = scan_words (wordstart, 1);
!   if (wordend > point)
!     wordend = point;
!   whitecnt = point - wordend;
! 
!   p = buffer = alloca (wordend - wordstart);
! 
!   for (idx = wordstart; idx < wordend; idx++)
      {
        register int c = CharAt (idx);
        if (UPPERCASEP (c))
***************
*** 245,252
      sym = oblookup (bf_cur->abbrev_table, buffer, p - buffer);
    else
      XFASTINT (sym) = 0;
!   if (XTYPE (sym) == Lisp_Int ||
!       NULL (XSYMBOL (sym)->value))
      sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
    if (XTYPE (sym) == Lisp_Int ||
        NULL (XSYMBOL (sym)->value))
--- 253,259 -----
      sym = oblookup (bf_cur->abbrev_table, buffer, p - buffer);
    else
      XFASTINT (sym) = 0;
!   if (XTYPE (sym) == Lisp_Int || NULL (XSYMBOL (sym)->value))
      sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
    if (XTYPE (sym) == Lisp_Int || NULL (XSYMBOL (sym)->value))
      return Qnil;
***************
*** 248,255
    if (XTYPE (sym) == Lisp_Int ||
        NULL (XSYMBOL (sym)->value))
      sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
!   if (XTYPE (sym) == Lisp_Int ||
!       NULL (XSYMBOL (sym)->value))
      return Qnil;
  
    if (INTERACTIVE && !EQ (minibuf_window, selected_window))
--- 255,261 -----
      XFASTINT (sym) = 0;
    if (XTYPE (sym) == Lisp_Int || NULL (XSYMBOL (sym)->value))
      sym = oblookup (Vglobal_abbrev_table, buffer, p - buffer);
!   if (XTYPE (sym) == Lisp_Int || NULL (XSYMBOL (sym)->value))
      return Qnil;
  
    if (INTERACTIVE && !EQ (minibuf_window, selected_window))
***************
*** 254,260
  
    if (INTERACTIVE && !EQ (minibuf_window, selected_window))
      {
!       SetPoint (wordstart + p - buffer);
        Fundo_boundary ();
      }
    SetPoint (wordstart);
--- 260,266 -----
  
    if (INTERACTIVE && !EQ (minibuf_window, selected_window))
      {
!       SetPoint (wordend);
        Fundo_boundary ();
      }
    SetPoint (wordstart);
***************
*** 259,267
      }
    SetPoint (wordstart);
    Vlast_abbrev_text
!     = Fbuffer_substring (make_number (point),
! 			 make_number (point + (p - buffer)));
!   del_range (point, point + (p - buffer));
  
    /* Now sym is the abbrev symbol. */
    Vlast_abbrev = sym;
--- 265,272 -----
      }
    SetPoint (wordstart);
    Vlast_abbrev_text
!     = Fbuffer_substring (make_number (wordstart), make_number (wordend));
!   del_range (wordstart, wordend);
  
    /* Now sym is the abbrev symbol. */
    Vlast_abbrev = sym;
***************
*** 265,271
  
    /* Now sym is the abbrev symbol. */
    Vlast_abbrev = sym;
!   last_abbrev_point = point;
  
    if (XTYPE (XSYMBOL (sym)->plist) == Lisp_Int)
      XSETINT (XSYMBOL (sym)->plist,
--- 270,276 -----
  
    /* Now sym is the abbrev symbol. */
    Vlast_abbrev = sym;
!   last_abbrev_point = wordstart;
  
    if (XTYPE (XSYMBOL (sym)->plist) == Lisp_Int)
      /* Increment use count */
***************
*** 268,275
    last_abbrev_point = point;
  
    if (XTYPE (XSYMBOL (sym)->plist) == Lisp_Int)
!     XSETINT (XSYMBOL (sym)->plist,
! 	     XINT (XSYMBOL (sym)->plist) + 1);	/* Increment use count */
  
    expansion = XSYMBOL (sym)->value;
    InsCStr (XSTRING (expansion)->data, XSTRING (expansion)->size);
--- 273,280 -----
    last_abbrev_point = wordstart;
  
    if (XTYPE (XSYMBOL (sym)->plist) == Lisp_Int)
!     /* Increment use count */
!     XSETINT (XSYMBOL (sym)->plist, XINT (XSYMBOL (sym)->plist) + 1);
  
    expansion = XSYMBOL (sym)->value;
    InsCStr (XSTRING (expansion)->data, XSTRING (expansion)->size);
***************
*** 273,278
--- 278,284 -----

    expansion = XSYMBOL (sym)->value;
    InsCStr (XSTRING (expansion)->data, XSTRING (expansion)->size);
+   SetPoint (point + whitecnt);
  
    if (uccount && !lccount)
      {

ABBREV.EL FIXES (expand-region-abbrevs):

  1. Ignores its prefix argument (missing `P' from the interactive spec).

  2. Does unnecessary fiddling to get the region args in the right order.
     The `r' interactive spec already does this.

  3. Uses expand-abbrev to determine whether a word has an abbrev defined.
     This has the very undesirable side-effect of munging the undo
     information (especially buffer-modified) which makes undoing a very
     verbose operation!  Just pick up the word from the buffer and use
     abbrev-expansion instead.

  4. Make file argument to read-abbrev-file and quietly-read-abbrev-file
     optional (default to abbrev-file-name).

  5. Make write-abbrev-file default file to abbrev-file-name rather than the
     current visited file name!

  6. Fix the prompt for add-abbrev when undefining (arg < 0).

*** abbrev.el;-0	Fri May  5 15:42:42 1989
--- abbrev.el		Thu Jul 27 15:21:52 1989
***************
*** 129,136
  	 (skip-chars-backward " \t\n\f")
  	 (setq abbrevs (cons (list name exp hook count) abbrevs)))
         (define-abbrev-table table abbrevs)))))
! 
! (defun read-abbrev-file (file &optional quietly)
    "Read abbrev definitions from file written with write-abbrev-file.
  Takes file name as argument.
  Optional second argument non-nil means don't print anything."
--- 129,136 -----
  	 (skip-chars-backward " \t\n\f")
  	 (setq abbrevs (cons (list name exp hook count) abbrevs)))
         (define-abbrev-table table abbrevs)))))
! 
! (defun read-abbrev-file (&optional file quietly)
    "Read abbrev definitions from file written with write-abbrev-file.
  Takes file name as argument.
  Optional second argument non-nil means don't print anything."
***************
*** 138,145
    (load (if (and file (> (length file) 0)) file abbrev-file-name)
  	nil quietly)
    (setq save-abbrevs t abbrevs-changed nil))
! 
! (defun quietly-read-abbrev-file (file)
    "Read abbrev definitions from file written with write-abbrev-file.
  Takes file name as argument.  Does not print anything."
    ;(interactive "fRead abbrev file: ")
--- 138,145 -----
    (load (if (and file (> (length file) 0)) file abbrev-file-name)
  	nil quietly)
    (setq save-abbrevs t abbrevs-changed nil))
! 
! (defun quietly-read-abbrev-file (&optional file)
    "Read abbrev definitions from file written with write-abbrev-file.
  Takes file name as argument.  Does not print anything."
    (interactive "fRead abbrev file: ")
***************
*** 142,148
  (defun quietly-read-abbrev-file (file)
    "Read abbrev definitions from file written with write-abbrev-file.
  Takes file name as argument.  Does not print anything."
!   ;(interactive "fRead abbrev file: ")
    (read-abbrev-file file t))
  
  (defun write-abbrev-file (file)
--- 142,148 -----
  (defun quietly-read-abbrev-file (&optional file)
    "Read abbrev definitions from file written with write-abbrev-file.
  Takes file name as argument.  Does not print anything."
!   (interactive "fRead abbrev file: ")
    (read-abbrev-file file t))
  
  (defun write-abbrev-file (file)
***************
*** 148,154
  (defun write-abbrev-file (file)
    "Write all abbrev definitions to file of Lisp code.
  The file can be loaded to define the same abbrevs."
!   (interactive "FWrite abbrev file: ")
    (or (and file (> (length file) 0))
        (setq file abbrev-file-name))
    (save-excursion
--- 148,158 -----
  (defun write-abbrev-file (file)
    "Write all abbrev definitions to file of Lisp code.
  The file can be loaded to define the same abbrevs."
!   (interactive
!    (list
!     (read-file-name "Write abbrev file: "
! 		    (file-name-directory (expand-file-name abbrev-file-name))
! 		    abbrev-file-name)))
    (or (and file (> (length file) 0))
        (setq file abbrev-file-name))
    (save-excursion
***************
*** 191,198
  		   (if (= arg 0) (mark)
  		     (save-excursion (forward-word (- arg)) (point))))))
  	name)
!     (setq name (read-string (format "%s abbrev for \"%s\": "
! 				    type exp)))
      (if (or (null exp)
  	    (not (abbrev-expansion name table))
  	    (y-or-n-p (format "%s expands to \"%s\"; redefine? "
--- 195,204 -----
  		   (if (= arg 0) (mark)
  		     (save-excursion (forward-word (- arg)) (point))))))
  	name)
!     (setq name (read-string
! 		(if exp
! 		    (format "%s abbrev for \"%s\": " type exp)
! 		  (format "Undefine %s abbrev: " type))))
      (if (or (null exp)
  	    (not (abbrev-expansion name table))
  	    (y-or-n-p (format "%s expands to \"%s\"; redefine? "
***************
*** 254,260
  The user is asked to type y or n for each occurrence.
  A numeric argument means don't query; expand all abbrevs.
  Calling from a program, arguments are START END &optional NOQUERY."
!   (interactive "r")
    (save-excursion
      (goto-char (min start end))
      (let ((lim (- (point-max) (max start end))))
--- 260,266 -----
  The user is asked to type y or n for each occurrence.
  A numeric argument means don't query; expand all abbrevs.
  Calling from a program, arguments are START END &optional NOQUERY."
!   (interactive "r\nP")
    (save-excursion
      (goto-char start)
      (let ((lim (- (point-max) end)) pnt)
***************
*** 256,263
  Calling from a program, arguments are START END &optional NOQUERY."
    (interactive "r")
    (save-excursion
!     (goto-char (min start end))
!     (let ((lim (- (point-max) (max start end))))
        (while (and (not (eobp))
  		  (progn (forward-word 1)
  			 (<= (point) (- (point-max) lim))))
--- 262,269 -----
  Calling from a program, arguments are START END &optional NOQUERY."
    (interactive "r\nP")
    (save-excursion
!     (goto-char start)
!     (let ((lim (- (point-max) end)) pnt)
        (while (and (not (eobp))
  		  (forward-word 1)
  		  (<= (setq pnt (point)) (- (point-max) lim)))
***************
*** 259,270
      (goto-char (min start end))
      (let ((lim (- (point-max) (max start end))))
        (while (and (not (eobp))
! 		  (progn (forward-word 1)
! 			 (<= (point) (- (point-max) lim))))
! 	(let ((modp (buffer-modified-p)))
! 	  (if (expand-abbrev)
! 	      (progn
! 	       (set-buffer-modified-p modp)
! 	       (unexpand-abbrev)
! 	       (if (or noquery (y-or-n-p "Expand this? "))
! 		   (expand-abbrev)))))))))
--- 265,275 -----
      (goto-char start)
      (let ((lim (- (point-max) end)) pnt)
        (while (and (not (eobp))
! 		  (forward-word 1)
! 		  (<= (setq pnt (point)) (- (point-max) lim)))
! 	(if (abbrev-expansion
! 	     (prog1
! 		 (buffer-substring (progn (forward-word -1) (point)) pnt)
! 	       (goto-char pnt)))
! 	    (if (or noquery (y-or-n-p "Expand this? "))
! 		(expand-abbrev)))))))