diff options
-rw-r--r-- | src/nvim/os/env.c | 35 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 2 | ||||
-rw-r--r-- | src/nvim/search.c | 63 | ||||
-rw-r--r-- | src/nvim/testdir/test_textobjects.vim | 25 | ||||
-rw-r--r-- | test/functional/ui/wildmode_spec.lua | 30 |
5 files changed, 120 insertions, 35 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 8a8220b6e7..e7bfbc8240 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -150,28 +150,47 @@ int os_unsetenv(const char *name) char *os_getenvname_at_index(size_t index) { +#ifdef _WIN32 + // Check if index is inside the environ array and is not the last element. + for (size_t i = 0; i <= index; i++) { + if (_wenviron[i] == NULL) { + return NULL; + } + } + wchar_t *utf16_str = _wenviron[index]; + char *utf8_str; + int conversion_result = utf16_to_utf8(utf16_str, &utf8_str); + if (conversion_result != 0) { + EMSG2("utf16_to_utf8 failed: %d", conversion_result); + return NULL; + } + size_t namesize = 0; + while (utf8_str[namesize] != '=' && utf8_str[namesize] != NUL) { + namesize++; + } + char *name = (char *)vim_strnsave((char_u *)utf8_str, namesize); + xfree(utf8_str); + return name; +#else # if defined(HAVE__NSGETENVIRON) char **environ = *_NSGetEnviron(); -# elif !defined(__WIN32__) - // Borland C++ 5.2 has this in a header file. +# else extern char **environ; # endif - // check if index is inside the environ array - for (size_t i = 0; i < index; i++) { + // Check if index is inside the environ array and is not the last element. + for (size_t i = 0; i <= index; i++) { if (environ[i] == NULL) { return NULL; } } char *str = environ[index]; - if (str == NULL) { - return NULL; - } size_t namesize = 0; while (str[namesize] != '=' && str[namesize] != NUL) { namesize++; } char *name = (char *)vim_strnsave((char_u *)str, namesize); return name; +#endif } /// Get the process ID of the Neovim process. @@ -404,7 +423,7 @@ void expand_env_esc(char_u *restrict srcp, var = NULL; } else { if (src[1] == '{') { - ++tail; + tail++; } #endif *var = NUL; diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 109ea6c487..7f2ebeec2f 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -1104,7 +1104,7 @@ char *os_resolve_shortcut(const char *fname) if (hr == S_OK && wsz[0] != NUL) { const int conversion_result = utf16_to_utf8(wsz, &rfname); if (conversion_result != 0) { - EMSG2("utf16_to_utf8 failed: %s", uv_strerror(conversion_result)); + EMSG2("utf16_to_utf8 failed: %d", conversion_result); } } diff --git a/src/nvim/search.c b/src/nvim/search.c index b09931b337..f6b80d1b79 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3687,11 +3687,12 @@ current_quote( int col_end; int col_start = curwin->w_cursor.col; bool inclusive = false; - int vis_empty = TRUE; /* Visual selection <= 1 char */ - int vis_bef_curs = FALSE; /* Visual starts before cursor */ - int inside_quotes = FALSE; /* Looks like "i'" done before */ - int selected_quote = FALSE; /* Has quote inside selection */ + int vis_empty = true; // Visual selection <= 1 char + int vis_bef_curs = false; // Visual starts before cursor + int inside_quotes = false; // Looks like "i'" done before + int selected_quote = false; // Has quote inside selection int i; + int restore_vis_bef = false; // resotre VIsual on abort // Correct cursor when 'selection' is "exclusive". if (VIsual_active) { @@ -3709,6 +3710,7 @@ current_quote( curwin->w_cursor = VIsual; VIsual = t; vis_bef_curs = true; + restore_vis_bef = true; } dec_cursor(); } @@ -3749,8 +3751,9 @@ current_quote( /* Assume we are on a closing quote: move to after the next * opening quote. */ col_start = find_next_quote(line, col_start + 1, quotechar, NULL); - if (col_start < 0) - return FALSE; + if (col_start < 0) { + goto abort_search; + } col_end = find_next_quote(line, col_start + 1, quotechar, curbuf->b_p_qe); if (col_end < 0) { @@ -3760,8 +3763,9 @@ current_quote( } } else { col_end = find_prev_quote(line, col_start, quotechar, NULL); - if (line[col_end] != quotechar) - return FALSE; + if (line[col_end] != quotechar) { + goto abort_search; + } col_start = find_prev_quote(line, col_end, quotechar, curbuf->b_p_qe); if (line[col_start] != quotechar) { @@ -3789,17 +3793,20 @@ current_quote( for (;; ) { /* Find open quote character. */ col_start = find_next_quote(line, col_start, quotechar, NULL); - if (col_start < 0 || col_start > first_col) - return FALSE; - /* Find close quote character. */ + if (col_start < 0 || col_start > first_col) { + goto abort_search; + } + // Find close quote character. col_end = find_next_quote(line, col_start + 1, quotechar, curbuf->b_p_qe); - if (col_end < 0) - return FALSE; - /* If is cursor between start and end quote character, it is - * target text object. */ - if (col_start <= first_col && first_col <= col_end) + if (col_end < 0) { + goto abort_search; + } + // If is cursor between start and end quote character, it is + // target text object. + if (col_start <= first_col && first_col <= col_end) { break; + } col_start = col_end + 1; } } else { @@ -3808,15 +3815,17 @@ current_quote( if (line[col_start] != quotechar) { /* No quote before the cursor, look after the cursor. */ col_start = find_next_quote(line, col_start, quotechar, NULL); - if (col_start < 0) - return FALSE; + if (col_start < 0) { + goto abort_search; + } } /* Find close quote character. */ col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) - return FALSE; + curbuf->b_p_qe); + if (col_end < 0) { + goto abort_search; + } } /* When "include" is TRUE, include spaces after closing quote or before @@ -3893,6 +3902,18 @@ current_quote( } return OK; + +abort_search: + if (VIsual_active && *p_sel == 'e') { + inc_cursor(); + if (restore_vis_bef) { + pos_T t = curwin->w_cursor; + + curwin->w_cursor = VIsual; + VIsual = t; + } + } + return false; } diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim index 6a2f5044cc..9194e0014d 100644 --- a/src/nvim/testdir/test_textobjects.vim +++ b/src/nvim/testdir/test_textobjects.vim @@ -52,6 +52,31 @@ func Test_quote_selection_selection_exclusive() bw! endfunc +func Test_quote_selection_selection_exclusive_abort() + new + set selection=exclusive + call setline(1, "'abzzc'") + let exp_curs = [0, 1, 6, 0] + call cursor(1,1) + exe 'norm! fcdvi"' + " make sure to end visual mode to have a clear state + exe "norm! \<esc>" + call assert_equal(exp_curs, getpos('.')) + call cursor(1,1) + exe 'norm! fcvi"' + exe "norm! \<esc>" + call assert_equal(exp_curs, getpos('.')) + call cursor(1,2) + exe 'norm! vfcoi"' + exe "norm! \<esc>" + let exp_curs = [0, 1, 2, 0] + let exp_visu = [0, 1, 7, 0] + call assert_equal(exp_curs, getpos('.')) + call assert_equal(exp_visu, getpos("'>")) + set selection&vim + bw! +endfunc + " Tests for string and html text objects func Test_string_html_objects() enew! diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index ffe71cfadf..7cd09fb222 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -171,19 +171,21 @@ end) describe('command line completion', function() local screen - before_each(function() - clear() screen = Screen.new(40, 5) - screen:attach() - screen:set_default_attr_ids({[1]={bold=true, foreground=Screen.colors.Blue}}) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow}, + [3] = {bold = true, reverse = true}, + }) end) - after_each(function() os.remove('Xtest-functional-viml-compl-dir') end) it('lists directories with empty PATH', function() + clear() + screen:attach() local tmp = funcs.tempname() command('e '.. tmp) command('cd %:h') @@ -198,6 +200,24 @@ describe('command line completion', function() :!Xtest-functional-viml-compl-dir^ | ]]) end) + + it('completes (multibyte) env var names #9655', function() + clear({env={ + ['XTEST_1AaあB']='foo', + ['XTEST_2']='bar', + }}) + screen:attach() + command('set wildmode=full') + command('set wildmenu') + feed(':!echo $XTEST_<tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {2:XTEST_1AaあB}{3: XTEST_2 }| + :!echo $XTEST_1AaあB^ | + ]]) + end) end) describe('ui/ext_wildmenu', function() |