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

Add support for path completion #2608

Merged
merged 19 commits into from
Nov 22, 2024

Conversation

Philipp-M
Copy link
Contributor

@Philipp-M Philipp-M commented May 29, 2022

This PR adds support for path completion.

It supports the following:

  • Autocompletion is triggered with /.
  • Documentation preview (file permissions, canonicalized path).
  • shell expansion (e.g. ~/path, $HOME/path, ${HOME}/path)
  • Async (via spawn_blocking instead of tokios file accessor functions, as they IMHO make the code less readable and are quite a bit slower than just spawning a "thread")
  • Configurable with editor.path-completion (default true), per-language overrideable path-completion support
  • Refactors goto_file with a new more robust path-detection/resolution mechanism and also adds shell-expansion.

A baby-step towards #1015

@kirawi
Copy link
Member

kirawi commented May 30, 2022

I think it would be better to split off the changes to the LSP into a separate PR. Unless completion is dependent upon them?

@Philipp-M
Copy link
Contributor Author

You mean all the commits that are also in #2507?

In case, I will rebase this as soon as the relevant commits this PR is dependent on are on master, currently only the last commit is relevant for this PR or different to #2507.

@the-mikedavis the-mikedavis linked an issue Jun 25, 2022 that may be closed by this pull request
@nrdxp
Copy link
Contributor

nrdxp commented Jun 29, 2022

just fyi, tried to rebase this on master for my own use and even though there was only a minor merge conflict in the languages.toml, it doesn't actually build after the changes made in #2738

If trying to use your new macro where the old language_server! was called I get a type error:

error[E0277]: `(dyn for<'r, 's, 't0> FnOnce(&'r mut compositor::Compositor, &'s mut compositor::Context<'t0>) + 'static)` cannot be sent between threads safely
   --> helix-term/src/commands/lsp.rs:848:8
    |
848 |     cx.callback(
    |        ^^^^^^^^ `(dyn for<'r, 's, 't0> FnOnce(&'r mut compositor::Compositor, &'s mut compositor::Context<'t0>) + 'static)` cannot be sent between threads safely

@Philipp-M
Copy link
Contributor Author

Rebased to current master and fixed the issue (the acquire for the language-server inside the closure was unnecessary as only the offset-encoding is required there)

@nrdxp
Copy link
Contributor

nrdxp commented Jul 9, 2022

What is left to move this out of draft status? I've been using this for over a week now and it seems to work fine.

@Philipp-M
Copy link
Contributor Author

Well for one (biggest blocker): This is currently dependent on a few commits (particularly the extension/merging of the completion menu) of #2507, and I'm unsure how to progress as I'm awaiting some feedback there.

Also support for windows paths should be added, this should be simple (by extending the path regex), but I would like to first resolve the first issue.

Another (smaller, maybe not worth to fix) issue is, that currently only one path per line is possible, this could probably be tackled with a different path-regex. But I've read that every character but \0 is allowed in a unix filepath, so I think it's difficult to find a good regex that doesn't have (realworld) limitations.

I've also experimented with async io (via tokio::fs), but IMHO the performance-drop and probably race-conditions (in the completion menu, if writing to fast/slow IO) wasn't worth it to continue that path (yet).

@kirawi kirawi added A-helix-term Area: Helix term improvements S-experimental Status: Ongoing experiment that does not require reviewing and won't be merged in its current state. labels Sep 13, 2022
@Philipp-M Philipp-M force-pushed the path-completion branch 2 times, most recently from e224b0d to 1dc2381 Compare September 26, 2022 21:32
let items = ui::PATH_REGEX
.find(&line_until_cursor)
.and_then(|matched_path| {
let matched_path = matched_path.as_str();
Copy link
Contributor

@cole-h cole-h Nov 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to also add a denylist setting? I run NixOS, so attempting to index /nix/store would be extremely slow with its (currently) ~265000 files / directories.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can just use the .(git)ignore for that?

Actually I've used nix/store for stress testing/general feeling, and I thought it was acceptable given the amount of files (but I've got a fast CPU and NVME drive for /nix ...))

Would someone actually edit something directly in /nix/store or in a directory with that much files/folders?

I'm not sure of a daily usecase currently where this would really be a problem, but I'm open for different solutions (my suggestion would be a global .ignore)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't edit things in the Nix store, no, but I do use Helix to read files in there very frequently. I'd rather not use a .ignore for that because so many other tools read that, and I'd like to set this only in Helix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it's less of a blocker (literally :)) for typing, as it's now async and results will be discarded when not relevant anymore (i.e. the user has typed something that doesn't match the completion item).

