77# Then Vim can send requests to the server:
88# :let response = ch_sendexpr(handle, 'hello!')
99#
10- # And you can control Vim by typing a JSON message here, e.g.:
11- # ["ex","echo 'hi there'"]
12- #
13- # There is no prompt, just type a line and press Enter.
14- # To exit cleanly type "quit<Enter>".
15- #
1610# See ":help channel-demo" in Vim.
1711#
1812# This requires Python 2.6 or later.
3024 # Python 2
3125 import SocketServer as socketserver
3226
33- thesocket = None
34-
3527class ThreadedTCPRequestHandler (socketserver .BaseRequestHandler ):
3628
3729 def handle (self ):
3830 print ("=== socket opened ===" )
39- global thesocket
40- thesocket = self .request
4131 while True :
4232 try :
43- data = self .request .recv (4096 ).decode ('utf-8' )
33+ received = self .request .recv (4096 ).decode ('utf-8' )
4434 except socket .error :
4535 print ("=== socket error ===" )
4636 break
4737 except IOError :
4838 print ("=== socket closed ===" )
4939 break
50- if data == '' :
40+ if received == '' :
5141 print ("=== socket closed ===" )
5242 break
53- print ("received: {}" .format (data ))
54- try :
55- decoded = json .loads (data )
56- except ValueError :
57- print ("json decoding failed" )
58- decoded = [- 1 , '' ]
59-
60- # Send a response if the sequence number is positive.
61- # Negative numbers are used for "eval" responses.
62- if decoded [0 ] >= 0 :
63- if decoded [1 ] == 'hello!' :
64- # simply send back a string
65- response = "got it"
66- elif decoded [1 ] == 'make change' :
67- # Send two ex commands at the same time, before replying to
68- # the request.
69- cmd = '["ex","call append(\\ "$\\ ",\\ "added1\\ ")"]'
70- cmd += '["ex","call append(\\ "$\\ ",\\ "added2\\ ")"]'
71- print ("sending: {}" .format (cmd ))
72- thesocket .sendall (cmd .encode ('utf-8' ))
73- response = "ok"
74- elif decoded [1 ] == '!quit!' :
75- # we're done
76- sys .exit (0 )
43+ print ("received: {}" .format (received ))
44+
45+ # We may receive two messages at once. Take the part up to the
46+ # matching "]" (recognized by finding "][").
47+ todo = received
48+ while todo != '' :
49+ splitidx = todo .find ('][' )
50+ if splitidx < 0 :
51+ used = todo
52+ todo = ''
7753 else :
78- response = "what?"
54+ used = todo [:splitidx + 1 ]
55+ todo = todo [splitidx + 1 :]
56+ if used != received :
57+ print ("using: {}" .format (used ))
58+
59+ try :
60+ decoded = json .loads (used )
61+ except ValueError :
62+ print ("json decoding failed" )
63+ decoded = [- 1 , '' ]
7964
80- encoded = json .dumps ([decoded [0 ], response ])
81- print ("sending: {}" .format (encoded ))
82- thesocket .sendall (encoded .encode ('utf-8' ))
65+ # Send a response if the sequence number is positive.
66+ if decoded [0 ] >= 0 :
67+ if decoded [1 ] == 'hello!' :
68+ # simply send back a string
69+ response = "got it"
70+ elif decoded [1 ] == 'make change' :
71+ # Send two ex commands at the same time, before
72+ # replying to the request.
73+ cmd = '["ex","call append(\\ "$\\ ",\\ "added1\\ ")"]'
74+ cmd += '["ex","call append(\\ "$\\ ",\\ "added2\\ ")"]'
75+ print ("sending: {}" .format (cmd ))
76+ self .request .sendall (cmd .encode ('utf-8' ))
77+ response = "ok"
78+ elif decoded [1 ] == 'eval-works' :
79+ # Send an eval request. We ignore the response.
80+ cmd = '["eval","\\ "foo\\ " . 123", -1]'
81+ print ("sending: {}" .format (cmd ))
82+ self .request .sendall (cmd .encode ('utf-8' ))
83+ response = "ok"
84+ elif decoded [1 ] == 'eval-fails' :
85+ # Send an eval request that will fail.
86+ cmd = '["eval","xxx", -2]'
87+ print ("sending: {}" .format (cmd ))
88+ self .request .sendall (cmd .encode ('utf-8' ))
89+ response = "ok"
90+ elif decoded [1 ] == 'eval-bad' :
91+ # Send an eval request missing the third argument.
92+ cmd = '["eval","xxx"]'
93+ print ("sending: {}" .format (cmd ))
94+ self .request .sendall (cmd .encode ('utf-8' ))
95+ response = "ok"
96+ elif decoded [1 ] == 'eval-result' :
97+ # Send back the last received eval result.
98+ response = last_eval
99+ elif decoded [1 ] == '!quit!' :
100+ # we're done
101+ self .server .shutdown ()
102+ break
103+ elif decoded [1 ] == '!crash!' :
104+ # Crash!
105+ 42 / 0
106+ else :
107+ response = "what?"
83108
84- thesocket = None
109+ encoded = json .dumps ([decoded [0 ], response ])
110+ print ("sending: {}" .format (encoded ))
111+ self .request .sendall (encoded .encode ('utf-8' ))
112+
113+ # Negative numbers are used for "eval" responses.
114+ elif decoded [0 ] < 0 :
115+ last_eval = decoded
85116
86117class ThreadedTCPServer (socketserver .ThreadingMixIn , socketserver .TCPServer ):
87118 pass
@@ -97,14 +128,14 @@ class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
97128 server_thread = threading .Thread (target = server .serve_forever )
98129
99130 # Exit the server thread when the main thread terminates
100- server_thread .daemon = True
101131 server_thread .start ()
102132
103133 # Write the port number in Xportnr, so that the test knows it.
104134 f = open ("Xportnr" , "w" )
105135 f .write ("{}" .format (port ))
106136 f .close ()
107137
108- # Block here
109138 print ("Listening on port {}" .format (port ))
110- server .serve_forever ()
139+
140+ # Main thread terminates, but the server continues running
141+ # until server.shutdown() is called.
0 commit comments