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