Commit Graph
97 Commits
Author SHA1 Message Date
Lewis Russell 9dd0eeb6ea refactor(help): reuse help.lua to generate build tags
Make gen_helptags.lua call help.lua instead of keeping its own tag
parser. Builds and :helptags now use the same code.

Allow the shared code to run without Neovim, and fail the build when tag
generation reports an error.

AI-assisted
2026-09-10 20:05:49 +01:00
Lewis Russell 515c61f075 perf(fs): defer path joining in find()
Only join paths for matches and entries needed for traversal. This
avoids string processing for rejected files and improves selective
searches across the Neovim tree by about 19-25%.

AI-assisted
2026-09-10 14:57:10 +02:00
Lewis Russell d039f19af5 build: enable more EmmyLua checks
Enable checks for unused code, deprecated calls, return types, and
annotations.

Fix the warnings and replace the deprecated highlight function. Keep
exceptions where old APIs are still needed or the checker gets it wrong.

AI-assisted
2026-09-09 22:31:58 +01:00
Lewis Russell 65ef6fdaee build: replace LuaLS with EmmyLua
Problem: LuaLS struggles with the generics used in Nvim's runtime,
requiring broad diagnostic suppressions. Indexing is also slow.

Solution: Use EmmyLua for type checks in the build and CI. It offers
more sophisticated type checking, substantially better support for
generics, and much better flow analysis.

Correct the affected annotations. Use `@internal`, supported directly by
EmmyLua, instead of `@nodoc` for shared internal declarations, and
support it in the help parser.

AI-assisted
2026-09-07 15:33:22 +01:00
Willaaaaaaa e0e2f978a0 feat(vim.fs): slug() supports URI #41241
Problem:
`vim.fs.slug()` does not handle URIs like `term://foo//123:bash`,
so callers (e.g. terminal persistence) must strip the scheme before
calling `slug()`.

Solution:
Detect `scheme://` from the raw input before `normalize()` and
replace it with a `=uri-<scheme>-` prefix.
2026-08-16 13:29:34 -04:00
Justin M. Keyes 9a93ac6533 refactor(vim.fs): slug() minor cleanup 2026-08-06 10:27:29 +02:00
Justin M. Keyes 7d2249c579 docs: misc, :bcd, slug() 2026-08-06 10:27:29 +02:00
Olivia Kinnear 6107629c5b feat(fs): vim.fs.normalize{plain:boolean} #41127
`opts.plain=true` does not expand tildes in addition to environment
variables, unlike `opts.expand_env=false`.

`opts.expand_env=false` is soft-deprecated.
2026-08-05 16:11:13 -04:00
Willaaaaaaa 7b03df5d54 feat(lua): vim.fs.slug() #41005
Problem:
Several subsystems need to derive a short, filesystem-safe identifier from an
arbitrary path, and each reinvents it ad-hoc:
- `'undodir'` and `swapfiles` encode the full path into a single filename, which
  may exceed filesystem length-limits.
- `:connect ssh://` needs the SSH ControlPath socket name to stay under the
  104-byte `sun_path` limit on macOS; today the path overflows it.
- the upcoming :terminal state dir.
- arbitrary plugin purposes.

Solution:
Provide `vim.fs.slug()`, which generates a bounded, one-way filename from an
arbitrary string. The input is normalized so equivalent paths produce the
same result. An 8-char hash is appended for uniqueness
2026-08-04 15:24:35 -04:00
Justin M. Keyes 98d767cd53 docs: func/expr options, misc #41102 2026-08-01 17:48:32 -04:00
AlexCodesApps b11f1b1f76 feat(vim.fs): abspath({cwd, plain}) #40597
Adds optional parameters to `vim.fs.abspath`:
1. `cwd` to specify directory akin to `--relative-from` in `realpath(1)`.
2. `plain` disables expansion of tilde (~) in paths.
2026-08-01 09:09:21 -04:00
Justin M. Keyes 6cdab150bc docs: misc #41063 2026-07-30 15:09:19 -04:00
Barrett Ruth ac4e5460b1 feat(vim.fs): dir(opts.normalize) 2026-07-25 18:02:55 -05:00
Barrett Ruth cfd7f29d52 feat(vim.fs): vim.fs.mkdir() #40599
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.
2026-07-08 07:16:29 -04:00
Justin M. Keyes 971a0a0fe0 feat(vim.fs): dir() ergonomics 2026-07-01 13:00:06 +02:00
Justin M. Keyes f141916e3d fix(vim.fs): dir(), find() error-reporting 2026-07-01 12:05:41 +02:00
Rudrajeet Pal 4e04dff228 feat(vim.fs): dir(), find() error-reporting
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.
2026-07-01 12:05:41 +02:00
Justin M. Keyes d2073d2eec refactor: cleanup, docs #40480 2026-06-29 13:10:31 -04:00
abdulahmoda 4b5f026ac9 fix(vim.fs): fs.dir() may return nil "type" on some filesystems #39749
Problem:
Currently, only some filesystems (Btrfs, ext2, ext3, ext4) have full
support of accessing the `dirent` entry-type. On other filesystems,
`uv.fs_scandir_next` may return `nil` for an existing but unsupported
entry-type.

