Fix #7982 - roo javascript completion
authorAlan <alan@roojs.com>
Tue, 23 Jan 2024 09:38:20 +0000 (17:38 +0800)
committerAlan <alan@roojs.com>
Tue, 23 Jan 2024 09:38:20 +0000 (17:38 +0800)
13 files changed:
src/Application.vala
src/Builder4/DialogConfirm.bjs
src/Builder4/DialogConfirm.vala
src/JsRender/Node.vala
src/JsRender/NodeToJs.vala
src/JsRender/NodeToVala.vala
src/Palete/CompletionProvider.vala
src/Palete/Javascript.vala
src/Palete/LanguageClient.vala
src/Palete/LanguageClientDummy.vala
src/Palete/LanguageClientJavascript.vala
src/Palete/LanguageClientVala.vala
src/Project/Roo.vala

index 9eb45bd..7584337 100644 (file)
                        }
                        var loop = new MainLoop();
                        GLib.Timeout.add_seconds(1, () => {
-                               if (!ls.isReady()) {
-                                       GLib.debug("waiting for server to be ready");
-                                       return true;
-                               }
+                        
                                GLib.debug("Sending document_open");
                                // it's ready..
                                 
index 045bf89..551f453 100644 (file)
@@ -15,7 +15,7 @@
      "   this.el.response(Gtk.ResponseType.CANCEL);",
      "    this.el.hide();",
      "    return true;",
-     " ",
+     "",
      "}",
      ""
     ]
index dfb48ad..ef1281c 100644 (file)
@@ -1,53 +1,53 @@
-    static DialogConfirm  _DialogConfirm;
-
-    public class DialogConfirm : Object
-    {
-        public Gtk.MessageDialog el;
-        private DialogConfirm  _this;
-
-        public static DialogConfirm singleton()
-        {
-            if (_DialogConfirm == null) {
-                _DialogConfirm= new DialogConfirm();
-            }
-            return _DialogConfirm;
-        }
-
-            // my vars (def)
-
-        // ctor
-        public DialogConfirm()
-        {
-            _this = this;
-            this.el = new Gtk.MessageDialog( null, Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Test" );
-
-            // my vars (dec)
-
-            // set gobject values
-            this.el.title = "Please Confirm ";
-            this.el.name = "DialogConfirm";
-            this.el.modal = true;
-            this.el.use_markup = true;
-
-            //listeners
-            this.el.close_request.connect( (event) => {
-               this.el.response(Gtk.ResponseType.CANCEL);
-                this.el.hide();
-                return true;
-             
-            });
-        }
-
-        // user defined functions
-        public void showIt // caller needs to connect to the  response -  to get the result.
-          
-          (string title, string msg) {
-             //if (!this.el) { this.init(); } 
-             //this.success = success;
-             this.el.title = title;
-            this.el.text =  msg;
-            this.el.show();
-           
-           
-        }
-    }
+static DialogConfirm  _DialogConfirm;
+
+public class DialogConfirm : Object
+{
+       public Gtk.MessageDialog el;
+       private DialogConfirm  _this;
+
+       public static DialogConfirm singleton()
+       {
+               if (_DialogConfirm == null) {
+                   _DialogConfirm= new DialogConfirm();
+               }
+               return _DialogConfirm;
+       }
+
+               // my vars (def)
+
+       // ctor
+       public DialogConfirm()
+       {
+               _this = this;
+               this.el = new Gtk.MessageDialog( null, Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Test" );
+
+               // my vars (dec)
+
+               // set gobject values
+               this.el.title = "Please Confirm ";
+               this.el.name = "DialogConfirm";
+               this.el.modal = true;
+               this.el.use_markup = true;
+
+               //listeners
+               this.el.close_request.connect( (event) => {
+                  this.el.response(Gtk.ResponseType.CANCEL);
+                   this.el.hide();
+                   return true;
+               
+               });
+       }
+
+       // user defined functions
+       public void showIt // caller needs to connect to the  response -  to get the result.
+         
+         (string title, string msg) {
+            //if (!this.el) { this.init(); } 
+            //this.success = success;
+            this.el.title = title;
+           this.el.text =  msg;
+           this.el.show();
+          
+          
+       }
+}
index 497c435..7c448bb 100644 (file)
@@ -111,6 +111,9 @@ public class JsRender.Node : GLib.Object {
        public Gee.ArrayList<int> node_lines; 
        public Gee.HashMap<int,Node> node_lines_map; // store of l:xxx or p:....
        
+       
+       public string node_pad = "";
+       
        private int _updated_count = 0;
        public int updated_count { 
                get {
index 008a1f4..eae9235 100644 (file)
@@ -46,6 +46,7 @@ public class JsRender.NodeToJs : Object {
                this.node = node;
                this.doubleStringProps = doubleStringProps;
                this.pad = pad;
+               this.node.node_pad = pad;
                
                //this.els = new Gee.ArrayList<string>(); 
                //this.ar_props = new Gee.HashMap<string,string>();
index ce1991e..76480ee 100644 (file)
@@ -60,6 +60,8 @@ public class JsRender.NodeToVala : Object {
                        this.inpad = string.nfill(depth > 0 ? 1 : 0, '\t');
                }
                this.pad = this.inpad + "\t";
+               
+               this.node.node_pad = this.inpad;
                this.ipad = this.inpad + "\t\t";
                this.cls = node.xvala_cls;
                this.xcls = node.xvala_xcls;
index 9c365af..06259d4 100644 (file)
@@ -197,14 +197,21 @@ namespace Palete {
                                var offset =  end.get_line_offset();
                                if (this.editor.prop != null) {
                                //      tried line -1 (does not work)
-                               
+                                       GLib.debug("node pad = '%s' %d", this.editor.node.node_pad, this.editor.node.node_pad.length);
+                                       
                                        line += this.editor.prop.start_line ; 
                                        // this is based on Gtk using tabs (hence 1/2 chars);
-                                       offset += this.editor.file.file_namespace == "" ? 1 : 2; 
+                                       offset += this.editor.node.node_pad.length;
+                                       // javascript listeners are indented 2 more spaces.
+                                       if (this.editor.prop.ptype == JsRender.NodePropType.LISTENER) {
+                                               offset += 2;
+                                       }
                                } 
                                
-                               this.file.getLanguageServer().document_change_real(this.file, this.editor.tempFileContents());                          
+                               this.file.getLanguageServer().document_change_force(this.file, this.editor.tempFileContents());                         
                                try {
+                                       GLib.debug("sending request to language server %s", this.file.getLanguageServer().get_type().name());
+                                       
                                        res = yield this.file.getLanguageServer().completion(this.file, line, offset, 1);
                                } catch (GLib.Error e) {
                                        GLib.debug("got error %s", e.message);
index 4edd521..c70eed9 100644 (file)
@@ -97,7 +97,7 @@ namespace Palete {
                        //GLib.debug("go        t error %d %s", (int)ex.get_line_number() , ex.get_message() );
                        
 
-                       var ret = new CompileError.new_jserror(file, "ERR", (int) ex.get_line_number(), ex.get_message());
+                       var ret = new CompileError.new_jserror(file, "ERR", (int) ex.get_line_number() -1 , ex.get_message());
                         
                        ar.append(ret);
                        
index 245e321..a2dee4c 100644 (file)
@@ -35,37 +35,10 @@ namespace Palete {
        public abstract class LanguageClient :   Jsonrpc.Server {
        
                public Project.Project project;
-               private GLib.SubprocessLauncher launcher = null;
-               private GLib.Subprocess? subprocess = null;
-               private IOStream? subprocess_stream = null;
-           public Jsonrpc.Client? jsonrpc_client = null;
                
-               Gee.ArrayList<JsRender.JsRender> open_files;
-               private JsRender.JsRender? _change_queue_file = null;
-               private string change_queue_file_source = "";
-               
-               JsRender.JsRender? change_queue_file {
-                       set {
-                               this.change_queue_file_source = value == null ? "" : value.toSource();
-                               this._change_queue_file = value;
-                       } 
-                       get {
-                               return this._change_queue_file;
-                       } 
-               }
+        
  
-               uint change_queue_id = 0;
-               int countdown = 0;
-               protected bool initialized = false;
-               bool sent_shutdown = false;
-               private bool _closed = false;
-               private bool closed {
-                       get { return this._closed ; } 
-                       set {
-                               GLib.debug("closed has been set? to %s" , value ? "TRUE" : "FALSE" );
-                               this._closed = value;
-                       }
-               }
+
        
                public signal void log(LanguageClientAction action, string message);
                
@@ -74,108 +47,13 @@ namespace Palete {
                {
                        // extend versions will proably call initialize to start and connect to server.
                        this.project = project;
-                       this.open_files = new   Gee.ArrayList<JsRender.JsRender>();
-                       this.change_queue_id = GLib.Timeout.add_seconds(1, () => {
-                               if (this.change_queue_file == null) {
-                                       return true;
-                               }
-                               this.countdown--;
-                               if (this.countdown < 0){
-                                       this.document_change_real(this.change_queue_file,  this.change_queue_file_source);
-                                       this.change_queue_file = null;
-                                          
-                               }
-                               return true;
-                       });
+
+                       
                
                }
                 
-               public bool initProcess(string process_path)
-               {
-                       this.onClose();
-                       this.log(LanguageClientAction.LAUNCH, process_path);
-                       GLib.debug("Launching %s", process_path);
-                       this.launcher = new GLib.SubprocessLauncher (SubprocessFlags.STDIN_PIPE | SubprocessFlags.STDOUT_PIPE);
-                       this.launcher.set_environ(GLib.Environ.get());
-                       try {
-
-                               
-                               this.subprocess = launcher.spawnv ({ process_path });
-                               
-                               this.subprocess.wait_async.begin( null, ( obj,res ) => {
-                                       try {
-                                               this.subprocess.wait_async.end(res);
-                                       } catch (GLib.Error e) {
-                                               this.log(LanguageClientAction.ERROR_START, e.message);
-                                               GLib.debug("subprocess startup error %s", e.message);           
-                                       }
-                                       this.log(LanguageClientAction.EXIT, "process ended");
-                                       GLib.debug("Subprocess ended %s", process_path);
-                                       this.onClose();
-
-                               });
-                               var input_stream = this.subprocess.get_stdout_pipe ();
-                               var output_stream = this.subprocess.get_stdin_pipe ();
-                               if (input_stream is GLib.UnixInputStream && output_stream is GLib.UnixOutputStream) {
-                                       // set nonblocking
-                                       if (!GLib.Unix.set_fd_nonblocking(((GLib.UnixInputStream)input_stream).fd, true)
-                                        || !GLib.Unix.set_fd_nonblocking (((GLib.UnixOutputStream)output_stream).fd, true)) 
-                                        {
-                                               GLib.debug("could not set pipes to nonblocking");
-                                               this.onClose();
-                                           return false;
-                                   }
-                           }
-                           this.subprocess_stream = new GLib.SimpleIOStream (input_stream, output_stream);
-                       this.accept_io_stream ( this.subprocess_stream);
-                       } catch (GLib.Error e) {
-                               this.log(LanguageClientAction.ERROR_START, e.message);
-                               GLib.debug("subprocess startup error %s", e.message);   
-                               this.onClose();
-                               return false;
-               }
-            return true;
-        }
-        bool in_close = false;
-               protected void onClose()
-               {
-                       if (this.in_close) {
-                               return;
-                       }
-                       if (this.launcher == null) {
-                               return;
-                       }
-                       this.in_close = true;
-                       GLib.debug("onClose called");
-                       
-                       if (this.jsonrpc_client != null) {
-                               try {
-                                       this.jsonrpc_client.close();
-                               } catch (GLib.Error e) {
-                                       GLib.debug("rpc Error close error %s", e.message);      
-                               }               
-                       }
-                       if (this.subprocess_stream != null) {
-                               try {
-                                       this.subprocess_stream.close();
-                               } catch (GLib.Error e) {
-                                       GLib.debug("stream Error close  %s", e.message);        
-                               }               
-                       }
-                       if (this.subprocess != null) {
-                               this.subprocess.force_exit();
-                       }
-                       if (this.launcher != null) {
-                               this.launcher.close();
-                       }
-                       
-                       this.launcher = null;
-                       this.subprocess = null;
-                       this.jsonrpc_client = null;
-                       this.closed = true;             
-                       this.in_close = false;
-               }
+               
+               
                /**
                utility method to build variant based queries
                */
@@ -193,411 +71,25 @@ namespace Palete {
                        return builder.end ();
                }
                 
-               public override void client_accepted (Jsonrpc.Client client) 
-               {
-                       if (this.jsonrpc_client == null) {
-                               this.jsonrpc_client = client;
-                               
-                               GLib.debug("client accepted connection - calling init server");
-                               this.log(LanguageClientAction.ACCEPT, "client accepted");
-
-                               this.jsonrpc_client.notification.connect((method, paramz) => {
-                                       this.onNotification(method, paramz);
-                               });
-                                
-                               this.jsonrpc_client.failed.connect(() => {
-                                       this.log(LanguageClientAction.ERROR_RPC, "client failed");
-                                       this.onClose();
-                                       
-                                       GLib.debug("language server server has failed");
-                               });
-
-                               this.initialize_server ();
-                       } 
-                                        
-                        
-               }
-               public bool isReady()
-               {
-                       if (this.closed) {
-                               this.log(LanguageClientAction.RESTART,"closed is set - restarting");
-                               GLib.debug("server stopped = restarting");
-                               this.initialized = false;
-                               this.closed = false;
-                               this.startServer();
-                               foreach(var f in this.open_files) {
-                                       this.document_open(f);
-                               }
-                               return false; // can't do an operation yet?
-                                
-                       }
-                       
-                       if (!this.initialized) {
-                               GLib.debug("Server has not been initialized");
-                               return false;
-                       }
-                       if (this.sent_shutdown) {
-                               GLib.debug("Server has been started its shutting down process");
-                               return false;
-                       }
-                       // restart server..
-
-                       
-                       
-                       return true;
-               }
-               
-               
-               public abstract  void initialize_server();
-               public abstract  void startServer();
-               //public abstract   void  initialize_server()  ;
-                
                
                
                
-               public void onNotification(string method, Variant? return_value)
-               {
-                       switch (method) {
-                               case "textDocument/publishDiagnostics":
-                                       this.onDiagnostic(return_value);
-                                       return;
-                               default: 
-                                       break;
-                                
-                       }
-                       GLib.debug("got notification %s : %s",  method , Json.to_string (Json.gvariant_serialize (return_value), true));
-                       
-               }
-               
-               /***
-               
-               */
-               public void onDiagnostic(Variant? return_value) 
-               {
-
-                       var dg = Json.gobject_deserialize (typeof (Lsp.Diagnostics), Json.gvariant_serialize (return_value)) as Lsp.Diagnostics; 
-                       this.log(LanguageClientAction.DIAG, dg.filename);
-                       var f = this.project.getByPath(dg.filename);
-                       if (f == null) {
-                               //GLib.debug("no file %s", dg.uri);
-                               this.project.updateErrorsforFile(null);
-                               return;
-                       }
-                       foreach(var v in f.errorsByType.values) {
-                               v.remove_all();
-                       }
-                       foreach(var diag in dg.diagnostics) {
-                               var ce = new CompileError.new_from_diagnostic(f, diag);
-                               if (!f.errorsByType.has_key(ce.category)) {
-                                       f.errorsByType.set(ce.category, new  GLib.ListStore(typeof(CompileError)));
-                               }
-                               f.errorsByType.get(ce.category).append(ce);
-                       }
-                       f.project.updateErrorsforFile(f);
-                       
-               }
-               
-               public void document_open (JsRender.JsRender file)  
-               {
-                       if (!this.isReady()) {
-                               return;
-                       }
-                       if (!this.open_files.contains(file)) {
-                               this.open_files.add(file);
-                       }
-                       
-                       GLib.debug ("LS sent open");                     
-                       try {
-                               this.jsonrpc_client.send_notification (
-                                       "textDocument/didOpen",
-                                       this.buildDict (
-                                               textDocument : this.buildDict (
-                                                       uri: new Variant.string (file.to_url()),
-                                                       languageId :  new Variant.string (file.language_id()),
-                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version),
-                                                       text : new Variant.string (file.toSource())
-                                               )
-                                       ),
-                                       null
-                               );
-                               this.log(LanguageClientAction.OPEN, file.path);
-                       } catch( GLib.Error  e) {
-                               this.log(LanguageClientAction.ERROR_RPC, e.message);
-                               this.onClose();
-                               GLib.debug ("LS sent open err %s", e.message);
-                       }
-
-               }
-               
-               public   void document_save (JsRender.JsRender file)  
-       {
-                       if (!this.isReady()) {
-                               return;
-                       }
-                       this.change_queue_file = null;
-                       GLib.debug ("LS send save");
-                        try {
-                                 this.jsonrpc_client.send_notification  (
-                                       "textDocument/didChange",
-                                       this.buildDict (  
-                                               textDocument : this.buildDict (    ///TextDocumentItem;
-                                                       uri: new GLib.Variant.string (file.to_url()),
-                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version)
-                                               )
-                                       ),
-                                       null 
-                               );
-                               this.log(LanguageClientAction.SAVE, file.path);
-                       } catch( GLib.Error  e) {
-                               this.log(LanguageClientAction.ERROR_RPC, e.message);
-                               GLib.debug ("LS   save err %s", e.message);
-                               this.onClose();
-                       }
-
-         
-       }
-               public   void document_close (JsRender.JsRender file) 
-       {
-                       if (!this.isReady()) {
-                               return;
-                       }
-                       this.change_queue_file = null;
-                       
-                       if (this.open_files.contains(file)) {
-                               this.open_files.remove(file);
-                       }
-                       this.log(LanguageClientAction.CLOSE, file.path);
-                       GLib.debug ("LS send close");
-                       try {
-                                 this.jsonrpc_client.send_notification  (
-                                       "textDocument/didChange",
-                                       this.buildDict (  
-                                               textDocument : this.buildDict (    ///TextDocumentItem;
-                                                       uri: new GLib.Variant.string (file.to_url())
-                                                       
-                                               )
-                                       ),
-                                       null  
-                               );
-                       } catch( GLib.Error  e) {
-                               this.log(LanguageClientAction.ERROR_RPC, e.message);
-                               GLib.debug ("LS close err %s", e.message);
-                               this.onClose();
-                       }
-
-         
-       }
-       
-        
-               public void document_change (JsRender.JsRender file   )    
-               {
-                       if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
-                               this.document_change_real(this.change_queue_file, this.change_queue_file_source);
-                       }
-                       
-                       this.countdown = 3;
-                       this.change_queue_file = file;
-                        
-                       
-
-               }
-       
-
-               public void document_change_real (JsRender.JsRender file, string contents)  
-       {
-                       if (!this.isReady()) {
-                               return;
-                       }
-                            
-                       
-                       GLib.debug ("LS send change");
-                       var ar = new Json.Array();
-                       var obj = new Json.Object();
-                       obj.set_string_member("text", contents);
-                       ar.add_object_element(obj);
-                       var node = new Json.Node(Json.NodeType.ARRAY);
-                       node.set_array(ar);
-                       this.log(LanguageClientAction.CHANGE, file.path);
-                        try {
-                               this.jsonrpc_client.send_notification (
-                                       "textDocument/didChange",
-                                       this.buildDict (  
-                                               textDocument : this.buildDict (    ///TextDocumentItem;
-                                                       uri: new GLib.Variant.string (file.to_url()),
-                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version) 
-                                               ),
-                                               contentChanges : Json.gvariant_deserialize (node, null)
-                                               
-                                       ),
-                                       null 
-                               );
-                       } catch( GLib.Error  e) {
-                               this.log(LanguageClientAction.ERROR_RPC, e.message);
-                               GLib.debug ("LS change err %s", e.message);
-                               this.onClose();
-                       }
-
-         
-       }
-       // called by close window (on last window)...
-               public   void exit () throws GLib.Error 
-               {
-                       if (!this.isReady()) {
-                       
-                               return;
-                       }
-                       this.log(LanguageClientAction.TERM, "SEND exit");
-                
-                         this.jsonrpc_client.send_notification (
-                               "exit",
-                               null,
-                               null 
-                       );
-                       this.onClose();
-
-               }
-               // not used currently..
-               public async void shutdown () throws GLib.Error 
-               {
-                       if (!this.isReady()) {
-                               return;
-                       }
-                       this.log(LanguageClientAction.TERM, "SEND shutodwn");
-                       this.sent_shutdown  = true;
-                       Variant? return_value;
-                       yield this.jsonrpc_client.call_async (
-                               "shutdown",
-                               null,
-                               null,
-                               out return_value
-                       );
-                       GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));               
-               }
-               //public async  ??/symbol (string symbol) throws GLib.Error {
                
-               // and now for the important styff..
+               public abstract  void initialize_server();
                
-               /*
+               public abstract void document_open (JsRender.JsRender file) ; 
+               public abstract void document_save (JsRender.JsRender file); 
+               public abstract void document_close (JsRender.JsRender file);
+               public abstract void document_change (JsRender.JsRender file );
+               public abstract void document_change_force (JsRender.JsRender file, string contents );
+               public abstract void exit () throws GLib.Error;
+               public abstract async void shutdown () throws GLib.Error;
+               public abstract async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error;
+               public abstract async Gee.ArrayList<Lsp.DocumentSymbol> syntax (JsRender.JsRender file) throws GLib.Error;
                
-               @triggerType 1 = typing or ctl-spac, 2 = tiggercharactres?  3= inside completion?
-               */
-                public async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
-                {
-                       /* partial_result_token ,  work_done_token   context = null) */
-                       GLib.debug("get completion %s @ %d:%d", file.relpath, line, offset);
-                       
-                       var ret = new Lsp.CompletionList();     
-                       
-                   if (!this.isReady()) {
-                       GLib.debug("completion - language server not ready");
-                               return ret;
-                       }
-                       // make sure completion has the latest info..
-                       //if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
-                       //      this.document_change_real(this.change_queue_file, this.change_queue_file_source);
-                       //      this.change_queue_file != null;
-                       //}
-                       this.log(LanguageClientAction.COMPLETE, "SEND complete  %s @ %d:%d".printf(file.relpath, line, offset) );
-                       
-                       Variant? return_value;
-                       
-                       var args = this.buildDict (  
-                                       context : this.buildDict (    ///CompletionContext;
-                                               triggerKind: new GLib.Variant.int32 (triggerType) 
-                                       //      triggerCharacter :  new GLib.Variant.string ("")
-                                       ),
-                                       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))) 
-                                       )
-                               );
-                        
-                       GLib.debug ("textDocument/completion send with %s", Json.to_string (Json.gvariant_serialize (args), true));                                     
-                       
-                       yield this.jsonrpc_client.call_async (
-                               "textDocument/completion",
-                               args,
-                               null,
-                               out return_value
-                       );
-                       
-                       
-                       //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) {
-                               ret = Json.gobject_deserialize (typeof (Lsp.CompletionList), json) as Lsp.CompletionList; 
-                               this.log(LanguageClientAction.COMPLETE_REPLY, "GOT complete  %d items".printf(ret.items.size) );
-                               GLib.debug ("LS replied with Object");
-                               return ret;
-                       }  
-
-                       if (json.get_node_type() != Json.NodeType.ARRAY) {
-                               GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
-                               this.log(LanguageClientAction.ERROR_REPLY, "GOT something else??");
-                               return ret;
-                       
-                       }
-                       var ar = json.get_array();                      
-                       
-                       for(var i = 0; i < ar.get_length(); i++ ) {
-                               var add= Json.gobject_deserialize ( typeof (Lsp.CompletionItem),  ar.get_element(i)) as Lsp.CompletionItem;
-                               ret.items.add( add);
-                                        
-                       }
-                       this.log(LanguageClientAction.COMPLETE_REPLY, "GOT array %d items".printf(ret.items.size) );
-                       GLib.debug ("LS replied with Array");
-                       return ret;
-               
-
-               }
-               //CompletionListInfo.itmems.parse_varient  or CompletionListInfo.parsevarient
-               public 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);
-                       var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
-                       //ret = null;
-                   if (!this.isReady()) {
-                               return ret;
-                       }
-                       Variant? return_value;
-                       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
-                       );
-                       
-                       
-                       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();
-                       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 ;
-                       
-               
-
-               }
                
        }
