Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vim.glob.to_lpeg doesn't always work as expected #28931

Closed
faergeek opened this issue May 23, 2024 · 4 comments · Fixed by #29236
Closed

vim.glob.to_lpeg doesn't always work as expected #28931

faergeek opened this issue May 23, 2024 · 4 comments · Fixed by #29236
Labels
bug issues reporting wrong behavior lua stdlib
Milestone

Comments

@faergeek
Copy link
Contributor

faergeek commented May 23, 2024

Problem

Group conditions do not properly work when there are multiple groups starting with the same substring and the shorter one appears earlier.

For example, vim.glob.to_lpeg('**/*.{tsx,ts}'):match('test.tsx') matches, but vim.glob.to_lpeg('**/*.{ts,tsx}'):match('test.tsx') doesn't

Steps to reproduce

  1. nvim --clean
  2. :lua=vim.glob.to_lpeg('**/*.{tsx,ts}'):match('test.tsx') (returns 9)
  3. :lua=vim.glob.to_lpeg('**/*.{ts,tsx}'):match('test.tsx') (returns nil)

Expected behavior

Both of the globs match.

Neovim version (nvim -v)

v0.11.0-dev-57+gcd48b72b6

Vim (not Nvim) behaves the same?

n/a

Operating system/version

Arch Linux

Terminal name/version

kitty 0.34.1

$TERM environment variable

xterm-kitty

Installation

build from repo

@faergeek faergeek added the bug issues reporting wrong behavior label May 23, 2024
@zeertzjq zeertzjq added the lua stdlib label May 23, 2024
@faergeek
Copy link
Contributor Author

Patch with added tests for a particular glob with which I discovered the issue:

diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua
index 56cd4c9bb..383e66d33 100644
--- a/test/functional/lua/glob_spec.lua
+++ b/test/functional/lua/glob_spec.lua
@@ -223,6 +223,17 @@ describe('glob', function()
       eq(true, match('{[0-9],[a-z]}', '0'))
       eq(true, match('{[0-9],[a-z]}', 'a'))
       eq(false, match('{[0-9],[a-z]}', 'A'))
+
+      -- glob is from willRename filter in typescript-language-server
+      -- https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/src/lsp-server.ts#L266
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.js'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.ts'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mts'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mjs'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cjs'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cts'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.jsx'))
+      eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.tsx'))
     end)
   end)
 end)

Only last 2 cases do not match.

Not sure if I'll be able to figure out how to fix that myself.

@justinmk
Copy link
Member

@stevearc

@stevearc
Copy link
Sponsor Contributor

stevearc commented Jun 6, 2024

I didn't write the lpeg grammar, I merely moved it into the current file. It was added by @nojnhuh in #23788. I spent some time poking around; this seems to be a problem with greedy matching the first option in the list.

-- this fails
eq(true, match('**/*.{ts,tsx}', 'test.tsx'))
-- this succeeds
eq(true, match('**/*.{tsx,ts}', 'test.tsx'))
-- this also succeeds
eq(true, match('**/*.{tsx,ts}', 'test.ts'))

I have no idea how to fix this using purely lpeg. Intuitively I want to take the list of items inside the {} and sort them descending by length, but I couldn't figure out how to make that happen inside the lpeg expression.

@brynne8
Copy link

brynne8 commented Jun 6, 2024

I'm very sure why this happens. It's because vim.glob simply translates regex a | b into a + b, which is incorrect, since it means ordered choice in PEG. Also check the discussion: #29199

nojnhuh added a commit to nojnhuh/neovim that referenced this issue Jun 8, 2024
This change fixes an issue where glob patterns like `{a,ab}` would not
match `ab` because the first option `a` matches, then the end of the
string is expected but `b` is found, and LPeg does not backtrack to try
the next option `ab` which would match. The fix here is to also append
the rest of the pattern to the generated LPeg pattern for each option.
This changes a glob `{a,ab}` from being parsed as

    ("a" or "ab") "end of string"

to

    ("a" "end of string" or "ab" "end of string")

Here, matching against `ab` would try the first option, fail to match,
then proceed to the next option, and match.

The sacrifice this change makes is dropping support for nested `{}`
conditions, which VSCode doesn't seem to support or test AFAICT.

Fixes neovim#28931

Co-authored-by: Sergey Slipchenko <[email protected]>
justinmk pushed a commit that referenced this issue Jun 10, 2024
This change fixes an issue where glob patterns like `{a,ab}` would not
match `ab` because the first option `a` matches, then the end of the
string is expected but `b` is found, and LPeg does not backtrack to try
the next option `ab` which would match. The fix here is to also append
the rest of the pattern to the generated LPeg pattern for each option.
This changes a glob `{a,ab}` from being parsed as

    ("a" or "ab") "end of string"

to

    ("a" "end of string" or "ab" "end of string")

Here, matching against `ab` would try the first option, fail to match,
then proceed to the next option, and match.

The sacrifice this change makes is dropping support for nested `{}`
conditions, which VSCode doesn't seem to support or test AFAICT.

Fixes #28931

Co-authored-by: Sergey Slipchenko <[email protected]>
@justinmk justinmk added this to the 0.11 milestone Jun 10, 2024
TheLeoP added a commit to TheLeoP/neovim that referenced this issue Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug issues reporting wrong behavior lua stdlib
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants