Problem:
It's relatively easy to mispress key `a` to (a)llow arbitrary execution
of 'exrc' files. #35050
Solution:
- For exrc files (not directories), remove "allow" menu item.
Require the user to "view" and then explicitly `:trust` the file.
Problem: cannot easily trigger wildcard expansion
Solution: Introduce wildtrigger() function
(Girish Palya)
This PR introduces a new `wildtrigger()` function.
See `:h wildtrigger()`
`wildtrigger()` behaves like pressing the `wildchar,` but provides a
more refined and controlled completion experience:
- Suppresses beeps when no matches are found.
- Avoids displaying irrelevant completions (like full command lists)
when the prefix is insufficient or doesn't match.
- Skips completion if the typeahead buffer has pending input or if a
wildmenu is already active.
- Does not print "..." before completion.
This is an improvement on the `feedkeys()` based autocompletion script
given in vim/vim#16759.
closes: vim/vim#17806b486ed8266
While at it, also make Ctrl-Z trigger search completion.
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem:
- The VIM_VERSION_NODOT macro maintained support for legacy Vim
version-specific runtime directories (e.g., "vim82") which I believe
have never been relevant for Neovim
Solution:
- Remove it
- Rename `vim_version_dir()` to `vim_runtime_dir()`
Problem: not possible to anchor specific lines in diff mode
Solution: Add support for the anchoring lines in diff mode using the
'diffanchor' option (Yee Cheng Chin).
Adds support for anchoring specific lines to each other while viewing a
diff. While lines are anchored, they are guaranteed to be aligned to
each other in a diff view, allowing the user to control and inform the
diff algorithm what the desired alignment is. Internally, this is done
by splitting up the buffer at each anchor and run the diff algorithm on
each split section separately, and then merge the results back for a
logically consistent diff result.
To do this, add a new "diffanchors" option that takes a list of
`{address}`, and a new "diffopt" option value "anchor". Each address
specified will be an anchor, and the user can choose to use any type of
address, including marks, line numbers, or pattern search. Anchors are
sorted by line number in each file, and it's possible to have multiple
anchors on the same line (this is useful when doing multi-buffer diff).
Update documentation to provide examples.
This is similar to Git diff's `--anchored` flag. Other diff tools like
Meld/Araxis Merge also have similar features (called "synchronization
points" or "synchronization links"). We are not using Git/Xdiff's
`--anchored` implementation here because it has a very limited API
(it requires usage of the Patience algorithm, and can only anchor
unique lines that are the same across both files).
Because the user could anchor anywhere, diff anchors could result in
adjacent diff blocks (one block is directly touching another without a
gap), if there is a change right above the anchor point. We don't want
to merge these diff blocks because we want to line up the change at the
anchor. Adjacent diff blocks were first allowed when linematch was
added, but the existing code had a lot of branched paths where
line-matched diff blocks were handled differently. As a part of this
change, refactor them to have a more unified code path that is
generalized enough to handle adjacent diff blocks correctly and without
needing to carve in exceptions all over the place.
closes: vim/vim#176150d9160e11c
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
Problem:
Cannot use `nvim_open_term()` to pipe terminal scrollback > 100000
Solution:
Increase scrollback limit to 1000000
If there's no technical consequences of doing this, can be set even
higher in the future.
Problem:
Nvim depends on netrw to download/request URL contents.
Solution:
- Add `vim.net.request()` as a thin curl wrapper:
- Basic GET with --silent, --show-error, --fail, --location, --retry
- Optional `opts.outpath` to save to a file
- Operates asynchronously. Pass an `on_response` handler to get the result.
- Add integ tests (requires NVIM_TEST_INTEG to be set) to test success
and 404 failure.
- Health check for missing `curl`.
- Handle `:edit https://…` using `vim.net.request()`.
API Usage:
1. Asynchronous request:
vim.net.request('https://httpbingo.org/get', { retry = 2 }, function(err, response)
if err then
print('Fetch failed:', err)
else
print('Got body of length:', #response.body)
end
end)
2. Download to file:
vim.net.request('https://httpbingo.org/get', { outpath = 'out_async.txt' }, function(err)
if err then print('Error:', err) end
end)
3. Remote :edit integration (in runtime/plugin/net.lua) fetches into buffer:
:edit https://httpbingo.org/get
Problem: The maximum search count uses a hard-coded value of 99
(Andres Monge, Joschua Kesper)
Solution: Make it configurable using the 'maxsearchcount' option.
related: vim/vim#8855fixes: vim/vim#17527closes: vim/vim#17695b7b7fa04bf
Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit allows users to jump to the location specified in a
diagnostic's `relatedInformation`, using `gf` from within the
`open_float` window. The cursor need only be on line that displays the
related info.
Problem: winborder option only supported predefined styles and lacked support for custom border characters.
Solution: implement parsing for comma-separated list format that allows specifying 8 individual border characters (topleft, top, topright, right, botright, bottom, botleft, left).
Many terminals now include support for OSC 52 in their Primary Device
Attributes (DA1) response. This is preferable to using XTGETTCAP because
DA1 is _much_ more broadly supported.
Problem: Unable to tell whether msg_history_show event is emitted for a
:messages or g< command.
Solution: Add "prev_cmd" argument that is set to true for g<.
Problem:
Closes#31453
Solution:
Introduce `vim.lsp.Capability`, which may serve as the base class for
all LSP features that require caching data. it
- was created if there is at least one client that supports the specific method;
- was destroyed if all clients that support the method were detached.
- Apply the refactor for `folding_range.lua` and `semantic_tokens.lua`.
- Show active features in :checkhealth.
Future:
I found that these features that are expected to be refactored by
`vim.lsp.Capability` have one characteristic in common: they all send
LSP requests once the document is modified. The following code is
different, but they are all for this purpose.
- semantic tokens:
fb8dba413f/runtime/lua/vim/lsp/semantic_tokens.lua (L192-L198)
- inlay hints, folding ranges, document color
fb8dba413f/runtime/lua/vim/lsp/inlay_hint.lua (L250-L266)
I think I can sum up this characteristic as the need to keep certain
data synchronized with the latest version computed by the server.
I believe we can handle this at the `vim.lsp.Capability` level, and
I think it will be very useful.
Therefore, my next step is to implement LSP request sending and data
synchronization on `vim.lsp.Capability`, rather than limiting it to the
current create/destroy data approach.
Problem: Patch 9.1.1505 was not good
Solution: Revert "patch 9.1.1505: not possible to return completion type
for :ex command" and instead add the getcompletiontype()
function (Hirohito Higashi).
related: vim/vim#17606closes: vim/vim#1766296b3ef2389
Cherry-pick Test_multibyte_expression() from Vim, as it passes.
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Problem: 'wildchar' does not work in search contexts
Solution: implement search completion when 'wildchar' is typed
(Girish Palya).
This change enhances Vim's command-line completion by extending
'wildmode' behavior to search pattern contexts, including:
- '/' and '?' search commands
- ':s', ':g', ':v', and ':vim' commands
Completions preserve the exact regex pattern typed by the user,
appending the completed word directly to the original input. This
ensures that all regex elements — such as '<', '^', grouping brackets
'()', wildcards '\*', '.', and other special characters — remain intact
and in their original positions.
---
**Use Case**
While searching (using `/` or `?`) for lines containing a pattern like
`"foobar"`, you can now type a partial pattern (e.g., `/f`) followed by
a trigger key (`wildchar`) to open a **popup completion menu** showing
all matching words.
This offers two key benefits:
1. **Precision**: Select the exact word you're looking for without
typing it fully.
2. **Memory aid**: When you can’t recall a full function or variable
name, typing a few letters helps you visually identify and complete the
correct symbol.
---
**What’s New**
Completion is now supported in the following contexts:
- `/` and `?` search commands
- `:s`, `:g`, `:v`, and `:vimgrep` ex-commands
---
**Design Notes**
- While `'wildchar'` (usually `<Tab>`) triggers completion, you'll have
to use `<CTRL-V><Tab>` or "\t" to search for a literal tab.
- **Responsiveness**: Search remains responsive because it checks for
user input frequently.
---
**Try It Out**
Basic setup using the default `<Tab>` as the completion trigger:
```vim
set wim=noselect,full wop=pum wmnu
```
Now type:
```
/foo<Tab>
```
This opens a completion popup for matches containing "foo".
For matches beginning with "foo" type `/\<foo<Tab>`.
---
**Optional: Autocompletion**
For automatic popup menu completion as you type in search or `:`
commands, include this in your `.vimrc`:
```vim
vim9script
set wim=noselect:lastused,full wop=pum wcm=<C-@> wmnu
autocmd CmdlineChanged [:/?] CmdComplete()
def CmdComplete()
var [cmdline, curpos, cmdmode] = [getcmdline(), getcmdpos(),
expand('<afile>') == ':']
var trigger_char = '\%(\w\|[*/:.-]\)$'
var not_trigger_char = '^\%(\d\|,\|+\|-\)\+$' # Exclude numeric range
if getchar(1, {number: true}) == 0 # Typehead is empty, no more
pasted input
&& !wildmenumode() && curpos == cmdline->len() + 1
&& (!cmdmode || (cmdline =~ trigger_char && cmdline !~
not_trigger_char))
SkipCmdlineChanged()
feedkeys("\<C-@>", "t")
timer_start(0, (_) => getcmdline()->substitute('\%x00', '',
'ge')->setcmdline()) # Remove <C-@>
endif
enddef
def SkipCmdlineChanged(key = ''): string
set ei+=CmdlineChanged
timer_start(0, (_) => execute('set ei-=CmdlineChanged'))
return key == '' ? '' : ((wildmenumode() ? "\<C-E>" : '') .. key)
enddef
**Optional: Preserve history recall behavior**
cnoremap <expr> <Up> SkipCmdlineChanged("\<Up>")
cnoremap <expr> <Down> SkipCmdlineChanged("\<Down>")
**Optional: Customize popup height**
autocmd CmdlineEnter : set bo+=error | exec $'set ph={max([10,
winheight(0) - 4])}'
autocmd CmdlineEnter [/?] set bo+=error | set ph=8
autocmd CmdlineLeave [:/?] set bo-=error ph&
```
closes: vim/vim#175706b49fba8c8
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: no easy way to deduplicate text
Solution: add the :uniq ex command
(Hirohito Higashi)
closes: vim/vim#1753874f0a77bb9
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Make `vim.iter():take()` and `vim.iter():skip()`
optionally accept predicates to enable takewhile
and skipwhile patterns used in functional
programming.
Problem: No way to compute intersection of two version ranges, which is
useful when computing version range that fits inside several reference
ranges.
Solution: Add `vim.version.intersect()`.
Problem: `tostring()` applied to version range doesn't return
human-readable text with information about the range.
Solution: Add `__tostring()` method.
Problem: ext_messages cannot tell when the screen was cleared, which is
needed to clear visible messages. An empty message is also
never emitted, but clears messages from the message grid.
Solution: Repurpose the "msg_clear" event to be emitted when the screen
was cleared. Emit an empty message with the `empty` kind to
hint to a UI to clear the cmdline area.
Problem: ext_messages is implemented to mimic the message grid
implementation w.r.t. scrolling messages, clearing scrolled
messages, hit-enter-prompts and replacing a previous message.
Meanwhile, an ext_messages UI may not be implemented in a way
where these events are wanted. Moreover, correctness of these
events even assuming a "scrolled message" implementation
depends on fragile "currently visible messages" global state,
which already isn't correct after a previous message was
supposed to have been overwritten (because that should not only
happen when `msg_scroll == false`).
Solution: - No longer attempt to keep track of the currently visible
messages: remove the `msg_ext(_history)_visible` variables.
UIs may remove messages pre-emptively (timer based), or never
show messages that don't fit a certain area in the first place.
- No longer emit the `msg(_history)_clear` events to clear
"scrolled" messages. This opens up the `msg_clear` event to
be emitted when messages should actually be cleared (e.g.
when the screen is cleared). May also be useful to emit before
the first message in an event loop cycle as a hint to the UI
that it is a new batch of messages (vim._extui currently
schedules an event to determine that).
- Set `replace_last` explicitly at the few callsites that want
this to be set to true to replace an incomplete status message.
- Don't store a "keep" message to be re-emitted.
Problem:
Not easy to get user-input in prompt-buffer before the user submits the
input. Under the current system user/plugin needs to read the buffer
contents, figure out where the prompt is, then extract the text.
Solution:
- Add prompt_getinput().
- Extract prompt text extraction logic to a separate function
Problem:
In LSP configs, the function form of `cmd()` cannot easily get the
resolved root dir (workspace). One of the main use-cases of a dynamic
`cmd()` is to be able to start a new server whose binary may be located
*in the workspace* ([example](https://github.com/neovim/nvim-lspconfig/pull/3912)).
Compare `reuse_client()`, which also receives the resolved config.
Solution:
Pass the resolved config to `cmd()`.
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
This commit changes the `offset!` directive so that instead of setting a
`metadata.range` value for the entire pattern, it will set a
`metadata.offset` value. This offset will be applied to the range only
in `vim.treesitter.get_range()`, rather than at directive application
time. This allows the offset to be applied to any and all nodes captured
by the given pattern, and removes the requirement that `#offset!` be
applied to only a single node.
The downside of this change is that plugins which read from
`metadata.range` may be thrown off course, but such plugins should
prefer `vim.treesitter.get_range()` when retrieving ranges anyway.
Note that `#trim!` still sets `metadata.range`, and
`vim.treesitter.get_range()` still reads from `metadata.range`, if it
exists.