+       
 }
index d83ac1c..4d4a53d 100644 (file)
@@ -10,15 +10,24 @@ namespace Palete {
                        
                
                }
-                public override   void  initialize_server()   {
+               public override   void  initialize_server()   {
                        GLib.debug("initialize dummy server");                  
                }
-               public override void startServer()
-               {
-               }
-               public new bool isReady() 
-               {
-                       return false;
+               public override void document_open (JsRender.JsRender file)  {}
+               public override void document_save (JsRender.JsRender file)   {}
+               public override void document_change (JsRender.JsRender file    )     {}
+                       public override void document_change_force (JsRender.JsRender file, string contents    )     {}
+               public override void document_close (JsRender.JsRender file) {}
+               public override void exit () throws GLib.Error { }
+               public override async void shutdown () throws GLib.Error { }
+               public override async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error {
+                       var ret = new Lsp.CompletionList();     
+                       return ret;
+               }
+               
+               public override async Gee.ArrayList<Lsp.DocumentSymbol> syntax (JsRender.JsRender file) throws GLib.Error {
+                       var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
+                       return ret;
                }
        }
        
index 98f1d53..8f8b357 100644 (file)
@@ -2,66 +2,81 @@
 namespace Palete {
        public class LanguageClientJavascript : LanguageClient {
        
+               Gee.HashMap<string,string> file_contents;
        
                public LanguageClientJavascript(Project.Project project)
                {
                        // extend versions will proably call initialize to start and connect to server.
                        base(project);
-                       
+                       this.file_contents =  new Gee.HashMap<string,string>();
+                       GLib.debug(" START JAVASCRIPT LANG SERVER");
                
                }
                public override   void  initialize_server()   {
                        GLib.debug("initialize javascript server");                     
                }
-               public override void startServer()
-               {
-               }
+                
                 
                
                
-               
-               public new bool isReady() 
-               {
-                       return false;
-               }
-               public new void document_open (JsRender.JsRender file)  
+                
+               public override void document_open (JsRender.JsRender file)  
                {
-                       
+                       this.file_contents.set(file.path, file.toSourceCode());
                        Javascript.singleton().validate(file.toSourceCode(), file );
                        BuilderApplication.updateCompileResults();
                
                }
-               public new void document_save (JsRender.JsRender file)  
+               public override void document_save (JsRender.JsRender file)  
                {
+                       
+                       this.file_contents.set(file.path, file.toSourceCode());
+                       GLib.debug("set file %s : %d  chars", file.path, this.file_contents.get(file.path).length);
                        Javascript.singleton().validate(file.toSourceCode(), file );
                        BuilderApplication.updateCompileResults();
                }
-               public new void document_change (JsRender.JsRender file   )    
-               {
-                       Javascript.singleton().validate(file.toSourceCode(), file );
+               public override void document_change_force (JsRender.JsRender file, string contents )   {
+                       this.file_contents.set(file.path, contents);
+                       GLib.debug("set file %s : %d chars", file.path, this.file_contents.get(file.path).length);
+                       Javascript.singleton().validate(contents, file );
                        BuilderApplication.updateCompileResults();
                }
-               
-               public async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
+               public override void document_change (JsRender.JsRender file )    
+               {
+                       this.document_change_force( file, file.toSourceCode());
+               }
+               public override void document_close (JsRender.JsRender file) {}
+               public override void exit () throws GLib.Error { }
+               public override async void shutdown () throws GLib.Error { }
+               public override async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
                {
                
                        var ret = new Lsp.CompletionList();     
-                
-                       
-                       var ar = file.toSource().split("\n");
-                       var ln = line >= ar.length ? "" :  ar[line];
-                       if (ln.length >= offset) {
+                       if (this.file_contents.get(file.path) == null) {
+                               GLib.debug("got file %s : MISSING ", file.path);                                
                                return ret;
                        }
+                       //GLib.debug("got file %s : %s ", file.path, this.file_contents.get(file.path));
+                       
+                       var ar = this.file_contents.get(file.path).split("\n");
+                       var ln = line >= ar.length ? "" :  ar[line-1];
+                       if (offset-1 >= ln.length) {
+                               GLib.debug("request for complete on line %d  @ pos %d > line length %d", line, offset, (int) ln.length);
+                               return ret;
+                       } 
+                       GLib.debug("got Line %d:%d '%s' ", line, offset,  ln);
+                       
                        var start = -1;
-                       for (var i = offset; i > 0; i--) {
-                               GLib.debug("check char %c", ln[i]);
-                               if (ln[i].isalpha() || ln[i] == '.') {
+                       for (var i = offset - 1; i > 0; i--) {
+                               GLib.debug("check char %d '%c'", i, ln[i]); 
+                               if (ln[i].isalpha() || ln[i] == '.' || ln[i] == '_') { // any other allowed chars?
                                        start = i;
                                        continue;
                                }
                                break;
                        }
+                       
+                       
                        var complete_string = ln.substring(start, offset - start);
                        GLib.debug("complete string = %s", complete_string);
                        
@@ -109,15 +124,32 @@ namespace Palete {
                        var parts = complete_string.split(".");
                        var curtype = "";
                        var cur_instance = false;
+                       if (parts[0] == "_this") {
+                               if (file.tree == null) {
+
+                                       GLib.debug("file has no tree");
+                                       return ret; // no idea..
+                               }
+                               curtype = file.tree.fqn();
+                               cur_instance = true;                            
+                               // work out from the node, what the type is...
+                               // fetch node from element.
+
+                               //curtype = node.fqn();
+                               cur_instance = true;
+                       }
+                       
+                       
                        if (parts[0] == "this") {
                                // work out from the node, what the type is...
                                // fetch node from element.
-                               //if (node == null) {
-                                       GLib.debug("node is empty - no return\n");
+                               var node = file.lineToNode(line -1); // hopefuly
+                               if (node == null) {
+                                       GLib.debug("could nt find scope for 'this'");
                                        return ret; // no idea..
-                               //}
-                               //curtype = node.fqn();
-                               //cur_instance = true;
+                               }
+                               curtype = node.fqn();
+                               cur_instance = true;
                        }
                        if (parts[0] == "Roo") {        
                                curtype = "Roo";
@@ -132,7 +164,7 @@ namespace Palete {
                                // look up all the properties of the type...
                                var cls = this.project.palete.getClass(curtype);
                                if (cls == null) {
-                                       GLib.debug("could not get class of curtype %s\n", curtype);
+                                       GLib.debug("could not get class of curtype '%s'\n", curtype);
                                        return ret;
                                }
 
@@ -216,7 +248,7 @@ namespace Palete {
                                        // got a matching property...
                                        // return type?
                                        
-                                       var sci =  new Lsp.CompletionItem.keyword( prevbits + prop.name + "(", prop.name + "(" , prop.doctxt );
+                                       var sci =  new Lsp.CompletionItem.keyword( prop.name + "(", prop.name + "(" , prop.doctxt );
                                        ret.items.add(sci);
 
                                 
@@ -229,11 +261,11 @@ namespace Palete {
                                while (citer.next()) {
                                        var prop = citer.get_value();
                                        // does the name start with ...
-                                       if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
-                                               continue;
-                                       }
+                                       //if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
+                                       //      continue;
+                                       //}
                                        
-                                       var sci =  new Lsp.CompletionItem.keyword( prevbits +  prop.name + "(", prop.name + "(" , prop.doctxt );
+                                       var sci =  new Lsp.CompletionItem.keyword( prop.name, prop.name , prop.doctxt );
                                        ret.items.add(sci);
  
                                
@@ -256,6 +288,10 @@ namespace Palete {
                        return ret;
                
                }
+               public override async Gee.ArrayList<Lsp.DocumentSymbol> syntax (JsRender.JsRender file) throws GLib.Error {
+                       var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
+                       return ret;
+               }
                
        }
        
index 4860da2..f35f74f 100644 (file)
 
 namespace Palete {
        public class LanguageClientVala : LanguageClient {
-       
-       
+               int countdown = 0;
+               protected bool initialized = false;
+               bool sent_shutdown = false;
+               uint change_queue_id = 0;
+               
+                       
+               private bool _closed = false;
+               private bool closed {
+                       get { return this._closed ; } 
+                       set {
+                               GLib.debug("closed has been set? to %s" , value ? "TRUE" : "FALSE" );
+                               this._closed = value;
+                       }
+               }
+               private GLib.SubprocessLauncher launcher = null;
+               private GLib.Subprocess? subprocess = null;
+               private IOStream? subprocess_stream = null;
+           public Jsonrpc.Client? jsonrpc_client = null;
+               
+               Gee.ArrayList<JsRender.JsRender> open_files;
+               private JsRender.JsRender? _change_queue_file = null;
+               private string change_queue_file_source = "";
+               
+               JsRender.JsRender? change_queue_file {
+                       set {
+                               this.change_queue_file_source = value == null ? "" : value.toSource();
+                               this._change_queue_file = value;
+                       } 
+                       get {
+                               return this._change_queue_file;
+                       } 
+               }
+               void startServer()
+               {
+                       this.initProcess("/usr/bin/vala-language-server");
+               }
+               
+               
                public LanguageClientVala(Project.Project project)
                {
                        // extend versions will proably call initialize to start and connect to server.
                        base(project);
-                       
+                       this.open_files = new   Gee.ArrayList<JsRender.JsRender>();
+                       this.change_queue_id = GLib.Timeout.add_seconds(1, () => {
+                               if (this.change_queue_file == null) {
+                                       return true;
+                               }
+                               this.countdown--;
+                               if (this.countdown < 0){
+                                       this.document_change_force(this.change_queue_file,  this.change_queue_file_source);
+                                       this.change_queue_file = null;
+                                          
+                               }
+                               return true;
+                       });
                        this.startServer();
-                       
-               
+
                }
-               public override void startServer()
-               {
-                       this.initProcess("/usr/bin/vala-language-server");
                
+                
+               public bool initProcess(string process_path)
+               {
+                       this.onClose();
+                       this.log(LanguageClientAction.LAUNCH, process_path);
+                       GLib.debug("Launching %s", process_path);
+                       this.launcher = new GLib.SubprocessLauncher (SubprocessFlags.STDIN_PIPE | SubprocessFlags.STDOUT_PIPE);
+                       this.launcher.set_environ(GLib.Environ.get());
+                       try {
+
+                               
+                               this.subprocess = launcher.spawnv ({ process_path });
+                               
+                               this.subprocess.wait_async.begin( null, ( obj,res ) => {
+                                       try {
+                                               this.subprocess.wait_async.end(res);
+                                       } catch (GLib.Error e) {
+                                               this.log(LanguageClientAction.ERROR_START, e.message);
+                                               GLib.debug("subprocess startup error %s", e.message);           
+                                       }
+                                       this.log(LanguageClientAction.EXIT, "process ended");
+                                       GLib.debug("Subprocess ended %s", process_path);
+                                       this.onClose();
+
+                               });
+                               var input_stream = this.subprocess.get_stdout_pipe ();
+                               var output_stream = this.subprocess.get_stdin_pipe ();
+                               if (input_stream is GLib.UnixInputStream && output_stream is GLib.UnixOutputStream) {
+                                       // set nonblocking
+                                       if (!GLib.Unix.set_fd_nonblocking(((GLib.UnixInputStream)input_stream).fd, true)
+                                        || !GLib.Unix.set_fd_nonblocking (((GLib.UnixOutputStream)output_stream).fd, true)) 
+                                        {
+                                               GLib.debug("could not set pipes to nonblocking");
+                                               this.onClose();
+                                           return false;
+                                   }
+                           }
+                           this.subprocess_stream = new GLib.SimpleIOStream (input_stream, output_stream);
+                       this.accept_io_stream ( this.subprocess_stream);
+                       } catch (GLib.Error e) {
+                               this.log(LanguageClientAction.ERROR_START, e.message);
+                               GLib.debug("subprocess startup error %s", e.message);   
+                               this.onClose();
+                               return false;
+               }
+            return true;
+        }
+        bool in_close = false;
+               public override void client_accepted (Jsonrpc.Client client) 
+               {
+                       if (this.jsonrpc_client == null) {
+                               this.jsonrpc_client = client;
+                               
+                               GLib.debug("client accepted connection - calling init server");
+                               this.log(LanguageClientAction.ACCEPT, "client accepted");
+
+                               this.jsonrpc_client.notification.connect((method, paramz) => {
+                                       this.onNotification(method, paramz);
+                               });
+                                
+                               this.jsonrpc_client.failed.connect(() => {
+                                       this.log(LanguageClientAction.ERROR_RPC, "client failed");
+                                       this.onClose();
+                                       
+                                       GLib.debug("language server server has failed");
+                               });
+
+                               this.initialize_server ();
+                       } 
+                                        
+                        
                }
                
-                public override   void  initialize_server()   {
+               
+               public override   void  initialize_server()   {
                        try {
                                Variant? return_value;
                                    this.jsonrpc_client.call (
@@ -40,7 +157,420 @@ namespace Palete {
                        }
                        
                }
+               void onClose()
+               {
+                       if (this.in_close) {
+                               return;
+                       }
+                       if (this.launcher == null) {
+                               return;
+                       }
+                       this.in_close = true;
+                       GLib.debug("onClose called");
+                       
+                       if (this.jsonrpc_client != null) {
+                               try {
+                                       this.jsonrpc_client.close();
+                               } catch (GLib.Error e) {
+                                       GLib.debug("rpc Error close error %s", e.message);      
+                               }               
+                       }
+                       if (this.subprocess_stream != null) {
+                               try {
+                                       this.subprocess_stream.close();
+                               } catch (GLib.Error e) {
+                                       GLib.debug("stream Error close  %s", e.message);        
+                               }               
+                       }
+                       if (this.subprocess != null) {
+                               this.subprocess.force_exit();
+                       }
+                       if (this.launcher != null) {
+                               this.launcher.close();
+                       }
+                       
+                       this.launcher = null;
+                       this.subprocess = null;
+                       this.jsonrpc_client = null;
+                       this.closed = true;             
+                       this.in_close = false;
+               }
+       
+       
+               public bool isReady()
+               {
+                       if (this.closed) {
+                               this.log(LanguageClientAction.RESTART,"closed is set - restarting");
+                               GLib.debug("server stopped = restarting");
+                               this.initialized = false;
+                               this.closed = false;
+                               this.startServer();
+                               foreach(var f in this.open_files) {
+                                       this.document_open(f);
+                               }
+                               return false; // can't do an operation yet?
+                                
+                       }
+                       
+                       if (!this.initialized) {
+                               GLib.debug("Server has not been initialized");
+                               return false;
+                       }
+                       if (this.sent_shutdown) {
+                               GLib.debug("Server has been started its shutting down process");
+                               return false;
+                       }
+                       // restart server..
+
+                       
+                       
+                       return true;
+               }
        
+               public void onNotification(string method, Variant? return_value)
+               {
+                       switch (method) {
+                               case "textDocument/publishDiagnostics":
+                                       this.onDiagnostic(return_value);
+                                       return;
+                               default: 
+                                       break;
+                                
+                       }
+                       GLib.debug("got notification %s : %s",  method , Json.to_string (Json.gvariant_serialize (return_value), true));
+                       
+               }
+               
+               /***
+               
+               */
+               public void onDiagnostic(Variant? return_value) 
+               {
+
+                       var dg = Json.gobject_deserialize (typeof (Lsp.Diagnostics), Json.gvariant_serialize (return_value)) as Lsp.Diagnostics; 
+                       this.log(LanguageClientAction.DIAG, dg.filename);
+                       var f = this.project.getByPath(dg.filename);
+                       if (f == null) {
+                               //GLib.debug("no file %s", dg.uri);
+                               this.project.updateErrorsforFile(null);
+                               return;
+                       }
+                       foreach(var v in f.errorsByType.values) {
+                               v.remove_all();
+                       }
+                       foreach(var diag in dg.diagnostics) {
+                               var ce = new CompileError.new_from_diagnostic(f, diag);
+                               if (!f.errorsByType.has_key(ce.category)) {
+                                       f.errorsByType.set(ce.category, new  GLib.ListStore(typeof(CompileError)));
+                               }
+                               f.errorsByType.get(ce.category).append(ce);
+                       }
+                       f.project.updateErrorsforFile(f);
+                       
+               }
+               
+               public override void document_open (JsRender.JsRender file)  
+               {
+                       if (!this.isReady()) {
+                               return;
+                       }
+                       if (!this.open_files.contains(file)) {
+                               this.open_files.add(file);
+                       }
+                       
+                       GLib.debug ("LS sent open");                     
+                       try {
+                               this.jsonrpc_client.send_notification (
+                                       "textDocument/didOpen",
+                                       this.buildDict (
+                                               textDocument : this.buildDict (
+                                                       uri: new Variant.string (file.to_url()),
+                                                       languageId :  new Variant.string (file.language_id()),
+                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version),
+                                                       text : new Variant.string (file.toSource())
+                                               )
+                                       ),
+                                       null
+                               );
+                               this.log(LanguageClientAction.OPEN, file.path);
+                       } catch( GLib.Error  e) {
+                               this.log(LanguageClientAction.ERROR_RPC, e.message);
+                               this.onClose();
+                               GLib.debug ("LS sent open err %s", e.message);
+                       }
+
+               }
+               
+               public override  void document_save (JsRender.JsRender file)  
+       {
+                       if (!this.isReady()) {
+                               return;
+                       }
+                       this.change_queue_file = null;
+                       GLib.debug ("LS send save");
+                        try {
+                                 this.jsonrpc_client.send_notification  (
+                                       "textDocument/didChange",
+                                       this.buildDict (  
+                                               textDocument : this.buildDict (    ///TextDocumentItem;
+                                                       uri: new GLib.Variant.string (file.to_url()),
+                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version)
+                                               )
+                                       ),
+                                       null 
+                               );
+                               this.log(LanguageClientAction.SAVE, file.path);
+                       } catch( GLib.Error  e) {
+                               this.log(LanguageClientAction.ERROR_RPC, e.message);
+                               GLib.debug ("LS   save err %s", e.message);
+                               this.onClose();
+                       }
+
+         
+       }
+               public override  void document_close (JsRender.JsRender file) 
+       {
+                       if (!this.isReady()) {
+                               return;
+                       }
+                       this.change_queue_file = null;
+                       
+                       if (this.open_files.contains(file)) {
+                               this.open_files.remove(file);
+                       }
+                       this.log(LanguageClientAction.CLOSE, file.path);
+                       GLib.debug ("LS send close");
+                       try {
+                                 this.jsonrpc_client.send_notification  (
+                                       "textDocument/didChange",
+                                       this.buildDict (  
+                                               textDocument : this.buildDict (    ///TextDocumentItem;
+                                                       uri: new GLib.Variant.string (file.to_url())
+                                                       
+                                               )
+                                       ),
+                                       null  
+                               );
+                       } catch( GLib.Error  e) {
+                               this.log(LanguageClientAction.ERROR_RPC, e.message);
+                               GLib.debug ("LS close err %s", e.message);
+                               this.onClose();
+                       }
+
+         
+       }
+       
+        
+               public override void document_change (JsRender.JsRender file )    
+               {
+                       if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
+                               this.document_change_force(this.change_queue_file, this.change_queue_file_source);
+                       }
+                       
+                       this.countdown = 3;
+                       this.change_queue_file = file;
+                        
+                       
+
+               }
+       
+
+               public override void document_change_force (JsRender.JsRender file, string contents)  
+       {
+                       if (!this.isReady()) {
+                               return;
+                       }
+                            
+                       
+                       GLib.debug ("LS send change");
+                       var ar = new Json.Array();
+                       var obj = new Json.Object();
+                       obj.set_string_member("text", contents);
+                       ar.add_object_element(obj);
+                       var node = new Json.Node(Json.NodeType.ARRAY);
+                       node.set_array(ar);
+                       this.log(LanguageClientAction.CHANGE, file.path);
+                        try {
+                               this.jsonrpc_client.send_notification (
+                                       "textDocument/didChange",
+                                       this.buildDict (  
+                                               textDocument : this.buildDict (    ///TextDocumentItem;
+                                                       uri: new GLib.Variant.string (file.to_url()),
+                                                       version :  new GLib.Variant.uint64 ( (uint64) file.version) 
+                                               ),
+                                               contentChanges : Json.gvariant_deserialize (node, null)
+                                               
+                                       ),
+                                       null 
+                               );
+                       } catch( GLib.Error  e) {
+                               this.log(LanguageClientAction.ERROR_RPC, e.message);
+                               GLib.debug ("LS change err %s", e.message);
+                               this.onClose();
+                       }
+
+         
+       }
+       // called by close window (on last window)...
+               public override  void exit () throws GLib.Error 
+               {
+                       if (!this.isReady()) {
+                       
+                               return;
+                       }
+                       this.log(LanguageClientAction.TERM, "SEND exit");
+                
+                         this.jsonrpc_client.send_notification (
+                               "exit",
+                               null,
+                               null 
+                       );
+                       this.onClose();
+
+               }
+               // not used currently..
+               public override async void shutdown () throws GLib.Error 
+               {
+                       if (!this.isReady()) {
+                               return;
+                       }
+                       this.log(LanguageClientAction.TERM, "SEND shutodwn");
+                       this.sent_shutdown  = true;
+                       Variant? return_value;
+                       yield this.jsonrpc_client.call_async (
+                               "shutdown",
+                               null,
+                               null,
+                               out return_value
+                       );
+                       GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));               
+               }
+               //public async  ??/symbol (string symbol) throws GLib.Error {
+               
+               // and now for the important styff..
+               
+               /*
+               
+               @triggerType 1 = typing or ctl-spac, 2 = tiggercharactres?  3= inside completion?
+               */
+                public override async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
+                {
+                       /* partial_result_token ,  work_done_token   context = null) */
+                       GLib.debug("%s get completion %s @ %d:%d", this.get_type().name(),  file.relpath, line, offset);
+                       
+                       var ret = new Lsp.CompletionList();     
+                       
+                   if (!this.isReady()) {
+                       GLib.debug("completion - language server not ready");
+                               return ret;
+                       }
+                       // make sure completion has the latest info..
+                       //if (this.change_queue_file != null && this.change_queue_file.path != file.path) {
+                       //      this.document_change_real(this.change_queue_file, this.change_queue_file_source);
+                       //      this.change_queue_file != null;
+                       //}
+                       this.log(LanguageClientAction.COMPLETE, "SEND complete  %s @ %d:%d".printf(file.relpath, line, offset) );
+                       
+                       Variant? return_value;
+                       
+                       var args = this.buildDict (  
+                                       context : this.buildDict (    ///CompletionContext;
+                                               triggerKind: new GLib.Variant.int32 (triggerType) 
+                                       //      triggerCharacter :  new GLib.Variant.string ("")
+                                       ),
+                                       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))) 
+                                       )
+                               );
+                        
+                       GLib.debug ("textDocument/completion send with %s", Json.to_string (Json.gvariant_serialize (args), true));                                     
+                       
+                       yield this.jsonrpc_client.call_async (
+                               "textDocument/completion",
+                               args,
+                               null,
+                               out return_value
+                       );
+                       
+                       
+                       //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) {
+                               ret = Json.gobject_deserialize (typeof (Lsp.CompletionList), json) as Lsp.CompletionList; 
+                               this.log(LanguageClientAction.COMPLETE_REPLY, "GOT complete  %d items".printf(ret.items.size) );
+                               GLib.debug ("LS replied with Object");
+                               return ret;
+                       }  
+
+                       if (json.get_node_type() != Json.NodeType.ARRAY) {
+                               GLib.debug ("LS replied with %s", Json.to_string (Json.gvariant_serialize (return_value), true));                                       
+                               this.log(LanguageClientAction.ERROR_REPLY, "GOT something else??");
+                               return ret;
+                       
+                       }
+                       var ar = json.get_array();                      
+                       
+                       for(var i = 0; i < ar.get_length(); i++ ) {
+                               var add= Json.gobject_deserialize ( typeof (Lsp.CompletionItem),  ar.get_element(i)) as Lsp.CompletionItem;
+                               ret.items.add( add);
+                                        
+                       }
+                       this.log(LanguageClientAction.COMPLETE_REPLY, "GOT array %d items".printf(ret.items.size) );
+                       GLib.debug ("LS replied with Array");
+                       return ret;
+               
+
+               }
+               //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);
+                       var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
+                       //ret = null;
+                   if (!this.isReady()) {
+                               return ret;
+                       }
+                       Variant? return_value;
+                       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
+                       );
+                       
+                       
+                       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();
+                       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 ;
+                       
+               
+
+               }
+               
        }
        
 }
\ No newline at end of file
index 2cae18f..8863586 100644 (file)
@@ -88,20 +88,24 @@ public class Project.Roo : Project {
 
        public override Palete.LanguageClient getLanguageServer(string lang)
        {
-                 switch(lang) {
-                               case "javascript":
-                                       var ls = new Palete.LanguageClientJavascript(this);
-                                       ls.log.connect((act, msg) => {
-                                               //GLib.debug("log %s: %s", act.to_string(), msg);
-                                               BuilderApplication.showSpinnerLspLog(act,msg);
-                                       });
-                                       this.language_servers.set(lang, ls);
-                                       break;
-                                       
-                               default:
-                                       return this.language_servers.get("dummy");
-                 }
-                 return this.language_servers.get(lang);
+               if (this.language_servers.has_key(lang)) {
+                       return this.language_servers.get(lang);
+               }
+                 
+               switch(lang) {
+                       case "javascript":
+                               var ls = new Palete.LanguageClientJavascript(this);
+                               ls.log.connect((act, msg) => {
+                                       //GLib.debug("log %s: %s", act.to_string(), msg);
+                                       BuilderApplication.showSpinnerLspLog(act,msg);
+                               });
+                               this.language_servers.set(lang, ls);
+                               break;
+                               
+                       default:
+                               return this.language_servers.get("dummy");
+               }
+               return this.language_servers.get(lang);
        }
 
 }