emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 5c8fc0b0594: Add 'case-symbols-as-words' to configure symbol case


From: Eli Zaretskii
Subject: master 5c8fc0b0594: Add 'case-symbols-as-words' to configure symbol case behavior
Date: Sun, 29 Oct 2023 07:35:22 -0400 (EDT)

branch: master
commit 5c8fc0b0594b1e3af43d86c0bc96e10d03bc75a2
Author: Spencer Baugh <sbaugh@catern.com>
Commit: Eli Zaretskii <eliz@gnu.org>

    Add 'case-symbols-as-words' to configure symbol case behavior
    
    In some programming languages and styles, a symbol (or every
    symbol in a sequence of symbols) might be capitalized, but the
    individual words making up the symbol should never be capitalized.
    
    For example, in OCaml, type names Look_like_this and variable names
    look_like_this, but it is basically never correct for something to
    Look_Like_This.  And one might have "aa_bb cc_dd ee_ff" or "Aa_bb
    Cc_dd Ee_ff", but never "Aa_Bb Cc_Dd Ee_Ff".
    
    To support this, the new variable 'case-symbols-as-words' causes
    symbol constituents to be treated as part of words only for case
    operations.
    
    * src/casefiddle.c (case_ch_is_word): New function.
    (case_character_impl, case_character): Use 'case_ch_is_word'.
    (syms_of_casefiddle): Define 'case-symbols-as-words'.
    * src/search.c (Freplace_match): Use 'case-symbols-as-words'
    when calculating case pattern.
    * test/src/casefiddle-tests.el (casefiddle-tests--check-syms)
    (casefiddle-case-symbols-as-words): Test 'case-symbols-as-words'.
    * etc/NEWS: Announce 'case-symbols-as-words'.
    * doc/lispref/strings.texi (Case Conversion): Document
    'case-symbols-as-words'.
    (Bug#66614)
---
 doc/lispref/strings.texi     |  8 ++++++--
 etc/NEWS                     |  8 ++++++++
 src/casefiddle.c             | 25 +++++++++++++++++++++++--
 src/search.c                 | 11 +++++++----
 test/src/casefiddle-tests.el | 12 ++++++++++++
 5 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index 7d11db49def..665d4f9a8dc 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -1510,7 +1510,9 @@ case.
 
 The definition of a word is any sequence of consecutive characters that
 are assigned to the word constituent syntax class in the current syntax
-table (@pxref{Syntax Class Table}).
+table (@pxref{Syntax Class Table}), or if @code{case-symbols-as-words}
+is non-nil, also characters assigned to the symbol constituent syntax
+class.
 
 When @var{string-or-char} is a character, this function does the same
 thing as @code{upcase}.
@@ -1542,7 +1544,9 @@ had its initial letter converted to upper case.
 
 The definition of a word is any sequence of consecutive characters that
 are assigned to the word constituent syntax class in the current syntax
-table (@pxref{Syntax Class Table}).
+table (@pxref{Syntax Class Table}), or if @code{case-symbols-as-words}
+is non-nil, also characters assigned to the symbol constituent syntax
+class.
 
 When the argument to @code{upcase-initials} is a character,
 @code{upcase-initials} has the same result as @code{upcase}.
diff --git a/etc/NEWS b/etc/NEWS
index ed9f1a2124c..269346b5917 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1193,6 +1193,14 @@ instead of "ctags", "ebrowse", "etags", "hexl", 
"emacsclient", and
 "rcs2log", when starting one of these built in programs in a
 subprocess.
 
++++
+** New variable 'case-symbols-as-words' affects case operations for symbols.
+If non-nil, then case operations such as 'upcase-initials' or
+'replace-match' (with nil FIXEDCASE) will treat the entire symbol name
+as a single word.  This is useful for programming languages and styles
+where only the first letter of a symbol's name is ever capitalized.
+It defaults to nil.
+
 +++
 ** 'x-popup-menu' now understands touch screen events.
 When a 'touchscreen-begin' or 'touchscreen-end' event is passed as the
diff --git a/src/casefiddle.c b/src/casefiddle.c
index d567a5e353a..3afb131c50e 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -92,6 +92,12 @@ prepare_casing_context (struct casing_context *ctx,
     SETUP_BUFFER_SYNTAX_TABLE ();      /* For syntax_prefix_flag_p.  */
 }
 
+static bool
+case_ch_is_word (enum syntaxcode syntax)
+{
+  return syntax == Sword || (case_symbols_as_words && syntax == Ssymbol);
+}
+
 struct casing_str_buf
 {
   unsigned char data[max (6, MAX_MULTIBYTE_LENGTH)];
@@ -115,7 +121,7 @@ case_character_impl (struct casing_str_buf *buf,
 
   /* Update inword state */
   bool was_inword = ctx->inword;
-  ctx->inword = SYNTAX (ch) == Sword &&
+  ctx->inword = case_ch_is_word (SYNTAX (ch)) &&
     (!ctx->inbuffer || was_inword || !syntax_prefix_flag_p (ch));
 
   /* Normalize flag so its one of CASE_UP, CASE_DOWN or CASE_CAPITALIZE.  */
@@ -222,7 +228,7 @@ case_character (struct casing_str_buf *buf, struct 
casing_context *ctx,
      has a word syntax (i.e. current character is end of word), use final
      sigma.  */
   if (was_inword && ch == GREEK_CAPITAL_LETTER_SIGMA && changed
-      && (!next || SYNTAX (STRING_CHAR (next)) != Sword))
+      && (!next || !case_ch_is_word (SYNTAX (STRING_CHAR (next)))))
     {
       buf->len_bytes = CHAR_STRING (GREEK_SMALL_LETTER_FINAL_SIGMA, buf->data);
       buf->len_chars = 1;
@@ -720,6 +726,21 @@ Called with one argument METHOD which can be:
   3rd argument.  */);
   Vregion_extract_function = Qnil; /* simple.el sets this.  */
 
+  DEFVAR_BOOL ("case-symbols-as-words", case_symbols_as_words,
+    doc: /* If non-nil, case functions treat symbol syntax as part of words.
+
+Functions such as `upcase-initials' and `replace-match' check or modify
+the case pattern of sequences of characters.  Normally, these operate on
+sequences of characters whose syntax is word constituent.  If this
+variable is non-nil, then they operate on sequences of characters whose
+syntax is either word constituent or symbol constituent.
+
+This is useful for programming languages and styles where only the first
+letter of a symbol's name is ever capitalized.*/);
+  case_symbols_as_words = 0;
+  DEFSYM (Qcase_symbols_as_words, "case-symbols-as-words");
+  Fmake_variable_buffer_local (Qcase_symbols_as_words);
+
   defsubr (&Supcase);
   defsubr (&Sdowncase);
   defsubr (&Scapitalize);
diff --git a/src/search.c b/src/search.c
index e9b29bb7179..692d8488049 100644
--- a/src/search.c
+++ b/src/search.c
@@ -2365,7 +2365,7 @@ text has only capital letters and has at least one 
multiletter word,
 convert NEWTEXT to all caps.  Otherwise if all words are capitalized
 in the replaced text, capitalize each word in NEWTEXT.  Note that
 what exactly is a word is determined by the syntax tables in effect
-in the current buffer.
+in the current buffer, and the variable `case-symbols-as-words'.
 
 If optional third arg LITERAL is non-nil, insert NEWTEXT literally.
 Otherwise treat `\\' as special:
@@ -2479,7 +2479,8 @@ since only regular expressions have distinguished 
subexpressions.  */)
              /* Cannot be all caps if any original char is lower case */
 
              some_lowercase = 1;
-             if (SYNTAX (prevc) != Sword)
+             if (SYNTAX (prevc) != Sword
+                 && !(case_symbols_as_words && SYNTAX (prevc) == Ssymbol))
                some_nonuppercase_initial = 1;
              else
                some_multiletter_word = 1;
@@ -2487,7 +2488,8 @@ since only regular expressions have distinguished 
subexpressions.  */)
          else if (uppercasep (c))
            {
              some_uppercase = 1;
-             if (SYNTAX (prevc) != Sword)
+             if (SYNTAX (prevc) != Sword
+                 && !(case_symbols_as_words && SYNTAX (prevc) == Ssymbol))
                ;
              else
                some_multiletter_word = 1;
@@ -2496,7 +2498,8 @@ since only regular expressions have distinguished 
subexpressions.  */)
            {
              /* If the initial is a caseless word constituent,
                 treat that like a lowercase initial.  */
-             if (SYNTAX (prevc) != Sword)
+             if (SYNTAX (prevc) != Sword
+                 && !(case_symbols_as_words && SYNTAX (prevc) == Ssymbol))
                some_nonuppercase_initial = 1;
            }
 
diff --git a/test/src/casefiddle-tests.el b/test/src/casefiddle-tests.el
index e7f4348b0c6..12984d898b9 100644
--- a/test/src/casefiddle-tests.el
+++ b/test/src/casefiddle-tests.el
@@ -294,4 +294,16 @@
     ;;(should (string-equal (capitalize "indIá") "İndıa"))
     ))
 
+(defun casefiddle-tests--check-syms (init with-words with-symbols)
+  (let ((case-symbols-as-words nil))
+    (should (string-equal (upcase-initials init) with-words)))
+  (let ((case-symbols-as-words t))
+    (should (string-equal (upcase-initials init) with-symbols))))
+
+(ert-deftest casefiddle-case-symbols-as-words ()
+  (casefiddle-tests--check-syms "Aa_bb Cc_dd" "Aa_Bb Cc_Dd" "Aa_bb Cc_dd")
+  (casefiddle-tests--check-syms "Aa_bb cc_DD" "Aa_Bb Cc_DD" "Aa_bb Cc_DD")
+  (casefiddle-tests--check-syms "aa_bb cc_dd" "Aa_Bb Cc_Dd" "Aa_bb Cc_dd")
+  (casefiddle-tests--check-syms "Aa_Bb Cc_Dd" "Aa_Bb Cc_Dd" "Aa_Bb Cc_Dd"))
+
 ;;; casefiddle-tests.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]