-
-
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 for unix paths #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 🙏 |
@Philipp-M thanks for the work. I built https://github.com/Philipp-M/helix/tree/path-completion/ on MacOS 14.4.1 and path completion worked for me as expected. Let me know if you want specific things tested. |
749ec12
to
6bcbfdc
Compare
I don't think we have proper visibility on this PR, and poor Phillip has been force pushing updates for a few years now. I've been using this patch from the close to the beginning and haven't had any issues with it. Sorry if the ping is inappropriate but @archseer or @the-mikedavis do you guys have an idea of what is missing or why this hasn't been merged in so long? Or has it just been overlooked? |
Thanks for the great work. I just forked the main Helix repo and rebased your PR as well as another PR (#11164) on my forks master. Just built it from there and works great. Was one of the major things which hindered me switching completely to Helix. Hope it will find its way into the main repo soon. One thing I encountered is that expanding Tilde ( |
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.
Looks great to me, who are the main people we need to review this to get this finally merged in?
let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { | ||
range: range_to_lsp_range( | ||
&text, | ||
Range::new(cursor - edit_diff, cursor), | ||
OffsetEncoding::default(), | ||
), | ||
new_text: file_name.clone(), | ||
})); |
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'd like to try to find a way to avoid digging ourselves into lsp-types here. It makes for a pretty small+focused change but I think we should be introducing core types like helix_core::Diagnostic
where possible or at least wrappers/replacements like #11486. I suspect it's a potentially large refactor but I think this is the right feature to introduce it with since the actual searching/completion part of this is quite small. (Compared to completing words from the buffer for example)
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 haven't looked into this much but it might be pretty simple to update the CompletionItem
struct to have an enum between the lsp::CompletionItem
and a helix_core::CompletionItem
struct that has a changeset or transaction instead of text_edits
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.
Actually a previous iteration of this PR (e.g. this) had an enum CompletionItem
with separating variants LSP
and Path
.
I wasn't sure having a separate mechanism additional to lsp::CompletionItem
would make sense, since there was already the variants lsp::CompletionItemKind::{FILE, FOLDER}
.
But I guess when thinking about more completion sources it may make sense, especially when the move to more core types resembling those in lsp
is planned anyways.
So when I'm getting you right, you mean a CompletionItem
at a lower-level than in ui::completion
(which I think was the previous iteration). I wonder if it makes sense to generally abstract over lsp::CompletionItem
and wrap it in helix_core::CompletionItem
. I should probably investigate this, as I think you're right in that this would need a larger refactor (maybe worth it).
I think a Transaction
would make more sense here, being more general (and we have impl From<ChangeSet> for Transaction
already)?
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.
Ok, I don't think abstracting over lsp::CompletionItem
makes sense with the current architecture. So rather having a "data" container helix_core::CompletionItem
similar to helix_core::Diagnostic
a little bit independent of lsp::CompletionItem
with data like documentation (possibly lazy) and Transaction
etc. makes probably more sense for now.
Is it planned btw. to move more logic of this kind from helix-term
to e.g. helix-view
or even helix-core
?
I could imagine helix_term::ui::CompletionItem
would make more sense in helix-view
?
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 generally the more we can move from -term to -view the merrier. Ideally most of what lives in -term right now would be in -view (even commands) but it will take quite a bit of work to decouple the UI elements. So -term would just be the terminal backend and then there could be a -gui crate that would also implement the UI components.
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.
Ok, good to know, I'm actually thinking about starting that refactor in this PR, that would obviously blow up this PR a little bit, and would likely produce merge-conflicts with other PRs (e.g. #9996), which is why I'm not sure about it, as I'd like to avoid resolving merge-conflicts and/or maintain this PR for a longer time (in a state where this is more interconnected with the rest of the editor-logic).
Like putting a lot of logic of helix_term::ui::completion
into e.g. helix-view::completion
as I don't see many dependencies to helix-term
currently. (Same for the handlers I guess).
But maybe keep it more incremental, and leave the CompletionItem
(and the path/lsp CompletionItem
resolution logic) currently in helix-term
, i.e. only helix_term::ui::completion::CompletionItem
to an enum roughly like this:
pub enum PathKind { Folder, File, Link } // maybe not worth it...
pub enum CompletionItem {
Lsp {
item: lsp::CompletionItem,
id: LanguageServerId,
resolved: bool,
},
Path { // Not sure if this should be a more generic `Core`,
// but this probably allows being more flexible in the future
kind: PathKind,
item: helix_core::CompletionItem,
},
}
pub struct helix_core::CompletionItem {
pub transaction: Transaction,
pub label: String,
/// Containing Markdown, this could be turned e.g. into an enum to be more structured
pub documentation: String,
}
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 yeah, working incrementally is probably the right way to go about this. Moving more things to helix-view would mainly help the GUI effort which I don't believe anyone is working on actively anyways. I'm also worried about conflicts with #9801 (though on second look it doesn't look like it would conflict much). An enum like that looks good even if it's only a stepping stone to a bigger refactor later.
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.
Actually I have merged the snipped system with path-completion in my personal branch, I don't remember that this caused any serious merge-conflicts...
Ok, good to know, then I'll go the incremental route (when I find the time).
#[allow(clippy::unnecessary_cast)] | ||
acc.push(if mode & (*p as u32) > 0 { *s } else { '-' }); |
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.
#[allow(clippy::unnecessary_cast)] | |
acc.push(if mode & (*p as u32) > 0 { *s } else { '-' }); | |
acc.push(if mode & p > 0 { *s } else { '-' }); |
it looks like the compiler derefs this automatically now
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.
Actually I guess you could use into_iter
instead of iter here and also drop the deref for s
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 into_iter
is possible, also added String::with_capacity(9)
to avoid unnecessary allocs...
Btw. the cast is necessary for e.g. OSX (added a comment as well) as there is p: u16
.
6bcbfdc
to
a0e10fc
Compare
Ok, did a bit of refactoring to the I've added the basically unchanged struct helix_core::CompletionItem {
pub transaction: Transaction,
pub label: String,
/// Containing Markdown
pub documentation: String,
} I think that could be extended over time when necessary.
I've also added support for this along the way. |
* 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
a0e10fc
to
cc19db1
Compare
Hmm nightly rustc seems to be able to handle a few more borrow-checking cases it seems, something like: let transaction = match item {
Arm1 { item, .. } => &item_to_transaction(item),
Arm2 { item, .. } => &item.transaction
}; doesn't seem to be possible without nightly... |
Btw. I have also refactored the handling of additional text edits of lsp completion, composing it now as a single |
Well I just reverted that change again... I thought compose handles different resulting |
Interesting that nightly allows borrowing that value. An alternative could be wrapping it in a |
…completion items
Not sure if anyone's mentioned this before, but have you considered taking inspiration or logic from the nvim cmp-path plugin? As far as I've noticed it doesn't attempt any complexities like Home-path resolution except the tilde |
I have not, but since it's implemented already (and it's not really complex IMO), I guess we can keep support for resolution of |
Well if it works it works. Either way I'd just be grateful to have this as part of the main editor. This feature is on the list of things I'd like to have before giving Helix a more serious attempt. |
fwiw I have been using Helix for years now and just carrying this along as a patch pretty much that whole time. It works and I've never had an issue with it. Hope it get's merged soon |
Seems like all reviews are passing and the code works, maybe it's time to finally merge this ~2 year old MR? |
Thanks for this excellent PR - I can confirm that it works very well, love it and use it a lot :) . |
I am using it and have had no problems, could not live without it now. |
This PR adds support for path completion, currently only unix paths supported.
It supports the following:
/
.~/path
,$HOME/path
,${HOME}/path
)CompletionItemKind
) only supports files and folders but not symlinks)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 supportA baby-step towards #1015