src/Palete/LanguageClientVala.vala
[roobuilder] / src / Palete / LanguageClientVala.vala
1
2 namespace Palete {
3         public class LanguageClientVala : LanguageClient {
4                 protected bool initialized = false;
5                 bool sent_shutdown = false;
6                 uint change_queue_id = 0;
7                 
8                         
9                 private bool _closed = false;
10                 private bool closed {
11                         get { return this._closed ; } 
12                         set {
13                                 GLib.debug("closed has been set? to %s" , value ? "TRUE" : "FALSE" );
14                                 this._closed = value;
15                         }
16                 }
17                 private GLib.SubprocessLauncher launcher = null;
18                 private GLib.Subprocess? subprocess = null;
19                 private IOStream? subprocess_stream = null;
20             public Jsonrpc.Client? jsonrpc_client = null;
21                 
22                 int countdown = 0;
23                 Gee.ArrayList<JsRender.JsRender> open_files;
24                 private JsRender.JsRender? _change_queue_file = null;
25                 int doc_countdown = 0;
26                 private string change_queue_file_source = "";
27                 private JsRender.JsRender? doc_queue_file = null;
28
29                 
30                 JsRender.JsRender? change_queue_file {
31                         set {
32                                 this.change_queue_file_source = value == null ? "" : value.toSource();
33                                 this._change_queue_file = value;
34                         } 
35                         get {
36                                 return this._change_queue_file;
37                         } 
38                 }
39                 
40
41                 
42                 void startServer()
43                 {
44                         var exe = GLib.Environment.find_program_in_path( "vala-language-server");
45                         if (exe == null) {
46                                 GLib.warning("could not find vala-language-server");
47                                  
48                                 return;
49                         }
50                         this.initProcess(exe);
51                 }
52                 
53                 
54                 public LanguageClientVala(Project.Project project)
55                 {
56                         // extend versions will proably call initialize to start and connect to server.
57                         base(project);
58
59                         if (this.change_queue_id == 0 ) {
60                                 this.change_queue_id = GLib.Timeout.add(500, () => {
61                                         this.run_change_queue();
62                                         this.run_doc_queue();
63                                         return true;
64                                 });
65                         }
66                         
67                         this.startServer();
68
69                 }
70                 
71                 void run_change_queue()
72                 {
73                 
74                         if (this.change_queue_file == null) {
75                                 return ;
76                         }
77                         if (this.countdown < -1) {
78                                 return;
79                         }
80                         if (this.getting_diagnostics) {
81                                 return;
82                         }
83                         this.countdown--;
84
85                 
86                         if (this.countdown < 0){
87                                 this.document_change_force.begin(this.change_queue_file,  this.change_queue_file_source, (o, res) => {
88                                         this.document_change_force.end(res);
89                                 });
90                                 this.change_queue_file = null;
91                                    
92                         }
93                         return ;
94                 }
95                  
96                  
97                 void run_doc_queue()
98                 {
99                 
100                         if (this.doc_queue_file == null) {
101                                 return ;
102                         }
103                         if (this.doc_countdown < -1) {
104                                 return;
105                         }
106                         this.doc_countdown--;
107
108                         if (this.doc_countdown < 0){
109                                 var sendfile = this.doc_queue_file;
110                                 this.documentSymbols.begin(this.doc_queue_file, (o, res) => {
111                                         var ret = this.documentSymbols.end(res);
112                                         sendfile.navigation_tree_updated(ret);
113                                 });
114                                 this.doc_queue_file = null;
115                                    
116                         }
117                         return ;
118                 }
119                 
120                 
121                 
122                 public bool initProcess(string process_path)
123                 {
124                         this.onClose();
125                         this.log(LanguageClientAction.LAUNCH, process_path);
126                         GLib.debug("Launching %s", process_path);
127                         this.launcher = new GLib.SubprocessLauncher (SubprocessFlags.STDIN_PIPE | SubprocessFlags.STDOUT_PIPE);
128                         var env = GLib.Environ.get();
129                         env += "G_MESSAGES_DEBUG=all";
130
131                         this.launcher.set_environ(env);
132                         var logpath = GLib.Environment.get_home_dir() + "/.cache/vala-language-server";
133                         
134                         if (!GLib.FileUtils.test(logpath, GLib.FileTest.IS_DIR)) {
135                                 Posix.mkdir(logpath, 0700);
136                         }
137                         // not very reliable..
138                         //this.launcher.set_stderr_file_path( 
139                         //      logpath + "/" + 
140                         //      (new GLib.DateTime.now_local()).format("%Y-%m-%d") + ".log"
141                         //);
142                         //GLib.debug("log lang server to %s", logpath + "/" + 
143                         //      (new GLib.DateTime.now_local()).format("%Y-%m-%d") + ".log");
144
145                         try {
146
147                                 
148                                 this.subprocess = launcher.spawnv ({ process_path , "2>" , "/tmp/vala-language-server.log" });
149                                 
150                                 this.subprocess.wait_async.begin( null, ( obj,res ) => {
151                                         try {
152                                                 this.subprocess.wait_async.end(res);
153                                         } catch (GLib.Error e) {
154                                                 this.log(LanguageClientAction.ERROR_START, e.message);
155                                                 GLib.debug("subprocess startup error %s", e.message);           
156                                         }
157                                         this.log(LanguageClientAction.EXIT, "process ended");
158                                         GLib.debug("Subprocess ended %s", process_path);
159                                         this.onClose();
160
161                                 });
162                                 var input_stream = this.subprocess.get_stdout_pipe ();
163                                 var output_stream = this.subprocess.get_stdin_pipe ();
164  
165                                 if (input_stream is GLib.UnixInputStream && output_stream is GLib.UnixOutputStream) {
166                                         // set nonblocking
167                                         if (!GLib.Unix.set_fd_nonblocking(((GLib.UnixInputStream)input_stream).fd, true)
168                                          || !GLib.Unix.set_fd_nonblocking (((GLib.UnixOutputStream)output_stream).fd, true)) 
169                                          {
170                                                 GLib.debug("could not set pipes to nonblocking");
171                                                 this.onClose();
172                                             return false;
173                                     }
174                             }
175                             this.subprocess_stream = new GLib.SimpleIOStream (input_stream, output_stream);
176                         this.accept_io_stream ( this.subprocess_stream);
177                         } catch (GLib.Error e) {
178                                 this.log(LanguageClientAction.ERROR_START, e.message);
179                                 GLib.debug("subprocess startup error %s", e.message);   
180                                 this.onClose();
181                                 return false;
182                 }
183             return true;
184         }
185         bool in_close = false;
186                 public override void client_accepted (Jsonrpc.Client client) 
187                 {
188                         if (this.jsonrpc_client == null) {
189                                 this.jsonrpc_client = client;
190                                 
191                                 GLib.debug("client accepted connection - calling init server");
192                                 this.log(LanguageClientAction.ACCEPT, "client accepted");
193
194                                 this.jsonrpc_client.notification.connect((method, paramz) => {
195                                         this.onNotification(method, paramz);
196                                 });
197                                  
198                                 this.jsonrpc_client.failed.connect(() => {
199                                         this.log(LanguageClientAction.ERROR_RPC, "client failed");
200                                         GLib.debug("language server server has failed");                                        
201                                         this.onClose();
202                                         
203
204                                 });
205
206                                 this.initialize_server ();
207                         } 
208                                          
209                          
210                 }
211                 
212                 
213                 public override   void  initialize_server()   {
214                         try {
215                                 Variant? return_value;
216                                     this.jsonrpc_client.call (
217                                     "initialize",
218                                     this.buildDict (
219                                         processId: new Variant.int32 ((int32) Posix.getpid ()),
220                                         rootPath: new Variant.string (this.project.path),
221                                         rootUri: new Variant.string (File.new_for_path (this.project.path).get_uri ()),
222                                         capabilities : this.buildDict (
223                                                 textDocument: this.buildDict (
224                                                         documentSymbol : this.buildDict (
225                                                                 hierarchicalDocumentSymbolSupport : new Variant.boolean (true)
226                                                         )
227                                                 )
228                                         )
229                                     ),
230                                     null,
231                                     out return_value
232                                 );
233                                 GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));
234                                 this.open_files = new Gee.ArrayList<JsRender.JsRender>((a,b) => {
235                                         return a.path == b.path;
236                                 });
237                                 this.initialized = true;
238                                 this.getting_diagnostics = false;
239                                 return;
240                         } catch (GLib.Error e) {
241                                 GLib.debug ("LS replied with error %s", e.message);
242                                 this.onClose();
243                         }
244                         
245                 }
246                 void onClose()
247                 {
248                         if (this.in_close) {
249                                 return;
250                         }
251                         if (this.launcher == null) {
252                                 return;
253                         }
254                         this.getting_diagnostics = false;
255                         this.in_close = true;
256                         GLib.debug("onClose called");
257                         
258                         if (this.jsonrpc_client != null) {
259                                 try {
260                                         this.jsonrpc_client.close();
261                                 } catch (GLib.Error e) {
262                                         GLib.debug("rpc Error close error %s", e.message);      
263                                 }               
264                         }
265                         if (this.subprocess_stream != null) {
266                                 try {
267                                         this.subprocess_stream.close();
268                                 } catch (GLib.Error e) {
269                                         GLib.debug("stream Error close  %s", e.message);        
270                                 }               
271                         }
272                         if (this.subprocess != null) {
273                                 this.subprocess.force_exit();
274                         }
275                         if (this.launcher != null) {
276                                 this.launcher.close();
277                         }
278                         
279                         this.launcher = null;
280                         this.subprocess = null;
281                         this.jsonrpc_client = null;
282                         this.closed = true;             
283                         this.in_close = false;
284                 }
285         
286                 public async void restartServer()
287                 {
288                         this.startServer();
289                          
290                 }
291         
292                 public bool isReady()
293                 {
294                         if (this.closed) {
295                                 this.log(LanguageClientAction.RESTART,"closed is set - restarting");
296                                 GLib.debug("server stopped = restarting");
297                                 this.initialized = false;
298                                 this.closed = false;
299                                 GLib.MainLoop loop = new GLib.MainLoop ();
300                                 this.restartServer.begin ((obj, async_res) => {
301                                         this.restartServer.end(async_res);
302                                         loop.quit ();
303                                 });
304                                 return false; // can't do an operation yet?
305                                  
306                         }
307                         
308                         if (!this.initialized) {
309                                 GLib.debug("Server has not been initialized");
310                                 return false;
311                         }
312                         if (this.sent_shutdown) {
313                                 GLib.debug("Server has been started its shutting down process");
314                                 return false;
315                         }
316                         // restart server..
317                 
318                         
319                         
320                         return true;
321                 }
322         
323                 public void onNotification(string method, Variant? return_value)
324                 {
325                         switch (method) {
326                                 case "textDocument/publishDiagnostics":
327                                         //GLib.debug("got notification %s : %s",  method , Json.to_string (Json.gvariant_serialize (return_value), true));
328                                          
329                                         GLib.Idle.add(() => {
330                                                 this.onDiagnostic(return_value);
331                                                 return false;
332                                         });
333                                         return;
334                                 default: 
335                                         break;
336                                  
337                         }
338                         GLib.debug("got notification %s : %s",  method , Json.to_string (Json.gvariant_serialize (return_value), true));
339                         
340                 }
341                 
342                 bool getting_diagnostics = false;
343                 /***
344                 
345                 */
346                 public void onDiagnostic(Variant? return_value) 
347                 {
348                         //GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                     
349                         var dg = Json.gobject_deserialize (typeof (Lsp.Diagnostics), Json.gvariant_serialize (return_value)) as Lsp.Diagnostics; 
350                         GLib.debug("got diag for %s", dg.filename);
351                         this.log(LanguageClientAction.DIAG, dg.filename);
352                         if (this.project.path == dg.filename) {
353                                 this.getting_diagnostics = false;
354                                 this.log(LanguageClientAction.DIAG_END, "diagnostics done");
355                                 return;
356                         
357                         }
358                         this.getting_diagnostics =true;
359                         var f = this.project.getByPath(dg.filename);
360                         if (f == null) {
361                                 //GLib.debug("no file %s", dg.uri);
362                                 //this.project.updateErrorsforFile(null);
363                                 return;
364                         }
365                         //GLib.debug("got Diagnostics for %s", f.path);
366                         f.updateErrors( dg.diagnostics );
367                          
368                         
369                 }
370                 
371                 public override void document_open (JsRender.JsRender file)  
372                 {
373                         if (!this.isReady()) {
374                                 return;
375                         }
376                         if (this.open_files.contains(file)) {
377                                 return;
378                         }
379                         this.open_files.add(file);
380                         
381                         
382                         GLib.debug ("LS sent open");                     
383                         try {
384                                 this.jsonrpc_client.send_notification (
385                                         "textDocument/didOpen",
386                                         this.buildDict (
387                                                 textDocument : this.buildDict (
388                                                         uri: new Variant.string (file.to_url()),
389                                                         languageId :  new Variant.string (file.language_id()),
390                                                         version :  new GLib.Variant.uint64 ( (uint64) file.version),
391                                                         text : new Variant.string (file.toSource())
392                                                 )
393                                         ),
394                                         null
395                                 );
396                                 this.log(LanguageClientAction.OPEN, file.path);
397                         } catch( GLib.Error  e) {
398                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
399                                 this.onClose();
400                                 GLib.debug ("LS sent open err %s", e.message);
401                         }
402
403                 }
404                 
405                 public override  async void document_save (JsRender.JsRender file)  
406         {
407                         if (!this.isReady()) {
408                                 return;
409                         }
410                         // save only really flags the file on the server - to actually force a change update - we need to 
411                         // flag it as changed.
412                         yield this.document_change_force(file, file.toSource());
413                         
414                         this.change_queue_file = null;
415                         GLib.debug ("LS send save");
416                          try {
417                          
418                                 var args = this.buildDict (  
419                                         textDocument : this.buildDict (    ///TextDocumentItem;
420                                                 uri: new GLib.Variant.string (file.to_url()),
421                                                 version :  new GLib.Variant.uint64 ( (uint64) file.version)
422                                         )
423                                 );
424                          
425                                 //GLib.debug ("textDocument/save send with %s", Json.to_string (Json.gvariant_serialize (args), true));                                 
426                         
427                          
428                          
429                                   yield this.jsonrpc_client.send_notification_async  (
430                                         "textDocument/didSave",
431                                         args,
432                                         null 
433                                 );
434                                 this.log(LanguageClientAction.SAVE, file.path);
435                         } catch( GLib.Error  e) {
436                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
437                                 GLib.debug ("LS   save err %s", e.message);
438                                 this.onClose();
439                         }
440
441          
442         }
443                 public override  void document_close (JsRender.JsRender file) 
444         {
445                         if (!this.isReady()) {
446                                 return;
447                         }
448                         this.change_queue_file = null;
449                         
450                         if (this.open_files.contains(file)) {
451                                 this.open_files.remove(file);
452                         }
453                         this.log(LanguageClientAction.CLOSE, file.path);
454                         GLib.debug ("LS send close");
455                         try {
456                                   this.jsonrpc_client.send_notification  (
457                                         "textDocument/didChange",
458                                         this.buildDict (  
459                                                 textDocument : this.buildDict (    ///TextDocumentItem;
460                                                         uri: new GLib.Variant.string (file.to_url())
461                                                         
462                                                 )
463                                         ),
464                                         null  
465                                 );
466                         } catch( GLib.Error  e) {
467                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
468                                 GLib.debug ("LS close err %s", e.message);
469                                 this.onClose();
470                         }
471
472          
473         }
474         
475          
476                 public override void document_change (JsRender.JsRender file )    
477                 {
478                         if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
479                                 this.document_change_force.begin(this.change_queue_file, this.change_queue_file_source, (o, res) => {
480                                         this.document_change_force.end(res);
481                                 });
482                         }
483                         
484                         this.countdown = 2;
485                         this.change_queue_file = file;
486                          
487                         
488
489                 }
490         
491
492                 public override async void document_change_force (JsRender.JsRender file, string contents)  
493         {
494                         
495                         
496                         if (!this.isReady()) {
497                                 return;
498                         }
499                         this.countdown = -2; // not really relivant..
500                         this.change_queue_file = null; // this is more important..
501                         
502                     if (!this.open_files.contains(file)) {
503                                  this.document_open(file);
504                         }  
505                         
506                         GLib.debug ("LS send change %s rev %d", file.path, file.version);
507                         var ar = new Json.Array();
508                         var obj = new Json.Object();
509                         obj.set_string_member("text", contents);
510                         ar.add_object_element(obj);
511                         var node = new Json.Node(Json.NodeType.ARRAY);
512                         node.set_array(ar);
513                         this.log(LanguageClientAction.CHANGE, file.path);
514                          try {
515                                 yield this.jsonrpc_client.send_notification_async (
516                                         "textDocument/didChange",
517                                         this.buildDict (  
518                                                 textDocument : this.buildDict (    ///TextDocumentItem;
519                                                         uri: new GLib.Variant.string (file.to_url()),
520                                                         version :  new GLib.Variant.uint64 ( (uint64) file.version) 
521                                                 ),
522                                                 contentChanges : Json.gvariant_deserialize (node, null)
523                                                 
524                                         ),
525                                         null 
526                                 );
527                         } catch( GLib.Error  e) {
528                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
529                                 GLib.debug ("LS change err %s", e.message);
530                                 this.onClose();
531                         }
532
533          
534         }
535         // called by close window (on last window)...
536                 public override  void exit () throws GLib.Error 
537                 {
538                         if (!this.isReady()) {
539                         
540                                 return;
541                         }
542                         this.log(LanguageClientAction.TERM, "SEND exit");
543                  
544                           this.jsonrpc_client.send_notification (
545                                 "exit",
546                                 null,
547                                 null 
548                         );
549                         this.onClose();
550
551                 }
552                 // not used currently..
553                 public override async void shutdown () throws GLib.Error 
554                 {
555                         if (!this.isReady()) {
556                                 return;
557                         }
558                         this.log(LanguageClientAction.TERM, "SEND shutodwn");
559                         this.sent_shutdown  = true;
560                         Variant? return_value;
561                         yield this.jsonrpc_client.call_async (
562                                 "shutdown",
563                                 null,
564                                 null,
565                                 out return_value
566                         );
567                         GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));               
568                 }
569                 //public async  ??/symbol (string symbol) throws GLib.Error {
570                 
571                 // and now for the important styff..
572                 
573                 /*
574                 
575                 @triggerType 1 = typing or ctl-spac, 2 = tiggercharactres?  3= inside completion?
576                 */
577                  public override async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
578                  {
579                         /* partial_result_token ,  work_done_token   context = null) */
580                         GLib.debug("%s get completion %s @ %d:%d", this.get_type().name(),  file.relpath, line, offset);
581                         
582                         var ret = new Lsp.CompletionList();     
583                         
584                     if (!this.isReady()) {
585                         GLib.debug("completion - language server not ready");
586                                 return ret;
587                         }
588                         // make sure completion has the latest info..
589                         //if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
590                         //      this.document_change_real(this.change_queue_file, this.change_queue_file_source);
591                         //      this.change_queue_file != null;
592                         //}
593                         this.log(LanguageClientAction.COMPLETE, "SEND complete  %s @ %d:%d".printf(file.relpath, line, offset) );
594                         
595                         Variant? return_value;
596                         
597                         var args = this.buildDict (  
598                                         context : this.buildDict (    ///CompletionContext;
599                                                 triggerKind: new GLib.Variant.int32 (triggerType) 
600                                         //      triggerCharacter :  new GLib.Variant.string ("")
601                                         ),
602                                         textDocument : this.buildDict (    ///TextDocumentItem;
603                                                 uri: new GLib.Variant.string (file.to_url()),
604                                                 version :  new GLib.Variant.uint64 ( (uint64) file.version) 
605                                         ), 
606                                         position :  this.buildDict ( 
607                                                 line :  new GLib.Variant.uint64 ( (uint) line) ,
608                                                 character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
609                                         )
610                                 );
611                          
612                         GLib.debug ("textDocument/completion send with %s", Json.to_string (Json.gvariant_serialize (args), true));                                     
613                         
614                         yield this.jsonrpc_client.call_async (
615                                 "textDocument/completion",
616                                 args,
617                                 null,
618                                 out return_value
619                         );
620                         
621                         
622                         //GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                     
623                         var json = Json.gvariant_serialize (return_value);
624
625
626                         if (json.get_node_type() == Json.NodeType.OBJECT) {
627                                 ret = Json.gobject_deserialize (typeof (Lsp.CompletionList), json) as Lsp.CompletionList; 
628                                 this.log(LanguageClientAction.COMPLETE_REPLY, "GOT complete  %d items".printf(ret.items.size) );
629                                 GLib.debug ("LS replied with Object");
630                                 return ret;
631                         }  
632
633                         if (json.get_node_type() != Json.NodeType.ARRAY) {
634                                 GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
635                                 this.log(LanguageClientAction.ERROR_REPLY, "GOT something else??");
636                                 return ret;
637                         
638                         }
639                         var ar = json.get_array();                      
640                         
641                         for(var i = 0; i < ar.get_length(); i++ ) {
642                                 var add= Json.gobject_deserialize ( typeof (Lsp.CompletionItem),  ar.get_element(i)) as Lsp.CompletionItem;
643                                 ret.items.add( add);
644                                          
645                         }
646                         this.log(LanguageClientAction.COMPLETE_REPLY, "GOT array %d items".printf(ret.items.size) );
647                         GLib.debug ("LS replied with Array");
648                         return ret;
649                 
650
651                 }
652                 
653                 async int hover_queue()
654                 {
655                         SourceFunc cb = this.hover_queue.callback;
656                         hover_call_count++;
657                         var call_id = hover_call_count;
658                         
659                         GLib.Timeout.add(500, () => {
660                                  GLib.Idle.add(cb);
661                                  return false;
662                         });
663                         
664                         yield;
665                         return call_id;
666                 }
667                 
668                 static int hover_call_count = 1;
669  
670                 
671                 //CompletionListInfo.itmems.parse_varient  or CompletionListInfo.parsevarient
672                 public override async  Lsp.Hover hover (JsRender.JsRender file, int line, int offset) throws GLib.Error 
673                  {
674                         /* partial_result_token ,  work_done_token   context = null) */
675                         //GLib.debug("get hover %s %d %d", file.relpath, (int)line, (int)offset);
676                         var ret = new Lsp.Hover();      
677                         //ret = null;
678                     if (!this.isReady()) {
679                                 return ret;
680                         }
681                         var  call_id = yield this.hover_queue();
682                         
683                         //GLib.debug("end hover call=%d   count=%d", call_id, hover_call_count);                        
684                         if (call_id != hover_call_count) {
685                                 //GLib.debug("get hover CANCELLED %s %d %d", file.relpath, (int)line, (int)offset);
686                                 return ret;
687                         }
688                         
689                         //GLib.debug("get hover RUN %s %d %d", file.relpath, (int)line, (int)offset);
690                         
691                         
692                         
693                         Variant? return_value;
694                         yield this.jsonrpc_client.call_async (
695                                 "textDocument/hover",
696                                 this.buildDict (  
697                                          
698                                         textDocument : this.buildDict (    ///TextDocumentItem;
699                                                 uri: new GLib.Variant.string (file.to_url()),
700                                                 version :  new GLib.Variant.uint64 ( (uint64) file.version) 
701                                         ),
702                                         position :  this.buildDict ( 
703                                                 line :  new GLib.Variant.uint64 ( (uint) line) ,
704                                                 character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
705                                         )
706                                          
707                                 ),
708                                 null,
709                                 out return_value
710                         );
711                         //GLib.debug ("LS hover replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
712                         if (return_value == null) {
713                                 return ret;
714                         }
715                         
716                         var json = Json.gvariant_serialize (return_value);
717                         if (json.get_node_type() != Json.NodeType.OBJECT) {
718                                 return ret;
719                         }
720                         
721                         
722                         ret =  Json.gobject_deserialize ( typeof (Lsp.Hover),  json) as Lsp.Hover; 
723                         
724                         return ret;
725                         
726                 
727
728                 }
729                 
730                 public override void queueDocumentSymbols (JsRender.JsRender file) 
731                 {
732                         if (this.doc_queue_file != null && this.doc_queue_file.path != file.path) {
733                                 var sendfile = this.doc_queue_file;
734                                 this.documentSymbols.begin(this.doc_queue_file, (o, res) => {
735                                         var ret = documentSymbols.end(res);
736                                         sendfile.navigation_tree_updated(ret);
737                                 });
738                         }
739                         
740                         this.doc_countdown = 2;
741                         this.doc_queue_file = file;
742                 }
743                 
744          
745                 public override async Gee.ArrayList<Lsp.DocumentSymbol> documentSymbols (JsRender.JsRender file) throws GLib.Error {
746                         /* partial_result_token ,  work_done_token   context = null) */
747                         GLib.debug("get documentSymbols %s", file.relpath);
748                         var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
749                         //ret = null;
750                     if (!this.isReady()) {
751                                 return ret;
752                         }
753                         Variant? return_value;
754                         yield this.jsonrpc_client.call_async (
755                                 "textDocument/documentSymbol",
756                                 this.buildDict (  
757                                          
758                                         textDocument : this.buildDict (    ///TextDocumentItem;
759                                                 uri: new GLib.Variant.string (file.to_url()),
760                                                 version :  new GLib.Variant.uint64 ( (uint64) file.version) 
761                                         ) 
762                                          
763                                 ),
764                                 null,
765                                 out return_value
766                         );
767                         
768                         
769                         //GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                     
770                         var json = Json.gvariant_serialize (return_value);
771                          
772                          
773
774                         var ar = json.get_array();
775                         GLib.debug ("LS replied with %D items", ar.get_length());
776                         for(var i = 0; i < ar.get_length(); i++ ) {
777                                 var add= Json.gobject_deserialize ( typeof (Lsp.DocumentSymbol),  ar.get_element(i)) as Lsp.DocumentSymbol;
778                                 ret.add( add);
779                                          
780                         }
781                         return ret ;
782                         
783                 
784                 }
785                 public override async Gee.ArrayList<Lsp.SignatureInformation> signatureHelp (JsRender.JsRender file, int line, int offset) throws GLib.Error {
786                         /* partial_result_token ,  work_done_token   context = null) */
787                         GLib.debug("get signatureHelp %s, %d, %d", file.relpath, line, offset);
788                         var ret = new Gee.ArrayList<Lsp.SignatureInformation>();        
789                         //ret = null;
790                     if (!this.isReady()) {
791                                 return ret;
792                         }
793                         Variant? return_value;
794                                 yield this.jsonrpc_client.call_async (
795                                 "textDocument/signatureHelp",
796                                 this.buildDict (  
797                                          
798                                         textDocument : this.buildDict (    ///TextDocumentItem;
799                                                 uri: new GLib.Variant.string (file.to_url())
800                                         ),
801                                         position :  this.buildDict ( 
802                                                 line :  new GLib.Variant.uint64 ( (uint) line) ,
803                                                 character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
804                                         )
805                                          
806                                 ),
807                                 null,
808                                 out return_value
809                         );
810                         
811                         
812                         GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
813                         var json = Json.gvariant_serialize (return_value);
814                         if (json.get_node_type() != Json.NodeType.ARRAY) {
815                                 return ret;
816                         }
817                         
818                          
819
820                         var ar = json.get_array();
821                         GLib.debug ("LS replied with %D items", ar.get_length());
822                         for(var i = 0; i < ar.get_length(); i++ ) {
823                                 var add= Json.gobject_deserialize ( typeof (Lsp.SignatureInformation),  ar.get_element(i)) as Lsp.SignatureInformation;
824                                 ret.add( add);
825                                          
826                         }
827                         return ret ;
828                         
829                 
830                 }
831                 public override async Gee.ArrayList<Lsp.SymbolInformation> symbol (string sym) throws GLib.Error
832                 {
833                         /* partial_result_token ,  work_done_token   context = null) */
834                         GLib.debug("get symbol %s,", sym);
835                         var ret = new Gee.ArrayList<Lsp.SymbolInformation>();   
836                         //ret = null;
837                         if (!this.isReady()) {
838                                 return ret;
839                         }
840                         Variant? return_value;
841                                 yield this.jsonrpc_client.call_async (
842                                 "textDocument/symbol",
843                                 this.buildDict (  
844                                         query :  new GLib.Variant.string (sym)                                   
845                                 ),
846                                 null,
847                                 out return_value
848                         );
849                         
850 GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));       
851                         return ret;
852                 }
853                 
854         }
855         
856         
857         
858         
859         
860         
861         
862         
863 }