
    PL
jce                        d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z
 ddlmZmZmZmZmZmZ ddlmZ ddlmZmZmZ ddlmZmZmZmZmZ dd	lmZm Z m!Z!  ej"        d
          Z#dZ$ G d d          Z% G d d          Z&ddZ'dgZ(dS )u  Service-level orchestration for LSP clients.

The :class:`LSPService` is the bridge between the synchronous
file_operations layer and the async :class:`agent.lsp.client.LSPClient`.

Design choices:

- A **single asyncio event loop** runs in a background thread.  All
  client work happens on that loop.  Synchronous callers from
  ``tools/file_operations.py`` use :meth:`get_diagnostics_sync` to
  open + wait + drain in one blocking call.

- One client per ``(server_id, workspace_root)`` key.  Lazy spawn:
  the first request for a key spawns the client; subsequent requests
  re-use it.

- A **broken-set** records ``(server_id, workspace_root)`` pairs that
  failed to spawn or initialize.  These are never retried for the
  life of the service.  Mirrors OpenCode's design.

- A **delta baseline** map keeps "diagnostics-as-of-the-last-snapshot"
  per file.  ``snapshot_baseline()`` is called BEFORE a write; the
  next ``get_diagnostics_sync()`` returns only diagnostics that
  weren't in the baseline.  This is the lift from Claude Code's
  ``beforeFileEdited`` / ``getNewDiagnostics`` pattern, except wired
  to the local LSP layer instead of MCP IDE RPC.

The service is **off by default** — call :meth:`is_active` to check
whether it's actually doing anything.  When LSP is disabled in
config, when no git workspace can be detected, when all configured
servers are missing binaries and auto-install is off, ``is_active``
returns False and the file_operations layer falls through to the
in-process syntax check.
    )annotationsN)Future)AnyCallableDictListOptionalTuple)eventlog)DIAGNOSTICS_DOCUMENT_WAIT	LSPClientfile_uri)ServerContext	ServerDef	SpawnSpecfind_server_for_filelanguage_id_for)clear_cacheis_inside_workspaceresolve_workspace_for_filezagent.lsp.manageriX  c                  @    e Zd ZdZddZddZddZddddZddZdS )_BackgroundLoopu   A daemon thread that owns one asyncio event loop.

    Provides :meth:`run` for synchronous callers — submits a coroutine
    to the loop and blocks until it finishes (or a timeout fires).
    returnNonec                R    d | _         d | _        t          j                    | _        d S N)_loop_thread	threadingEvent_readyselfs    5/home/kuhnn/.hermes/hermes-agent/agent/lsp/manager.py__init__z_BackgroundLoop.__init__L   s#    :>
37o''    c                    | j         d S t          j        | j        dd          | _         | j                                          | j                            d           d S )Nzhermes-lsp-loopT)targetnamedaemong      @timeout)r   r   Thread_run_foreverstartr!   waitr"   s    r$   r/   z_BackgroundLoop.startQ   si    <#F '$"
 
 

 	%%%%%r&   c                ^   t          j                    }|| _        t          j        |           | j                                         	 |                                 	 |                                 d S # t          $ r Y d S w xY w# 	 |                                 w # t          $ r Y w w xY wxY wr   )	asyncionew_event_loopr   set_event_loopr!   setrun_foreverclose	Exceptionr#   loops     r$   r.   z_BackgroundLoop._run_forever\   s    %''
t$$$	

   

   sB   	B A4 4
BBB,BB,
B)&B,(B))B,Nr+   r,   Optional[float]r   c               B   ddl m} | j        7t          j        |          r|                                 t          d           ||| j                  }|t          d          	 |                    |          S # t          $ r |	                                  w xY w)zSubmit a coroutine to the loop and block until done.

        Returns the coroutine's result, or raises its exception.
        r   )safe_schedule_threadsafeNzbackground loop not startedzbackground loop not runningr+   )
agent.async_utilsr=   r   r2   iscoroutiner7   RuntimeErrorresultr8   cancel)r#   coror,   r=   futs        r$   runz_BackgroundLoop.runi   s    
 	?>>>>>:"4(( 

