Merge pull request #16047 from mcepl/vim-8.2.3520

vim-patch:8.2.3520: cannot define a function for thesaurus completion
This commit is contained in:
Jan Edmund Lazo
2021-11-14 21:23:42 -05:00
committed by GitHub
11 changed files with 194 additions and 45 deletions

View File

@@ -804,6 +804,9 @@ CTRL-X CTRL-K Search the files given with the 'dictionary' option
CTRL-P Search backwards for next matching keyword. This CTRL-P Search backwards for next matching keyword. This
keyword replaces the previous matching keyword. keyword replaces the previous matching keyword.
Completing words in 'thesaurus' *compl-thesaurus*
*i_CTRL-X_CTRL-T* *i_CTRL-X_CTRL-T*
CTRL-X CTRL-T Works as CTRL-X CTRL-K, but in a special way. It uses CTRL-X CTRL-T Works as CTRL-X CTRL-K, but in a special way. It uses
the 'thesaurus' option instead of 'dictionary'. If a the 'thesaurus' option instead of 'dictionary'. If a
@@ -812,16 +815,6 @@ CTRL-X CTRL-T Works as CTRL-X CTRL-K, but in a special way. It uses
matches, even though they don't complete the word. matches, even though they don't complete the word.
Thus a word can be completely replaced. Thus a word can be completely replaced.
For an example, imagine the 'thesaurus' file has a
line like this: >
angry furious mad enraged
< Placing the cursor after the letters "ang" and typing
CTRL-X CTRL-T would complete the word "angry";
subsequent presses would change the word to "furious",
"mad" etc.
Other uses include translation between two languages,
or grouping API functions by keyword.
CTRL-T or CTRL-T or
CTRL-N Search forward for next matching keyword. This CTRL-N Search forward for next matching keyword. This
keyword replaces the previous matching keyword. keyword replaces the previous matching keyword.
@@ -829,6 +822,59 @@ CTRL-X CTRL-T Works as CTRL-X CTRL-K, but in a special way. It uses
CTRL-P Search backwards for next matching keyword. This CTRL-P Search backwards for next matching keyword. This
keyword replaces the previous matching keyword. keyword replaces the previous matching keyword.
In the file used by the 'thesaurus' option each line in the file should
contain words with similar meaning, separated by non-keyword characters (white
space is preferred). Maximum line length is 510 bytes.
For an example, imagine the 'thesaurus' file has a line like this: >
angry furious mad enraged
<Placing the cursor after the letters "ang" and typing CTRL-X CTRL-T would
complete the word "angry"; subsequent presses would change the word to
"furious", "mad" etc.
Other uses include translation between two languages, or grouping API
functions by keyword.
An English word list was added to this github issue:
https://github.com/vim/vim/issues/629#issuecomment-443293282
Unpack thesaurus_pkg.zip, put the thesaurus.txt file somewhere, e.g.
~/.vim/thesaurus/english.txt, and the 'thesaurus' option to this file name.
Completing keywords with 'thesaurusfunc' *compl-thesaurusfunc*
If the 'thesaurusfunc' option is set, then the user specified function is
invoked to get the list of completion matches and the 'thesaurus' option is
not used. See |complete-functions| for an explanation of how the function is
invoked and what it should return.
Here is an example that uses the "aiksaurus" command (provided by Magnus
Groß): >
func Thesaur(findstart, base)
if a:findstart
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] =~ '\a'
let start -= 1
endwhile
return start
else
let res = []
let h = ''
for l in split(system('aiksaurus '.shellescape(a:base)), '\n')
if l[:3] == '=== '
let h = substitute(l[4:], ' =*$', '', '')
elseif l[0] =~ '\a'
call extend(res, map(split(l, ', '), {_, val -> {'word': val, 'menu': '('.h.')'}}))
endif
endfor
return res
endif
endfunc
set thesaurusfunc=Thesaur
Completing keywords in the current and included files *compl-keyword* Completing keywords in the current and included files *compl-keyword*
@@ -1032,7 +1078,7 @@ CTRL-X CTRL-Z Stop completion without changing the text.
FUNCTIONS FOR FINDING COMPLETIONS *complete-functions* FUNCTIONS FOR FINDING COMPLETIONS *complete-functions*
This applies to 'completefunc' and 'omnifunc'. This applies to 'completefunc', 'thesaurusfunc' and 'omnifunc'.
The function is called in two different ways: The function is called in two different ways:
- First the function is called to find the start of the text to be completed. - First the function is called to find the start of the text to be completed.

View File

@@ -6448,19 +6448,28 @@ A jump table for the options with a short description can be found at |Q_op|.
'thesaurus' 'tsr' string (default "") 'thesaurus' 'tsr' string (default "")
global or local to buffer |global-local| global or local to buffer |global-local|
List of file names, separated by commas, that are used to lookup words List of file names, separated by commas, that are used to lookup words
for thesaurus completion commands |i_CTRL-X_CTRL-T|. for thesaurus completion commands |i_CTRL-X_CTRL-T|. See
|compl-thesaurus|.
Each line in the file should contain words with similar meaning, This option is not used if 'thesaurusfunc' is set, either for the
separated by non-keyword characters (white space is preferred). buffer or globally.
Maximum line length is 510 bytes.
To include a comma in a file name precede it with a backslash. Spaces To include a comma in a file name precede it with a backslash. Spaces
after a comma are ignored, otherwise spaces are included in the file after a comma are ignored, otherwise spaces are included in the file
name. See |option-backslash| about using backslashes. name. See |option-backslash| about using backslashes. The use of
The use of |:set+=| and |:set-=| is preferred when adding or removing |:set+=| and |:set-=| is preferred when adding or removing directories
directories from the list. This avoids problems when a future version from the list. This avoids problems when a future version uses
uses another default. another default. Backticks cannot be used in this option for security
Backticks cannot be used in this option for security reasons. reasons.
*'thesaurusfunc'* *'tsrfu'*
'thesaurusfunc' 'tsrfu' string (default: empty)
global or local to buffer |global-local|
This option specifies a function to be used for thesaurus completion
with CTRL-X CTRL-T. |i_CTRL-X_CTRL-T| See |compl-thesaurusfunc|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
*'tildeop'* *'top'* *'notildeop'* *'notop'* *'tildeop'* *'top'* *'notildeop'* *'notop'*
'tildeop' 'top' boolean (default off) 'tildeop' 'top' boolean (default off)

View File

@@ -895,6 +895,7 @@ Short explanation of each option: *option-list*
'terse' shorten some messages 'terse' shorten some messages
'textwidth' 'tw' maximum width of text that is being inserted 'textwidth' 'tw' maximum width of text that is being inserted
'thesaurus' 'tsr' list of thesaurus files for keyword completion 'thesaurus' 'tsr' list of thesaurus files for keyword completion
'thesaurusfunc' 'tsrfu' function to be used for thesaurus completion
'tildeop' 'top' tilde command "~" behaves like an operator 'tildeop' 'top' tilde command "~" behaves like an operator
'timeout' 'to' time out on mappings and key codes 'timeout' 'to' time out on mappings and key codes
'timeoutlen' 'tm' time out time in milliseconds 'timeoutlen' 'tm' time out time in milliseconds

View File

@@ -1925,6 +1925,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_cpt); clear_string_option(&buf->b_p_cpt);
clear_string_option(&buf->b_p_cfu); clear_string_option(&buf->b_p_cfu);
clear_string_option(&buf->b_p_ofu); clear_string_option(&buf->b_p_ofu);
clear_string_option(&buf->b_p_tsrfu);
clear_string_option(&buf->b_p_gp); clear_string_option(&buf->b_p_gp);
clear_string_option(&buf->b_p_mp); clear_string_option(&buf->b_p_mp);
clear_string_option(&buf->b_p_efm); clear_string_option(&buf->b_p_efm);

View File

