901 Commits

Author SHA1 Message Date
zeertzjq
ec982dfb93 vim-patch:9.2.1004: a completion function cannot tell why it was called (#41500)
Problem:  A function used through 'omnifunc' or 'complete' is called the
          same way whether 'autocomplete' started the completion or a
          key asked for one, so it cannot answer differently.
Solution: Report which of the two it is in complete_info() as "auto". It
          is returned only when asked for in {what}, so what
          complete_info() says by itself does not change
          (Hirohito Higashi).

closes: vim/vim#21143

1f56c351de

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-08-26 07:21:22 +00:00
Justin M. Keyes
a1de07418b feat(ui2): lift ui2 options into 'messagesopt' (part 1) #41474
Problem:
In order for ui2 to graduate to the main "messages ui" its configuration
needs to graduate into actual options.

Solution:
Migrate some of its config to 'messagesopt':
- "maxheight" (note: currently this is an integer treated as
  a "percentage"; if we want to support a row count we could allow
  values with units, like `"42%"`)
- "pager"
- "timeout"

Also improves error messages:

    messagesopt=hit-enter,history:500,bogus       E474: Unknown item 'bogus'
    messagesopt=hit-enter,history:500,progress:x  E474: 'progress' must be one of: , c
    messagesopt=hit-enter,history:abc             E474: 'history' requires a number
2026-08-25 03:58:17 -04:00
glepnir
92d5531f96 vim-patch:9.2.1001: complete_info() does not report the item highlight groups (#41461)
Problem:  complete_info() omits "abbr_hlgroup" and "kind_hlgroup".
Solution: Keep the highlight group ID with the match instead of the
          resolved attribute and add both entries to the returned items
          (glepnir).

closes: vim/vim#21105

1c32cede0a
2026-08-24 14:35:25 +08:00
zeertzjq
cbe513fca6 vim-patch:63d08d4: runtime(doc): update :h write-plugin and readdir() example
1) The complete example plugin at :h write-plugin the end of the
   documentation didn't reflect the snippets provided during the
   tutorial. In most of the Add() function, interpolated strings are
   used, but the final result used concatenated strings.

2) The example provided in readdir() to get a list of files ending in
   ".txt" didn't properly escape the dot in the regular expression:
      readdir(dirname, {n -> n =~ '.txt$'})
   This would match any file ending with "txt" that is at least 4
   characters long, instead it should be:
      readdir(dirname, {n -> n =~ '\.txt$'})

closes: vim/vim#21123

63d08d4386

Co-authored-by: Josep Puigdemont <josep.puigdemont@gmail.com>
2026-08-24 08:17:27 +08:00
Justin M. Keyes
354ea3bf2a docs: misc #41452
Co-authored-by: darkdi <rantovov5@gmail.com>
Co-authored-by: Qiaoxi Guo <28090444+breadtitor@users.noreply.github.com>
Co-authored-by: zaveshaa <zaveshaa@gmail.com>
2026-08-23 12:38:07 -04:00
Justin M. Keyes
47cd769ed5 feat(cmdatom): mappings capture continuation
Problem:
A mapping that ends mid-operation (`nnoremap ,D d`) emits a content-free
"mapping" atom plus a `pending` field, and the "continuation" motion
arrives as a sibling atom. Consumers must stitch the two together (which
has broken cases, e.g. Insert-opening mappings (",i") lose their session
entirely).

- ",i": the session atom is dropped bc the mapping RHS is consumed
  before the session starts (typebuf_maplen()==0), so
  atom_is_user_input()=false.
- ":normal"-in-opfunc: the opfunc internal "v..y" session (a) became
  kVatomTyped just because the deferred composite was open, masking the
  real operator capture via atom_captures, and (b) its nested frames
  re-derived the outer redo.
- "Motion" based on `moved=true`, has false negatives.
- `CmdAtom.remap` is unnecessary, and clutters the docs/usage.

Solution:
- Introduce `frame_id` to identify CmdFrames.
- Classify `type=motion` better, via `NV_MOTION` flag on the `nv_cmds` table.
- Drop `CmdAtom.pending`, `CmdAtom.remap`.
- Defer atom_composite_end() at the clock edge while an operator is
  pending, Visual is active, or `restart_edit` is set: the composite
  keeps collecting, so the continuation is captured in the mapping atom.
- ",i": Now an open composite counts as user input.
- ":normal"-in-opfunc: Now handled correctly.
- `remap` is now decided by `composite.payload || 0 subatoms`.
  atom_payload_mark() records the read the resolution never captures.
