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

Windows Support [WIP] #1001

Closed
wants to merge 3 commits into from
Closed

Windows Support [WIP] #1001

wants to merge 3 commits into from

Conversation

TheLeoP
Copy link
Contributor

@TheLeoP TheLeoP commented Jan 15, 2024

This intended to continue the work of #961.

TODO:

  • Why does Fzflua buffers not work with ctrl-n and ctrl-p?
  • Add support for quickstart on Windows
  • Check if shell is cmd.exe, not only if os is windows (support posix shells on windows?)
  • ???

TheLeoP and others added 3 commits January 14, 2024 13:54
refactor: retire complex windows escaping logic
refactor: fzf `--multi` option
refactor: path module (+added tests)
fix: misc fixes for windows
fix: cwd header test
fix: path.starts_with_separator
fix: git commits|bcommits
fix: git_diff previewer `sh -c` -> `cmd`
fix: profiles, help_tags
chore: lua_ls warnings, format luarc.json with prettier
@TheLeoP
Copy link
Contributor Author

TheLeoP commented Jan 15, 2024

@ibhagwan. Is there something I can help you with right now? If no, I can continue checking that all Fzflua comands are working as expected.

All the changes seem great, I'll check the test on my Linux environment because, last time I checked, PlenaryBusted did not have support for windows :c.

@ibhagwan
Copy link
Owner

ibhagwan commented Jan 15, 2024

Is there something I can help you with right now? If no, I can continue checking that all Fzflua comands are working as expected.

Whatever you can think of, certainly you can let me know which commands do not work properly and we can add them to the TODO list.

If you're up to up you can also write tests for libuv.shellescape, just recently I found out a flaw in the logic whereas if the path ended in \ the resulting escaped string would be invalid as explained in the comment below:

-- adjust when escaping a string that ends with a blackslash
-- otherwise the ending sequence will appear as a literal quote
-- and will be missing the end quotes
-- c:\foo\ -> "c:\foo\" // WRONG
-- c:\foo\ -> "c:\foo\\" // RIGHT

last time I checked, nvim-lua/plenary.nvim#255 :c.

Pleanary busted works on my windows VM:
image

