diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/private/dispatch.c | 3 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 47 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 8 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 114 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/main.c | 1 | ||||
-rw-r--r-- | src/nvim/normal.c | 4 | ||||
-rw-r--r-- | src/nvim/screen.c | 21 | ||||
-rw-r--r-- | src/nvim/testdir/test_help.vim | 36 | ||||
-rw-r--r-- | src/nvim/testdir/test_help_tagjump.vim | 28 | ||||
-rw-r--r-- | src/nvim/testdir/test_hlsearch.vim | 14 |
11 files changed, 180 insertions, 98 deletions
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index dec2b6c185..c08225bbfc 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -40,7 +40,8 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, map_get(String, MsgpackRpcRequestHandler)(methods, m); if (!rv.fn) { - api_set_error(error, kErrorTypeException, "Invalid method: %s", + api_set_error(error, kErrorTypeException, "Invalid method: %.*s", + m.size > 0 ? m.size : sizeof("<empty>"), m.size > 0 ? m.data : "<empty>"); } return rv; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f3e883de02..ecc0ede4a4 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -162,7 +162,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err) dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size); if (di == NULL) { - api_set_error(err, kErrorTypeValidation, "Key '%s' not found", key.data); + api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data); return (Object)OBJECT_INIT; } @@ -191,13 +191,12 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, } if (key.size == 0) { - api_set_error(err, kErrorTypeValidation, - "Empty variable names aren't allowed"); + api_set_error(err, kErrorTypeValidation, "Key name is empty"); return rv; } if (key.size > INT_MAX) { - api_set_error(err, kErrorTypeValidation, "Key length is too high"); + api_set_error(err, kErrorTypeValidation, "Key name is too long"); return rv; } @@ -220,7 +219,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, // Delete the key if (di == NULL) { // Doesn't exist, fail - api_set_error(err, kErrorTypeValidation, "Key does not exist: %s", + api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data); } else { // Return the old value @@ -284,9 +283,7 @@ Object get_option_from(void *from, int type, String name, Error *err) type, from); if (!flags) { - api_set_error(err, - kErrorTypeValidation, - "Invalid option name \"%s\"", + api_set_error(err, kErrorTypeValidation, "Invalid option name: '%s'", name.data); return rv; } @@ -303,15 +300,14 @@ Object get_option_from(void *from, int type, String name, Error *err) rv.data.string.data = stringval; rv.data.string.size = strlen(stringval); } else { - api_set_error(err, - kErrorTypeException, - "Unable to get value for option \"%s\"", + api_set_error(err, kErrorTypeException, + "Failed to get value for option '%s'", name.data); } } else { api_set_error(err, kErrorTypeException, - "Unknown type for option \"%s\"", + "Unknown type for option '%s'", name.data); } @@ -336,24 +332,20 @@ void set_option_to(uint64_t channel_id, void *to, int type, int flags = get_option_value_strict(name.data, NULL, NULL, type, to); if (flags == 0) { - api_set_error(err, - kErrorTypeValidation, - "Invalid option name \"%s\"", + api_set_error(err, kErrorTypeValidation, "Invalid option name '%s'", name.data); return; } if (value.type == kObjectTypeNil) { if (type == SREQ_GLOBAL) { - api_set_error(err, - kErrorTypeException, - "Unable to unset option \"%s\"", + api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", name.data); return; } else if (!(flags & SOPT_GLOBAL)) { api_set_error(err, kErrorTypeException, - "Cannot unset option \"%s\" " + "Cannot unset option '%s' " "because it doesn't have a global value", name.data); return; @@ -370,7 +362,7 @@ void set_option_to(uint64_t channel_id, void *to, int type, if (value.type != kObjectTypeBoolean) { api_set_error(err, kErrorTypeValidation, - "Option \"%s\" requires a boolean value", + "Option '%s' requires a Boolean value", name.data); return; } @@ -378,17 +370,15 @@ void set_option_to(uint64_t channel_id, void *to, int type, numval = value.data.boolean; } else if (flags & SOPT_NUM) { if (value.type != kObjectTypeInteger) { - api_set_error(err, - kErrorTypeValidation, - "Option \"%s\" requires an integer value", + api_set_error(err, kErrorTypeValidation, + "Option '%s' requires an integer value", name.data); return; } if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - api_set_error(err, - kErrorTypeValidation, - "Value for option \"%s\" is outside range", + api_set_error(err, kErrorTypeValidation, + "Value for option '%s' is out of range", name.data); return; } @@ -396,9 +386,8 @@ void set_option_to(uint64_t channel_id, void *to, int type, numval = (int)value.data.integer; } else { if (value.type != kObjectTypeString) { - api_set_error(err, - kErrorTypeValidation, - "Option \"%s\" requires a string value", + api_set_error(err, kErrorTypeValidation, + "Option '%s' requires a string value", name.data); return; } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e78b8c776d..fed20a272a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -502,7 +502,7 @@ Integer nvim_strwidth(String text, Error *err) FUNC_API_SINCE(1) { if (text.size > INT_MAX) { - api_set_error(err, kErrorTypeValidation, "String length is too high"); + api_set_error(err, kErrorTypeValidation, "String is too long"); return 0; } @@ -559,7 +559,7 @@ void nvim_set_current_dir(String dir, Error *err) FUNC_API_SINCE(1) { if (dir.size >= MAXPATHL) { - api_set_error(err, kErrorTypeValidation, "Directory string is too long"); + api_set_error(err, kErrorTypeValidation, "Directory name is too long"); return; } @@ -1136,14 +1136,14 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) if (calls.items[i].type != kObjectTypeArray) { api_set_error(err, kErrorTypeValidation, - "All items in calls array must be arrays"); + "Items in calls array must be arrays"); goto validation_error; } Array call = calls.items[i].data.array; if (call.size != 2) { api_set_error(err, kErrorTypeValidation, - "All items in calls array must be arrays of size 2"); + "Items in calls array must be arrays of size 2"); goto validation_error; } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index ca975ee02a..a9e9364dc3 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -4675,49 +4675,66 @@ static int help_compare(const void *s1, const void *s2) return strcmp(p1, p2); } -/* - * Find all help tags matching "arg", sort them and return in matches[], with - * the number of matches in num_matches. - * The matches will be sorted with a "best" match algorithm. - * When "keep_lang" is TRUE try keeping the language of the current buffer. - */ -int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_lang) +// Find all help tags matching "arg", sort them and return in matches[], with +// the number of matches in num_matches. +// The matches will be sorted with a "best" match algorithm. +// When "keep_lang" is true try keeping the language of the current buffer. +int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, + bool keep_lang) { - char_u *s, *d; int i; - static char *(mtable[]) = {"*", "g*", "[*", "]*", - "/*", "/\\*", "\"*", "**", - "/\\(\\)", "/\\%(\\)", - "?", ":?", "?<CR>", "g?", "g?g?", "g??", - "/\\?", "/\\z(\\)", "\\=", ":s\\=", - "[count]", "[quotex]", - "[range]", ":[range]", - "[pattern]", "\\|", "\\%$", - "s/\\~", "s/\\U", "s/\\L", - "s/\\1", "s/\\2", "s/\\3", "s/\\9"}; - static char *(rtable[]) = {"star", "gstar", "[star", "]star", - "/star", "/\\\\star", "quotestar", "starstar", - "/\\\\(\\\\)", "/\\\\%(\\\\)", - "?", ":?", "?<CR>", "g?", "g?g?", "g??", - "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=", - "\\[count]", "\\[quotex]", - "\\[range]", ":\\[range]", - "\\[pattern]", "\\\\bar", "/\\\\%\\$", - "s/\\\\\\~", "s/\\\\U", "s/\\\\L", - "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"}; - int flags; - - d = IObuff; /* assume IObuff is long enough! */ - - /* - * Recognize a few exceptions to the rule. Some strings that contain '*' - * with "star". Otherwise '*' is recognized as a wildcard. - */ - for (i = (int)ARRAY_SIZE(mtable); --i >= 0; ) - if (STRCMP(arg, mtable[i]) == 0) { - STRCPY(d, rtable[i]); - break; + static const char *(mtable[]) = { + "*", "g*", "[*", "]*", + "/*", "/\\*", "\"*", "**", + "/\\(\\)", "/\\%(\\)", + "?", ":?", "?<CR>", "g?", "g?g?", "g??", + "-?", "q?", "v_g?", + "/\\?", "/\\z(\\)", "\\=", ":s\\=", + "[count]", "[quotex]", + "[range]", ":[range]", + "[pattern]", "\\|", "\\%$", + "s/\\~", "s/\\U", "s/\\L", + "s/\\1", "s/\\2", "s/\\3", "s/\\9" + }; + static const char *(rtable[]) = { + "star", "gstar", "[star", "]star", + "/star", "/\\\\star", "quotestar", "starstar", + "/\\\\(\\\\)", "/\\\\%(\\\\)", + "?", ":?", "?<CR>", "g?", "g?g?", "g??", + "-?", "q?", "v_g?", + "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=", + "\\[count]", "\\[quotex]", + "\\[range]", ":\\[range]", + "\\[pattern]", "\\\\bar", "/\\\\%\\$", + "s/\\\\\\~", "s/\\\\U", "s/\\\\L", + "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9" + }; + static const char *(expr_table[]) = { + "!=?", "!~?", "<=?", "<?", "==?", "=~?", + ">=?", ">?", "is?", "isnot?" + }; + char_u *d = IObuff; // assume IObuff is long enough! + + if (STRNICMP(arg, "expr-", 5) == 0) { + // When the string starting with "expr-" and containing '?' and matches + // the table, it is taken literally. Otherwise '?' is recognized as a + // wildcard. + for (i = (int)ARRAY_SIZE(expr_table); --i >= 0; ) { + if (STRCMP(arg + 5, expr_table[i]) == 0) { + STRCPY(d, arg); + break; + } + } + } else { + // Recognize a few exceptions to the rule. Some strings that contain + // '*' with "star". Otherwise '*' is recognized as a wildcard. + for (i = (int)ARRAY_SIZE(mtable); --i >= 0; ) { + if (STRCMP(arg, mtable[i]) == 0) { + STRCPY(d, rtable[i]); + break; + } } + } if (i < 0) { /* no match in table */ /* Replace "\S" with "/\\S", etc. Otherwise every tag is matched. @@ -4749,7 +4766,7 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la if (*arg == '(' && arg[1] == '\'') { arg++; } - for (s = arg; *s; s++) { + for (const char_u *s = arg; *s; s++) { // Replace "|" with "bar" and '"' with "quote" to match the name of // the tags for these commands. // Replace "*" with ".*" and "?" with "." to match command line @@ -4858,9 +4875,10 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la *matches = (char_u **)""; *num_matches = 0; - flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE; - if (keep_lang) + int flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE; + if (keep_lang) { flags |= TAG_KEEP_LANG; + } if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK && *num_matches > 0) { /* Sort the matches found on the heuristic number that is after the @@ -5017,11 +5035,9 @@ void fix_help_buffer(void) const char_u *const f1 = fnames[i1]; const char_u *const f2 = fnames[i2]; const char_u *const t1 = path_tail(f1); - if (fnamencmp(f1, f2, t1 - f1) != 0) { - continue; - } + const char_u *const t2 = path_tail(f2); const char_u *const e1 = STRRCHR(t1, '.'); - const char_u *const e2 = STRRCHR(path_tail(f2), '.'); + const char_u *const e2 = STRRCHR(t2, '.'); if (e1 == NULL || e2 == NULL) { continue; } @@ -5032,8 +5048,10 @@ void fix_help_buffer(void) fnames[i1] = NULL; continue; } - if (fnamencmp(f1, f2, e1 - f1) != 0) + if (e1 - f1 != e2 - f2 + || fnamencmp(f1, f2, e1 - f1) != 0) { continue; + } if (fnamecmp(e1, ".txt") == 0 && fnamecmp(e2, fname + 4) == 0) { /* use .abx instead of .txt */ diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 786e2cd12c..ff625d6dc9 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4677,7 +4677,7 @@ ExpandFromContext ( /* With an empty argument we would get all the help tags, which is * very slow. Get matches for "help" instead. */ if (find_help_tags(*pat == NUL ? (char_u *)"help" : pat, - num_file, file, FALSE) == OK) { + num_file, file, false) == OK) { cleanup_help_tags(*num_file, *file); return OK; } diff --git a/src/nvim/main.c b/src/nvim/main.c index af7c194edc..ab8b33aa12 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -892,6 +892,7 @@ static void command_line_scan(mparm_T *parmp) set_option_value("rl", 1L, NULL, 0); break; } + case '?': // "-?" give help message (for MS-Windows) case 'h': { // "-h" give help message usage(); mch_exit(0); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 0bf93ee001..09444ace0f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -4771,6 +4771,10 @@ static void nv_ident(cmdarg_T *cap) assert(*kp != NUL); // option.c:do_set() should default to ":help" if empty. bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command bool kp_help = (STRCMP(kp, ":he") == 0 || STRCMP(kp, ":help") == 0); + if (kp_help && *skipwhite(ptr) == NUL) { + EMSG(_(e_noident)); // found white space only + return; + } size_t buf_size = n * 2 + 30 + STRLEN(kp); char *buf = xmalloc(buf_size); buf[0] = NUL; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 91840026a5..884fef69d1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3912,23 +3912,16 @@ win_line ( } } - /* - * At end of the text line. - */ + // + // At end of the text line. + // if (c == NUL) { - if (eol_hl_off > 0 && vcol - eol_hl_off == (long)wp->w_virtcol - && lnum == wp->w_cursor.lnum) { - /* highlight last char after line */ - --col; - --off; - --vcol; - } - - /* Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. */ - if (wp->w_p_wrap) + // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. + if (wp->w_p_wrap) { v = wp->w_skipcol; - else + } else { v = wp->w_leftcol; + } /* check if line ends before left margin */ if (vcol < v + col - win_col_off(wp)) diff --git a/src/nvim/testdir/test_help.vim b/src/nvim/testdir/test_help.vim index 26edc16107..ed3181564c 100644 --- a/src/nvim/testdir/test_help.vim +++ b/src/nvim/testdir/test_help.vim @@ -13,4 +13,40 @@ endfunc func Test_help_errors() call assert_fails('help doesnotexist', 'E149:') call assert_fails('help!', 'E478:') + + new + set keywordprg=:help + call setline(1, " ") + call assert_fails('normal VK', 'E349:') + bwipe! +endfunc + +func Test_help_keyword() + new + set keywordprg=:help + call setline(1, " Visual ") + normal VK + call assert_match('^Visual mode', getline('.')) + call assert_equal('help', &ft) + close + bwipe! +endfunc + +func Test_help_local_additions() + call mkdir('Xruntime/doc', 'p') + call writefile(['*mydoc.txt* my awesome doc'], 'Xruntime/doc/mydoc.txt') + call writefile(['*mydoc-ext.txt* my extended awesome doc'], 'Xruntime/doc/mydoc-ext.txt') + let rtp_save = &rtp + set rtp+=./Xruntime + help + 1 + call search('mydoc.txt') + call assert_equal('|mydoc.txt| my awesome doc', getline('.')) + 1 + call search('mydoc-ext.txt') + call assert_equal('|mydoc-ext.txt| my extended awesome doc', getline('.')) + close + + call delete('Xruntime', 'rf') + let &rtp = rtp_save endfunc diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim index 4d4a902031..c873487b92 100644 --- a/src/nvim/testdir/test_help_tagjump.vim +++ b/src/nvim/testdir/test_help_tagjump.vim @@ -38,6 +38,34 @@ func Test_help_tagjump() call assert_true(getline('.') =~ '\*:?\*') helpclose + help q? + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*q?\*') + call assert_true(expand('<cword>') == 'q?') + helpclose + + help -? + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*-?\*') + helpclose + + help v_g? + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*v_g?\*') + helpclose + + help expr-!=? + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*expr-!=?\*') + call assert_true(expand('<cword>') == 'expr-!=?') + helpclose + + help expr-isnot? + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*expr-isnot?\*') + call assert_true(expand('<cword>') == 'expr-isnot?') + helpclose + help FileW*Post call assert_equal("help", &filetype) call assert_true(getline('.') =~ '\*FileWritePost\*') diff --git a/src/nvim/testdir/test_hlsearch.vim b/src/nvim/testdir/test_hlsearch.vim index 066fdd0250..1fc7b04f88 100644 --- a/src/nvim/testdir/test_hlsearch.vim +++ b/src/nvim/testdir/test_hlsearch.vim @@ -4,7 +4,6 @@ function! Test_hlsearch() new call setline(1, repeat(['aaa'], 10)) set hlsearch nolazyredraw - let r=[] " redraw is needed to make hlsearch highlight the matches exe "normal! /aaa\<CR>" | redraw let r1 = screenattr(1, 1) @@ -32,3 +31,16 @@ function! Test_hlsearch() call getchar(1) enew! endfunction + +func Test_hlsearch_eol_highlight() + new + call append(1, repeat([''], 9)) + set hlsearch nolazyredraw + exe "normal! /$\<CR>" | redraw + let attr = screenattr(1, 1) + for row in range(2, 10) + call assert_equal(attr, screenattr(row, 1), 'in line ' . row) + endfor + set nohlsearch + bwipe! +endfunc |