Commit Graph

1889 Commits

Author SHA1 Message Date
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
Justin M. Keyes
83ced05984 fix(ctx): coverity CHECKED_RETURN
CID 649145:         Error handling issues  CHECKED_RETURN
    /src/nvim/api/window.c: 138             in nvim_win_set_cursor()
    132       // Make sure we stick in this column.
    133       w->w_set_curswant = true;
    134
    135       // make sure cursor is in visible range and
    136       // cursorcolumn and cursorline are updated even if w != curwin
    137       CtxSwitch switchwin;
    >>>     CID 649145:         Error handling issues  (CHECKED_RETURN)
    >>>     Calling "ctx_switch" without checking return value (as is done elsewhere 5 out of 6 times).
    138       ctx_switch(&switchwin, w, NULL, NULL, kCtxNoEvents | kCtxNoDisplay);
    139       update_topline(curwin);
    140       validate_cursor(curwin);
    141       ctx_restore(&switchwin);
    142
    143       redraw_later(w, UPD_VALID);
2026-07-12 15:15:46 +02:00
Justin M. Keyes
d25ae8b8c2 refactor(input): rename getchar.c => input.c #40698
Problem:
`getchar.c` is a quirky name and doesn't align with our existing
`os/input.c` and `tui/input.c` modules, which encompass the same topic
at different layers.

Solution:
Rename `getchar.c` => `input.c` for discoverability.

Introduce `dialog.c` for functionality related to showing confirm
prompts, dialogs, etc.
2026-07-12 08:34:13 -04:00
Justin M. Keyes
4349c386db refactor(ctx): drop switch_win/restore_win #40693 2026-07-11 13:29:59 -04:00
Justin M. Keyes
0f1e0a7900 refactor(ctx): drop aucmd_prepbuf/aucmd_restbuf #40692 2026-07-11 12:04:31 -04:00
Justin M. Keyes
8d51e07fa1 feat(eval): writefile() treats RPC string as "blob"
related: fb6aeaba2d
2026-07-11 13:49:52 +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
Justin M. Keyes
d3ffc94110 refactor(cmdpreview): lift undo-checkpoint code
This is a mechanical lift of undo save-and-restore logic into... the
module that owns undo.
2026-07-10 03:27:37 +02:00
Justin M. Keyes
6bb1aa74e6 refactor: unify context-switching concepts 2026-07-10 03:27:37 +02:00
Justin M. Keyes
8c285c6c33 refactor(api): drop CmdParseInfo indirection #40657
Just Say No to indirection.
2026-07-09 13:30:33 -04:00
Vivek Kumar
bcbd9d7992 refactor(api): promote magic spec from CmdParseInfo to exarg_T #39119
Problem:
`magic` was owned by `CmdParseInfo`, but command handlers
need it at execution time via `exarg_T`.

Solution:
Move `magic` into `exarg_T`, and initialize it in `parse_cmdline()`.
2026-07-09 11:53:40 -04:00
Justin M. Keyes
8dfe4d6629 fix(api): nvim_win_resize tweaks #40596 2026-07-05 13:22:16 -04:00
Justin M. Keyes
a0fd59352a Merge #40520 nvim_win_resize 2026-07-05 12:06:13 -04:00
XiaowenHu96
ce718e31f4 feat(api): add nvim_win_resize()
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().
2026-07-05 21:47:34 +08:00
glepnir
7312df77bb fix(api): nvim_buf_set_text resets changelist to 0 #39965
Problem: changed_lines got a hardcoded 0, so the changelist entry
and '. mark always recorded column 0 instead of where the edit
actually happened.

Solution: pass start_col instead. changelist now tracks the real
column.
2026-06-29 14:38:07 -04:00
Justin M. Keyes
d2073d2eec refactor: cleanup, docs #40480 2026-06-29 13:10:31 -04:00
Justin M. Keyes
559730af0a perf(options): avoid Lua<=>API roundtrips #40477
Problem:
- Lua<=>API roundtrips
- Although we prefer Lua for most business-logic code, doing this
  conversion in C makes sense in this case because:
  1. setting options is a hot path
  2. most of the options logic lives in C
  3. the current arrangement is MORE verbose and requires MORE code

Solution:
Move conversion to a C util.
- nvim_set_option_value passes the raw Object (scalar, Array, or Dict)
  to `object_as_optval_for()` which flattens it to the canonical `:set`
  string and validates the type.
- drop `convert_value_to_vim`, eliminate its roundtrip.
2026-06-29 10:00:36 -04:00
Justin M. Keyes
87b42e1209 build: lint "strtol" #40442
Problem:
No lint for strtol().

Solution:
Add lint, and update existing usages.

Callers that previously got a (garbage) large positive value:
- `indent.c`: use getdigits() (intmax, no int truncation) with def=1 so
  overflow/too-large values stay positive and fall through to the
  existing "too big" check (E475).
- `file_search.c`: use getdigits() with def=255 so overflow/too-large
  values keep the "max expand" (else) branch.

