From 376de1483ee5380aaf5d2b6bb93d6ba245bfc329 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 8 Oct 2024 06:24:36 +0800 Subject: fix(drawline): correct highlight priority with Visual selection (#30706) --- src/nvim/drawline.c | 50 +++++++++------------------------ test/functional/ui/decorations_spec.lua | 2 +- test/functional/ui/fold_spec.lua | 16 +++++++---- test/functional/ui/spell_spec.lua | 31 ++++++++++++++++++++ 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 3b88dd2e90..79f3298eb4 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -927,7 +927,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s bool noinvcur = false; // don't invert the cursor bool lnum_in_visual_area = false; - bool attr_pri = false; // char_attr has priority + int char_attr_pri = 0; // attributes with high priority + int char_attr_base = 0; // attributes with low priority bool area_highlighting = false; // Visual or incsearch highlighting in this line int vi_attr = 0; // attributes for Visual and incsearch highlighting int area_attr = 0; // attributes desired by highlighting @@ -1741,16 +1742,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } // Decide which of the highlight attributes to use. - attr_pri = true; - if (area_attr != 0) { - wlv.char_attr = hl_combine_attr(wlv.line_attr, area_attr); + char_attr_pri = hl_combine_attr(wlv.line_attr, area_attr); if (!highlight_match) { // let search highlight show in Visual area if possible - wlv.char_attr = hl_combine_attr(search_attr, wlv.char_attr); + char_attr_pri = hl_combine_attr(search_attr, char_attr_pri); } } else if (search_attr != 0) { - wlv.char_attr = hl_combine_attr(wlv.line_attr, search_attr); + char_attr_pri = hl_combine_attr(wlv.line_attr, search_attr); } else if (wlv.line_attr != 0 && ((wlv.fromcol == -10 && wlv.tocol == MAXCOL) || wlv.vcol < wlv.fromcol @@ -1758,15 +1757,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s || wlv.vcol >= wlv.tocol)) { // Use wlv.line_attr when not in the Visual or 'incsearch' area // (area_attr may be 0 when "noinvcur" is set). - wlv.char_attr = wlv.line_attr; + char_attr_pri = wlv.line_attr; } else { - attr_pri = false; - wlv.char_attr = decor_attr; - } - - if (folded_attr != 0) { - wlv.char_attr = hl_combine_attr(folded_attr, wlv.char_attr); + char_attr_pri = 0; } + char_attr_base = hl_combine_attr(folded_attr, decor_attr); + wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); } if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) { @@ -1997,25 +1993,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s can_spell = TRISTATE_TO_BOOL(decor_state.spell, can_spell); } - if (folded_attr) { - decor_attr = hl_combine_attr(folded_attr, decor_attr); - } - - if (decor_attr) { - if (!attr_pri) { - if (wlv.cul_attr) { - wlv.char_attr = 0 != wlv.line_attr_lowprio - ? hl_combine_attr(wlv.cul_attr, decor_attr) - : hl_combine_attr(decor_attr, wlv.cul_attr); - } else { - wlv.char_attr = decor_attr; - } - } else { - wlv.char_attr = hl_combine_attr(decor_attr, wlv.char_attr); - } - } else if (!attr_pri) { - wlv.char_attr = 0; - } + char_attr_base = hl_combine_attr(folded_attr, decor_attr); + wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); // Check spelling (unless at the end of the line). // Only do this when there is no syntax highlighting, the @@ -2083,11 +2062,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } if (spell_attr != 0) { - if (!attr_pri) { - wlv.char_attr = hl_combine_attr(wlv.char_attr, spell_attr); - } else { - wlv.char_attr = hl_combine_attr(spell_attr, wlv.char_attr); - } + char_attr_base = hl_combine_attr(char_attr_base, spell_attr); + wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); } if (wp->w_buffer->terminal) { diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 042975f898..d96f614cd9 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -1964,7 +1964,7 @@ describe('extmark decorations', function() ]]} end) - pending('highlight applies to a full TAB in visual block mode', function() + it('highlight applies to a full TAB in visual block mode', function() screen:try_resize(50, 8) command('hi! Visual guifg=NONE guibg=LightGrey') api.nvim_buf_set_lines(0, 0, -1, true, {'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf'}) diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 2712e5ff48..8f6e8aef7e 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -55,6 +55,8 @@ describe('folded lines', function() }, [19] = { background = Screen.colors.Yellow, foreground = Screen.colors.DarkBlue }, [20] = { background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue }, + [21] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Green }, + [22] = { background = Screen.colors.Red, foreground = Screen.colors.Green }, }) end) @@ -2625,6 +2627,8 @@ describe('folded lines', function() command('hi! CursorLine guibg=NONE guifg=Red gui=NONE') command('hi F0 guibg=Red guifg=Black') command('hi F1 guifg=White') + command([[syn match Keyword /\/]]) + command('hi! Keyword guibg=NONE guifg=Green') api.nvim_set_option_value('cursorline', true, {}) api.nvim_set_option_value('foldcolumn', '4', {}) api.nvim_set_option_value('foldtext', '', {}) @@ -2662,7 +2666,7 @@ describe('folded lines', function() ## grid 2 {7: }This is a | {7:- }valid English | - {7:│+ }{5:sentence composed by······}| + {7:│+ }{21:sentence}{5: composed by······}| {7:│+ }{13:^in his cave.··············}| {1:~ }|*2 ## grid 3 @@ -2672,7 +2676,7 @@ describe('folded lines', function() screen:expect([[ {7: }This is a | {7:- }valid English | - {7:│+ }{5:sentence composed by······}| + {7:│+ }{21:sentence}{5: composed by······}| {7:│+ }{13:^in his cave.··············}| {1:~ }|*2 | @@ -2689,7 +2693,7 @@ describe('folded lines', function() ## grid 2 {7: }This is a | {7:- }^v{14:alid English} | - {7:│+ }{15:sentence composed by······}| + {7:│+ }{22:sentence}{15: composed by······}| {7:│+ }{15:in his cave.··············}| {1:~ }|*2 ## grid 3 @@ -2699,7 +2703,7 @@ describe('folded lines', function() screen:expect([[ {7: }This is a | {7:- }^v{14:alid English} | - {7:│+ }{15:sentence composed by······}| + {7:│+ }{22:sentence}{15: composed by······}| {7:│+ }{15:in his cave.··············}| {1:~ }|*2 {11:-- VISUAL LINE --} | @@ -2715,7 +2719,7 @@ describe('folded lines', function() ## grid 2 a si sihT{7: }| {14:hsilgnE dila}^v{7: -}| - {15:······yb desopmoc ecnetnes}{7: +│}| + {15:······yb desopmoc }{22:ecnetnes}{7: +│}| {15:··············.evac sih ni}{7: +│}| {1: ~}|*2 ## grid 3 @@ -2725,7 +2729,7 @@ describe('folded lines', function() screen:expect([[ a si sihT{7: }| {14:hsilgnE dila}^v{7: -}| - {15:······yb desopmoc ecnetnes}{7: +│}| + {15:······yb desopmoc }{22:ecnetnes}{7: +│}| {15:··············.evac sih ni}{7: +│}| {1: ~}|*2 {11:-- VISUAL LINE --} | diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index da112148cd..f0fa47ebfb 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -377,4 +377,35 @@ describe("'spell'", function() | ]]) end) + + it('overrides syntax when Visual selection is active', function() + screen:try_resize(43, 3) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { foreground = Screen.colors.Blue }, + [2] = { foreground = Screen.colors.Red }, + [3] = { foreground = Screen.colors.Blue, underline = true }, + [4] = { foreground = Screen.colors.Red, underline = true }, + [5] = { bold = true }, + }) + exec([[ + hi! Comment guibg=NONE guifg=Blue gui=NONE guisp=NONE + hi! SpellBad guibg=NONE guifg=Red gui=NONE guisp=NONE + hi! Visual guibg=NONE guifg=NONE gui=underline guisp=NONE + syn match Comment "//.*" + call setline(1, '// Here is a misspeld word.') + set spell + ]]) + screen:expect([[ + {1:^// Here is a }{2:misspeld}{1: word.} | + {0:~ }| + | + ]]) + feed('V') + screen:expect([[ + {1:^/}{3:/ Here is a }{4:misspeld}{3: word.} | + {0:~ }| + {5:-- VISUAL LINE --} | + ]]) + end) end) -- cgit From 5805716ca4dac8f214ed5fd8c3f0a5905a394e8c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 8 Oct 2024 06:51:57 +0800 Subject: vim-patch:9.1.0765: No test for patches 6.2.418 and 7.3.489 (#30713) Problem: No test for patches 6.2.418 and 7.3.489 Solution: Add a test. Fix some whitespace problems in test_mapping.vim. Document the behavior (zeertzjq). closes: vim/vim#15815 https://github.com/vim/vim/commit/5df3cb2898d8b4ad42ac367a436afc79bffecfb4 --- runtime/doc/map.txt | 2 + test/old/testdir/test_cmdline.vim | 2 +- test/old/testdir/test_mapping.vim | 81 +++++++++++++++++++++++++++----------- test/old/testdir/test_quickfix.vim | 4 +- 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 7fd1f3bfbb..4a4e34661f 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -66,6 +66,8 @@ modes. where the map command applies. Disallow mapping of {rhs}, to avoid nested and recursive mappings. Often used to redefine a command. + Note: Keys in {rhs} also won't trigger abbreviation, + with the exception of |i_CTRL-]| and |c_CTRL-]|. Note: When appears in the {rhs} this part is always applied even if remapping is disallowed. diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 9f25a42c38..b3179686b1 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -4070,7 +4070,7 @@ func Test_term_option() let &cpo = _cpo endfunc -func Test_cd_bslsh_completion_windows() +func Test_cd_bslash_completion_windows() CheckMSWindows let save_shellslash = &shellslash set noshellslash diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim index e4e446c55c..3b7ede2e08 100644 --- a/test/old/testdir/test_mapping.vim +++ b/test/old/testdir/test_mapping.vim @@ -6,33 +6,62 @@ source screendump.vim source term_util.vim func Test_abbreviation() + new " abbreviation with 0x80 should work inoreab чкпр vim call feedkeys("Goчкпр \", "xt") call assert_equal('vim ', getline('$')) iunab чкпр - set nomodified + bwipe! +endfunc + +func Test_abbreviation_with_noremap() + nnoremap :echo "cheese" + cabbr cheese xxx + call feedkeys(":echo \"cheese\"\\"\", 'tx') + call assert_equal('"echo "xxx"', @:) + call feedkeys("\\\"\", 'tx') + call assert_equal('"echo "cheese"', @:) + nnoremap :echo "cheese" + call feedkeys("\\\"\", 'tx') + call assert_equal('"echo "xxx"', @:) + nunmap + cunabbr cheese + + new + inoremap ( () + iabbr fnu fun + call feedkeys("ifnu(", 'tx') + call assert_equal('fun()', getline(1)) + bwipe! endfunc func Test_abclear() - abbrev foo foobar - iabbrev fooi foobari - cabbrev fooc foobarc - call assert_equal("\n\nc fooc foobarc\ni fooi foobari\n! foo foobar", execute('abbrev')) - - iabclear - call assert_equal("\n\nc fooc foobarc\nc foo foobar", execute('abbrev')) - abbrev foo foobar - iabbrev fooi foobari - - cabclear - call assert_equal("\n\ni fooi foobari\ni foo foobar", execute('abbrev')) - abbrev foo foobar - cabbrev fooc foobarc - - abclear - call assert_equal("\n\nNo abbreviation found", execute('abbrev')) - call assert_fails('%abclear', 'E481:') + abbrev foo foobar + iabbrev fooi foobari + cabbrev fooc foobarc + call assert_equal("\n\n" + \ .. "c fooc foobarc\n" + \ .. "i fooi foobari\n" + \ .. "! foo foobar", execute('abbrev')) + + iabclear + call assert_equal("\n\n" + \ .. "c fooc foobarc\n" + \ .. "c foo foobar", execute('abbrev')) + abbrev foo foobar + iabbrev fooi foobari + + cabclear + call assert_equal("\n\n" + \ .. "i fooi foobari\n" + \ .. "i foo foobar", execute('abbrev')) + abbrev foo foobar + cabbrev fooc foobarc + + abclear + call assert_equal("\n\nNo abbreviation found", execute('abbrev')) + call assert_fails('%abclear', 'E481:') endfunc func Test_abclear_buffer() @@ -42,15 +71,21 @@ func Test_abclear_buffer() new X2 abbrev foo2 foobar2 - call assert_equal("\n\n! foo2 @foobar2\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo2 @foobar2\n" + \ .. "! foo foobar", execute('abbrev')) abclear - call assert_equal("\n\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo foobar", execute('abbrev')) b X1 - call assert_equal("\n\n! foo1 @foobar1\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo1 @foobar1\n" + \ .. "! foo foobar", execute('abbrev')) abclear - call assert_equal("\n\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo foobar", execute('abbrev')) abclear call assert_equal("\n\nNo abbreviation found", execute('abbrev')) diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim index 753875963b..b4f8b2626a 100644 --- a/test/old/testdir/test_quickfix.vim +++ b/test/old/testdir/test_quickfix.vim @@ -6459,8 +6459,8 @@ func Test_cbuffer_range() call XbufferTests_range('l') endfunc -" Test for displaying fname pass from setqflist when the name -" are hard links to prevent seemly duplicate entries. +" Test for displaying fname passed from setqflist() when the names include +" hard links to prevent seemingly duplicate entries. func Xtest_hardlink_fname(cchar) call s:setup_commands(a:cchar) %bwipe -- cgit From 60e1862ccba744c4252d30f043bb077c2c657427 Mon Sep 17 00:00:00 2001 From: Devon Gardner Date: Mon, 7 Oct 2024 23:22:09 +0000 Subject: fix(coverity/510275): linematch out of bounds access (#30687) Problem: Int pointer cast to unsigned long pointer causes potential memory corruption. Solution: Cast and store value first, then pass the new pointer. --- src/nvim/linematch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c index 8943e6e8a6..39dfb8eeb9 100644 --- a/src/nvim/linematch.c +++ b/src/nvim/linematch.c @@ -150,7 +150,9 @@ static int count_n_matched_chars(mmfile_t **sp, const size_t n, bool iwhite) mmfile_t fastforward_buf_to_lnum(mmfile_t s, linenr_T lnum) { for (int i = 0; i < lnum - 1; i++) { - s.ptr = strnchr(s.ptr, (size_t *)&s.size, '\n'); + size_t n = (size_t)s.size; + s.ptr = strnchr(s.ptr, &n, '\n'); + s.size = (int)n; if (!s.ptr) { break; } -- cgit From f659699a26999cba4947f3c335c6e48d05c95310 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 8 Oct 2024 08:43:44 +0800 Subject: vim-patch:9.1.0766: too many strlen() calls in ex_getln.c (#30715) Problem: too many strlen() calls in ex_getln.c Solution: refactor the code to reduce the number of strlen() calls (John Marriott) closes: vim/vim#15809 https://github.com/vim/vim/commit/ccf8907570e14396e265b742e51f5089fdf97bf5 Co-authored-by: John Marriott --- src/nvim/ex_getln.c | 86 +++++++++++++++++++++++++++++++---------------------- src/nvim/search.c | 5 ++++ 2 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 7d87e609ca..ca01a158a3 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -125,6 +125,7 @@ typedef struct { bool gotesc; // true when just typed int do_abbr; // when true check for abbr. char *lookfor; // string to match + int lookforlen; int hiscnt; // current history line in use int save_hiscnt; // history line before attempting // to jump to next match @@ -385,7 +386,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s if (!use_last_pat) { char c = *end; *end = NUL; - bool empty = empty_pattern_magic(p, strlen(p), magic); + bool empty = empty_pattern_magic(p, (size_t)(end - p), magic); *end = c; if (empty) { goto theend; @@ -538,7 +539,8 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state if (!use_last_pat) { next_char = ccline.cmdbuff[skiplen + patlen]; ccline.cmdbuff[skiplen + patlen] = NUL; - if (empty_pattern(ccline.cmdbuff + skiplen, search_delim) && !no_hlsearch) { + if (empty_pattern(ccline.cmdbuff + skiplen, (size_t)patlen, search_delim) + && !no_hlsearch) { redraw_all_later(UPD_SOME_VALID); set_no_hlsearch(true); } @@ -900,12 +902,11 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear && ccline.cmdlen && s->firstc != NUL && (s->some_key_typed || s->histype == HIST_SEARCH)) { - size_t cmdbufflen = strlen(ccline.cmdbuff); - add_to_history(s->histype, ccline.cmdbuff, cmdbufflen, true, + add_to_history(s->histype, ccline.cmdbuff, (size_t)ccline.cmdlen, true, s->histype == HIST_SEARCH ? s->firstc : NUL); if (s->firstc == ':') { xfree(new_last_cmdline); - new_last_cmdline = xstrnsave(ccline.cmdbuff, cmdbufflen); + new_last_cmdline = xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen); } } @@ -1262,6 +1263,7 @@ static int command_line_execute(VimState *state, int key) && s->c != K_LEFT && s->c != K_RIGHT && (s->xpc.xp_numfiles > 0 || (s->c != Ctrl_P && s->c != Ctrl_N))) { XFREE_CLEAR(s->lookfor); + s->lookforlen = 0; } // When there are matching completions to select works like @@ -1440,7 +1442,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s return FAIL; } skiplen = 0; - patlen = (int)strlen(pat); + patlen = (int)last_search_pattern_len(); } else { pat = ccline.cmdbuff + skiplen; } @@ -1574,7 +1576,8 @@ static int command_line_erase_chars(CommandLineState *s) return CMDLINE_NOT_CHANGED; } - XFREE_CLEAR(ccline.cmdbuff); // no commandline to return + dealloc_cmdbuff(); // no commandline to return + if (!cmd_silent && !ui_has(kUICmdline)) { msg_col = 0; msg_putchar(' '); // delete ':' @@ -1702,7 +1705,6 @@ static void command_line_left_right_mouse(CommandLineState *s) static void command_line_next_histidx(CommandLineState *s, bool next_match) { - int j = (int)strlen(s->lookfor); while (true) { // one step backwards if (!next_match) { @@ -1746,7 +1748,7 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match) if ((s->c != K_UP && s->c != K_DOWN) || s->hiscnt == s->save_hiscnt || strncmp(get_histentry(s->histype)[s->hiscnt].hisstr, - s->lookfor, (size_t)j) == 0) { + s->lookfor, (size_t)s->lookforlen) == 0) { break; } } @@ -1765,30 +1767,34 @@ static int command_line_browse_history(CommandLineState *s) // save current command string so it can be restored later if (s->lookfor == NULL) { - s->lookfor = xstrdup(ccline.cmdbuff); + s->lookfor = xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen); s->lookfor[ccline.cmdpos] = NUL; + s->lookforlen = ccline.cmdpos; } bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN); command_line_next_histidx(s, next_match); - if (s->hiscnt != s->save_hiscnt) { - // jumped to other entry + if (s->hiscnt != s->save_hiscnt) { // jumped to other entry char *p; + int plen; int old_firstc; - XFREE_CLEAR(ccline.cmdbuff); + dealloc_cmdbuff(); + s->xpc.xp_context = EXPAND_NOTHING; if (s->hiscnt == get_hislen()) { p = s->lookfor; // back to the old one + plen = s->lookforlen; } else { p = get_histentry(s->histype)[s->hiscnt].hisstr; + plen = (int)strlen(p); } if (s->histype == HIST_SEARCH && p != s->lookfor - && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) { + && (old_firstc = (uint8_t)p[plen + 1]) != s->firstc) { int len = 0; // Correct for the separator character used when // adding the history entry vs the one used now. @@ -1827,12 +1833,13 @@ static int command_line_browse_history(CommandLineState *s) } } ccline.cmdbuff[len] = NUL; + ccline.cmdpos = ccline.cmdlen = len; } else { - alloc_cmdbuff((int)strlen(p)); + alloc_cmdbuff(plen); STRCPY(ccline.cmdbuff, p); + ccline.cmdpos = ccline.cmdlen = plen; } - ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff); redrawcmd(); return CMDLINE_CHANGED; } @@ -2201,18 +2208,17 @@ static int command_line_not_changed(CommandLineState *s) /// Guess that the pattern matches everything. Only finds specific cases, such /// as a trailing \|, which can happen while typing a pattern. -static bool empty_pattern(char *p, int delim) +static bool empty_pattern(char *p, size_t len, int delim) { - size_t n = strlen(p); magic_T magic_val = MAGIC_ON; - if (n > 0) { + if (len > 0) { skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val); } else { return true; } - return empty_pattern_magic(p, n, magic_val); + return empty_pattern_magic(p, len, magic_val); } static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val) @@ -2225,11 +2231,9 @@ static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val) // true, if the pattern is empty, or the pattern ends with \| and magic is // set (or it ends with '|' and very magic is set) - return len == 0 || (len > 1 - && ((p[len - 2] == '\\' - && p[len - 1] == '|' && magic_val == MAGIC_ON) - || (p[len - 2] != '\\' - && p[len - 1] == '|' && magic_val == MAGIC_ALL))); + return len == 0 || (len > 1 && p[len - 1] == '|' + && ((p[len - 2] == '\\' && magic_val == MAGIC_ON) + || (p[len - 2] != '\\' && magic_val == MAGIC_ALL))); } handle_T cmdpreview_get_bufnr(void) @@ -2710,7 +2714,7 @@ static int command_line_changed(CommandLineState *s) /// Abandon the command line. static void abandon_cmdline(void) { - XFREE_CLEAR(ccline.cmdbuff); + dealloc_cmdbuff(); ccline.redraw_state = kCmdRedrawNone; if (msg_scrolled == 0) { compute_cmdrow(); @@ -3000,8 +3004,15 @@ bool cmdline_at_end(void) return (ccline.cmdpos >= ccline.cmdlen); } -// Allocate a new command line buffer. -// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. +/// Deallocate a command line buffer, updating the buffer size and length. +static void dealloc_cmdbuff(void) +{ + XFREE_CLEAR(ccline.cmdbuff); + ccline.cmdlen = ccline.cmdbufflen = 0; +} + +/// Allocate a new command line buffer. +/// Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. static void alloc_cmdbuff(int len) { // give some extra space to avoid having to allocate all the time @@ -3023,6 +3034,7 @@ void realloc_cmdbuff(int len) } char *p = ccline.cmdbuff; + alloc_cmdbuff(len); // will get some more // There isn't always a NUL after the command, but it may need to be // there, thus copy up to the NUL and add a NUL. @@ -4509,17 +4521,20 @@ static int open_cmdwin(void) cmdwin_result = Ctrl_C; } // Set the new command line from the cmdline buffer. - xfree(ccline.cmdbuff); + dealloc_cmdbuff(); + if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!"; + size_t plen = (cmdwin_result == K_XF2) ? 2 : 3; if (histtype == HIST_CMD) { // Execute the command directly. - ccline.cmdbuff = xstrdup(p); + ccline.cmdbuff = xmemdupz(p, plen); + ccline.cmdlen = (int)plen; + ccline.cmdbufflen = (int)plen + 1; cmdwin_result = CAR; } else { // First need to cancel what we were doing. - ccline.cmdbuff = NULL; stuffcharReadbuff(':'); stuffReadbuff(p); stuffcharReadbuff(CAR); @@ -4529,17 +4544,18 @@ static int open_cmdwin(void) // and don't modify the cmd window. ccline.cmdbuff = NULL; } else { - ccline.cmdbuff = xstrdup(get_cursor_line_ptr()); + ccline.cmdlen = get_cursor_line_len(); + ccline.cmdbufflen = ccline.cmdlen + 1; + ccline.cmdbuff = xstrnsave(get_cursor_line_ptr(), (size_t)ccline.cmdlen); } + if (ccline.cmdbuff == NULL) { - ccline.cmdbuff = xstrdup(""); + ccline.cmdbuff = xmemdupz("", 0); ccline.cmdlen = 0; ccline.cmdbufflen = 1; ccline.cmdpos = 0; cmdwin_result = Ctrl_C; } else { - ccline.cmdlen = (int)strlen(ccline.cmdbuff); - ccline.cmdbufflen = ccline.cmdlen + 1; ccline.cmdpos = curwin->w_cursor.col; // If the cursor is on the last character, it probably should be after it. if (ccline.cmdpos == ccline.cmdlen - 1 || ccline.cmdpos > ccline.cmdlen) { diff --git a/src/nvim/search.c b/src/nvim/search.c index ff6e135df1..2a935f6878 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -380,6 +380,11 @@ char *last_search_pattern(void) return spats[RE_SEARCH].pat; } +size_t last_search_pattern_len(void) +{ + return spats[RE_SEARCH].patlen; +} + /// Return true when case should be ignored for search pattern "pat". /// Uses the 'ignorecase' and 'smartcase' options. int ignorecase(char *pat) -- cgit From 7de8bdaeb8792dd7a2c6f57a2181d72a95707ef0 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 7 Oct 2024 22:10:19 +0200 Subject: vim-patch:4f51f3a: runtime(spec): set comments and commentstring options closes: vim/vim#15817 https://github.com/vim/vim/commit/4f51f3a5732725a25ff64f509506c9c81b1c96a5 Co-authored-by: Andreas Schneider --- runtime/ftplugin/spec.vim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/runtime/ftplugin/spec.vim b/runtime/ftplugin/spec.vim index fa125be52c..dcf2908911 100644 --- a/runtime/ftplugin/spec.vim +++ b/runtime/ftplugin/spec.vim @@ -5,6 +5,7 @@ " Last Change: 2015 Jun 01 " Update by Zdenek Dohnal, 2022 May 17 " 2024 Sep 10 by Vim Project: add epoch support for spec changelog, #15537 +" 2024 Oct 07 by Vim Project: add comment support, #15817 if exists("b:did_ftplugin") finish @@ -14,6 +15,11 @@ let b:did_ftplugin = 1 let s:cpo_save = &cpo set cpo&vim +setlocal comments=b:# +setlocal commentstring=#\ %s + +let b:undo_ftplugin = "setlocal comments< commentstring<" + if !exists("no_plugin_maps") && !exists("no_spec_maps") if !hasmapto("SpecChangelog") map c SpecChangelog @@ -216,4 +222,4 @@ let b:match_words = let &cpo = s:cpo_save unlet s:cpo_save -let b:undo_ftplugin = "unlet! b:match_ignorecase b:match_words" +let b:undo_ftplugin ..= " | unlet! b:match_ignorecase b:match_words" -- cgit From 7737f892063ac716c6d94b4329df788cf268a719 Mon Sep 17 00:00:00 2001 From: Johnny Shaw Date: Thu, 15 Aug 2024 00:39:32 -0600 Subject: fix: deps build for ARM64 MSVC Problem: Neovim will not build for ARM64 using MSVC due to misconfigured gettext dependency build settings. Solution: Fix the dependency build settings for gettext when building with MSVC. --- cmake.deps/cmake/GettextCMakeLists.txt | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/cmake.deps/cmake/GettextCMakeLists.txt b/cmake.deps/cmake/GettextCMakeLists.txt index 722420e830..b86f3c6a52 100644 --- a/cmake.deps/cmake/GettextCMakeLists.txt +++ b/cmake.deps/cmake/GettextCMakeLists.txt @@ -15,15 +15,20 @@ string(REPLACE "#undef HAVE_LONG_LONG_INT" "#define HAVE_LONG_LONG_INT 1" CONFIG string(REPLACE "#undef HAVE_ICONV_H" "#define HAVE_ICONV_H 1" CONFIG_CONTENT ${CONFIG_CONTENT}) string(REPLACE "#undef HAVE_ICONV" "#define HAVE_ICONV 1" CONFIG_CONTENT ${CONFIG_CONTENT}) string(REPLACE "#undef ICONV_CONST" "#define ICONV_CONST const" CONFIG_CONTENT ${CONFIG_CONTENT}) -string(REPLACE "#undef uintmax_t" " - #if _WIN64 - # define intmax_t long long - # define uintmax_t unsigned long long - #elif _WIN32 - # define intmax_t long - # define uintmax_t unsigned long - #endif" - CONFIG_CONTENT ${CONFIG_CONTENT}) +if(MSVC) + string(REPLACE "#undef HAVE_STDINT_H_WITH_UINTMAX" "#define HAVE_STDINT_H_WITH_UINTMAX 1" CONFIG_CONTENT ${CONFIG_CONTENT}) + string(REPLACE "#undef HAVE_STDINT_H" "#define HAVE_STDINT_H 1" CONFIG_CONTENT ${CONFIG_CONTENT}) +else() + string(REPLACE "#undef uintmax_t" " + #if _WIN64 + # define intmax_t long long + # define uintmax_t unsigned long long + #elif _WIN32 + # define intmax_t long + # define uintmax_t unsigned long + #endif" + CONFIG_CONTENT ${CONFIG_CONTENT}) + endif() file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gettext-runtime/config.h ${CONFIG_CONTENT}) set(HAVE_NEWLOCALE 0) -- cgit From 214ce8d33c11f75b3500212258f09b58b3d42e80 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 8 Oct 2024 07:42:20 -0700 Subject: fix(gen_help_html): first tag in h2 is broken #30720 Problem: In h2 headings, the first tag points to an invalid anchor. This used to work but regressed a few months ago, possibly related to ceea6898a8bdcb6c4cfe06b8dc4739c144e6b1f8. Solution: - Simplify the logic, don't try to be clever: - Always use to_heading_tag() for the h2 `id`. - Also: - Render tags as ``, because `` is unnecessary and doesn't look great in headings. - In the main h1, use "foo.txt" as the anchor `name` (rarely used), prefer the next found tag for the `href`. --- runtime/doc/nvim.txt | 2 +- scripts/gen_help_html.lua | 23 ++++++----------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/runtime/doc/nvim.txt b/runtime/doc/nvim.txt index f8eba3f7f8..86e344c654 100644 --- a/runtime/doc/nvim.txt +++ b/runtime/doc/nvim.txt @@ -4,7 +4,7 @@ NVIM REFERENCE MANUAL -Nvim *neovim* *nvim* *nvim-intro* +Nvim *nvim* *neovim* *nvim-intro* Nvim is based on Vim by Bram Moolenaar. diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua index f6e799508b..b5dbce38f6 100644 --- a/scripts/gen_help_html.lua +++ b/scripts/gen_help_html.lua @@ -554,11 +554,8 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) return '' -- Spurious "===" or "---" in the help doc. end - -- Use the first *tag* node as the heading anchor, if any. - local tagnode = first(heading_node, 'tag') - -- Use the *tag* as the heading anchor id, if possible. - local tagname = tagnode and url_encode(trim(node_text(tagnode:child(1), false))) - or to_heading_tag(hname) + -- Generate an anchor id from the heading text. + local tagname = to_heading_tag(hname) if node_name == 'h1' or #headings == 0 then ---@type nvim.gen_help_html.heading local heading = { name = hname, subheadings = {}, tag = tagname } @@ -678,7 +675,7 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) table.insert(stats.first_tags, tagname) return '' end - local el = in_heading and 'span' or 'code' + local el = 'span' local encoded_tagname = url_encode(tagname) local s = ('%s<%s id="%s" class="%s">%s'):format( ws(), @@ -694,15 +691,6 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) end if in_heading and prev ~= 'tag' then - -- Don't set "id", let the heading use the tag as its "id" (used by search engines). - s = ('%s<%s class="%s">%s'):format( - ws(), - el, - cssclass, - encoded_tagname, - trimmed, - el - ) -- Start the container for tags in a heading. -- This makes "justify-content:space-between" right-align the tags. --

foo bartag1 tag2

@@ -957,7 +945,7 @@ local function gen_one(fname, text, to_fname, old, commit, parser_path)
-

%s

+

%s

Nvim :help pages, generated @@ -970,8 +958,9 @@ local function gen_one(fname, text, to_fname, old, commit, parser_path)

]]):format( logo_svg, - stats.first_tags[2] or '', stats.first_tags[1] or '', + stats.first_tags[2] or '', + stats.first_tags[2] or '', title, vim.fs.basename(fname), main -- cgit From 5f04e4ac4fd0d5058cf339b8824eed41b6981e85 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Oct 2024 07:15:52 +0800 Subject: vim-patch:d3b55d7: runtime(help): highlight CTRL- correctly (#30727) https://github.com/vim/vim/commit/d3b55d7f76e32e9b7f895fe43f37435ce7bf782e Co-authored-by: Christian Brabandt --- runtime/syntax/help.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim index fd128bb0b5..bccbacaeec 100644 --- a/runtime/syntax/help.vim +++ b/runtime/syntax/help.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Vim help file " Maintainer: The Vim Project -" Last Change: 2024 Oct 05 +" Last Change: 2024 Oct 08 " Former Maintainer: Bram Moolenaar " Quit when a (custom) syntax file was already loaded @@ -92,6 +92,7 @@ syn match helpSpecial "\[group]" syn match helpNormal "\[\(readonly\|fifo\|socket\|converted\|crypted\)]" syn match helpSpecial "CTRL-." +syn match helpSpecial "CTRL-<\a\+>" syn match helpSpecial "CTRL-SHIFT-." syn match helpSpecial "CTRL-Break" syn match helpSpecial "CTRL-PageUp" -- cgit From e98b1b0235a5e817c00814549606631703ab2041 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Oct 2024 07:16:43 +0800 Subject: vim-patch:9.1.0767: A condition is always true in ex_getln.c (#30726) Problem: A cmdlen == 0 condition is always true as ccline.cmdlen == 0 was already checked above (after v9.1.0766). Solution: Remove the condition and the variable. (zeertzjq) closes: vim/vim#15830 https://github.com/vim/vim/commit/c9aa6e4f2a040dc7f8411139d39d0463487100da --- test/old/testdir/test_mapping.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim index 3b7ede2e08..96fa0304dc 100644 --- a/test/old/testdir/test_mapping.vim +++ b/test/old/testdir/test_mapping.vim @@ -88,7 +88,7 @@ func Test_abclear_buffer() \ .. "! foo foobar", execute('abbrev')) abclear - call assert_equal("\n\nNo abbreviation found", execute('abbrev')) + call assert_equal("\n\nNo abbreviation found", execute('abbrev')) %bwipe endfunc -- cgit From f449a38f6a47bee30f0d4e291d8234d1ac8288a7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 9 Oct 2024 08:14:18 +0800 Subject: vim-patch:9.1.0770: current command line completion is a bit limited (#30728) Problem: current command completion is a bit limited Solution: Add the shellcmdline completion type and getmdcomplpat() function (Ruslan Russkikh). closes: vim/vim#15823 https://github.com/vim/vim/commit/0407d621bbad020b840ffbbbd25ba023bbc05edd Co-authored-by: Ruslan Russkikh --- runtime/doc/builtin.txt | 13 +++++- runtime/doc/map.txt | 2 + runtime/doc/usr_41.txt | 2 + runtime/lua/vim/_meta/vimfn.lua | 12 +++++- runtime/syntax/vim.vim | 2 +- src/nvim/cmdexpand.c | 4 +- src/nvim/cmdexpand_defs.h | 1 + src/nvim/eval.lua | 16 +++++++- src/nvim/ex_getln.c | 39 +++++++++++++++++- src/nvim/usercmd.c | 7 ++-- test/old/testdir/test_cmdline.vim | 86 ++++++++++++++++++++++++++++++++------- 11 files changed, 161 insertions(+), 23 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 4c726f86d2..617fd87553 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -3224,13 +3224,24 @@ getcharstr([{expr}]) *getcharstr()* Return: ~ (`string`) +getcmdcomplpat() *getcmdcomplpat()* + Return completion pattern of the current command-line. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|. + Returns an empty string when completion is not defined. + + Return: ~ + (`string`) + getcmdcompltype() *getcmdcompltype()* Return the type of the current command-line completion. Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, - |getcmdprompt()| and |setcmdline()|. + |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. Return: ~ diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 4a4e34661f..11048aee30 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1413,6 +1413,8 @@ completion can be enabled: -complete=runtime file and directory names in |'runtimepath'| -complete=scriptnames sourced script names -complete=shellcmd Shell command + -complete=shellcmdline First is a shell command and subsequent ones + are filenames. The same behavior as |:!cmd| -complete=sign |:sign| suboptions -complete=syntax syntax file names |'syntax'| -complete=syntime |:syntime| suboptions diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 8c7ed875cf..3202a70b76 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -906,6 +906,8 @@ Buffers, windows and the argument list: swapname() get the swap file path of a buffer Command line: *command-line-functions* + getcmdcomplpat() get completion pattern of the current command + line getcmdcompltype() get the type of the current command line completion getcmdline() get the current command line input diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 3f6deba092..1e1e87fca8 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -2879,12 +2879,22 @@ function vim.fn.getcharsearch() end --- @return string function vim.fn.getcharstr(expr) end +--- Return completion pattern of the current command-line. +--- Only works when the command line is being edited, thus +--- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. +--- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, +--- |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|. +--- Returns an empty string when completion is not defined. +--- +--- @return string +function vim.fn.getcmdcomplpat() end + --- Return the type of the current command-line completion. --- Only works when the command line is being edited, thus --- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. --- See |:command-completion| for the return string. --- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, ---- |getcmdprompt()| and |setcmdline()|. +--- |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. --- Returns an empty string when completion is not defined. --- --- @return string diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index 9073c6e7bf..6e38076d35 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -381,7 +381,7 @@ endif syn case ignore syn keyword vimUserCmdAttrKey contained a[ddr] ban[g] bar bu[ffer] com[plete] cou[nt] k[eepscript] n[args] ra[nge] re[gister] " GEN_SYN_VIM: vimUserCmdAttrCmplt, START_STR='syn keyword vimUserCmdAttrCmplt contained', END_STR='' -syn keyword vimUserCmdAttrCmplt contained arglist augroup behave breakpoint buffer color command compiler cscope diff_buffer dir dir_in_path environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages option packadd runtime scriptnames shellcmd sign syntax syntime tag tag_listfiles user var +syn keyword vimUserCmdAttrCmplt contained arglist augroup behave breakpoint buffer color command compiler cscope diff_buffer dir dir_in_path environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages option packadd runtime scriptnames shellcmd shellcmdline sign syntax syntime tag tag_listfiles user var syn keyword vimUserCmdAttrCmplt contained custom customlist nextgroup=vimUserCmdAttrCmpltFunc,vimUserCmdError syn match vimUserCmdAttrCmpltFunc contained ",\%([sS]:\|<[sS][iI][dD]>\)\=\%(\h\w*\%([.#]\h\w*\)\+\|\h\w*\)"hs=s+1 nextgroup=vimUserCmdError " GEN_SYN_VIM: vimUserCmdAttrAddr, START_STR='syn keyword vimUserCmdAttrAddr contained', END_STR='' diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 402a891099..b37a1d690f 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -119,6 +119,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp) && xp->xp_context != EXPAND_PACKADD && xp->xp_context != EXPAND_RUNTIME && xp->xp_context != EXPAND_SHELLCMD + && xp->xp_context != EXPAND_SHELLCMDLINE && xp->xp_context != EXPAND_TAGS && xp->xp_context != EXPAND_TAGS_LISTFILES && xp->xp_context != EXPAND_USER_LIST @@ -1527,7 +1528,8 @@ static void set_context_for_wildcard_arg(exarg_T *eap, const char *arg, bool use xp->xp_context = EXPAND_FILES; // For a shell command more chars need to be escaped. - if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal) { + if (usefilter || eap->cmdidx == CMD_bang || eap->cmdidx == CMD_terminal + || *complp == EXPAND_SHELLCMDLINE) { #ifndef BACKSLASH_IN_FILENAME xp->xp_shell = true; #endif diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h index 3369790151..86725eafd6 100644 --- a/src/nvim/cmdexpand_defs.h +++ b/src/nvim/cmdexpand_defs.h @@ -106,6 +106,7 @@ enum { EXPAND_ARGOPT, EXPAND_KEYMAP, EXPAND_DIRS_IN_CDPATH, + EXPAND_SHELLCMDLINE, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 50aaf9e03b..24f986ef4e 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3611,6 +3611,20 @@ M.funcs = { returns = 'string', signature = 'getcharstr([{expr}])', }, + getcmdcomplpat = { + desc = [=[ + Return completion pattern of the current command-line. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, + |getcmdprompt()|, |getcmdcompltype()| and |setcmdline()|. + Returns an empty string when completion is not defined. + ]=], + name = 'getcmdcomplpat', + params = {}, + returns = 'string', + signature = 'getcmdcomplpat()', + }, getcmdcompltype = { desc = [=[ Return the type of the current command-line completion. @@ -3618,7 +3632,7 @@ M.funcs = { requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, - |getcmdprompt()| and |setcmdline()|. + |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. ]=], name = 'getcmdcompltype', diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index ca01a158a3..b58a6b16f1 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4086,14 +4086,44 @@ static char *get_cmdline_str(void) return xstrnsave(p->cmdbuff, (size_t)p->cmdlen); } +/// Get the current command-line completion pattern. +static char *get_cmdline_completion_pattern(void) +{ + if (cmdline_star > 0) { + return NULL; + } + + CmdlineInfo *p = get_ccline_ptr(); + if (p == NULL || p->xpc == NULL) { + return NULL; + } + + int xp_context = p->xpc->xp_context; + if (xp_context == EXPAND_NOTHING) { + set_expand_context(p->xpc); + xp_context = p->xpc->xp_context; + p->xpc->xp_context = EXPAND_NOTHING; + } + if (xp_context == EXPAND_UNSUCCESSFUL) { + return NULL; + } + + char *compl_pat = p->xpc->xp_pattern; + if (compl_pat == NULL) { + return NULL; + } + + return xstrdup(compl_pat); +} + /// Get the current command-line completion type. static char *get_cmdline_completion(void) { if (cmdline_star > 0) { return NULL; } - CmdlineInfo *p = get_ccline_ptr(); + CmdlineInfo *p = get_ccline_ptr(); if (p == NULL || p->xpc == NULL) { return NULL; } @@ -4123,6 +4153,13 @@ static char *get_cmdline_completion(void) return xstrdup(cmd_compl); } +/// "getcmdcomplpat()" function +void f_getcmdcomplpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = get_cmdline_completion_pattern(); +} + /// "getcmdcompltype()" function void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index d32e0ee319..8404b2bc14 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -91,6 +91,7 @@ static const char *command_complete[] = { [EXPAND_PACKADD] = "packadd", [EXPAND_RUNTIME] = "runtime", [EXPAND_SHELLCMD] = "shellcmd", + [EXPAND_SHELLCMDLINE] = "shellcmdline", [EXPAND_SIGN] = "sign", [EXPAND_TAGS] = "tag", [EXPAND_TAGS_LISTFILES] = "tag_listfiles", @@ -285,8 +286,7 @@ const char *set_context_in_user_cmdarg(const char *cmd FUNC_ATTR_UNUSED, const c } if (argt & EX_XFILE) { - // EX_XFILE: file names are handled above. - xp->xp_context = context; + // EX_XFILE: file names are handled before this call. return NULL; } @@ -675,7 +675,8 @@ int parse_compl_arg(const char *value, int vallen, int *complp, uint32_t *argt, *complp = i; if (i == EXPAND_BUFFERS) { *argt |= EX_BUFNAME; - } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES) { + } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES + || i == EXPAND_SHELLCMDLINE) { *argt |= EX_XFILE; } break; diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index b3179686b1..a5df637cc2 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -1012,8 +1012,7 @@ func Test_cmdline_complete_user_names() call feedkeys(':e ~' . first_letter . "\\\"\", 'tx') call assert_match('^"e \~.*\<' . whoami . '\>', @:) endif - endif - if has('win32') + elseif has('win32') " Just in case: check that the system has an Administrator account. let names = system('net user') if names =~ 'Administrator' @@ -1022,14 +1021,25 @@ func Test_cmdline_complete_user_names() call feedkeys(':e ~A' . "\\\"\", 'tx') call assert_match('^"e \~.*Administrator', @:) endif + else + throw 'Skipped: does not work on this platform' endif endfunc +func Test_cmdline_complete_shellcmdline() + CheckExecutable whoami + command -nargs=1 -complete=shellcmdline MyCmd + + call feedkeys(":MyCmd whoam\\\"\", 'tx') + call assert_match('^".*\', @:) + + delcommand MyCmd +endfunc + func Test_cmdline_complete_bang() - if executable('whoami') - call feedkeys(":!whoam\\\"\", 'tx') - call assert_match('^".*\', @:) - endif + CheckExecutable whoami + call feedkeys(":!whoam\\\"\", 'tx') + call assert_match('^".*\', @:) endfunc func Test_cmdline_complete_languages() @@ -3800,6 +3810,52 @@ func Test_cmdline_complete_substitute_short() endfor endfunc +" Test for shellcmdline command argument completion +func Test_cmdline_complete_shellcmdline_argument() + command -nargs=+ -complete=shellcmdline MyCmd + + set wildoptions=fuzzy + + call feedkeys(":MyCmd vim test_cmdline.\\\"\", 'xt') + call assert_equal('"MyCmd vim test_cmdline.vim', @:) + + call feedkeys(":MyCmd vim nonexistentfile\\\"\", 'xt') + call assert_equal('"MyCmd vim nonexistentfile', @:) + + let compl1 = getcompletion('', 'file')[0] + let compl2 = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \\\"\", 'xt') + call assert_equal('"MyCmd vim ' .. compl1, @:) + + call feedkeys(":MyCmd vim \ \\\"\", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl1, @:) + + let compl = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \ \\\\"\", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl2, @:) + + set wildoptions& + call feedkeys(":MyCmd vim test_cmdline.\\\"\", 'xt') + call assert_equal('"MyCmd vim test_cmdline.vim', @:) + + call feedkeys(":MyCmd vim nonexistentfile\\\"\", 'xt') + call assert_equal('"MyCmd vim nonexistentfile', @:) + + let compl1 = getcompletion('', 'file')[0] + let compl2 = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \\\"\", 'xt') + call assert_equal('"MyCmd vim ' .. compl1, @:) + + call feedkeys(":MyCmd vim \ \\\"\", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl1, @:) + + let compl = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \ \\\\"\", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl2, @:) + + delcommand MyCmd +endfunc + " Test for :! shell command argument completion func Test_cmdline_complete_bang_cmd_argument() set wildoptions=fuzzy @@ -3811,30 +3867,32 @@ func Test_cmdline_complete_bang_cmd_argument() endfunc func Call_cmd_funcs() - return [getcmdpos(), getcmdscreenpos(), getcmdcompltype()] + return [getcmdpos(), getcmdscreenpos(), getcmdcompltype(), getcmdcomplpat()] endfunc func Test_screenpos_and_completion() call assert_equal(0, getcmdpos()) call assert_equal(0, getcmdscreenpos()) call assert_equal('', getcmdcompltype()) + call assert_equal('', getcmdcomplpat()) cnoremap string(Call_cmd_funcs()) call feedkeys(":let a\\\"\", "xt") - call assert_equal("\"let a[6, 7, 'var']", @:) + call assert_equal("\"let a[6, 7, 'var', 'a']", @:) call feedkeys(":quit \\\"\", "xt") - call assert_equal("\"quit [6, 7, '']", @:) + call assert_equal("\"quit [6, 7, '', '']", @:) call feedkeys(":nosuchcommand \\\"\", "xt") - call assert_equal("\"nosuchcommand [15, 16, '']", @:) + call assert_equal("\"nosuchcommand [15, 16, '', '']", @:) - " Check that getcmdcompltype() doesn't interfere with cmdline completion. + " Check that getcmdcompltype() and getcmdcomplpat() don't interfere with + " cmdline completion. let g:results = [] cnoremap let g:results += [[getcmdline()] + Call_cmd_funcs()] call feedkeys(":sign un\\\\\\\", "xt") call assert_equal([ - \ ['sign undefine', 14, 15, 'sign'], - \ ['sign unplace', 13, 14, 'sign'], - \ ['sign un', 8, 9, 'sign']], g:results) + \ ['sign undefine', 14, 15, 'sign', 'undefine'], + \ ['sign unplace', 13, 14, 'sign', 'unplace'], + \ ['sign un', 8, 9, 'sign', 'un']], g:results) unlet g:results cunmap -- cgit From 525352117b489a73e686a0343ec8b68babc9c921 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 9 Oct 2024 09:43:14 +0200 Subject: vim-patch:cb1d1dc: runtime(skill): Update syntax file to fix string escapes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The syntax script allowed for single backslash escapes like this "string\"" But did not accommodate for the uncommon case: "\\" Let's fix this by also skipping over double backslashes in the skillString region. closes: vim/vim#15832 https://github.com/vim/vim/commit/cb1d1dcc879cadfe81ca0088b7e7ebbcd92a9ff3 Co-authored-by: Simão Afonso @ Powertools Tech --- runtime/syntax/skill.vim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/syntax/skill.vim b/runtime/syntax/skill.vim index 47afffc0a9..dd4c191b6f 100644 --- a/runtime/syntax/skill.vim +++ b/runtime/syntax/skill.vim @@ -1,13 +1,14 @@ " Vim syntax file " Language: SKILL " Maintainer: Toby Schaffer -" Last Change: 2003 May 11 " Comments: SKILL is a Lisp-like programming language for use in EDA " tools from Cadence Design Systems. It allows you to have " a programming environment within the Cadence environment " that gives you access to the complete tool set and design " database. This file also defines syntax highlighting for " certain Design Framework II interface functions. +" Last Change: 2003 May 11 +" 2024 Oct 08 by Vim Project: allow double backslashes in skillString " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -509,7 +510,7 @@ syn match skilltechFunctions "(\(tech\|tc\)\u\a\+\>"hs=s+1 syn match skilltechFunctions "\<\(tech\|tc\)\u\a\+("he=e-1 " strings -syn region skillString start=+"+ skip=+\\"+ end=+"+ +syn region skillString start=+"+ skip=+\\\@ Date: Wed, 9 Oct 2024 09:43:26 +0200 Subject: vim-patch:830a802: runtime(nasm): Update nasm syntax script https://github.com/vim/vim/commit/830a802f9176ad38f115c18015987a871c99f3a4 Co-authored-by: Andrii Sokolov Co-authored-by: sarvel --- runtime/syntax/nasm.vim | 1009 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 806 insertions(+), 203 deletions(-) diff --git a/runtime/syntax/nasm.vim b/runtime/syntax/nasm.vim index e1dfc1db12..22d7c2729a 100644 --- a/runtime/syntax/nasm.vim +++ b/runtime/syntax/nasm.vim @@ -3,16 +3,16 @@ " Maintainer: Andrii Sokolov " Original Author: Manuel M.H. Stol " Former Maintainer: Manuel M.H. Stol -" Contributors: +" Contributors: " Leonard König (C string highlighting), " Peter Stanhope (Add missing 64-bit mode registers) -" Frédéric Hamel (F16c support, partial AVX +" Frédéric Hamel (F16c support, partial AVX " support, other) -" Last Change: 2023 Sep 7 +" sarvel (Complete set of supported instructions) +" Last Change: 2024 Oct 8 " NASM Home: http://www.nasm.us/ - " Setup Syntax: " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -22,7 +22,6 @@ endif syn case ignore - " Vim search and movement commands on identifers " Comments at start of a line inside which to skip search for indentifiers setlocal comments=:; @@ -89,16 +88,20 @@ syn match nasmString +\("[^"]\{-}"\|'[^']\{-}'\)+ " Highlight C escape- and format-sequences within ``-strings syn match nasmCString +\(`[^`]\{-}`\)+ contains=nasmCStringEscape,nasmCStringFormat extend syn case ignore -syn match nasmBinNumber "\<[0-1]\+b\>" -syn match nasmBinNumber "\<\~[0-1]\+b\>"lc=1 -syn match nasmOctNumber "\<\o\+q\>" -syn match nasmOctNumber "\<\~\o\+q\>"lc=1 -syn match nasmDecNumber "\<\d\+\>" -syn match nasmDecNumber "\<\~\d\+\>"lc=1 -syn match nasmHexNumber "\<\(\d\x*h\|0x\x\+\|\$\d\x*\)\>" -syn match nasmHexNumber "\<\~\(\d\x*h\|0x\x\+\|\$\d\x*\)\>"lc=1 -syn match nasmFltNumber "\<\d\+\.\d*\(e[+-]\=\d\+\)\=\>" -syn keyword nasmFltNumber Inf Infinity Indefinite NaN SNaN QNaN +syn match nasmBinNumber "\<\([01][01_]*[by]\|0[by][01_]\+\)\>" +syn match nasmBinNumber "\<\~\([01][01_]*[by]\|0[by][01_]\+\)\>"lc=1 +syn match nasmOctNumber "\<\(\o[0-7_]*[qo]\|0[qo][0-7_]\+\)\>" +syn match nasmOctNumber "\<\~\(\o[0-7_]*[qo]\|0[qo][0-7_]\+\)\>"lc=1 +syn match nasmDecNumber "\<\(\d[0-9_]*\|\d[0-9_]*d\|0d[0-9_]\+\)\>" +syn match nasmDecNumber "\<\~\(\d[0-9_]*\|\d[0-9_]*d\|0d[0-9_]\+\)\>"lc=1 +syn match nasmHexNumber "\<\(\d[0-9a-f_]*h\|0[xh][0-9a-f_]\+\|\$\d[0-9a-f_]*\)\>" +syn match nasmHexNumber "\<\~\(\d[0-9a-f_]*h\|0[xh][0-9a-f_]\+\|\$\d[0-9a-f_]*\)\>"lc=1 +syn match nasmBinFloat "\<\(0[by][01_]*\.[01_]*\(p[+-]\=[0-9_]*\)\=\)\|\(0[by][01_]*p[+-]\=[0-9_]*\)\>" +syn match nasmOctFloat "\<\(0[qo][0-7_]*\.[0-7_]*\(p[+-]\=[0-9_]*\)\=\)\|\(0[qo][0-7_]*p[+-]\=[0-9_]*\)\>" +syn match nasmDecFloat "\<\(\d[0-9_]*\.[0-9_]*\(e[+-]\=[0-9_]*\)\=\)\|\(\d[0-9_]*e[+-]\=[0-9_]*\)\>" +syn match nasmHexFloat "\<\(0[xh][0-9a-f_]\+\.[0-9a-f_]*\(p[+-]\=[0-9_]*\)\=\)\|\(0[xh][0-9a-f_]\+p[+-]\=[0-9_]*\)\>" +syn keyword nasmSpecFloat Inf NaN SNaN QNaN __?Infinity?__ __?NaN?__ __?SNaN?__ __?QNaN?__ +syn match nasmBcdConst "\<\(\d[0-9_]*p\|0p[0-9_]\+\)\>" syn match nasmNumberError "\<\~\s*\d\+\.\d*\(e[+-]\=\d\+\)\=\>" @@ -108,8 +111,8 @@ syn keyword nasmTypeError DF EXTRN FWORD RESF TBYTE syn keyword nasmType FAR NEAR SHORT syn keyword nasmType BYTE WORD DWORD QWORD DQWORD HWORD DHWORD TWORD syn keyword nasmType CDECL FASTCALL NONE PASCAL STDCALL -syn keyword nasmStorage DB DW DD DQ DDQ DT -syn keyword nasmStorage RESB RESW RESD RESQ RESDQ REST +syn keyword nasmStorage DB DW DD DQ DT DO DY DZ +syn keyword nasmStorage RESB RESW RESD RESQ REST RESO RESY RESZ syn keyword nasmStorage EXTERN GLOBAL COMMON " Structured storage types syn match nasmTypeError "\<\(AT\|I\=\(END\)\=\(STRUCT\=\|UNION\)\|I\=END\)\>" @@ -272,7 +275,6 @@ syn keyword nasmConstant __BITS__ __DATE__ __FILE__ __FORMAT__ __LINE__ syn keyword nasmConstant __NASM_MAJOR__ __NASM_MINOR__ __NASM_VERSION__ syn keyword nasmConstant __TIME__ " Instruction modifiers -syn match nasmInstructnError "\" syn match nasmInstrModifier "\(^\|:\)\s*[C-GS]S\>"ms=e-1 syn keyword nasmInstrModifier A16 A32 O16 O32 syn match nasmInstrModifier "\"lc=5,ms=e-1 @@ -290,7 +292,7 @@ syn keyword nasmStdDirective ENDPROC EPILOGUE LOCALS PROC PROLOGUE USES syn keyword nasmStdDirective ENDIF ELSE ELIF ELSIF IF "syn keyword nasmStdDirective BREAK CASE DEFAULT ENDSWITCH SWITCH "syn keyword nasmStdDirective CASE OF ENDCASE -syn keyword nasmStdDirective DO ENDFOR ENDWHILE FOR REPEAT UNTIL WHILE EXIT +syn keyword nasmStdDirective ENDFOR ENDWHILE FOR REPEAT UNTIL WHILE EXIT syn case ignore " Format specific directives: (all formats) " (excluded: extension directives to section, global, common and extern) @@ -302,193 +304,726 @@ syn keyword nasmFmtDirective _GLOBAL_OFFSET_TABLE_ __GLOBAL_OFFSET_TABLE_ syn keyword nasmFmtDirective ..start ..got ..gotoff ..gotpc ..plt ..sym syn case ignore - - +" Instruction errors: +" Instruction modifiers +syn match nasmInstructnError "\" " Standard Instructions: -syn match nasmInstructnError "\<\(F\=CMOV\|SET\)N\=\a\{0,2}\>" +syn match nasmInstructnError "\<\(F\=CMOV\|SET\|J\)N\=\a\{0,2}\>" +syn match nasmInstructnError "\" syn keyword nasmInstructnError CMPS MOVS LCS LODS STOS XLAT -syn match nasmStdInstruction "\" syn match nasmInstructnError "\\s*[^:]"he=e-1 -syn match nasmStdInstruction "\<\(CMOV\|J\|SET\)\(N\=\([ABGL]E\=\|[CEOSZ]\)\|P[EO]\=\)\>" -syn match nasmStdInstruction "\" -syn keyword nasmStdInstruction AAA AAD AAM AAS ADC ADD AND -syn keyword nasmStdInstruction BOUND BSF BSR BSWAP BT[C] BTR BTS -syn keyword nasmStdInstruction CALL CBW CDQ CDQE CLC CLD CMC CMP CMPSB CMPSD CMPSW CMPSQ -syn keyword nasmStdInstruction CMPXCHG CMPXCHG8B CPUID CWD[E] CQO -syn keyword nasmStdInstruction DAA DAS DEC DIV ENTER -syn keyword nasmStdInstruction IDIV IMUL INC INT[O] IRET[D] IRETW IRETQ -syn keyword nasmStdInstruction JCXZ JECXZ JMP -syn keyword nasmStdInstruction LAHF LDS LEA LEAVE LES LFS LGS LODSB LODSD LODSQ -syn keyword nasmStdInstruction LODSW LOOP[E] LOOPNE LOOPNZ LOOPZ LSS -syn keyword nasmStdInstruction MOVSB MOVSD MOVSW MOVSX MOVSQ MOVZX MUL NEG NOP NOT -syn keyword nasmStdInstruction OR POPA[D] POPAW POPF[D] POPFW POPFQ -syn keyword nasmStdInstruction PUSH[AD] PUSHAW PUSHF[D] PUSHFW PUSHFQ -syn keyword nasmStdInstruction PAUSE -syn keyword nasmStdInstruction RCL RCR RETF RET[N] ROL ROR -syn keyword nasmStdInstruction SAHF SAL SAR SBB SCASB SCASD SCASW -syn keyword nasmStdInstruction SHL[D] SHR[D] STC STD STOSB STOSD STOSW STOSQ SUB -syn keyword nasmStdInstruction TEST XADD XCHG XLATB XOR -syn keyword