Problem:
Buffer-local CWD (:bcd) is "sticky", similar to window-local CWD (:lcd).
But this contradicts one of its main benefits: per-buffer "project root"
for LSP, OSC7.
Other problems:
- A buffer created with :edit/:enew/:new silently inherits b_localdir
(and b_prevdir) from the previous buffer.
- curbuf_reusable() refuses to recycle a scratch buffer that has
`b_localdir`.
- After :new/:vnew/:tabnew the CWD sticks to previous buffer's
`b_localdir` even though the new curbuf has none, so :new is not
equivalent to ":split | enew", and getcwd() disagrees with
haslocaldir().
- Requires "which buffer spawned this buffer" semantics that no other
buffer-local state has.
Solution:
Drop sticky/inherit behavior of buffer-local CWD (:bcd).
- do_ecmd: always apply the new curbuf's dir (`fix_current_dir`), like
`do_autochdir` already does. :tabnew from a :bcd buffer now reverts to
global CWD (and fires DirChanged), same as :tabnew from a :lcd window.
- curbuf_reusable(): recycling a scratch buffer frees its b_localdir.
To get sticky/inherit behavior of CWD, use `:lcd`.
Problem:
No way to set a buffer-local directory.
Use-cases:
- "Root dir" for LSP (and the "project" concept).
- `:terminal` OSC 7
Solution:
Add `:bcd` command.
- Extend `getcwd()` to take a third arg; `getcwd(-1, -1, bunfr)` returns
the buffer-local working directory.
- Buffer-local directories have less priority than window-local
ones, and more priority than tab-local ones.
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
Ignore is linked to Normal by default, making the text visible instead
of hidden.
Solution:
Replace the default link with an explicit highlight definition using
ctermfg=0 guifg=bg.
Problem:
Assigning to the local value of a global-local boolean option
('autoread', 'autocomplete', 'fsync') aborts:
Assertion failed: (curval.type == newval.type), function
ex_let_option, file vars.c, line 1408.
ex_let_one
ex_let_vars
ex_let
execute_cmd0
do_cmdline
call_user_func
...
eval_map_expr
vgetorpeek
vgetc
state_enter
main
A global-local option may have local value `kObjectTypeUnset`, but
`ex_let_option()` guards only `kObjectTypeNil`.
Solution:
When curval is Unset, resolve it to the inherited global value.
Problem:
By default, `nvim` does not survive if its host terminal dies. This is
inconvenient if you want to use Nvim as a "session manager" (like tmux).
Solution:
Let users opt-in to the "survive" behavior via `:detach!` (bang "!").
This marks the current UI as "detachable", so the server will not
self-exit if the UI channel closes.
Problem:
The default 'ruler' is implemented in C instead of the 'statusline' DSL.
Solution:
Replace the C implementation with a default 'rulerformat' expression.
This is a continuation of #1248 and #33036.
Advantages:
- configuration is more discoverable, the default being a useful example
- users and plugins can augment the default
- code reuse and less C code to maintain
- ui2: due to the use of an item group with `minwid`, it can expand
instead of truncating when the content gets too long, which is
particularly useful for locales with long translations of Top/Bot/All
Implementation details:
As is the case for 'statusline', when trying to set 'rulerformat' to an
empty string, the default expression is restored instead, mimicking how
previously the default C implementation would have been activated.
Just like before, `:set rulerformat=` and `:set rulerformat&` have the
same effect, and the ruler is disabled with `:set noruler`.
The default expression uses an item group with `%=`, unlike the fallback
in the previous default statusline `%-14.(%l,%c%V%) %P`, because the
total width and how it is configured is immediately clear without
documentation, it is a more useful pattern in general that works when
both sides have flexible width, and it also works for vim, which is
useful for configuration sharing/reuse.
A truncation marker `%<` is added at the end to mimic how at small
screen widths, the scroll percentage would disappear first, so that the
cursor position can remain fully visible.
BREAKING CHANGES:
- `&rulerformat` can no longer be set to an empty string
- ui2: the default ruler is no longer of fixed width, but can expand
- at very small screen widths (< 36 columns)
- ui2: it will no longer try to shrink white-space before truncating
- it truncates gradually from the right, whereas previously, the
scroll percentage would disappear all at once
- l10n can no longer add a space after the comma between line and column
(this was only done for one language: Ukrainian)
It's necessary to copy the global 'fileencoding' to the buffer-local
value before entering the buffer, otherwise 'fileencoding' is changed
when reading the file, which will mark the file as modified.
- Remove code that is never executed because the ruler is never rendered
separately for a window with visible statusline or when `ls=3`, in
other words: the variables `part_of_status` and `in_status_line` were
always false for the ruler and badly named for the statusline itself.
- Leave `maxwidth` unchanged after calling `stl_alloc_click_defs`.
- Don't reuse the window's click definitions for the ruler. Even though
it doesn't seem to be a bug because statusline and ruler are never
shown at the same time for the same window, the ruler currently
doesn't support clicks anyway.
- Disentangle the different cases, in particular statusline- from ruler-
specific code. Another example: `wp->w_wincol`, `wp->w_winrow`, and
`wp->w_width` are always used together, but this was hard to see.
Problem: Traditionally, the ruler in the last line is one cell shorter
than in the statusline, leaving the last cell of the screen blank.
According to code comments, this is in order to prevent unwanted
scrolling on "some" (unspecified, but presumably ancient) terminals.
Berkeley vi is more specific in its `vs_modeline` function: dumb
terminals with hardware scroll, SunOS 4.1.1 and Ultrix 4.2 curses.
(n)curses still has a similar limitation in `(w)addstr`, but apparently
only for historical reasons.
Maintaining the different widths leads to awkward inconsistencies when
the ruler is configured with 'rulerformat', except for the special case
where it contains a top-level `%=`. Shifting the ruler in the last line
to the left would be a solution, but the empty cell at the end doesn't
seem to be relevant anymore.
Solution: extend the ruler in the last line all the way to the right
edge of the screen, just like in the statusline. The exact same amount
of place will be available to the rest of the UI as before.
BREAKING CHANGE:
- the default ruler width is now 18 cells
- the last cell of the screen is no longer empty
Closes#41076
Problem: the ruler is not cleared in the following circumstances:
- ui1 is running
- 'rulerformat' is configured
- the default ruler was not previously visible in the last line, for
example because 'rulerformat' is configured in init.lua
- 'ruler' is disabled without using the command-line, for example via
key-binding (entering the command-line would clear the ruler)
The corresponding test case did not fail because 'rulerformat' was set
while the default ruler was shown.
Solution: use a dedicated variable for tracking whether the ui1 ruler
was previously shown in the last line. `did_ruler_col` is now only used
for setting `msg_col`, which is not implemented in the case where
'rulerformat' is configured.
Reorder the test code to make the individual checks more independent
from each other, and to reflect the future where 'rulerformat' will
never be empty. Note that the check where 'rulerformat' was configured
relied on the default ruler not being cleared and a stale "0," still
being shown in front of the new ruler - this is also fixed with ui2.
Fixes#38777 in case 'rulerformat' is set.
See PR 38879. Original message:
Problem: When the 'ruler' is in the last line of the screen, it takes
local highlight definitions of the current window, tripping an
assert (since c1648cf).
Solution: Don't use window-local highlight definitions when the ruler is
not part of a statusline.
Problem: transstr() appends with STRCAT()/STRLEN() from the start of
the result on every iteration, making it quadratic to the
length of the string.
Solution: Keep a tail pointer and append at it. (Samuel Schlesinger).
closes: vim/vim#20925124c86868c
Co-authored-by: Samuel Schlesinger <sgschlesinger@gmail.com>
Problem: "zb" scrolls incorrectly with cursor just above fold.
Solution: Handle boff.lnum being set to the last line of a fold
(zeertzjq).
With the cursor just above fold, botline_forw() moves boff.lnum to the
last line of the fold, but curwin->w_botline is at the first line of the
fold, so the boff.lnum == curwin->w_botline condition never holds.
Instead, check that boff.lnum has just moved to or past w_botline by
comparing its previous value with w_botline.
Also make a similar change to the loff.lnum check above for symmetry.
That one doesn't change behavior, as topline_back() sets loff.lnum to
the first line of a fold.
related: neovim/neovim#41122
closes: vim/vim#20923aee686334c
Problem:
'breakindent' and 'showbreak' draw their own padding with no
reference to whatever decoration or syntax highlight is currently
active, so it goes unhighlighted even mid-highlight, not just past a
real EOL. Gating this on the decoration's `hl_eol` flag (as an
earlier version of this fix did) missed plain highlights with no
`hl_eol` at all, which have the exact same problem.
Solution:
Snapshot decor_attr into decor_attr_save right before it can be
reset by 'linebreak' filler handling, and pass it into
handle_breakindent()/handle_showbreak_and_filler() to extend into
their padding: it is not a real end of the highlight, just screen
cells with no buffer text. Like the 'linebreak' filler, an
underline/strikethrough/overline is excluded, since it looks like a
broken line drawn over the gap. This also fixes 'breakindent' losing
the highlight right after a real 'linebreak' word-push, since that
reset otherwise leaked into the next row.
Problem:
ui2 clears the substitute confirmation match when it updates its prompt buffer with hlsearch disabled.
Solution:
Only invalidate the match highlight when the current buffer changes.
Problem:
When 'linebreak' pushes a word entirely to the next screen row, the
filler cells left on the current row keep whatever highlight was set
by the last real character before the break, even when that highlight
should not extend past it (e.g. an underline, which looks broken drawn
over blank cells).
Solution:
Reset decor_attr and area_attr at the filler when their attribute has
an underline, undercurl, strikethrough, or overline; otherwise leave
them, since a plain background or reverse-video highlight looks
correct extending through blank filler cells, regardless of where the
pushed-down word happens to end. search_attr keeps the same check,
plus its pre-existing on_last_col case (its own match ending exactly
here).
Problem: On MS-Windows, get_cmd_output() removes its reserved temporary
file before the shell opens it, allowing another Vim process to
reuse the same name.
Solution: Keep the temporary file reserved until command output handling is
complete (Sam Roeca).
closes: vim/vim#209150db0c3c142
Co-authored-by: Sam Roeca <samuel.roeca@gmail.com>
Introduce an initial browser-based Neovim demo with automatic startup and UI integration. The demo is functional but still requires persistence, additional testing, and further stabilization.
Acknowledgment: UiState in app.js is based on the implementation from github.com/MuNeNiCK/nvim-wasm, with additional modifications and updates
vim-patch:8.2.0110: prop_find() is not implemented
vim-patch:8.2.0318: Vim9: types not sufficiently tested
vim-patch:8.2.0518: a terminal falls back to setting $TERM to "xterm"
vim-patch:8.2.0543: Vim9: function with varargs does not work properly
vim-patch:8.2.0571: double free when passing invalid argument to job_start()
vim-patch:8.2.0582: color ramp test does not show text colors
vim-patch:8.2.1641: Vim9: cannot use 0 or 1 where a bool is expected
vim-patch:8.2.1692: build fails because TTFLAG_STATIC is missing
vim-patch:8.2.1855: Vim9: get error message when nothing is wrong
vim-patch:8.2.3104: Vim9: unspecified function type causes type error
vim-patch:8.2.3479: crash when calling job_start with an invalid argument
vim-patch:8.2.3481: failures when char is unsigned
vim-patch:9.0.1377: job_status() may return "dead" if the process parent changed
vim-patch:9.0.2084: Vim9: abstract static methods are possible
vim-patch:9.1.0751: Error callback for term_start() not used
vim-patch:9.1.1094: Vim9: problem finding implemented method in type hierarchy
vim-patch:9.2.0889: VMS: spurious "INVALID DECC FEATURE VALUE" message at every startup
vim-patch:6351c1775 CI: Bump github/codeql-action
vim-patch:64b0196a9 runtime(doc): remove todo entry for test_codestyle errors
vim-patch:8.2.0073: initializing globals with COMMA is clumsy
vim-patch:8.2.0253: crash when using :disassamble without argument
vim-patch:8.2.0306: Vim9: :substitute(pat(repl does not work in Vim9 script
vim-patch:8.2.0311: Vim9: insufficient script tests
vim-patch:8.2.0486: Vim9: some code and error messages not tested
vim-patch:8.2.0529: Vim9: function argument with default not checked
vim-patch:8.2.0530: test crashes on s390
vim-patch:8.2.0604: :startinsert in a terminal window used later
vim-patch:8.2.0652: compiler warning for char conversion
Problem:
`:set foo=<tab>` and `:set foo?` for func/expr options set to a Lua
function, always displays "v:lua".
The existing "<Lua N: file:line>" form was avoided because the ref id
N changes on every read of the same option.
Solution:
- Don't attempt to tab-complete Lua functions.
- Show "<Lua file:line>" (or "<Lua>" if source file is unknown).
Example:
:set operatorfunc?
operatorfunc=<Lua ~/.config/nvim/init.lua:42>
Problem: With 'smoothscroll' the scroll position in a long line is lost when
a window is temporarily squeezed to a couple of lines, for example
when opening and closing a help window.
Solution: When the cursor ends up in the skipped columns, skip up to the
screen line the cursor is in instead of showing the start of the
line.
closes: vim/vim#2089215f8ba5cec
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem: cursor_correct() checks for 'smoothscroll' with 'wrap' off, a
combination where 'smoothscroll' has no effect.
Solution: Remove the check, adjust_skipcol() already handles the case where
the cursor line just fits in the window.
closes: vim/vim#208912ea497f072
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem: With 'smoothscroll' the scroll position in a long line is lost when
moving to a column with "|".
Solution: Adjust the skipped columns for the column the cursor ends up in,
not for column zero.
related: vim/vim#20885
closes: vim/vim#208905ed8fc10fa
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem: :bwipe crashes if WinLeave wipes all other buffers
(after 9.1.2068).
Solution: Check for NULL pointer.
related: neovim/neovim#41066closes: vim/vim#208883e4019a082
Problem:
Numerous callers have to manually check optval ownership (i.e. whether,
and how, to release) via `is_callback_option`, `option_is_global_local`,
etc. This is fragile, hard to use correctly; and if we introduce another
optval variant in the future, we'll have to redo all of these careful
checks and boilerplate again.
Solution:
Provide a unified system and use it everywhere:
optval_free_owned
optval_is_owned
optval_own
Problem:
Cannot assign Lua functions/closures to "func" ('completefunc',
'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options.
Solution:
- Store "func"/"expr" options as `Callback` instead of string.
- Delete oceans of copy-pasted code.
- BREAKING: LuaRef returned via RPC/Vimscript is now represented as
`"<Lua N: file:line>"` (like what `:map` shows) instead of `nil`.
- Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin.
Helped-by: Lewis Russell <lewis6991@gmail.com>
vim-patch:decab25ac runtime(doc): Vim9: dictionary in a lambda block is not documented
vim-patch:f594f41e7 runtime(doc): regenerate help tags
vim-patch:61997d8ce translation(it): Update Italian man page
vim-patch:9.2.0876: GTK4: compile error with disabled netbeans feat
vim-patch:9.2.0877: Vim9: crash when a closure assigns to a variable declared in a loop
vim-patch:9.2.0878: Vim9: cannot use a script variable of an enclosing block in a lambda
vim-patch:9.2.0879: popup: "maxwidth" is not respected when 'wrap' is off
vim-patch:902db1d7a runtime(doc): update todo for the remaining 'smoothscroll' scroll position
vim-patch:9.1.0045: --remote-* does not ignore wilidignore
Problem: With 'smoothscroll' the scroll position of a window is lost when
its height changes.
Solution: Only reset the skipped columns when 'smoothscroll' is off, where
they just serve to keep the cursor visible.
closes: vim/vim#2088517f3923b8c
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem: The window scrolls when an autocommand window is used while the
cursor is behind multi-byte characters.
Solution: Use the byte column instead of the character count when computing
how many screen lines the text up to the cursor takes.
fixes: vim/vim#12085closes: vim/vim#208847fe3ea7658
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem:
xterm doesn't reset to user configured default with the sequence `\x1b[0 q`.
Solution:
Restore old behavior: if the reset cursor style terminfo entry is
absent, xterm's sequence should set the cursor to steady block, which is
the xterm default. In the near future, they may support another option
(`\x1b[7 q`) to reset to the user configured default.
Problem: When the only window has 'winfixheight' set and 'laststatus'
is one, splitting it leaves one screen line unused. This
happens for example when jumping to an item from a maximized
quickfix window (rendcrx)
Solution: Do not subtract the height of the status line twice
(Hirohito Higashi)
fixes: vim/vim#20495closes: vim/vim#20871ab36bcc870
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Problem:
Latent bug from 7f6c14ed54 (2015).
If an option default is "false" (`o.defaults.if_false = false`, e.g.
'fileignorecase'), codegen does not give it a `.def_val` on the platform
where its `#if` condition is undefined; it is zero-initialized.
This wasn't noticed until the parent commit, where zero value is
kObjectTypeNil, which `set_option_varp()` rejects.
Solution:
Check `if_false == nil` insteada of "falsey", so the `#else` branch gets
generated.
Problem:
The object subsystem has an intermediate representation for no real
reason. Besides the code cost, this also adds an extra (api <=> OptVal)
conversion step, which is a (small) perf cost.
Solution:
We already have `Object`, so use it instead.
- drop `OptVal`, `OptValData`, `OptValType`, and related boilerplate.
- add `kObjectTypeUnset`.
Problem: An insecurely-set 'indentexpr', 'formatexpr', 'includeexpr'
or 'complete' value can end up evaluated outside the
sandbox after buf_copy_options() and clears the flag.
Solution: Copy the insecure flag alongside the value in
buf_copy_options(), and make 'complete' a per-buffer
insecure-flags field
Supported by AI.
closes: vim/vim#2086135f7fdfdfb
I'm a bit hesitant to port this, but it's a follow-up to #39452.
Co-authored-by: Christian Brabandt <cb@256bit.org>