The other conversions (api/command.c, eval/window.c, highlight_group.c,
tui/tui.c) only diverge on pathological overflow inputs where strtol's
result was already garbage and the observable outcome is unchanged.
2026-06-28 19:01:24 -04:00
Kyle
f34ee3da80 feat(api): nvim_set_option_value(operation=...) #39849
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`.
2026-06-28 13:20:56 -04:00
Justin M. Keyes
b2bf7bcfb1 feat(cmdwin): implement cmdwin as a normal buf+win
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).
2026-06-25 18:36:24 +02:00
Justin M. Keyes
8e3b216d0b docs: bufadd(), fnameescape() guidance #40378 2026-06-23 10:08:50 -04:00
Barrett Ruth
db30608058 fix(tui): attribute TermResponse to source channel #40330
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.
2026-06-23 06:19:56 -04:00
Justin M. Keyes
a6584b205c docs: misc 2026-06-11 13:35:19 +02:00
Justin M. Keyes
8f584031bc docs: misc #40126 2026-06-08 16:12:14 -04:00
jreidx
d9aa06eed8 feat(extmark): virt_lines_overflow "wrap" and "auto"
Problem: Extmark has support for horizontal scrolling and truncating, but not wrapping.

Solution: Extend virt_lines_overflow flags to support "wrap" and "auto" based on proposed changes in #18282.
2026-06-08 22:19:25 +08:00
glepnir
11b9e6f193 fix(option): allow empty/blank edges in 'winborder' #40112
Problem:
The comma form of 'winborder' is split with copy_option_part(),
whose skip_to_option_part() eats spaces after a comma, and empty
fields are rejected.

Solution:
Split the comma form literally on ',', keeping empty fields and
single-space fields.
2026-06-05 06:37:07 -04:00
Justin M. Keyes
70f8c7bbf3 Merge #40057 from luukvbaal/hidenodraw
perf(redraw): don't redraw hidden windows
2026-06-02 08:51:08 -04:00
Luuk van Baal
9cf684ed7d fix(float): validate conflicts for nvim_win_set_config()
Problem:  nvim_win_set_config() does not error on flags not allowed for
          non-floating windows.
          `hide` should not be allowed for non-floating windows.
Solution: Check that a window is a split when reconfiguring.
          Error when trying to hide a split window.
2026-06-01 01:02:01 +02:00
Luuk van Baal
253378f86a perf(redraw): don't redraw hidden windows
Problem:  Hidden windows are redrawn unnecessarily.
Solution: If a window is hidden, don't bother drawing it.
2026-05-31 23:15:39 +02:00
glepnir
70cfeabe23 fix(float): title/footer shows printable control chars #40047
Problem:
Literal tab (or other control char) in a float title/footer is
not made printable, so it renders incorrectly instead of as "^I".

Solution:
Normalize title/footer text for display like 'statusline'
tab to "^I", parameterize parse_virt_text() with untab
and recompute the width.
2026-05-30 10:02:16 -04:00
Justin M. Keyes
f5fae7aa5c docs: misc, options, pos/range 2026-05-30 12:57:24 +02:00
Justin M. Keyes
f1fad32e2e docs: misc, custom text-object #39877
text-object-define is a pattern I found in tpope's plugins (e.g.
https://github.com/tpope/vim-jdaddy) which shows an elegant way to
define a text-object. (Any mistakes in the example are my fault.)
2026-05-20 05:21:27 -04:00
Barrett Ruth
5181984db9 fix(api): nvim_exec_autocmds({buf=x}) runs in buffer context #39061
Problem: `nvim_exec_autocmds({ buf = ... })` matches the target buffer, but callbacks and modelines run with the caller buffer current rather than the target buffer.

Solution: Execute the buffered path in prepared target-buffer context and restore the caller afterward.
2026-05-20 03:48:55 -04:00
Justin M. Keyes
16d17c50bb refactor: simplify aucmd_restbuf usage #39879
Problem:
`aucmd_restbuf` must be guarded in case `aucmd_prepbuf` wasn't called.

Solution:
Update `aucmd_restbuf` to be a no-op if `aucmd_prepbuf` wasn't called.
This requires `aco` to be zero-initialized.
2026-05-19 05:09:23 -04:00
glepnir
450ba41436 fix(api): adjust Visual position after nvim_buf_set_text #30690
Problem:
Visual selection could end up in the wrong place after
nvim_buf_set_text or nvim_buf_set_lines. In some delete cases,
Visual.lnum was already clamped before the line shift happened, so the
adjustment got skipped.

Solution:
Split fix_cursor_cols into reusable fix_pos_col logic and reuse it
for Visual updates. Also adjust Visual.lnum before changed_lines so
the shift uses the original position before final clamping.
2026-05-18 13:08:26 -04:00
bfredl
e932d6ff17 fix(api): regressions with lua return values #39837
fixes #39834
fixes #39833
fixes #39851
2026-05-18 09:05:49 -04:00
zeertzjq
7b46848f14 vim-patch:9.2.0494: User commands cannot handle single args with spaces (#39854)
Problem:  User commands cannot handle single args with spaces
Solution: Add the -nargs=_ attribute (Maxim Kim)

-nargs=_ allow user commands to have a single argument with spaces.

For example given the following Test command and TestComplete function:

```
vim9script
def TestComplete(A: string, _: string, _: number): list<string>
    var all = ["qqqq", "aaaa", "qq aa"]
    return all->matchfuzzy(A)
