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