Merge branch 'master' of http://git.roojs.com/roobuilder
[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                 
203                 public override   void  initialize_server()   {
204                         try {
205                                 Variant? return_value;
206                                     this.jsonrpc_client.call (
207                                     "initialize",
208                                     this.buildDict (
209                                         processId: new Variant.int32 ((int32) Posix.getpid ()),
210                                         rootPath: new Variant.string (this.project.path),
211                                         rootUri: new Variant.string (File.new_for_path (this.project.path).get_uri ()),
212                                         capabilities : this.buildDict (
213                                                 textDocument: this.buildDict (
214                                                         documentSymbol : this.buildDict (
215                                                                 hierarchicalDocumentSymbolSupport : new Variant.boolean (true)
216                                                         )
217                                                 )
218                                         )
219                                     ),
220                                     null,
221                                     out return_value
222                                 );
223                                 GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));
224                                 this.open_files = new Gee.ArrayList<JsRender.JsRender>((a,b) => {
225                                         return a.path == b.path;
226                                 });
227                                 this.initialized = true;
228                                 this.getting_diagnostics = false;
229                                 return;
230                         } catch (GLib.Error e) {
231                                 GLib.debug ("LS replied with error %s", e.message);
232                                 this.onClose();
233                         }
234                         
235                 }
236                 void onClose()
237                 {
238                         if (this.in_close) {
239                                 return;
240                         }
241                         if (this.launcher == null) {
242                                 return;
243                         }
244                         this.getting_diagnostics = false;
245                         this.in_close = true;
246                         GLib.debug("onClose called");
247                         
248                         if (this.jsonrpc_client != null) {
249                                 try {
250                                         this.jsonrpc_client.close();
251                                 } catch (GLib.Error e) {
252                                         GLib.debug("rpc Error close error %s", e.message);      
253                                 }               
254                         }
255                         if (this.subprocess_stream != null) {
256                                 try {
257                                         this.subprocess_stream.close();
258                                 } catch (GLib.Error e) {
259                                         GLib.debug("stream Error close  %s", e.message);        
260                                 }               
261                         }
262                         if (this.subprocess != null) {
263                                 this.subprocess.force_exit();
264                         }
265                         if (this.launcher != null) {
266                                 this.launcher.close();
267                         }
268                         
269                         this.launcher = null;
270                         this.subprocess = null;
271                         this.jsonrpc_client = null;
272                         this.closed = true;             
273                         this.in_close = false;
274                 }
275         
276                 public async void restartServer()
277                 {
278                         this.startServer();
279                          
280                 }
281         
282                 public bool isReady()
283                 {
284                         if (this.closed) {
285                                 this.log(LanguageClientAction.RESTART,"closed is set - restarting");
286                                 GLib.debug("server stopped = restarting");
287                                 this.initialized = false;
288                                 this.closed = false;
289                                 GLib.MainLoop loop = new GLib.MainLoop ();
290                                 this.restartServer.begin ((obj, async_res) => {
291                                         this.restartServer.end(async_res);
292                                         loop.quit ();
293                                 });
294                                 return false; // can't do an operation yet?
295                                  
296                         }
297                         
298                         if (!this.initialized) {
299                                 GLib.debug("Server has not been initialized");
300                                 return false;
301                         }
302                         if (this.sent_shutdown) {
303                                 GLib.debug("Server has been started its shutting down process");
304                                 return false;
305                         }
306                         // restart server..
307                 
308                         
309                         
310                         return true;
311                 }
312         
313                 public void onNotification(string method, Variant? return_value)
314                 {
315                         switch (method) {
316                                 case "textDocument/publishDiagnostics":
317                                         //GLib.debug("got notification %s : %s",  method , Json.to_string (Json.gvariant_serialize (return_value), true));
318                                          
319                                         GLib.Idle.add(() => {
320                                                 this.onDiagnostic(return_value);
321                                                 return false;
322                                         });
323                                         return;
324                                 default: 
325                                         break;
326                                  
327                         }
328                         GLib.debug("got notification %s : %s",  method , Json.to_string (Json.gvariant_serialize (return_value), true));
329                         
330                 }
331                 
332                 bool getting_diagnostics = false;
333                 /***
334                 
335                 */
336                 public void onDiagnostic(Variant? return_value) 
337                 {
338                         //GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                     
339                         var dg = Json.gobject_deserialize (typeof (Lsp.Diagnostics), Json.gvariant_serialize (return_value)) as Lsp.Diagnostics; 
340                         GLib.debug("got diag for %s", dg.filename);
341                         this.log(LanguageClientAction.DIAG, dg.filename);
342                         if (this.project.path == dg.filename) {
343                                 this.getting_diagnostics = false;
344                                 this.log(LanguageClientAction.DIAG_END, "diagnostics done");
345                                 return;
346                         
347                         }
348                         this.getting_diagnostics =true;
349                         var f = this.project.getByPath(dg.filename);
350                         if (f == null) {
351                                 //GLib.debug("no file %s", dg.uri);
352                                 //this.project.updateErrorsforFile(null);
353                                 return;
354                         }
355                         //GLib.debug("got Diagnostics for %s", f.path);
356                         f.updateErrors( dg.diagnostics );
357                          
358                         
359                 }
360                 
361                 public override void document_open (JsRender.JsRender file)  
362                 {
363                         if (!this.isReady()) {
364                                 return;
365                         }
366                         if (this.open_files.contains(file)) {
367                                 return;
368                         }
369                         this.open_files.add(file);
370                         
371                         
372                         GLib.debug ("LS sent open");                     
373                         try {
374                                 this.jsonrpc_client.send_notification (
375                                         "textDocument/didOpen",
376                                         this.buildDict (
377                                                 textDocument : this.buildDict (
378                                                         uri: new Variant.string (file.to_url()),
379                                                         languageId :  new Variant.string (file.language_id()),
380                                                         version :  new GLib.Variant.uint64 ( (uint64) file.version),
381                                                         text : new Variant.string (file.toSource())
382                                                 )
383                                         ),
384                                         null
385                                 );
386                                 this.log(LanguageClientAction.OPEN, file.path);
387                         } catch( GLib.Error  e) {
388                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
389                                 this.onClose();
390                                 GLib.debug ("LS sent open err %s", e.message);
391                         }
392
393                 }
394                 
395                 public override  async void document_save (JsRender.JsRender file)  
396         {
397                         if (!this.isReady()) {
398                                 return;
399                         }
400                         // save only really flags the file on the server - to actually force a change update - we need to 
401                         // flag it as changed.
402                         yield this.document_change_force(file, file.toSource());
403                         
404                         this.change_queue_file = null;
405                         GLib.debug ("LS send save");
406                          try {
407                          
408                                 var args = this.buildDict (  
409                                         textDocument : this.buildDict (    ///TextDocumentItem;
410                                                 uri: new GLib.Variant.string (file.to_url()),
411                                                 version :  new GLib.Variant.uint64 ( (uint64) file.version)
412                                         )
413                                 );
414                          
415                                 //GLib.debug ("textDocument/save send with %s", Json.to_string (Json.gvariant_serialize (args), true));                                 
416                         
417                          
418                          
419                                   yield this.jsonrpc_client.send_notification_async  (
420                                         "textDocument/didSave",
421                                         args,
422                                         null 
423                                 );
424                                 this.log(LanguageClientAction.SAVE, file.path);
425                         } catch( GLib.Error  e) {
426                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
427                                 GLib.debug ("LS   save err %s", e.message);
428                                 this.onClose();
429                         }
430
431          
432         }
433                 public override  void document_close (JsRender.JsRender file) 
434         {
435                         if (!this.isReady()) {
436                                 return;
437                         }
438                         this.change_queue_file = null;
439                         
440                         if (this.open_files.contains(file)) {
441                                 this.open_files.remove(file);
442                         }
443                         this.log(LanguageClientAction.CLOSE, file.path);
444                         GLib.debug ("LS send close");
445                         try {
446                                   this.jsonrpc_client.send_notification  (
447                                         "textDocument/didChange",
448                                         this.buildDict (  
449                                                 textDocument : this.buildDict (    ///TextDocumentItem;
450                                                         uri: new GLib.Variant.string (file.to_url())
451                                                         
452                                                 )
453                                         ),
454                                         null  
455                                 );
456                         } catch( GLib.Error  e) {
457                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
458                                 GLib.debug ("LS close err %s", e.message);
459                                 this.onClose();
460                         }
461
462          
463         }
464         
465          
466                 public override void document_change (JsRender.JsRender file )    
467                 {
468                         if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
469                                 this.document_change_force.begin(this.change_queue_file, this.change_queue_file_source, (o, res) => {
470                                         this.document_change_force.end(res);
471                                 });
472                         }
473                         
474                         this.countdown = 2;
475                         this.change_queue_file = file;
476                          
477                         
478
479                 }
480         
481
482                 public override async void document_change_force (JsRender.JsRender file, string contents)  
483         {
484                         
485                         
486                         if (!this.isReady()) {
487                                 return;
488                         }
489                         this.countdown = -2; // not really relivant..
490                         this.change_queue_file = null; // this is more important..
491                         
492                     if (!this.open_files.contains(file)) {
493                                  this.document_open(file);
494                         }  
495                         
496                         GLib.debug ("LS send change %s rev %d", file.path, file.version);
497                         var ar = new Json.Array();
498                         var obj = new Json.Object();
499                         obj.set_string_member("text", contents);
500                         ar.add_object_element(obj);
501                         var node = new Json.Node(Json.NodeType.ARRAY);
502                         node.set_array(ar);
503                         this.log(LanguageClientAction.CHANGE, file.path);
504                          try {
505                                 yield this.jsonrpc_client.send_notification_async (
506                                         "textDocument/didChange",
507                                         this.buildDict (  
508                                                 textDocument : this.buildDict (    ///TextDocumentItem;
509                                                         uri: new GLib.Variant.string (file.to_url()),
510                                                         version :  new GLib.Variant.uint64 ( (uint64) file.version) 
511                                                 ),
512                                                 contentChanges : Json.gvariant_deserialize (node, null)
513                                                 
514                                         ),
515                                         null 
516                                 );
517                         } catch( GLib.Error  e) {
518                                 this.log(LanguageClientAction.ERROR_RPC, e.message);
519                                 GLib.debug ("LS change err %s", e.message);
520                                 this.onClose();
521                         }
522
523          
524         }
525         // called by close window (on last window)...
526                 public override  void exit () throws GLib.Error 
527                 {
528                         if (!this.isReady()) {
529                         
530                                 return;
531                         }
532                         this.log(LanguageClientAction.TERM, "SEND exit");
533                  
534                           this.jsonrpc_client.send_notification (
535                                 "exit",
536                                 null,
537                                 null 
538                         );
539                         this.onClose();
540
541                 }
542                 // not used currently..
543                 public override async void shutdown () throws GLib.Error 
544                 {
545                         if (!this.isReady()) {
546                                 return;
547                         }
548                         this.log(LanguageClientAction.TERM, "SEND shutodwn");
549                         this.sent_shutdown  = true;
550                         Variant? return_value;
551                         yield this.jsonrpc_client.call_async (
552                                 "shutdown",
553                                 null,
554                                 null,
555                                 out return_value
556                         );
557                         GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));               
558                 }
559                 //public async  ??/symbol (string symbol) throws GLib.Error {
560                 
561                 // and now for the important styff..
562                 
563                 /*
564                 
565                 @triggerType 1 = typing or ctl-spac, 2 = tiggercharactres?  3= inside completion?
566                 */
567                  public override async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
568                  {
569                         /* partial_result_token ,  work_done_token   context = null) */
570                         GLib.debug("%s get completion %s @ %d:%d", this.get_type().name(),  file.relpath, line, offset);
571                         
572                         var ret = new Lsp.CompletionList();     
573                         
574                     if (!this.isReady()) {
575                         GLib.debug("completion - language server not ready");
576                                 return ret;
577                         }
578                         // make sure completion has the latest info..
579                         //if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
580                         //      this.document_change_real(this.change_queue_file, this.change_queue_file_source);
581                         //      this.change_queue_file != null;
582                         //}
583                         this.log(LanguageClientAction.COMPLETE, "SEND complete  %s @ %d:%d".printf(file.relpath, line, offset) );
584                         
585                         Variant? return_value;
586                         
587                         var args = this.buildDict (  
588                                         context : this.buildDict (    ///CompletionContext;
589                                                 triggerKind: new GLib.Variant.int32 (triggerType) 
590                                         //      triggerCharacter :  new GLib.Variant.string ("")
591                                         ),
592                                         textDocument : this.buildDict (    ///TextDocumentItem;
593                                                 uri: new GLib.Variant.string (file.to_url()),
594                                                 version :  new GLib.Variant.uint64 ( (uint64) file.version) 
595                                         ), 
596                                         position :  this.buildDict ( 
597                                                 line :  new GLib.Variant.uint64 ( (uint) line) ,
598                                                 character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
599                                         )
600                                 );
601                          
602                         GLib.debug ("textDocument/completion send with %s", Json.to_string (Json.gvariant_serialize (args), true));                                     
603                         
604                         yield this.jsonrpc_client.call_async (
605                                 "textDocument/completion",
606                                 args,
607                                 null,
608                                 out return_value
609                         );
610                         
611                         
612                         //GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                     
613                         var json = Json.gvariant_serialize (return_value);
614
615
616                         if (json.get_node_type() == Json.NodeType.OBJECT) {
617                                 ret = Json.gobject_deserialize (typeof (Lsp.CompletionList), json) as Lsp.CompletionList; 
618                                 this.log(LanguageClientAction.COMPLETE_REPLY, "GOT complete  %d items".printf(ret.items.size) );
619                                 GLib.debug ("LS replied with Object");
620                                 return ret;
621                         }  
622
623                         if (json.get_node_type() != Json.NodeType.ARRAY) {
624                                 GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
625                                 this.log(LanguageClientAction.ERROR_REPLY, "GOT something else??");
626                                 return ret;
627                         
628                         }
629                         var ar = json.get_array();                      
630                         
631                         for(var i = 0; i < ar.get_length(); i++ ) {
632                                 var add= Json.gobject_deserialize ( typeof (Lsp.CompletionItem),  ar.get_element(i)) as Lsp.CompletionItem;
633                                 ret.items.add( add);
634                                          
635                         }
636                         this.log(LanguageClientAction.COMPLETE_REPLY, "GOT array %d items".printf(ret.items.size) );
637                         GLib.debug ("LS replied with Array");
638                         return ret;
639                 
640
641                 }
642                 
643          
644                 
645                 static int hover_call_count = 1;
646                 bool getting_hover = false;
647                 
648                 //CompletionListInfo.itmems.parse_varient  or CompletionListInfo.parsevarient
649                 public override async  Lsp.Hover hover (JsRender.JsRender file, int line, int offset) throws GLib.Error 
650                  {
651                         /* partial_result_token ,  work_done_token   context = null) */
652                         //GLib.debug("get hover %s %d %d", file.relpath, (int)line, (int)offset);
653                         var ret = new Lsp.Hover();      
654                         //ret = null;
655                     if (!this.isReady()) {
656                                 return ret;
657                         }
658                         if (this.getting_hover) {
659                                 return ret;
660                         }
661                         
662                         hover_call_count++;
663                         var  call_id = yield this.queuer(hover_call_count);
664                         
665                         //GLib.debug("end hover call=%d   count=%d", call_id, hover_call_count);                        
666                         if (call_id != hover_call_count) {
667                                 //GLib.debug("get hover CANCELLED %s %d %d", file.relpath, (int)line, (int)offset);
668                                 return ret;
669                         }
670                         
671                         //GLib.debug("get hover RUN %s %d %d", file.relpath, (int)line, (int)offset);
672                         
673                         this.getting_hover = true;
674                         
675                         Variant? return_value;
676                         try {
677                                 yield this.jsonrpc_client.call_async (
678                                         "textDocument/hover",
679                                         this.buildDict (  
680                                                  
681                                                 textDocument : this.buildDict (    ///TextDocumentItem;
682                                                         uri: new GLib.Variant.string (file.to_url()),
683                                                         version :  new GLib.Variant.uint64 ( (uint64) file.version) 
684                                                 ),
685                                                 position :  this.buildDict ( 
686                                                         line :  new GLib.Variant.uint64 ( (uint) line) ,
687                                                         character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
688                                                 )
689                                                  
690                                         ),
691                                         null,
692                                         out return_value
693                                 );
694                         } catch(GLib.Error e) {
695                                 this.getting_hover = false;
696                                 throw e;
697                         }
698                         this.getting_hover = false;
699                          GLib.debug ("LS hover replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                        
700                         if (return_value == null) {
701                                 return ret;
702                         }
703                         
704                         var json = Json.gvariant_serialize (return_value);
705                         if (json.get_node_type() != Json.NodeType.OBJECT) {
706                                 return ret;
707                         }
708                         
709                         
710                         ret =  Json.gobject_deserialize ( typeof (Lsp.Hover),  json) as Lsp.Hover; 
711                         
712                         return ret;
713                         
714                 
715
716                 }
717                 
718                 
719                 static int doc_symbol_queue_call_count = 1;
720  
721                 
722                 
723                 public override void queueDocumentSymbols (JsRender.JsRender file) 
724                 {
725                           
726                         this.documentSymbols.begin(file, (o, res) => {
727                                 var ret = documentSymbols.end(res);
728                                 file.navigation_tree_updated(ret);
729                         });
730                   
731                          
732                 }
733                 
734                 bool getting_symbols = false;
735          
736                 public override async Gee.ArrayList<Lsp.DocumentSymbol> documentSymbols (JsRender.JsRender file) throws GLib.Error 
737                 {
738                         /* partial_result_token ,  work_done_token   context = null) */
739                         GLib.debug("get documentSymbols %s", file.relpath);
740                         var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
741                         //ret = null;
742                     if (!this.isReady()) {
743                                 return ret;
744                         }
745                         if (this.getting_symbols) {
746                                 return ret;
747                         }
748
749                         
750                         doc_symbol_queue_call_count++;
751                         var call_id = yield this.queuer(doc_symbol_queue_call_count);
752                         if (call_id != doc_symbol_queue_call_count) {
753                                 
754                                 return ret;
755                         }
756                         this.getting_symbols = true;
757                         
758                         Variant? return_value;
759                         try { 
760                                 yield this.jsonrpc_client.call_async (
761                                         "textDocument/documentSymbol",
762                                         this.buildDict (  
763                                                  
764                                                 textDocument : this.buildDict (    ///TextDocumentItem;
765                                                         uri: new GLib.Variant.string (file.to_url()),
766                                                         version :  new GLib.Variant.uint64 ( (uint64) file.version) 
767                                                 ) 
768                                                  
769                                         ),
770                                         null,
771                                         out return_value
772                                 );
773                         } catch(Error e) {
774                                 this.getting_symbols = false;                   
775                                 throw e;
776                         }
777                         this.getting_symbols = false;
778                         
779                         GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
780                         var json = Json.gvariant_serialize (return_value);
781                          
782                          
783
784                         var ar = json.get_array();
785                         GLib.debug ("LS replied with %D items", ar.get_length());
786                         for(var i = 0; i < ar.get_length(); i++ ) {
787                                 var add= Json.gobject_deserialize ( typeof (Lsp.DocumentSymbol),  ar.get_element(i)) as Lsp.DocumentSymbol;
788                                 ret.add( add);
789                                          
790                         }
791                         return ret ;
792                         
793                 
794                 }
795                 // cant seem to get this to show anything!!
796                 public override async Gee.ArrayList<Lsp.SignatureInformation> signatureHelp (JsRender.JsRender file, int line, int offset) throws GLib.Error {
797                         /* partial_result_token ,  work_done_token   context = null) */
798                         GLib.debug("get signatureHelp %s, %d, %d", file.relpath, line, offset);
799                         var ret = new Gee.ArrayList<Lsp.SignatureInformation>();        
800                         //ret = null;
801                     if (!this.isReady()) {
802                                 return ret;
803                         }
804                         Variant? return_value;
805                                 yield this.jsonrpc_client.call_async (
806                                 "textDocument/signatureHelp",
807                                 this.buildDict (  
808                                          
809                                         textDocument : this.buildDict (    ///TextDocumentItem;
810                                                 uri: new GLib.Variant.string (file.to_url())
811                                         ),
812                                         position :  this.buildDict ( 
813                                                 line :  new GLib.Variant.uint64 ( (uint) line) ,
814                                                 character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
815                                         )
816                                          
817                                 ),
818                                 null,
819                                 out return_value
820                         );
821                         
822                         
823                         GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
824                         var json = Json.gvariant_serialize (return_value);
825                         if (json.get_node_type() != Json.NodeType.ARRAY) {
826                                 return ret;
827                         }
828                         
829                          
830
831                         var ar = json.get_array();
832                         GLib.debug ("LS replied with %D items", ar.get_length());
833                         for(var i = 0; i < ar.get_length(); i++ ) {
834                                 var add= Json.gobject_deserialize ( typeof (Lsp.SignatureInformation),  ar.get_element(i)) as Lsp.SignatureInformation;
835                                 ret.add( add);
836                                          
837                         }
838                         return ret ;
839                         
840                 
841                 }
842                 // ok for general symbol search, not much details though.
843                 public override async Gee.ArrayList<Lsp.SymbolInformation> symbol (string sym) throws GLib.Error
844                 {
845                         /* partial_result_token ,  work_done_token   context = null) */
846                         GLib.debug("get symbol %s,", sym);
847                         var ret = new Gee.ArrayList<Lsp.SymbolInformation>();   
848                         //ret = null;
849                         if (!this.isReady()) {
850                                 return ret;
851                         }
852                         Variant? return_value;
853                                 yield this.jsonrpc_client.call_async (
854                                 "workspace/symbol",
855                                 this.buildDict (  
856                                         query :  new GLib.Variant.string (sym)                                   
857                                 ),
858                                 null,
859                                 out return_value
860                         );
861                         
862 GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));       
863                         return ret;
864                 }
865                 
866         }
867         
868         
869         
870         
871         
872         
873         
874         
875 }