77 Commits

Author SHA1 Message Date
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. Keyes 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
Justin M. Keyes 9a5bbaf813 docs: more @since annotations #30660 2024-10-04 08:12:17 -07:00
Justin M. Keyes 47e6b2233f fix(vim.fs): dirname() returns "." on mingw/msys2 #30480
Problem:
`vim.fs.dirname([[C:\User\XXX\AppData\Local]])` returns "." on
mingw/msys2.

Solution:
- Check for "mingw" when deciding `iswin`.
- Use `has("win32")` where possible, it works in "fast" contexts since
  b02eeb6a72.
2024-09-23 06:05:58 -07:00
Lewis Russell 511b991e66 feat(fs.lua): add vim.fs.rm()
Analogous to the shell `rm` command.
2024-09-22 15:05:24 +01:00
Gregory Anders 206f8f24a2 fix(fs): make vim.fs.root work for relative paths and unnamed buffers (#28964)
If a buffer does not have a backing file then fall back to the current
working directory.
2024-05-24 10:48:32 -05:00
Lewis Russell 14a5813c20 perf(vim.fs.normalize): use iterator
~10% faster.
2024-05-15 12:38:26 +01:00
Lewis Russell dcdefd0428 perf(loader): use a quicker version of vim.fs.normalize
Problem:

vim.fs.normalize() normalizes too much vim.loader and is slow.

Solution:

Make it faster by doing less. This reduces the times spent in
vim.fs.normalize in vim.loader from ~13ms -> 1-2ms.

Numbers from a relative benchmark:
- Skipping `vim.validate()`: 285ms -> 230ms
- Skipping `path_resolve_dot()`: 285ms -> 60ms
- Skipping `double_slash`: 60ms -> 35ms
2024-05-15 12:38:26 +01:00
Mathias Fussenegger 8bb67d64e2 perf(fs): normalize path only once in fs.dir
Re-normalizing a path after a `joinpath` isn't necessary. Calling
`normalize` on each child directory had quite a bit of impact when
traversing a large directory.

A simple test showed:

Before: ~144ms
After: ~80ms

running the following logic against a dir with 4367 child folders and
25826 files:

    local files = {}
    local start = uv.hrtime()
    for name, type in vim.fs.dir(path, { depth = max_depth }) do
      table.insert(files, { name, type })
    end
    local duration = uv.hrtime() - start

Relates to https://github.com/neovim/neovim/issues/23291
2024-05-14 09:42:10 +01:00
Gregory Anders 38b9c322c9 feat(fs): add vim.fs.root (#28477)
vim.fs.root() is a function for finding a project root relative to a
buffer using one or more "root markers". This is useful for LSP and
could be useful for other "projects" designs, as well as for any plugins
which work with a "projects" concept.
2024-04-24 21:43:46 -05:00
Famiu Haque 8e5c48b08d feat(lua): vim.fs.normalize() resolves ".", ".." #28203
Problem:
`vim.fs.normalize` does not resolve `.` and `..` components. This makes
no sense as the entire point of normalization is to remove redundancy
from the path. The path normalization functions in several other
languages (Java, Python, C++, etc.) also resolve `.` and `..`
components.

Reference:
- Python: https://docs.python.org/3/library/os.path.html#os.path.normpath
- Java: https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html#normalize--
- C++: https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal

Solution:
Resolve "." and ".." in `vim.fs.normalize`.

    Before:
    "~/foo/bar/../baz/./" => "~/foo/bar/../baz/."
    After:
    "~/foo/bar/../baz/./" => "~/foo/baz"
2024-04-16 12:13:44 -07:00
dundargoc 2424c3e696 fix: support UNC paths in vim.fs.normalize
Closes https://github.com/neovim/neovim/issues/27068.
2024-03-30 00:51:09 +01:00
James Trew 38e38d1b40 fix(fs): allow backslash characters in unix paths
Backslashes are valid characters in unix style paths.

Fix the conversion of backslashes to forward slashes in several `vim.fs`
functions when not on Windows. On Windows, backslashes will still be converted
to forward slashes.
2024-03-29 17:23:01 +01:00
altermo ae5095cac9 fix(fs): use generics for better typing 2024-03-06 21:56:47 +00:00
Lewis Russell ea44f74d84 refactor(types): more fixes 2024-03-06 10:45:22 +00:00
Lewis Russell a5fe8f59d9 docs: improve/add documentation of Lua types
- Added `@inlinedoc` so single use Lua types can be inlined into the
  functions docs. E.g.

  ```lua
  --- @class myopts
  --- @inlinedoc
  ---
  --- Documentation for some field
  --- @field somefield integer

  --- @param opts myOpts
  function foo(opts)
  end
  ```

  Will be rendered as

  ```
  foo(opts)

    Parameters:
      - {opts} (table) Object with the fields:
               - somefield (integer) Documentation
                 for some field
  ```

- Marked many classes with with `@nodoc` or `(private)`.
  We can eventually introduce these when we want to.
2024-03-01 23:02:18 +00:00
Lewis Russell 9beb40a4db feat(docs): replace lua2dox.lua
Problem:

The documentation flow (`gen_vimdoc.py`) has several issues:
- it's not very versatile
- depends on doxygen
- doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C.
- The intermediate XML files and filters makes it too much like a rube goldberg machine.

Solution:

Re-implement the flow using Lua, LPEG and treesitter.

- `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic.
- `lua2dox.lua` is gone!
- No more XML files.
- Doxygen is now longer used and instead we now use:
  - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`).
  - LPEG for C parsing (see `scripts/cdoc_parser.lua`)
  - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`).
  - Treesitter for Markdown parsing (see `scripts/text_utils.lua`).
- The generated `runtime/doc/*.mpack` files have been removed.
   - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly.
- Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change).
2024-02-27 14:41:17 +00:00
Gregory Anders 2e92065686 docs: replace <pre> with ``` (#25136) 2023-09-14 08:23:01 -05:00
Lewis Russell 37c58226a8 fix(lua): vim.fs typing (#24608) 2023-08-08 11:58:29 +01:00
futsuuu 86ce3878d6 docs(lua): clarify fs.find() documentation #24394 2023-07-19 09:55:35 -07:00
Lewis Russell be74807eef docs(lua): more improvements (#24387)
* docs(lua): teach lua2dox how to table

* docs(lua): teach gen_vimdoc.py about local functions

No more need to mark local functions with @private

* docs(lua): mention @nodoc and @meta in dev-lua-doc

* fixup!

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>

---------

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2023-07-18 15:42:30 +01:00
Mike e4da418ba8 fix(fs.lua): normalize slash truncation (#23753)
Preserve last slash in windows' root drive directories
2023-07-18 14:36:04 +08:00