Commit e0ce8bdd authored by Christian Hergert's avatar Christian Hergert
Browse files

vala-pack: remove legacy vala code

This needs to be provided by GVls now, and we are going to aggressively
remove Vala code from Builder.
parent 0efdb2a2
/* ide-vala-indenter.vala
*
* Copyright 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using GLib;
using Ide;
namespace Ide
{
public class ValaClient : Ide.Object {
public static unowned Ide.ValaClient from_context (Ide.Context context) {
context.lock ();
var client = (Ide.ValaClient)context.ensure_child_typed (typeof (ValaClient));
if (client == null) {
client = new Ide.ValaClient ();
context.append (client);
}
context.unlock ();
unowned Ide.ValaClient self = client;
return self;
}
public unowned string get_name () {
return typeof (Ide.ValaClient).name ();
}
private enum State {
INITIAL,
SPAWNING,
RUNNING,
SHUTDOWN
}
GLib.Queue<GetContextCB> get_client;
Ide.SubprocessSupervisor supervisor;
Jsonrpc.Client rpc_client;
GLib.File root_uri;
//GLib.HashTable<GLib.File, int64?> seq_by_file = null;
State state = State.INITIAL;
~ValaClient () {
state = State.SHUTDOWN;
if (supervisor != null) {
var _supervisor = supervisor;
supervisor = null;
_supervisor.stop ();
}
}
[Compact]
public class GetContextCB {
public SourceFunc source_func;
}
public override void parent_set (Ide.Object? parent) {
if (parent == null)
return;
get_client = new GLib.Queue<GetContextCB> ();
unowned Ide.Context? context = get_context ();
root_uri = context.ref_workdir ();
var launcher = new Ide.SubprocessLauncher (GLib.SubprocessFlags.STDOUT_PIPE | GLib.SubprocessFlags.STDIN_PIPE);
if (root_uri.is_native ())
launcher.cwd = root_uri.get_path ();
launcher.clean_env = false;
launcher.push_argv (ValaConfig.PACKAGE_LIBEXECDIR + "/gnome-builder-vala");
supervisor = new Ide.SubprocessSupervisor ();
supervisor.set_launcher (launcher);
supervisor.spawned.connect (subprocess_spawned);
supervisor.exited.connect (subprocess_exited);
unowned Ide.BufferManager buffer_manager = Ide.BufferManager.from_context (context);
buffer_manager.buffer_saved.connect (buffer_saved);
}
public void subprocess_exited (Ide.Subprocess object) {
if (state == State.RUNNING)
state = State.SPAWNING;
rpc_client = null;
}
public void subprocess_spawned (Ide.Subprocess subprocess) {
if (state == State.SPAWNING)
state = State.RUNNING;
unowned GLib.UnixInputStream input = subprocess.get_stdout_pipe () as GLib.UnixInputStream;
unowned GLib.UnixOutputStream output = subprocess.get_stdin_pipe () as GLib.UnixOutputStream;
var stream = new GLib.SimpleIOStream (input, output);
try {
GLib.Unix.set_fd_nonblocking (input.get_fd (), true);
} catch (Error e) {}
try {
GLib.Unix.set_fd_nonblocking (output.get_fd (), true);
} catch (Error e) {}
rpc_client = new Jsonrpc.Client (stream);
rpc_client.set_use_gvariant (true);
var @params = Jsonrpc.Message.@new (
"rootUri", Jsonrpc.Message.PutString.create (root_uri.get_uri ()),
"rootPath", Jsonrpc.Message.PutString.create (root_uri.get_path ()),
"processId", Jsonrpc.Message.PutInt64.create (Posix.getpid ()),
"capabilities", "{", "}"
);
rpc_client.call_async.begin ("initialize", params, null);
GetContextCB cb = null;
lock (get_client) {
while ((cb = get_client.pop_head ()) != null) {
cb.source_func ();
}
}
}
public void buffer_saved (Ide.Buffer buffer) {
/*
* We need to clear the cached buffer on the peer (and potentially
* pop the translation unit cache) now that the buffer has been
* saved to disk and we no longer need the draft.
*/
var gfile = buffer.file;
/*lock (seq_by_file) {
if (seq_by_file != null) {
seq_by_file.remove (gfile);
}
}*/
/* skip if thereis no peer */
if (rpc_client == null)
return;
if (gfile != null)
set_buffer_async.begin (gfile);
}
public async GLib.Variant? call_async (string method,
GLib.Variant @params,
GLib.Cancellable? cancellable)
throws GLib.Error
{
try {
var client = yield get_client_async (cancellable);
GLib.Variant reply;
yield client.call_async (method, params, cancellable, out reply);
return reply;
} catch (Error e) {
throw e;
}
}
public async GLib.Variant index_file_async (GLib.File file,
string[]? flags = null,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files can be indexed");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"flags", Jsonrpc.Message.PutStrv.create (flags)
);
try {
return yield call_async ("vala/indexFile",
params,
cancellable);
} catch (Error e) {
throw e;
}
}
public async string get_index_key_async (GLib.File file,
string[]? flags = null,
uint line,
uint column,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"flags", Jsonrpc.Message.PutStrv.create (flags),
"line", Jsonrpc.Message.PutInt64.create (line),
"column", Jsonrpc.Message.PutInt64.create (column)
);
try {
var reply = yield call_async ("vala/getIndexKey",
params,
cancellable);
if (!reply.is_of_type (GLib.VariantType.STRING)) {
throw new GLib.IOError.INVALID_DATA ("Got a result back that was not a string");
}
return reply.dup_string ();
} catch (Error e) {
throw e;
}
}
public async Ide.SymbolTree get_symbol_tree_async (GLib.File file,
string[]? flags = null,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"flags", Jsonrpc.Message.PutStrv.create (flags)
);
try {
var reply = yield call_async ("vala/getSymbolTree",
params,
cancellable);
return new ValaSymbolTree (file, reply);
} catch (Error e) {
throw e;
}
}
public async Ide.Symbol? locate_symbol_async (GLib.File file,
string[]? flags = null,
uint line,
uint column,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"flags", Jsonrpc.Message.PutStrv.create (flags),
"line", Jsonrpc.Message.PutInt64.create (line),
"column", Jsonrpc.Message.PutInt64.create (column)
);
try {
var reply = yield call_async ("vala/locateSymbol",
params,
cancellable);
return new Ide.Symbol.from_variant (reply);
} catch (Error e) {
throw e;
}
}
public async Ide.Symbol? find_nearest_scope_async (GLib.File file,
string[]? flags = null,
uint line,
uint column,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"flags", Jsonrpc.Message.PutStrv.create (flags),
"line", Jsonrpc.Message.PutInt64.create (line),
"column", Jsonrpc.Message.PutInt64.create (column)
);
try {
var reply = yield call_async ("vala/findNearestScope",
params,
cancellable);
return new Ide.Symbol.from_variant (reply);
} catch (Error e) {
throw e;
}
}
public async Ide.Symbol? proposals_populate_async (GLib.File file,
uint line,
uint column,
string? line_text,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"line", Jsonrpc.Message.PutInt64.create (line),
"column", Jsonrpc.Message.PutInt64.create (column),
"line_text", Jsonrpc.Message.PutString.create (line_text)
);
try {
var reply = yield call_async ("vala/complete",
params,
cancellable);
if (reply != null) {
return new Ide.Symbol.from_variant (reply);
}
return null;
} catch (Error e) {
throw e;
}
}
private async Jsonrpc.Client get_client_async (GLib.Cancellable? cancellable) throws GLib.Error {
switch (state) {
default:
state = State.SPAWNING;
var cb = new GetContextCB ();
cb.source_func = get_client_async.callback;
lock (get_client) {
get_client.push_tail ((owned) cb);
}
supervisor.start ();
yield;
return rpc_client;
case State.SPAWNING:
var cb = new GetContextCB ();
cb.source_func = get_client_async.callback;
lock (get_client) {
get_client.push_tail ((owned) cb);
}
yield;
return rpc_client;
case State.RUNNING:
return rpc_client;
case State.SHUTDOWN:
throw new GLib.IOError.CLOSED ("The client has been closed");
}
}
private void sync_buffers () {
unowned Ide.Context context = get_context ();
unowned Ide.UnsavedFiles unsaved_files_object = Ide.UnsavedFiles.from_context (context);
var unsaved_files = unsaved_files_object.to_array ();
//lock (seq_by_file) {
/*if (seq_by_file == null)
seq_by_file = new GLib.HashTable<GLib.File, int64?> (GLib.File.hash, GLib.File.equal);*/
/*
* We need to sync buffers to the subprocess, but only those that are of any
* consequence to us. So that means Vala files.
*
* Further more, to avoid the chatter, we only want to send updated buffers
* for unsaved files which we have not already sent or we'll be way too
* chatty and cancel any cached translation units the subprocess has.
*
* Since the subprocess processes commands in order, we can simply call the
* function to set the buffer on the peer and ignore the result (and it will
* be used on subsequence commands).
*/
unsaved_files.foreach ((unsaved_file) => {
unowned GLib.File file = unsaved_file.get_file ();
string? name = file.get_basename ();
if (name == null || !(name.has_suffix (".vala") ||
name.has_suffix (".vapi")))
return;
set_buffer_async.begin (file, unsaved_file.get_content ());
});
//}
}
public async bool set_buffer_async (GLib.File file, GLib.Bytes? bytes = null, GLib.Cancellable? cancellable = null) throws GLib.Error {
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("File must be a local file");
var dict = new VariantDict ();
dict.insert ("path", "s", file.get_path ());
/* data doesn't need to be utf-8, but it does have to be
* a valid byte string (no embedded \0 bytes).
*/
if (bytes != null && bytes.get_data () != null) {
dict.insert ("contents", "^ay", bytes.get_data ());
}
try {
yield call_async ("vala/setBuffer", dict.end (), cancellable);
} catch (Error e) {
throw e;
}
return true;
}
public async Ide.Diagnostics diagnose_async (GLib.File file,
string[]? flags = null,
GLib.Cancellable? cancellable = null)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
sync_buffers ();
var params = Jsonrpc.Message.@new (
"path", Jsonrpc.Message.PutString.create (file.get_path ()),
"flags", Jsonrpc.Message.PutStrv.create (flags)
);
try {
var reply = yield call_async ("vala/diagnose",
params,
cancellable);
var iter = reply.iterator ();
GLib.Variant variant;
var ret = new Ide.Diagnostics ();
while ((variant = iter.next_value ()) != null) {
var diag = new Ide.Diagnostic.from_variant (variant);
if (diag != null) {
ret.take (diag);
}
}
return ret;
} catch (Error e) {
throw e;
}
}
}
}
/* ide-vala-indenter.vala
*
* Copyright 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using GLib;
using Ide;
namespace Ide
{
public class ValaCodeIndexer : Ide.Object, Ide.CodeIndexer
{
public async Ide.CodeIndexEntries index_file_async (GLib.File file,
[CCode (array_length = false, array_null_terminated = true)] string[]? build_flags,
GLib.Cancellable? cancellable)
throws GLib.Error
{
if (!file.is_native ())
throw new GLib.IOError.NOT_SUPPORTED ("Only native files are supported");
unowned Ide.Context? context = this.get_context ();
unowned Ide.ValaClient client = Ide.ValaClient.from_context (context);
try {
var entries = yield client.index_file_async (file, build_flags, cancellable);
return new ValaCodeIndexEntries (file, entries);
} catch (Error e) {
throw e;
}
}
public async string generate_key_async (Ide.Location location,
string[]? build_flags,
GLib.Cancellable? cancellable)
throws GLib.Error
{
unowned Ide.Context context = this.get_context ();
unowned Ide.ValaClient client = Ide.ValaClient.from_context (context);
var line = location.line + 1;
var column = location.line_offset + 1;
try {
return yield client.get_index_key_async (location.file, build_flags, line, column, cancellable);
} catch (Error e) {
throw e;
}
}
}
public class ValaCodeIndexEntries : GLib.Object, Ide.CodeIndexEntries
{
GLib.GenericArray<Ide.CodeIndexEntry> entries;
GLib.File file;
uint pos;
public GLib.File get_file ()
{
return this.file;
}
public ValaCodeIndexEntries (GLib.File file, GLib.Variant ventries)
{
entries = new GLib.GenericArray<Ide.CodeIndexEntry> ();
this.file = file;
var iter = ventries.iterator ();
Ide.SymbolFlags flags;
Ide.SymbolKind kind;
string key;
string name;
uint begin_line;
uint begin_line_offset;
uint end_line;
uint end_line_offset;
while (iter.next ("(usisuuuu)",
out flags,
out key,
out kind,
out name,
out begin_line,
out begin_line_offset,
out end_line,
out end_line_offset)) {
var entry_builder = new Ide.CodeIndexEntryBuilder ();
entry_builder.set_flags (flags);
entry_builder.set_key (key);
entry_builder.set_kind (kind);
entry_builder.set_name (name);
entry_builder.set_range (begin_line, begin_line_offset, end_line, end_line_offset);
entries.add (entry_builder.build ());
}
}
public Ide.CodeIndexEntry? get_next_entry ()
{
if (this.pos < entries.length)
return this.entries [this.pos++];
return null;
}
public async GLib.GenericArray<Ide.CodeIndexEntry> next_entries_async (GLib.Cancellable? cancellable)
throws GLib.Error
{
var ret = new GLib.GenericArray<Ide.CodeIndexEntry> ();
for (;;)
{
Ide.CodeIndexEntry entry = get_next_entry ();
if (entry == null)
break;
ret.add (entry);
}
return ret;
}
}
}
/* ide-vala-completion-item.vala
*
* Copyright 2015 Christian Hergert <christian@hergert.me>
*