0
0
mirror of https://github.com/vim/vim.git synced 2025-08-26 20:03:41 -04:00

patch 8.2.3520: cannot define a function for thesaurus completion

Problem:    Cannot define a function for thesaurus completion.
Solution:   Add 'thesaurusfunc'. (Yegappan Lakshmanan, closes #8987,
            closes 8950)
This commit is contained in:
Yegappan Lakshmanan 2021-10-16 15:41:29 +01:00 committed by Bram Moolenaar
parent 2286304cdb
commit 160e994d76
12 changed files with 138 additions and 8 deletions

View File

@ -842,6 +842,12 @@ CTRL-X CTRL-T Works as CTRL-X CTRL-K, but in a special way. It uses
Other uses include translation between two languages,
or grouping API functions by keyword.
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.
CTRL-T or
CTRL-N Search forward for next matching keyword. This
keyword replaces the previous matching keyword.
@ -1052,7 +1058,7 @@ CTRL-X CTRL-Z Stop completion without changing the text.
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:
- First the function is called to find the start of the text to be completed.

View File

@ -8028,6 +8028,18 @@ A jump table for the options with a short description can be found at |Q_op|.
uses another default.
Backticks cannot be used in this option for security reasons.
*'thesaurusfunc'* *tsrfu'*
'thesaurusfunc' 'tsrfu' string (default: empty)
local to buffer
{not available when compiled without the |+eval|
feature}
This option specifies a function to be used for thesaurus completion
with CTRL-X CTRL-T. |i_CTRL-X_CTRL-T|
See |complete-functions| for an explanation of how the function is
invoked and what it should return.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
*'tildeop'* *'top'* *'notildeop'* *'notop'*
'tildeop' 'top' boolean (default off)
global

View File

@ -948,6 +948,7 @@ Short explanation of each option: *option-list*
'textmode' 'tx' obsolete, use 'fileformat'
'textwidth' 'tw' maximum width of text that is being inserted
'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
'timeout' 'to' time out on mappings and key codes
'timeoutlen' 'tm' time out time in milliseconds

View File

