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