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_COMPOUND 3 // find case-folded compound word
|
||||||
#define FIND_KEEPCOMPOUND 4 // find keep-case 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_word(matchinf_T *mip, int mode);
|
||||||
static void find_prefix(matchinf_T *mip, int mode);
|
static void find_prefix(matchinf_T *mip, int mode);
|
||||||
static int fold_more(matchinf_T *mip);
|
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 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 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 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.
|
* Main spell-checking function.
|
||||||
@@ -170,7 +176,7 @@ spell_check(
|
|||||||
int lpi;
|
int lpi;
|
||||||
int count_word = docount;
|
int count_word = docount;
|
||||||
int use_camel_case = *wp->w_s->b_p_spo != NUL;
|
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
|
// A word never starts at a space or a control character. Return quickly
|
||||||
// then, skipping over the character.
|
// then, skipping over the character.
|
||||||
@@ -202,27 +208,15 @@ spell_check(
|
|||||||
mi.mi_fend = ptr;
|
mi.mi_fend = ptr;
|
||||||
if (spell_iswordp(mi.mi_fend, wp))
|
if (spell_iswordp(mi.mi_fend, wp))
|
||||||
{
|
{
|
||||||
int prev_upper;
|
|
||||||
int this_upper = FALSE; // init for gcc
|
|
||||||
|
|
||||||
if (use_camel_case)
|
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
|
do
|
||||||
{
|
{
|
||||||
MB_PTR_ADV(mi.mi_fend);
|
MB_PTR_ADV(mi.mi_fend);
|
||||||
if (use_camel_case)
|
} while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp));
|
||||||
{
|
|
||||||
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)
|
|
||||||
&& !camel_case);
|
|
||||||
|
|
||||||
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL)
|
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL)
|
||||||
{
|
{
|
||||||
@@ -253,7 +247,7 @@ spell_check(
|
|||||||
MAXWLEN + 1);
|
MAXWLEN + 1);
|
||||||
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
|
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.
|
// Introduce a fake word end space into the folded word.
|
||||||
mi.mi_fword[mi.mi_fwordlen - 1] = ' ';
|
mi.mi_fword[mi.mi_fwordlen - 1] = ' ';
|
||||||
|
|
||||||
@@ -387,6 +381,75 @@ spell_check(
|
|||||||
return (int)(mi.mi_end - ptr);
|
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.
|
* Check if the word at "mip->mi_word" is in the tree.
|
||||||
* When "mode" is FIND_FOLDWORD check in fold-case word tree.
|
* When "mode" is FIND_FOLDWORD check in fold-case word tree.
|
||||||
|
@@ -132,6 +132,26 @@ foobar/?
|
|||||||
set spell&
|
set spell&
|
||||||
endfunc
|
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()
|
func Test_spell_file_missing()
|
||||||
let s:spell_file_missing = 0
|
let s:spell_file_missing = 0
|
||||||
augroup TestSpellFileMissing
|
augroup TestSpellFileMissing
|
||||||
|
@@ -699,6 +699,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1810,
|
||||||
/**/
|
/**/
|
||||||
1809,
|
1809,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user