enddef
command! -nargs=_ -complete=customlist,TestComplete Test echo <q-args>
```

`:Test q a<tab>` should successfully complete `qq aa`

fixes:  vim/vim#20102
closes: vim/vim#20189

f0e874a129

Co-authored-by: Maxim Kim <habamax@gmail.com>
2026-05-18 17:44:26 +08:00
Justin M. Keyes
846b8b2420 refactor: group nvim_buf_call, nvim_win_call tests #39828 2026-05-17 11:20:54 -04:00
bfredl
0aa7d2f4d5 feat(api): nvim_buf_call, win_call can has multiple return values #39801
from the "because we can and it is not much code" department. (diffcount
excluding tests is actually negative)

fixes https://github.com/neovim/neovim/issues/39636#issuecomment-4397141270
2026-05-17 10:25:22 -04:00
Justin M. Keyes
e572c9c80a feat(api): tab-local option scope #39811
Problem:
2d795face6 added support for tab-local options ('cmdheight')
to `nvim_get_option_value`, but not to:

    nvim_get_option_info2()
    nvim_set_option_value(…, { tab = … })
    gettabwinvar()

Solution:
- Update `options.lua` to model tab-local options. Introduce `kOptScopeTab`.
- Handle tab scope in the options layer so it works for all options APIs.

Note:
- No change to `gettabvar()`. Not sure if needed/wanted.

fix https://github.com/neovim/neovim/issues/31140
2026-05-17 10:24:46 -04:00
Justin M. Keyes
5ba0d28634 refactor(api): tab-local nvim_get_option_value #39810 2026-05-16 11:37:37 -04:00
EliWiegman
2d795face6 fix(api): nvim_get_option_value tab-local 'cmdheight' #39259
Problem:
API clients cannot query the tab-local value of 'cmdheight'.

Solution:
Allow nvim_get_option_value() to accept { tab = <tab-ID> } for 'cmdheight'.
2026-05-16 09:31:05 -04:00
zeertzjq
986382069a refactor: make nvim_put() trigger TextPut* with '_' as regname 2026-05-13 06:57:07 +08:00
luukvbaal
de67f93aea fix(messages): fast context for for nvim_echo({kind}) callback #39755
Problem:  vim.ui_attach() callback for nvim_echo() call that spoofs an
          internal message kind is executed in fast context.

Solution: Set msg_show callback |api-fast| context dynamically at
          external message callsites, and for internal list_cmd",
          "progress" and "shell*" messages.
2026-05-12 16:28:54 -04:00
bfredl
7673adc952 Merge pull request #38675 from bfredl/errdefer
feat(ui_client): "press ENTER" free nvim crashes
2026-05-12 11:00:26 +02:00
luukvbaal
96fc7c150f fix(api): don't update 'title' when renaming non-curbuf #39743
Problem:  'title' is updated when changing the name of a non-current
          buffer with nvim_buf_set_name().
Solution: Set RedrawingDisabled when renaming the buffer.
2026-05-11 15:54:55 -04:00
bfredl
9c42db1181 feat(ui_client): "press ENTER" free nvim crash debugging
This feature might be a little silly and niche, but it is very useful
for _my_ workflow (and open source is about mee)

An issue which is never present on high quality RELEASE builds, but
might occur on Debug builds is that the Nvim server crashes
on some error in your unfinished PR code. If you compile your debug
builds with sanitizers enabled, as you should, the ASAN/UBSAN runtime
will print some useful info about your mistake to stderr or a log file,
such as a stack trace. This can be used to jump to the error in the
code.

This allows the nvim server to install a signal hander in the ui client,
which can load this log file in a good safe version of nvim and parse it
using 'errorformat'

This is inspired by the "press ENTER" free workflow of ui2 and applies
it beyond the lifetime cycle of the nvim instance.

example config:
```lua
    local asan = vim.env.ASAN_OPTIONS
    if asan ~= nil and string.match(asan, "log_path=/tmp/nvim_asan")  then
      local myname = "/tmp/nvim_asan."..vim.uv.getpid()

      local args = {"--embed", "-n", "+set efm=%+A%*[^/]%f:%l:%c", "+silent cfile "..myname, "+silent cfirst", "+silent copen"}

      vim.api.nvim__set_restart_on_crash("nvim", args)
    end
```

and run your debug nvim like so

    ASAN_OPTIONS=handle_abort=1,handle_sigill=1,log_path=/tmp/nvim_asan ./build/bin/nvim
2026-05-11 11:00:03 +02:00
Justin M. Keyes
b351024daf build(docs): lint more quasi-keysets #39654
Problem:
Linter missed backtick and double-quote keynames in the quasi-keyset of
the `nvim_create_user_command` docstring.

Solution:
Update the linter to check backtick-surrounded and quote-surrounded key
names.
2026-05-07 16:00:26 +00:00