On a fast computer it's still acceptable IMHO, especially if the folder was indexed once (i.e. is likely cached in memory when accessing again)).

If this is still relevant, can you/someone maybe think/prototype how the UX/configuration for this look like (I'm happy to implement it, but I'm not sure how the UI for this should look like).

But the (completion-)menu is quite slow with > ~100k entries that are sorted synchronously every keystroke.
I think a more sophisticated lazier/async/"streamable" menu/picker implementation would be probably help in general (I still think that the behavior is so similar (also in the future), that the implementations should be shared, but that's a different topic...).

@Philipp-M Philipp-M force-pushed the path-completion branch 3 times, most recently from 7435f08 to b594f49 Compare November 25, 2022 00:16
@nrdxp
Copy link
Contributor

nrdxp commented Jan 26, 2023

Did something change? After rebasing on the last push path completion seems to have just stopped working all together. Do I need to configure something differently?

@Philipp-M
Copy link
Contributor Author

Have you tried using the HEAD of this branch?

My personal fork (rebased on this branch) is still working.

It's a little bit out of sync with master, I will try to find time soon to rebase this and the multiple-language-servers PR onto master.

@nrdxp
Copy link
Contributor

nrdxp commented Jan 27, 2023

Oops, I figured it out. It was my own fault, I forgot to push my latest changes of my forked branch (based on this branch) to the remote so my system never pulled my rebase. Apologies 🙏

@pascalkuthe
Copy link
Member

pushed to this branch by accident, sorry about that I reverted the change (not clear in github UI)

Axlefublr added a commit to Axlefublr/helix that referenced this pull request Oct 8, 2024
Adds support for path completion for unix paths

* Autocompletion is triggered with `/`.
* Documentation preview (file type, file permissions, canonicalized full path).
* Home-path resolution (`~/path`, `$HOME/path`, `${HOME}/path`)
* Link resolution (makes sense for preview, since the LSP specification (`CompletionItemKind`) only supports files and folders but not symlinks)
* Async (via `spawn_blocking` instead of tokios file accessor functions, as they IMHO make the code less readable and are quite a bit slower than just spawning a "thread")
* Configurable with `editor.path-completion` (default `true`), per-language overrideable path-completion support

Handle windows CI

Micro-optimization and revert of composing additional text edits

Use `PartialEq` for `LspCompletionItem` and don't prefix-filter path completion items

Apply suggestions from code review

Co-authored-by: Michael Davis <[email protected]>

Apply suggestions from code review

Fix cargo fmt

Fix byte offsets in `matched_path`
@Philipp-M Philipp-M changed the title Add support for path completion for unix paths Add support for path completion Oct 14, 2024
@Philipp-M
Copy link
Contributor Author

AFAICS path detection + shell-expansion should now be quite a bit more robust with @pascalkuthe s changes, and should also support windows.
I have no (easy) way currently test this though, so real-world testing would be appreciated.

@the-mikedavis the-mikedavis added S-waiting-on-review Status: Awaiting review from a maintainer. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 14, 2024
Copy link
Member

@pascalkuthe pascalkuthe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is starting to look pretty good, thanks for addressing my comments! I found a couple smaller things but hopefully should be ready soon

@@ -196,6 +202,7 @@ fn request_completion(
// necessary from our side too.
trigger.pos = cursor;
let trigger_text = text.slice(..cursor);
let cancel_completion = Arc::new(AtomicBool::new(false));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to build custom synchronization code here around atomic. What you did is reasonable but I want it to be part of a single cancelation token implementation. I thought our cancelation token was already clonable when I made that comment but seems I misremembered.

I already have a specific implementation in mind (a simplified variant if the tokio-utils cancelation token). I am currently on vacation but I will send a PR for that to your branch once I get back (unless you want to /get around to implementing that first)

Copy link
Contributor Author

@Philipp-M Philipp-M Oct 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can wait for your PR, thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put up a PR, ended up a bit more complex than I thaught but I am very happy with it. After looking at it I also did a lot of "quick hacks" like this that weren't really wrong but are better centralized in dedicated shared code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, probably better to have this a little bit more encapsulated.

helix-term/src/handlers/completion.rs Outdated Show resolved Hide resolved
helix-term/src/handlers/completion/path.rs Show resolved Hide resolved
helix-term/src/handlers/completion/path.rs Outdated Show resolved Hide resolved
@David-Else
Copy link
Contributor

When using the % macro with this branch the home directory is not included: #12002.

Check this out with a file in your Linux home directory:

[keys.normal.space]
o = "@:o <C-r>%<C-w>"

@Philipp-M
Copy link
Contributor Author

Philipp-M commented Nov 5, 2024

I'm not sure what the expected outcome is, or whether this is a bug at all?

I've compared the path-completion branch with current master and it seems to have the same behavior for me.
I don't think there should be any difference to master for this macro reasoning from the code as the new shell-expansion doesn't seem to be used in the open impl.

Nice macro btw.

@David-Else
Copy link
Contributor

@Philipp-M I don't think it is a problem or a bug, chatting about it in the linked discussion.

Copy link
Member

@the-mikedavis the-mikedavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First thanks for working on this @Philipp-M and especially for keeping the branch alive for so long1! 😀

I've been running this locally for a few weeks now and I'm pretty sure it's good to go. I'd like to merge it down and have it sit in master for a while to eek out any bugs we might've introduced in the completion changes. I might've felt a change in the ranges we replace with a completion, but this might be a rust-analyzer peculiarity or me imagining things so I don't want it to block the merge. I'd like to see more eyes from anyone running master before a possible December release.

Using this in some Nix files and, nicely, Cargo.tomls has been quite nice. Thanks again @Philipp-M! (And completion and regex improvements from @pascalkuthe ofc :)

This is one small step for non-LSP completions and one giant leap for moving the codebase away from its very close relationship with LSP 🚀

Footnotes

  1. Some of the other PRs merged recently have been 10,000 + this PR's number 😅

@the-mikedavis the-mikedavis merged commit dc941d6 into helix-editor:master Nov 22, 2024
6 checks passed
@RoloEdits
Copy link
Contributor

@the-mikedavis I have also been experiencing some issues with rust-analyzer, without this branch's changes, which I expanded on more in #11933. So shouldn't have anything to do with this pr.

@RoloEdits
Copy link
Contributor

I did notice that the msrv was broken though. Some of the OsStr stuff needs rust 1.74.0

warning: current MSRV (Minimum Supported Rust Version) is `1.70.0` but this item is stable since `1.74.0`
  --> helix-stdx\src\env.rs:98:21
   |
98 |     let bytes = src.as_encoded_bytes();
   |                     ^^^^^^^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv
   = note: `#[warn(clippy::incompatible_msrv)]` on by default

warning: current MSRV (Minimum Supported Rust Version) is `1.70.0` but this item is stable since `1.74.0`
   --> helix-stdx\src\env.rs:117:28
    |
117 |         let var = unsafe { OsStr::from_encoded_bytes_unchecked(var) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv

warning: current MSRV (Minimum Supported Rust Version) is `1.70.0` but this item is stable since `1.74.0`
   --> helix-stdx\src\env.rs:124:25
    |
124 |                     val.as_encoded_bytes()
    |                         ^^^^^^^^^^^^^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv

warning: current MSRV (Minimum Supported Rust Version) is `1.70.0` but this item is stable since `1.74.0`
   --> helix-stdx\src\env.rs:138:18
    |
138 |         unsafe { OsString::from_encoded_bytes_unchecked(res) }.into()
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv

@poliorcetics
Copy link
Contributor

IIRC Helix uses Firefox's MRSV ? It's currently 1.76.0 (https://firefox-source-docs.mozilla.org/writing-rust-code/update-policy.html) so we could just increase it

@Philipp-M Philipp-M deleted the path-completion branch November 22, 2024 10:40
@Philipp-M Philipp-M mentioned this pull request Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-helix-term Area: Helix term improvements S-waiting-on-review Status: Awaiting review from a maintainer.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

autocompleting file paths