-
-
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
Feat: Sticky Context #6118
base: master
Are you sure you want to change the base?
Feat: Sticky Context #6118
Conversation
7ce93e9
to
f1d26a6
Compare
i think in order to satisfy clippys complaint, i would have to use the Maybe someone else got an idea how to get the |
56c857f
to
2e6c02b
Compare
acbc1a0
to
f22cbf9
Compare
Don't worry too much about it, this one lint is helpful most of the time but it can't account for the context of the code, ignoring it is often ok (I'm on my phone so I won't review right now, I can't tell for your use case yet) |
Note: the Neovim plugin this is based on is switching to queries for determining the nodes (nvim-treesitter/nvim-treesitter-context#198). We should do the same (similar to indents where we started with a toml config but now use proper queries) |
Do i understand it correctly, that you'd want seperate injection queries (tree-sitter) for the context? If so, i think i can do that. |
I would advocate not to depend on tree-sitter on this feature. There are still many languages that don't have TS. |
in order for this feature to work without tree-sitter, i would have to manually parse scopes, which are VERY inconsistent throughout languages, therefore tree-sitter is, imo, the only way of doing this kind of properly. You also could - of course - always create tree-sitter grammars as well as add languages to helix |
Helix is primarily a TS based editor and languages, I think supporting plaintext files for some basic editing operations (like pair matching) can make sense but not for features that require semantic information (as this one does). The right fix is to create a TS grammar for those languages instead of adding language specific code into helix. Creating a TS grammar is not that hard and most mainstream languages do have one |
OK. I see your point. Unfortunately, for people like DevOps or SysAdmins it still means opening lots of text files (scripts, configs etc.) in weird languages that will never have a TS. But, again, it's just my concern and wish. This feature is so needed that I would be happy if it works at least for the supported languages. |
Helix has grammars for markup and configuration languages too (like markdown). Any file that has syntax highlighting in helix has a TS grammar. We even have TS grammars for filetypes like |
I tested this pr and it shows a bit strange in golang. I also support the use of tree-sitter queries, nvim-treesitter-context/queries provides a lot of language , we can use it, other languages can be added later. |
What exactly looks strange? |
I have added the following configuration.
I test with golang base library Some times it is displayed correctly and some times it is not displayed. |
ahh maybe i know why. I will remove that, as it's an old artifact. Thanks for the finding! :) |
When I have non-ascii in my code, the capture is incorrect. For example, the following insert method. test file: https://gist.github.com/erasin/a15c4f250beff8c9f7e4aaeae4a1128c 2023-03-10.13.52.18.movI get a panic when using the mouse to scroll end of file. The error was not found in master. thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Char index out of bounds: char index 4184, Rope/RopeSlice char length 4173', /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/ropey-1.6.0/src/slice.rs:379:41
stack backtrace:
0: 0x109be68c6 - std::backtrace_rs::backtrace::libunwind::trace::h310cbd77a7d2ae59
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
1: 0x109be68c6 - std::backtrace_rs::backtrace::trace_unsynchronized::h5768bae568840507
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x109be68c6 - std::sys_common::backtrace::_print_fmt::hd104a205649a2ffb
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/sys_common/backtrace.rs:65:5
3: 0x109be68c6 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h521420ec33f3769d
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/sys_common/backtrace.rs:44:22
4: 0x109c08c6a - core::fmt::write::h694a0d7c23f57ada
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/fmt/mod.rs:1208:17
5: 0x109bdfb9c - std::io::Write::write_fmt::h1920a3973ad439e5
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/io/mod.rs:1682:15
6: 0x109be66aa - std::sys_common::backtrace::_print::h75582c4ed1a04abb
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/sys_common/backtrace.rs:47:5
7: 0x109be66aa - std::sys_common::backtrace::print::hef1aa4dbdc07ee06
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/sys_common/backtrace.rs:34:9
8: 0x109be88d3 - std::panicking::default_hook::{{closure}}::h529701a1070b4ce0
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:267:22
9: 0x109be8628 - std::panicking::default_hook::hfeeab2c667b2d7c2
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:286:9
10: 0x1083df5c1 - <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call::h9afa8b8b4a6f4294
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/boxed.rs:2032:9
11: 0x108406e1f - helix_term::application::Application::run::{{closure}}::{{closure}}::h59304607632a2a9a
at /Users/erasin/github/helix/helix-term/src/application.rs:1061:13
12: 0x109be9027 - <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call::h23ed9dbfdf16f482
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/boxed.rs:2032:9
13: 0x109be9027 - std::panicking::rust_panic_with_hook::h1b5245192f90251d
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:692:13
14: 0x109be8dd4 - std::panicking::begin_panic_handler::{{closure}}::h3658f3a9566379d4
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:579:13
15: 0x109be6d68 - std::sys_common::backtrace::__rust_end_short_backtrace::h9e01645d962f8882
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/sys_common/backtrace.rs:137:18
16: 0x109be8a9d - rust_begin_unwind
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:575:5
17: 0x109c4bee3 - core::panicking::panic_fmt::h0097ad8ec0b07517
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/panicking.rs:64:14
18: 0x109c4c365 - core::result::unwrap_failed::h2a0ffdcdbffb9262
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/result.rs:1791:5
19: 0x10964bc3a - core::result::Result<T,E>::unwrap::h76fa627ea2ccb7e6
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/result.rs:1113:23
- 20: 0x10870149f - ropey::slice::RopeSlice::char_to_line::h83b3a9f53cafd361
- at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/ropey-1.6.0/src/slice.rs:379:9
- 21: 0x1087b4dac - helix_term::ui::editor::EditorView::calculate_sticky_nodes::hd44adebca1ce03c2
- at /Users/erasin/github/helix/helix-term/src/ui/editor.rs:857:24
- 22: 0x1087b0298 - helix_term::ui::editor::EditorView::render_view::h801f2329103ac9f0
- at /Users/erasin/github/helix/helix-term/src/ui/editor.rs:191:17
- 23: 0x1087b9fa4 - <helix_term::ui::editor::EditorView as helix_term::compositor::Component>::render::h0d6ad5e880ce309a
- at /Users/erasin/github/helix/helix-term/src/ui/editor.rs:1604:13
- 24: 0x1087cb16e - helix_term::compositor::Compositor::render::h421b649aa5e8a5c7
- at /Users/erasin/github/helix/helix-term/src/compositor.rs:170:13
- 25: 0x108407ee7 - helix_term::application::Application::render::{{closure}}::h9128185baddbd711
- at /Users/erasin/github/helix/helix-term/src/application.rs:285:9
- 26: 0x108401061 - helix_term::application::Application::handle_terminal_events::{{closure}}::h452798700217d49a
- at /Users/erasin/github/helix/helix-term/src/application.rs:618:26
- 27: 0x1083ffbfe - helix_term::application::Application::event_loop_until_idle::{{closure}}::h8cc9ae38c69ea5ec
- at /Users/erasin/github/helix/helix-term/src/application.rs:326:55
- 28: 0x1083fd20c - helix_term::application::Application::event_loop::{{closure}}::hf15c5275827c0534
- at /Users/erasin/github/helix/helix-term/src/application.rs:302:57
- 29: 0x10840691d - helix_term::application::Application::run::{{closure}}::h64d788da4e75353b
- at /Users/erasin/github/helix/helix-term/src/application.rs:1064:38
- 30: 0x1083f5e1e - hx::main_impl::{{closure}}::h64babcb08100836d
- at /Users/erasin/github/helix/helix-term/src/main.rs:156:53
31: 0x1083d659e - tokio::runtime::park::CachedParkThread::block_on::{{closure}}::h04680cd7055be189
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/park.rs:283:63
32: 0x1083d6403 - tokio::runtime::coop::with_budget::h3450751a913955ea
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/coop.rs:107:5
33: 0x1083d6403 - tokio::runtime::coop::budget::hfece1804ad294c58
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/coop.rs:73:5
34: 0x1083d6403 - tokio::runtime::park::CachedParkThread::block_on::h50891113bf07b160
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/park.rs:283:31
35: 0x1083ed336 - tokio::runtime::context::BlockingRegionGuard::block_on::h97a7cfd8b0f5191b
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/context.rs:315:13
36: 0x1083b9bd5 - tokio::runtime::scheduler::multi_thread::MultiThread::block_on::h6a41409b5c3a1748
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/scheduler/multi_thread/mod.rs:66:9
37: 0x108417cfb - tokio::runtime::runtime::Runtime::block_on::h72dfd34556937174
at /Users/erasin/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/tokio-1.26.0/src/runtime/runtime.rs:304:45
38: 0x10840905e - hx::main_impl::h594c06858aac3bd2
at /Users/erasin/github/helix/helix-term/src/main.rs:158:5
39: 0x108408f01 - hx::main::hbd7e18d2aacb3ddc
at /Users/erasin/github/helix/helix-term/src/main.rs:38:21
40: 0x108409f7e - core::ops::function::FnOnce::call_once::h81bdc8e78b625ab3
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/ops/function.rs:507:5
41: 0x1083df8a1 - std::sys_common::backtrace::__rust_begin_short_backtrace::h582282e1d3fcd9fa
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/sys_common/backtrace.rs:121:18
42: 0x1083e5d64 - std::rt::lang_start::{{closure}}::h8919f335f7d65c4f
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/rt.rs:166:18
43: 0x109bd9a24 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h2302f1d25ef2ca9b
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/ops/function.rs:606:13
44: 0x109bd9a24 - std::panicking::try::do_call::h6695e32a593de2cc
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:483:40
45: 0x109bd9a24 - std::panicking::try::hd4a93095627721a9
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:447:19
46: 0x109bd9a24 - std::panic::catch_unwind::he41b3dba63feca94
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panic.rs:137:14
47: 0x109bd9a24 - std::rt::lang_start_internal::{{closure}}::hbf45583011495a61
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/rt.rs:148:48
48: 0x109bd9a24 - std::panicking::try::do_call::ha3e6b3edab7da449
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:483:40
49: 0x109bd9a24 - std::panicking::try::hd4e0f354bf7022b9
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:447:19
50: 0x109bd9a24 - std::panic::catch_unwind::h1035b163871a4269
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panic.rs:137:14
51: 0x109bd9a24 - std::rt::lang_start_internal::hd56d2fa7efb2dd60
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/rt.rs:148:20
52: 0x1083e5d37 - std::rt::lang_start::h2981ed93936c2adf
at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/rt.rs:165:17
53: 0x1084090e8 - _main
54: 0x7ff816549310 - <unknown>
|
Yes, we should reuse the https://github.com/nvim-treesitter/nvim-treesitter-context/blob/master/queries/go/context.scm This ways they are shareable across editors. |
Ok, have started working on it, and will continue these days. |
49e657d
to
7021fc4
Compare
helix-term/src/ui/editor.rs
Outdated
.take(max_nodes_amount) | ||
.rev() | ||
.enumerate() | ||
.take_while(|(i, _)| *i + 1 != visual_cursor_pos as usize) // also only nodes that don't overlap with the visual cursor position | ||
.map(|(i, node)| { | ||
let mut new_node = node; | ||
new_node.visual_line = i as u16; | ||
new_node | ||
}) | ||
.collect(); |
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 will take max_node_amount
and then remove elements again if they overlap, is that intended ?
The version below avoids one Vec
allocation but I'm not convinced it would be faster, how big are you expecting context
to be most of the time ?
context.reverse();
if context.len() > max_node_amount {
// only take the nodes until 1 / 3 of the viewport is reached or the maximum amount of sticky nodes
context.drain(max_node_amount..);
}
let mut idx = 0;
let mut overlap_reached = 1 == visual_cursor_pos;
context.retain_mut(|node| {
if overlap_reached { return false; }
overlap_reached = idx + 1 == visual_cursor_pos;
node.visual_line = idx;
idx += 1;
true
});
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 would say that it will mostly sit around 3~5 nodes.
So i think performance there is not really that big of a deal, i would much rather avoid more of the text.x_to_y
calls, as they're rather heavy. O(log n)
@poliorcetics i appreciate that you already di a new review, but I wasn't finished ^^` |
Can you tell me how to repr.? |
@TornaxO7 thx! :) |
You're welcome |
dd5bc8d
to
a5a3b5f
Compare
I have found a bug, for a language containing class which is annotated shows incorrect value. (language is java) @SystemService(Context.ACTIVITY_SERVICE) The sticky context generated is @SystemService instead of the class ActivityManager. Another question I have is, how can I persist the multiple case inside a switch block? I've put the appropriate switch query in the context.scm - however, once I scroll down, only the last switch-case value is remembered, the cases above it go away. |
I have no way of validating that, since i haven't done any java context query.
Since the switch case is going out of scope, there's no real way of doing it. |
Thanks for the other issue with annotation - it is not just limited to classes but functions which are overriden are also affected. |
Looks like 1d0a3d4 breaks this PR, made some changes to fix it, @TornaxO7 can you review index d7736d7a..71f0fdcc 100644
--- a/helix-term/src/ui/context.rs
+++ b/helix-term/src/ui/context.rs
@@ -61,7 +61,7 @@ pub fn from_context(
let viewport = view.inner_area(doc);
let cursor_byte = text.char_to_byte(doc.selection(view.id).primary().cursor(text));
- let anchor_line = text.char_to_line(view.offset.anchor);
+ let anchor_line = text.char_to_line(doc.view_offset(view.id).anchor);
let visual_cursor_row = cursor_cache.row;
if visual_cursor_row == 0 {
@@ -104,7 +104,7 @@ pub fn calculate_sticky_nodes(
let tree = syntax.tree();
let text = doc.text().slice(..);
- let mut cached_nodes = build_cached_nodes(nodes, view, &mut context).unwrap_or_default();
+ let mut cached_nodes = build_cached_nodes(doc, nodes, view, &mut context).unwrap_or_default();
if cached_nodes.iter().any(|node| node.view_id != view.id) {
cached_nodes.clear();
@@ -205,7 +205,7 @@ pub fn calculate_sticky_nodes(
.unwrap_or(&(node.start_byte()..node.end_byte()))
.clone(),
indicator: None,
- anchor: view.offset.anchor,
+ anchor: doc.view_offset(view.id).anchor,
has_context_end: node_byte_range.is_some(),
view_id: view.id,
});
@@ -215,7 +215,7 @@ pub fn calculate_sticky_nodes(
if result.is_empty() {
if !cached_nodes.is_empty() {
if config.sticky_context.indicator {
- return Some(add_indicator(&context.viewport, view, cached_nodes));
+ return Some(add_indicator(doc, &context.viewport, view, cached_nodes));
}
return Some(cached_nodes);
@@ -256,13 +256,14 @@ pub fn calculate_sticky_nodes(
.collect();
if config.sticky_context.indicator {
- res = add_indicator(&context.viewport, view, res);
+ res = add_indicator(doc, &context.viewport, view, res);
}
Some(res)
}
fn build_cached_nodes(
+ doc: &Document,
nodes: Option<&Vec<StickyNode>>,
view: &View,
context: &mut StickyNodeContext,
@@ -273,7 +274,10 @@ fn build_cached_nodes(
}
// nothing has changed, so the cached result can be returned
- if nodes.iter().any(|node| view.offset.anchor == node.anchor) {
+ if nodes
+ .iter()
+ .any(|node| doc.view_offset(view.id).anchor == node.anchor)
+ {
return Some(nodes.iter().take(context.visual_row).cloned().collect());
}
@@ -344,7 +348,12 @@ fn node_in_range(
}
/// Adds an indicator line to the Sticky Context
-fn add_indicator(viewport: &Rect, view: &View, res: Vec<StickyNode>) -> Vec<StickyNode> {
+fn add_indicator(
+ doc: &Document,
+ viewport: &Rect,
+ view: &View,
+ res: Vec<StickyNode>,
+) -> Vec<StickyNode> {
let mut res = res;
let str = "─".repeat(viewport.width as usize);
res.push(StickyNode {
@@ -352,7 +361,7 @@ fn add_indicator(viewport: &Rect, view: &View, res: Vec<StickyNode>) -> Vec<Stic
visual_line: res.len() as u16,
byte_range: 0..0,
indicator: Some(str),
- anchor: view.offset.anchor,
+ anchor: doc.view_offset(view.id).anchor,
has_context_end: false,
view_id: view.id,
}); |
a5a3b5f
to
b8a6e4f
Compare
May I ask what you exactly did? I'm getting
if I'm on |
yea it's because i already pushed an update. |
I'm able to crash helix after cherry-picking your patch. Without it, not happening. More surprised to find it after couple of days. To reproduce: Sync with latest HEAD, cherry-pick your patch. Now, go to commands.rs -> func global_search. Check the FileImpl struct, it's used inside PickerColumn::new("path"), inside it, type "item.", LSP will give pop-up with possible contents, use ctrl+n to navigate, helix crashes. Sometimes it doesn't happen when list returned by LSP is small.
|
18a63ef
to
8ad3a03
Compare
based on the backtrace and what you describe i can safely assume this doesn't seem to be an issue of this pr, and it's most likely fixed here: #11266 This has been fixed with the latest rebase. |
18555e7
to
ea3ac71
Compare
A lot more work has been put into this and those were 116 commits up to this point. I decided to squash all of them so that i will have an easier time rebasing in the future.
a0efb1a
to
9a7c439
Compare
That looks amazing and I’ve been missing that feature since my move away from |
Thank you! |
How severe and how often are the known issues occurring? Would it be on to merge with the feature toggled off by default and work on them separately? |
quite frequently. They're not really severe, but also not perfect.
On another node, i am not sure how this PR will continue. I suspect that it could make much more sense to make it a plugin instead (once the plugin support is finished) |
I believe this belongs in core. I am eager to hear a maintainer's opinion on this Thank you for doing this |
!! If your preferred colorscheme / language is not yet in this PR, please feel free to open a PR on my branch:
sticky-context
to add those! It helps me quite a lot, as i can't keep track of every single colorscheme / language that helix supports !!This is supposed to be the "successor PR" of #3944 .
Since @matoous has no time to pick up on it, i have started to continue on it (as i have also previously worked a bit on it!).
This is for now working, but with very rough edges and needs some fine adjustments.
Features, in no particular order:
{
or just"..."
- this should be possible via the text api -> i would also strongly believe, that this will make the 'configuration of tree-sitter nodes' obsolete.TypescriptECMAScript----- Bug Smashing: ------
I beg anyone to find another bug as mentioned here, to immediately notify me, even if it's minor, i am happy to investigate it (also; if possible, create a reproducer)
----- Overview: ------
impl
of structsshould then be collapsed to:
fn render(...) {
Small gif:
closes #396