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