diff options
-rwxr-xr-x | .github/workflows/env.sh | 2 | ||||
-rwxr-xr-x | ci/common/submit_coverage.sh | 4 | ||||
-rwxr-xr-x | ci/install.sh | 8 | ||||
-rw-r--r-- | runtime/autoload/dist/ft.vim | 15 | ||||
-rw-r--r-- | runtime/filetype.vim | 9 | ||||
-rw-r--r-- | runtime/lua/vim/filetype.lua | 2 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 6 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 34 | ||||
-rw-r--r-- | src/nvim/ex_session.c | 28 | ||||
-rw-r--r-- | src/nvim/getchar.c | 5 | ||||
-rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 8 | ||||
-rw-r--r-- | src/nvim/testdir/test_filetype.vim | 18 | ||||
-rw-r--r-- | src/nvim/testdir/test_mksession.vim | 30 | ||||
-rw-r--r-- | src/nvim/testdir/test_search.vim | 103 | ||||
-rw-r--r-- | test/functional/editor/meta_key_spec.lua | 16 |
15 files changed, 246 insertions, 42 deletions
diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh index acdbc5da1e..0964995605 100755 --- a/.github/workflows/env.sh +++ b/.github/workflows/env.sh @@ -35,7 +35,7 @@ case "$FLAVOR" in cat <<EOF >> "$GITHUB_ENV" CLANG_SANITIZER=ASAN_UBSAN SYMBOLIZER=asan_symbolize-13 -ASAN_OPTIONS=detect_leaks=1:check_initialization_order=1:log_path=$GITHUB_WORKSPACE/build/log/asan +ASAN_OPTIONS=detect_leaks=1:check_initialization_order=1:log_path=$GITHUB_WORKSPACE/build/log/asan:intercept_tls_get_addr=0 UBSAN_OPTIONS=print_stacktrace=1 log_path=$GITHUB_WORKSPACE/build/log/ubsan EOF ;; diff --git a/ci/common/submit_coverage.sh b/ci/common/submit_coverage.sh index 9c7887de0b..cb6ab62b5b 100755 --- a/ci/common/submit_coverage.sh +++ b/ci/common/submit_coverage.sh @@ -18,12 +18,12 @@ if ! [ -f "$codecov_sh" ]; then curl --retry 5 --silent --fail -o "$codecov_sh" https://codecov.io/bash chmod +x "$codecov_sh" - python3 -m pip install --quiet --user gcovr + python -m pip install --quiet --user gcovr fi ( cd build - python3 -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2 --exclude '.*/auto/.*' --root .. --delete -o ../coverage.xml --xml + python -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2 --exclude '.*/auto/.*' --root .. --delete -o ../coverage.xml --xml ) # Upload to codecov. diff --git a/ci/install.sh b/ci/install.sh index bd42274b49..894e090de2 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -4,12 +4,8 @@ set -e set -o pipefail # Use default CC to avoid compilation problems when installing Python modules. -echo "Install neovim module for Python 3." -CC=cc python3 -m pip -q install --user --upgrade pynvim -if python2 -m pip -c True 2>&1; then - echo "Install neovim module for Python 2." - CC=cc python2 -m pip -q install --user --upgrade pynvim -fi +echo "Install neovim module for Python." +CC=cc python -m pip -q install --user --upgrade pynvim echo "Install neovim RubyGem." gem install --no-document --bindir "$HOME/.local/bin" --user-install --pre neovim diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index 69712046a5..86c71fa52d 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -862,6 +862,21 @@ func dist#ft#FTfoam() endwhile endfunc +" Determine if a *.tf file is TF mud client or terraform +func dist#ft#FTtf() + let numberOfLines = line('$') + for i in range(1, numberOfLines) + let currentLine = trim(getline(i)) + let firstCharacter = currentLine[0] + if firstCharacter !=? ";" && firstCharacter !=? "/" && firstCharacter !=? "" + setf terraform + return + endif + endfor + setf tf +endfunc + + " Restore 'cpoptions' let &cpo = s:cpo_save unlet s:cpo_save diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 2a0a5110f2..6a27998cf4 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1942,10 +1942,13 @@ au BufNewFile,BufRead texmf.cnf setf texmf au BufNewFile,BufRead .tidyrc,tidyrc,tidy.conf setf tidy " TF mud client -au BufNewFile,BufRead *.tf,.tfrc,tfrc setf tf +au BufNewFile,BufRead .tfrc,tfrc setf tf + +" TF mud client or terraform +au BufNewFile,BufRead *.tf call dist#ft#FTtf() " TLA+ -au BufRead,BufNewFile *.tla setf tla +au BufNewFile,BufRead *.tla setf tla " tmux configuration au BufNewFile,BufRead {.,}tmux*.conf setf tmux @@ -1954,7 +1957,7 @@ au BufNewFile,BufRead {.,}tmux*.conf setf tmux au BufNewFile,BufRead *.toml setf toml " TPP - Text Presentation Program -au BufNewFile,BufReadPost *.tpp setf tpp +au BufNewFile,BufRead *.tpp setf tpp " Treetop au BufRead,BufNewFile *.treetop setf treetop diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index bd3b44e95b..7fa2fbe001 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -661,7 +661,6 @@ local extension = { txi = "texinfo", texinfo = "texinfo", text = "text", - tf = "tf", tfvars = "terraform", tla = "tla", tli = "tli", @@ -827,6 +826,7 @@ local extension = { stm = function() vim.fn["dist#ft#FThtml"]() end, tcsh = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, tex = function() vim.fn["dist#ft#FTtex"]() end, + tf = function() vim.fn["dist#ft#FTtf"]() end, w = function() vim.fn["dist#ft#FTprogress_cweb"]() end, xml = function() vim.fn["dist#ft#FTxml"]() end, y = function() vim.fn["dist#ft#FTy"]() end, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 4a07f6a850..29b6310c54 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3795,7 +3795,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) } // "getmousepos()" function -void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr) { dict_T *d; win_T *wp; @@ -6927,7 +6927,7 @@ static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fpt } /// "prompt_getprompt({buffer})" function -void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) FUNC_ATTR_NONNULL_ALL { // return an empty string by default, e.g. it's not a prompt buffer @@ -10673,7 +10673,7 @@ static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) /* * "string()" function */ -void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = (char_u *)encode_tv2string(&argvars[0], NULL); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index bfcb8c1663..c30d58a8eb 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2891,13 +2891,17 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr) exarg_T ea; char_u *name = argvars[0].vval.v_string; - while (name[0] != NUL && name[0] == ':') { + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + if (name == NULL) { + return; + } + + while (*name == ':') { name++; } name = skip_range(name, NULL); - rettv->v_type = VAR_STRING; - ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name; ea.cmdidx = (cmdidx_T)0; char_u *p = find_command(&ea, NULL); @@ -2906,7 +2910,7 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr) } rettv->vval.v_string = vim_strsave(IS_USER_CMDIDX(ea.cmdidx) - ? get_user_commands(NULL, ea.useridx) + ? get_user_command_name(ea.useridx, ea.cmdidx) : cmdnames[ea.cmdidx].cmd_name); } @@ -5151,7 +5155,7 @@ static int check_more(int message, bool forceit) char_u *get_command_name(expand_T *xp, int idx) { if (idx >= CMD_SIZE) { - return get_user_command_name(idx); + return expand_user_command_name(idx); } return cmdnames[idx].cmd_name; } @@ -6270,7 +6274,7 @@ static void do_ucmd(exarg_T *eap) xfree(split_buf); } -static char_u *get_user_command_name(int idx) +static char_u *expand_user_command_name(int idx) { return get_user_commands(NULL, idx - CMD_SIZE); } @@ -6303,6 +6307,24 @@ char_u *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx) return NULL; } +// Get the name of user command "idx". "cmdidx" can be CMD_USER or +// CMD_USER_BUF. +// Returns NULL if the command is not found. +static char_u *get_user_command_name(int idx, int cmdidx) +{ + if (cmdidx == CMD_USER && idx < ucmds.ga_len) { + return USER_CMD(idx)->uc_name; + } + if (cmdidx == CMD_USER_BUF) { + // In cmdwin, the alternative buffer should be used. + buf_T *buf = (cmdwin_type != 0 && get_cmdline_type() == NUL) ? prevwin->w_buffer : curbuf; + if (idx < buf->b_ucmds.ga_len) { + return USER_CMD_GA(&buf->b_ucmds, idx)->uc_name; + } + } + return NULL; +} + /* * Function given to ExpandGeneric() to obtain the list of user command * attributes. diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index a37cad9f2d..a6d6bcbb8d 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -338,14 +338,26 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr // Edit the file. Skip this when ":next" already did it. if (add_edit && (!did_next || wp->w_arg_idx_invalid)) { - char *fname_esc = - ses_escape_fname(ses_get_fname(wp->w_buffer, flagp), flagp); - // - // Load the file. - // - if (wp->w_buffer->b_ffname != NULL - && (!bt_nofile(wp->w_buffer) - || wp->w_buffer->terminal)) { + char *fname_esc = ses_escape_fname(ses_get_fname(wp->w_buffer, flagp), flagp); + if (bt_help(wp->w_buffer)) { + char *curtag = ""; + + // A help buffer needs some options to be set. + // First, create a new empty buffer with "buftype=help". + // Then ":help" will re-use both the buffer and the window and set + // the options, even when "options" is not in 'sessionoptions'. + if (0 < wp->w_tagstackidx && wp->w_tagstackidx <= wp->w_tagstacklen) { + curtag = (char *)wp->w_tagstack[wp->w_tagstackidx - 1].tagname; + } + + if (put_line(fd, "enew | setl bt=help") == FAIL + || fprintf(fd, "help %s", curtag) < 0 || put_eol(fd) == FAIL) { + return FAIL; + } + } else if (wp->w_buffer->b_ffname != NULL + && (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal)) { + // Load the file. + // Editing a file in this buffer: use ":edit file". // This may have side effects! (e.g., compressed or network file). // diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 55bcfa0e97..3e0f01852e 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1598,8 +1598,9 @@ int vgetc(void) if (!no_mapping && KeyTyped && !(State & TERM_FOCUS) && (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) { mod_mask = 0; - ins_char_typebuf(c, 0); - ins_char_typebuf(ESC, 0); + int len = ins_char_typebuf(c, 0); + (void)ins_char_typebuf(ESC, 0); + ungetchars(len + 3); // The ALT/META modifier takes three more bytes continue; } diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 1672b0e840..ff4cbe544c 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -500,8 +500,16 @@ func Test_fullcommand() for [in, want] in items(tests) call assert_equal(want, fullcommand(in)) endfor + call assert_equal('', fullcommand(v:_null_string)) call assert_equal('syntax', 'syn'->fullcommand()) + + command -buffer BufferLocalCommand : + command GlobalCommand : + call assert_equal('GlobalCommand', fullcommand('GlobalCom')) + call assert_equal('BufferLocalCommand', fullcommand('BufferL')) + delcommand BufferLocalCommand + delcommand GlobalCommand endfunc func Test_shellcmd_completion() diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index eb4824aa32..8d6f9ded1d 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -746,6 +746,24 @@ func Test_hook_file() filetype off endfunc +func Test_tf_file() + filetype on + + call writefile([';;; TF MUD client is super duper cool'], 'Xfile.tf') + split Xfile.tf + call assert_equal('tf', &filetype) + bwipe! + + call writefile(['provider "azurerm" {'], 'Xfile.tf') + split Xfile.tf + call assert_equal('terraform', &filetype) + bwipe! + + call delete('Xfile.tf') + filetype off +endfunc + + func Test_ts_file() filetype on diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim index 057895047d..a87691abf9 100644 --- a/src/nvim/testdir/test_mksession.vim +++ b/src/nvim/testdir/test_mksession.vim @@ -696,6 +696,36 @@ func Test_mksession_foldopt() set sessionoptions& endfunc +" Test for mksession with "help" but not "options" in 'sessionoptions' +func Test_mksession_help_noopt() + set sessionoptions-=options + set sessionoptions+=help + help + let fname = expand('%') + mksession! Xtest_mks.out + bwipe + + source Xtest_mks.out + call assert_equal('help', &buftype) + call assert_equal('help', &filetype) + call assert_equal(fname, expand('%')) + call assert_false(&modifiable) + call assert_true(&readonly) + + helpclose + help index + let fname = expand('%') + mksession! Xtest_mks.out + bwipe + + source Xtest_mks.out + call assert_equal('help', &buftype) + call assert_equal(fname, expand('%')) + + call delete('Xtest_mks.out') + set sessionoptions& +endfunc + " Test for mksession with window position func Test_mksession_winpos() if !has('gui_running') diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index c796f1f676..2a1a93b5e3 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -292,15 +292,84 @@ endfunc func Test_searchpair() new - call setline(1, ['other code here', '', '[', '" cursor here', ']']) + call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]']) + + 4 + call assert_equal(3, searchpair('\[', '', ']', 'bW')) + call assert_equal([0, 3, 2, 0], getpos('.')) + 4 + call assert_equal(2, searchpair('\[', '', ']', 'bWr')) + call assert_equal([0, 2, 6, 0], getpos('.')) + 4 + call assert_equal(1, searchpair('\[', '', ']', 'bWm')) + call assert_equal([0, 3, 2, 0], getpos('.')) + 4|norm ^ + call assert_equal(5, searchpair('\[', '', ']', 'Wn')) + call assert_equal([0, 4, 2, 0], getpos('.')) + 4 + call assert_equal(2, searchpair('\[', '', ']', 'bW', + \ 'getline(".") =~ "^\\s*\["')) + call assert_equal([0, 2, 6, 0], getpos('.')) + set nomagic + 4 + call assert_equal(3, searchpair('\[', '', ']', 'bW')) + call assert_equal([0, 3, 2, 0], getpos('.')) + set magic + 4|norm ^ + call assert_equal(0, searchpair('{', '', '}', 'bW')) + call assert_equal([0, 4, 2, 0], getpos('.')) + + %d + call setline(1, ['if 1', ' if 2', ' else', ' endif 2', 'endif 1']) + + /\<if 1 + call assert_equal(5, searchpair('\<if\>', '\<else\>', '\<endif\>', 'W')) + call assert_equal([0, 5, 1, 0], getpos('.')) + /\<if 2 + call assert_equal(3, searchpair('\<if\>', '\<else\>', '\<endif\>', 'W')) + call assert_equal([0, 3, 3, 0], getpos('.')) + + q! +endfunc + +func Test_searchpairpos() + new + call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]']) + + 4 + call assert_equal([3, 2], searchpairpos('\[', '', ']', 'bW')) + call assert_equal([0, 3, 2, 0], getpos('.')) 4 - let a = searchpair('\[','',']','bW') - call assert_equal(3, a) + call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bWr')) + call assert_equal([0, 2, 6, 0], getpos('.')) + 4|norm ^ + call assert_equal([5, 2], searchpairpos('\[', '', ']', 'Wn')) + call assert_equal([0, 4, 2, 0], getpos('.')) + 4 + call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bW', + \ 'getline(".") =~ "^\\s*\["')) + call assert_equal([0, 2, 6, 0], getpos('.')) + 4 + call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bWr')) + call assert_equal([0, 2, 6, 0], getpos('.')) set nomagic 4 - let a = searchpair('\[','',']','bW') - call assert_equal(3, a) + call assert_equal([3, 2], searchpairpos('\[', '', ']', 'bW')) + call assert_equal([0, 3, 2, 0], getpos('.')) set magic + 4|norm ^ + call assert_equal([0, 0], searchpairpos('{', '', '}', 'bW')) + call assert_equal([0, 4, 2, 0], getpos('.')) + + %d + call setline(1, ['if 1', ' if 2', ' else', ' endif 2', 'endif 1']) + /\<if 1 + call assert_equal([5, 1], searchpairpos('\<if\>', '\<else\>', '\<endif\>', 'W')) + call assert_equal([0, 5, 1, 0], getpos('.')) + /\<if 2 + call assert_equal([3, 3], searchpairpos('\<if\>', '\<else\>', '\<endif\>', 'W')) + call assert_equal([0, 3, 3, 0], getpos('.')) + q! endfunc @@ -312,14 +381,28 @@ func Test_searchpair_errors() call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0') call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99') call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100') + call assert_fails("call searchpair('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e') + call assert_fails("call searchpair('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn') +endfunc + +func Test_searchpairpos_errors() + call assert_fails("call searchpairpos([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String') + call assert_fails("call searchpairpos('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String') + call assert_fails("call searchpairpos('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String') + call assert_fails("call searchpairpos('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags') + call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0') + call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99') + call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100') + call assert_fails("call searchpairpos('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e') + call assert_fails("call searchpairpos('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn') endfunc func Test_searchpair_skip() func Zero() - return 0 + return 0 endfunc func Partial(x) - return a:x + return a:x endfunc new call setline(1, ['{', 'foo', 'foo', 'foo', '}']) @@ -1192,7 +1275,7 @@ endfunc " This was causing E874. Also causes an invalid read? func Test_look_behind() new - call setline(1, '0\|\&\n\@<=') + call setline(1, '0\|\&\n\@<=') call search(getline(".")) bwipe! endfunc @@ -1236,11 +1319,11 @@ endfunc func Test_search_Ctrl_L_combining() " Make sure, that Ctrl-L works correctly with combining characters. " It uses an artificial example of an 'a' with 4 combining chars: - " 'a' U+0061 Dec:97 LATIN SMALL LETTER A a /\%u61\Z "\u0061" + " 'a' U+0061 Dec:97 LATIN SMALL LETTER A a /\%u61\Z "\u0061" " ' ̀' U+0300 Dec:768 COMBINING GRAVE ACCENT ̀ /\%u300\Z "\u0300" " ' ́' U+0301 Dec:769 COMBINING ACUTE ACCENT ́ /\%u301\Z "\u0301" " ' ̇' U+0307 Dec:775 COMBINING DOT ABOVE ̇ /\%u307\Z "\u0307" - " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW ̣ /\%u323 "\u0323" + " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW ̣ /\%u323 "\u0323" " Those should also appear on the commandline CheckOption incsearch diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua index f811b8ae8d..8efcc81616 100644 --- a/test/functional/editor/meta_key_spec.lua +++ b/test/functional/editor/meta_key_spec.lua @@ -104,4 +104,20 @@ describe('meta-keys #8226 #13042', function() eq({ 0, 2, 1, 0, }, funcs.getpos('.')) eq('nt', eval('mode(1)')) end) + + it('ALT/META when recording a macro #13235', function() + feed('ifoo<CR>bar<CR>baz<Esc>gg0') + -- <M-"> is reinterpreted as <Esc>" + feed('qrviw"ayC// This is some text: <M-">apq') + expect([[ + // This is some text: foo + bar + baz]]) + -- Should not insert an extra double quote when replaying + feed('j0@rj0@@') + expect([[ + // This is some text: foo + // This is some text: bar + // This is some text: baz]]) + end) end) |