aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/autocmd.txt4
-rw-r--r--runtime/doc/news.txt4
-rw-r--r--runtime/doc/terminal.txt3
-rw-r--r--runtime/doc/vvars.txt2
-rw-r--r--runtime/lua/vim/_defaults.lua4
-rw-r--r--runtime/lua/vim/_meta/vvars.lua2
-rw-r--r--runtime/lua/vim/diagnostic.lua21
-rw-r--r--runtime/lua/vim/loader.lua6
-rw-r--r--src/nvim/insexpand.c17
-rw-r--r--src/nvim/runtime.c84
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/vvars.lua2
-rw-r--r--test/functional/editor/defaults_spec.lua68
-rw-r--r--test/functional/lua/system_spec.lua1
-rw-r--r--test/old/testdir/test_ins_complete.vim85
15 files changed, 246 insertions, 59 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 998ef5e9f3..c094281154 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -463,6 +463,10 @@ CompleteDone After Insert mode completion is done. Either
|v:completed_item| gives the completed item.
Sets these |v:event| keys:
+ complete_word The word that was
+ selected, empty if
+ abandoned complete.
+ complete_type |complete_info_mode|
reason Reason for completion being
done. Can be one of:
- "accept": completion was
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index ad3f2c0a6a..58fe2e02e8 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -58,6 +58,8 @@ DEFAULTS
• |]d-default| and |[d-default| accept a count.
• |[D-default| and |]D-default| jump to the first and last diagnostic in the
current buffer, respectively.
+• 'number', 'relativenumber', and 'signcolumn' are disabled in |terminal|
+ buffers. See |terminal-config| for an example of changing these defaults.
DIAGNOSTICS
@@ -303,6 +305,8 @@ UI
|hl-PmenuSel| and |hl-PmenuMatch| both inherit from |hl-Pmenu|, and
|hl-PmenuMatchSel| inherits highlights from both |hl-PmenuSel| and
|hl-PmenuMatch|.
+• |vim.diagnostic.setqflist()| updates existing diagnostics quickfix list if one
+ exists.
• |ui-messages| content chunks now also contain the highlight group ID.
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index ed9659d6e7..27586c38a7 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -108,6 +108,9 @@ global configuration.
- 'list' is disabled
- 'wrap' is disabled
+- 'number' is disabled
+- 'relativenumber' is disabled
+- 'signcolumn' is set to "no"
You can change the defaults with a TermOpen autocommand: >vim
au TermOpen * setlocal list
diff --git a/runtime/doc/vvars.txt b/runtime/doc/vvars.txt
index 0c349c4e57..32f3b96269 100644
--- a/runtime/doc/vvars.txt
+++ b/runtime/doc/vvars.txt
@@ -189,6 +189,8 @@ v:event
changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone|
+ complete_word The word that was selected, empty if abandoned complete.
+ complete_type See |complete_info_mode|
*v:exception* *exception-variable*
v:exception
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index ef83a3ccc3..f891c3baa4 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -49,10 +49,10 @@ do
vim.keymap.set('x', '*', function()
return _visual_search('/')
- end, { desc = ':help v_star-default', expr = true, silent = true })
+ end, { desc = ':help v_star-default', expr = true, replace_keycodes = false })
vim.keymap.set('x', '#', function()
return _visual_search('?')
- end, { desc = ':help v_#-default', expr = true, silent = true })
+ end, { desc = ':help v_#-default', expr = true, replace_keycodes = false })
end
--- Map Y to y$. This mimics the behavior of D and C. See |Y-default|
diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua
index 8784fdbac9..264907109f 100644
--- a/runtime/lua/vim/_meta/vvars.lua
+++ b/runtime/lua/vim/_meta/vvars.lua
@@ -197,6 +197,8 @@ vim.v.errors = ...
--- changing window (or tab) on `DirChanged`.
--- status Job status or exit code, -1 means "unknown". `TermClose`
--- reason Reason for completion being done. `CompleteDone`
+--- complete_word The word that was selected, empty if abandoned complete.
+--- complete_type See `complete_info_mode`
--- @type any
vim.v.event = ...
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 2de996feeb..dbf4f56032 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -2,6 +2,8 @@ local api, if_nil = vim.api, vim.F.if_nil
local M = {}
+local _qf_id = nil
+
--- [diagnostic-structure]()
---
--- Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based
@@ -848,9 +850,24 @@ local function set_list(loclist, opts)
local diagnostics = get_diagnostics(bufnr, opts --[[@as vim.diagnostic.GetOpts]], false)
local items = M.toqflist(diagnostics)
if loclist then
- vim.fn.setloclist(winnr, {}, ' ', { title = title, items = items })
+ vim.fn.setloclist(winnr, {}, 'u', { title = title, items = items })
else
- vim.fn.setqflist({}, ' ', { title = title, items = items })
+ -- Check if the diagnostics quickfix list no longer exists.
+ if _qf_id and vim.fn.getqflist({ id = _qf_id }).id == 0 then
+ _qf_id = nil
+ end
+
+ -- If we already have a diagnostics quickfix, update it rather than creating a new one.
+ -- This avoids polluting the finite set of quickfix lists, and preserves the currently selected
+ -- entry.
+ vim.fn.setqflist({}, _qf_id and 'u' or ' ', {
+ title = title,
+ items = items,
+ id = _qf_id,
+ })
+
+ -- Get the id of the newly created quickfix list.
+ _qf_id = vim.fn.getqflist({ id = 0 }).id
end
if open then
api.nvim_command(loclist and 'lwindow' or 'botright cwindow')
diff --git a/runtime/lua/vim/loader.lua b/runtime/lua/vim/loader.lua
index 71d0188128..c7158673fe 100644
--- a/runtime/lua/vim/loader.lua
+++ b/runtime/lua/vim/loader.lua
@@ -446,6 +446,12 @@ function M.enable(enable)
end
end
+--- @deprecated
+function M.disable()
+ vim.deprecate('vim.loader.disable', 'vim.loader.enable(false)', '0.12')
+ vim.loader.enable(false)
+end
+
--- Tracks the time spent in a function
--- @generic F: function
--- @param f F
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index a1cebb407e..93d081153c 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -561,11 +561,19 @@ static bool is_first_match(const compl_T *const match)
return match == compl_first_match;
}
-static void do_autocmd_completedone(int c)
+static void do_autocmd_completedone(int c, int mode, char *word)
{
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
+ mode = mode & ~CTRL_X_WANT_IDENT;
+ char *mode_str = NULL;
+ if (ctrl_x_mode_names[mode]) {
+ mode_str = ctrl_x_mode_names[mode];
+ }
+ tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : "");
+ tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : "");
+
tv_dict_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel"));
tv_dict_set_keys_readonly(v_event);
@@ -2115,12 +2123,14 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
}
+ char *word = NULL;
// If the popup menu is displayed pressing CTRL-Y means accepting
// the selection without inserting anything. When
// compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible()) {
+ word = xstrdup(compl_shown_match->cp_str);
retval = true;
}
@@ -2178,7 +2188,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, prev_mode, word);
+ xfree(word);
return retval;
}
@@ -2267,7 +2278,7 @@ bool ins_compl_prep(int c)
} else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
// Trigger the CompleteDone event to give scripts a chance to act
// upon the (possibly failed) completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, ctrl_x_mode, NULL);
}
may_trigger_modechanged();
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 3f00b74e61..ff7471025f 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -159,10 +159,7 @@ char *estack_sfile(estack_arg_T which)
{
const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) {
- if (entry->es_name == NULL) {
- return NULL;
- }
- return xstrdup(entry->es_name);
+ return entry->es_name != NULL ? xstrdup(entry->es_name) : NULL;
}
// If evaluated in a function or autocommand, return the path of the script
@@ -499,7 +496,6 @@ static void runtime_search_path_unref(RuntimeSearchPath path, const int *ref)
/// return FAIL when no file could be sourced, OK otherwise.
static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *cookie)
{
- char *tail;
bool did_one = false;
char buf[MAXPATHL];
@@ -533,7 +529,7 @@ static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback,
} else if (buflen + strlen(name) + 2 < MAXPATHL) {
STRCPY(buf, item.path);
add_pathsep(buf);
- tail = buf + strlen(buf);
+ char *tail = buf + strlen(buf);
// Loop over all patterns in "name"
char *np = name;
@@ -935,7 +931,6 @@ static int gen_expand_wildcards_and_cb(int num_pat, char **pats, int flags, bool
/// @param is_pack whether the added dir is a "pack/*/start/*/" style package
static int add_pack_dir_to_rtp(char *fname, bool is_pack)
{
- char *p;
char *afterdir = NULL;
int retval = FAIL;
@@ -943,7 +938,7 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
char *p2 = p1;
char *p3 = p1;
char *p4 = p1;
- for (p = p1; *p; MB_PTR_ADV(p)) {
+ for (char *p = p1; *p; MB_PTR_ADV(p)) {
if (vim_ispathsep_nocolon(*p)) {
p4 = p3;
p3 = p2;
@@ -970,21 +965,21 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
// Also stop at the first "after" directory
size_t fname_len = strlen(ffname);
- char *buf = try_malloc(MAXPATHL);
- if (buf == NULL) {
- goto theend;
- }
+ char buf[MAXPATHL];
const char *insp = NULL;
const char *after_insp = NULL;
- for (const char *entry = p_rtp; *entry != NUL;) {
+ const char *entry = p_rtp;
+ while (*entry != NUL) {
const char *cur_entry = entry;
-
copy_option_part((char **)&entry, buf, MAXPATHL, ",");
- if ((p = strstr(buf, "after")) != NULL
- && p > buf
- && vim_ispathsep(p[-1])
- && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',')) {
+ char *p = strstr(buf, "after");
+ bool is_after = p != NULL
+ && p > buf
+ && vim_ispathsep(p[-1])
+ && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',');
+
+ if (is_after) {
if (insp == NULL) {
// Did not find "ffname" before the first "after" directory,
// insert it before this entry.
@@ -1000,12 +995,11 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
if (rtp_ffname == NULL) {
goto theend;
}
- bool match = path_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
- xfree(rtp_ffname);
- if (match) {
+ if (path_fnamencmp(rtp_ffname, ffname, fname_len) == 0) {
// Insert "ffname" after this entry (and comma).
insp = entry;
}
+ xfree(rtp_ffname);
}
}
@@ -1075,7 +1069,6 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
retval = OK;
theend:
- xfree(buf);
xfree(ffname);
xfree(afterdir);
return retval;
@@ -1123,7 +1116,7 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
bool did_one = false;
if (cookie != &APP_LOAD) {
- char *buf = xmalloc(MAXPATHL);
+ char buf[MAXPATHL];
for (int i = 0; i < num_fnames; i++) {
bool found = false;
@@ -1138,7 +1131,6 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
if (!found) {
// directory is not yet in 'runtimepath', add it
if (add_pack_dir_to_rtp(fnames[i], false) == FAIL) {
- xfree(buf);
return;
}
}
@@ -1147,7 +1139,6 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
break;
}
}
- xfree(buf);
}
if (!all && did_one) {
@@ -1276,25 +1267,23 @@ void ex_packadd(exarg_T *eap)
static const char plugpat[] = "pack/*/%s/%s"; // NOLINT
int res = OK;
- // Round 1: use "start", round 2: use "opt".
- for (int round = 1; round <= 2; round++) {
- // Only look under "start" when loading packages wasn't done yet.
- if (round == 1 && did_source_packages) {
- continue;
- }
+ const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
+ char *pat = xmallocz(len);
+ void *cookie = eap->forceit ? &APP_ADD_DIR : &APP_BOTH;
- const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
- char *pat = xmallocz(len);
- vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
- // The first round don't give a "not found" error, in the second round
- // only when nothing was found in the first round.
- res =
- do_in_path(p_pp, "", pat,
- DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
- round == 1 ? add_start_pack_plugins : add_opt_pack_plugins,
- eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
- xfree(pat);
+ // Only look under "start" when loading packages wasn't done yet.
+ if (!did_source_packages) {
+ vim_snprintf(pat, len, plugpat, "start", eap->arg);
+ res = do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR,
+ add_start_pack_plugins, cookie);
}
+
+ // Give a "not found" error if nothing was found in 'start' or 'opt'.
+ vim_snprintf(pat, len, plugpat, "opt", eap->arg);
+ do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR + (res == FAIL ? DIP_ERR : 0),
+ add_opt_pack_plugins, cookie);
+
+ xfree(pat);
}
static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap,
@@ -2726,22 +2715,15 @@ retry:
/// Without the multi-byte feature it's simply ignored.
void ex_scriptencoding(exarg_T *eap)
{
- source_cookie_T *sp;
- char *name;
-
if (!getline_equal(eap->ea_getline, eap->cookie, getsourceline)) {
emsg(_("E167: :scriptencoding used outside of a sourced file"));
return;
}
- if (*eap->arg != NUL) {
- name = enc_canonize(eap->arg);
- } else {
- name = eap->arg;
- }
+ char *name = (*eap->arg != NUL) ? enc_canonize(eap->arg) : eap->arg;
// Setup for conversion from the specified encoding to 'encoding'.
- sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
+ source_cookie_T *sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
convert_setup(&sp->conv, name, p_enc);
if (name != eap->arg) {
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 00e977710f..7437a7a32f 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -3141,7 +3141,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
c = *ws;
}
if (strstr(s, "^^") != NULL) {
- if (c != NUL) {
+ if (c != NUL && reslen < MAXWLEN) {
wres[reslen++] = c;
}
memmove(word, word + i + 1, sizeof(int) * (size_t)(wordlen - (i + 1) + 1));
diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua
index 5fc014a50c..f1b8c22bdd 100644
--- a/src/nvim/vvars.lua
+++ b/src/nvim/vvars.lua
@@ -208,6 +208,8 @@ M.vars = {
changing window (or tab) on |DirChanged|.
status Job status or exit code, -1 means "unknown". |TermClose|
reason Reason for completion being done. |CompleteDone|
+ complete_word The word that was selected, empty if abandoned complete.
+ complete_type See |complete_info_mode|
]=],
},
exception = {
diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua
index 3b0be5c9d9..b62c5afcfc 100644
--- a/test/functional/editor/defaults_spec.lua
+++ b/test/functional/editor/defaults_spec.lua
@@ -94,6 +94,74 @@ describe('default', function()
end)
describe('key mappings', function()
+ describe('Visual mode search mappings', function()
+ it('handle various chars properly', function()
+ n.clear({ args_rm = { '--cmd' } })
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = { foreground = Screen.colors.NvimDarkGray4 },
+ [2] = {
+ foreground = Screen.colors.NvimDarkGray3,
+ background = Screen.colors.NvimLightGray3,
+ },
+ [3] = {
+ foreground = Screen.colors.NvimLightGrey1,
+ background = Screen.colors.NvimDarkYellow,
+ },
+ [4] = {
+ foreground = Screen.colors.NvimDarkGrey1,
+ background = Screen.colors.NvimLightYellow,
+ },
+ })
+ n.api.nvim_buf_set_lines(0, 0, -1, true, {
+ [[testing <CR> /?\!1]],
+ [[testing <CR> /?\!2]],
+ [[testing <CR> /?\!3]],
+ [[testing <CR> /?\!4]],
+ })
+ n.feed('gg0vf!o*')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {4:^testing <CR> /?\!}2 |
+ {3:testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 2,1 All}|
+ /\Vtesting <CR> \/?\\! [2/4] |
+ ]])
+ n.feed('n')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {3:testing <CR> /?\!}2 |
+ {4:^testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 3,1 All}|
+ /\Vtesting <CR> \/?\\! [3/4] |
+ ]])
+ n.feed('G0vf!o#')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {3:testing <CR> /?\!}2 |
+ {4:^testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 3,1 All}|
+ ?\Vtesting <CR> /?\\! [3/4] |
+ ]])
+ n.feed('n')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {4:^testing <CR> /?\!}2 |
+ {3:testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 2,1 All}|
+ ?\Vtesting <CR> /?\\! [2/4] |
+ ]])
+ end)
+ end)
+
describe('unimpaired-style mappings', function()
it('show the command ouptut when successful', function()
n.clear({ args_rm = { '--cmd' } })
diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua
index 79a70c9c72..6c320376c9 100644
--- a/test/functional/lua/system_spec.lua
+++ b/test/functional/lua/system_spec.lua
@@ -122,6 +122,7 @@ describe('vim.system', function()
it('always captures all content of stdout/stderr #30846', function()
t.skip(n.fn.executable('git') == 0, 'missing "git" command')
+ t.skip(n.fn.isdirectory('.git') == 0, 'missing ".git" directory')
eq(
0,
exec_lua(function()
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index 6cc894c28c..bf7477f088 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -253,6 +253,91 @@ func Test_CompleteDoneNone()
au! CompleteDone
endfunc
+func Test_CompleteDone_vevent_keys()
+ func OnDone()
+ let g:complete_word = get(v:event, 'complete_word', v:null)
+ let g:complete_type = get(v:event, 'complete_type', v:null)
+ endfunction
+
+ autocmd CompleteDone * :call OnDone()
+
+ func CompleteFunc(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "bar"}]
+ endfunc
+ set omnifunc=CompleteFunc
+ set completefunc=CompleteFunc
+ set completeopt+=menuone
+
+ new
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-N>\<C-Y>\<Esc>0", 'tx')
+ call assert_equal('bar', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<ESC>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim\<CR>completion test\<CR>\<C-X>\<C-l>\<C-Y>", 'tx')
+ call assert_equal('completion test', g:complete_word)
+ call assert_equal('whole_line', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-U>\<C-Y>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('function', g:complete_type)
+
+ inoremap <buffer> <f3> <cmd>call complete(1, ["red", "blue"])<cr>
+ call feedkeys("S\<f3>\<C-Y>", 'tx')
+ call assert_equal('red', g:complete_word)
+ call assert_equal('eval', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-V>\<C-Y>", 'tx')
+ call assert_equal('!', g:complete_word)
+ call assert_equal('cmdline', g:complete_type)
+
+ call writefile([''], 'foo_test', 'D')
+ call feedkeys("Sfoo\<C-X>\<C-F>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo_test', g:complete_word)
+ call assert_equal('files', g:complete_type)
+
+ call writefile(['hello help'], 'test_case.txt', 'D')
+ set dictionary=test_case.txt
+ call feedkeys("ggdGSh\<C-X>\<C-K>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('hello', g:complete_word)
+ call assert_equal('dictionary', g:complete_type)
+
+ set spell spelllang=en_us
+ call feedkeys("STheatre\<C-X>s\<C-Y>\<Esc>", 'tx')
+ call assert_equal('Theater', g:complete_word)
+ call assert_equal('spell', g:complete_type)
+
+ bwipe!
+ set completeopt& omnifunc& completefunc& spell& spelllang& dictionary&
+ autocmd! CompleteDone
+ delfunc OnDone
+ delfunc CompleteFunc
+ unlet g:complete_word
+ unlet g:complete_type
+endfunc
+
func Test_CompleteDoneDict()
au CompleteDonePre * :call <SID>CompleteDone_CheckCompletedItemDict(1)
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict(0)