| Commit message (Collapse) | Author | Age |
| |
|
|
| |
Alias semantis are identical to using the full extreg name.
|
| |
|
|
| |
Add tests for aliases.
|
| | |
|
| |
|
|
|
|
|
| |
- support for let syntax: let @~extreg_name = ...
- support for expressions: let x = @~extreg_name
- support for cmdline <C-r>
- support for ex commands: <cmd>put ~extreg_name
|
| | |
|
| |
|
|
|
| |
Problem: No way to check if cascade is in action.
Solution: Add `v:cascading` variable.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: getfsize() checks the file type twice.
Solution: Use S_ISDIR macro instead of calling mch_isdir()
(Yasuhiro Matsumoto).
On MS-Windows: 40.8 us -> 26.6 us for a file, 41.1 us -> 25.3 us for
a directory.
closes: vim/vim#21448
Assisted-by: AI
https://github.com/vim/vim/commit/ea1e40e5e06b1a6a5abebe77223f4a7e36930a87
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: cannot pass "true" to timer_paused().
Solution: Use tv_get_bool(). (closes vim/vim#6891)
https://github.com/vim/vim/commit/418155def2aa45afd7fc034db341dc874b00af3a
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
|
| |
Problem: Vim9: cannot pass "true" to submatch(), term_gettty() and
term_start()
Solution: Use tv_get_bool_chk(). (closes vim/vim#6888, closes vim/vim#6890, closes vim/vim#6889)
https://github.com/vim/vim/commit/ad30470610e228e66afb837fdbab6bea36c43de4
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem: repeat() with a large number can cause an overflow
(Yuyao Jiang)
Solution: Add overflow check for the various repeat() functions.
related: vim/vim#21373
https://github.com/vim/vim/commit/70903d2be29ddf759ea55cfa6d343c026ea04779
Co-authored-by: Christian Brabandt <cb@256bit.org>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: list2blob() appends one byte at a time.
Solution: Preallocate the buffer and write the bytes directly
(Yasuhiro Matsumoto).
Cover large conversions, descending ranges, and invalid trailing items.
All 33 blob tests pass. Local five-run medians improve by 17% for 4096
items and 19% for 65536 items.
closes: vim/vim#21385
https://github.com/vim/vim/commit/c77608d35e899a0103d022fb9edb19c58ea00396
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
API append, prepend, and remove operations reach the option setter as
full replacements. This can clear an expression's untrusted flag and
allow it to write files, unlike equivalent :set operations.
Solution:
Pass replacement status through the option setters so merges preserve
the existing value's trust restrictions.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
| |
Problem:
Redundant logic.
Solution:
Deduplicate.
Also: `winrestview()` no longer forces a status-line redraw and
resending `win_pos` (`win_new_width()` on unchanged width).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: Option validators and setters repeatedly pass error buffers and
their sizes separately. Some setters return messages in static storage.
Solution:
- Add CharBuf for borrowed writable storage, with its length including
space for a terminating NUL.
- Move option error buffers to the callers that report errors. Preserve
existing buffer sizes, truncation, and calls that do not need a
message.
- Consolidate option error formatting and the duplicated code that lists
valid option values.
- Return error messages directly from do_one_set_option().
- Remove unused arguments from get_option_newval() and
set_option_value_for().
- Handle legacy TTY assignments in the existing callers and remove the
redundant compatibility wrapper.
- Reuse CharBuf for Tree-sitter query errors.
- Pass CharBuf through the statusline and statuscolumn builders,
retaining the buffer sizes provided by their callers, including title
formatting.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
needed (#41925)
Problem: getregionpos() returns a pair of positions for every line, so
obtaining just the outer endpoints of a region costs O(lines);
for a 100000 line region that is about 1.4 million list
allocations for a result of which the caller keeps two
positions.
Solution: Add a "bounds" item to {opts} that returns a single pair with
the start on the first line and the end on the last line
(Volodymyr Chernetskyi).
The lines in between do not influence the outer endpoints, so with
"bounds" they are not visited at all. The two positions then come from
different lines and describe a diagonal of the region rather than its
shape; for a blockwise region they are the start of the first line and
the end of the last line, not the corners of the block. This is exactly
what indexing the full result gives, so the awkward corners are kept as
they are, including an empty first line yielding a "col" of 0 for the
start while the end keeps its own column.
On a 100000 line buffer this takes getregionpos() from about 45 ms to
about 0.003 ms per call.
closes: vim/vim#21209
https://github.com/vim/vim/commit/2173c3e4eceedc76c4fd7d56cdbfbbd35e9be853
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
function frame (#41460)
Problem: In the debugger ">up" and ">frame" select an older function call
frame, but get_funccal_local_ht() and the related functions check
current_funccal while returning a dictionary of the frame that
get_funccal() selected. A :def function keeps its local variables
on the vim9 stack, its funccall_T has no l: and a: dictionaries and
is allocated cleared, so with such a frame selected the returned
hashtab has a NULL ht_array and evaluating any variable name at the
debug prompt crashes in hash_lookup().
Solution: Check the funccal that is actually used and return NULL when it has
no l: variables, so that the variable is reported as undefined
instead.
closes: vim/vim#21111
https://github.com/vim/vim/commit/5ad47b07af72950624904a9ec0bc9f2d4ebc77a6
Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Notes:
- 8.2.1614 also flips searchcount()'s "recompute" default to FALSE;
- 8.2.1620 flips it back, so the default stays true here.
vim-patch:8.2.1601: Vim9: cannot use 'true" with garbagecollect()
https://github.com/vim/vim/commit/2df47310422f4a77e85de7901a5299923a1addd3
vim-patch:8.2.1602: Vim9: cannot use 'true" with getbufinfo()
https://github.com/vim/vim/commit/036c2cf719e3de445779a275514030be66e26883
vim-patch:8.2.1603: Vim9: cannot use "true" with getchar()
https://github.com/vim/vim/commit/c08cc72947fdfab484f53c5d9bbea662bc5a9c8f
vim-patch:8.2.1604: Vim9: cannot use "true" with getcompletion()
https://github.com/vim/vim/commit/d217a87755ba01fc626b1c178c682fcd05ab3a28
vim-patch:8.2.1614: Vim9: cannot pass "true" to searchcount()
https://github.com/vim/vim/commit/597aaac9d2b090e0eb738ab4e2afd454b7b92393
vim-patch:8.2.1615: Vim9: cannot pass "true" to searchdecl()
https://github.com/vim/vim/commit/30788d3d37a90b0702d94b7272ed26672534ba6f
vim-patch:8.2.1616: Vim9: cannot pass "true" to synID()
https://github.com/vim/vim/commit/fcb6d7082d563acc33866b3d3a659c32ad19a9e1
vim-patch:8.2.1617: Vim9: cannot pass "true" to win_splitmove()
https://github.com/vim/vim/commit/4b9bd692bdffba03fda04f9979e25431b53e416b
vim-patch:8.2.1619: Vim9: cannot pass "true" to spellsuggest()
https://github.com/vim/vim/commit/7c27f337bf278babc1ccdcb66ac975f115d660b7
vim-patch:8.2.1620: searchcount() test fails
https://github.com/vim/vim/commit/4140c4f3fff1a441f2837f2f911ab0f0368e412a
N/A patches:
vim-patch:8.2.1606: has() takes no second argument in Nvim
https://github.com/vim/vim/commit/04637e243d39f791cfc97c3ce96d99ef1bf047e1
vim-patch:8.2.1610: list2str()/str2list() take no "utf8" argument
https://github.com/vim/vim/commit/a48f786787e8e070c1a611146fd1f0f7e141e60a
vim-patch:8.2.1611: nr2char() ignores its "utf8" argument
https://github.com/vim/vim/commit/ed6a430fae72c077ec106c9620379b69cfec3035
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: string_reduce() copies *rettv into argv[0] before calling
eval_expr_typval(). When the evaluator fails early, rettv is
never reset and still aliases argv[0] v_string.
clear_tv(&argv[0]) frees it, leaving rettv dangling and when
in vim9script get_func_tv() frees it again (Ave Dva).
Solution: Set rettv->v_type = VAR_UNKNOWN like what is done in
list_reduce() and tuple_reduce(), use tv_get_string_strict()
in f_reduce()
closes: vim/vim#21048
Supported by AI.
https://github.com/vim/vim/commit/cd59994c455a20d39d5cc41b4978ecfd2bf4be2e
Co-authored-by: Christian Brabandt <cb@256bit.org>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: The comments on the precomputed sort keys explain the code by
contrasting it with the previous implementation, and one of
them exceeds 80 columns (after v9.2.0937).
Solution: Drop the redundant comments and shorten the union member ones
(Hirohito Higashi).
related: vim/vim#21003
closes: vim/vim#21030
https://github.com/vim/vim/commit/722f4292e55d48520b7e32cabb4b8640293d0977
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
comparison (#41286)
Problem: sort() with "n", "N" or "f" converts an item to its number on
every comparison. For "n" that is a tv2string() plus strtod()
per comparison, so sorting a list of numbers turns each number
into a string and back O(n log n) times, dwarfing the sort.
Solution: Compute the numeric key of each item once, before the sort,
and compare the stored key (Samuel Schlesinger). Only the
builtin numeric compare modes are affected; uniq(), which
passes a bare list item to the compare function, and the
string and user-function paths are unchanged.
Sorting a list of 100000 numbers (min of 3, macOS arm64):
- sort(l, 'n'): 0.205s -> 0.017s
- sort(l, 'N'): 0.017s -> 0.010s
- sort(l, 'f'): 0.014s -> 0.010s
The result is identical, including that a string is still treated as 0
in "n" mode and that "N" keeps full 64-bit precision.
Add Test_sort_numeric_precomputed(): a large shuffled list sorted with
"n", mixed integers and floats, int64 values beyond the exact range of
a double for "N", and uniq() over the non-precomputed path.
closes: vim/vim#21003
https://github.com/vim/vim/commit/c8c59db9dfdc2db5f17aa0a78ea1464f035bdf5e
Co-authored-by: Samuel Schlesinger <sgschlesinger@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Now this was a cargo cult anti-pattern to write home about.
Doing painful save-and-restore bookkeeping around a separate
`magic_overruled` decoy global is just as messy as doing painful
save-and-restore logic around `p_magic` itself. only that now you need
to wrap every access to the effective value in a function call.
This replaces this with a marvellous new Clean Code technique™:
passing in the intended behavior as a function parameter to functions
where either the option or an explicit value might be used.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: Vim9: can't use v:true for option flags.
Solution: Add tv_get_bool_chk(). (closes vim/vim#6725)
----
"tv_get_bool_or_number_chk()" without vim9 params is identical to
"tv_get_number_chk()".
"tv_get_number_chk()" and tv"_get_bool_chk()" are identical
after excluding new vim9 params.
Yes, "want_bool" param is N/A because of "in_vim9script()".
If I port it, then I will refactor these macros or "static inline"
functions within "src/nvim/eval/typval.h".
----
https://github.com/vim/vim/commit/36967b32fd02eaab4273c1a1e7a1210a5fe45d09
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: The channel source file is too big.
Solution: Move job related code to a new source file.
----
Move eval-related prompt-buffer API to src/nvim/nvim/eval/buffer.c.
https://github.com/neovim/neovim/pull/37743#issuecomment-3897416840
----
https://github.com/vim/vim/commit/8b5866ded6036f7adece26b6d16962bbd2d47842
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: bufnr() doesn't take "true" argument.
Solution: use tv_get_bool_chk(). (closes vim/vim#6863)
https://github.com/vim/vim/commit/fe136c9a85412f4bdb5de70ef8416af5fa382b28
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
| |
Problem: Vim9: cannot use "true" for some popup options.
Solution: Add dict_get_bool(). (closes vim/vim#6725)
https://github.com/vim/vim/commit/558813314d63dd0263a7a86c0496c1e89b5c8cba
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: index() does not take "true" as argument.
Solution: Use tv_get_bool_chk(). (closes vim/vim#6823)
https://github.com/vim/vim/commit/6c553f9c04a698ac2e19584f8ea8e2cb7cd98c80
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: globpath() doesnot take "true" as argument.
Solution: Use tv_get_bool_chk(). (closes vim/vim#6821)
https://github.com/vim/vim/commit/f966ce5ea24748eed10f708d4f828be44887a559
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: glob() doesnot take "true" as argument.
Solution: Use tv_get_bool_chk(). (closes vim/vim#6821)
https://github.com/vim/vim/commit/5892ea151197c8a6363c7ce2322d84277b97353e
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: getreg() does not take "true" as argument.
Solution: Use tv_get_bool_chk(). (closes vim/vim#6820)
https://github.com/vim/vim/commit/67ff97ded70a87bc77f58d0bf9a261710ae88112
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: expand() does not take "true" as argument.
Solution: Use tv_get_bool_chk(). (closes vim/vim#6819)
https://github.com/vim/vim/commit/551d25e76545df785a9f62df52f34bc1dd368bfb
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
Redudant code
Solution:
Add `path_fold_char()` to normalize path sep.
Refactor `pathcmp()` and `path_fnamencmp()` into `path_cmp`.
| feature | pathcmp | path_fnamencmp | path_cmp(now) |
| ------------------------ | -------------- | -------------- | ------------- |
| case folding | `mb_toupper()` | `utf_fold()` | `utf_fold()` |
| consults fileignorecase | ✅ | ✅ | `ic` param |
| `maxlen` | ✅ | ✅ | ✅ |
| `/` == `\` | ✅ | ✅ | ✅ |
| MSWIN drive letter | ❌ | ✅ | ✅ |
| sep affects sorting | ✅ | ❌ | ✅ |
| ignores a trailing slash | ✅ | ❌ | ✅ |
Refactor `path_fnamecmp` and `path_full_compare` into `path_equal`,
with flags controlling "no filesystem" comparison (i.e. `path_cmp`), env
variables expansion, absolute path resolution and filesystem access.
|
| |
|
|
|
|
|
|
|
|
| |
#41216
Problem: Vim9: error when passing getreginfo() result to setreg().
Solution: Use dict_get_bool() for "isunnamed". (closes vim/vim#6784)
https://github.com/vim/vim/commit/6a950581da52b410a74531044aae8f1f8f38a7df
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: count() third argument cannot be "true".
Solution: use tv_get_bool_chk(). (closes vim/vim#6818)
https://github.com/vim/vim/commit/119f5572306c4abba91eaf446c0c52637db223e8
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
| |
Problem: Vim9: bufname('%') gives an error.
Solution: Only give an error for wrong argument type. (closes vim/vim#6807)
https://github.com/vim/vim/commit/02aaad91094939758e053588dd23ebda467eea29
Co-authored-by: Bram Moolenaar <Bram@vim.org>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
- Explicit `:bcd` (etc.) persists from `nvim_buf_call()` but not from an
autocmd handler targeting a hidden buf (`LspAttach`, `TermRequest`, …),
which needs a `vim.schedule()` workaround.
- `vim._with()` is supposed to work as a "sandbox", discarding
side-effects, but it leaks CWD changes: `:lcd` from a `win` context,
any chdir from a visible-buffer context.
Solution:
- Explicit :cd/:tcd/:bcd during a temp context persists by default.
- "Ambient" directory changes ('autochdir', existing win-local CWD,
etc.) are still undone, as before.
- Add `kCtxKeepDirs`: snapshot/restore the target's full CWD state
(w/b/tp-local, global, cwd). Used by `vim._with()` and `'inccommand'`,
which must not leak state.
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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:
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:
Assigning a Boolean or special value (v:true/v:false/v:null/v:none) to a TTY
option aborts:
Assertion failed: (curval.type == newval.type), function ex_let_option, file vars.c, line 1408.
3 libsystem_c.dylib __assert_rtn + 284
4 nvim ex_let_one + 3308
5 nvim ex_let_vars + 112
6 nvim ex_let + 2356
7 nvim execute_cmd0 + 252
8 nvim do_cmdline + 9076
9 nvim call_user_func + 3320
10 nvim call_func + 2076
11 nvim get_func_tv + 696
12 nvim eval_func + 380
20 nvim eval_to_string_eap + 276
21 nvim eval_map_expr + 444
22 nvim vgetorpeek + 3172
23 nvim vgetc + 764
Solution:
Apply the string-type check to TTY options too, so a Boolean/special value
gives "E928: String required" instead of aborting. Valid string/number
assignments to `t_*` pseudo-options still silently no-op.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Similar to #36123, the ui2 windows confuse `:$q`, which doesn't close
the last window on the tab, but targets a hidden ui2 window.
The problem seems to be a combination of using
`FOR_ALL_WINDOWS_IN_TAB()`, which includes hidden windows, and then
counting the windows without factoring in `win_has_winnr()`.
There are examples of using `win_has_winnr()`, such as:
- [`eval/buffer.c`'s `buf_win_common()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/buffer.c#L474-L475)
- [`eval/window.c`'s `f_getwininfo()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/window.c#L130-L135)
- [`window.c`'s `win_get_tabwin()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/window.c#L7860-L7869)
But possibly problematic ones:
- `ex_docmd.c`'s:
- [`invalid_range()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/ex_docmd.c#L3891-L3893)
- ^ should this include hidden windows? Can a user address them by number? `win_has_winnr()` suggests not
- [`ex_close()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/ex_docmd.c#L5233-L5244)
- [`ex_hide()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/ex_docmd.c#L5478-L5484)
- `eval/window.c`'s:
- [`f_winrestcmd()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/window.c#L797-L808)
- [`find_win_by_nr()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/window.c#L172-L180)
|