Problem:
`vim.filetype.match()` needs a cheap way to recognize directory buffers
without doing filesystem stat work.
Solution:
Ensure full buffer names for directories end in a trailing slash. Now
directory buffers can proceed through the normal 'filetype' path.
Note side-effects: session and ShaDa buffer-list restore behavior must
be compatible, so those + corresponding tests must be updated.
Problem:
`vim.fs` does not provide a directory creation helper matching its
filesystem API shape.
Solution:
Add `vim.fs.mkdir()` as a thin wrapper around `vim.fn.mkdir()`, with
`parents` and `mode` options.
Problem:
Session files specified at startup `-S [file]`, logically conflict
with `:restart`.
Solution:
Remove `-S [file]` from `v:argv` when doing :restart.
Also for the "bang" variant `:restart!`, just because it's
simpler (if anyone reports a use-case later, we can revisit).
Problem:
Inlay hints used separate global and per-buffer bufstates tables and
bespoke global autocmds for managing the inlay hint state across buffers
and clients, duplicating the lifecycle logic already provided by the
Capability framework. This caused inconsistencies in how client state
was handled and inlay hint state lifecycle was managed compared to other
LSP features.
Solution:
Replace the ad-hoc bufstate tracking and global autocmds in
vim.lsp.inlay_hint with a proper InlayHint subclass of Capability.
This also refactors the way inlay hint state is managed and fixes bugs I
found while doing this:
1. For each line with inlay hints, the list of the hints along with
whether they have been applied is stored in a current result on the
client state. This allows the on_win decorator to clear all inlay
hints for an old document version once, and then re-add the new
version's hints line-by-line as they are drawn to the screen,
modeling the semantic tokens module.
2. It fixes problems with mixing results from multiple clients attached
to the buffer by fully moving each client's state to its own table.
Previously, only the most recent document version used to populate a
line's inlay hints was stored, but there was no distinction for which
client the hints may have come from. (Fixes#36318)
3. It fixes the workspace/inlayHint/refresh server->client notification
behavior. Previously it would only re-request inlay hints for buffers
currently displayed in a window but would not invalidate them in
non-displayed buffers (or provide any mechanism for those buffers to
re-request at a later time). Model semantic token module here again
by invalidating all buffers, and adding a BufWinEnter autocmd to
refresh hints.
4. Add a mechanism to cancel in-flight requests if a new request for a
newer document version is made before the last one returned
5. Handle stale results by simply dropping them.
Ref #6645
Problem:
When a window is resized it takes space from the window right/below first,
and only falls back to the window left/above when there is no more room.
Sometimes a user wants the space to come from a specific direction.
Solution:
Add nvim_win_resize(win, width, height, {anchor}) which resizes a window
with a choosable anchor edge, letting a window grow leftwards or upwards
by taking space from the window to the left or above first. The default
anchor reproduces nvim_win_set_width()/nvim_win_set_height().
Problem:
`vim.lsp.buf.format()` accepts ranges using nvim indexing, where an
end column of -1 means end of line. LSP ranges cannot use that,
which is confusing for things like range formatting.
Solution:
Resolve -1 end columns to the line length before converting the range to
LSP positions.
Problem:
Plugins using RPC sockets cannot detect when the peer closes a
`sockconnect()` channel, so reconnect logic has no reliable trigger.
Solution:
Add a `ChanClose` event with channel info before the channel is removed,
matching the existing `ChanOpen`/`ChanInfo` event model.
Problem:
`request()` and `notify()` are methods of the object returned by
`vim.lsp.rpc.start()`/`connect()`, but were rendered with module-level
helptags (`vim.lsp.rpc.request()`, `vim.lsp.rpc.notify()`) (erroneously
implying module functions that do not exist).
Solution:
Mark the wrappers `@private` and describe them on `vim.lsp.rpc.Client` instead.
Problem:
The dir.lua "-" mapping cannot be easily overridden (because of autocmd
ordering).
Solution:
- Move it to defaults.lua.
- Also to be extra polite: fall back to builtin `-` motion if the user
disabled the `dir.lua` plugin.
Problem: the pos argument in ListOps for lsp is an optional parameter,
but the lua_ls typing system doesn't reflect that
Solution: let pos be optional
Co-authored-by: nikolightsaber <nikolightsaber@gmail.com>
- Move whitespace formatting settings from the indent to the filetype
plugin behind a "typst_recommended_style" config option.
- Set browsefilter
- Improve syntax file
Thanks to Maxim Kim for taking on maintainership of the typst runtime
files.
related: vim/vim#20036
closes: vim/vim#20077dd8975428b
Co-authored-by: Doug Kearns <dougkearns@gmail.com>
Co-authored-by: Maxim Kim <habamax@gmail.com>
Problem:
Redundant code.
Solution:
Add path_skip_sep() and use it.
Dropping MB_PTR_ADV is safe: the loops only advance while `*p` is
a one-byte separator (`/`, `\`, `:`). MB_PTR_ADV was needed in legacy
Vim because it supported non-UTF-8 (DBCS) *internal* encodings.
Problem:
On Windows, `fnamemodify('//foo/C$', ':h')` incorrectly removes `C$`
as a regular file name and returns `//foo`. However, this is a valid
UNC path, `foo` is a server name and `C$` is a share name.
The correct result should be `//foo/C$`.
Solution:
Extend `os_fileinfo2` and `FileInfo` with `prefix_off`, `rest_off` to
identify path types and logical root boundaries. ':h' can use this info
to prevent traversing past the logical root.
Examples:
/foo => /
//foo => // (POSIX)
//foo/bar => //foo (POSIX)
//server/share/foo => //server/share/ (Windows)
C:/foo => C:/
//?/C:/foo => //?/C:/
Co-authored-by: Barrett Ruth <br@barrettruth.com>
Problem:
vim.fs.dir() and vim.fs.find() drop errors returned by uv.fs_scandir().
Solution:
- vim.fs.dir():
- Return root scan failures as a secondary return value.
- Propagate recursive scan failures through the iterator. This allows
callers to distinguish unreadable directories from empty ones.
- vim.fs.find(): Collect errors during search, and return the list as
a second retval.
Problem:
- If cmdwin window is split, ENTER in one does not close the others.
- If cmdwin is put into a different tabpage via <c-w>T, it stops working
(ENTER does not execute the cmd).
Solution:
- Close the buffer instead of the window.
- In the WinClosed handler, skip `M._cleanup()` unless this is the last
cmdwin window.
The system version of ConPTY in kernel32.dll is old and will
mangle some VT sequences sent by shells. Newer versions of ConPTY
available as part of the Windows Terminal project fix this by
passing through VT sequences unmodified when the terminal has set
ENABLE_VIRTUAL_TERMINAL_INPUT. This change allows users to fix
buggy behaviour of Neovim's terminal on Windows by copying
conpty.dll to Neovim's bin directory.
Co-authored-by: Scott Young <s@sjy.au>
Problem:
`:restart` does not preserve window layout, etc.
Solution:
- Change `:restart` to save/restore a session automatically.
- Introduce "bang" variant `:restart!` to restart *without* session
save/restore.
- Introduce `v:startreason`.
- `ZR` maps to `:restart!`.
Problem:
`nvim_set_option_value` cannot "update" options similar to `:set opt=`,
`:set opt+=`, etc. The Lua impls of "vim.opt" / "vim.o" have incomplete,
bespoke reimplementations of those operations.
ref #38420
Solution:
- Add `operation` param to `nvim_set_option_value`, which may be "set",
"append", "prepend", or "remove".
- Use this feature to implement `vim.opt` / `vim.o`.
Problem: due to totally async install/update/checkout there is no
guaranteed order of `PackChanged{Pre,}` events across different
plugins. This might lead to conflicts when callback for some "main"
plugin relies on features from "dependency" plugin: i.e. callback for
"main" plugin can trigger before installing/updating "dependency"
plugin. The installation order can be enforced by separate
vim.pack.add() calls, but update/checkout can not.
Solution: Trigger events in bulk independently of async execution:
- `PackChangedPre` before any action for all input plugins in order
they are supplied. It will also trigger even if an action will fail.
- `PackChanged` after all actions finished for all sucessfully
affected plugins in order they are supplied.
This also comes with a couple of side effect changes:
- `PackChangedPre kind=delete` is now also triggered even if the
delete won't be done. This makes it more aligned with `kind=install`
and `kind=update`.
- Force update (`:packupdate!`) and "udpate LSP action" now do two
async steps: download/compute updates and apply them. This also
results in two progress reports.
This is mostly a by-product of the implementation (there has to be
a pre-computation of target revision for all plugins before doing
`PackChangedPre` in bulk before possibly applying an update), but I
kind of like it more this way as it is more explicit of what's going
on. If absolutely not acceptable, there might be some hacks to
mitigate it at least in code action, but I'd keep it like this.
Problem:
dir.lua leaves previously-navigated directory buffers around.
This is fine by default, but users need a simple way to opt out.
Solution:
1. Respect `set hidden` (via `'bufhidden'`) as one way to make
previously-navigated dir buffers from showing up.
2. Document a one-liner to hide these buffers
Problem: Separation markers (%=) are ignored within item groups. This
lead to a regression when the C implementation of the statusline was
replaced with a default expression. When the user configured a custom
ruler expression with a %= and used the overloaded item group syntax to
set the ruler width, the separation marker worked in the ruler, but not
when the ruler was incorporated into the statusline where the item group
syntax was interpreted in the usual way.
Solution: Analogously to top-level behaviour, expand separation markers
evenly within item groups until `minwid` is reached (if set).
ref https://github.com/neovim/neovim/pull/33036
fix https://github.com/neovim/neovim/issues/39984
ref https://github.com/neovim/neovim/issues/40247
Problem: The recursion offset into the static `stl_items` was not taken
into account when adjusting the item count after truncation.
Steps to reproduce: first prepare `stl_items`:
set stl=%{%repeat('%#Error#',10)%}
then watch how the Error highlight leaks into the recursive call:
set stl=%l%l%l%{%nvim_eval_statusline('test%l%<',{'maxwidth':3,'highlights':1}).highlights%}
ref https://github.com/neovim/neovim/issues/32259
* fix(statusline): consistent truncation at multicell character
Problem 1: truncation of item groups at multicell character didn't take
into account that minwid can be specified as a negative number.
Problem 2: after truncation at top-level from the right at multicell
character, the returned width was always `maxwidth`, even though the
actual width was reduced. In vim, this can be observed as a statusline
that is not fully drawn until the edge of the screen:
vim --clean +"set ls=2 stl=%{%repeat('x',&columns-2)%}🙂x%<"
Problem 3: after truncation at top-level from the left at multicell
character, the resulting gap to reach `maxwidth` again was filled with
fillchars, but then the final NUL was not set correctly.
This can be seen in the following example, where the statuscolumn spills
into the editing area starting from line 10:
nvim --clean +"set number stc=%<x🙂%{repeat('x',43)}%l" +"norm yy10p"
Solution: fix the small errors and, at top-level, consistently reduce
the size instead of compensating with fillchars. In the case of the
statusline and the winbar, the remaining place is filled with the
configured fillchars in `win_redr_custom`, after `build_stl_str_hl` has
returned. In all other cases (title, icon, statuscol, tabline, ruler),
there seems to be no point in adding additional spaces at the end.
* feat(statusline)!: scope %< to item groups
Problem:
Previously, item groups were only truncated at the beginning, which is
often not desired. In the example
%.15(path: %f%)
the group's title/label is truncated away:
<th/to/file.txt
Truncation markers (%<) in item groups were processed at the top-level
in the end, which can be confusing. Only the first %< is used for the
whole string, and it is used even if the containing item group is
hidden. Additionally, in the case of hidden item groups, the marker's
position was not adapted. For example,
%(hidden%<%)%f
had the effect of truncating the path somewhere in the middle:
/path/<file.txt
Solution:
Make truncation consistent with top-level behaviour, which has a better
default of truncating at the first `Normal` item, i.e.
path: <file.txt
and allows for fine-grained control with truncation markers (%<). E.g.
%.15(path: %f%<%)
now yields
path: /path/to>
The original behaviour can be restored like so:
%.15(%<path: %f%)
BREAKING CHANGE: %< is no longer processed at top-level
- the default truncation behaviour has changed: now at first item
- truncation markers inside item groups don't affect truncation outside
of the item group anymore
- several truncation markers can now have an effect when separated with
item groups, whereas previously only the first one globally had
ref https://github.com/neovim/neovim/issues/39984
Problem:
cmd given as string[] always starts using Nvim's CWD, which is arbitrary.
Solution:
If cmd_cwd is not given, use root_dir as CWD.
BREAKING CHANGE: LSP commands given as string arrays now use `root_dir` as
the process working directory when `cmd_cwd` is unset.
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
`:edit <dir>` and `nvim <dir>` currently rely on netrw to show local directory
contents.
Solution:
- Provide `filetype=directory`.
- Introduce dir.lua, a small plugin that provides directory listing, opening
items, parent navigation, and refresh.
- `netrw` remains available for `:Explore`, remote paths, archives, and file
operations. To continue
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
cmdwin (the `:q` cmdline buffer) has various limitations which require
special-casing all over the codebase.
Besides complicating the code, it also breaks async plugins if they try
to create buffers/windows after some work is done, if the user happens
to open cmdwin at the wrong the moment:
Lua callback: …/guh.nvim/lua/guh/util.lua:531:
E11: Invalid in command-line window; <CR> executes, CTRL-C quits
stack traceback:
[C]: in function 'nvim_buf_delete'
…/guh.nvim/lua/guh/util.lua:531: in function <…/guh.nvim/lua/guh/util.lua:526>
Solution:
Just say no to "inception". Reimplement cmdwin as a normal buffer+window.
All of the cmdwin contortions (in both core, and innocent plugins) exist
literally only to support "inception": recursive
cmdwin-in-cmdline-things, like `<c-r>=`, `/`, search-during-substitute,
`:input()`, etc. So we just won't support that (though I have
a potential plan for that later, which I call "modal parking lot").
The benefit is that plugins, and core, no longer have to care about
cmdwin.
BONUS:
- mouse-drag on vertical separators works (it only worked for
horizontal/statusline before)
- inccommand-in-cmdwin now works correctly, for free (thus don't need
#40077).
POTENTIAL FOLLOWUPS
- Drop `CHECK_CMDWIN` ("E11: Invalid in command-line window"), allow chaos.
- Unify `BUFLOCK_OK` / `LOCK_OK` ?
DESIGN:
- Eliminate lots of C globals, `EX_CMDWIN`, etc.
- `text_locked()` no longer reports true for cmdwin.
- cmdwin = a normal window with 'winfixbuf', 'bufhidden=wipe',
'buftype=nofile'. Invariants come from those options rather than
special cases throughout the codebase.
- `nv_record` for q:/q//q? calls Lua
`nlua_call_vimfn("vim._core.cmdwin", …)`. No `K_CMDWIN`
/ cmdline-reader detour.
- `cedit_key` (`c_CTRL-F`) schedules a deferred event that calls
`vim._core.cmdwin.open(type, content, pos)` and returns `Ctrl_C` so
the in-flight cmdline cancels. Reader state is not serialized; instead
the captured `(type, line, col)` is replayed via
`nvim_feedkeys(type..line.."<CR>", "nt", …)` after user confirms.
- On confirm/cancel: `<CR>` / `<C-C>` calls into Lua which closes the
window and re-feeds the cmdline.
BREAKING CHANGES:
- Expression-register cmdline (`<C-R>=` from insert-mode) no longer
supports cmdwin. Same applies to `input()` / `inputlist()` (already
covered by `text_locked`).
- Usage of cmdwin in macros/mappings will probably break (assuming they
ever worked).
Problem: Attach-time terminal probes cannot distinguish responses from
different attached UIs.
Solution: Identify the UI by RPC channel id in `TermResponse` and make
`vim.tty.request()` filter responses by channel.
Problem: ':delete #' silently fails to update "# and clobbers "0.
Solution: Treat "# like "/, writable only with :let and setreg().
closes: vim/vim#205927aeab74687
Co-authored-by: Doug Kearns <dougkearns@gmail.com>