This means consumers (such as `fs.dir()`), cannot know if `nil` means
"non-existent" or "unsupported".

Solution:
Fall back to `uv.fs_lstat` when `etype` is `nil`; return "unknown" if it
fails.
2026-05-29 14:24:22 -04:00
Justin M. Keyes c7f5f44b60 refactor(vim.fs): deduplicate by using vim.fn #39782
Problem:
61e99217e6 replaced usages of `vim.fn`. This duplicates non-trivial
logic and may have introduced bugs like 38e38d1b40.

Later on, b02eeb6a72 graduated `fnamemodify` to `fast`, so avoiding it
in `vim.fs` is no longer necessary.

Solution:
Use `vim.fn` to deduplicate `vim.fs.dirname()` and `vim.fs.basename()`.

Note: the "nvim -l" test-runner switch from the original PR (#30483) is
already done by 9432e6c1e2 (#39676).
2026-05-14 13:02:36 -04:00
Justin M. Keyes b70224e3bd docs: misc #39256 2026-04-25 11:16:18 -04:00
Justin M. Keyes 54398c5874 docs: misc #39045 2026-04-18 15:38:59 -04:00
Justin M. Keyes 64d55b74d8 docs: news #38464 2026-03-28 09:59:54 -04:00
Yochem van Rosmalen 72a63346d8 feat(stdlib): vim.fs.ext() returns file extension #36997
Problem:
Checking the extension of a file is done often, e.g. in Nvim's codebase
for differentiating Lua and Vimscript files in the runtime. The current
way to do this in Lua is (1) a Lua pattern match, which has pitfalls
such as not considering filenames starting with a dot, or (2)
fnamemodify() which is both hard to discover and hard to use / read if
not very familiar with the possible modifiers.

vim.fs.ext() returns the file extension including the leading dot of
the extension. Similar to the "file extension" implementation of many
other stdlibs (including fnamemodify(file, ":e")), a leading dot
doesn't indicate the start of the extension. E.g.: the .git folder in a
repository doesn't have the extension .git, but it simply has no
extension, similar to a folder named git or any other filename without
dot(s).
2026-03-20 05:08:00 -04:00
Lewis Russell ce1154048b refactor: integer functions, optimize asserts #34112
refactor(lua): add integer coercion helpers

Add vim._tointeger() and vim._ensure_integer(), including optional base
support, and switch integer-only tonumber()/assert call sites in the Lua
runtime to use them.

This also cleans up related integer parsing in LSP, health, loader, URI,
tohtml, and Treesitter code.

supported by AI
2026-03-12 11:04:05 -04:00
Yochem van Rosmalen dc5d313d66 fix(vim.fs): joinpath() should ignore empty items #38077
Problem:
vim.fs.joinpath treats empty string as a path segment
(it adds a path separator for each empty item):

    print(vim.fs.joinpath('', 'after/lsp', '')) -- '/after/lsp/'
    print(vim.fs.joinpath('', '')) -- '/'

Especially problematic if the empty segment is the first segment, as
that converts the path to an absolute path.

Solution:
Ignore empty (length of 0) path segments.

Benchmark:

    local function test(func)
      local t = vim.uv.hrtime()
      for _ = 1, 100000, 1 do
        func('', 'this/is', 'a/very/long/path', '', 'it', 'really', 'is')
      end
      print(math.floor((vim.uv.hrtime() - t) / 1e6), 'ms')
    end

- with Iter():filter() --> 370 ms
- building new segments table --> 208 ms
- with vim.tbl_filter --> 232 ms
- Instead of gsub split on `/` in all parts --> 1870 ms
2026-02-27 17:45:07 -05:00
Justin M. Keyes 5870627a24 docs: vim.fs path expansion
fix #37583
2026-02-12 13:46:53 +01:00
Evgeni Chasnovski 14c708634e fix(vim.fs): make rm() work with symlink to a directory 2026-02-10 16:40:12 +00:00
phanium dfa5d79d05 fix: misc typos #37471 2026-01-27 09:18:02 -05:00
Jason Shipman 825e182139 fix(vim.fs): avoid fn.fnamemodify in fs.root #37162
Problem: vim.fs.root uses vim.fn.fnamemodify. vim.fn table isn't
available from nvim -ll or thread contexts.

Solution: Swap out vim.fn.fnamemodify for vim.fs.abspath.

This is a temporary workaround and may be reverted since the
long-term plan is to use more fast=true "fn" functions from vim.fs
where possible.
2025-12-30 01:57:06 -05:00
Justin M. Keyes 1f9d9cb2e5 fix(vim.fs): abspath(".") returns "/…/." #36583 2025-11-16 22:36:03 -08:00
Cameron Ring f11f8546e7 fix(vim.fs): root() should always return absolute path #36466 2025-11-16 21:41:26 -08:00
Justin M. Keyes 3f16037e45 docs: getpos, getregion, lsp 2025-11-15 22:47:38 -05:00
Christian Clason c10e36fc01 refactor(lua): consistent use of local aliases 2025-08-28 11:34:01 +02:00
phanium 496691f985 docs: vim.fs.dir.Opts type #34546
Follow the pattern of vim.fs.find.Opts
2025-06-17 07:14:25 -07:00
Justin M. Keyes 8001276bd0 docs: vim.fs., diagnostics, lsp #34402 2025-06-13 07:49:21 -07:00
Siddhant Agarwal 2f0fbdaa48 feat(vim.fs): root() can specify "equal priority" #34276 2025-06-09 09:31:37 -07:00
Justin M. KeyesandMaria José Solano 52a4bc4548 docs: lsp, emoji, startup #33446
Co-authored-by: Maria José Solano <majosolano99@gmail.com>
2025-04-27 13:40:46 -07:00
Mike 6401b433f7 fix(vim.fs): default to follow=false #32859
Problem:
Following symlinks can have surprising behavior and slow performance.

Solution:
Do not set it by default.
2025-03-14 01:36:39 -07:00
Lewis Russell 6aa42e8f92 fix: resolve all remaining LuaLS diagnostics 2025-01-27 16:37:50 +00:00
Mike 611ef35491 feat(vim.fs): find(), dir() can "follow" symlinks #31551
Problem:
vim.fs.dir(), vim.fs.find() do not follow symlinks.

Solution:
- Add "follow" flag.
- Enable it by default.
2025-01-14 16:39:17 -08:00
dundargoc 0631492f9c feat: add vim.fs.relpath
This is needed to replace the nvim-lspconfig function is_descendant that
some lspconfg configurations still use.
2025-01-13 13:14:52 +01:00
dundargoc a8ace2c58a fix(vim.fs.normalize): normalize case for windows drive letter
Also add tests for the current path casing behavior so it doesn't get
accidentally changed.
2025-01-04 21:48:45 +01:00
dundargoc 6dc0eb9f41 fix(vim.fs.abspath): correctly handle UNC paths 2025-01-01 23:42:42 +01:00
Justin M. Keyes dc692f553a docs: misc #31479 2025-01-01 12:29:51 -08:00
Gustav Eikaas 0bef3b911c fix(vim.fs): joinpath() does not normalize slashes on Windows #31782 2024-12-31 07:40:05 -08:00
Famiu Haque 5180707310 feat(lua): add vim.fs.abspath
Problem: There is currently no way to check if a given path is absolute or convert a relative path to an absolute path through the Lua stdlib. `vim.fs.joinpath` does not work when the path is absolute. There is also currently no way to resolve `C:foo\bar` style paths in Windows.

Solution: Add `vim.fs.abspath`, which allows converting any path to an absolute path. This also allows checking if current path is absolute by doing `vim.fs.abspath(path) == path`. It also has support for `C:foo\bar` style paths in Windows.
2024-12-28 11:40:39 +01:00
dundargoc 76dcc7029b docs: add tag vim.fs.exists() and document suggested replacement 2024-11-27 19:56:08 +01:00
Lewis Russell 3572319b4c feat(vim.validate): improve fast form and deprecate spec form
Problem:

`vim.validate()` takes two forms when it only needs one.

Solution:

- Teach the fast form all the features of the spec form.
- Deprecate the spec form.
- General optimizations for both forms.
- Add a `message` argument which can be used alongside or in place
  of the `optional` argument.
2024-10-21 11:32:06 +01:00
Lewis Russell 3f3e4837d5 perf(validate): use lighter version
- Also fix `vim.validate()` for PUC Lua when showing errors for values
  that aren't string or number.
2024-10-17 16:53:52 +01:00