@@ -5,7 +5,6 @@ pub(crate) mod typed;
5
5
pub use dap:: * ;
6
6
use helix_vcs:: Hunk ;
7
7
pub use lsp:: * ;
8
- use tokio:: sync:: oneshot;
9
8
use tui:: widgets:: Row ;
10
9
pub use typed:: * ;
11
10
@@ -33,7 +32,7 @@ use helix_core::{
33
32
} ;
34
33
use helix_view:: {
35
34
document:: { FormatterError , Mode , SCRATCH_BUFFER_NAME } ,
36
- editor:: { Action , CompleteAction } ,
35
+ editor:: Action ,
37
36
info:: Info ,
38
37
input:: KeyEvent ,
39
38
keyboard:: KeyCode ,
@@ -52,14 +51,10 @@ use crate::{
52
51
filter_picker_entry,
53
52
job:: Callback ,
54
53
keymap:: ReverseKeymap ,
55
- ui:: {
56
- self , editor:: InsertEvent , lsp:: SignatureHelp , overlay:: overlaid, CompletionItem , Picker ,
57
- Popup , Prompt , PromptEvent ,
58
- } ,
54
+ ui:: { self , overlay:: overlaid, Picker , Popup , Prompt , PromptEvent } ,
59
55
} ;
60
56
61
57
use crate :: job:: { self , Jobs } ;
62
- use futures_util:: { stream:: FuturesUnordered , TryStreamExt } ;
63
58
use std:: { collections:: HashMap , fmt, future:: Future } ;
64
59
use std:: { collections:: HashSet , num:: NonZeroUsize } ;
65
60
@@ -2478,7 +2473,6 @@ fn delete_by_selection_insert_mode(
2478
2473
) ;
2479
2474
}
2480
2475
doc. apply ( & transaction, view. id ) ;
2481
- lsp:: signature_help_impl ( cx, SignatureHelpInvoked :: Automatic ) ;
2482
2476
}
2483
2477
2484
2478
fn delete_selection ( cx : & mut Context ) {
@@ -2552,10 +2546,6 @@ fn insert_mode(cx: &mut Context) {
2552
2546
. transform ( |range| Range :: new ( range. to ( ) , range. from ( ) ) ) ;
2553
2547
2554
2548
doc. set_selection ( view. id , selection) ;
2555
-
2556
- // [TODO] temporary workaround until we're not using the idle timer to
2557
- // trigger auto completions any more
2558
- cx. editor . clear_idle_timer ( ) ;
2559
2549
}
2560
2550
2561
2551
// inserts at the end of each selection
@@ -3378,9 +3368,9 @@ fn hunk_range(hunk: Hunk, text: RopeSlice) -> Range {
3378
3368
3379
3369
pub mod insert {
3380
3370
use crate :: events:: PostInsertChar ;
3371
+
3381
3372
use super :: * ;
3382
3373
pub type Hook = fn ( & Rope , & Selection , char ) -> Option < Transaction > ;
3383
- pub type PostHook = fn ( & mut Context , char ) ;
3384
3374
3385
3375
/// Exclude the cursor in range.
3386
3376
fn exclude_cursor ( text : RopeSlice , range : Range , cursor : Range ) -> Range {
@@ -3394,88 +3384,6 @@ pub mod insert {
3394
3384
}
3395
3385
}
3396
3386
3397
- // It trigger completion when idle timer reaches deadline
3398
- // Only trigger completion if the word under cursor is longer than n characters
3399
- pub fn idle_completion ( cx : & mut Context ) {
3400
- let config = cx. editor . config ( ) ;
3401
- let ( view, doc) = current ! ( cx. editor) ;
3402
- let text = doc. text ( ) . slice ( ..) ;
3403
- let cursor = doc. selection ( view. id ) . primary ( ) . cursor ( text) ;
3404
-
3405
- use helix_core:: chars:: char_is_word;
3406
- let mut iter = text. chars_at ( cursor) ;
3407
- iter. reverse ( ) ;
3408
- for _ in 0 ..config. completion_trigger_len {
3409
- match iter. next ( ) {
3410
- Some ( c) if char_is_word ( c) => { }
3411
- _ => return ,
3412
- }
3413
- }
3414
- super :: completion ( cx) ;
3415
- }
3416
-
3417
- fn language_server_completion ( cx : & mut Context , ch : char ) {
3418
- let config = cx. editor . config ( ) ;
3419
- if !config. auto_completion {
3420
- return ;
3421
- }
3422
-
3423
- use helix_lsp:: lsp;
3424
- // if ch matches completion char, trigger completion
3425
- let doc = doc_mut ! ( cx. editor) ;
3426
- let trigger_completion = doc
3427
- . language_servers_with_feature ( LanguageServerFeature :: Completion )
3428
- . any ( |ls| {
3429
- // TODO: what if trigger is multiple chars long
3430
- matches ! ( & ls. capabilities( ) . completion_provider, Some ( lsp:: CompletionOptions {
3431
- trigger_characters: Some ( triggers) ,
3432
- ..
3433
- } ) if triggers. iter( ) . any( |trigger| trigger. contains( ch) ) )
3434
- } ) ;
3435
-
3436
- if trigger_completion {
3437
- cx. editor . clear_idle_timer ( ) ;
3438
- super :: completion ( cx) ;
3439
- }
3440
- }
3441
-
3442
- fn signature_help ( cx : & mut Context , ch : char ) {
3443
- use helix_lsp:: lsp;
3444
- // if ch matches signature_help char, trigger
3445
- let doc = doc_mut ! ( cx. editor) ;
3446
- // TODO support multiple language servers (not just the first that is found), likely by merging UI somehow
3447
- let Some ( language_server) = doc
3448
- . language_servers_with_feature ( LanguageServerFeature :: SignatureHelp )
3449
- . next ( )
3450
- else {
3451
- return ;
3452
- } ;
3453
-
3454
- let capabilities = language_server. capabilities ( ) ;
3455
-
3456
- if let lsp:: ServerCapabilities {
3457
- signature_help_provider :
3458
- Some ( lsp:: SignatureHelpOptions {
3459
- trigger_characters : Some ( triggers) ,
3460
- // TODO: retrigger_characters
3461
- ..
3462
- } ) ,
3463
- ..
3464
- } = capabilities
3465
- {
3466
- // TODO: what if trigger is multiple chars long
3467
- let is_trigger = triggers. iter ( ) . any ( |trigger| trigger. contains ( ch) ) ;
3468
- // lsp doesn't tell us when to close the signature help, so we request
3469
- // the help information again after common close triggers which should
3470
- // return None, which in turn closes the popup.
3471
- let close_triggers = & [ ')' , ';' , '.' ] ;
3472
-
3473
- if is_trigger || close_triggers. contains ( & ch) {
3474
- super :: signature_help_impl ( cx, SignatureHelpInvoked :: Automatic ) ;
3475
- }
3476
- }
3477
- }
3478
-
3479
3387
// The default insert hook: simply insert the character
3480
3388
#[ allow( clippy:: unnecessary_wraps) ] // need to use Option<> because of the Hook signature
3481
3389
fn insert ( doc : & Rope , selection : & Selection , ch : char ) -> Option < Transaction > {
@@ -3505,12 +3413,6 @@ pub mod insert {
3505
3413
doc. apply ( & t, view. id ) ;
3506
3414
}
3507
3415
3508
- // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
3509
- // this could also generically look at Transaction, but it's a bit annoying to look at
3510
- // Operation instead of Change.
3511
- for hook in & [ language_server_completion, signature_help] {
3512
- hook ( cx, c) ;
3513
- }
3514
3416
helix_event:: dispatch ( PostInsertChar { c, cx } ) ;
3515
3417
}
3516
3418
@@ -3735,8 +3637,6 @@ pub mod insert {
3735
3637
} ) ;
3736
3638
let ( view, doc) = current ! ( cx. editor) ;
3737
3639
doc. apply ( & transaction, view. id ) ;
3738
-
3739
- lsp:: signature_help_impl ( cx, SignatureHelpInvoked :: Automatic ) ;
3740
3640
}
3741
3641
3742
3642
pub fn delete_char_forward ( cx : & mut Context ) {
@@ -4373,151 +4273,7 @@ fn remove_primary_selection(cx: &mut Context) {
4373
4273
}
4374
4274
4375
4275
pub fn completion ( cx : & mut Context ) {
4376
- use helix_lsp:: { lsp, util:: pos_to_lsp_pos} ;
4377
-
4378
- let ( view, doc) = current ! ( cx. editor) ;
4379
-
4380
- let savepoint = if let Some ( CompleteAction :: Selected { savepoint } ) = & cx. editor . last_completion
4381
- {
4382
- savepoint. clone ( )
4383
- } else {
4384
- doc. savepoint ( view)
4385
- } ;
4386
-
4387
- let text = savepoint. text . clone ( ) ;
4388
- let cursor = savepoint. cursor ( ) ;
4389
-
4390
- let mut seen_language_servers = HashSet :: new ( ) ;
4391
-
4392
- let mut futures: FuturesUnordered < _ > = doc
4393
- . language_servers_with_feature ( LanguageServerFeature :: Completion )
4394
- . filter ( |ls| seen_language_servers. insert ( ls. id ( ) ) )
4395
- . map ( |language_server| {
4396
- let language_server_id = language_server. id ( ) ;
4397
- let offset_encoding = language_server. offset_encoding ( ) ;
4398
- let pos = pos_to_lsp_pos ( & text, cursor, offset_encoding) ;
4399
- let doc_id = doc. identifier ( ) ;
4400
- let completion_request = language_server. completion ( doc_id, pos, None ) . unwrap ( ) ;
4401
-
4402
- async move {
4403
- let json = completion_request. await ?;
4404
- let response: Option < lsp:: CompletionResponse > = serde_json:: from_value ( json) ?;
4405
-
4406
- let items = match response {
4407
- Some ( lsp:: CompletionResponse :: Array ( items) ) => items,
4408
- // TODO: do something with is_incomplete
4409
- Some ( lsp:: CompletionResponse :: List ( lsp:: CompletionList {
4410
- is_incomplete : _is_incomplete,
4411
- items,
4412
- } ) ) => items,
4413
- None => Vec :: new ( ) ,
4414
- }
4415
- . into_iter ( )
4416
- . map ( |item| CompletionItem {
4417
- item,
4418
- language_server_id,
4419
- resolved : false ,
4420
- } )
4421
- . collect ( ) ;
4422
-
4423
- anyhow:: Ok ( items)
4424
- }
4425
- } )
4426
- . collect ( ) ;
4427
-
4428
- // setup a channel that allows the request to be canceled
4429
- let ( tx, rx) = oneshot:: channel ( ) ;
4430
- // set completion_request so that this request can be canceled
4431
- // by setting completion_request, the old channel stored there is dropped
4432
- // and the associated request is automatically dropped
4433
- cx. editor . completion_request_handle = Some ( tx) ;
4434
- let future = async move {
4435
- let items_future = async move {
4436
- let mut items = Vec :: new ( ) ;
4437
- // TODO if one completion request errors, all other completion requests are discarded (even if they're valid)
4438
- while let Some ( mut lsp_items) = futures. try_next ( ) . await ? {
4439
- items. append ( & mut lsp_items) ;
4440
- }
4441
- anyhow:: Ok ( items)
4442
- } ;
4443
- tokio:: select! {
4444
- biased;
4445
- _ = rx => {
4446
- Ok ( Vec :: new( ) )
4447
- }
4448
- res = items_future => {
4449
- res
4450
- }
4451
- }
4452
- } ;
4453
-
4454
- let trigger_offset = cursor;
4455
-
4456
- // TODO: trigger_offset should be the cursor offset but we also need a starting offset from where we want to apply
4457
- // completion filtering. For example logger.te| should filter the initial suggestion list with "te".
4458
-
4459
- use helix_core:: chars;
4460
- let mut iter = text. chars_at ( cursor) ;
4461
- iter. reverse ( ) ;
4462
- let offset = iter. take_while ( |ch| chars:: char_is_word ( * ch) ) . count ( ) ;
4463
- let start_offset = cursor. saturating_sub ( offset) ;
4464
-
4465
- let trigger_doc = doc. id ( ) ;
4466
- let trigger_view = view. id ;
4467
-
4468
- // FIXME: The commands Context can only have a single callback
4469
- // which means it gets overwritten when executing keybindings
4470
- // with multiple commands or macros. This would mean that completion
4471
- // might be incorrectly applied when repeating the insertmode action
4472
- //
4473
- // TODO: to solve this either make cx.callback a Vec of callbacks or
4474
- // alternatively move `last_insert` to `helix_view::Editor`
4475
- cx. callback = Some ( Box :: new (
4476
- move |compositor : & mut Compositor , _cx : & mut compositor:: Context | {
4477
- let ui = compositor. find :: < ui:: EditorView > ( ) . unwrap ( ) ;
4478
- ui. last_insert . 1 . push ( InsertEvent :: RequestCompletion ) ;
4479
- } ,
4480
- ) ) ;
4481
-
4482
- cx. jobs . callback ( async move {
4483
- let items = future. await ?;
4484
- let call = move |editor : & mut Editor , compositor : & mut Compositor | {
4485
- let ( view, doc) = current_ref ! ( editor) ;
4486
- // check if the completion request is stale.
4487
- //
4488
- // Completions are completed asynchronously and therefore the user could
4489
- //switch document/view or leave insert mode. In all of thoise cases the
4490
- // completion should be discarded
4491
- if editor. mode != Mode :: Insert || view. id != trigger_view || doc. id ( ) != trigger_doc {
4492
- return ;
4493
- }
4494
-
4495
- if items. is_empty ( ) {
4496
- // editor.set_error("No completion available");
4497
- return ;
4498
- }
4499
- let size = compositor. size ( ) ;
4500
- let ui = compositor. find :: < ui:: EditorView > ( ) . unwrap ( ) ;
4501
- let completion_area = ui. set_completion (
4502
- editor,
4503
- savepoint,
4504
- items,
4505
- start_offset,
4506
- trigger_offset,
4507
- size,
4508
- ) ;
4509
- let size = compositor. size ( ) ;
4510
- let signature_help_area = compositor
4511
- . find_id :: < Popup < SignatureHelp > > ( SignatureHelp :: ID )
4512
- . map ( |signature_help| signature_help. area ( size, editor) ) ;
4513
- // Delete the signature help popup if they intersect.
4514
- if matches ! ( ( completion_area, signature_help_area) , ( Some ( a) , Some ( b) ) if a. intersects( b) )
4515
- {
4516
- compositor. remove ( SignatureHelp :: ID ) ;
4517
- }
4518
- } ;
4519
- Ok ( Callback :: EditorCompositor ( Box :: new ( call) ) )
4520
- } ) ;
4276
+ cx. editor . handlers . trigger_completions ( ) ;
4521
4277
}
4522
4278
4523
4279
// comments
@@ -4696,10 +4452,6 @@ fn move_node_bound_impl(cx: &mut Context, dir: Direction, movement: Movement) {
4696
4452
) ;
4697
4453
4698
4454
doc. set_selection ( view. id , selection) ;
4699
-
4700
- // [TODO] temporary workaround until we're not using the idle timer to
4701
- // trigger auto completions any more
4702
- editor. clear_idle_timer ( ) ;
4703
4455
}
4704
4456
} ;
4705
4457
0 commit comments