}
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..
" this.el.response(Gtk.ResponseType.CANCEL);",
" this.el.hide();",
" return true;",
- " ",
+ "",
"}",
""
]
- 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();
+
+
+ }
+}
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 {
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>();
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;
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);
//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);
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);
{
// 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
*/
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 ;
-
-
-
- }
}
+
}
}
- 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;
}
}
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);
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";
// 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;
}
// 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);
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);
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;
+ }
}
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 (
}
}
+ 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
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);
}
}