@@ -766,6 +766,7 @@ struct file_buffer {
unsigned b_tc_flags; ///< flags for 'tagcase' unsigned b_tc_flags; ///< flags for 'tagcase'
char_u *b_p_dict; ///< 'dictionary' local value char_u *b_p_dict; ///< 'dictionary' local value
char_u *b_p_tsr; ///< 'thesaurus' local value char_u *b_p_tsr; ///< 'thesaurus' local value
char_u *b_p_tsrfu; ///< 'thesaurusfunc' local value
long b_p_ul; ///< 'undolevels' local value long b_p_ul; ///< 'undolevels' local value
int b_p_udf; ///< 'undofile' int b_p_udf; ///< 'undofile'
char_u *b_p_lw; ///< 'lispwords' local value char_u *b_p_lw; ///< 'lispwords' local value

View File

@@ -2071,7 +2071,8 @@ static bool check_compl_option(bool dict_opt)
{ {
if (dict_opt if (dict_opt
? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell) ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
: (*curbuf->b_p_tsr == NUL && *p_tsr == NUL)) { : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL
&& *curbuf->b_p_tsrfu == NUL && *p_tsrfu == NUL)) {
ctrl_x_mode = CTRL_X_NORMAL; ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL; edit_submode = NULL;
msg_attr((dict_opt msg_attr((dict_opt
@@ -3922,6 +3923,20 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
} }
/// Get the user-defined completion function name for completion 'type'
static char_u *get_complete_funcname(int type) {
switch (type) {
case CTRL_X_FUNCTION:
return curbuf->b_p_cfu;
case CTRL_X_OMNI:
return curbuf->b_p_ofu;
case CTRL_X_THESAURUS:
return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu;
default:
return (char_u *)"";
}
}
/// Execute user defined complete function 'completefunc' or 'omnifunc', and /// Execute user defined complete function 'completefunc' or 'omnifunc', and
/// get matches in "matches". /// get matches in "matches".
/// ///
@@ -3938,7 +3953,7 @@ static void expand_by_function(int type, char_u *base)
const int save_State = State; const int save_State = State;
assert(curbuf != NULL); assert(curbuf != NULL);
funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu; funcname = get_complete_funcname(type);
if (*funcname == NUL) { if (*funcname == NUL) {
return; return;
} }
@@ -4097,6 +4112,13 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
(char_u **)cptext, true, &user_data, dir, flags, dup); (char_u **)cptext, true, &user_data, dir, flags, dup);
} }
/// Returns true when using a user-defined function for thesaurus completion.
static bool thesaurus_func_complete(int type)
{
return type == CTRL_X_THESAURUS
&& (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
}
// Get the next expansion(s), using "compl_pattern". // Get the next expansion(s), using "compl_pattern".
// The search starts at position "ini" in curbuf and in the direction // The search starts at position "ini" in curbuf and in the direction
// compl_direction. // compl_direction.
@@ -4270,17 +4292,17 @@ static int ins_compl_get_exp(pos_T *ini)
case CTRL_X_DICTIONARY: case CTRL_X_DICTIONARY:
case CTRL_X_THESAURUS: case CTRL_X_THESAURUS:
ins_compl_dictionaries(dict != NULL ? dict if (thesaurus_func_complete(type)) {
: (type == CTRL_X_THESAURUS expand_by_function(type, compl_pattern);
? (*curbuf->b_p_tsr == NUL } else {
? p_tsr ins_compl_dictionaries(dict != NULL ? dict
: curbuf->b_p_tsr) : (type == CTRL_X_THESAURUS
: (*curbuf->b_p_dict == NUL ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
? p_dict : (*curbuf->b_p_dict ==
: curbuf->b_p_dict)), NUL ? p_dict : curbuf->b_p_dict)),
compl_pattern, compl_pattern,
dict != NULL ? dict_f dict != NULL ? dict_f : 0, type == CTRL_X_THESAURUS);
: 0, type == CTRL_X_THESAURUS); }
dict = NULL; dict = NULL;
break; break;
@@ -5093,7 +5115,9 @@ static int ins_complete(int c, bool enable_pum)
} }
// Work out completion pattern and original text -- webb // Work out completion pattern and original text -- webb
if (ctrl_x_mode == CTRL_X_NORMAL || (ctrl_x_mode & CTRL_X_WANT_IDENT)) { if (ctrl_x_mode == CTRL_X_NORMAL
|| (ctrl_x_mode & CTRL_X_WANT_IDENT
&& !thesaurus_func_complete(ctrl_x_mode))) {
if ((compl_cont_status & CONT_SOL) if ((compl_cont_status & CONT_SOL)
|| ctrl_x_mode == CTRL_X_PATH_DEFINES) { || ctrl_x_mode == CTRL_X_PATH_DEFINES) {
if (!(compl_cont_status & CONT_ADDING)) { if (!(compl_cont_status & CONT_ADDING)) {
@@ -5203,22 +5227,18 @@ static int ins_complete(int c, bool enable_pum)
compl_col = (int)(compl_xp.xp_pattern - compl_pattern); compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
} }
compl_length = curs_col - compl_col; compl_length = curs_col - compl_col;
} else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == } else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
CTRL_X_OMNI) { || thesaurus_func_complete(ctrl_x_mode)) {
/* // Call user defined function 'completefunc' with "a:findstart"
* Call user defined function 'completefunc' with "a:findstart" // set to 1 to obtain the length of text to use for completion.
* set to 1 to obtain the length of text to use for completion.
*/
char_u *funcname; char_u *funcname;
pos_T pos; pos_T pos;
win_T *curwin_save; win_T *curwin_save;
buf_T *curbuf_save; buf_T *curbuf_save;
const int save_State = State; const int save_State = State;
/* Call 'completefunc' or 'omnifunc' and get pattern length as a // Call 'completefunc' or 'omnifunc' and get pattern length as a string
* string */ funcname = get_complete_funcname(ctrl_x_mode);
funcname = ctrl_x_mode == CTRL_X_FUNCTION
? curbuf->b_p_cfu : curbuf->b_p_ofu;
if (*funcname == NUL) { if (*funcname == NUL) {
semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
? "completefunc" : "omnifunc"); ? "completefunc" : "omnifunc");

View File

@@ -2034,6 +2034,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_tc); check_string_option(&buf->b_p_tc);
check_string_option(&buf->b_p_dict); check_string_option(&buf->b_p_dict);
check_string_option(&buf->b_p_tsr); check_string_option(&buf->b_p_tsr);
check_string_option(&buf->b_p_tsrfu);
check_string_option(&buf->b_p_lw); check_string_option(&buf->b_p_lw);
check_string_option(&buf->b_p_bkc); check_string_option(&buf->b_p_bkc);
check_string_option(&buf->b_p_menc); check_string_option(&buf->b_p_menc);
@@ -5536,6 +5537,9 @@ void unset_global_local_option(char *name, void *from)
case PV_TSR: case PV_TSR:
clear_string_option(&buf->b_p_tsr); clear_string_option(&buf->b_p_tsr);
break; break;
case PV_TSRFU:
clear_string_option(&buf->b_p_tsrfu);
break;
case PV_FP: case PV_FP:
clear_string_option(&buf->b_p_fp); clear_string_option(&buf->b_p_fp);
break; break;
@@ -5619,6 +5623,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
return (char_u *)&(curbuf->b_p_dict); return (char_u *)&(curbuf->b_p_dict);
case PV_TSR: case PV_TSR:
return (char_u *)&(curbuf->b_p_tsr); return (char_u *)&(curbuf->b_p_tsr);
case PV_TSRFU:
return (char_u *)&(curbuf->b_p_tsrfu);
case PV_TFU: case PV_TFU:
return (char_u *)&(curbuf->b_p_tfu); return (char_u *)&(curbuf->b_p_tfu);
case PV_SBR: case PV_SBR:
@@ -5695,6 +5701,9 @@ static char_u *get_varp(vimoption_T *p)
case PV_TSR: case PV_TSR:
return *curbuf->b_p_tsr != NUL return *curbuf->b_p_tsr != NUL
? (char_u *)&(curbuf->b_p_tsr) : p->var; ? (char_u *)&(curbuf->b_p_tsr) : p->var;
case PV_TSRFU:
return *curbuf->b_p_tsrfu != NUL
? (char_u *)&(curbuf->b_p_tsrfu) : p->var;
case PV_FP: case PV_FP:
return *curbuf->b_p_fp != NUL return *curbuf->b_p_fp != NUL
? (char_u *)&(curbuf->b_p_fp) : p->var; ? (char_u *)&(curbuf->b_p_fp) : p->var;
@@ -6253,6 +6262,7 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inex = vim_strsave(p_inex); buf->b_p_inex = vim_strsave(p_inex);
buf->b_p_dict = empty_option; buf->b_p_dict = empty_option;
buf->b_p_tsr = empty_option; buf->b_p_tsr = empty_option;
buf->b_p_tsrfu = empty_option;
buf->b_p_qe = vim_strsave(p_qe); buf->b_p_qe = vim_strsave(p_qe);
buf->b_p_udf = p_udf; buf->b_p_udf = p_udf;
buf->b_p_lw = empty_option; buf->b_p_lw = empty_option;

View File

@@ -686,6 +686,7 @@ EXTERN long p_titlelen; ///< 'titlelen'
EXTERN char_u *p_titleold; ///< 'titleold' EXTERN char_u *p_titleold; ///< 'titleold'
EXTERN char_u *p_titlestring; ///< 'titlestring' EXTERN char_u *p_titlestring; ///< 'titlestring'
EXTERN char_u *p_tsr; ///< 'thesaurus' EXTERN char_u *p_tsr; ///< 'thesaurus'
EXTERN char_u *p_tsrfu; ///< 'thesaurusfunc'
EXTERN int p_tgc; ///< 'termguicolors' EXTERN int p_tgc; ///< 'termguicolors'
EXTERN int p_ttimeout; ///< 'ttimeout' EXTERN int p_ttimeout; ///< 'ttimeout'
EXTERN long p_ttm; ///< 'ttimeoutlen' EXTERN long p_ttm; ///< 'ttimeoutlen'
@@ -826,6 +827,7 @@ enum {
BV_SW, BV_SW,
BV_SWF, BV_SWF,
BV_TFU, BV_TFU,
BV_TSRFU,
BV_TAGS, BV_TAGS,
BV_TC, BV_TC,
BV_TS, BV_TS,

View File

@@ -2535,6 +2535,15 @@ return {
varname='p_tsr', varname='p_tsr',
defaults={if_true=""} defaults={if_true=""}
}, },
{
full_name='thesaurusfunc', abbreviation='tsrfu',
short_desc=N_("function used for thesaurus completion"),
type='string', scope={'global', 'buffer'},
secure=true,
alloced=true,
varname='p_tsrfu',
defaults={if_true=""}
},
{ {
full_name='tildeop', abbreviation='top', full_name='tildeop', abbreviation='top',
short_desc=N_("tilde command \"~\" behaves like an operator"), short_desc=N_("tilde command \"~\" behaves like an operator"),

View File

@@ -870,6 +870,56 @@ func Test_edit_CTRL_T()
bw! bw!
endfunc endfunc
" Test 'thesaurusfunc'
func MyThesaurus(findstart, base)
let mythesaurus = [
\ #{word: "happy",
\ synonyms: "cheerful,blissful,flying high,looking good,peppy"},
\ #{word: "kind",
\ synonyms: "amiable,bleeding-heart,heart in right place"}]
if a:findstart
" locate the start of the word
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] =~ '\a'
let start -= 1
endwhile
return start
else
" find strings matching with "a:base"
let res = []
for w in mythesaurus
if w.word =~ '^' . a:base
call add(res, w.word)
call extend(res, split(w.synonyms, ","))
endif
endfor
return res
endif
endfunc
func Test_thesaurus_func()
new
set thesaurus=notused
set thesaurusfunc=NotUsed
setlocal thesaurusfunc=MyThesaurus
call setline(1, "an ki")
call cursor(1, 1)
call feedkeys("A\<c-x>\<c-t>\<c-n>\<cr>\<esc>", 'tnix')
call assert_equal(['an amiable', ''], getline(1, '$'))
setlocal thesaurusfunc=NonExistingFunc
call assert_fails("normal $a\<C-X>\<C-T>", 'E117:')
setlocal thesaurusfunc=
set thesaurusfunc=NonExistingFunc
call assert_fails("normal $a\<C-X>\<C-T>", 'E117:')
%bw!
set thesaurusfunc=
set thesaurus=
endfunc
func Test_edit_CTRL_U() func Test_edit_CTRL_U()
" Test 'completefunc' " Test 'completefunc'
new new

View File

@@ -209,7 +209,7 @@ func Test_set_completion()
" Expand abbreviation of options. " Expand abbreviation of options.
call feedkeys(":set ts\<C-A>\<C-B>\"\<CR>", 'tx') call feedkeys(":set ts\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tabstop thesaurus', @:) call assert_equal('"set tabstop thesaurus thesaurusfunc', @:)
" Expand current value " Expand current value
call feedkeys(":set fileencodings=\<C-A>\<C-B>\"\<CR>", 'tx') call feedkeys(":set fileencodings=\<C-A>\<C-B>\"\<CR>", 'tx')