@ -2364,6 +2364,7 @@ free_buf_options(
#ifdef FEAT_COMPL_FUNC
clear_string_option(&buf->b_p_cfu);
clear_string_option(&buf->b_p_ofu);
clear_string_option(&buf->b_p_thsfu);
#endif
#ifdef FEAT_QUICKFIX
clear_string_option(&buf->b_p_gp);

View File

@ -299,7 +299,11 @@ has_compl_option(int dict_opt)
&& !curwin->w_p_spell
#endif
)
: (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
: (*curbuf->b_p_tsr == NUL && *p_tsr == NUL
#ifdef FEAT_COMPL_FUNC
&& *curbuf->b_p_thsfu == NUL
#endif
))
{
ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
@ -2229,6 +2233,25 @@ ins_compl_next_buf(buf_T *buf, int flag)
}
#ifdef FEAT_COMPL_FUNC
/*
* 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_thsfu;
default:
return (char_u *)"";
}
}
/*
* Execute user defined complete function 'completefunc' or 'omnifunc', and
* get matches in "matches".
@ -2246,7 +2269,7 @@ expand_by_function(
typval_T rettv;
int save_State = State;
funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
funcname = get_complete_funcname(type);
if (*funcname == NUL)
return;
@ -2720,6 +2743,21 @@ f_complete_info(typval_T *argvars, typval_T *rettv)
}
#endif
/*
* Returns TRUE when using a user-defined function for thesaurus completion.
*/
static int
thesaurus_func_complete(int type UNUSED)
{
#ifdef FEAT_COMPL_FUNC
return (type == CTRL_X_THESAURUS
&& curbuf->b_p_thsfu != NULL
&& *curbuf->b_p_thsfu != NUL);
#else
return FALSE;
#endif
}
/*
* Get the next expansion(s), using "compl_pattern".
* The search starts at position "ini" in curbuf and in the direction
@ -2906,6 +2944,11 @@ ins_compl_get_exp(pos_T *ini)
case CTRL_X_DICTIONARY:
case CTRL_X_THESAURUS:
#ifdef FEAT_COMPL_FUNC
if (thesaurus_func_complete(type))
expand_by_function(type, compl_pattern);
else
#endif
ins_compl_dictionaries(
dict != NULL ? dict
: (type == CTRL_X_THESAURUS
@ -3760,7 +3803,9 @@ ins_complete(int c, int enable_pum)
}
// 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)
|| ctrl_x_mode == CTRL_X_PATH_DEFINES)
@ -3910,7 +3955,8 @@ ins_complete(int c, int enable_pum)
compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
compl_length = curs_col - compl_col;
}
else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
|| thesaurus_func_complete(ctrl_x_mode))
{
#ifdef FEAT_COMPL_FUNC
// Call user defined function 'completefunc' with "a:findstart"
@ -3923,8 +3969,7 @@ ins_complete(int c, int enable_pum)
// Call 'completefunc' or 'omnifunc' and get pattern length as a
// string
funcname = ctrl_x_mode == CTRL_X_FUNCTION
? curbuf->b_p_cfu : curbuf->b_p_ofu;
funcname = get_complete_funcname(ctrl_x_mode);
if (*funcname == NUL)
{
semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION

View File

@ -5433,6 +5433,7 @@ get_varp(struct vimoption *p)
#ifdef FEAT_COMPL_FUNC
case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
case PV_THSFU: return (char_u *)&(curbuf->b_p_thsfu);
#endif
#ifdef FEAT_EVAL
case PV_TFU: return (char_u *)&(curbuf->b_p_tfu);
@ -5935,6 +5936,8 @@ buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_CFU);
buf->b_p_ofu = vim_strsave(p_ofu);
COPY_OPT_SCTX(buf, BV_OFU);
buf->b_p_thsfu = vim_strsave(p_thsfu);
COPY_OPT_SCTX(buf, BV_THSFU);
#endif
#ifdef FEAT_EVAL
buf->b_p_tfu = vim_strsave(p_tfu);

View File

@ -404,6 +404,7 @@ EXTERN char_u *p_cinw; // 'cinwords'
#ifdef FEAT_COMPL_FUNC
EXTERN char_u *p_cfu; // 'completefunc'
EXTERN char_u *p_ofu; // 'omnifunc'
EXTERN char_u *p_thsfu; // 'thesaurusfunc'
#endif
EXTERN int p_ci; // 'copyindent'
#if defined(FEAT_GUI) && defined(MACOS_X)
@ -1217,6 +1218,9 @@ enum
#endif
, BV_TAGS
, BV_TC
#ifdef FEAT_COMPL_FUNC
, BV_THSFU
#endif
, BV_TS
, BV_TW
, BV_TX

View File

@ -140,6 +140,9 @@
#ifdef FEAT_EVAL
# define PV_TFU OPT_BUF(BV_TFU)
#endif
#ifdef FEAT_COMPL_FUNC
# define PV_THSFU OPT_BUF(BV_THSFU)
#endif
#define PV_TAGS OPT_BOTH(OPT_BUF(BV_TAGS))
#define PV_TC OPT_BOTH(OPT_BUF(BV_TC))
#define PV_TS OPT_BUF(BV_TS)
@ -2616,6 +2619,15 @@ static struct vimoption options[] =
{"thesaurus", "tsr", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
(char_u *)&p_tsr, PV_TSR,
{(char_u *)"", (char_u *)0L} SCTX_INIT},
{"thesaurusfunc", "tsrfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE,
#ifdef FEAT_COMPL_FUNC
(char_u *)&p_thsfu, PV_THSFU,
{(char_u *)"", (char_u *)0L}
#else
(char_u *)NULL, PV_NONE,
{(char_u *)0L, (char_u *)0L}
#endif
SCTX_INIT},
{"tildeop", "top", P_BOOL|P_VI_DEF|P_VIM,
(char_u *)&p_to, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCTX_INIT},

View File

@ -271,6 +271,7 @@ check_buf_options(buf_T *buf)
#ifdef FEAT_COMPL_FUNC
check_string_option(&buf->b_p_cfu);
check_string_option(&buf->b_p_ofu);
check_string_option(&buf->b_p_thsfu);
#endif
#ifdef FEAT_EVAL
check_string_option(&buf->b_p_tfu);

View File

@ -2864,6 +2864,7 @@ struct file_buffer
#ifdef FEAT_COMPL_FUNC
char_u *b_p_cfu; // 'completefunc'
char_u *b_p_ofu; // 'omnifunc'
char_u *b_p_thsfu; // 'thesaurusfunc'
#endif
#ifdef FEAT_EVAL
char_u *b_p_tfu; // 'tagfunc'

View File

@ -890,6 +890,48 @@ func Test_edit_CTRL_T()
bw!
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=
set 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, '$'))
set thesaurusfunc=NonExistingFunc
call assert_fails("normal $a\<C-X>\<C-T>", 'E117:')
set thesaurusfunc&
%bw!
endfunc
func Test_edit_CTRL_U()
" Test 'completefunc'
new

View File

@ -757,6 +757,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3520,
/**/
3519,
/**/