on master help sign in
Filter the initial completion
66f26e8Blaž Hrastnik
helix-term/src/application.rs+6−5
@@ -234,9 +234,8 @@ impl Application {
234 }
234 }
235
235
236 pub fn handle_idle_timeout(&mut self) {
236 pub fn handle_idle_timeout(&mut self) {
237+ use crate::commands::{completion, Context};
237 use helix_view::document::Mode;
238 use helix_view::document::Mode;
238− use crate::commands::{Context, completion};
239−
240
239
241 if doc_mut!(self.editor).mode != Mode::Insert {
240 if doc_mut!(self.editor).mode != Mode::Insert {
242 return;
241 return;
@@ -254,6 +253,8 @@ impl Application {
254 return;
253 return;
255 }
254 }
256
255
256+ // TODO: if completion window was closed with enter (and no selection) we shouldn't retrigger
257+
257 let mut cx = Context {
258 let mut cx = Context {
258 selected_register: helix_view::RegisterSelection::default(),
259 selected_register: helix_view::RegisterSelection::default(),
259 editor: &mut self.editor,
260 editor: &mut self.editor,
@@ -262,9 +263,9 @@ impl Application {
262 callback: None,
263 callback: None,
263 on_next_key_callback: None,
264 on_next_key_callback: None,
264 };
265 };
265− completion(&mut cx);
266+ completion(&mut cx);
266− // TODO: scan backwards for trigger and filter the box
267+ // TODO: scan backwards for trigger and filter the box
267− self.render();
268+ self.render();
268 }
269 }
269
270
270 pub fn handle_terminal_events(&mut self, event: Option<Result<Event, crossterm::ErrorKind>>) {
271 pub fn handle_terminal_events(&mut self, event: Option<Result<Event, crossterm::ErrorKind>>) {
helix-term/src/commands.rs+12−5
@@ -4090,10 +4090,8 @@ pub fn completion(cx: &mut Context) {
4090 };
4090 };
4091
4091
4092 let offset_encoding = language_server.offset_encoding();
4092 let offset_encoding = language_server.offset_encoding();
4093− let cursor = doc
4093+ let text = doc.text().slice(..);
4094− .selection(view.id)
4094+ let cursor = doc.selection(view.id).primary().cursor(text);
4095− .primary()
4096− .cursor(doc.text().slice(..));
4097
4095
4098 let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding);
4096 let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding);
4099
4097
@@ -4101,6 +4099,15 @@ pub fn completion(cx: &mut Context) {
4101
4099
4102 let trigger_offset = cursor;
4100 let trigger_offset = cursor;
4103
4101
4102+ // TODO: trigger_offset should be the cursor offset but we also need a starting offset from where we want to apply
4103+ // completion filtering. For example logger.te| should filter the initial suggestion list with "te".
4104+
4105+ use helix_core::chars;
4106+ let mut iter = text.chars_at(cursor);
4107+ iter.reverse();
4108+ let offset = iter.take_while(|ch| chars::char_is_word(*ch)).count();
4109+ let start_offset = cursor.saturating_sub(offset);
4110+
4104 cx.callback(
4111 cx.callback(
4105 future,
4112 future,
4106 move |editor: &mut Editor,
4113 move |editor: &mut Editor,
@@ -4131,7 +4138,7 @@ pub fn completion(cx: &mut Context) {
4131 .find(std::any::type_name::<ui::EditorView>())
4138 .find(std::any::type_name::<ui::EditorView>())
4132 .unwrap();
4139 .unwrap();
4133 if let Some(ui) = ui.as_any_mut().downcast_mut::<ui::EditorView>() {
4140 if let Some(ui) = ui.as_any_mut().downcast_mut::<ui::EditorView>() {
4134− ui.set_completion(items, offset_encoding, trigger_offset, size);
4141+ ui.set_completion(editor, items, offset_encoding, start_offset, trigger_offset, size);
4135 };
4142 };
4136 },
4143 },
4137 );
4144 );
helix-term/src/ui/completion.rs+19−6
@@ -69,14 +69,17 @@ impl menu::Item for CompletionItem {
69/// Wraps a Menu.
69/// Wraps a Menu.
70pub struct Completion {
70pub struct Completion {
71 popup: Popup<Menu<CompletionItem>>,
71 popup: Popup<Menu<CompletionItem>>,
72+ start_offset: usize,
72 trigger_offset: usize,
73 trigger_offset: usize,
73 // TODO: maintain a completioncontext with trigger kind & trigger char
74 // TODO: maintain a completioncontext with trigger kind & trigger char
74}
75}
75
76
76impl Completion {
77impl Completion {
77 pub fn new(
78 pub fn new(
79+ editor: &Editor,
78 items: Vec<CompletionItem>,
80 items: Vec<CompletionItem>,
79 offset_encoding: helix_lsp::OffsetEncoding,
81 offset_encoding: helix_lsp::OffsetEncoding,
82+ start_offset: usize,
80 trigger_offset: usize,
83 trigger_offset: usize,
81 ) -> Self {
84 ) -> Self {
82 // let items: Vec<CompletionItem> = Vec::new();
85 // let items: Vec<CompletionItem> = Vec::new();
@@ -175,16 +178,22 @@ impl Completion {
175 };
178 };
176 });
179 });
177 let popup = Popup::new(menu);
180 let popup = Popup::new(menu);
178− Self {
181+ let mut completion = Self {
179 popup,
182 popup,
183+ start_offset,
180 trigger_offset,
184 trigger_offset,
181− }
185+ };
186+
187+ // need to recompute immediately in case start_offset != trigger_offset
188+ completion.recompute_filter(editor);
189+
190+ completion
182 }
191 }
183
192
184− pub fn update(&mut self, cx: &mut commands::Context) {
193+ pub fn recompute_filter(&mut self, editor: &Editor) {
185 // recompute menu based on matches
194 // recompute menu based on matches
186 let menu = self.popup.contents_mut();
195 let menu = self.popup.contents_mut();
187− let (view, doc) = current!(cx.editor);
196+ let (view, doc) = current_ref!(editor);
188
197
189 // cx.hooks()
198 // cx.hooks()
190 // cx.add_hook(enum type, ||)
199 // cx.add_hook(enum type, ||)
@@ -200,14 +209,18 @@ impl Completion {
200 .selection(view.id)
209 .selection(view.id)
201 .primary()
210 .primary()
202 .cursor(doc.text().slice(..));
211 .cursor(doc.text().slice(..));
203− if self.trigger_offset <= cursor {
212+ if self.start_offset <= cursor {
204− let fragment = doc.text().slice(self.trigger_offset..cursor);
213+ let fragment = doc.text().slice(self.start_offset..cursor);
205 let text = Cow::from(fragment);
214 let text = Cow::from(fragment);
206 // TODO: logic is same as ui/picker
215 // TODO: logic is same as ui/picker
207 menu.score(&text);
216 menu.score(&text);
208 }
217 }
209 }
218 }
210
219
220+ pub fn update(&mut self, cx: &mut commands::Context) {
221+ self.recompute_filter(cx.editor)
222+ }
223+
211 pub fn is_empty(&self) -> bool {
224 pub fn is_empty(&self) -> bool {
212 self.popup.contents().is_empty()
225 self.popup.contents().is_empty()
213 }
226 }
helix-term/src/ui/editor.rs+4−1
@@ -721,12 +721,15 @@ impl EditorView {
721
721
722 pub fn set_completion(
722 pub fn set_completion(
723 &mut self,
723 &mut self,
724+ editor: &Editor,
724 items: Vec<helix_lsp::lsp::CompletionItem>,
725 items: Vec<helix_lsp::lsp::CompletionItem>,
725 offset_encoding: helix_lsp::OffsetEncoding,
726 offset_encoding: helix_lsp::OffsetEncoding,
727+ start_offset: usize,
726 trigger_offset: usize,
728 trigger_offset: usize,
727 size: Rect,
729 size: Rect,
728 ) {
730 ) {
731+ let mut completion =
729− let mut completion = Completion::new(items, offset_encoding, trigger_offset);
732+ Completion::new(editor, items, offset_encoding, start_offset, trigger_offset);
730 // TODO : propagate required size on resize to completion too
733 // TODO : propagate required size on resize to completion too
731 completion.required_size((size.width, size.height));
734 completion.required_size((size.width, size.height));
732 self.completion = Some(completion);
735 self.completion = Some(completion);
helix-view/src/macros.rs+16
@@ -44,3 +44,19 @@ macro_rules! view {
44 $( $editor ).+ .tree.get($( $editor ).+ .tree.focus)
44 $( $editor ).+ .tree.get($( $editor ).+ .tree.focus)
45 }};
45 }};
46}
46}
47+
48+#[macro_export]
49+macro_rules! doc {
50+ ( $( $editor:ident ).+ ) => {{
51+ $crate::current_ref!( $( $editor ).+ ).1
52+ }};
53+}
54+
55+#[macro_export]
56+macro_rules! current_ref {
57+ ( $( $editor:ident ).+ ) => {{
58+ let view = $( $editor ).+ .tree.get($( $editor ).+ .tree.focus);
59+ let doc = &$( $editor ).+ .documents[view.doc];
60+ (view, doc)
61+ }};
62+}