<===&&tTZ88;<===	::g:... 	 	 	JJLLL	s   (A> > Bc                    | j         }|d S 	 |                    |j                   n# t          $ r Y nw xY w| j        | j                            d           d | _         d | _        d S )N       @r+   )r   call_soon_threadsafestopr@   r   joinr9   s     r$   rI   z_BackgroundLoop.stop|   s    z<F	%%di0000 	 	 	D	<#Lc***
s   ( 
55r   r   )r,   r;   r   r   )	__name__
__module____qualname____doc__r%   r/   r.   rE   rI    r&   r$   r   r   E   s         ( ( ( (
	& 	& 	& 	&    7;      &     r&   r   c                      e Zd ZdZddddedd2dZed3d            Zd4dZd5dZ	d6dZ
ddddd7d%Zd8d(Zd9d)Zd:d*Zd:d+Zd:d,Zd;d.Zd9d/Zd<d1ZdS )=
LSPServicezThe process-wide LSP service.

    Created once via :meth:`create_from_config`; the
    :func:`agent.lsp.get_service` accessor manages the singleton.
    Most callers should use that accessor rather than constructing
    :class:`LSPService` directly.
    N)binary_overridesenv_overridesinit_overridesdisabled_serversidle_timeoutenabledbool	wait_modestrwait_timeoutfloatinstall_strategyrS   Optional[Dict[str, List[str]]]rT   #Optional[Dict[str, Dict[str, str]]]rU   #Optional[Dict[str, Dict[str, Any]]]rV   Optional[List[str]]rW   r   r   c       	           || _         |dv r|nd| _        || _        || _        |pi | _        |pi | _        |pi | _        t          |pg           | _        |	| _	        t                      | _        | j         r| j                                         i | _        t                      | _        i | _        i | _        t#          j                    | _        i | _        d S )N>   fulldocumentre   )_enabled
_wait_mode_wait_timeout_install_strategy_binary_overrides_env_overrides_init_overridesr5   _disabled_servers_idle_timeoutr   r   r/   _clients_broken	_spawning
_last_usedr   Lock_state_lock_delta_baseline)
r#   rX   rZ   r\   r^   rS   rT   rU   rV   rW   s
             r$   r%   zLSPService.__init__   s      '04H'H'H))j)!1!1!7R+1r-3!$%5%;!<!<)$&&
= 	J ;=EE@B8:$>++ ACr&   Optional['LSPService']c           
        	 ddl m}  |            }n3# t          $ r&}t                              d|           Y d}~dS d}~ww xY wt          |t                    r|                    d          pi ni }t          |t                    si }t          |                    dd                    }|                    dd	          }t          |                    d
t                              }|                    dd          }|                    d          pi }	g }
i }i }i }t          |	t                    r|	                                D ]\  }}t          |t                    s|                    d          r|
                    |           |                    d          }t          |t                    r|r|||<   |                    d          }t          |t                    r!d |                                D             ||<   |                    d          }t          |t                    r|||<    | ||||||||
          S )zBuild a service from ``hermes_cli.config`` settings.

        Returns ``None`` if the config can't be loaded.  The service
        itself returns ``is_active()`` False when LSP is disabled.
        r   )load_configzLSP config load failed: %sNlsprX   TrZ   re   r\   r^   autoserversdisabledcommandenvc                4    i | ]\  }}|t          |          S rP   )r[   ).0kvs      r$   
