diff options
-rw-r--r-- | runtime/doc/starting.txt | 3 | ||||
-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/testdir/test_help.vim | 36 | ||||
-rw-r--r-- | src/nvim/testdir/test_help_tagjump.vim | 28 |
7 files changed, 138 insertions, 50 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index c9ce2b9dc1..3440131642 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -76,7 +76,8 @@ The option arguments may be given in any order. Single-letter options can be combined after one dash. There can be no option arguments after the "--" argument. ---help *-h* *--help* +--help *-h* *--help* *-?* +-? -h Give usage (help) message and exit. See |info-message| about capturing the text. 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/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\*') |