4e01b21 - latest commit a few minutes ago added support for listing files with the dir command (so we're not dependent on having rg|fd installed) and also fixed path_shorten (the command I ran is in the bottom of the screenshot):
image

@TheLeoP
Copy link
Contributor Author

TheLeoP commented Jan 15, 2024

If you're up to up you can also write tests for libuv.shellescape, just recently I found out a flaw in the logic whereas if the path ended in \ the resulting escaped string would be invalid as explained in the comment below:

Would it be ok to allways use / for paths on commands? Or would it better to add a pair of additional \ if a path ends witt \?

Pleanary busted works on my windows VM:

Oh, you are right, I just tested it :o. Those are awesome news.

@ibhagwan
Copy link
Owner

Would it be ok to allways use / for paths on commands? Or would it better to add a pair of additional \ if a path ends witt \?

Not sure if I understand your question properly, I think it would be ok to use / for all paths that are hidden from the user (is that what you mean by "commands"?) but if the user specifically requested say :FzfLua files cwd=c:\... I'd still prefer to display the paths unchanged from the users' request.

@ibhagwan
Copy link
Owner

ibhagwan commented Jan 15, 2024

If you take a look at tests\path_spec.lua you'll see I have all kinds of tests for different separator combos, the new path module logic considers both \ and / as valid separators on windows (even mixed and matched inside one path e.g. c:\some/path) and also semi-heuristics do determine which separator style to add if one is needed:

M.separator = function(path)
-- auto-detect separator from fully qualified paths, e.g. "C:\..." or "~/..."
if utils.__IS_WINDOWS and path then
local maybe_separators = { string_byte(path, 3), string_byte(path, 2) }
for _, s in ipairs(maybe_separators) do
if M.byte_is_separator(s) then
return string.char(s)
end
end
end
return string.char(utils._if_win(M.bslash_byte, M.fslash_byte))
end

Edit: Btw, I haven't finished the rewrite of the path module, I still wish to revamp entry_to_file.

@ibhagwan
Copy link
Owner

@TheLeoP, shouldn't change much as you didn't add new commits yet, just FYI that I rebased the windows branch again after the recent commits.

@ibhagwan ibhagwan force-pushed the windows branch 17 times, most recently from d39677f to 7b9069f Compare January 28, 2024 04:16
@ibhagwan
Copy link
Owner

ibhagwan commented Jan 28, 2024

@TheLeoP, I know I've said this beore but I think I've nailed it, the perfect windows escape logic for CMD.exe which is a combined approach of blackslahes and carets.

If you want you can get a glimpse of windows going full retard at tests\libuv_spec.lua:

it("shellescape (win caret)", function()
assert.are.same(libuv.shellescape([[]], 2), [[^"^"]])
assert.are.same(libuv.shellescape([["]], 2), [[^"\^"^"]])
assert.are.same(libuv.shellescape([[^"]], 2), [[^"^^\^"^"]])
assert.are.same(libuv.shellescape([[\"]], 2), [[^"\\\^"^"]])
assert.are.same(libuv.shellescape([[\^"]], 2), [[^"^^\\\^"^"]])
assert.are.same(libuv.shellescape([[^"^"]], 2), [[^"^^\^"^^\^"^"]])
assert.are.same(libuv.shellescape([[__^^"^"__]], 2), [[^"__^^^^\^"^^\^"__^"]])
assert.are.same(libuv.shellescape([[__!^^"^"__]], 2),
-- 1st: ^"_^!^^^^\^"^^\^"_^"
-- 2nd: ^"_^^^!^^^^^^^^^^\\\^"^^^^^^\\\^"_^"
[[^"__^^^!^^^^^^^^^^\\\^"^^^^^^\\\^"__^"]])
assert.are.same(libuv.shellescape([[__^^^^\^"^^\^"__]], 2),
[[^"__^^^^^^^^^^\\\^"^^^^^^\\\^"__^"]])
assert.are.same(libuv.shellescape([[^]], 2), [[^"^^^"]])
assert.are.same(libuv.shellescape([[^^]], 2), [[^"^^^^^"]])
assert.are.same(libuv.shellescape([[^^^]], 2), [[^"^^^^^^^"]])
assert.are.same(libuv.shellescape([[^!^]], 2), [[^"^^^^^^^!^^^^^"]])
assert.are.same(libuv.shellescape([[!^"]], 2),
-- 1st inner: ^!^^\^"
-- 2nd inner: ^^^!^^^^^^\\\^"
[[^"^^^!^^^^^^\\\^"^"]])
assert.are.same(libuv.shellescape([[!\"]], 2), [[^"^^^!^^\\\\\\\^"^"]])
assert.are.same(libuv.shellescape([[!\^"]], 2), [[^"^^^!^^^^^^\\\\\\\^"^"]])
assert.are.same(libuv.shellescape([[()%^"<>&|]], 2), [[^"^(^)^%^^\^"^<^>^&^|^"]])
assert.are.same(libuv.shellescape([[()%^"<>&|!]], 2),
-- 1st inner: ^(^)^%^^\^"^<^>^&^|^!
-- 2nd inner: ^^^(^^^)^^^%^^^^^^\^"^^^<^^^>^^^&^^^|^^^!
[[^"^^^(^^^)^^^%^^^^^^\\\^"^^^<^^^>^^^&^^^|^^^!^"]])
assert.are.same(libuv.shellescape([[foo]], 2), [[^"foo^"]])
assert.are.same(libuv.shellescape([[foo\]], 2), [[^"foo\\^"]])
assert.are.same(libuv.shellescape([[foo^]], 2), [[^"foo^^^"]])
assert.are.same(libuv.shellescape([[foo\\]], 2), [[^"foo\\\\^"]])
assert.are.same(libuv.shellescape([[foo\\\]], 2), [[^"foo\\\\\\^"]])
assert.are.same(libuv.shellescape([[foo\\\\]], 2), [[^"foo\\\\\\\\^"]])
assert.are.same(libuv.shellescape([[f!oo]], 2), [[^"f^^^!oo^"]])
assert.are.same(libuv.shellescape([[^"foo^"]], 2), [[^"^^\^"foo^^\^"^"]])
assert.are.same(libuv.shellescape([[\^"foo\^"]], 2), [[^"^^\\\^"foo^^\\\^"^"]])
assert.are.same(libuv.shellescape([[foo""bar]], 2), [[^"foo\^"\^"bar^"]])
assert.are.same(libuv.shellescape([[foo^"^"bar]], 2), [[^"foo^^\^"^^\^"bar^"]])
assert.are.same(libuv.shellescape([["foo\"bar"]], 2), [[^"\^"foo\\\^"bar\^"^"]])
assert.are.same(libuv.shellescape([[foo\^"]], 2), [[^"foo^^\\\^"^"]])
assert.are.same(libuv.shellescape([[foo\"]], 2), [[^"foo\\\^"^"]])
assert.are.same(libuv.shellescape([[^"foo\^"^"]], 2), [[^"^^\^"foo^^\\\^"^^\^"^"]])
assert.are.same(libuv.shellescape([[foo\"bar]], 2), [[^"foo\\\^"bar^"]])
assert.are.same(libuv.shellescape([[foo\\"bar]], 2), [[^"foo\\\\\^"bar^"]])
assert.are.same(libuv.shellescape([[foo\\^^"bar]], 2), [[^"foo\\^^^^\^"bar^"]])
assert.are.same(libuv.shellescape([[foo\\\^^^"]], 2), [[^"foo\\\^^^^^^\^"^"]])

Once libuv.shellescape and the path module was figured it seems to smooth sailing as not too many adjustments need to be done, other than extra dumb windows suff such as having to double the escape sequences if ! is found anywhere in the command:

if utils.__IS_WINDOWS and opts.cmd:match("!") then
-- https://ss64.com/nt/syntax-esc.html
-- This changes slightly if you are running with DelayedExpansion of variables:
-- if any part of the command line includes an '!' then CMD will escape a second
-- time, so ^^^^ will become ^
opts.cmd = opts.cmd:gsub('[%(%)%%!%^<>&|"]', function(x)
return "^" .. x
end)

I'm a bit tired so I didn't test everything fully (which I intend to invest time in tomorrow) but I think it's fair to say I'm getting close to finalizing the windows code which I also utilized for general improvements (base64 encoding of the arguments, code dedup where possible, etc).

My plan is to make a list of pickers and options to test and make sure these work on Mac/Linux/Windows, e.g.:

  • Files
    • cwd
    • cwd_prompt
    • previewer: builtin
    • previewer: bat
    • dir (no rg/fd installed)
    • rg (no fd installed)
    • fd
    • file_ignore_patterns
    • multiprocess (true/false)

Would be appreicated if you can do some rudimentary testing and lmk if the code is on the right track and works on your environment as it works on mine?

@ibhagwan ibhagwan force-pushed the windows branch 2 times, most recently from d22828e to 089ec99 Compare January 28, 2024 14:33
@ibhagwan ibhagwan force-pushed the windows branch 13 times, most recently from 9065879 to 8bf3b5e Compare February 4, 2024 19:44
@ibhagwan ibhagwan force-pushed the windows branch 15 times, most recently from 97ab3d5 to a038250 Compare February 11, 2024 23:38
@ibhagwan
Copy link
Owner

This PR is mainly used for tracking, since I'm getitng closer to releasing the windows branch for beta testing I'm going to close this PR and continue tracking in #1038.

Once fully merged your original contribution from #961 will retain it's authorship and be merged to main under your name.

@ibhagwan ibhagwan closed this Feb 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants