unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Support for case sensitive abbrev expansion
@ 2002-07-25 19:39 Károly Lőrentey
  2002-07-26  8:30 ` Miles Bader
  0 siblings, 1 reply; 4+ messages in thread
From: Károly Lőrentey @ 2002-07-25 19:39 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 2247 bytes --]


I use abbrevs while coding to expand control structure keywords to
whole statement templates.  abbrev-mode saves me huge amounts of
typing, IMHO it's an incredibly useful feature in Emacs.  But there is
one thing that has annoyed me ever since I defined my first source
code abbrev: the case-insensitivity (and, what's more,
case-preservation) of expansions.

Case-preserving is useful in text modes, but in most programming
languages, preserving the case of an abbrev expansion simply does not
make sense.  Even ignoring case differences can lead to unexpected
behavior: for example, JDE defines 'sw' as an abbrev of the Java
keyword 'switch'.  Currently this means that abbrev-mode expands all
of 'sw', 'Sw', 'sW' and 'SW', which is quite annoying while editing
source code written in a case-sensitive language.

This patch adds support for case-sensitive expansion of abbrevs.  A
new variable `abbrev-case-fold' is defined to let the user control
case behavior.  By default, case-sensitivity is inherited from
`case-fold-search'.

I implemented `abbrev-case-fold' as a new primitive buffer-local
variable.  (Buffer-locality is necessary, because IMHO most people
would want to keep the nifty case-preserving behavior in text
buffers.)  This required changes in buffer.c, buffer.h, cus-start.el
and elint.el, in addition to abbrev.c.  The patch includes
documentation updates and a NEWS entry.  If necessary, I am prepared
to sign a copyright assignment.

What do you think?  Is this the right way to do this?

-- Károly Lőrentey


2002-07-25  Károly Lőrentey <lorentey@elte.hu>
	  
	* buffer.h (struct buffer) <abbrev_case_fold>: New buffer-local
	variable.
	
	* buffer.c (Qcase_fold_search): New variable.
	(init_buffer_once): Initialize abbrev_case_fold.
	(syms_of_buffer): Initialize new vars.
	
	* abbrev.c (Qcase_fold_search): New variable.
	(Fdefine_global_abbrev, Fdefine_mode_abbrev): Do not downcase
	abbrev.
	(Fexpand_abbrev): Add support for case-sensitive expansion.
	(syms_of_abbrev): Initialize new vars.

2002-07-25  Károly Lőrentey <lorentey@elte.hu>

	* cus-start.el: Added abbrev-case-fold.

	* emacs-lisp/elint.el (elint-standard-variables): Added
	abbrev-case-fold.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Support for case sensitive abbrev expansion --]
[-- Type: text/x-patch, Size: 12588 bytes --]

Index: etc/NEWS
===================================================================
RCS file: /cvsroot/emacs/emacs/etc/NEWS,v
retrieving revision 1.718
diff -b -c -r1.718 NEWS
*** etc/NEWS	24 Jul 2002 22:14:47 -0000	1.718
--- etc/NEWS	25 Jul 2002 19:25:44 -0000
***************
*** 58,63 ****
--- 58,70 ----
  * Changes in Emacs 21.4
  
  +++
+ ** New user option `abbrev-case-fold'.  This option can be disabled to
+ avoid expanding abbrevs if their case differs from how they were
+ defined.  This is handy when the case preserving feature of abbrevs
+ doesn't make sense (e.g. in most programming modes).  The default is
+ to use the same setting as case-fold-search.
+ 
+ +++
  ** You can now customize the use of window fringes.  To control this
  for all frames, use M-x fringe-mode or the Show/Hide submenu of the
  top-level Options menu, or customize the `fringe-mode' variable.  To
Index: man/abbrevs.texi
===================================================================
RCS file: /cvsroot/emacs/emacs/man/abbrevs.texi,v
retrieving revision 1.16
diff -b -c -r1.16 abbrevs.texi
*** man/abbrevs.texi	3 Jan 2002 05:19:26 -0000	1.16
--- man/abbrevs.texi	25 Jul 2002 19:25:44 -0000
***************
*** 155,166 ****
  can be part of an abbrev.  The most common way to use an abbrev is to
  insert it and then insert a punctuation character to expand it.
  
  @vindex abbrev-all-caps
!   Abbrev expansion preserves case; thus, @samp{foo} expands into @samp{find
! outer otter}; @samp{Foo} into @samp{Find outer otter}, and @samp{FOO} into
! @samp{FIND OUTER OTTER} or @samp{Find Outer Otter} according to the
! variable @code{abbrev-all-caps} (a non-@code{nil} value chooses the first
! of the two expansions).
  
    These commands are used to control abbrev expansion:
  
--- 155,174 ----
  can be part of an abbrev.  The most common way to use an abbrev is to
  insert it and then insert a punctuation character to expand it.
  
+ @vindex abbrev-case-fold
+   Usually, abbrev expansion is case-insensitive; thus, @samp{foo},
+ @samp{Foo}, and @samp{FOO} are all expanded.  If you set the variable
+ @code{abbrev-case-fold} to @code{nil}, then all letters in the abbrev
+ must match exactly, including case.  This is a per-buffer variable;
+ altering the variable affects only the current buffer, but there is a
+ default value which you can change as well. @xref{Locals}.
+ 
  @vindex abbrev-all-caps
!   Case-insensitive abbrev expansion preserves case; thus, @samp{foo}
! expands into @samp{find outer otter}; @samp{Foo} into @samp{Find outer
! otter}, and @samp{FOO} into @samp{FIND OUTER OTTER} or @samp{Find
! Outer Otter} according to the variable @code{abbrev-all-caps} (a
! non-@code{nil} value chooses the first of the two expansions).
  
    These commands are used to control abbrev expansion:
  
Index: src/buffer.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/buffer.h,v
retrieving revision 1.85
diff -b -c -r1.85 buffer.h
*** src/buffer.h	10 Jan 2002 11:13:17 -0000	1.85
--- src/buffer.h	25 Jul 2002 19:25:45 -0000
***************
*** 639,644 ****
--- 639,646 ----
    Lisp_Object overwrite_mode;
    /* non-nil means abbrev mode is on.  Expand abbrevs automatically.  */
    Lisp_Object abbrev_mode;
+   /* Control whether ignore case when expanding abbreviations. */
+   Lisp_Object abbrev_case_fold;
    /* Display table to use for text in this buffer.  */
    Lisp_Object display_table;
    /* t means the mark and region are currently active.  */
Index: src/buffer.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/buffer.c,v
retrieving revision 1.398
diff -b -c -r1.398 buffer.c
*** src/buffer.c	21 Jul 2002 20:25:32 -0000	1.398
--- src/buffer.c	25 Jul 2002 19:25:48 -0000
***************
*** 4867,4872 ****
--- 4867,4873 ----
    buffer_defaults.abbrev_mode = Qnil;
    buffer_defaults.overwrite_mode = Qnil;
    buffer_defaults.case_fold_search = Qt;
+   buffer_defaults.abbrev_case_fold = intern ("case-fold-search");
    buffer_defaults.auto_fill_function = Qnil;
    buffer_defaults.selective_display = Qnil;
  #ifndef old
***************
*** 4936,4941 ****
--- 4937,4943 ----
    XSETFASTINT (buffer_local_flags.abbrev_mode, idx); ++idx;
    XSETFASTINT (buffer_local_flags.overwrite_mode, idx); ++idx;
    XSETFASTINT (buffer_local_flags.case_fold_search, idx); ++idx;
+   XSETFASTINT (buffer_local_flags.abbrev_case_fold, idx); ++idx;
    XSETFASTINT (buffer_local_flags.auto_fill_function, idx); ++idx;
    XSETFASTINT (buffer_local_flags.selective_display, idx); ++idx;
  #ifndef old
***************
*** 5196,5201 ****
--- 5198,5208 ----
  		     doc: /* Default value of `case-fold-search' for buffers that don't override it.
  This is the same as (default-value 'case-fold-search).  */);
  