<dictcomp>z1LSPService.create_from_config.<locals>.<dictcomp>   s$    *M*M*MA1c!ff*M*M*Mr&   initialization_options)rX   rZ   r\   r^   rS   rT   rU   rV   )hermes_cli.configrx   r8   loggerdebug
isinstancedictgetrY   r]   r   itemsappendlist)clsrx   cfgelsp_cfgrX   rZ   r\   r^   servers_cfgr|   rS   rT   rU   r)   subcmdr~   inits                      r$   create_from_configzLSPService.create_from_config   ss   	555555+--CC 	 	 	LL5q99944444	 -7sD,A,AI3775>>'Rr'4(( 	Gw{{9d3344KKZ88	W[[9RSSTT";;'96BBkk),,2133546k4(( 	0(..00 0 0	c!#t,, 77:&& *OOD)))ggi((c4(( 1S 1-0$T*ggennc4(( N*M*M*M*M*MM$'ww788dD)) 0+/N4(s%--')%	
 	
 	
 		
s    
A>Ac                    | j         S )z8Return True iff this service should be consulted at all.)rf   r"   s    r$   	is_activezLSPService.is_active   s
    }r&   	file_pathc                   | j         sdS t          |          }||j        | j        v rdS t	          |          \  }}|r|sdS 	 |                    ||          p|}n# t          $ r |}Y nw xY w|j        |f| j        v rdS dS )u@  Return True iff LSP should run for this specific file.

        Gates on workspace detection (file or cwd inside a git worktree),
        on whether any registered server matches the extension, and
        on whether the (server_id, workspace_root) pair is in the
        broken-set from a previous spawn failure.

        Files in already-broken pairs return False so the file_operations
        layer skips the LSP path entirely — no spawn attempts, no
        timeout cost — until the service is restarted (``hermes lsp
        restart``) or the process exits.
        FNT)rf   r   	server_idrm   r   resolve_rootr8   rp   )r#   r   srvws_rootgated_inper_server_roots         r$   enabled_forzLSPService.enabled_for   s     } 	5"9--;#-4+AAA56yAA 	H 	5
	&!..y'BBMgOO 	& 	& 	&%OOO	&M?+t|;;5ts   A A,+A,c                   |                      |          sdS 	 | j                            |                     |          d          }|pg | j        t
          j                            |          <   dS # t          $ rd}t          
                    d||           |                     ||           g | j        t
          j                            |          <   Y d}~dS d}~ww xY w)u  Snapshot current diagnostics for ``file_path`` as the delta baseline.

        Called BEFORE a write so the next ``get_diagnostics_sync()``
        can filter out pre-existing errors.  Best-effort — failures
        are silently swallowed so a flaky server can't break a write.

        Outer timeouts (e.g. server hangs during initialize) mark the
        (server_id, workspace_root) pair as broken so subsequent edits
        skip it instantly instead of re-paying the timeout cost.
        Ng       @r+   z#baseline snapshot failed for %s: %s)r   r   rE   _snapshot_asyncru   ospathabspathr8   r   r   _mark_broken_for_file)r#   r   diagsr   s       r$   snapshot_baselinezLSPService.snapshot_baseline  s     	** 	F	BJNN4#7#7	#B#BCNPPE?D{D !;!;<<< 	B 	B 	BLL>	1MMM&&y!444?AD !;!;<<<<<<<	Bs   AA3 3
