From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: sbaugh@catern.com Newsgroups: gmane.emacs.bugs Subject: bug#66614: 29.1.50; Support not capitalizing words inside symbols Date: Sat, 21 Oct 2023 15:11:08 +0000 (UTC) Message-ID: <87wmvgroxg.fsf@catern.com> References: <831qdrok34.fsf@gnu.org> <83zg0fmdpm.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="26806"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: Spencer Baugh , 66614@debbugs.gnu.org To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Oct 21 17:11:55 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1quDdq-0006k3-OW for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 21 Oct 2023 17:11:55 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1quDdZ-0000tY-LG; Sat, 21 Oct 2023 11:11:37 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1quDdX-0000tP-8d for bug-gnu-emacs@gnu.org; Sat, 21 Oct 2023 11:11:35 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1quDdX-0007cj-0o for bug-gnu-emacs@gnu.org; Sat, 21 Oct 2023 11:11:35 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1quDdy-00018J-HB for bug-gnu-emacs@gnu.org; Sat, 21 Oct 2023 11:12:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: sbaugh@catern.com Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 21 Oct 2023 15:12:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 66614 X-GNU-PR-Package: emacs Original-Received: via spool by 66614-submit@debbugs.gnu.org id=B66614.16979011114336 (code B ref 66614); Sat, 21 Oct 2023 15:12:02 +0000 Original-Received: (at 66614) by debbugs.gnu.org; 21 Oct 2023 15:11:51 +0000 Original-Received: from localhost ([127.0.0.1]:44877 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1quDdj-00017o-8o for submit@debbugs.gnu.org; Sat, 21 Oct 2023 11:11:51 -0400 Original-Received: from s.wrqvtzvf.outbound-mail.sendgrid.net ([149.72.126.143]:27438) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1quDdd-00017Q-CL for 66614@debbugs.gnu.org; Sat, 21 Oct 2023 11:11:45 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=catern.com; h=from:subject:in-reply-to:references:mime-version:to:cc:content-type: cc:content-type:from:subject:to; s=s1; bh=LwLTPTSExTmmP1Gk6ohnIfrcSQoxUjzgLPFkGA/xqss=; b=ylPCGAbDMGceg5x7otP9Y2b+9PW/fGAlSOgPSatwfthC1CkTvr5O9siiStkRk8F1FGxL 3iWlj7aUa7tP8exiol12bG3nOuLNBL1qL6nbJofKeR6rmBSBskj8sRQS2gw/+xKmHLIAO7 +h/yZ7Mwv0dHbSwPd7/5uHTSeI3DTEmHd2jH21fnrW7+zxyfoL/t/hPPo0dDY+kGgR8pdk X2+KuTng74rUOzeuaXp248ulCvWBbktVXgiLq/pC0QW7ebWA5+CRyaWw5Axd2j8ackrK5j Z9RjJq7eRWHvO9OeQX14ts3RxVAjffWopXCB0TvXzxFVUma5uudL3tKVOjMThmHg== Original-Received: by filterdrecv-5bbdbb56cd-h9hcp with SMTP id filterdrecv-5bbdbb56cd-h9hcp-1-6533EA0C-2 2023-10-21 15:11:08.073493827 +0000 UTC m=+333079.648129779 Original-Received: from earth.catern.com (unknown) by geopod-ismtpd-36 (SG) with ESMTP id hi6sN3WoSTiDLodmZI7dXA Sat, 21 Oct 2023 15:11:07.989 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=::1; helo=localhost; envelope-from=sbaugh@catern.com; receiver=gnu.org Original-Received: from localhost (localhost [IPv6:::1]) by earth.catern.com (Postfix) with ESMTPSA id 881046360E; Sat, 21 Oct 2023 11:11:07 -0400 (EDT) In-Reply-To: <83zg0fmdpm.fsf@gnu.org> (Eli Zaretskii's message of "Thu, 19 Oct 2023 07:35:33 +0300") X-SG-EID: ZgbRq7gjGrt0q/Pjvxk7wM0yQFRdOkTJAtEbkjCkHbKkzMtZIoMQrhduyXzOA5gy8VWGai6eIkslCr0jm6M2cbvkA3cKsk9VehQMoP1dhsl+MeTwqEhsbVUvVU5tkrF3oODkDFtFTWon8MdXzjgabrBK06MmgHqfHZwMjN37fLZm4Pr4/5szAgNsp7kuxb/v3NCBevYDZ34xAqjnx/6twA== X-Entity-ID: d/0VcHixlS0t7iB1YKCv4Q== X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:272914 Archived-At: --=-=-= Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Eli Zaretskii writes: >> From: Spencer Baugh >> Cc: 66614@debbugs.gnu.org >> Date: Wed, 18 Oct 2023 15:38:34 -0400 >> >> >> + 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 who >> >> +syntax is either word constituent or symbol constituent. >> >> + >> >> +This is useful for programming styles which wish to capitalize the >> >> +beginning of symbols, but not capitalize individual words in a symbol.*/); >> > >> > Similar comments about this doc string. >> >> Fixed. >> >> > Also, shouldn't this variable be buffer-local? You want certain major >> > modes to set it, right? >> >> Yes, I want certain major modes to set it, although it's also possible >> that some users will want to set it globally. >> >> Are you suggesting it should be a DEFVAR_PER_BUFFER? I can do that, but >> I didn't think it was worth putting another slot into struct buffer. > > You don't have to add it to the buffer structure, you could call > Fmake_variable_buffer_local instead. We already do that for some > variables. Oh, of course. Done. --=-=-= Content-Type: text/x-patch; charset=utf-8 Content-Disposition: inline; filename=0001-Add-case-symbols-as-words-to-configure-symbol-case-b.patch Content-Transfer-Encoding: quoted-printable >From 22540be262399f3ec232da713b3ba454299e18d2 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Sat, 21 Oct 2023 11:09:39 -0400 Subject: [PATCH] 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): Add. (case_character_impl): Use case_ch_is_word. (case_character): Use case_ch_is_word. (syms_of_casefiddle): Define case-symbols-as-words. (bug#66614) * 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. --- 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 Conversion =20 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. =20 When @var{string-or-char} is a character, this function does the same thing as @code{upcase}. @@ -1542,7 +1544,9 @@ Case Conversion =20 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. =20 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 4a44782f972..9d1a81789c6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1131,6 +1131,14 @@ instead of "ctags", "ebrowse", "etags", "hexl", "ema= csclient", and "rcs2log", when starting one of these built in programs in a subprocess. =20 ++++ +** New variable 'case-symbols-as-words' affects case operations for symbol= s. +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. */ } =20 +static bool +case_ch_is_word (enum syntaxcode syntax) +{ + return syntax =3D=3D Sword || (case_symbols_as_words && syntax =3D=3D Ss= ymbol); +} + struct casing_str_buf { unsigned char data[max (6, MAX_MULTIBYTE_LENGTH)]; @@ -115,7 +121,7 @@ case_character_impl (struct casing_str_buf *buf, =20 /* Update inword state */ bool was_inword =3D ctx->inword; - ctx->inword =3D SYNTAX (ch) =3D=3D Sword && + ctx->inword =3D case_ch_is_word (SYNTAX (ch)) && (!ctx->inbuffer || was_inword || !syntax_prefix_flag_p (ch)); =20 /* 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 casi= ng_context *ctx, has a word syntax (i.e. current character is end of word), use final sigma. */ if (was_inword && ch =3D=3D GREEK_CAPITAL_LETTER_SIGMA && changed - && (!next || SYNTAX (STRING_CHAR (next)) !=3D Sword)) + && (!next || !case_ch_is_word (SYNTAX (STRING_CHAR (next))))) { buf->len_bytes =3D CHAR_STRING (GREEK_SMALL_LETTER_FINAL_SIGMA, buf-= >data); buf->len_chars =3D 1; @@ -720,6 +726,21 @@ syms_of_casefiddle (void) 3rd argument. */); Vregion_extract_function =3D Qnil; /* simple.el sets this. */ =20 + DEFVAR_BOOL ("case-symbols-as-words", case_symbols_as_words, + doc: /* If non-nil, case functions treat symbol syntax as part of word= s. + +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 =3D 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 @@ DEFUN ("replace-match", Freplace_match, Sreplace_matc= h, 1, 5, 0, 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'. =20 If optional third arg LITERAL is non-nil, insert NEWTEXT literally. Otherwise treat `\\' as special: @@ -2479,7 +2479,8 @@ DEFUN ("replace-match", Freplace_match, Sreplace_matc= h, 1, 5, 0, /* Cannot be all caps if any original char is lower case */ =20 some_lowercase =3D 1; - if (SYNTAX (prevc) !=3D Sword) + if (SYNTAX (prevc) !=3D Sword + && !(case_symbols_as_words && SYNTAX (prevc) =3D=3D Ssymbol)) some_nonuppercase_initial =3D 1; else some_multiletter_word =3D 1; @@ -2487,7 +2488,8 @@ DEFUN ("replace-match", Freplace_match, Sreplace_matc= h, 1, 5, 0, else if (uppercasep (c)) { some_uppercase =3D 1; - if (SYNTAX (prevc) !=3D Sword) + if (SYNTAX (prevc) !=3D Sword + && !(case_symbols_as_words && SYNTAX (prevc) =3D=3D Ssymbol)) ; else some_multiletter_word =3D 1; @@ -2496,7 +2498,8 @@ DEFUN ("replace-match", Freplace_match, Sreplace_matc= h, 1, 5, 0, { /* If the initial is a caseless word constituent, treat that like a lowercase initial. */ - if (SYNTAX (prevc) !=3D Sword) + if (SYNTAX (prevc) !=3D Sword + && !(case_symbols_as_words && SYNTAX (prevc) =3D=3D Ssymbol)) some_nonuppercase_initial =3D 1; } =20 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 @@ casefiddle-turkish ;;(should (string-equal (capitalize "indI=C3=A1") "=C4=B0nd=C4=B1a")) )) =20 +(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 --=20 2.41.0 --=-=-=--