casing: don’t assume letters are *either* upper- or lower-case (bug#24603)
A compatibility digraph characters, such as Dž, are neither upper- nor lower-case. At the moment however, those are reported as upper-case¹ despite the fact that they change when upper-cased. Stop checking if a character is upper-case before trying to up-case it so that title-case characters are handled correctly. This fixes one of the issues mentioned in bug#24603. ¹ Because they change when converted to lower-case. Notice an asymmetry in that for a character to be considered lower-case it must not be upper-case (plus the usual condition of changing when upper-cased). * src/buffer.h (upcase1): Delete. (upcase): Change to upcase character unconditionally just like downcase does it. This is what upcase1 was. * src/casefiddle.c (casify_object, casify_region): Use upcase instead of upcase1 and don’t check !uppercasep(x) before calling upcase. * src/keyboard.c (read_key_sequence): Don’t check if uppercase(x), just downcase(x) and see if it changed. * test/src/casefiddle-tests.el (casefiddle-tests--characters, casefiddle-tests-casing): Update test cases which are now passing.
This commit is contained in:
parent
5ec3a58462
commit
6220faeb4e
5 changed files with 42 additions and 37 deletions
8
etc/NEWS
8
etc/NEWS
|
@ -338,6 +338,12 @@ same as in modes where the character is not whitespace.
|
|||
Instead of only checking the modification time, Emacs now also checks
|
||||
the file's actual content before prompting the user.
|
||||
|
||||
** Title case characters are properly converted to upper case.
|
||||
'upcase', 'upcase-region' et al. convert title case characters (such
|
||||
as Dz) into their upper case form (such as DZ). As a downside,
|
||||
'capitalize' and 'upcase-initials' produce awkward words where first
|
||||
two letters are upper case, e.g. DŽungla (instead of Džungla).
|
||||
|
||||
|
||||
* Changes in Specialized Modes and Packages in Emacs 26.1
|
||||
|
||||
|
@ -1028,7 +1034,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
Local variables:
|
||||
coding: us-ascii
|
||||
coding: utf-8
|
||||
mode: outline
|
||||
paragraph-separate: "[ ]*$"
|
||||
end:
|
||||
|
|
18
src/buffer.h
18
src/buffer.h
|
@ -1365,28 +1365,28 @@ downcase (int c)
|
|||
return NATNUMP (down) ? XFASTINT (down) : c;
|
||||
}
|
||||
|
||||
/* True if C is upper case. */
|
||||
INLINE bool uppercasep (int c) { return downcase (c) != c; }
|
||||
|
||||
/* Upcase a character C known to be not upper case. */
|
||||
/* Upcase a character C, or make no change if that cannot be done. */
|
||||
INLINE int
|
||||
upcase1 (int c)
|
||||
upcase (int c)
|
||||
{
|
||||
Lisp_Object upcase_table = BVAR (current_buffer, upcase_table);
|
||||
Lisp_Object up = CHAR_TABLE_REF (upcase_table, c);
|
||||
return NATNUMP (up) ? XFASTINT (up) : c;
|
||||
}
|
||||
|
||||
/* True if C is upper case. */
|
||||
INLINE bool uppercasep (int c)
|
||||
{
|
||||
return downcase (c) != c;
|
||||
}
|
||||
|
||||
/* True if C is lower case. */
|
||||
INLINE bool
|
||||
lowercasep (int c)
|
||||
{
|
||||
return !uppercasep (c) && upcase1 (c) != c;
|
||||
return !uppercasep (c) && upcase (c) != c;
|
||||
}
|
||||
|
||||
/* Upcase a character C, or make no change if that cannot be done. */
|
||||
INLINE int upcase (int c) { return uppercasep (c) ? c : upcase1 (c); }
|
||||
|
||||
INLINE_HEADER_END
|
||||
|
||||
#endif /* EMACS_BUFFER_H */
|
||||
|
|
|
@ -64,13 +64,9 @@ casify_object (enum case_action flag, Lisp_Object obj)
|
|||
multibyte = 1;
|
||||
if (! multibyte)
|
||||
MAKE_CHAR_MULTIBYTE (c1);
|
||||
c = downcase (c1);
|
||||
if (inword)
|
||||
XSETFASTINT (obj, c | flags);
|
||||
else if (c == (XFASTINT (obj) & ~flagbits))
|
||||
c = flag == CASE_DOWN ? downcase (c1) : upcase (c1);
|
||||
if (c != c1)
|
||||
{
|
||||
if (! inword)
|
||||
c = upcase1 (c1);
|
||||
if (! multibyte)
|
||||
MAKE_CHAR_UNIBYTE (c);
|
||||
XSETFASTINT (obj, c | flags);
|
||||
|
@ -95,7 +91,7 @@ casify_object (enum case_action flag, Lisp_Object obj)
|
|||
c = downcase (c);
|
||||
else if (!uppercasep (c)
|
||||
&& (!inword || flag != CASE_CAPITALIZE_UP))
|
||||
c = upcase1 (c1);
|
||||
c = upcase (c1);
|
||||
if ((int) flag >= (int) CASE_CAPITALIZE)
|
||||
inword = (SYNTAX (c) == Sword);
|
||||
if (c != c1)
|
||||
|
@ -127,9 +123,8 @@ casify_object (enum case_action flag, Lisp_Object obj)
|
|||
c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i_byte, len);
|
||||
if (inword && flag != CASE_CAPITALIZE_UP)
|
||||
c = downcase (c);
|
||||
else if (!uppercasep (c)
|
||||
&& (!inword || flag != CASE_CAPITALIZE_UP))
|
||||
c = upcase1 (c);
|
||||
else if (!inword || flag != CASE_CAPITALIZE_UP)
|
||||
c = upcase (c);
|
||||
if ((int) flag >= (int) CASE_CAPITALIZE)
|
||||
inword = (SYNTAX (c) == Sword);
|
||||
o += CHAR_STRING (c, o);
|
||||
|
@ -236,9 +231,8 @@ casify_region (enum case_action flag, Lisp_Object b, Lisp_Object e)
|
|||
c2 = c;
|
||||
if (inword && flag != CASE_CAPITALIZE_UP)
|
||||
c = downcase (c);
|
||||
else if (!uppercasep (c)
|
||||
&& (!inword || flag != CASE_CAPITALIZE_UP))
|
||||
c = upcase1 (c);
|
||||
else if (!inword || flag != CASE_CAPITALIZE_UP)
|
||||
c = upcase (c);
|
||||
if ((int) flag >= (int) CASE_CAPITALIZE)
|
||||
inword = ((SYNTAX (c) == Sword)
|
||||
&& (inword || !syntax_prefix_flag_p (c)));
|
||||
|
|
|
@ -9642,22 +9642,26 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
|
|||
use the corresponding lower-case letter instead. */
|
||||
if (NILP (current_binding)
|
||||
&& /* indec.start >= t && fkey.start >= t && */ keytran.start >= t
|
||||
&& INTEGERP (key)
|
||||
&& ((CHARACTERP (make_number (XINT (key) & ~CHAR_MODIFIER_MASK))
|
||||
&& uppercasep (XINT (key) & ~CHAR_MODIFIER_MASK))
|
||||
|| (XINT (key) & shift_modifier)))
|
||||
&& INTEGERP (key))
|
||||
{
|
||||
Lisp_Object new_key;
|
||||
int k = XINT (key);
|
||||
|
||||
if (k & shift_modifier)
|
||||
XSETINT (new_key, k & ~shift_modifier);
|
||||
else if (CHARACTERP (make_number (k & ~CHAR_MODIFIER_MASK)))
|
||||
{
|
||||
int dc = downcase(k & ~CHAR_MODIFIER_MASK);
|
||||
if (dc == (k & ~CHAR_MODIFIER_MASK))
|
||||
goto not_upcase;
|
||||
XSETINT (new_key, dc | (k & CHAR_MODIFIER_MASK));
|
||||
}
|
||||
else
|
||||
goto not_upcase;
|
||||
|
||||
original_uppercase = key;
|
||||
original_uppercase_position = t - 1;
|
||||
|
||||
if (XINT (key) & shift_modifier)
|
||||
XSETINT (new_key, XINT (key) & ~shift_modifier);
|
||||
else
|
||||
XSETINT (new_key, (downcase (XINT (key) & ~CHAR_MODIFIER_MASK)
|
||||
| (XINT (key) & CHAR_MODIFIER_MASK)));
|
||||
|
||||
/* We have to do this unconditionally, regardless of whether
|
||||
the lower-case char is defined in the keymaps, because they
|
||||
might get translated through function-key-map. */
|
||||
|
@ -9668,6 +9672,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
|
|||
goto replay_sequence;
|
||||
}
|
||||
|
||||
not_upcase:
|
||||
if (NILP (current_binding)
|
||||
&& help_char_p (EVENT_HEAD (key)) && t > 1)
|
||||
{
|
||||
|
|
|
@ -63,13 +63,13 @@
|
|||
(?Ł ?Ł ?ł ?Ł)
|
||||
(?ł ?Ł ?ł ?Ł)
|
||||
|
||||
;; FIXME(bug#24603): We should have:
|
||||
;; FIXME(bug#24603): Commented ones are what we want.
|
||||
;;(?DŽ ?DŽ ?dž ?Dž)
|
||||
;; but instead we have:
|
||||
(?DŽ ?DŽ ?dž ?DŽ)
|
||||
;; FIXME(bug#24603): Those two are broken at the moment:
|
||||
;;(?Dž ?DŽ ?dž ?Dž)
|
||||
(?Dž ?DŽ ?dž ?DŽ)
|
||||
;;(?dž ?DŽ ?dž ?Dž)
|
||||
(?dž ?DŽ ?dž ?DŽ)
|
||||
|
||||
(?Σ ?Σ ?σ ?Σ)
|
||||
(?σ ?Σ ?σ ?Σ)
|
||||
|
@ -197,7 +197,7 @@
|
|||
;;("ΌΣΟΣ" "ΌΣΟΣ" "όσος" "Όσος" "Όσος")
|
||||
;; And here’s what is actually happening:
|
||||
("DŽUNGLA" "DŽUNGLA" "džungla" "DŽungla" "DŽUNGLA")
|
||||
("Džungla" "DžUNGLA" "džungla" "Džungla" "Džungla")
|
||||
("Džungla" "DŽUNGLA" "džungla" "DŽungla" "DŽungla")
|
||||
("džungla" "DŽUNGLA" "džungla" "DŽungla" "DŽungla")
|
||||
("define" "DEfiNE" "define" "Define" "Define")
|
||||
("fish" "fiSH" "fish" "fish" "fish")
|
||||
|
|
Loading…
Add table
Reference in a new issue