- `toplevel` is now decided by `CmdFrame.parent == NULL`.

before/after:

    INPUT       BEFORE                             AFTER
    ---------------------------------------------------------------------
    ,D w        {mapping lhs=,D pending=operator}  {operator lhs=,Dw keys=dw}
                + {operator keys=dw}
    ysiw"       {mapping lhs=ys pending=operator}  {operator lhs=ysiw" keys=g@iw"}
                + {operator lhs=g@iw"}
    ,v d        {mapping pending=visual}           {visual lhs=,vd keys=viwd}
                + {visual lhs=viwd}
    ,i XY<Esc>  {normal keys=i lhs=,iXY<Esc>}      {insert keys=1iXY<Esc> text=XY}
2026-08-22 17:29:34 +02:00
Justin M. Keyes
6423657352 feat(cmdatom)!: eliminate the need for vim-repeat #41414
Problem:
- `lhs` is not fully realized. E.g. for a "payload" mapping
  `lhs` omits the `getchar()` payload during a mapping (vim-surround
  `ds'` reports `lhs="ds"`). This means plugins like vim-repeat are
  still needed...
- The "delta" fields of a CmdAtom are calculated too late.
  - `<abuf>` and `changed` check whatever (wrong) buffer a command
    (":bnext") might land in.
  - CTRL-W_w between two windows on the same buffer reports type="motion".

Solution:
- `CmdOrigin` samples (buf/win/cursor/changedtick) at each "scope" entry
  (CmdFrame, composite, Visual session, insert session).
- `dd<C-w>l` reports `changed=true` for the buffer it edited, regardless
  of where the cursor ends up.
- New fields:
  - `pos`: cursor position at command start.
  - `moved`: indicates whether the cursor moved (in same buffer).
  - `undoseq`: undo state at settlement.
- lhs now includes the payload: "ds)" reports lhs="ds)" instead of "ds".
  - Easy for users to "replay" any atom.
- Rename: type "command" => "normal", "ex" => "excmd"; `arg` => `cmdarg`
- Drop `cascade` field (no reason to expose it)
2026-08-21 13:42:17 -04:00
zeertzjq
12c3e59e6a vim-patch:76f1eed: runtime(doc): clarify how setbufvar() handles window options (#41408)
related: vim/vim#21089
closes:  vim/vim#21104

76f1eed3a5

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-08-21 09:25:40 +08:00
zeertzjq
0e140ded51 vim-patch:bce3eb1: runtime(doc): clarify the 'findfunc' option (#41389)
Remove the note about "this function is called only once per :find
command invocation".

fixes: vim/vim#21062

bce3eb1fae

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-08-20 09:11:13 +08:00
Goldpigg
ab82c2c6b0 feat(extmark): virt_lines can highlight until EOL #41289 2026-08-18 08:35:22 -04:00
Justin M. Keyes
b107154ba2 docs: misc, cwd, vimscript.txt #41356
Extract vimscript.txt from repeat.txt
2026-08-17 13:37:08 -04:00
Justin M. Keyes
64a301184e feat(input)!: CmdAtom event #41297
Problem:
There is no unified notion of a "user action".

Vim processes input by one-char-at-a-time, and mostly throws away any
hints it might gather about the user's action, with one exception: it
stores the last _edit_ action (the "redo buffer", encoded as
unstructured `["x][v][count]body` bytes).

Plugins can only observe individual keys (vim.on_key) and high-level
effects (TextChanged, CursorMoved).

Solution:
- Users can subscribe to `CmdAtom` events to handle any user action.
  - Event is deferred; handlers cannot cancel or interfere with user
    actions.
- Capture `CmdSpec` from the normal/insert/visual subsystems.
  - typeahead/readahead stay unstructured (`buffheader_T`): they are key
    streams, not commands.
  - the redo/record buffers become `StringBuilder`: fewer
    allocations/copies.
- Repurpose the input/redo engine to accept `CmdSpec` objects.

"atom": one repeatable unit of user input, as a resolved (post-mapping)
keysequence plus structured fields. Only user actions, not `:normal`,
API calls, or non-"t" `feedkeys`.

BREAKING: dot-repeat of an Insert session, replays the entire session
including cursor-moves (:help ins-repeat).

BREAKING: dot-repeat of a Visual operation, replays the selection
instead of operating on a fixed-size region.
2026-08-14 09:30:31 -04:00
zeertzjq
ecaf9e9396 vim-patch:02bf089: runtime(doc): clarify diff_filler() function (#41283)
fixes: vim/vim#20990

02bf0893d5

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-08-12 08:24:48 +08:00
Justin M. Keyes
a4a544032a feat(cwd)!: :lcd! (bang), rearrange :bcd/:lcd/… scope precedence #41194
Problem:
- buf-local CWD scope is lower priority than :lcd, which is weird.
  ```
  win > buf > tab > global
  ```
- No way to clear current CWD at a given scope.

Solution:
- Rerrange scope precedence to:
  ```
  buf > win > tab > global
  ```
- Introduce "bang" variants (`:bcd!`/`:lcd!`/`:tcd!`) which clears the
  local CWD for the given scope.
2026-08-07 04:41:37 -04:00
Justin M. Keyes
7d2249c579 docs: misc, :bcd, slug() 2026-08-06 10:27:29 +02:00
Justin M. Keyes
9cd4dd1c19 fix(:bcd): do not "inherit" buffer-local dir
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`.
2026-08-04 20:48:44 +02:00
Justin M. Keyes
46ca236525 fix(cwd): validate getcwd(…, -1) 2026-08-04 20:48:44 +02:00
Justin M. Keyes
db2e86fba4 refactor(editor): cleanup change-directory (:bcd) logic 2026-08-04 20:48:05 +02:00
saher
ea3868bcf9 feat(editor): :bcd changes buffer-local directory
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>
2026-08-04 20:09:48 +02:00
Sébastien Hoffmann
ca07e505f9 refactor(ruler)!: replace C implementation with 'rulerformat' expression
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)
2026-08-04 12:12:23 +02:00
Sébastien Hoffmann
259e6fa9cc fix(ruler)!: consistent width in last line and statusline
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
2026-08-04 06:36:58 +02:00
Justin M. Keyes
98d767cd53 docs: func/expr options, misc #41102 2026-08-01 17:48:32 -04:00
Justin M. Keyes
3e01dcddbe refactor(options): memory management
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
2026-07-31 21:50:04 +02:00
Justin M. Keyes
726d1a92d2 feat(options): lua closure/function options
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>
2026-07-31 21:50:04 +02:00
zeertzjq
a85cce90e3 vim-patch:partial:b4ae16c: runtime(doc): clarify 'laststatus' effect (#41052)
fixes: vim/vim#20875

b4ae16ca3e

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-07-30 00:11:46 +00:00
glepnir
916a6e9546 fix(eval): complete_info() equal, preselect, commit_chars #41022
Problem:  complete_info() does not report "equal", "preselect" or "commit_chars".

Solution: Report them for the items that set them.
2026-07-28 07:24:58 -04:00
Justin M. Keyes
80cd482577 fix(lua): vim.regex():match_str abort in Luv callback #41008 2026-07-27 11:01:54 +00:00
Justin M. Keyes
359459dec6 refactor(exmode): Ex-mode as cmdwin + Lua #40991
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
  that can be achieved with `cmdwin`, which also gains extra UX
  benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
  scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
  "Entering Ex mode" message).

Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
  cmdwin" in Lua.
  - "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
  - Drop POSIX Ex-mode quirks.

Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
  pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
  stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
  (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).

Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=>stdout
- -V1=>stderr
- CRLF input
- continue-after-error and exit codes

Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
  waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
  answers: Nvim stops at end-of-input, skipping the rest of the script,
  exit 0. Use ":lua io.read()" instead.
  - If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
  cmdline input from stdin.
2026-07-27 06:25:21 -04:00
zeertzjq
43b666cb27 vim-patch:770eb7d: runtime(doc): clarify expandcmd() and "~" behaviour
fixes: vim/vim#20793

770eb7db17

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-07-26 09:01:32 +08:00
Barrett Ruth
22d44ef875 fix(api): add lhs option for keymap deletion 2026-07-25 10:36:56 -07:00
Justin M. Keyes
715d8887ec docs: misc #40847
Co-authored-by: Barrett Ruth <br@barrettruth.com>
Co-authored-by: Nathan Zeng <nathan.j.zeng@gmail.com>
2026-07-25 12:47:51 -04:00
zeertzjq
db41e4c74f vim-patch:0c1a214: runtime(doc): Fix truncated sentence in :h map()
fixes: vim/vim#20725

0c1a214497

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-07-25 06:32:03 +08:00
glepnir
f95bd73935 feat(float): 'previewpopup' option #26799
Problem:
The preview-window (:pedit, etc.) always uses a split, but it would be
useful as a floatwin (or "popup").

Solution:
Support Vim's 'previewpopup' option.
2026-07-23 17:27:14 -04:00
zeertzjq
b81c60c3fa vim-patch:9.2.0830: the completion menu is not used on terminals without colors (#40917)
Problem:  When the terminal reports no colors ("t_Co" is 0 or 1) the
          insert mode completion popup menu is not shown at all, while
          the command line completion popup menu ('wildoptions' contains
          "pum") is shown.  In 'wildmenu' completion the current match
          cannot be told apart from the other matches (Maxim Kim)
Solution: Show the insert mode completion popup menu regardless of the
          number of colors and add "term" attributes to the default
          highlighting of Pmenu, PmenuSel and PmenuThumb.  The wildmenu
          is drawn with the attributes of the status line, which is
          reversed, and on most terminals the standout mode is the same
          as the reverse mode, thus use the underline mode for the
          default highlighting of WildMenu (Hirohito Higashi).

fixes:  vim/vim#20800
closes: vim/vim#20803

52485e0d24

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 07:40:11 +00:00
Justin M. Keyes
6f5fae3f8c fix(lua): vim.keycode cleanup #40817 2026-07-18 14:31:36 -04:00
Justin M. Keyes
446b9d8c55 docs: misc, remove some old help tags #40214
- Remove old help tags: they add noise to cmdline completion.

Co-authored-by: acehinnnqru <acehinnnqru@gmail.com>
Co-authored-by: KangaZero <samuelyongw@gmail.com>
Co-authored-by: Simone Ragusa <hi@interrato.dev>
Co-authored-by: Chinmay Dalal <~chinmay/public-inbox@lists.sr.ht>
Co-authored-by: coyaSONG <66289470+coyaSONG@users.noreply.github.com>
Co-authored-by: Olivia Kinnear <git@superatomic.dev>
2026-07-18 04:29:51 -04:00
Barrett Ruth
12e8db3847 fix(restart): distinguish v:exitreason for :restart! #40801 2026-07-18 04:07:14 -04:00
Justin M. Keyes
e0e7f65b74 refactor(detach): eliminate nvim__ui_detach #40793
Problem:
`nvim__ui_detach` was added in 85e0559d46 in order to implement
`detach_others` from Lua. Using Lua in this case is doing more harm than
good.

Solution:
Extract `ui_detach_channel`, which also allows it to be used for the
"self detach" path from `ex_detach`.

Bonus: the old MSWIN path always called `os_swap_to_hidden_console()`;
now `ui_detach_channel` only does so for a stdio channel. For the common
stdio TUI this is identical; for a socket UI it's more correct (no
parent console to swap).
2026-07-17 16:37:45 -04:00
Jason Woodland
85e0559d46 feat(ui): ":%detach!" detaches all other UIs #39216
Problem:
Not easy for one UI to kick the others off a shared Nvim server.

Solution:
Treat `:%detach` as detach-other-UIs.
2026-07-17 15:23:34 -04:00
Justin M. Keyes
31ad7d4527 Merge #40621 fix(ui2)!: legacy 'ruler' inconsistencies 2026-07-15 08:13:37 -04:00
Justin M. Keyes
671e9d4913 feat(marks): :marks completion, list extmarks #40743
Problem:
- No UI for listing extmarks.
- `:marks` doesn't support cmdline-completion.

Solution:
- Add completion and extmarks support to `:marks`.
- Update `get_buf_local_marks` to include the ":" (prompt-buffer) mark.
2026-07-15 05:55:51 -04:00
Justin M. Keyes
eb94149a29 refactor(vimscript)!: drop ctxget(), ctxpush(), etc #40724
Problem:
This functions are most likely never used in the wild.
- They are redundant with `nvim_get_context` + `nvim_load_context`.
- The "context" concept was never fully developed and hasn't gained
  traction.

Solution:
Drop these vimscript aliases, they are just extra cruft.
2026-07-13 17:57:13 -04:00
Justin M. Keyes
fe794153ed feat(docs): mark optional API parameters 2026-07-13 20:01:55 +02:00
Justin M. Keyes
9982f6e0e4 refactor(api): omit optional param 2026-07-13 19:44:15 +02:00
tao
4a08596314 fix(path): normalize separators (slashes) #39155
Problem:
Continue separators normalization, and try to keep it at the
nvim <-> external boundary, e.g., `fn.xxx`, `api.xxx`, `:xxx`

Solution:
some key changes
- normalize `$HOME-windows`
- normalize entry points of changing directory
  - `nvim_set_current_dir()`, `chdir()`
- normalize the named pipe
  - `--listen` arg, `--server` arg, `:restart`
  - `serverstart()`, `sockconnect()`, `serverstop()`
- make `expand()` respect 'shellslash' again
- clean up `did_set_shellslash`
- replace `forward_slash` with `TO_SLASH`
- remove obsolete `TMP_PATHSEPSTR`
- remove `slash_adjust` in `do_autocmd_dirchanged`?
- make `fnamemodify()` always return `/` (except when substituting
  separators via `:s`, `:gs` ?)

Note:
- these funcs still apply `slash_adjust` on return, as before:
  `:pwd`, `chdir()`, `exepath()`, `getcwd()`
- these funcs alwarys return `/`, unlike before the normalization PRs
  - `getcompletion()`, `finddir()`, `findfile()`

Also
- clean up code, comments, formatting and tests
- move `TO_SLASH` from `f_chdir` to `changedir_func`
- move `TO_SLASH` from `f_bufadd` to `buflist_new`

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2026-07-12 13:23:44 -04:00
Sébastien Hoffmann
935a14bb72 docs(ui2): deprecate v:echospace
The purpose of `v:echospace` was to avoid disruptive "Press ENTER"
prompts. Since those are no longer a problem with ui2, the complexity
of maintaining it up-to-date is no longer justified.
2026-07-11 18:44:49 +02:00
Sébastien Hoffmann
c5be331502 fix(ui2)!: don't constrain ruler to ru_wid, fix leading item group
Problem: ui2's ruler is no longer of fixed width, and the internal width
variable `ru_wid` now acts as an arbitrary maximum, which is unnecessary
because the same can now be achieved transparently with an item group.
Furthermore, the old way of setting `ru_wid` with an overloaded subset
of the item group syntax leads to a number of inconsistencies. In
particular, when the configured ruler expression is reused for including
the ruler into the statusline, where the item group syntax is
interpreted in the usual way. The fact that this width is set in the
`minwid` position is more confusing now that it is a de-facto maximum.

Solution: for ui2, constrain the ruler only by half the screen width,
which previously was an additional limit relevant on small screens.
Skip the special-case treatment of the ruler's leading item group spec,
process it like a normal item group.

Example: the current fallback ruler expression in the default statusline
now actually works for `rulerformat` itself:
  set rulerformat=%-14.(%l,%c%V%)\ %P
because the result can naturally expand to 18 cells instead of being
truncated to the default 17 cells, and removing the period after
`minwid` doesn't change the result, whereas before, it would unhelpfully
lead to setting the fixed ruler width to 14 cells.

BREAKING CHANGE: if the user used to set the ruler's fixed width, it
will now be treated as minimum instead of a maximum width, which in
practice increases backwards-compatibility with ui1 and vim. The main
remaining difference is that item groups are right-aligned by default,
but backwards-compatibility can be achieved by setting a negative
`minwid`, which ui1 and vim ignore. To restore the previous fixed width,
specify `maxwid` as well, but this does not work in ui1 and vim.
If `rulerformat` contains a `%=` without enclosing item group, it will
now expand to fill half the screen width. But in that case, it will
already spread out similarly in the new expression-based statusline, so
consistency of the ruler in both positions is increased.
To simulate the previous default behaviour, wrap it in `%-17.17(...%)`.
For best compatibility and reuse with vim, leave out `maxwid` and make
`minwid` negative, e.g. `%-20(...%)`.

fix https://github.com/neovim/neovim/issues/40247
2026-07-11 18:31:54 +02:00
glepnir
59dbca9b0c fix(api): nvim_cmd() "args" type too narrow #40670
Problem: nvim_cmd() accepts number/boolean in args and converts them
to strings, but the keyset declares ArrayOf(String).

Solution: use ArrayOf(Union(Integer, String, Boolean)) and wrap union
types in parens when generating array annotations.
2026-07-10 20:34:08 -04:00
Barrett Ruth
3b88a8a65d fix(filetype): ensure directory bufname ends w/ slash sep #40552
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.
2026-07-10 12:40:13 -04:00
Evgeni Chasnovski
0653e7a338 feat(pack): 'packlockfile' option #40562
Problem: No way to configure the lockfile location.

Solution: Add 'packlockfile' option.
2026-07-08 12:23:28 -04:00