forked from aniani/vim
patch 9.0.1810: camel-case spelling has issues with digits
Problem: camel-case spelling has issues with digits Solution: Improve the camCase spell checking by taking digits and caps into account Rewrite the conditions to check for word boundaries by taking into account the presence of digits and all-caps sequences such as acronyms. closes: #12644 closes: #12933 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: LemonBoy <thatlemon@gmail.com>
This commit is contained in:
committed by
Christian Brabandt
parent
6c93c94929
commit
d08745040b
97
src/spell.c
97
src/spell.c
@@ -125,6 +125,11 @@ static int spell_mb_isword_class(int cl, win_T *wp);
|
||||
#define FIND_COMPOUND 3 // find case-folded compound word
|
||||
#define FIND_KEEPCOMPOUND 4 // find keep-case compound word
|
||||
|
||||
// type values for get_char_type
|
||||
#define CHAR_OTHER 0
|
||||
#define CHAR_UPPER 1
|
||||
#define CHAR_DIGIT 2
|
||||
|
||||
static void find_word(matchinf_T *mip, int mode);
|
||||
static void find_prefix(matchinf_T *mip, int mode);
|
||||
static int fold_more(matchinf_T *mip);
|
||||
@@ -138,6 +143,7 @@ static void spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res);
|
||||
static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res);
|
||||
static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int round, int flags, linenr_T lnum);
|
||||
static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, int *dir, int round, int flags, linenr_T startlnum);
|
||||
static char_u *advance_camelcase_word(char_u *p, win_T *wp, int *is_camel_case);
|
||||
|
||||
/*
|
||||
* Main spell-checking function.
|
||||
@@ -170,7 +176,7 @@ spell_check(
|
||||
int lpi;
|
||||
int count_word = docount;
|
||||
int use_camel_case = *wp->w_s->b_p_spo != NUL;
|
||||
int camel_case = 0;
|
||||
int is_camel_case = FALSE;
|
||||
|
||||
// A word never starts at a space or a control character. Return quickly
|
||||
// then, skipping over the character.
|
||||
@@ -202,27 +208,15 @@ spell_check(
|
||||
mi.mi_fend = ptr;
|
||||
if (spell_iswordp(mi.mi_fend, wp))
|
||||
{
|
||||
int prev_upper;
|
||||
int this_upper = FALSE; // init for gcc
|
||||
|
||||
if (use_camel_case)
|
||||
mi.mi_fend = advance_camelcase_word(ptr, wp, &is_camel_case);
|
||||
else
|
||||
{
|
||||
c = PTR2CHAR(mi.mi_fend);
|
||||
this_upper = SPELL_ISUPPER(c);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
MB_PTR_ADV(mi.mi_fend);
|
||||
if (use_camel_case)
|
||||
{
|
||||
prev_upper = this_upper;
|
||||
c = PTR2CHAR(mi.mi_fend);
|
||||
this_upper = SPELL_ISUPPER(c);
|
||||
camel_case = !prev_upper && this_upper;
|
||||
} while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp));
|
||||
}
|
||||
} while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp)
|
||||
&& !camel_case);
|
||||
|
||||
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL)
|
||||
{
|
||||
@@ -253,7 +247,7 @@ spell_check(
|
||||
MAXWLEN + 1);
|
||||
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
|
||||
|
||||
if (camel_case && mi.mi_fwordlen > 0)
|
||||
if (is_camel_case && mi.mi_fwordlen > 0)
|
||||
// Introduce a fake word end space into the folded word.
|
||||
mi.mi_fword[mi.mi_fwordlen - 1] = ' ';
|
||||
|
||||
@@ -387,6 +381,75 @@ spell_check(
|
||||
return (int)(mi.mi_end - ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the type of character 'c'.
|
||||
*/
|
||||
static int
|
||||
get_char_type(int c)
|
||||
{
|
||||
if (VIM_ISDIGIT(c))
|
||||
return CHAR_DIGIT;
|
||||
if (SPELL_ISUPPER(c))
|
||||
return CHAR_UPPER;
|
||||
return CHAR_OTHER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a pointer to the end of the word starting at "str".
|
||||
* Supports camelCase words.
|
||||
*/
|
||||
static char_u *
|
||||
advance_camelcase_word(char_u *str, win_T *wp, int *is_camel_case)
|
||||
{
|
||||
int last_type, last_last_type, this_type;
|
||||
int c;
|
||||
char_u *end = str;
|
||||
|
||||
*is_camel_case = FALSE;
|
||||
|
||||
if (*str == NUL)
|
||||
return str;
|
||||
|
||||
c = PTR2CHAR(end);
|
||||
MB_PTR_ADV(end);
|
||||
// We need at most the types of the type of the last two chars.
|
||||
last_last_type = -1;
|
||||
last_type = get_char_type(c);
|
||||
|
||||
while (*end != NUL && spell_iswordp(end, wp))
|
||||
{
|
||||
c = PTR2CHAR(end);
|
||||
this_type = get_char_type(c);
|
||||
|
||||
if (last_last_type == CHAR_UPPER && last_type == CHAR_UPPER
|
||||
&& this_type == CHAR_OTHER)
|
||||
{
|
||||
// Handle the following cases:
|
||||
// UpperUpperLower
|
||||
*is_camel_case = TRUE;
|
||||
// Back up by one char.
|
||||
MB_PTR_BACK(str, end);
|
||||
break;
|
||||
}
|
||||
else if ((this_type == CHAR_UPPER && last_type == CHAR_OTHER)
|
||||
|| (this_type != last_type
|
||||
&& (this_type == CHAR_DIGIT || last_type == CHAR_DIGIT)))
|
||||
{
|
||||
// Handle the following cases:
|
||||
// LowerUpper LowerDigit UpperDigit DigitUpper DigitLower
|
||||
*is_camel_case = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
last_last_type = last_type;
|
||||
last_type = this_type;
|
||||
|
||||
MB_PTR_ADV(end);
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the word at "mip->mi_word" is in the tree.
|
||||
* When "mode" is FIND_FOLDWORD check in fold-case word tree.
|
||||
|
@@ -132,6 +132,26 @@ foobar/?
|
||||
set spell&
|
||||
endfunc
|
||||
|
||||
func Test_spell_camelcase()
|
||||
set spell spelloptions=camel
|
||||
let words = [
|
||||
\ 'UPPER',
|
||||
\ 'lower',
|
||||
\ 'mixedCase',
|
||||
\ 'HTML',
|
||||
\ 'XMLHttpRequest',
|
||||
\ 'foo123bar',
|
||||
\ '12345678',
|
||||
\ 'HELLO123world',
|
||||
\]
|
||||
|
||||
for word in words
|
||||
call assert_equal(['', ''], spellbadword(word))
|
||||
endfor
|
||||
|
||||
set spell& spelloptions&
|
||||
endfunc
|
||||
|
||||
func Test_spell_file_missing()
|
||||
let s:spell_file_missing = 0
|
||||
augroup TestSpellFileMissing
|
||||
|
@@ -699,6 +699,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1810,
|
||||
/**/
|
||||
1809,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user