
    Je{^                        d Z ddlZddl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
mZmZmZmZm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 ddlmZ ddlmZmZmZm Z m!Z! ddl"m#Z#m$Z$m%Z%m&Z& dd	l'm(Z( dd
l)m*Z* ddl+m,Z,m-Z-  ej\                   ej^                   ej`                          ejb                  e2                  Z3dZ4dZ5dZ6dZ7erdZ7 ejp                  e9      Z:e% G d dee*e             Z;d Z<e9dk(  r e<        yy)z
Spyder Language Server Protocol Client implementation.

This client implements the calls and procedures required to
communicate with a v3.0 Language Server Protocol server.
    N)QObjectQProcessQSocketNotifierSignalSlot)SpyderConfigurationAccessor)DEVget_conf_pathget_debug_level
is_pynsistrunning_under_pytest)is_anaconda)CLIENT_CAPABILITESSERVER_CAPABILITESTEXT_DOCUMENT_SYNC_OPTIONSCompletionRequestTypesClientConstants)send_requestsend_notificationclass_registerhandles)MessageKind)LSPMethodProviderMixIn)getcwd_or_homeselect_portpendingserver_ready	127.0.0.1messagesverbosec                      e Zd ZdZ eee      Z ee      Z ee      Z	i  e
       dfdZd Zed        Zed        Zed        Zed        Zd	 Z eej*                        d
        Zd Zd Zd Zd Zd Zd Zd Zd Zd Z e       d        Z d Z! e"e#       e$e%jL                        d               Z' e$e%jP                        d        Z) e"e%jP                        d        Z* e+e%jX                        d        Z- e"e%jL                        d        Z. e+e%j^                        d        Z0ed        Z1ed        Z2y) 	LSPClientz4Language Server Protocol v3.0 client implementation.pythonc                 N   t        j                  |        || _        d | _        d | _        d | _        d | _        d | _        d | _        d | _	        d | _
        || _        d| _        d| _        d| _        i | _        i | _        i | _        i | _        d| _        d| _        |d   st+        |d         | _        n
|d   | _        |d   | _        |j1                  dd      | _        |j1                  dd      | _        | j4                  r.| j2                  r"d}t6        j9                  |       t;        |      || _        |j1                  d	i       | _        t@        | _!        tD        | _#        tI        jJ                         | _&        |j1                  d
d      | _'        |d   | _(        g | _)        y )NF   externalport)default_porthoststdiozQIf server is set to use stdio communication, then it cannot be an external serverconfigurationsargs cmd)*r   __init__managerzmq_in_socketzmq_out_socketzmq_in_portzmq_out_port	transportserver	stdio_pidnotifierlanguageinitializedready_to_closerequest_seq
req_statuswatched_fileswatched_folders	req_replyserver_unresponsivetransport_unresponsiver   server_portserver_hostgetexternal_serverr*   loggererrorAssertionErrorfolderr+   r   client_capabilitesr   server_capabiliteszmqContextcontext_server_args_server_cmd	_requests)selfparentserver_settingsrJ   r9   rH   s         [/usr/lib/python3/dist-packages/spyder/plugins/completion/providers/languageserver/client.pyr/   zLSPClient.__init__L   s    	!"   #!#( &+# z**,V4 6D  /v6D*62.22:uE$((%8
 ::$..<ELL ''-112BBG"4"4{{} ,//;*51     c                 ^   t               dk(  rydj                  || j                  t        j                               }t        t        j                  d|            }t        j                  t        j                  |            s(t        j                  t        j                  |             |S )z
        Get filename to redirect server or transport logs to in
        debugging mode.

        Parameters
        ----------
        kind: str
            It can be "server" or "transport".
        r   Nz{0}_{1}_{2}.loglsp_logs)r   formatr9   osgetpidr
   ospjoinexistsdirnamemakedirs)rS   kindfnamelocations       rV   _get_log_filenamezLSPClient._get_log_filename   sv     !!((t}}biikJ *e!<= zz#++h/0KKH-.rW   c                 $    | j                  d      S )zO
        Filename to redirect the server process stdout/stderr output.
        r6   re   rS   s    rV   server_log_filezLSPClient.server_log_file   s    
 %%h//rW   c                 $    | j                  d      S )zZ
        Filename to redirect the transport process stdout/stderr
        output.
        r5   rg   rh   s    rV   transport_log_filezLSPClient.transport_log_file   s     %%k22rW   c                    g }| j                   dk(  r|t        j                  dgz  }|| j                  gz  }| j                  j                  | j                  | j                        }t        |      dkD  r||j                  d      z  }| j                   dk(  r\t               dkD  rO|d| j                  gz  }t               dk(  r|j                  d       |S t               d	k(  r|j                  d
       |S )z!Arguments for the server process.r#   z-mr)   r'   r    z
--log-file   z-v   z-vv)r9   sys
executablerQ   rP   rZ   rD   rC   lensplitr   ri   appendrS   r,   host_and_ports      rV   server_argszLSPClient.server_args   s     ==H$S^^T**D!!"" ))00!!!! 1 # }!M'',,D==H$):Q)>\4#7#788D A%D!  !"a'E"rW   c           
         t         j                  dt        j                  t        dd      d| j
                  dt        t                     g}dj                  | j                  | j                        }||j                  d      z  }|d	t        | j                        d
t        | j                        gz  }| j                  r5|dgz  }t               dkD  r|d| j                  gz  }|| j                   z  }|S |dgz  }|S )z$Arguments for the transport process.z-ur5   zmain.pyz--folderz--transport-debugz*--server-host {host} --server-port {port} rm   rn   z--zmq-in-portz--zmq-out-portz--stdio-serverr   z--server-log-filez--external-server)rq   rr   r]   r^   LOCATIONrJ   strr   rZ   rD   rC   rt   r4   r3   r*   ri   rx   rv   s      rV   transport_argszLSPClient.transport_args   s    NNHHX{I6_%6!7
 EKK!!!! L # 	##C(( 	#d&7&7"8!3t'7'7#8: 	: ::%&&D 1$,d.B.BCCD$$$D  ())DrW   c                    | j                   j                  t        j                        | _        | j                  j                  dj                  t                    | _        | j                   j                  t        j                        | _	        | j                  j                  d       | j                  j                  dj                  t                    | _        y)z#Create PyZMQ sockets for transport.ztcp://{}r   N)rO   socketrM   PAIRr2   bind_to_random_portrZ   	LOCALHOSTr4   r1   set_hwmr3   rh   s    rV   create_transport_socketsz"LSPClient.create_transport_sockets   s    "ll11#((; //CCi(*!\\00:""1%--AAi(*rW   c                 N    | j                   j                  | j                         y)z;Handle errors with the transport layer or server processes.N)sig_went_downemitr9   )rS   rH   s     rV   handle_process_errorszLSPClient.handle_process_errors   s     	.rW   c                    | j                   s| j                  ryt        j                  dj	                  dj                  | j                                     t        |       | _        | j                  j                         }| j                  dk(  rt        j
                  t               dd      }t        j                  |      st        j                  |       t        j                   dk(  rdt        j"                  v r#|j%                  dt        j"                  d          t'               st)               sd	t        j"                  v r|j%                  d	t        j"                  d	          nld}t        j"                  D ]%  }|j%                  |t        j"                  |          ' t        j                  d
j	                  |j+                                      | j                  j-                  |       | j                  j.                  j1                  | j2                         | j                  j5                  |       | j                  j7                  t        j8                         | j:                  %| j                  j=                  | j:                         | j                  j?                  | j                  d   | j                  dd        y)zStart server.NzStarting server: {0}rn   r#   	lsp_pathscwdntUSERPROFILEAPPDATAz!Server process env variables: {0}r   r%   ) rF   r*   rG   inforZ   r^   rx   r   r6   processEnvironmentr9   r]   r
   r_   r[   ra   nameenvironinsertr   r   keyssetProcessEnvironmenterrorOccurredconnectr   setWorkingDirectorysetProcessChannelModeMergedChannelsri   setStandardOutputFilestart)rS   envr   vars       rV   start_serverzLSPClient.start_server   s    4::*11#((4;K;K2LMN tnkk,,. ==H$
 ((=?K?C::c?C ww$
 !BJJ.JJ}bjj.GH %*,!RZZ/JJy"**Y*?@ C zz 1

3

301KK;BB388:NO 	))#.!!))$*D*DE'',))(*A*AB+KK--d.B.BC 	$**1-t/?/?/CDrW   c                 t   t         j                  dj                  dj                  | j                        | j
                               t        |       | _        | j                  j                         }| j
                  dk7  rv| j                  rjt        j                  D ]%  }|j                  |t        j                  |          ' t         j                  dj                  |j                                      | j                  j                  |       | j                  j                  j!                  | j"                         | j                  r[| j                  j%                  t        j&                         | j(                  | j                  j+                  | j(                         nZ| j                  j%                  t        j,                         | j(                  %| j                  j/                  | j(                         | j                  j1                  | j                  d   | j                  dd        y)zStart transport layer.zStarting transport for {1}: {0}rn   r#   z$Transport process env variables: {0}Nr   r%   )rG   r   rZ   r^   r|   r9   r   r5   r   r*   r[   r   r   r   r   r   r   r   r   SeparateChannelsrk   setStandardErrorFiler   r   r   )rS   r   r   s      rV   start_transportzLSPClient.start_transport4  s   5VCHHT%8%894==I	K "$nn//1 ==H$zz 1

3

301KK>EE
  	,,S1 	$$,,T-G-GH::NN001J1JK&&233D4K4KLNN001H1HI&&244T5L5LM 	T003T5H5H5LMrW   c                    | j                          | j                          | j                          | j                  j	                  t
        j                        }t        |t        j                  |       | _	        | j                  j                  j                  | j                         t        j                  dj                  | j                                y)zStart client.zLSP {} client started!N)r   r   r   r1   
getsockoptrM   FDr   Readr8   	activatedr   on_msg_receivedrG   debugrZ   r9   )rS   fids     rV   r   zLSPClient.startU  s     	%%'   ++CFF3'_-A-A4H''(<(<= 	-44T]]CDrW   c                 T   t         j                  dj                  | j                               | j                  Q| j                  j
                  j                  | j                         | j                  j                  d       d| _        | j                  5| j                  j                          | j                  j                  d       | j                  j                          | j                  6| j                  j                          | j                  j                  d       yy)zStop transport and server.zStopping {} client...NFi  )rG   r   rZ   r9   r8   r   
disconnectr   
setEnabledr5   closewaitForFinishedrO   destroyr6   rh   s    rV   stopzLSPClient.stopd  s    +224==AB==$MM##..t/C/CDMM$$U+ DM >>%NN  "NN**40;;"KKKK''- #rW   c                 \    | j                   j                         }|t        j                  k7  S )z#Detect if transport layer is alive.)r5   stater   
NotRunningrS   r   s     rV   is_transport_alivezLSPClient.is_transport_alivex  s%    $$&++++rW   c                    d}t        j                  | j                        sd}|S 	 t        j                  | j                        j	                         }|t         j                  k(  rd}|S # t         j
                  $ r d}Y .w xY w)z"Check if an stdio server is alive.TFr-   )psutil
pid_existsr7   ProcessstatusNoSuchProcessSTATUS_ZOMBIE)rS   alive
pid_statuss      rV   is_stdio_alivezLSPClient.is_stdio_alive}  s{      0E  #^^DNN;BBD
 V111	 ''  
 s   -A+ +BBc                 \    | j                   j                         }|t        j                  k7  S )z Detect if a tcp server is alive.)r6   r   r   r   r   s     rV   is_server_alivezLSPClient.is_server_alive  s%    !!#++++rW   c                 "   d}| j                   rx| j                         sht        j                  dj	                  | j
                               | j                  s,d| _        | j                  j                  | j
                         d}| j                  rx| j                         sht        j                  dj	                  | j
                               | j                  s,d| _        | j                  j                  | j
                         d}| j                  rx| j                         sht        j                  dj	                  | j
                               | j                  s,d| _        | j                  j                  | j
                         d}|S )zh
        Detect if the transport layer or server are down to inform our
        users about it.
        Fz Transport layer for {} is down!!TzLSP server for {} is down!!)r5   r   rG   r   rZ   r9   rB   r   r   r6   r   rA   r7   r   )rS   is_downs     rV   r   zLSPClient.is_down  s%   
 >>$"9"9";LL299$--HJ...2+""''6G;;t335LL6==dmmLM+++/(""''6G>>$"5"5"7LL6==dmmLM+++/(""''6GrW   c                    | j                         ry| j                  s|dk7  ryt        j                  |v ry| j                  }|t
        j                  k(  r*| j                  ||d}|| j                  | j                  <   n;|t
        j                  k(  r| j                  |d}n|t
        j                  k(  r||d}t        j                  dj                  ||             t               r| j                  j                  ||f       d}t!        j                          }||z   }	 	 | j"                  j%                  t&        j(                         | xj                  dz  c_        t+        |      S # t&        j,                  j.                  $ rw t!        j                          |kD  r'| j0                  j3                  | j4                         Y y| j                  rt        j7                  d	       t!        j8                  d
       Y nw xY w)zSend message to transport.N
initialize)idmethodparams)r   result)r   r   zPerform request {0} with id {1}r%   flagsz#The send queue is full! Retrying...g?)r   r:   r   CANCELr<   r   REQUESTr=   RESPONSENOTIFICATIONrG   r   rZ   r   rR   ru   timer2   
send_pyobjrM   NOBLOCKintrH   Againr   r   r9   warningsleep)	rS   r   r   rb   _idmsgtimeout
start_timetimeout_times	            rV   sendzLSPClient.send  s   <<> Fl$:!!V+;&&&&&  C
 17DOOD,,-[)))&& C [---  C
 	6==fcJK  !NN!!3-0 YY[
!G+##..s#++.F  A% 3x99?? 99;-&&++DMM:##NN#HI

2 s   $A
E/ /AH
6HHc           	         | j                   j                  d       	 	 | j                  j                  t        j
                        }	 |d   }t        j                  dj                  | j                  |             d|v rt        j                  dj                  | j                  t        |d                      | j                  dk(  rt               d	kD  st        ro|d   j                  d
d      }|d   j                  di       j                  d      }|4dj                  |      }|dz   |z   }| j                   j#                  |       |d   }|| j$                  v r | j$                  |   ddg i       nd|v r]|d   d	   dk7  rd|v rt'        |d         | _        |d   | j*                  v r| j*                  |d      }t-        | |      } ||d          nd|v r|d   |d   }|| j.                  v r| j.                  |   }|| j*                  v rk| j*                  |   }t-        | |      } ||d   |       | j.                  j1                  |       || j$                  v r| j$                  j1                  |       f# t        $ r Y w xY w# t2        $ r Y t        j4                  $ r | j                   j                  d       Y yw xY w)zProcess received messages.FTr   r   z{} response: {}rH   z{} Response error: {}r#   r   messager-   data	tracebackN
r   r   $r   )r8   r   r1   
recv_pyobjrM   r   rG   r   rZ   r9   KeyErrorreprr   r	   rE   r^   sig_server_errorr   r@   r   r<   handler_registrygetattrr=   popRuntimeErrorZMQError)	rS   respr   r   r   req_idhandler_namehandlerreq_types	            rV   r   zLSPClient.on_msg_received  s    	  '7))443;;4G!(^FLL)00GI
 d?LL!8"(&T']8K"LN}}0 +,q0C&*7m&7&7	2&FG)-g):):62)F),[)9 &(4,.GGI,>	,5,<w,F	 $ 5 5 : :9 E!%d!T^^32DNN624(BH%H~a(C/4</24:D,>T-B-BB $ 5 5d8n E )&-dL&AG#DN3%H~1!%d!T__4'+v'>H'4+@+@@/3/D/DX/N*1$*E 'X ? $ 3 3F ;#)T^^#;$(NN$6$6v$>c    R    << ((.s<   *J 	4J =HJ 	JJ JJ 	K-KKc                     || j                   v r@| j                   |   }t        | |      } ||      }d|v r|d   r|d   | j                  |<   |S y )Nresponse_callbackrequires_response)sender_registryr   r@   )rS   r   r   r   r   r   s         rV   perform_requestzLSPClient.perform_request#  sd    T)))//7LdL1G&/C"f,-.*01D*EDNN3'J *rW   )r   c                    |d   | _         | j                  s| j                  j                         nd }|t	        j
                  t        j                  | j                              j                         | j                  t        d}|S )Npid)	processIdrootUricapabilitiestrace)r7   rF   r5   r   pathlibPathr]   abspathrJ   as_urirK   TRACE)rS   r   r,   kwargsr   s        rV   r   zLSPClient.initialize.  sj      040D0Ddnn&&($||CKK$<=DDF 33	
 rW   c                 
    i }|S N rS   r   s     rV   shutdownzLSPClient.shutdown;      rW   c                     d| _         y )NT)r;   )rS   responser,   s      rV   handle_shutdownzLSPClient.handle_shutdown@  s
    "rW   c                 
    i }|S r  r  r  s     rV   exitzLSPClient.exitD  r  rW   c                    |d   }t        |d   t              r|d   }t        |d<   ||d   d<   |d   |j                  d       | j                  j                  |       d| _        | j                          | j                  | j                         | j                  j                  | j                  | j                         y)zd
        Register server capabilities and inform other plugins that it's
        available.
        r   textDocumentSyncchangeNT)
isinstancer   r   r   rL   updater:   initialized_callsend_configurationsr+   sig_initializer   r9   )rS   rL   r,   rb   s       rV   process_server_capabilitiesz%LSPClient.process_server_capabilitiesI  s     0?();<cB%&89D5O12?C128<019""#56&&'9:   	  !4!45 	  !8!8$--HrW   c                 
    i }|S r  r  r  s     rV   r  zLSPClient.initialized_callg  r  rW   c                 0    | j                   d   }|d   d   S )N	workspaceworkspaceFolders	supportedrL   rS   workspace_settingss     rV   support_multiple_workspacesz%LSPClient.support_multiple_workspacesm  s$    !44[A!"45kBBrW   c                 0    | j                   d   }|d   d   S )Nr  r  changeNotificationsr  r  s     rV   support_workspace_updatez"LSPClient.support_workspace_updater  s%    !44[A!"456KLLrW   N)3__name__
__module____qualname____doc__r   dictr{   r  r   r   r   r/   re   propertyri   rk   rx   r|   r   r   r   ProcessErrorr   r   r   r   r   r   r   r   r   r   r   r   r   SERVER_READYr   r   
INITIALIZEr   SHUTDOWNr  r  r   EXITr  r  INITIALIZEDr  r  r"  r  rW   rV   r"   r"   =   s   > D#&N c{ 3KM "$&("<|. 0 0 3 3  .  >* 
(

 / !/;EzNBE.(,
,
<5n 
V; ;z \/::;	 < 	 /889 : #,,-# .# 499: ; #../I 0I: 4@@A B
 C C M MrW   r"   c                  `   ddl m}   | d      }d}dddd	}t        |||      }|j                          |j                  j                  |j                         t        j                  t        j                  t        j                         t        j                  |j                                y
)zTest LSP client.r   )qapplication   )	test_timez%--host %(host)s --port %(port)s --tcpr   i'  pyls)r)   r'   r.   N)spyder.utils.qthelpersr0  r"   r   aboutToQuitr   r   signalSIGINTSIG_DFLrq   r  exec_)r0  appserver_args_fmtrU   lsps        rV   testr=  x  su    3

#C=O*DHO
C/
:CIIKOOCHH%
MM&--0HHSYY[rW   __main__)=r&  loggingr[   os.pathpathr]   r   r6  rq   r   qtpy.QtCorer   r   r   r   r   rM   r   spyder.api.config.mixinsr   spyder.config.baser	   r
   r   r   r   spyder.config.utilsr   spyder.plugins.completion.apir   r   r   r   r   =spyder.plugins.completion.providers.languageserver.decoratorsr   r   r   r   <spyder.plugins.completion.providers.languageserver.transportr   <spyder.plugins.completion.providers.languageserver.providersr   spyder.utils.miscr   r   realpathr^   getcwdr`   __file__rz   PENDINGr*  r   r  	getLoggerr#  rG   r"   r=  r  rW   rV   <module>rP     s    	    
  I H 
  AK K + > > 9 3<<!,X!68 9
	 	E			8	$ wM/1L wM wMt zF rW   