diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2020-01-18 16:12:16 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-18 16:12:16 -0800 |
commit | fb8b0503baf95ccd9ab4a30220dd08ca8b16736b (patch) | |
tree | 8106670804b58724a15c64da4473b78393528601 | |
parent | fd89ad7bfb1534c42c99b36ca025ea42ccbee7e1 (diff) | |
parent | ad35cbca76222deb33357b63a61a29945ef084f7 (diff) | |
download | rneovim-fb8b0503baf95ccd9ab4a30220dd08ca8b16736b.tar.gz rneovim-fb8b0503baf95ccd9ab4a30220dd08ca8b16736b.tar.bz2 rneovim-fb8b0503baf95ccd9ab4a30220dd08ca8b16736b.zip |
Merge #11707 from janlazo/vim-8.1.1434
vim-patch:8.1.{716,1139},8.2.{112,120,123}
-rw-r--r-- | runtime/doc/autocmd.txt | 2 | ||||
-rw-r--r-- | src/nvim/edit.c | 20 | ||||
-rw-r--r-- | src/nvim/eval.c | 11 | ||||
-rw-r--r-- | src/nvim/indent_c.c | 3 | ||||
-rw-r--r-- | src/nvim/ops.c | 2 | ||||
-rw-r--r-- | src/nvim/spell.c | 246 | ||||
-rw-r--r-- | src/nvim/testdir/test_cindent.vim | 9 | ||||
-rw-r--r-- | src/nvim/testdir/test_ins_complete.vim | 66 | ||||
-rw-r--r-- | src/nvim/testdir/test_marks.vim | 21 |
9 files changed, 112 insertions, 268 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 45bead968d..774e6a5d92 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -596,6 +596,8 @@ CompleteChanged *CompleteChanged* CompleteDone After Insert mode completion is done. Either when something was completed or abandoning completion. |ins-completion| + |complete_info()| can be used, the info is + cleared after triggering CompleteDone. The |v:completed_item| variable contains the completed item. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index cdb4b127da..0c183add16 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3385,6 +3385,7 @@ static bool ins_compl_prep(int c) { char_u *ptr; bool retval = false; + const int prev_mode = ctrl_x_mode; /* Forget any previous 'special' messages if this is actually * a ^X mode key - bar ^R, in which case we wait to see what it gives us. @@ -3593,6 +3594,18 @@ static bool ins_compl_prep(int c) auto_format(FALSE, TRUE); + { + const int new_mode = ctrl_x_mode; + + // Trigger the CompleteDone event to give scripts a chance to + // act upon the completion. Do this before clearing the info, + // and restore ctrl_x_mode, so that complete_info() can be + // used. + ctrl_x_mode = prev_mode; + ins_apply_autocmds(EVENT_COMPLETEDONE); + ctrl_x_mode = new_mode; + } + ins_compl_free(); compl_started = false; compl_matches = 0; @@ -3617,9 +3630,6 @@ static bool ins_compl_prep(int c) */ if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0))) do_c_expr_indent(); - /* Trigger the CompleteDone event to give scripts a chance to act - * upon the completion. */ - ins_apply_autocmds(EVENT_COMPLETEDONE); } } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) /* Trigger the CompleteDone event to give scripts a chance to act @@ -3747,6 +3757,8 @@ expand_by_function( case VAR_DICT: matchdict = rettv.vval.v_dict; break; + case VAR_SPECIAL: + FALLTHROUGH; default: // TODO(brammool): Give error message? tv_clear(&rettv); @@ -5210,7 +5222,7 @@ static int ins_complete(int c, bool enable_pum) } } - /* Show a message about what (completion) mode we're in. */ + // Show a message about what (completion) mode we're in. showmode(); if (!shortmess(SHM_COMPLETIONMENU)) { if (edit_submode_extra != NULL) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9916ee3bd3..797c61a482 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -16018,7 +16018,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char *const name = tv_get_string_chk(argvars); if (name != NULL) { if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) { - if (--pos.col < 0) { + if (pos.col != MAXCOL && --pos.col < 0) { pos.col = 0; } if (name[0] == '.' && name[1] == NUL) { @@ -19045,6 +19045,15 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr) fp = var2fpos(&argvars[0], FALSE, &fnum); if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count && fnum == curbuf->b_fnum) { + // Limit the column to a valid value, getvvcol() doesn't check. + if (fp->col < 0) { + fp->col = 0; + } else { + const size_t len = STRLEN(ml_get(fp->lnum)); + if (fp->col > (colnr_T)len) { + fp->col = (colnr_T)len; + } + } getvvcol(curwin, fp, NULL, NULL, &vcol); ++vcol; } diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 1ca1f3dae5..67a7e58ed7 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -461,6 +461,9 @@ cin_iscase ( if (cin_starts_with(s, "case")) { for (s += 4; *s; ++s) { s = cin_skipcomment(s); + if (*s == NUL) { + break; + } if (*s == ':') { if (s[1] == ':') /* skip over "::" for C++ */ ++s; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 5da81dbff6..da2b81fd0a 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1372,7 +1372,7 @@ int op_delete(oparg_T *oap) linenr_T lnum; char_u *ptr; char_u *newp, *oldp; - struct block_def bd; + struct block_def bd = { 0 }; linenr_T old_lcount = curbuf->b_ml.ml_line_count; if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to do diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 5feb7efda9..c75a53a777 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -5835,10 +5835,7 @@ void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res) word = fword; } - if (has_mbyte) - spell_soundfold_wsal(slang, word, res); - else - spell_soundfold_sal(slang, word, res); + spell_soundfold_wsal(slang, word, res); } } @@ -5903,250 +5900,13 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) res[ri] = NUL; } -static void spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res) -{ - salitem_T *smp; - char_u word[MAXWLEN]; - char_u *s = inword; - char_u *t; - char_u *pf; - int i, j, z; - int reslen; - int n, k = 0; - int z0; - int k0; - int n0; - int c; - int pri; - int p0 = -333; - int c0; - - // Remove accents, if wanted. We actually remove all non-word characters. - // But keep white space. We need a copy, the word may be changed here. - if (slang->sl_rem_accents) { - t = word; - while (*s != NUL) { - if (ascii_iswhite(*s)) { - *t++ = ' '; - s = skipwhite(s); - } else { - if (spell_iswordp_nmw(s, curwin)) - *t++ = *s; - ++s; - } - } - *t = NUL; - } else - STRLCPY(word, s, MAXWLEN); - - smp = (salitem_T *)slang->sl_sal.ga_data; - - // This comes from Aspell phonet.cpp. Converted from C++ to C. - // Changed to keep spaces. - i = reslen = z = 0; - while ((c = word[i]) != NUL) { - // Start with the first rule that has the character in the word. - n = slang->sl_sal_first[c]; - z0 = 0; - - if (n >= 0) { - // check all rules for the same letter - for (; (s = smp[n].sm_lead)[0] == c; ++n) { - // Quickly skip entries that don't match the word. Most - // entries are less then three chars, optimize for that. - k = smp[n].sm_leadlen; - if (k > 1) { - if (word[i + 1] != s[1]) - continue; - if (k > 2) { - for (j = 2; j < k; ++j) - if (word[i + j] != s[j]) - break; - if (j < k) - continue; - } - } - - if ((pf = smp[n].sm_oneof) != NULL) { - // Check for match with one of the chars in "sm_oneof". - while (*pf != NUL && *pf != word[i + k]) - ++pf; - if (*pf == NUL) - continue; - ++k; - } - s = smp[n].sm_rules; - pri = 5; // default priority - - p0 = *s; - k0 = k; - while (*s == '-' && k > 1) { - k--; - s++; - } - if (*s == '<') - s++; - if (ascii_isdigit(*s)) { - // determine priority - pri = *s - '0'; - s++; - } - if (*s == '^' && *(s + 1) == '^') - s++; - - if (*s == NUL - || (*s == '^' - && (i == 0 || !(word[i - 1] == ' ' - || spell_iswordp(word + i - 1, curwin))) - && (*(s + 1) != '$' - || (!spell_iswordp(word + i + k0, curwin)))) - || (*s == '$' && i > 0 - && spell_iswordp(word + i - 1, curwin) - && (!spell_iswordp(word + i + k0, curwin)))) { - // search for followup rules, if: - // followup and k > 1 and NO '-' in searchstring - c0 = word[i + k - 1]; - n0 = slang->sl_sal_first[c0]; - - if (slang->sl_followup && k > 1 && n0 >= 0 - && p0 != '-' && word[i + k] != NUL) { - // test follow-up rule for "word[i + k]" - for (; (s = smp[n0].sm_lead)[0] == c0; ++n0) { - // Quickly skip entries that don't match the word. - k0 = smp[n0].sm_leadlen; - if (k0 > 1) { - if (word[i + k] != s[1]) - continue; - if (k0 > 2) { - pf = word + i + k + 1; - for (j = 2; j < k0; ++j) - if (*pf++ != s[j]) - break; - if (j < k0) - continue; - } - } - k0 += k - 1; - - if ((pf = smp[n0].sm_oneof) != NULL) { - // Check for match with one of the chars in - // "sm_oneof". - while (*pf != NUL && *pf != word[i + k0]) - ++pf; - if (*pf == NUL) - continue; - ++k0; - } - - p0 = 5; - s = smp[n0].sm_rules; - while (*s == '-') { - // "k0" gets NOT reduced because - // "if (k0 == k)" - s++; - } - if (*s == '<') - s++; - if (ascii_isdigit(*s)) { - p0 = *s - '0'; - s++; - } - - if (*s == NUL - // *s == '^' cuts - || (*s == '$' - && !spell_iswordp(word + i + k0, - curwin))) { - if (k0 == k) - // this is just a piece of the string - continue; - - if (p0 < pri) - // priority too low - continue; - // rule fits; stop search - break; - } - } - - if (p0 >= pri && smp[n0].sm_lead[0] == c0) - continue; - } - - // replace string - s = smp[n].sm_to; - if (s == NULL) - s = (char_u *)""; - pf = smp[n].sm_rules; - p0 = (vim_strchr(pf, '<') != NULL) ? 1 : 0; - if (p0 == 1 && z == 0) { - // rule with '<' is used - if (reslen > 0 && *s != NUL && (res[reslen - 1] == c - || res[reslen - 1] == *s)) - reslen--; - z0 = 1; - z = 1; - k0 = 0; - while (*s != NUL && word[i + k0] != NUL) { - word[i + k0] = *s; - k0++; - s++; - } - if (k > k0) - STRMOVE(word + i + k0, word + i + k); - - // new "actual letter" - c = word[i]; - } else { - // no '<' rule used - i += k - 1; - z = 0; - while (*s != NUL && s[1] != NUL && reslen < MAXWLEN) { - if (reslen == 0 || res[reslen - 1] != *s) - res[reslen++] = *s; - s++; - } - // new "actual letter" - c = *s; - if (strstr((char *)pf, "^^") != NULL) { - if (c != NUL) - res[reslen++] = c; - STRMOVE(word, word + i + 1); - i = 0; - z0 = 1; - } - } - break; - } - } - } else if (ascii_iswhite(c)) { - c = ' '; - k = 1; - } - - if (z0 == 0) { - if (k && !p0 && reslen < MAXWLEN && c != NUL - && (!slang->sl_collapse || reslen == 0 - || res[reslen - 1] != c)) - // condense only double letters - res[reslen++] = c; - - i++; - z = 0; - k = 0; - } - } - - res[reslen] = NUL; -} - // Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]". // Multi-byte version of spell_soundfold(). static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) { salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; - int word[MAXWLEN]; - int wres[MAXWLEN]; + int word[MAXWLEN] = { 0 }; + int wres[MAXWLEN] = { 0 }; int l; int *ws; int *pf; diff --git a/src/nvim/testdir/test_cindent.vim b/src/nvim/testdir/test_cindent.vim index d9795d9335..debc9da46d 100644 --- a/src/nvim/testdir/test_cindent.vim +++ b/src/nvim/testdir/test_cindent.vim @@ -118,4 +118,13 @@ b = something(); bw! endfunc +" this was going beyond the end of the line. +func Test_cindent_case() + new + call setline(1, "case x: // x") + set cindent + norm! f:a: + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 52ec281d82..e6d427db05 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -98,6 +98,15 @@ func Test_ins_complete() call delete('Xdir', 'rf') endfunc +func s:CompleteDone_CompleteFuncNone( findstart, base ) + throw 'skipped: Nvim does not support v:none' + if a:findstart + return 0 + endif + + return v:none +endfunc + function! s:CompleteDone_CompleteFuncDict( findstart, base ) if a:findstart return 0 @@ -117,6 +126,10 @@ function! s:CompleteDone_CompleteFuncDict( findstart, base ) \ } endfunction +func s:CompleteDone_CheckCompletedItemNone() + let s:called_completedone = 1 +endfunc + function! s:CompleteDone_CheckCompletedItemDict() call assert_equal( 'aword', v:completed_item[ 'word' ] ) call assert_equal( 'wrd', v:completed_item[ 'abbr' ] ) @@ -125,18 +138,37 @@ function! s:CompleteDone_CheckCompletedItemDict() call assert_equal( 'W', v:completed_item[ 'kind' ] ) call assert_equal( 'test', v:completed_item[ 'user_data' ] ) + call assert_equal('function', complete_info().mode) + let s:called_completedone = 1 endfunction -function Test_CompleteDoneDict() +func Test_CompleteDoneNone() + throw 'skipped: Nvim does not support v:none' + au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemNone() + let oldline = join(map(range(&columns), 'nr2char(screenchar(&lines-1, v:val+1))'), '') + + set completefunc=<SID>CompleteDone_CompleteFuncNone + execute "normal a\<C-X>\<C-U>\<C-Y>" + set completefunc& + let newline = join(map(range(&columns), 'nr2char(screenchar(&lines-1, v:val+1))'), '') + + call assert_true(s:called_completedone) + call assert_equal(oldline, newline) + + let s:called_completedone = 0 + au! CompleteDone +endfunc + +func Test_CompleteDoneDict() au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict() set completefunc=<SID>CompleteDone_CompleteFuncDict execute "normal a\<C-X>\<C-U>\<C-Y>" set completefunc& - call assert_equal( 'test', v:completed_item[ 'user_data' ] ) - call assert_true( s:called_completedone ) + call assert_equal('test', v:completed_item[ 'user_data' ]) + call assert_true(s:called_completedone) let s:called_completedone = 0 au! CompleteDone @@ -155,7 +187,7 @@ func Test_CompleteDone_undo() au! CompleteDone endfunc -function! s:CompleteDone_CompleteFuncDictNoUserData( findstart, base ) +func s:CompleteDone_CompleteFuncDictNoUserData(findstart, base) if a:findstart return 0 endif @@ -171,9 +203,9 @@ function! s:CompleteDone_CompleteFuncDictNoUserData( findstart, base ) \ } \ ] \ } -endfunction +endfunc -function! s:CompleteDone_CheckCompletedItemDictNoUserData() +func s:CompleteDone_CheckCompletedItemDictNoUserData() call assert_equal( 'aword', v:completed_item[ 'word' ] ) call assert_equal( 'wrd', v:completed_item[ 'abbr' ] ) call assert_equal( 'extra text', v:completed_item[ 'menu' ] ) @@ -182,31 +214,31 @@ function! s:CompleteDone_CheckCompletedItemDictNoUserData() call assert_equal( '', v:completed_item[ 'user_data' ] ) let s:called_completedone = 1 -endfunction +endfunc -function Test_CompleteDoneDictNoUserData() +func Test_CompleteDoneDictNoUserData() au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDictNoUserData() set completefunc=<SID>CompleteDone_CompleteFuncDictNoUserData execute "normal a\<C-X>\<C-U>\<C-Y>" set completefunc& - call assert_equal( '', v:completed_item[ 'user_data' ] ) - call assert_true( s:called_completedone ) + call assert_equal('', v:completed_item[ 'user_data' ]) + call assert_true(s:called_completedone) let s:called_completedone = 0 au! CompleteDone endfunc -function! s:CompleteDone_CompleteFuncList( findstart, base ) +func s:CompleteDone_CompleteFuncList(findstart, base) if a:findstart return 0 endif return [ 'aword' ] -endfunction +endfunc -function! s:CompleteDone_CheckCompletedItemList() +func s:CompleteDone_CheckCompletedItemList() call assert_equal( 'aword', v:completed_item[ 'word' ] ) call assert_equal( '', v:completed_item[ 'abbr' ] ) call assert_equal( '', v:completed_item[ 'menu' ] ) @@ -215,17 +247,17 @@ function! s:CompleteDone_CheckCompletedItemList() call assert_equal( '', v:completed_item[ 'user_data' ] ) let s:called_completedone = 1 -endfunction +endfunc -function Test_CompleteDoneList() +func Test_CompleteDoneList() au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemList() set completefunc=<SID>CompleteDone_CompleteFuncList execute "normal a\<C-X>\<C-U>\<C-Y>" set completefunc& - call assert_equal( '', v:completed_item[ 'user_data' ] ) - call assert_true( s:called_completedone ) + call assert_equal('', v:completed_item[ 'user_data' ]) + call assert_true(s:called_completedone) let s:called_completedone = 0 au! CompleteDone diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim index 272553c29f..06b9dc9dab 100644 --- a/src/nvim/testdir/test_marks.vim +++ b/src/nvim/testdir/test_marks.vim @@ -26,11 +26,11 @@ function! Test_Incr_Marks() endfunction func Test_setpos() - new one + new Xone let onebuf = bufnr('%') let onewin = win_getid() call setline(1, ['aaa', 'bbb', 'ccc']) - new two + new Xtwo let twobuf = bufnr('%') let twowin = win_getid() call setline(1, ['aaa', 'bbb', 'ccc']) @@ -63,7 +63,24 @@ func Test_setpos() call setpos("'N", [onebuf, 1, 3, 0]) call assert_equal([onebuf, 1, 3, 0], getpos("'N")) + " try invalid column and check virtcol() call win_gotoid(onewin) + call setpos("'a", [0, 1, 2, 0]) + call assert_equal([0, 1, 2, 0], getpos("'a")) + call setpos("'a", [0, 1, -5, 0]) + call assert_equal([0, 1, 2, 0], getpos("'a")) + call setpos("'a", [0, 1, 0, 0]) + call assert_equal([0, 1, 1, 0], getpos("'a")) + call setpos("'a", [0, 1, 4, 0]) + call assert_equal([0, 1, 4, 0], getpos("'a")) + call assert_equal(4, virtcol("'a")) + call setpos("'a", [0, 1, 5, 0]) + call assert_equal([0, 1, 5, 0], getpos("'a")) + call assert_equal(4, virtcol("'a")) + call setpos("'a", [0, 1, 21341234, 0]) + call assert_equal([0, 1, 21341234, 0], getpos("'a")) + call assert_equal(4, virtcol("'a")) + bwipe! call win_gotoid(twowin) bwipe! |