-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
base: master
Are you sure you want to change the base?
Conversation
I think it would be better to split off the changes to the LSP into a separate PR. Unless completion is dependent upon them? |
e325640
to
d4dfb7d
Compare
d4dfb7d
to
bc62cb1
Compare
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
|
bc62cb1
to
0865642
Compare
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) |
0865642
to
f5ae055
Compare
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. |
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 I've also experimented with async io (via |
f5ae055
to
344f3d4
Compare
344f3d4
to
24dff03
Compare
24dff03
to
354ac33
Compare
e224b0d
to
1dc2381
Compare
1dc2381
to
3721d63
Compare
3721d63
to
9193aa4
Compare
9193aa4
to
0af6cfe
Compare
helix-term/src/commands.rs
Outdated
let items = ui::PATH_REGEX | ||
.find(&line_until_cursor) | ||
.and_then(|matched_path| { | ||
let matched_path = matched_path.as_str(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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...).
7435f08
to
b594f49
Compare
b594f49
to
12c0889
Compare
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? |
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. |
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 🙏 |
Thanks for the review, I think I handled all the feedback. |
.filter_map(Result::ok) | ||
.filter_map(|dir_entry| dir_entry.metadata().ok().map(|md| (dir_entry.path(), md))) | ||
.map(|(path, md)| { | ||
let file_name = path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a bit ugly, what dir_entry.path()
does is just dir_path.join(dir_entry.file_name())
so going trough all this to extractd the file name again doesn't seem ideal. Instead just extract the file name and use that here (and just do dir_path.join(file_name)
below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be handled in the recent push.
helix-term/src/ui/completion.rs
Outdated
Path(PathCompletionItem), | ||
} | ||
|
||
impl PartialEq<CompletionItem> for LspCompletionItem { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we necessarily need these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #2608 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I was hoping to avoid the operator overload by just doing CompletionItem::Lsp(..)
but I guess that doesn't work because we use a reference there... Feels a bit overkill but I guess it's fine if moved into a separate file.
helix-term/src/ui/completion.rs
Outdated
#[derive(Debug, PartialEq, Clone)] | ||
pub enum CompletionItem { | ||
Lsp(LspCompletionItem), | ||
Path(PathCompletionItem), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need a seperate PathCompletionItem
type. Instead we can just have a kind: Cow<str>
on helix_core::CompletionItem
. At that point we could also just call that variant Other
(so it's clear there will only ever be an lsp variant and one for everything else going trough the helix-core type).
I am also not really sure about this abstraction in general. I think first starters this should be much better encapsulated. This file is certainly the wrong place for it (I don't want the handler/resolve code to depend on the UI at all). So probably at least a submodule in handlers::completion
. I would also like to have as much information extraction as possible within methods (like preselect
). It's ok to keep `lsp_item_to_transaction in the UI code for now since that is a larger change (altough it also doesn't belong there)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need a seperate
PathCompletionItem
type. Instead we can just have a kind:Cow<str>
onhelix_core::CompletionItem
. At that point we could also just call that variantOther
(so it's clear there will only ever be an lsp variant and one for everything else going trough the helix-core type).
I just fear that there may be more information relevant for a completion item, but that fear may well be unjustified.
This file is certainly the wrong place for it
See recent discussion for it, I'm aware of it, but I don't want to start an even bigger refactor, when PRs are open for so long without any kind of review to avoid resolving merge-conflicts. It shouldn't be too hard to move this somewhere else, when that kind of refactor is done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just fear that there may be more information relevant for a completion item, but that fear may well be unjustified.
To me if there is more relevant information is should be added to the generic helix_core::CompletionItem
. I don't want to couple the UI code to the completion sources. Basically helix_core::CompletionItem
shouldn't be modeled after whatever data completion sources can or can't provide but instead by the data that the UI can actually support (and I would want everything to go trough that generic interface except LSP). The only reason that lsp needs to be separate is because creating the transaction is complicated and needs to be done lazily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #2608 (comment) for it, I'm aware of it, but I don't want to start an even bigger refactor, when PRs are open for so long without any kind of review to avoid resolving merge-conflicts. It shouldn't be too hard to move this somewhere else, when that kind of refactor is done.
I agree that we shouldn't do a large refactor in this PR but moving this into another file inside helix term (like in the handler) is a pretty easy cosmetic change and reduces spaghetti code by a lot. I don't think that would even conflict with the snippet system PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be handled.
9aeedc2
to
59b2cf5
Compare
pushed to this branch by accident, sorry about that I reverted the change (not clear in github UI) |
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`
AFAICS path detection + shell-expansion should now be quite a bit more robust with @pascalkuthe s changes, and should also support windows. |
There was a problem hiding this 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)); |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
This PR adds support for path completion.
It supports the following:
/
.~/path
,$HOME/path
,${HOME}/path
)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")editor.path-completion
(defaulttrue
), per-language overrideable path-completion supportgoto_file
with a new more robust path-detection/resolution mechanism and also adds shell-expansion.A baby-step towards #1015