+   DEFVAR_LISP_NOPRO ("default-abbrev-case-fold",
+ 		     &buffer_defaults.abbrev_case_fold,
+ 		     doc: /* Default value of `abbrev-case-fold' for buffers that don't override it.
+ This is the same as (default-value 'abbrev-case-fold').  */);
+   
  #ifdef DOS_NT
    DEFVAR_LISP_NOPRO ("default-buffer-file-type", 
  		     &buffer_defaults.buffer_file_type,
Index: src/abbrev.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/abbrev.c,v
retrieving revision 1.55
diff -b -c -r1.55 abbrev.c
*** src/abbrev.c	15 Jul 2002 00:00:35 -0000	1.55
--- src/abbrev.c	25 Jul 2002 19:25:49 -0000
***************
*** 84,89 ****
--- 84,90 ----
  Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook;
  
  Lisp_Object Qsystem_type, Qcount;
+ Lisp_Object Qcase_fold_search;
  \f
  DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
         doc: /* Create a new, empty abbrev table object.  */)
***************
*** 166,172 ****
       (abbrev, expansion)
       Lisp_Object abbrev, expansion;
  {
!   Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (abbrev),
  		  expansion, Qnil, make_number (0), Qnil);
    return abbrev;
  }
--- 167,173 ----
       (abbrev, expansion)
       Lisp_Object abbrev, expansion;
  {
!   Fdefine_abbrev (Vglobal_abbrev_table, abbrev,
  		  expansion, Qnil, make_number (0), Qnil);
    return abbrev;
  }
***************
*** 180,186 ****
    if (NILP (current_buffer->abbrev_table))
      error ("Major mode has no abbrev table");
  
!   Fdefine_abbrev (current_buffer->abbrev_table, Fdowncase (abbrev),
  		  expansion, Qnil, make_number (0), Qnil);
    return abbrev;
  }
--- 181,187 ----
    if (NILP (current_buffer->abbrev_table))
      error ("Major mode has no abbrev table");
  
!   Fdefine_abbrev (current_buffer->abbrev_table, abbrev,
  		  expansion, Qnil, make_number (0), Qnil);
    return abbrev;
  }
***************
*** 244,254 ****
--- 245,264 ----
    register Lisp_Object sym;
    Lisp_Object expansion, hook, tem;
    Lisp_Object value;
+   int case_fold;
  
    value = Qnil;
  
    Frun_hooks (1, &Qpre_abbrev_expand_hook);
  
+   if (SYMBOLP (current_buffer->abbrev_case_fold)
+       && EQ (current_buffer->abbrev_case_fold, Qcase_fold_search))
+     {
+       case_fold = !NILP (current_buffer->case_fold_search);
+     }
+   else
+     case_fold = !NILP (current_buffer->abbrev_case_fold);
+   
    wordstart = 0;
    if (!(BUFFERP (Vabbrev_start_location_buffer)
  	&& XBUFFER (Vabbrev_start_location_buffer) == current_buffer))
***************
*** 294,300 ****
        /* ??? This loop needs to go by characters!  */
        register int c = FETCH_BYTE (idx);
        if (UPPERCASEP (c))
! 	c = DOWNCASE (c), uccount++;
        else if (! NOCASEP (c))
  	lccount++;
        *p++ = c;
--- 304,314 ----
        /* ??? This loop needs to go by characters!  */
        register int c = FETCH_BYTE (idx);
        if (UPPERCASEP (c))
!         {
!           if (case_fold)
!             c = DOWNCASE (c);
!           uccount++;
!         }
        else if (! NOCASEP (c))
          lccount++;
        *p++ = c;
***************
*** 348,356 ****
  			  SBYTES (expansion), 1);
        SET_PT (PT + whitecnt);
  
!       if (uccount && !lccount)
  	{
! 	  /* Abbrev was all caps */
  	  /* If expansion is multiple words, normally capitalize each word */
  	  /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
  	     but Megatest 68000 compiler can't handle that */
--- 362,370 ----
  			  SBYTES (expansion), 1);
        SET_PT (PT + whitecnt);
  
!       if (case_fold && uccount && !lccount)
  	{
! 	  /* Abbrev was all caps with case insensitive expansion */
  	  /* If expansion is multiple words, normally capitalize each word */
  	  /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
  	     but Megatest 68000 compiler can't handle that */
***************
*** 365,371 ****
  	  Fupcase_region (make_number (wordstart), make_number (PT));
  	caped: ;
  	}
!       else if (uccount)
  	{
  	  /* Abbrev included some caps.  Cap first initial of expansion */
  	  int pos = wordstart_byte;
--- 379,385 ----
  	  Fupcase_region (make_number (wordstart), make_number (PT));
  	caped: ;
  	}
!       else if (case_fold && uccount)
  	{
  	  /* Abbrev included some caps.  Cap first initial of expansion */
  	  int pos = wordstart_byte;
***************
*** 600,605 ****
--- 614,622 ----
    Qcount = intern ("count");
    staticpro (&Qcount);
  
+   Qcase_fold_search = intern ("case-fold-search");
+   staticpro (&Qcase_fold_search);
+ 
    DEFVAR_LISP ("abbrev-table-name-list", &Vabbrev_table_name_list,
  	       doc: /* List of symbols whose values are abbrev tables.  */);
    Vabbrev_table_name_list = Fcons (intern ("fundamental-mode-abbrev-table"),
***************
*** 647,652 ****
--- 664,682 ----
    DEFVAR_PER_BUFFER ("local-abbrev-table", &current_buffer->abbrev_table, Qnil,
  		     doc: /* Local (mode-specific) abbrev table of current buffer.  */);
  
+   DEFVAR_PER_BUFFER ("abbrev-case-fold", &current_buffer->abbrev_case_fold, Qcase_fold_search,
+                      doc: /* *Control whether ignore case when expanding abbreviations.
+ A value of nil means case is significant, and abbrevs must
+ be typed exactly the same as they were defined in order to
+ be recognized.
+ A value of `case-fold-search' (the default) means case is
+ significant if `case-fold-search' is nil.
+ Any other non-nil value means case is not significant.
+ 
+ Note that if you define abbrevs containing uppercase
+ characters, then they will not be available if the
+ expansion is case-insensitive. */);
+                              
    DEFVAR_BOOL ("abbrevs-changed", &abbrevs_changed,
  	       doc: /* Set non-nil by defining or altering any word abbrevs.
  This causes `save-some-buffers' to offer to save the abbrevs.  */);
Index: lisp/cus-start.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/cus-start.el,v
retrieving revision 1.51
diff -b -c -r1.51 cus-start.el
*** lisp/cus-start.el	22 Jul 2002 15:22:49 -0000	1.51
--- lisp/cus-start.el	25 Jul 2002 19:25:49 -0000
***************
*** 57,62 ****
--- 57,68 ----
  	     (indicate-empty-lines display boolean "21.1")
  	     (scroll-up-aggressively windows boolean "21.1")
  	     (scroll-down-aggressively windows boolean "21.1")
+ 	     (abbrev-case-fold 
+ 	      abbrev-mode 
+ 	      (choice (const :tag "Don't ignore case" nil)
+ 		      (const :tag "Ignore case" t)
+ 		      (const :tag "Same as case-fold-search" case-fold-search))
+ 	      "21.4")
  	     ;; callint.c
  	     (mark-even-if-inactive editing-basics boolean)
  	     ;; callproc.c
Index: lisp/emacs-lisp/elint.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/emacs-lisp/elint.el,v
retrieving revision 1.5
diff -b -c -r1.5 elint.el
*** lisp/emacs-lisp/elint.el	22 Dec 2001 13:37:30 -0000	1.5
--- lisp/emacs-lisp/elint.el	25 Jul 2002 19:25:50 -0000
***************
*** 728,734 ****
  ;;;
  
  (defconst elint-standard-variables
!   '(abbrev-mode auto-fill-function buffer-auto-save-file-name
       buffer-backed-up buffer-display-table buffer-file-format
       buffer-file-name buffer-file-number buffer-file-truename
       buffer-file-type buffer-invisibility-spec buffer-offer-save
--- 728,734 ----
  ;;;
  
  (defconst elint-standard-variables
!   '(abbrev-case-fold abbrev-mode auto-fill-function buffer-auto-save-file-name
       buffer-backed-up buffer-display-table buffer-file-format
       buffer-file-name buffer-file-number buffer-file-truename
       buffer-file-type buffer-invisibility-spec buffer-offer-save

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-07-27 18:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-07-25 19:39 [PATCH] Support for case sensitive abbrev expansion Károly Lőrentey
2002-07-26  8:30 ` Miles Bader
2002-07-26 16:21   ` Károly Lőrentey
2002-07-27 18:52   ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).