Merge branch 'master' of http://git.roojs.com/roobuilder
[roobuilder] / src / Palete / LanguageClientVala.vala
index 9a508de..f49bbd8 100644 (file)
@@ -1,7 +1,6 @@
 
 namespace Palete {
        public class LanguageClientVala : LanguageClient {
-               int countdown = 0;
                protected bool initialized = false;
                bool sent_shutdown = false;
                uint change_queue_id = 0;
@@ -20,9 +19,13 @@ namespace Palete {
                private IOStream? subprocess_stream = null;
            public Jsonrpc.Client? jsonrpc_client = null;
                
+               int countdown = 0;
                Gee.ArrayList<JsRender.JsRender> open_files;
                private JsRender.JsRender? _change_queue_file = null;
+               int doc_countdown = 0;
                private string change_queue_file_source = "";
+               private JsRender.JsRender? doc_queue_file = null;
+
                
                JsRender.JsRender? change_queue_file {
                        set {
@@ -33,6 +36,9 @@ namespace Palete {
                                return this._change_queue_file;
                        } 
                }
+               
+
+               
                void startServer()
                {
                        var exe = GLib.Environment.find_program_in_path( "vala-language-server");
@@ -50,30 +56,59 @@ namespace Palete {
                        // extend versions will proably call initialize to start and connect to server.
                        base(project);
 
-                       this.change_queue_id = GLib.Timeout.add_seconds(1, () => {
-                               if (this.change_queue_file == null) {
-                                       return true;
-                               }
-                               if (this.getting_diagnostics) {
-                                       return true;
-                               }
-                               this.countdown--;
-
+                       if (this.change_queue_id == 0 ) {
+                               this.change_queue_id = GLib.Timeout.add(500, () => {
+                                       this.run_change_queue(); 
+                                       return true;
+                               });
+                       }
                        
-                               if (this.countdown < 0){
-                                       this.document_change_force.begin(this.change_queue_file,  this.change_queue_file_source, (o, res) => {
-                                               this.document_change_force.end(res);
-                                       });
-                                       this.change_queue_file = null;
-                                          
-                               }
-                               return true;
-                       });
                        this.startServer();
 
                }
                
+               void run_change_queue()
+               {
+               
+                       if (this.change_queue_file == null) {
+                               return ;
+                       }
+                       if (this.countdown < -1) {
+                               return;
+                       }
+                       if (this.getting_diagnostics) {
+                               return;
+                       }
+                       this.countdown--;
+
+               
+                       if (this.countdown < 0){
+                               this.document_change_force.begin(this.change_queue_file,  this.change_queue_file_source, (o, res) => {
+                                       this.document_change_force.end(res);
+                               });
+                               this.change_queue_file = null;
+                                  
+                       }
+                       return ;
+               }
                 
+               async int queuer(int cnt)
+               {
+                       SourceFunc cb = this.queuer.callback;
+                 
+                       GLib.Timeout.add(500, () => {
+                                GLib.Idle.add((owned) cb);
+                                return false;
+                       });
+                       
+                       yield;
+                       return cnt;
+               }
+               static int doc_queue_id = 0;
+               
+        
+               
+               
                public bool initProcess(string process_path)
                {
                        this.onClose();
@@ -160,7 +195,6 @@ namespace Palete {
 
                                this.initialize_server ();
                        } 
-                                        
                         
                }
                
@@ -173,7 +207,14 @@ namespace Palete {
                                    this.buildDict (
                                        processId: new Variant.int32 ((int32) Posix.getpid ()),
                                        rootPath: new Variant.string (this.project.path),
-                                       rootUri: new Variant.string (File.new_for_path (this.project.path).get_uri ())
+                                       rootUri: new Variant.string (File.new_for_path (this.project.path).get_uri ()),
+                                       capabilities : this.buildDict (
+                                               textDocument: this.buildDict (
+                                                       documentSymbol : this.buildDict (
+                                                               hierarchicalDocumentSymbolSupport : new Variant.boolean (true)
+                                                       )
+                                               )
+                                       )
                                    ),
                                    null,
                                    out return_value
@@ -237,7 +278,7 @@ namespace Palete {
                         
                }
        
-               public bool isReady()
+               public override bool isReady()
                {
                        if (this.closed) {
                                this.log(LanguageClientAction.RESTART,"closed is set - restarting");
@@ -429,7 +470,7 @@ namespace Palete {
                                });
                        }
                        
-                       this.countdown = 3;
+                       this.countdown = 2;
                        this.change_queue_file = file;
                         
                        
@@ -444,7 +485,7 @@ namespace Palete {
                        if (!this.isReady()) {
                                return;
                        }
-                       this.countdown = 9; // not really relivant..
+                       this.countdown = -2; // not really relivant..
                        this.change_queue_file = null; // this is more important..
                        
                    if (!this.open_files.contains(file)) {
@@ -598,39 +639,73 @@ namespace Palete {
 
                }
                
+        
+               
+               static int hover_call_count = 1;
+               bool getting_hover = false;
                
                //CompletionListInfo.itmems.parse_varient  or CompletionListInfo.parsevarient
                public override async  Lsp.Hover hover (JsRender.JsRender file, int line, int offset) throws GLib.Error 
                 {
                        /* partial_result_token ,  work_done_token   context = null) */
-                       GLib.debug("get syntax %s", file.relpath);
+                       //GLib.debug("get hover %s %d %d", file.relpath, (int)line, (int)offset);
                        var ret = new Lsp.Hover();      
                        //ret = null;
                    if (!this.isReady()) {
                                return ret;
                        }
+                       if (this.getting_hover) {
+                               return ret;
+                       }
+                       
+                       hover_call_count++;
+                       var  call_id = yield this.queuer(hover_call_count);
+                       
+                       //GLib.debug("end hover call=%d   count=%d", call_id, hover_call_count);                        
+                       if (call_id != hover_call_count) {
+                               //GLib.debug("get hover CANCELLED %s %d %d", file.relpath, (int)line, (int)offset);
+                               return ret;
+                       }
+                       
+                       //GLib.debug("get hover RUN %s %d %d", file.relpath, (int)line, (int)offset);
+                       
+                       this.getting_hover = true;
+                       
                        Variant? return_value;
-                       yield this.jsonrpc_client.call_async (
-                               "textDocument/hover",
-                               this.buildDict (  
-                                        
-                                       textDocument : this.buildDict (    ///TextDocumentItem;
-                                               uri: new GLib.Variant.string (file.to_url()),
-                                               version :  new GLib.Variant.uint64 ( (uint64) file.version) 
+                       try {
+                               yield this.jsonrpc_client.call_async (
+                                       "textDocument/hover",
+                                       this.buildDict (  
+                                                
+                                               textDocument : this.buildDict (    ///TextDocumentItem;
+                                                       uri: new GLib.Variant.string (file.to_url()),
+                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version) 
+                                               ),
+                                               position :  this.buildDict ( 
+                                                       line :  new GLib.Variant.uint64 ( (uint) line) ,
+                                                       character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
+                                               )
+                                                
                                        ),
-                                       position :  this.buildDict ( 
-                                               line :  new GLib.Variant.uint64 ( (uint) line) ,
-                                               character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
-                                       )
-                                        
-                               ),
-                               null,
-                               out return_value
-                       );
-                       
+                                       null,
+                                       out return_value
+                               );
+                       } catch(GLib.Error e) {
+                               this.getting_hover = false;
+                               throw e;
+                       }
+                       this.getting_hover = false;
+                        GLib.debug ("LS hover replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                        
+                       if (return_value == null) {
+                               return ret;
+                       }
                        
-                       GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
                        var json = Json.gvariant_serialize (return_value);
+                       if (json.get_node_type() != Json.NodeType.OBJECT) {
+                               return ret;
+                       }
+                       
+                       
                        ret =  Json.gobject_deserialize ( typeof (Lsp.Hover),  json) as Lsp.Hover; 
                        
                        return ret;
@@ -640,26 +715,105 @@ namespace Palete {
                }
                
                
+               static int doc_symbol_queue_call_count = 1;
                
-               //CompletionListInfo.itmems.parse_varient  or CompletionListInfo.parsevarient
-               public override async Gee.ArrayList<Lsp.DocumentSymbol> syntax (JsRender.JsRender file) throws GLib.Error 
-                {
-                       /* partial_result_token ,  work_done_token   context = null) */
-                       GLib.debug("get syntax %s", file.relpath);
+               
+               public override void queueDocumentSymbols (JsRender.JsRender file) 
+               {
+                         
+                       this.documentSymbols.begin(file, (o, res) => {
+                               var ret = documentSymbols.end(res);
+                               file.navigation_tree_updated(ret);
+                       });
+                 
+                        
+               }
+               
+               bool getting_symbols = false;
+        
+               public override async Gee.ArrayList<Lsp.DocumentSymbol> documentSymbols (JsRender.JsRender file) throws GLib.Error 
+               {
+                       /* partial_result_token ,  work_done_token   context = null) */
+                       GLib.debug("get documentSymbols %s", file.relpath);
                        var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
                        //ret = null;
                    if (!this.isReady()) {
+                       GLib.debug("docsymbols not ready");
+                               return ret;
+                       }
+                       if (this.getting_symbols) {
+                               GLib.debug("docsymbols currently getting symbols");
                                return ret;
                        }
+
+                       
+                       doc_symbol_queue_call_count++;
+                       var call_id = yield this.queuer(doc_symbol_queue_call_count);
+                       if (call_id != doc_symbol_queue_call_count) {
+                               GLib.debug("docsymbols call id does not match %d %d" ,call_id , doc_symbol_queue_call_count);
+                               return ret;
+                       }
+                       this.getting_symbols = true;
+                       
                        Variant? return_value;
-                       yield this.jsonrpc_client.call_async (
-                               "textDocument/documentSymbol",
+                       try { 
+                               yield this.jsonrpc_client.call_async (
+                                       "textDocument/documentSymbol",
+                                       this.buildDict (  
+                                                
+                                               textDocument : this.buildDict (    ///TextDocumentItem;
+                                                       uri: new GLib.Variant.string (file.to_url()),
+                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version) 
+                                               ) 
+                                                
+                                       ),
+                                       null,
+                                       out return_value
+                               );
+                       } catch(Error e) {
+                               this.getting_symbols = false;                   
+                               throw e;
+                       }
+                       this.getting_symbols = false;
+                       
+                       GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
+                       var json = Json.gvariant_serialize (return_value);
+                        
+                        
+
+                       var ar = json.get_array();
+                       GLib.debug ("LS replied with %D items", ar.get_length());
+                       for(var i = 0; i < ar.get_length(); i++ ) {
+                               var add= Json.gobject_deserialize ( typeof (Lsp.DocumentSymbol),  ar.get_element(i)) as Lsp.DocumentSymbol;
+                               ret.add( add);
+                                        
+                       }
+                       return ret ;
+                       
+               
+               }
+               // cant seem to get this to show anything!!
+               public override async Gee.ArrayList<Lsp.SignatureInformation> signatureHelp (JsRender.JsRender file, int line, int offset) throws GLib.Error {
+                       /* partial_result_token ,  work_done_token   context = null) */
+                       GLib.debug("get signatureHelp %s, %d, %d", file.relpath, line, offset);
+                       var ret = new Gee.ArrayList<Lsp.SignatureInformation>();        
+                       //ret = null;
+                   if (!this.isReady()) {
+                               return ret;
+                       }
+                       Variant? return_value;
+                               yield this.jsonrpc_client.call_async (
+                               "textDocument/signatureHelp",
                                this.buildDict (  
                                         
                                        textDocument : this.buildDict (    ///TextDocumentItem;
-                                               uri: new GLib.Variant.string (file.to_url()),
-                                               version :  new GLib.Variant.uint64 ( (uint64) file.version) 
-                                       ) 
+                                               uri: new GLib.Variant.string (file.to_url())
+                                       ),
+                                       position :  this.buildDict ( 
+                                               line :  new GLib.Variant.uint64 ( (uint) line) ,
+                                               character :  new GLib.Variant.uint64 ( uint.max(0,  (offset -1))) 
+                                       )
                                         
                                ),
                                null,
@@ -669,21 +823,54 @@ namespace Palete {
                        
                        GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
                        var json = Json.gvariant_serialize (return_value);
-                        
+                       if (json.get_node_type() != Json.NodeType.ARRAY) {
+                               return ret;
+                       }
+                       
                         
 
                        var ar = json.get_array();
+                       GLib.debug ("LS replied with %D items", ar.get_length());
                        for(var i = 0; i < ar.get_length(); i++ ) {
-                               var add= Json.gobject_deserialize ( typeof (Lsp.DocumentSymbol),  ar.get_element(i)) as Lsp.DocumentSymbol;
+                               var add= Json.gobject_deserialize ( typeof (Lsp.SignatureInformation),  ar.get_element(i)) as Lsp.SignatureInformation;
                                ret.add( add);
                                         
                        }
-                               return ret ;
+                       return ret ;
                        
                
-
+               }
+               // ok for general symbol search, not much details though.
+               public override async Gee.ArrayList<Lsp.SymbolInformation> symbol (string sym) throws GLib.Error
+               {
+                       /* partial_result_token ,  work_done_token   context = null) */
+                       GLib.debug("get symbol %s,", sym);
+                       var ret = new Gee.ArrayList<Lsp.SymbolInformation>();   
+                       //ret = null;
+                       if (!this.isReady()) {
+                               return ret;
+                       }
+                       Variant? return_value;
+                               yield this.jsonrpc_client.call_async (
+                               "workspace/symbol",
+                               this.buildDict (  
+                                       query :  new GLib.Variant.string (sym)                                   
+                               ),
+                               null,
+                               out return_value
+                       );
+                       
+GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));      
+                       return ret;
                }
                
        }
        
+       
+       
+       
+       
+       
+       
+       
 }
\ No newline at end of file