C!=ACC!T)deltar,   
line_shiftr   r,   r;   r   (Optional[Callable[[int], Optional[int]]]List[Dict[str, Any]]c               `   |                      |          sg S t          |          }|r|j        nd}	 ||n	| j        dz   }| j                            |                     |          |          pg }n# t          j        $ rS}	t          j
        ||           t                              d||	           |                     ||	           g cY d}	~	S d}	~	wt          $ rT}	t          j        |||	           t                              d||	           |                     ||	           g cY d}	~	S d}	~	ww xY wt           j                            |          }
|r| j                            |
          pg }|r.|ddlm}  |||          }d	 |D             fd
|D             }	 | j                            |                     |          d          pg }n# t          $ r g }Y nw xY w|r
|| j        |
<   |r$t          j        ||t3          |                     nt          j        ||           |S )u  Synchronously open ``file_path`` in the right server, wait for
        diagnostics, return them.

        If ``delta`` is True (default), the result is filtered against
        any baseline previously captured via :meth:`snapshot_baseline`.
        Diagnostics present in the baseline are removed so the caller
        only sees errors introduced by the current edit.

        When ``line_shift`` is provided, baseline diagnostics are
        remapped through it before the set-difference.  This handles
        the case where the edit deleted or inserted lines, causing
        pre-existing diagnostics below the edit point to surface at
        different line numbers in the post-edit snapshot — without
        the shift, they'd all look "introduced by this edit".  Pass
        a callable built by
        :func:`agent.lsp.range_shift.build_line_shift` (pre_text,
        post_text).  Omit when pre/post content isn't available;
        the unshifted comparison still catches diagnostics that
        didn't move.

        Returns an empty list when LSP is disabled, when no workspace
        can be detected, when no server matches, or when the server
        can't be spawned.  Never raises.
        ?NrG   r+   z"LSP diagnostics timeout for %s: %sz'LSP diagnostics fetch failed for %s: %sr   )shift_baselinec                ,    h | ]}t          |          S rP   	_diag_key)r   ds     r$   	<setcomp>z2LSPService.get_diagnostics_sync.<locals>.<setcomp>u  s    777	!777r&   c                6    g | ]}t          |          v|S rP   r   )r   r   seens     r$   
<listcomp>z3LSPService.get_diagnostics_sync.<locals>.<listcomp>v  s)    FFFqYq\\-E-E-E-E-Er&   )r   r   r   rh   r   rE   _open_and_wait_asyncr2   TimeoutErrorr   log_timeoutr   r   r   r8   log_server_errorr   r   r   ru   r   agent.lsp.range_shiftr   _current_diags_asynclog_diagnosticslen	log_clean)r#   r   r   r,   r   r   r   tr   r   abs_pathbaseliner   freshr   s                 @r$   get_diagnostics_synczLSPService.get_diagnostics_sync3  s   @ 	** 	I #9--%(1CMMc		".D4F4LAJNN4#<#<Y#G#GQRNSSYWYEE# 	 	 	 I666LL=y!LLL&&y!444IIIIII 	 	 	%iA>>>LLBIqQQQ&&y!444IIIIII		 7??9-- 	7+//99?RH 
G) EDDDDD-~h
CCH77h777FFFFEFFF
t'@'@'K'KUXYY_]_    716$X. 	5$Y	3u::FFFFy)444sC   ?A4 4D2ACD2D2A	D-'D2-D2#1G G$#G$excBaseExceptionc                B   t          |          }|dS t          |          \  }}|r|sdS 	 |                    ||          p|}n# t          $ r |}Y nw xY w|j        |f}|| j        v }| j                            |           | j        5  | j        	                    |d          }	ddd           n# 1 swxY w Y   |	@	 | j
                            |	                                d           n# t          $ r Y nw xY w|st          j        |j        ||           dS dS )u  Mark the (server_id, workspace_root) pair as broken so subsequent
        edits skip it instantly instead of re-paying timeout cost.

        Called when the outer ``_loop.run`` timeout cancels an in-flight
        spawn/initialize that the inner ``_get_or_spawn`` task was still
        holding open.  Without this, every subsequent write would re-enter
        the spawn path and re-pay the full ``snapshot_baseline``
        timeout (8s) until the binary is fixed.

        Also kills any orphan client process that survived the cancelled
        future, and emits a single eventlog WARNING so the user knows
        which server gave up.

        ``exc`` is whatever exception the outer wrapper caught — used
        only for logging, never re-raised.
        Ng      ?r+   )r   r   r   r8   r   rp   addrt   ro   popr   rE   shutdownr   log_spawn_failed)
r#   r   r   r   r   gatedr   keyalready_brokenclients
             r$   r   z LSPService._mark_broken_for_file  s   " #9--;F3I>> 	E 	F	&!..y'BBMgOO 	& 	& 	&%OOO	&}o.,  	2 	2]&&sD11F	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 	2 
v00#>>>>     	K%cm_cJJJJJ	K 	Ks5   A AAB33B7:B7.C0 0
C=<C=c                *   | j         sdS 	 | j                            |                                 d           n2# t          $ r%}t
                              d|           Y d}~nd}~ww xY w| j                                         t                       dS )z3Tear down all clients and stop the background loop.Ng      $@r+   zLSP shutdown error: %s)	rf   r   rE   _shutdown_asyncr8   r   r   rI   r   )r#   r   s     r$   r   zLSPService.shutdown  s    } 	F	6JNN4//114N@@@@ 	6 	6 	6LL1155555555	6
s   .: 
A)A$$A)c                  K   |                      |           d {V }|g S 	 |                    |t          |                     d {V }|                    ||| j                   d {V  n4# t
          $ r'}t                              d|           g cY d }~S d }~ww xY wt          j                    | j	        |j
        |j        f<   t          |                    |                    S )Nlanguage_idmodezsnapshot open/wait failed: %s)_get_or_spawn	open_filer   wait_for_diagnosticsrg   r8   r   r   timerr   r   workspace_rootr   diagnostics_forr#   r   r   versionr   s        r$   r   zLSPService._snapshot_async  s     )))44444444>I	",,YOT]D^D^,________G--it-WWWWWWWWWW 	 	 	LL8!<<<IIIIII	 FJY[[)6+@ABF**955666s   AA1 1
B";BB"B"c                  K   |                      |           d {V }|g S 	 |                    |t          |                     d {V }|                    |           d {V  |                    ||| j                   d {V  n5# t          $ r(}t                              d||           g cY d }~S d }~ww xY wt          j	                    | j
        |j        |j        f<   t          |                    |                    S )Nr   r   zopen/wait failed for %s: %s)r   r   r   	save_filer   rg   r8   r   r   r   rr   r   r   r   r   r   s        r$   r   zLSPService._open_and_wait_async  sG     )))44444444>I	",,YOT]D^D^,________G""9-----------it-WWWWWWWWWW 	 	 	LL6	1EEEIIIIII	 FJY[[)6+@ABF**955666s   A(B 
B>B93B>9B>c                $  K   t          |          \  }}t          |          }|r|r|sg S | j        5  | j                            |j        |f          }d d d            n# 1 swxY w Y   |g S t          |                    |                    S r   )r   r   rt   ro   r   r   r   r   )r#   r   wsr   r   r   s         r$   r   zLSPService._current_diags_async  s      .y99	E"9-- 	u 	 	I 	< 	<]&&r':;;F	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	< 	<>IF**955666s   "A!!A%(A%Optional[LSPClient]c           	       K   t          |          }|d S |j        | j        v rt          j        |j        |d           d S t          |          \  }}|r|st          j        |j        |           d S |                    ||          }|t          j        |j        |d           d S |j        |f}|| j        v rd S | j	        5  | j
                            |          }|/|j        r(t          j        |j        |           |cd d d            S | j                            |          }d d d            n# 1 swxY w Y   |	 | d {V S # t          $ r Y d S w xY wt!          j                    }	|	                                }
| j	        5  |
| j        |<   d d d            n# 1 swxY w Y   	 t'          || j        | j        | j        | j                  }|                    ||          }|t          j        |j        |j                   | j                            |           |
                    d            	 | j	        5  | j                            |d            d d d            d S # 1 swxY w Y   d S t;          |j        |j        |j        |j         |j!        |j"        |j#        p|j$                  }	 |%                                 d {V  n# t          $ r}t          j&        |j        ||           | j                            |           |
                    d            Y d }~| j	        5  | j                            |d            d d d            d S # 1 swxY w Y   d S d }~ww xY w| j	        5  || j
        |<   d d d            n# 1 swxY w Y   tO          j'                    | j(        |<   t          j        |j        |           |
                    |           || j	        5  | j                            |d            d d d            S # 1 swxY w Y   S # | j	        5  | j                            |d            d d d            w # 1 swxY w Y   w xY w)Nzdisabled in configz%exclude marker hit (server gated off))r   r^   rS   rT   rU   )r   r   r}   r~   cwdr   seed_diagnostics_on_first_push))r   r   rm   r   log_disabledr   log_no_project_rootr   rp   rt   ro   r   
is_running
log_activerq   r8   r2   get_running_loopcreate_futurer   ri   rj   rk   rl   build_spawnlog_server_unavailabler   
set_resultr   r   r   r}   r~   r   r   r   seed_first_pushr/   r   r   rr   )r#   r   r   r   r   r   r   r   spawningr:   spawn_futurectxspecr   s                 r$   r   zLSPService._get_or_spawn  s     "9--;4=D222!#-<PQQQ43I>> 	E 	(	BBB4**9g>>"!y*Q   4}o.$,4 	/ 	/]&&s++F!f&7!#CM?CCC		/ 	/ 	/ 	/ 	/ 	/ 	/ 	/
 ~))#..H	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ %~~~~~~%   tt '))'+'9'9';'; 	/ 	/".DN3	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/*	..!%!7!%!7"1#3  C ???C88D|
 /s}MMM  %%%''---0 ! . .""3---. . . . . . . . . . . . . . . . . ./ -#2HH'+'B/3/R/iVYVi  Fllnn$$$$$$$$   )#-!LLL  %%%''---ttt ! . .""3---. . . . . . . . . . . . . . . . . .
 ! , ,%+c", , , , , , , , , , , , , , ,#'9;;DOC ???##F+++! . .""3---. . . . . . . . . . . . . . . .! . .""3---. . . . . . . . . . . . . . . .s   ?D5D55D9<D9E 
EE
F!!F%(F%-BP! I,,I03I09A P! :K P! 
M/A
M*)P! 4MM!$M!*M//
P! 9NP! NP! NAP! -PP	P	!Q)QQQQQQc                l  K   | j         5  t          | j                                                  }| j                                         | j                                         | j                                         d d d            n# 1 swxY w Y   t          j        d |D             ddi d {V  d S )Nc              3  >   K   | ]}|                                 V  d S r   )r   )r   cs     r$   	<genexpr>z-LSPService._shutdown_async.<locals>.<genexpr>E  s*      ,,qajjll,,,,,,r&   return_exceptionsT)	rt   r   ro   valuesclearrp   rr   r2   gather)r#   clientss     r$   r   zLSPService._shutdown_async>  s      	$ 	$4=//1122GM!!!L   O!!###		$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$
 n,,G,,,
"
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
s   A2BBBDict[str, Any]c           	        | j         5  d | j                                        D             }t          | j                  }ddd           n# 1 swxY w Y   | j        | j        | j        | j        ||t          | j
                  dS )z<Return a snapshot of the service for the CLI status command.c                N    g | ]"\  }}|d          |d         |j         |j        d#S )r      )r   r   staterunning)r  r   )r   r   r   s      r$   r   z)LSPService.get_status.<locals>.<listcomp>P  sM        Aq "#1&'dW |	   r&   N)rX   rZ   r\   r^   r   brokenrV   )rt   ro   r   r   rp   rf   rg   rh   ri   sortedrm   )r#   r   r  s      r$   
get_statuszLSPService.get_statusM  s     
	( 
	(  !M//11  G $,''F
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( } . $ 6 &t'= > >
 
 	
s   8AAA)rX   rY   rZ   r[   r\   r]   r^   r[   rS   r_   rT   r`   rU   ra   rV   rb   rW   r]   r   r   )r   rv   )r   rY   )r   r[   r   rY   )r   r[   r   r   )
r   r[   r   rY   r,   r;   r   r   r   r   )r   r[   r   r   r   r   rK   )r   r[   r   r   )r   r[   r   r   )r   r   )rL   rM   rN   rO   DEFAULT_IDLE_TIMEOUTr%   classmethodr   r   r   r   r   r   r   r   r   r   r   r   r  rP   r&   r$   rR   rR      s        & <@=A>B042&C &C &C &C &C &CP 3
 3
 3
 [3
r      BB B B B2 #'?CR R R R R Rh.K .K .K .K`	 	 	 	7 7 7 77 7 7 7	7 	7 	7 	7P. P. P. P.d	
 	
 	
 	

 
 
 
 
 
r&   rR   r   r   r   r[   c                   |                      d          pi }|                     d          pi }|                     d          pi }|                      d          }|$t          |t                    st          |          }d                    t          |                      d          pd          t          |pd	          t          |                      d
          pd	          t          |                      d          pd	                                          |                     dd           d|                     dd           d|                     dd           d|                     dd           g          S )up  Content equality key used for cross-edit delta filtering.

    Includes the diagnostic's position range — when used together
    with :func:`agent.lsp.range_shift.shift_baseline`, the baseline
    is line-shifted into post-edit coordinates BEFORE this key is
    computed, so identical-but-shifted diagnostics hash equal.  Two
    genuinely distinct diagnostics at different lines (e.g. the same
    error class introduced at a second site) hash differently and
    are surfaced as new.

    Mirrors :func:`agent.lsp.client._diagnostic_key`; intentionally
    identical so the two layers agree on diagnostic identity.
    ranger/   endcodeN severityr   sourcemessageliner   :	character-)r   r   r[   rJ   strip)r   rngr/   r  r  s        r$   r   r   e  sV    %%..
BCGGG"E
''%..
BC55==D
4 5 54yy;;j!!&Q''
OOh%2&&i  &B''--//yy##ppeiiQ&?&?pp#''&RSBTBTppWZW^W^_jlmWnWnpp	
  r&   )r   r   r   r[   ))rO   
__future__r   r2   loggingr   r   r   concurrent.futuresr   ConcurrentFuturetypingr   r   r   r   r	   r
   	agent.lspr   agent.lsp.clientr   r   r   agent.lsp.serversr   r   r   r   r   agent.lsp.workspacer   r   r   	getLoggerr   r	  r   rR   r   __all__rP   r&   r$   <module>r%     s  ! !D # " " " " "   				      9 9 9 9 9 9 = = = = = = = = = = = = = = = =               
                       
	.	/	/ B B B B B B B BJX
 X
 X
 X
 X
 X
 X
 X
v   > .r&   