aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lua.txt284
-rw-r--r--runtime/doc/treesitter.txt295
-rw-r--r--src/nvim/ex_getln.c34
-rw-r--r--src/nvim/testdir/test_autocmd.vim31
-rw-r--r--src/nvim/testdir/test_gf.vim27
-rw-r--r--src/nvim/testdir/test_search.vim18
-rw-r--r--src/nvim/window.c6
7 files changed, 398 insertions, 297 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 477e70a9ae..2b638a8539 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -551,290 +551,6 @@ Example: TCP echo-server *tcp-server*
print('TCP echo-server listening on port: '..server:getsockname().port)
------------------------------------------------------------------------------
-VIM.TREESITTER *lua-treesitter*
-
-Nvim integrates the tree-sitter library for incremental parsing of buffers.
-
-Currently Nvim does not provide the tree-sitter parsers, instead these must
-be built separately, for instance using the tree-sitter utility. The only
-exception is a C parser being included in official builds for testing
-purposes. Parsers are searched for as `parser/{lang}.*` in any 'runtimepath'
-directory. A parser can also be loaded manually using a full path: >
-
- vim.treesitter.require_language("python", "/path/to/python.so")
-
-<Create a parser for a buffer and a given language (if another plugin uses the
-same buffer/language combination, it will be safely reused). Use >
-
- parser = vim.treesitter.get_parser(bufnr, lang)
-
-<`bufnr=0` can be used for current buffer. `lang` will default to 'filetype' (this
-doesn't work yet for some filetypes like "cpp") Currently, the parser will be
-retained for the lifetime of a buffer but this is subject to change. A plugin
-should keep a reference to the parser object as long as it wants incremental
-updates.
-
-Parser files *treesitter-parsers*
-
-Parsers are the heart of tree-sitter. They are libraries that tree-sitter will
-search for in the `parser` runtime directory.
-
-For a parser to be available for a given language, there must be a file named
-`{lang}.so` within the parser directory.
-
-Parser methods *lua-treesitter-parser*
-
-tsparser:parse() *tsparser:parse()*
-Whenever you need to access the current syntax tree, parse the buffer: >
-
- tstree = parser:parse()
-
-<This will return an immutable tree that represents the current state of the
-buffer. When the plugin wants to access the state after a (possible) edit
-it should call `parse()` again. If the buffer wasn't edited, the same tree will
-be returned again without extra work. If the buffer was parsed before,
-incremental parsing will be done of the changed parts.
-
-NB: to use the parser directly inside a |nvim_buf_attach| Lua callback, you must
-call `get_parser()` before you register your callback. But preferably parsing
-shouldn't be done directly in the change callback anyway as they will be very
-frequent. Rather a plugin that does any kind of analysis on a tree should use
-a timer to throttle too frequent updates.
-
-tsparser:set_included_ranges({ranges}) *tsparser:set_included_ranges()*
- Changes the ranges the parser should consider. This is used for
- language injection. {ranges} should be of the form (all zero-based): >
- {
- {start_node, end_node},
- ...
- }
-<
- NOTE: `start_node` and `end_node` are both inclusive.
-
-Tree methods *lua-treesitter-tree*
-
-tstree:root() *tstree:root()*
- Return the root node of this tree.
-
-
-Node methods *lua-treesitter-node*
-
-tsnode:parent() *tsnode:parent()*
- Get the node's immediate parent.
-
-tsnode:iter_children() *tsnode:iter_children()*
- Iterates over all the direct children of {tsnode}, regardless of
- wether they are named or not.
- Returns the child node plus the eventual field name corresponding to
- this child node.
-
-tsnode:field({name}) *tsnode:field()*
- Returns a table of the nodes corresponding to the {name} field.
-
-tsnode:child_count() *tsnode:child_count()*
- Get the node's number of children.
-
-tsnode:child({index}) *tsnode:child()*
- Get the node's child at the given {index}, where zero represents the
- first child.
-
-tsnode:named_child_count() *tsnode:named_child_count()*
- Get the node's number of named children.
-
-tsnode:named_child({index}) *tsnode:named_child()*
- Get the node's named child at the given {index}, where zero represents
- the first named child.
-
-tsnode:start() *tsnode:start()*
- Get the node's start position. Return three values: the row, column
- and total byte count (all zero-based).
-
-tsnode:end_() *tsnode:end_()*
- Get the node's end position. Return three values: the row, column
- and total byte count (all zero-based).
-
-tsnode:range() *tsnode:range()*
- Get the range of the node. Return four values: the row, column
- of the start position, then the row, column of the end position.
-
-tsnode:type() *tsnode:type()*
- Get the node's type as a string.
-
-tsnode:symbol() *tsnode:symbol()*
- Get the node's type as a numerical id.
-
-tsnode:named() *tsnode:named()*
- Check if the node is named. Named nodes correspond to named rules in
- the grammar, whereas anonymous nodes correspond to string literals
- in the grammar.
-
-tsnode:missing() *tsnode:missing()*
- Check if the node is missing. Missing nodes are inserted by the
- parser in order to recover from certain kinds of syntax errors.
-
-tsnode:has_error() *tsnode:has_error()*
- Check if the node is a syntax error or contains any syntax errors.
-
-tsnode:sexpr() *tsnode:sexpr()*
- Get an S-expression representing the node as a string.
-
-tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
- *tsnode:descendant_for_range()*
- Get the smallest node within this node that spans the given range of
- (row, column) positions
-
-tsnode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
- *tsnode:named_descendant_for_range()*
- Get the smallest named node within this node that spans the given
- range of (row, column) positions
-
-Query methods *lua-treesitter-query*
-
-Tree-sitter queries are supported, with some limitations. Currently, the only
-supported match predicate is `eq?` (both comparing a capture against a string
-and two captures against each other).
-
-vim.treesitter.parse_query({lang}, {query})
- *vim.treesitter.parse_query()*
- Parse {query} as a string. (If the query is in a file, the caller
- should read the contents into a string before calling).
-
-query:iter_captures({node}, {bufnr}, {start_row}, {end_row})
- *query:iter_captures()*
- Iterate over all captures from all matches inside {node}.
- {bufnr} is needed if the query contains predicates, then the caller
- must ensure to use a freshly parsed tree consistent with the current
- text of the buffer. {start_row} and {end_row} can be used to limit
- matches inside a row range (this is typically used with root node
- as the node, i e to get syntax highlight matches in the current
- viewport)
-
- The iterator returns two values, a numeric id identifying the capture
- and the captured node. The following example shows how to get captures
- by name:
->
- for id, node in query:iter_captures(tree:root(), bufnr, first, last) do
- local name = query.captures[id] -- name of the capture in the query
- -- typically useful info about the node:
- local type = node:type() -- type of the captured node
- local row1, col1, row2, col2 = node:range() -- range of the capture
- ... use the info here ...
- end
-<
-query:iter_matches({node}, {bufnr}, {start_row}, {end_row})
- *query:iter_matches()*
- Iterate over all matches within a node. The arguments are the same as
- for |query:iter_captures()| but the iterated values are different:
- an (1-based) index of the pattern in the query, and a table mapping
- capture indices to nodes. If the query has more than one pattern
- the capture table might be sparse, and e.g. `pairs` should be used and not
- `ipairs`. Here an example iterating over all captures in
- every match:
->
- for pattern, match in cquery:iter_matches(tree:root(), bufnr, first, last) do
- for id,node in pairs(match) do
- local name = query.captures[id]
- -- `node` was captured by the `name` capture in the match
- ... use the info here ...
- end
- end
-
-Treesitter Query Predicates *lua-treesitter-predicates*
-
-When writing queries for treesitter, one might use `predicates`, that is,
-special scheme nodes that are evaluted to verify things on a captured node for
-example, the |eq?| predicate : >
- ((identifier) @foo (#eq? @foo "foo"))
-
-This will only match identifier corresponding to the `"foo"` text.
-Here is a list of built-in predicates :
-
- `eq?` *ts-predicate-eq?*
- This predicate will check text correspondance between nodes or
- strings : >
- ((identifier) @foo (#eq? @foo "foo"))
- ((node1) @left (node2) @right (#eq? @left @right))
-<
- `match?` *ts-predicate-match?*
- `vim-match?` *ts-predicate-vim-match?*
- This will match if the provived vim regex matches the text
- corresponding to a node : >
- ((idenfitier) @constant (#match? @constant "^[A-Z_]+$"))
-< Note: the `^` and `$` anchors will respectively match the
- start and end of the node's text.
-
- `lua-match?` *ts-predicate-lua-match?*
- This will match the same way than |match?| but using lua
- regexes.
-
- `contains?` *ts-predicate-contains?*
- Will check if any of the following arguments appears in the
- text corresponding to the node : >
- ((identifier) @foo (#contains? @foo "foo"))
- ((identifier) @foo-bar (#contains @foo-bar "foo" "bar"))
-<
- *lua-treesitter-not-predicate*
-Each predicate has a `not-` prefixed predicate that is just the negation of
-the predicate.
-
- *vim.treesitter.query.add_predicate()*
-vim.treesitter.query.add_predicate({name}, {handler})
-
-This adds a predicate with the name {name} to be used in queries.
-{handler} should be a function whose signature will be : >
- handler(match, pattern, bufnr, predicate)
-<
- *vim.treesitter.query.list_predicates()*
-vim.treesitter.query.list_predicates()
-
-This lists the currently available predicates to use in queries.
-
-Treesitter syntax highlighting (WIP) *lua-treesitter-highlight*
-
-NOTE: This is a partially implemented feature, and not usable as a default
-solution yet. What is documented here is a temporary interface indented
-for those who want to experiment with this feature and contribute to
-its development.
-
-Highlights are defined in the same query format as in the tree-sitter highlight
-crate, which some limitations and additions. Set a highlight query for a
-buffer with this code: >
-
- local query = [[
- "for" @keyword
- "if" @keyword
- "return" @keyword
-
- (string_literal) @string
- (number_literal) @number
- (comment) @comment
-
- (preproc_function_def name: (identifier) @function)
-
- ; ... more definitions
- ]]
-
- highlighter = vim.treesitter.TSHighlighter.new(query, bufnr, lang)
- -- alternatively, to use the current buffer and its filetype:
- -- highlighter = vim.treesitter.TSHighlighter.new(query)
-
- -- Don't recreate the highlighter for the same buffer, instead
- -- modify the query like this:
- local query2 = [[ ... ]]
- highlighter:set_query(query2)
-
-As mentioned above the supported predicate is currently only `eq?`. `match?`
-predicates behave like matching always fails. As an addition a capture which
-begin with an upper-case letter like `@WarningMsg` will map directly to this
-highlight group, if defined. Also if the predicate begins with upper-case and
-contains a dot only the part before the first will be interpreted as the
-highlight group. As an example, this warns of a binary expression with two
-identical identifiers, highlighting both as |hl-WarningMsg|: >
-
- ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right)
- (eq? @WarningMsg.left @WarningMsg.right))
-
-------------------------------------------------------------------------------
VIM.HIGHLIGHT *lua-highlight*
Nvim includes a function for highlighting a selection on yank (see for example
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
new file mode 100644
index 0000000000..7f644486f7
--- /dev/null
+++ b/runtime/doc/treesitter.txt
@@ -0,0 +1,295 @@
+*treesitter.txt* Nvim
+
+
+ NVIM REFERENCE MANUAL
+
+
+Tree-sitter integration *treesitter*
+
+ Type |gO| to see the table of contents.
+
+------------------------------------------------------------------------------
+VIM.TREESITTER *lua-treesitter*
+
+Nvim integrates the tree-sitter library for incremental parsing of buffers.
+
+Currently Nvim does not provide the tree-sitter parsers, instead these must
+be built separately, for instance using the tree-sitter utility. The only
+exception is a C parser being included in official builds for testing
+purposes. Parsers are searched for as `parser/{lang}.*` in any 'runtimepath'
+directory. A parser can also be loaded manually using a full path: >
+
+ vim.treesitter.require_language("python", "/path/to/python.so")
+
+<Create a parser for a buffer and a given language (if another plugin uses the
+same buffer/language combination, it will be safely reused). Use >
+
+ parser = vim.treesitter.get_parser(bufnr, lang)
+
+<`bufnr=0` can be used for current buffer. `lang` will default to 'filetype' (this
+doesn't work yet for some filetypes like "cpp") Currently, the parser will be
+retained for the lifetime of a buffer but this is subject to change. A plugin
+should keep a reference to the parser object as long as it wants incremental
+updates.
+
+Parser files *treesitter-parsers*
+
+Parsers are the heart of tree-sitter. They are libraries that tree-sitter will
+search for in the `parser` runtime directory.
+
+For a parser to be available for a given language, there must be a file named
+`{lang}.so` within the parser directory.
+
+Parser methods *lua-treesitter-parser*
+
+tsparser:parse() *tsparser:parse()*
+Whenever you need to access the current syntax tree, parse the buffer: >
+
+ tstree = parser:parse()
+
+<This will return an immutable tree that represents the current state of the
+buffer. When the plugin wants to access the state after a (possible) edit
+it should call `parse()` again. If the buffer wasn't edited, the same tree will
+be returned again without extra work. If the buffer was parsed before,
+incremental parsing will be done of the changed parts.
+
+NB: to use the parser directly inside a |nvim_buf_attach| Lua callback, you must
+call `get_parser()` before you register your callback. But preferably parsing
+shouldn't be done directly in the change callback anyway as they will be very
+frequent. Rather a plugin that does any kind of analysis on a tree should use
+a timer to throttle too frequent updates.
+
+tsparser:set_included_ranges({ranges}) *tsparser:set_included_ranges()*
+ Changes the ranges the parser should consider. This is used for
+ language injection. {ranges} should be of the form (all zero-based): >
+ {
+ {start_node, end_node},
+ ...
+ }
+<
+ NOTE: `start_node` and `end_node` are both inclusive.
+
+Tree methods *lua-treesitter-tree*
+
+tstree:root() *tstree:root()*
+ Return the root node of this tree.
+
+
+Node methods *lua-treesitter-node*
+
+tsnode:parent() *tsnode:parent()*
+ Get the node's immediate parent.
+
+tsnode:iter_children() *tsnode:iter_children()*
+ Iterates over all the direct children of {tsnode}, regardless of
+ wether they are named or not.
+ Returns the child node plus the eventual field name corresponding to
+ this child node.
+
+tsnode:field({name}) *tsnode:field()*
+ Returns a table of the nodes corresponding to the {name} field.
+
+tsnode:child_count() *tsnode:child_count()*
+ Get the node's number of children.
+
+tsnode:child({index}) *tsnode:child()*
+ Get the node's child at the given {index}, where zero represents the
+ first child.
+
+tsnode:named_child_count() *tsnode:named_child_count()*
+ Get the node's number of named children.
+
+tsnode:named_child({index}) *tsnode:named_child()*
+ Get the node's named child at the given {index}, where zero represents
+ the first named child.
+
+tsnode:start() *tsnode:start()*
+ Get the node's start position. Return three values: the row, column
+ and total byte count (all zero-based).
+
+tsnode:end_() *tsnode:end_()*
+ Get the node's end position. Return three values: the row, column
+ and total byte count (all zero-based).
+
+tsnode:range() *tsnode:range()*
+ Get the range of the node. Return four values: the row, column
+ of the start position, then the row, column of the end position.
+
+tsnode:type() *tsnode:type()*
+ Get the node's type as a string.
+
+tsnode:symbol() *tsnode:symbol()*
+ Get the node's type as a numerical id.
+
+tsnode:named() *tsnode:named()*
+ Check if the node is named. Named nodes correspond to named rules in
+ the grammar, whereas anonymous nodes correspond to string literals
+ in the grammar.
+
+tsnode:missing() *tsnode:missing()*
+ Check if the node is missing. Missing nodes are inserted by the
+ parser in order to recover from certain kinds of syntax errors.
+
+tsnode:has_error() *tsnode:has_error()*
+ Check if the node is a syntax error or contains any syntax errors.
+
+tsnode:sexpr() *tsnode:sexpr()*
+ Get an S-expression representing the node as a string.
+
+tsnode:descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
+ *tsnode:descendant_for_range()*
+ Get the smallest node within this node that spans the given range of
+ (row, column) positions
+
+tsnode:named_descendant_for_range({start_row}, {start_col}, {end_row}, {end_col})
+ *tsnode:named_descendant_for_range()*
+ Get the smallest named node within this node that spans the given
+ range of (row, column) positions
+
+Query methods *lua-treesitter-query*
+
+Tree-sitter queries are supported, with some limitations. Currently, the only
+supported match predicate is `eq?` (both comparing a capture against a string
+and two captures against each other).
+
+vim.treesitter.parse_query({lang}, {query})
+ *vim.treesitter.parse_query()*
+ Parse {query} as a string. (If the query is in a file, the caller
+ should read the contents into a string before calling).
+
+query:iter_captures({node}, {bufnr}, {start_row}, {end_row})
+ *query:iter_captures()*
+ Iterate over all captures from all matches inside {node}.
+ {bufnr} is needed if the query contains predicates, then the caller
+ must ensure to use a freshly parsed tree consistent with the current
+ text of the buffer. {start_row} and {end_row} can be used to limit
+ matches inside a row range (this is typically used with root node
+ as the node, i e to get syntax highlight matches in the current
+ viewport)
+
+ The iterator returns two values, a numeric id identifying the capture
+ and the captured node. The following example shows how to get captures
+ by name:
+>
+ for id, node in query:iter_captures(tree:root(), bufnr, first, last) do
+ local name = query.captures[id] -- name of the capture in the query
+ -- typically useful info about the node:
+ local type = node:type() -- type of the captured node
+ local row1, col1, row2, col2 = node:range() -- range of the capture
+ ... use the info here ...
+ end
+<
+query:iter_matches({node}, {bufnr}, {start_row}, {end_row})
+ *query:iter_matches()*
+ Iterate over all matches within a node. The arguments are the same as
+ for |query:iter_captures()| but the iterated values are different:
+ an (1-based) index of the pattern in the query, and a table mapping
+ capture indices to nodes. If the query has more than one pattern
+ the capture table might be sparse, and e.g. `pairs` should be used and not
+ `ipairs`. Here an example iterating over all captures in
+ every match:
+>
+ for pattern, match in cquery:iter_matches(tree:root(), bufnr, first, last) do
+ for id,node in pairs(match) do
+ local name = query.captures[id]
+ -- `node` was captured by the `name` capture in the match
+ ... use the info here ...
+ end
+ end
+
+Treesitter Query Predicates *lua-treesitter-predicates*
+
+When writing queries for treesitter, one might use `predicates`, that is,
+special scheme nodes that are evaluted to verify things on a captured node for
+example, the |eq?| predicate : >
+ ((identifier) @foo (#eq? @foo "foo"))
+
+This will only match identifier corresponding to the `"foo"` text.
+Here is a list of built-in predicates :
+
+ `eq?` *ts-predicate-eq?*
+ This predicate will check text correspondance between nodes or
+ strings : >
+ ((identifier) @foo (#eq? @foo "foo"))
+ ((node1) @left (node2) @right (#eq? @left @right))
+<
+ `match?` *ts-predicate-match?*
+ `vim-match?` *ts-predicate-vim-match?*
+ This will match if the provived vim regex matches the text
+ corresponding to a node : >
+ ((idenfitier) @constant (#match? @constant "^[A-Z_]+$"))
+< Note: the `^` and `$` anchors will respectively match the
+ start and end of the node's text.
+
+ `lua-match?` *ts-predicate-lua-match?*
+ This will match the same way than |match?| but using lua
+ regexes.
+
+ `contains?` *ts-predicate-contains?*
+ Will check if any of the following arguments appears in the
+ text corresponding to the node : >
+ ((identifier) @foo (#contains? @foo "foo"))
+ ((identifier) @foo-bar (#contains @foo-bar "foo" "bar"))
+<
+ *lua-treesitter-not-predicate*
+Each predicate has a `not-` prefixed predicate that is just the negation of
+the predicate.
+
+ *vim.treesitter.query.add_predicate()*
+vim.treesitter.query.add_predicate({name}, {handler})
+
+This adds a predicate with the name {name} to be used in queries.
+{handler} should be a function whose signature will be : >
+ handler(match, pattern, bufnr, predicate)
+<
+ *vim.treesitter.query.list_predicates()*
+vim.treesitter.query.list_predicates()
+
+This lists the currently available predicates to use in queries.
+
+Treesitter syntax highlighting (WIP) *lua-treesitter-highlight*
+
+NOTE: This is a partially implemented feature, and not usable as a default
+solution yet. What is documented here is a temporary interface indented
+for those who want to experiment with this feature and contribute to
+its development.
+
+Highlights are defined in the same query format as in the tree-sitter highlight
+crate, which some limitations and additions. Set a highlight query for a
+buffer with this code: >
+
+ local query = [[
+ "for" @keyword
+ "if" @keyword
+ "return" @keyword
+
+ (string_literal) @string
+ (number_literal) @number
+ (comment) @comment
+
+ (preproc_function_def name: (identifier) @function)
+
+ ; ... more definitions
+ ]]
+
+ highlighter = vim.treesitter.TSHighlighter.new(query, bufnr, lang)
+ -- alternatively, to use the current buffer and its filetype:
+ -- highlighter = vim.treesitter.TSHighlighter.new(query)
+
+ -- Don't recreate the highlighter for the same buffer, instead
+ -- modify the query like this:
+ local query2 = [[ ... ]]
+ highlighter:set_query(query2)
+
+As mentioned above the supported predicate is currently only `eq?`. `match?`
+predicates behave like matching always fails. As an addition a capture which
+begin with an upper-case letter like `@WarningMsg` will map directly to this
+highlight group, if defined. Also if the predicate begins with upper-case and
+contains a dot only the part before the first will be interpreted as the
+highlight group. As an example, this warns of a binary expression with two
+identical identifiers, highlighting both as |hl-WarningMsg|: >
+
+ ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right)
+ (eq? @WarningMsg.left @WarningMsg.right))
+
+ vim:tw=78:ts=8:ft=help:norl:
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 8f2d536e63..f9ca7bfa42 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -288,6 +288,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
exarg_T ea;
pos_T save_cursor;
bool use_last_pat;
+ bool retval = false;
*skiplen = 0;
*patlen = ccline.cmdlen;
@@ -307,6 +308,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
return false;
}
+ emsg_off++;
memset(&ea, 0, sizeof(ea));
ea.line1 = 1;
ea.line2 = 1;
@@ -318,13 +320,13 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
cmd = skip_range(ea.cmd, NULL);
if (vim_strchr((char_u *)"sgvl", *cmd) == NULL) {
- return false;
+ goto theend;
}
// Skip over "substitute" to find the pattern separator.
for (p = cmd; ASCII_ISALPHA(*p); p++) {}
if (*skipwhite(p) == NUL) {
- return false;
+ goto theend;
}
if (STRNCMP(cmd, "substitute", p - cmd) == 0
@@ -337,12 +339,15 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
p_magic = false;
}
} else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) {
- // skip over flags.
+ // skip over ! and flags
+ if (*p == '!') {
+ p = skipwhite(p + 1);
+ }
while (ASCII_ISALPHA(*(p = skipwhite(p)))) {
p++;
}
if (*p == NUL) {
- return false;
+ goto theend;
}
} else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0
|| STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0
@@ -353,14 +358,14 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
if (*p == '!') {
p++;
if (*skipwhite(p) == NUL) {
- return false;
+ goto theend;
}
}
if (*cmd != 'g') {
delim_optional = true;
}
} else {
- return false;
+ goto theend;
}
p = skipwhite(p);
@@ -369,7 +374,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
use_last_pat = end == p && *end == delim;
if (end == p && !use_last_pat) {
- return false;
+ goto theend;
}
// Don't do 'hlsearch' highlighting if the pattern matches everything.
@@ -381,7 +386,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
empty = empty_pattern(p);
*end = c;
if (empty) {
- return false;
+ goto theend;
}
}
@@ -409,7 +414,10 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s,
}
curwin->w_cursor = save_cursor;
- return true;
+ retval = true;
+theend:
+ emsg_off--;
+ return retval;
}
// May do 'incsearch' highlighting if desired.
@@ -549,6 +557,7 @@ static void may_do_incsearch_highlighting(int firstc, long count,
}
update_screen(SOME_VALID);
+ highlight_match = false;
restore_last_search_pattern();
// Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the
@@ -1541,6 +1550,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count,
highlight_match = true;
save_viewstate(&s->old_viewstate);
update_screen(NOT_VALID);
+ highlight_match = false;
redrawcmdline();
curwin->w_cursor = s->match_end;
} else {
@@ -6463,12 +6473,15 @@ static int open_cmdwin(void)
// Save the command line info, can be used recursively.
save_cmdline(&save_ccline);
- /* No Ex mode here! */
+ // No Ex mode here!
exmode_active = 0;
State = NORMAL;
setmouse();
+ // Reset here so it can be set by a CmdWinEnter autocommand.
+ cmdwin_result = 0;
+
// Trigger CmdwinEnter autocommands.
typestr[0] = (char_u)cmdwin_type;
typestr[1] = NUL;
@@ -6484,7 +6497,6 @@ static int open_cmdwin(void)
/*
* Call the main loop until <CR> or CTRL-C is typed.
*/
- cmdwin_result = 0;
normal_enter(true, false);
RedrawingDisabled = i;
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 3dd68873d4..094bb3ebd1 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1,6 +1,8 @@
" Tests for autocommands
source shared.vim
+source check.vim
+source term_util.vim
func! s:cleanup_buffers() abort
for bnr in range(1, bufnr('$'))
@@ -1735,6 +1737,35 @@ func Test_throw_in_BufWritePre()
au! throwing
endfunc
+func Test_autocmd_CmdWinEnter()
+ CheckRunVimInTerminal
+ " There is not cmdwin switch, so
+ " test for cmdline_hist
+ " (both are available with small builds)
+ CheckFeature cmdline_hist
+ let lines =<< trim END
+ let b:dummy_var = 'This is a dummy'
+ autocmd CmdWinEnter * quit
+ let winnr = winnr('$')
+ END
+ let filename='XCmdWinEnter'
+ call writefile(lines, filename)
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 6})
+
+ call term_sendkeys(buf, "q:")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":echo b:dummy_var\<cr>")
+ call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, ":echo &buftype\<cr>")
+ call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, ":echo winnr\<cr>")
+ call WaitForAssert({-> assert_match('^1', term_getline(buf, 6))}, 1000)
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete(filename)
+endfunc
+
func Test_FileChangedShell_reload()
if !has('unix')
return
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index 4a4ffcefa1..ee548037ba 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -1,3 +1,4 @@
+" Test for the gf and gF (goto file) commands
" This is a test if a URL is recognized by "gf", with the cursor before and
" after the "://". Also test ":\\".
@@ -109,7 +110,7 @@ func Test_gf()
endfunc
func Test_gf_visual()
- call writefile([], "Xtest_gf_visual")
+ call writefile(['one', 'two', 'three', 'four'], "Xtest_gf_visual")
new
call setline(1, 'XXXtest_gf_visualXXX')
set hidden
@@ -118,6 +119,30 @@ func Test_gf_visual()
norm! ttvtXgf
call assert_equal('Xtest_gf_visual', bufname('%'))
+ " if multiple lines are selected, then gf should fail
+ call setline(1, ["one", "two"])
+ normal VGgf
+ call assert_equal('Xtest_gf_visual', @%)
+
+ " following line number is used for gF
+ bwipe!
+ new
+ call setline(1, 'XXXtest_gf_visual:3XXX')
+ norm! 0ttvt:gF
+ call assert_equal('Xtest_gf_visual', bufname('%'))
+ call assert_equal(3, getcurpos()[1])
+
+ " line number in visual area is used for file name
+ if has('unix')
+ bwipe!
+ call writefile([], "Xtest_gf_visual:3")
+ new
+ call setline(1, 'XXXtest_gf_visual:3XXX')
+ norm! 0ttvtXgF
+ call assert_equal('Xtest_gf_visual:3', bufname('%'))
+ call delete('Xtest_gf_visual:3')
+ endif
+
bwipe!
call delete('Xtest_gf_visual')
set hidden&
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index e3a0fce5a6..211fc73562 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -708,6 +708,19 @@ func Test_incsearch_substitute_dump()
call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {})
call term_sendkeys(buf, "\<Esc>")
call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {})
+ call term_sendkeys(buf, ":%bwipe!\<CR>")
+ call term_sendkeys(buf, ":only!\<CR>")
+
+ " get :'<,'>s command in history
+ call term_sendkeys(buf, ":set cmdheight=2\<CR>")
+ call term_sendkeys(buf, "aasdfasdf\<Esc>")
+ call term_sendkeys(buf, "V:s/a/b/g\<CR>")
+ " Using '<,'> does not give E20
+ call term_sendkeys(buf, ":new\<CR>")
+ call term_sendkeys(buf, "aasdfasdf\<Esc>")
+ call term_sendkeys(buf, ":\<Up>\<Up>")
+ call VerifyScreenDump(buf, 'Test_incsearch_substitute_14', {})
+ call term_sendkeys(buf, "<Esc>")
call StopVimInTerminal(buf)
call delete('Xis_subst_script')
@@ -730,11 +743,14 @@ func Test_incsearch_sort_dump()
" the 'ambiwidth' check.
sleep 100m
- " Need to send one key at a time to force a redraw.
call term_sendkeys(buf, ':sort ni u /on')
call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
call term_sendkeys(buf, "\<Esc>")
+ call term_sendkeys(buf, ':sort! /on')
+ call VerifyScreenDump(buf, 'Test_incsearch_sort_02', {})
+ call term_sendkeys(buf, "\<Esc>")
+
call StopVimInTerminal(buf)
call delete('Xis_sort_script')
endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index cec0dfd67f..6608deb231 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6019,6 +6019,12 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
char_u *ptr;
if (get_visual_text(NULL, &ptr, &len) == FAIL)
return NULL;
+ // Only recognize ":123" here
+ if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) {
+ char_u *p = ptr + len + 1;
+
+ *file_lnum = getdigits_long(&p, false, 0);
+ }
return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname);
}
return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);