@@ -12,9 +12,10 @@ use lsp::{
1212 IoKind , LanguageServer , LanguageServerName , LanguageServerSelector , MessageType ,
1313 SetTraceParams , TraceValue , notification:: SetTrace ,
1414} ;
15- use project:: { Project , WorktreeId , search:: SearchQuery } ;
15+ use project:: { Project , WorktreeId , lsp_store :: LanguageServerLogType , search:: SearchQuery } ;
1616use std:: { any:: TypeId , borrow:: Cow , sync:: Arc } ;
1717use ui:: { Button , Checkbox , ContextMenu , Label , PopoverMenu , ToggleState , prelude:: * } ;
18+ use util:: ResultExt as _;
1819use workspace:: {
1920 SplitDirection , ToolbarItemEvent , ToolbarItemLocation , ToolbarItemView , Workspace , WorkspaceId ,
2021 item:: { Item , ItemHandle } ,
@@ -36,7 +37,7 @@ pub struct LogStore {
3637}
3738
3839struct ProjectState {
39- _subscriptions : [ gpui:: Subscription ; 2 ] ,
40+ _subscriptions : [ gpui:: Subscription ; 3 ] ,
4041}
4142
4243trait Message : AsRef < str > {
@@ -102,6 +103,7 @@ impl Message for RpcMessage {
102103}
103104
104105pub ( super ) struct LanguageServerState {
106+ project : WeakEntity < Project > ,
105107 name : Option < LanguageServerName > ,
106108 worktree_id : Option < WorktreeId > ,
107109 kind : LanguageServerKind ,
@@ -183,6 +185,13 @@ pub enum LogKind {
183185}
184186
185187impl 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+ }
186195 fn label ( & self ) -> & ' static str {
187196 match self {
188197 LogKind :: Rpc => RPC_MESSAGES ,
@@ -212,10 +221,11 @@ actions!(
212221 ]
213222) ;
214223
215- pub ( super ) struct GlobalLogStore ( pub WeakEntity < LogStore > ) ;
224+ pub struct GlobalLogStore ( pub WeakEntity < LogStore > ) ;
216225
217226impl Global for GlobalLogStore { }
218227
228+ // todo! do separate headless and local cases here: headless cares only about the downstream_client() part, NO log storage is needed
219229pub fn init ( cx : & mut App ) {
220230 let log_store = cx. new ( LogStore :: new) ;
221231 cx. set_global ( GlobalLogStore ( log_store. downgrade ( ) ) ) ;
@@ -311,6 +321,7 @@ impl LogStore {
311321
312322 pub fn add_project ( & mut self , project : & Entity < Project > , cx : & mut Context < Self > ) {
313323 let weak_project = project. downgrade ( ) ;
324+ let subscription_weak_project = weak_project. clone ( ) ;
314325 self . projects . insert (
315326 project. downgrade ( ) ,
316327 ProjectState {
@@ -356,13 +367,42 @@ impl LogStore {
356367 this. add_language_server_log ( * id, * typ, message, cx) ;
357368 }
358369 project:: LanguageServerLogType :: Trace ( _) => {
370+ // todo! do something with trace level
359371 this. add_language_server_trace ( * id, message, cx) ;
360372 }
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+ }
361381 }
362382 }
363383 _ => { }
364384 }
365385 } ) ,
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+ } ) ,
366406 ] ,
367407 } ,
368408 ) ;
@@ -382,6 +422,7 @@ impl LogStore {
382422 name : Option < LanguageServerName > ,
383423 worktree_id : Option < WorktreeId > ,
384424 server : Option < Arc < LanguageServer > > ,
425+ project : WeakEntity < Project > ,
385426 cx : & mut Context < Self > ,
386427 ) -> Option < & mut LanguageServerState > {
387428 let server_state = self . language_servers . entry ( server_id) . or_insert_with ( || {
@@ -390,6 +431,7 @@ impl LogStore {
390431 name : None ,
391432 worktree_id : None ,
392433 kind,
434+ project,
393435 rpc_state : None ,
394436 log_messages : VecDeque :: with_capacity ( MAX_STORED_LOG_ENTRIES ) ,
395437 trace_messages : VecDeque :: with_capacity ( MAX_STORED_LOG_ENTRIES ) ,
@@ -429,17 +471,21 @@ impl LogStore {
429471 let language_server_state = self . get_language_server_state ( id) ?;
430472
431473 let log_lines = & mut language_server_state. log_messages ;
432- Self :: add_language_server_message (
474+ if let Some ( new_message ) = Self :: push_new_message (
433475 log_lines,
434- id,
435476 LogMessage {
436477 message : message. trim_end ( ) . to_string ( ) ,
437478 typ,
438479 } ,
439480 language_server_state. log_level ,
440- LogKind :: Logs ,
441- cx,
442- ) ;
481+ ) {
482+ cx. emit ( Event :: NewServerLogEntry {
483+ id,
484+ kind : LanguageServerLogType :: Log ( typ) ,
485+ text : new_message,
486+ } ) ;
487+ }
488+
443489 Some ( ( ) )
444490 }
445491
@@ -452,38 +498,81 @@ impl LogStore {
452498 let language_server_state = self . get_language_server_state ( id) ?;
453499
454500 let log_lines = & mut language_server_state. trace_messages ;
455- Self :: add_language_server_message (
501+ if let Some ( new_message ) = Self :: push_new_message (
456502 log_lines,
457- id,
458503 TraceMessage {
459504 message : message. trim ( ) . to_string ( ) ,
460505 } ,
461506 ( ) ,
462- LogKind :: Trace ,
463- cx,
464- ) ;
507+ ) {
508+ cx. emit ( Event :: NewServerLogEntry {
509+ id,
510+ // todo! Ben, fix this here too!
511+ kind : LanguageServerLogType :: Trace ( project:: lsp_store:: TraceLevel :: Verbose ) ,
512+ text : new_message,
513+ } ) ;
514+ }
515+
465516 Some ( ( ) )
466517 }
467518
468- fn add_language_server_message < T : Message > (
519+ fn push_new_message < T : Message > (
469520 log_lines : & mut VecDeque < T > ,
470- id : LanguageServerId ,
471521 message : T ,
472522 current_severity : <T as Message >:: Level ,
473- kind : LogKind ,
474- cx : & mut Context < Self > ,
475- ) {
523+ ) -> Option < String > {
476524 while log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
477525 log_lines. pop_front ( ) ;
478526 }
479- let text = message. as_ref ( ) . to_string ( ) ;
480527 let visible = message. should_include ( current_severity) ;
528+
529+ let re = visible. then ( || message. as_ref ( ) . to_string ( ) ) ;
481530 log_lines. push_back ( message) ;
531+ re
532+ }
482533
483- if visible {
484- cx. emit ( Event :: NewServerLogEntry { id, kind, text } ) ;
485- cx. notify ( ) ;
534+ fn add_language_server_rpc (
535+ & mut self ,
536+ language_server_id : LanguageServerId ,
537+ kind : MessageKind ,
538+ message : & str ,
539+ cx : & mut Context < ' _ , LogStore > ,
540+ ) {
541+ let Some ( state) = self
542+ . get_language_server_state ( language_server_id)
543+ . and_then ( |state| state. rpc_state . as_mut ( ) )
544+ else {
545+ return ;
546+ } ;
547+
548+ let rpc_log_lines = & mut state. rpc_messages ;
549+ if state. last_message_kind != Some ( kind) {
550+ while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
551+ rpc_log_lines. pop_front ( ) ;
552+ }
553+ let line_before_message = match kind {
554+ MessageKind :: Send => SEND_LINE ,
555+ MessageKind :: Receive => RECEIVE_LINE ,
556+ } ;
557+ rpc_log_lines. push_back ( RpcMessage {
558+ message : line_before_message. to_string ( ) ,
559+ } ) ;
560+ cx. emit ( Event :: NewServerLogEntry {
561+ id : language_server_id,
562+ kind : LanguageServerLogType :: Rpc {
563+ received : kind == MessageKind :: Receive ,
564+ } ,
565+ text : line_before_message. to_string ( ) ,
566+ } ) ;
486567 }
568+
569+ while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
570+ rpc_log_lines. pop_front ( ) ;
571+ }
572+
573+ rpc_log_lines. push_back ( RpcMessage {
574+ message : message. trim ( ) . to_owned ( ) ,
575+ } ) ;
487576 }
488577
489578 fn remove_language_server ( & mut self , id : LanguageServerId , cx : & mut Context < Self > ) {
@@ -520,7 +609,7 @@ impl LogStore {
520609 } )
521610 }
522611
523- fn enable_rpc_trace_for_language_server (
612+ pub fn enable_rpc_trace_for_language_server (
524613 & mut self ,
525614 server_id : LanguageServerId ,
526615 ) -> Option < & mut LanguageServerRpcState > {
@@ -663,47 +752,19 @@ impl LogStore {
663752 }
664753 } ;
665754
666- let state = self
667- . get_language_server_state ( language_server_id) ?
668- . rpc_state
669- . as_mut ( ) ?;
670755 let kind = if is_received {
671756 MessageKind :: Receive
672757 } else {
673758 MessageKind :: Send
674759 } ;
675760
676- let rpc_log_lines = & mut state. rpc_messages ;
677- if state. last_message_kind != Some ( kind) {
678- while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
679- rpc_log_lines. pop_front ( ) ;
680- }
681- let line_before_message = match kind {
682- MessageKind :: Send => SEND_LINE ,
683- MessageKind :: Receive => RECEIVE_LINE ,
684- } ;
685- rpc_log_lines. push_back ( RpcMessage {
686- message : line_before_message. to_string ( ) ,
687- } ) ;
688- cx. emit ( Event :: NewServerLogEntry {
689- id : language_server_id,
690- kind : LogKind :: Rpc ,
691- text : line_before_message. to_string ( ) ,
692- } ) ;
693- }
694-
695- while rpc_log_lines. len ( ) + 1 >= MAX_STORED_LOG_ENTRIES {
696- rpc_log_lines. pop_front ( ) ;
697- }
698-
699- let message = message. trim ( ) ;
700- rpc_log_lines. push_back ( RpcMessage {
701- message : message. to_string ( ) ,
702- } ) ;
761+ self . add_language_server_rpc ( language_server_id, kind, message, cx) ;
703762 cx. emit ( Event :: NewServerLogEntry {
704763 id : language_server_id,
705- kind : LogKind :: Rpc ,
706- text : message. to_string ( ) ,
764+ kind : LanguageServerLogType :: Rpc {
765+ received : is_received,
766+ } ,
767+ text : message. to_owned ( ) ,
707768 } ) ;
708769 cx. notify ( ) ;
709770 Some ( ( ) )
@@ -757,7 +818,7 @@ impl LspLogView {
757818 move |log_view, _, e, window, cx| match e {
758819 Event :: NewServerLogEntry { id, kind, text } => {
759820 if log_view. current_server_id == Some ( * id)
760- && * kind == log_view. active_entry_kind
821+ && LogKind :: from_server_log_type ( kind) == log_view. active_entry_kind
761822 {
762823 log_view. editor . update ( cx, |editor, cx| {
763824 editor. set_read_only ( false ) ;
@@ -1075,6 +1136,21 @@ impl LspLogView {
10751136 } else {
10761137 log_store. disable_rpc_trace_for_language_server ( server_id) ;
10771138 }
1139+
1140+ if let Some ( server_state) = log_store. language_servers . get ( server_id) {
1141+ server_state
1142+ . project
1143+ . update ( cx, |project, cx| {
1144+ if let Some ( ( client, project) ) =
1145+ project. lsp_store ( ) . read ( cx) . upstream_client ( )
1146+ {
1147+ // todo! client.send a new proto message to propagate the enabled
1148+ // !!!! we have to have a handler on both headless and normal projects
1149+ // that handler has to touch the Global<LspLog> and amend the sending bit
1150+ }
1151+ } )
1152+ . ok ( ) ;
1153+ } ;
10781154 } ) ;
10791155 if !enabled && Some ( server_id) == self . current_server_id {
10801156 self . show_logs_for_server ( server_id, window, cx) ;
@@ -1113,6 +1189,8 @@ impl LspLogView {
11131189 window : & mut Window ,
11141190 cx : & mut Context < Self > ,
11151191 ) {
1192+ // todo! there's no language server for the remote case, hence no server info!
1193+ // BUT we do have the capabilities info within the LspStore.lsp_server_capabilities
11161194 let lsp_store = self . project . read ( cx) . lsp_store ( ) ;
11171195 let Some ( server) = lsp_store. read ( cx) . language_server_for_id ( server_id) else {
11181196 return ;
@@ -1737,7 +1815,7 @@ impl LspLogToolbarItemView {
17371815pub enum Event {
17381816 NewServerLogEntry {
17391817 id : LanguageServerId ,
1740- kind : LogKind ,
1818+ kind : LanguageServerLogType ,
17411819 text : String ,
17421820 } ,
17431821}
0 commit comments