@@ -12,9 +12,10 @@ use lsp::{
12
12
IoKind , LanguageServer , LanguageServerName , LanguageServerSelector , MessageType ,
13
13
SetTraceParams , TraceValue , notification:: SetTrace ,
14
14
} ;
15
- use project:: { Project , WorktreeId , search:: SearchQuery } ;
15
+ use project:: { Project , WorktreeId , lsp_store :: LanguageServerLogType , search:: SearchQuery } ;
16
16
use std:: { any:: TypeId , borrow:: Cow , sync:: Arc } ;
17
17
use ui:: { Button , Checkbox , ContextMenu , Label , PopoverMenu , ToggleState , prelude:: * } ;
18
+ use util:: ResultExt as _;
18
19
use workspace:: {
19
20
SplitDirection , ToolbarItemEvent , ToolbarItemLocation , ToolbarItemView , Workspace , WorkspaceId ,
20
21
item:: { Item , ItemHandle } ,
@@ -36,7 +37,7 @@ pub struct LogStore {
36
37
}
37
38
38
39
struct ProjectState {
39
- _subscriptions : [ gpui:: Subscription ; 2 ] ,
40
+ _subscriptions : [ gpui:: Subscription ; 3 ] ,
40
41
}
41
42
42
43
trait Message : AsRef < str > {
@@ -102,6 +103,7 @@ impl Message for RpcMessage {
102
103
}
103
104
104
105
pub ( super ) struct LanguageServerState {
106
+ project : WeakEntity < Project > ,
105
107
name : Option < LanguageServerName > ,
106
108
worktree_id : Option < WorktreeId > ,
107
109
kind : LanguageServerKind ,
@@ -183,6 +185,13 @@ pub enum LogKind {
183
185
}
184
186
185
187
impl LogKind {
188
+ fn from_server_log_type ( log_type : & LanguageServerLogType ) -> Self {
189
+ match log_type {
190
+ LanguageServerLogType :: Log ( _) => Self :: Logs ,
191
+ LanguageServerLogType :: Trace ( _) => Self :: Trace ,
192
+ LanguageServerLogType :: Rpc { .. } => Self :: Rpc ,
193
+ }
194
+ }
186
195
fn label ( & self ) -> & ' static str {
187
196
match self {
188
197
LogKind :: Rpc => RPC_MESSAGES ,
@@ -212,10 +221,11 @@ actions!(
212
221
]
213
222
) ;
214
223
215
- pub ( super ) struct GlobalLogStore ( pub WeakEntity < LogStore > ) ;
224
+ pub struct GlobalLogStore ( pub WeakEntity < LogStore > ) ;
216
225
217
226
impl Global for GlobalLogStore { }
218
227
228
+ // todo! do separate headless and local cases here: headless cares only about the downstream_client() part, NO log storage is needed
219
229
pub fn init ( cx : & mut App ) {
220
230
let log_store = cx. new ( LogStore :: new) ;
221
231
cx. set_global ( GlobalLogStore ( log_store. downgrade ( ) ) ) ;
@@ -311,6 +321,7 @@ impl LogStore {
311
321
312
322
pub fn add_project ( & mut self , project : & Entity < Project > , cx : & mut Context < Self > ) {
313
323
let weak_project = project. downgrade ( ) ;
324
+ let subscription_weak_project = weak_project. clone ( ) ;
314
325
self . projects . insert (
315
326
project. downgrade ( ) ,
316
327
ProjectState {
@@ -356,13 +367,42 @@ impl LogStore {
356
367
this. add_language_server_log ( * id, * typ, message, cx) ;
357
368
}
358
369
project:: LanguageServerLogType :: Trace ( _) => {
370
+ // todo! do something with trace level
359
371
this. add_language_server_trace ( * id, message, cx) ;
360
372
}
373
+ project:: LanguageServerLogType :: Rpc { received } => {
374
+ let kind = if * received {
375
+ MessageKind :: Receive
376
+ } else {
377
+ MessageKind :: Send
378
+ } ;
379
+ this. add_language_server_rpc ( * id, kind, message, cx) ;
380
+ }
361
381
}
362
382
}
363
383
_ => { }
364
384
}
365
385
} ) ,
386
+ cx. subscribe_self ( move |_, e, cx| match e {
387
+ Event :: NewServerLogEntry { id, kind, text } => {
388
+ subscription_weak_project
389
+ . update ( cx, |project, cx| {
390
+ if let Some ( ( client, project_id) ) =
391
+ project. lsp_store ( ) . read ( cx) . downstream_client ( )
392
+ {
393
+ client
394
+ . send ( proto:: LanguageServerLog {
395
+ project_id,
396
+ language_server_id : id. to_proto ( ) ,
397
+ message : text. clone ( ) ,
398
+ log_type : Some ( kind. to_proto ( ) ) ,
399
+ } )
400
+ . log_err ( ) ;
401
+ } ;
402
+ } )
403
+ . ok ( ) ;
404
+ }
405
+ } ) ,
366
406
] ,
367
407
} ,
368
408
) ;
@@ -382,6 +422,7 @@ impl LogStore {
382
422
name : Option < LanguageServerName > ,
383
423
worktree_id : Option < WorktreeId > ,
384
424
server : Option < Arc < LanguageServer > > ,
425
+ project : WeakEntity < Project > ,
385
426
cx : & mut Context < Self > ,
386
427
) -> Option < & mut LanguageServerState > {
387
428
let server_state = self . language_servers . entry ( server_id) . or_insert_with ( || {
@@ -390,6 +431,7 @@ impl LogStore {
390
431
name : None ,
391
432
worktree_id : None ,
392
433
kind,
434
+ project,
393
435
rpc_state : None ,
394
436
log_messages : VecDeque :: with_capacity ( MAX_STORED_LOG_ENTRIES ) ,
395
437
trace_messages : VecDeque :: with_capacity ( MAX_STORED_LOG_ENTRIES ) ,
@@ -432,17 +474,21 @@ impl LogStore {
432
474
let language_server_state = self . get_language_server_state ( id) ?;
433
475
434
476
let log_lines = & mut language_server_state. log_messages ;
435
- Self :: add_language_server_message (
477
+ if let Some ( new_message ) = Self :: push_new_message (
436
478
log_lines,
437
- id,
438
479
LogMessage {
439
480
message : message. trim_end ( ) . to_string ( ) ,
440
481
typ,
441
482
} ,
442
483
language_server_state. log_level ,
443
- LogKind :: Logs ,
444
- cx,
445
- ) ;
484
+ ) {
485
+ cx. emit ( Event :: NewServerLogEntry {
486
+ id,
487
+ kind : LanguageServerLogType :: Log ( typ) ,
488
+ text : new_message,
489
+ } ) ;
490
+ }
491
+
446
492
Some ( ( ) )
447
493
}
448
494
@@ -455,38 +501,81 @@ impl LogStore {
455
501
let language_server_state = self . get_language_server_state ( id) ?;
456
502
457
503
let log_lines = & mut language_server_state. trace_messages ;
458
- Self :: add_language_server_message (
504
+ if let Some ( new_message ) = Self :: push_new_message (
459
505
log_lines,
460
- id,
461
506
TraceMessage {
462
507
message : message. trim ( ) . to_string ( ) ,
463
508
} ,
464
509
( ) ,
465
- LogKind :: Trace ,
466
- cx,
467
- ) ;
510
+ ) {
511
+ cx. emit ( Event :: NewServerLogEntry {
512
+ id,
513
+ // todo! Ben, fix this here too!
514
+ kind : LanguageServerLogType :: Trace ( project:: lsp_store:: TraceLevel :: Verbose ) ,
515
+ text : new_message,
516
+ } ) ;
517
+ }
518
+
468
519
Some ( ( ) )
469
520
}
470
521
471
- fn add_language_server_message < T : Message > (
522
+ fn push_new_message < T : Message > (
472
523
log_lines : & mut VecDeque < T > ,
473
- id : LanguageServerId ,
474
524
message : T ,
475
525
current_severity : <T as Message >:: Level ,
476
- kind : LogKind ,
477
- cx : & mut Context < Self > ,
478
- ) {
526
+ ) -> Option < String > {
479
527
while log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
480
528
log_lines. pop_front ( ) ;
481
529
}
482
- let text = message. as_ref ( ) . to_string ( ) ;
483
530
let visible = message. should_include ( current_severity) ;
531
+
532
+ let re = visible. then ( || message. as_ref ( ) . to_string ( ) ) ;
484
533
log_lines. push_back ( message) ;
534
+ re
535
+ }
485
536
486
- if visible {
487
- cx. emit ( Event :: NewServerLogEntry { id, kind, text } ) ;
488
- cx. notify ( ) ;
537
+ fn add_language_server_rpc (
538
+ & mut self ,
539
+ language_server_id : LanguageServerId ,
540
+ kind : MessageKind ,
541
+ message : & str ,
542
+ cx : & mut Context < ' _ , LogStore > ,
543
+ ) {
544
+ let Some ( state) = self
545
+ . get_language_server_state ( language_server_id)
546
+ . and_then ( |state| state. rpc_state . as_mut ( ) )
547
+ else {
548
+ return ;
549
+ } ;
550
+
551
+ let rpc_log_lines = & mut state. rpc_messages ;
552
+ if state. last_message_kind != Some ( kind) {
553
+ while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
554
+ rpc_log_lines. pop_front ( ) ;
555
+ }
556
+ let line_before_message = match kind {
557
+ MessageKind :: Send => SEND_LINE ,
558
+ MessageKind :: Receive => RECEIVE_LINE ,
559
+ } ;
560
+ rpc_log_lines. push_back ( RpcMessage {
561
+ message : line_before_message. to_string ( ) ,
562
+ } ) ;
563
+ cx. emit ( Event :: NewServerLogEntry {
564
+ id : language_server_id,
565
+ kind : LanguageServerLogType :: Rpc {
566
+ received : kind == MessageKind :: Receive ,
567
+ } ,
568
+ text : line_before_message. to_string ( ) ,
569
+ } ) ;
489
570
}
571
+
572
+ while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
573
+ rpc_log_lines. pop_front ( ) ;
574
+ }
575
+
576
+ rpc_log_lines. push_back ( RpcMessage {
577
+ message : message. trim ( ) . to_owned ( ) ,
578
+ } ) ;
490
579
}
491
580
492
581
fn remove_language_server ( & mut self , id : LanguageServerId , cx : & mut Context < Self > ) {
@@ -523,7 +612,7 @@ impl LogStore {
523
612
} )
524
613
}
525
614
526
- fn enable_rpc_trace_for_language_server (
615
+ pub fn enable_rpc_trace_for_language_server (
527
616
& mut self ,
528
617
server_id : LanguageServerId ,
529
618
) -> Option < & mut LanguageServerRpcState > {
@@ -666,47 +755,19 @@ impl LogStore {
666
755
}
667
756
} ;
668
757
669
- let state = self
670
- . get_language_server_state ( language_server_id) ?
671
- . rpc_state
672
- . as_mut ( ) ?;
673
758
let kind = if is_received {
674
759
MessageKind :: Receive
675
760
} else {
676
761
MessageKind :: Send
677
762
} ;
678
763
679
- let rpc_log_lines = & mut state. rpc_messages ;
680
- if state. last_message_kind != Some ( kind) {
681
- while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
682
- rpc_log_lines. pop_front ( ) ;
683
- }
684
- let line_before_message = match kind {
685
- MessageKind :: Send => SEND_LINE ,
686
- MessageKind :: Receive => RECEIVE_LINE ,
687
- } ;
688
- rpc_log_lines. push_back ( RpcMessage {
689
- message : line_before_message. to_string ( ) ,
690
- } ) ;
691
- cx. emit ( Event :: NewServerLogEntry {
692
- id : language_server_id,
693
- kind : LogKind :: Rpc ,
694
- text : line_before_message. to_string ( ) ,
695
- } ) ;
696
- }
697
-
698
- while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
699
- rpc_log_lines. pop_front ( ) ;
700
- }
701
-
702
- let message = message. trim ( ) ;
703
- rpc_log_lines. push_back ( RpcMessage {
704
- message : message. to_string ( ) ,
705
- } ) ;
764
+ self . add_language_server_rpc ( language_server_id, kind, message, cx) ;
706
765
cx. emit ( Event :: NewServerLogEntry {
707
766
id : language_server_id,
708
- kind : LogKind :: Rpc ,
709
- text : message. to_string ( ) ,
767
+ kind : LanguageServerLogType :: Rpc {
768
+ received : is_received,
769
+ } ,
770
+ text : message. to_owned ( ) ,
710
771
} ) ;
711
772
cx. notify ( ) ;
712
773
Some ( ( ) )
@@ -762,7 +823,7 @@ impl LspLogView {
762
823
move |log_view, _, e, window, cx| match e {
763
824
Event :: NewServerLogEntry { id, kind, text } => {
764
825
if log_view. current_server_id == Some ( * id)
765
- && * kind == log_view. active_entry_kind
826
+ && LogKind :: from_server_log_type ( kind) == log_view. active_entry_kind
766
827
{
767
828
log_view. editor . update ( cx, |editor, cx| {
768
829
editor. set_read_only ( false ) ;
@@ -1084,6 +1145,21 @@ impl LspLogView {
1084
1145
} else {
1085
1146
log_store. disable_rpc_trace_for_language_server ( server_id) ;
1086
1147
}
1148
+
1149
+ if let Some ( server_state) = log_store. language_servers . get ( server_id) {
1150
+ server_state
1151
+ . project
1152
+ . update ( cx, |project, cx| {
1153
+ if let Some ( ( client, project) ) =
1154
+ project. lsp_store ( ) . read ( cx) . upstream_client ( )
1155
+ {
1156
+ // todo! client.send a new proto message to propagate the enabled
1157
+ // !!!! we have to have a handler on both headless and normal projects
1158
+ // that handler has to touch the Global<LspLog> and amend the sending bit
1159
+ }
1160
+ } )
1161
+ . ok ( ) ;
1162
+ } ;
1087
1163
} ) ;
1088
1164
if !enabled && Some ( server_id) == self . current_server_id {
1089
1165
self . show_logs_for_server ( server_id, window, cx) ;
@@ -1122,6 +1198,8 @@ impl LspLogView {
1122
1198
window : & mut Window ,
1123
1199
cx : & mut Context < Self > ,
1124
1200
) {
1201
+ // todo! there's no language server for the remote case, hence no server info!
1202
+ // BUT we do have the capabilities info within the LspStore.lsp_server_capabilities
1125
1203
let lsp_store = self . project . read ( cx) . lsp_store ( ) ;
1126
1204
let Some ( server) = lsp_store. read ( cx) . language_server_for_id ( server_id) else {
1127
1205
return ;
@@ -1746,7 +1824,7 @@ impl LspLogToolbarItemView {
1746
1824
pub enum Event {
1747
1825
NewServerLogEntry {
1748
1826
id : LanguageServerId ,
1749
- kind : LogKind ,
1827
+ kind : LanguageServerLogType ,
1750
1828
text : String ,
1751
1829
} ,
1752
1830
}
0 commit comments