mirror of
https://github.com/vim/vim
synced 2025-07-16 01:01:58 +00:00
patch 9.1.1341: cannot define completion triggers
Problem: Cannot define completion triggers and act upon it Solution: add the new option 'isexpand' and add the complete_match() function to return the completion matches according to the 'isexpand' setting (glepnir) Currently, completion trigger position is determined solely by the 'iskeyword' pattern (\k\+$), which causes issues when users need different completion behaviors - such as triggering after '/' for comments or '.' for methods. Modifying 'iskeyword' to include these characters has undesirable side effects on other Vim functionality that relies on keyword definitions. Introduce a new buffer-local option 'isexpand' that allows specifying different completion triggers and add the complete_match() function that finds the appropriate start column for completion based on these triggers, scanning backwards from cursor position. This separation of concerns allows customized completion behavior without affecting iskeyword-dependent features. The option's buffer-local nature enables per-filetype completion triggers. closes: #16716 Signed-off-by: glepnir <glephunter@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
32f49738d1
commit
bcd5995b40
@ -1,4 +1,4 @@
|
||||
*builtin.txt* For Vim version 9.1. Last change: 2025 Apr 23
|
||||
*builtin.txt* For Vim version 9.1. Last change: 2025 Apr 24
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -136,6 +136,7 @@ complete({startcol}, {matches}) none set Insert mode completion
|
||||
complete_add({expr}) Number add completion match
|
||||
complete_check() Number check for key typed during completion
|
||||
complete_info([{what}]) Dict get current completion information
|
||||
complete_match([{lnum}, {col}]) List get completion column and trigger text
|
||||
confirm({msg} [, {choices} [, {default} [, {type}]]])
|
||||
Number number of choice picked by user
|
||||
copy({expr}) any make a shallow copy of {expr}
|
||||
@ -2032,6 +2033,50 @@ complete_info([{what}]) *complete_info()*
|
||||
<
|
||||
Return type: dict<any>
|
||||
|
||||
complete_match([{lnum}, {col}]) *complete_match()*
|
||||
Returns a List of matches found according to the 'isexpand'
|
||||
option. Each match is represented as a List containing
|
||||
[startcol, trigger_text] where:
|
||||
- startcol: column position where completion should start,
|
||||
or -1 if no trigger position is found. For multi-character
|
||||
triggers, returns the column of the first character.
|
||||
- trigger_text: the matching trigger string from 'isexpand',
|
||||
or empty string if no match was found or when using the
|
||||
default 'iskeyword' pattern.
|
||||
|
||||
When 'isexpand' is empty, uses the 'iskeyword' pattern
|
||||
"\k\+$" to find the start of the current keyword.
|
||||
|
||||
When no arguments are provided, uses the current cursor
|
||||
position.
|
||||
|
||||
Examples: >
|
||||
set isexpand=.,->,/,/*,abc
|
||||
func CustomComplete()
|
||||
let res = complete_match()
|
||||
if res->len() == 0 | return | endif
|
||||
let [col, trigger] = res[0]
|
||||
let items = []
|
||||
if trigger == '/*'
|
||||
let items = ['/** */']
|
||||
elseif trigger == '/'
|
||||
let items = ['/*! */', '// TODO:', '// fixme:']
|
||||
elseif trigger == '.'
|
||||
let items = ['length()']
|
||||
elseif trigger =~ '^\->'
|
||||
let items = ['map()', 'reduce()']
|
||||
elseif trigger =~ '^\abc'
|
||||
let items = ['def', 'ghk']
|
||||
endif
|
||||
if items->len() > 0
|
||||
let startcol = trigger =~ '^/' ? col : col + len(trigger)
|
||||
call complete(startcol, items)
|
||||
endif
|
||||
endfunc
|
||||
inoremap <Tab> <Cmd>call CustomComplete()<CR>
|
||||
<
|
||||
Return type: list<list<any>>
|
||||
|
||||
*confirm()*
|
||||
confirm({msg} [, {choices} [, {default} [, {type}]]])
|
||||
confirm() offers the user a dialog, from which a choice can be
|
||||
|
@ -1,4 +1,4 @@
|
||||
*options.txt* For Vim version 9.1. Last change: 2025 Apr 19
|
||||
*options.txt* For Vim version 9.1. Last change: 2025 Apr 24
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -4983,6 +4983,19 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
and there is a letter before it, the completed part is made uppercase.
|
||||
With 'noinfercase' the match is used as-is.
|
||||
|
||||
*'isexpand'* *'ise'*
|
||||
'isexpand' 'ise' string (default: "")
|
||||
local to buffer
|
||||
Defines characters and patterns for completion in insert mode. Used by
|
||||
the |complete_match()| function to determine the starting position for
|
||||
completion. This is a comma-separated list of triggers. Each trigger
|
||||
can be:
|
||||
- A single character like "." or "/"
|
||||
- A sequence of characters like "->", "/*", or "/**"
|
||||
|
||||
Note: Use "\\," to add a literal comma as trigger character, see
|
||||
|option-backslash|.
|
||||
|
||||
*'insertmode'* *'im'* *'noinsertmode'* *'noim'*
|
||||
'insertmode' 'im' boolean (default off)
|
||||
global
|
||||
|
@ -436,6 +436,8 @@ $quote eval.txt /*$quote*
|
||||
'infercase' options.txt /*'infercase'*
|
||||
'insertmode' options.txt /*'insertmode'*
|
||||
'is' options.txt /*'is'*
|
||||
'ise' options.txt /*'ise'*
|
||||
'isexpand' options.txt /*'isexpand'*
|
||||
'isf' options.txt /*'isf'*
|
||||
'isfname' options.txt /*'isfname'*
|
||||
'isi' options.txt /*'isi'*
|
||||
@ -6663,6 +6665,7 @@ complete_add() builtin.txt /*complete_add()*
|
||||
complete_check() builtin.txt /*complete_check()*
|
||||
complete_info() builtin.txt /*complete_info()*
|
||||
complete_info_mode builtin.txt /*complete_info_mode*
|
||||
complete_match() builtin.txt /*complete_match()*
|
||||
completed_item-variable eval.txt /*completed_item-variable*
|
||||
completion-functions usr_41.txt /*completion-functions*
|
||||
complex-change change.txt /*complex-change*
|
||||
|
@ -1,4 +1,4 @@
|
||||
*todo.txt* For Vim version 9.1. Last change: 2025 Mar 27
|
||||
*todo.txt* For Vim version 9.1. Last change: 2025 Apr 24
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -4749,20 +4749,10 @@ Insert mode completion/expansion:
|
||||
7 When expanding file names with an environment variable, add the match with
|
||||
the unexpanded var. So $HOME/tm expands to "/home/guy/tmp" and
|
||||
"$HOME/tmp"
|
||||
8 When there is no word before the cursor but something like "sys." complete
|
||||
with "sys.". Works well for C and similar languages.
|
||||
9 ^X^L completion doesn't repeat correctly. It uses the first match with
|
||||
the last added line, instead of continuing where the last match ended.
|
||||
(Webb)
|
||||
8 Add option to set different behavior for Insert mode completion:
|
||||
- ignore/match case
|
||||
- different characters than 'iskeyword'
|
||||
8 Add option 'isexpand', containing characters when doing expansion (so that
|
||||
"." and "\" can be included, without changing 'iskeyword'). (Goldfarb)
|
||||
Also: 'istagword': characters used for CTRL-].
|
||||
When 'isexpand' or 'istagword' are empty, use 'iskeyword'.
|
||||
Alternative: Use a pattern so that start and end of a keyword can be
|
||||
defined, only allow dash in the middle, etc.
|
||||
8 Add option 'istagword': characters used for CTRL-]. like 'isexpand'
|
||||
8 Add a command to undo the completion, go back to the original text.
|
||||
7 Completion of an abbreviation: Can leave letters out, like what Instant
|
||||
text does: www.textware.com
|
||||
|
@ -1,4 +1,4 @@
|
||||
*usr_41.txt* For Vim version 9.1. Last change: 2025 Apr 21
|
||||
*usr_41.txt* For Vim version 9.1. Last change: 2025 Apr 24
|
||||
|
||||
VIM USER MANUAL - by Bram Moolenaar
|
||||
|
||||
@ -1124,6 +1124,8 @@ Insert mode completion: *completion-functions*
|
||||
complete_add() add to found matches
|
||||
complete_check() check if completion should be aborted
|
||||
complete_info() get current completion information
|
||||
complete_match() get insert completion start match col and
|
||||
trigger text
|
||||
pumvisible() check if the popup menu is displayed
|
||||
pum_getpos() position and size of popup menu if visible
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
*version9.txt* For Vim version 9.1. Last change: 2025 Apr 23
|
||||
*version9.txt* For Vim version 9.1. Last change: 2025 Apr 24
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -41688,6 +41688,7 @@ Functions: ~
|
||||
|blob2str()| convert a blob into a List of strings
|
||||
|bindtextdomain()| set message lookup translation base path
|
||||
|cmdcomplete_info()| get current cmdline completion info
|
||||
|complete_match()| get completion and trigger info
|
||||
|diff()| diff two Lists of strings
|
||||
|filecopy()| copy a file {from} to {to}
|
||||
|foreach()| apply function to List items
|
||||
@ -41750,6 +41751,7 @@ Options: ~
|
||||
'eventignorewin' autocommand events that are ignored in a window
|
||||
'findfunc' Vim function to obtain the results for a |:find|
|
||||
command
|
||||
'isexpand' defines triggers for completion
|
||||
'lhistory' Size of the location list stack |quickfix-stack|.
|
||||
'messagesopt' configure |:messages| and |hit-enter| prompt
|
||||
'pummaxwidth' maximum width for the completion popup menu
|
||||
|
@ -1,7 +1,7 @@
|
||||
" These commands create the option window.
|
||||
"
|
||||
" Maintainer: The Vim Project <https://github.com/vim/vim>
|
||||
" Last Change: 2025 Apr 07
|
||||
" Last Change: 2025 Apr 24
|
||||
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
|
||||
" If there already is an option window, jump to that one.
|
||||
@ -1254,6 +1254,8 @@ call <SID>AddOption("isfname", gettext("specifies the characters in a file name"
|
||||
call <SID>OptionG("isf", &isf)
|
||||
call <SID>AddOption("isident", gettext("specifies the characters in an identifier"))
|
||||
call <SID>OptionG("isi", &isi)
|
||||
call <SID>AddOption("isexpand", gettext("defines trigger strings for complete_match()"))
|
||||
call append("$", "\t" .. s:local_to_buffer)
|
||||
call <SID>AddOption("iskeyword", gettext("specifies the characters in a keyword"))
|
||||
call append("$", "\t" .. s:local_to_buffer)
|
||||
call <SID>OptionL("isk")
|
||||
|
@ -2494,6 +2494,7 @@ free_buf_options(
|
||||
clear_string_option(&buf->b_p_cinw);
|
||||
clear_string_option(&buf->b_p_cot);
|
||||
clear_string_option(&buf->b_p_cpt);
|
||||
clear_string_option(&buf->b_p_ise);
|
||||
#ifdef FEAT_COMPL_FUNC
|
||||
clear_string_option(&buf->b_p_cfu);
|
||||
free_callback(&buf->b_cfu_cb);
|
||||
|
@ -2104,6 +2104,8 @@ static funcentry_T global_functions[] =
|
||||
ret_number_bool, f_complete_check},
|
||||
{"complete_info", 0, 1, FEARG_1, arg1_list_string,
|
||||
ret_dict_any, f_complete_info},
|
||||
{"complete_match", 0, 2, 0, NULL,
|
||||
ret_list_any, f_complete_match},
|
||||
{"confirm", 1, 4, FEARG_1, arg4_string_string_number_string,
|
||||
ret_number, f_confirm},
|
||||
{"copy", 1, 1, FEARG_1, NULL,
|
||||
|
141
src/insexpand.c
141
src/insexpand.c
@ -3550,6 +3550,147 @@ f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
|
||||
RedrawingDisabled = save_RedrawingDisabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add match item to the return list.
|
||||
* Returns FAIL if out of memory, OK otherwise.
|
||||
*/
|
||||
static int
|
||||
add_match_to_list(
|
||||
typval_T *rettv,
|
||||
char_u *str,
|
||||
int len,
|
||||
int pos)
|
||||
{
|
||||
list_T *match;
|
||||
int ret;
|
||||
|
||||
match = list_alloc();
|
||||
if (match == NULL)
|
||||
return FAIL;
|
||||
|
||||
if ((ret = list_append_number(match, pos + 1)) == FAIL
|
||||
|| (ret = list_append_string(match, str, len)) == FAIL
|
||||
|| (ret = list_append_list(rettv->vval.v_list, match)) == FAIL)
|
||||
{
|
||||
vim_free(match);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* "complete_match()" function
|
||||
*/
|
||||
void
|
||||
f_complete_match(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
linenr_T lnum;
|
||||
colnr_T col;
|
||||
char_u *line = NULL;
|
||||
char_u *ise = NULL;
|
||||
regmatch_T regmatch;
|
||||
char_u *before_cursor = NULL;
|
||||
char_u *cur_end = NULL;
|
||||
char_u *trig = NULL;
|
||||
int bytepos = 0;
|
||||
char_u part[MAXPATHL];
|
||||
int ret;
|
||||
|
||||
if (rettv_list_alloc(rettv) == FAIL)
|
||||
return;
|
||||
|
||||
ise = curbuf->b_p_ise[0] != NUL ? curbuf->b_p_ise : p_ise;
|
||||
|
||||
if (argvars[0].v_type == VAR_UNKNOWN)
|
||||
{
|
||||
lnum = curwin->w_cursor.lnum;
|
||||
col = curwin->w_cursor.col;
|
||||
}
|
||||
else if (argvars[1].v_type == VAR_UNKNOWN)
|
||||
{
|
||||
emsg(_(e_invalid_argument));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
lnum = (linenr_T)tv_get_number(&argvars[0]);
|
||||
col = (colnr_T)tv_get_number(&argvars[1]);
|
||||
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
|
||||
{
|
||||
semsg(_(e_invalid_line_number_nr), lnum);
|
||||
return;
|
||||
}
|
||||
if (col < 1 || col > ml_get_buf_len(curbuf, lnum))
|
||||
{
|
||||
semsg(_(e_invalid_column_number_nr), col + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
line = ml_get_buf(curbuf, lnum, FALSE);
|
||||
if (line == NULL)
|
||||
return;
|
||||
|
||||
before_cursor = vim_strnsave(line, col);
|
||||
if (before_cursor == NULL)
|
||||
return;
|
||||
|
||||
if (ise == NULL || *ise == NUL)
|
||||
{
|
||||
regmatch.regprog = vim_regcomp((char_u *)"\\k\\+$", RE_MAGIC);
|
||||
if (regmatch.regprog != NULL)
|
||||
{
|
||||
if (vim_regexec_nl(®match, before_cursor, (colnr_T)0))
|
||||
{
|
||||
bytepos = (int)(regmatch.startp[0] - before_cursor);
|
||||
trig = vim_strnsave(regmatch.startp[0],
|
||||
regmatch.endp[0] - regmatch.startp[0]);
|
||||
if (trig == NULL)
|
||||
{
|
||||
vim_free(before_cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = add_match_to_list(rettv, trig, -1, bytepos);
|
||||
vim_free(trig);
|
||||
if (ret == FAIL)
|
||||
{
|
||||
vim_free(trig);
|
||||
vim_regfree(regmatch.regprog);
|
||||
return;
|
||||
}
|
||||
}
|
||||
vim_regfree(regmatch.regprog);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char_u *p = ise;
|
||||
cur_end = before_cursor + (int)STRLEN(before_cursor);
|
||||
|
||||
while (*p != NUL)
|
||||
{
|
||||
int len = copy_option_part(&p, part, MAXPATHL, ",");
|
||||
|
||||
if (len > 0 && len <= col)
|
||||
{
|
||||
if (STRNCMP(cur_end - len, part, len) == 0)
|
||||
{
|
||||
bytepos = col - len;
|
||||
if (add_match_to_list(rettv, part, len, bytepos) == FAIL)
|
||||
{
|
||||
vim_free(before_cursor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vim_free(before_cursor);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return Insert completion mode name string
|
||||
*/
|
||||
|
@ -6400,6 +6400,9 @@ unset_global_local_option(char_u *name, void *from)
|
||||
clear_string_option(&buf->b_p_cot);
|
||||
buf->b_cot_flags = 0;
|
||||
break;
|
||||
case PV_ISE:
|
||||
clear_string_option(&buf->b_p_ise);
|
||||
break;
|
||||
case PV_DICT:
|
||||
clear_string_option(&buf->b_p_dict);
|
||||
break;
|
||||
@ -6518,6 +6521,7 @@ get_varp_scope(struct vimoption *p, int scope)
|
||||
case PV_INC: return (char_u *)&(curbuf->b_p_inc);
|
||||
#endif
|
||||
case PV_COT: return (char_u *)&(curbuf->b_p_cot);
|
||||
case PV_ISE: return (char_u *)&(curbuf->b_p_ise);
|
||||
case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
|
||||
case PV_TSR: return (char_u *)&(curbuf->b_p_tsr);
|
||||
#ifdef FEAT_COMPL_FUNC
|
||||
@ -6600,6 +6604,8 @@ get_varp(struct vimoption *p)
|
||||
#endif
|
||||
case PV_COT: return *curbuf->b_p_cot != NUL
|
||||
? (char_u *)&(curbuf->b_p_cot) : p->var;
|
||||
case PV_ISE: return *curbuf->b_p_ise != NUL
|
||||
? (char_u *)&(curbuf->b_p_ise) : p->var;
|
||||
case PV_DICT: return *curbuf->b_p_dict != NUL
|
||||
? (char_u *)&(curbuf->b_p_dict) : p->var;
|
||||
case PV_TSR: return *curbuf->b_p_tsr != NUL
|
||||
@ -7431,6 +7437,7 @@ buf_copy_options(buf_T *buf, int flags)
|
||||
buf->b_cot_flags = 0;
|
||||
buf->b_p_dict = empty_option;
|
||||
buf->b_p_tsr = empty_option;
|
||||
buf->b_p_ise = empty_option;
|
||||
#ifdef FEAT_COMPL_FUNC
|
||||
buf->b_p_tsrfu = empty_option;
|
||||
#endif
|
||||
|
@ -731,6 +731,7 @@ EXTERN char_u *p_inde; // 'indentexpr'
|
||||
EXTERN char_u *p_indk; // 'indentkeys'
|
||||
#endif
|
||||
EXTERN int p_im; // 'insertmode'
|
||||
EXTERN char_u *p_ise; // 'isexpand'
|
||||
EXTERN char_u *p_isf; // 'isfname'
|
||||
EXTERN char_u *p_isi; // 'isident'
|
||||
EXTERN char_u *p_isk; // 'iskeyword'
|
||||
@ -1205,6 +1206,7 @@ enum
|
||||
, BV_INEX
|
||||
#endif
|
||||
, BV_INF
|
||||
, BV_ISE
|
||||
, BV_ISK
|
||||
#ifdef FEAT_CRYPT
|
||||
, BV_KEY
|
||||
|
@ -90,6 +90,7 @@
|
||||
# define PV_INEX OPT_BUF(BV_INEX)
|
||||
#endif
|
||||
#define PV_INF OPT_BUF(BV_INF)
|
||||
#define PV_ISE OPT_BOTH(OPT_BUF(BV_ISE))
|
||||
#define PV_ISK OPT_BUF(BV_ISK)
|
||||
#ifdef FEAT_CRYPT
|
||||
# define PV_KEY OPT_BUF(BV_KEY)
|
||||
@ -1458,6 +1459,10 @@ static struct vimoption options[] =
|
||||
{"insertmode", "im", P_BOOL|P_VI_DEF|P_VIM,
|
||||
(char_u *)&p_im, PV_NONE, did_set_insertmode, NULL,
|
||||
{(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
|
||||
{"isexpand", "ise", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
|
||||
(char_u *)&p_ise, PV_ISE, did_set_isexpand, NULL,
|
||||
{(char_u *)"", (char_u *)0L}
|
||||
SCTX_INIT},
|
||||
{"isfname", "isf", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
|
||||
(char_u *)&p_isf, PV_NONE, did_set_isopt, NULL,
|
||||
{
|
||||
|
@ -310,6 +310,7 @@ check_buf_options(buf_T *buf)
|
||||
check_string_option(&buf->b_p_cinw);
|
||||
check_string_option(&buf->b_p_cot);
|
||||
check_string_option(&buf->b_p_cpt);
|
||||
check_string_option(&buf->b_p_ise);
|
||||
#ifdef FEAT_COMPL_FUNC
|
||||
check_string_option(&buf->b_p_cfu);
|
||||
check_string_option(&buf->b_p_ofu);
|
||||
@ -2864,6 +2865,48 @@ did_set_imactivatekey(optset_T *args UNUSED)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The 'isexpand' option is changed.
|
||||
*/
|
||||
char *
|
||||
did_set_isexpand(optset_T *args)
|
||||
{
|
||||
char_u *ise = p_ise;
|
||||
char_u *p;
|
||||
int last_was_comma = FALSE;
|
||||
|
||||
if (args->os_flags & OPT_LOCAL)
|
||||
ise = curbuf->b_p_ise;
|
||||
|
||||
for (p = ise; *p != NUL;)
|
||||
{
|
||||
if (*p == '\\' && p[1] == ',')
|
||||
{
|
||||
p += 2;
|
||||
last_was_comma = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*p == ',')
|
||||
{
|
||||
if (last_was_comma)
|
||||
return e_invalid_argument;
|
||||
last_was_comma = TRUE;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
last_was_comma = FALSE;
|
||||
MB_PTR_ADV(p);
|
||||
}
|
||||
|
||||
if (last_was_comma)
|
||||
return e_invalid_argument;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The 'iskeyword' option is changed.
|
||||
*/
|
||||
|
@ -67,4 +67,5 @@ void ins_compl_check_keys(int frequency, int in_compl_func);
|
||||
int ins_complete(int c, int enable_pum);
|
||||
void free_insexpand_stuff(void);
|
||||
int ins_compl_cancel(void);
|
||||
void f_complete_match(typval_T *argvars, typval_T *rettv);
|
||||
/* vim: set ft=c : */
|
||||
|
@ -101,6 +101,7 @@ char *did_set_highlight(optset_T *args);
|
||||
int expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches);
|
||||
char *did_set_iconstring(optset_T *args);
|
||||
char *did_set_imactivatekey(optset_T *args);
|
||||
char *did_set_isexpand(optset_T *args);
|
||||
char *did_set_iskeyword(optset_T *args);
|
||||
char *did_set_isopt(optset_T *args);
|
||||
char *did_set_jumpoptions(optset_T *args);
|
||||
|
@ -3302,6 +3302,7 @@ struct file_buffer
|
||||
char_u *b_p_fo; // 'formatoptions'
|
||||
char_u *b_p_flp; // 'formatlistpat'
|
||||
int b_p_inf; // 'infercase'
|
||||
char_u *b_p_ise; // 'isexpand' local value
|
||||
char_u *b_p_isk; // 'iskeyword'
|
||||
#ifdef FEAT_FIND_ID
|
||||
char_u *b_p_def; // 'define' local value
|
||||
|
@ -229,6 +229,7 @@ let test_values = {
|
||||
\ 'imactivatekey': [['', 'S-space'], ['xxx']],
|
||||
\ 'isfname': [['', '@', '@,48-52'], ['xxx', '@48']],
|
||||
\ 'isident': [['', '@', '@,48-52'], ['xxx', '@48']],
|
||||
\ 'isexpand': [['', '.,->', '/,/*,\\,'], [',,', '\\,,']],
|
||||
\ 'iskeyword': [['', '@', '@,48-52'], ['xxx', '@48']],
|
||||
\ 'isprint': [['', '@', '@,48-52'], ['xxx', '@48']],
|
||||
\ 'jumpoptions': [['', 'stack'], ['xxx']],
|
||||
|
@ -4328,4 +4328,86 @@ func Test_nearest_cpt_option()
|
||||
delfunc PrintMenuWords
|
||||
endfunc
|
||||
|
||||
func Test_complete_match()
|
||||
set isexpand=.,/,->,abc,/*,_
|
||||
func TestComplete()
|
||||
let res = complete_match()
|
||||
if res->len() == 0
|
||||
return
|
||||
endif
|
||||
let [startcol, expandchar] = res[0]
|
||||
|
||||
if startcol >= 0
|
||||
let line = getline('.')
|
||||
|
||||
let items = []
|
||||
if expandchar == '/*'
|
||||
let items = ['/** */']
|
||||
elseif expandchar =~ '^/'
|
||||
let items = ['/*! */', '// TODO:', '// fixme:']
|
||||
elseif expandchar =~ '^\.' && startcol < 4
|
||||
let items = ['length()', 'push()', 'pop()', 'slice()']
|
||||
elseif expandchar =~ '^\.' && startcol > 4
|
||||
let items = ['map()', 'filter()', 'reduce()']
|
||||
elseif expandchar =~ '^\abc'
|
||||
let items = ['def', 'ghk']
|
||||
elseif expandchar =~ '^\->'
|
||||
let items = ['free()', 'xfree()']
|
||||
else
|
||||
let items = ['test1', 'test2', 'test3']
|
||||
endif
|
||||
|
||||
call complete(expandchar =~ '^/' ? startcol : startcol + strlen(expandchar), items)
|
||||
endif
|
||||
endfunc
|
||||
|
||||
new
|
||||
inoremap <buffer> <F5> <cmd>call TestComplete()<CR>
|
||||
|
||||
call feedkeys("S/*\<F5>\<C-Y>", 'tx')
|
||||
call assert_equal('/** */', getline('.'))
|
||||
|
||||
call feedkeys("S/\<F5>\<C-N>\<C-Y>", 'tx')
|
||||
call assert_equal('// TODO:', getline('.'))
|
||||
|
||||
call feedkeys("Swp.\<F5>\<C-N>\<C-Y>", 'tx')
|
||||
call assert_equal('wp.push()', getline('.'))
|
||||
|
||||
call feedkeys("Swp.property.\<F5>\<C-N>\<C-Y>", 'tx')
|
||||
call assert_equal('wp.property.filter()', getline('.'))
|
||||
|
||||
call feedkeys("Sp->\<F5>\<C-N>\<C-Y>", 'tx')
|
||||
call assert_equal('p->xfree()', getline('.'))
|
||||
|
||||
call feedkeys("Swp->property.\<F5>\<C-Y>", 'tx')
|
||||
call assert_equal('wp->property.map()', getline('.'))
|
||||
|
||||
call feedkeys("Sabc\<F5>\<C-Y>", 'tx')
|
||||
call assert_equal('abcdef', getline('.'))
|
||||
|
||||
call feedkeys("S_\<F5>\<C-Y>", 'tx')
|
||||
call assert_equal('_test1', getline('.'))
|
||||
|
||||
set ise&
|
||||
call feedkeys("Sabc \<ESC>:let g:result=complete_match()\<CR>", 'tx')
|
||||
call assert_equal([[1, 'abc']], g:result)
|
||||
|
||||
call assert_fails('call complete_match(99, 0)', 'E966:')
|
||||
call assert_fails('call complete_match(1, 99)', 'E964:')
|
||||
call assert_fails('call complete_match(1)', 'E474:')
|
||||
|
||||
set ise=你好,好
|
||||
call feedkeys("S你好 \<ESC>:let g:result=complete_match()\<CR>", 'tx')
|
||||
call assert_equal([[1, '你好'], [4, '好']], g:result)
|
||||
|
||||
set ise=\\,,->
|
||||
call feedkeys("Sabc, \<ESC>:let g:result=complete_match()\<CR>", 'tx')
|
||||
call assert_equal([[4, ',']], g:result)
|
||||
|
||||
bw!
|
||||
unlet g:result
|
||||
set isexpand&
|
||||
delfunc TestComplete
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1341,
|
||||
/**/
|
||||
1340,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user