feat: WIP start work on goto_definition LSP command
This commit is contained in:
parent
eb94bf5258
commit
2e8fd58ba5
5 changed files with 121 additions and 82 deletions
|
@ -52,7 +52,7 @@ const Process = struct {
|
|||
.recv_buf = std.ArrayList(u8).init(a),
|
||||
.parent = tp.self_pid().clone(),
|
||||
.tag = try a.dupeZ(u8, tag),
|
||||
.logger = log.logger(@typeName(Self)),
|
||||
.logger = log.logger(module_name),
|
||||
};
|
||||
return tp.spawn_link(self.a, self, Process.start, tag) catch |e| tp.exit_error(e);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ const Process = struct {
|
|||
|
||||
fn start(self: *Process) tp.result {
|
||||
_ = tp.set_trap(true);
|
||||
self.sp = tp.subprocess.init(self.a, self.cmd, sp_tag, self.stdin_behavior) catch |e| return tp.exit_error(e);
|
||||
self.sp = tp.subprocess.init(self.a, self.cmd, sp_tag, .Pipe) catch |e| return tp.exit_error(e);
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
||||
|
@ -101,30 +101,20 @@ const Process = struct {
|
|||
|
||||
fn handle_output(self: *Process, bytes: []u8) !void {
|
||||
try self.recv_buf.appendSlice(bytes);
|
||||
@import("log").logger(module_name).print("{s}", .{bytes}) catch {};
|
||||
self.logger.print("{s}", .{bytes});
|
||||
const message = try self.frame_message() orelse return;
|
||||
_ = message;
|
||||
}
|
||||
|
||||
fn handle_terminated(self: *Process) !void {
|
||||
const recv_buf = try self.recv_buf.toOwnedSlice();
|
||||
var it = std.mem.splitScalar(u8, recv_buf, '\n');
|
||||
while (it.next()) |json| {
|
||||
if (json.len == 0) continue;
|
||||
var msg_buf: [tp.max_message_size]u8 = undefined;
|
||||
const msg: tp.message = .{ .buf = try cbor.fromJson(json, &msg_buf) };
|
||||
try self.dispatch(msg);
|
||||
// var buf: [tp.max_message_size]u8 = undefined;
|
||||
// @import("log").logger(module_name).print("json: {s}", .{try msg.to_json(&buf)}) catch {};
|
||||
}
|
||||
@import("log").logger(module_name).print("done", .{}) catch {};
|
||||
self.logger.print("done", .{});
|
||||
try self.parent.send(.{ self.tag, "done" });
|
||||
}
|
||||
|
||||
fn frame_message(self: *Self) !?Message {
|
||||
const end = std.mem.indexOf(u8, self.recv_buf, "\r\n\r\n") orelse return null;
|
||||
const headers = try Headers.parse(self.recv_buf[0..end]);
|
||||
const body = self.recv_buf[end + 2 ..];
|
||||
fn frame_message(self: *Process) !?Message {
|
||||
const end = std.mem.indexOf(u8, self.recv_buf.items, "\r\n\r\n") orelse return null;
|
||||
const headers = try Headers.parse(self.recv_buf.items[0..end]);
|
||||
const body = self.recv_buf.items[end + 2 ..];
|
||||
if (body.len < headers.content_length) return null;
|
||||
return .{ .body = body };
|
||||
}
|
||||
|
@ -153,14 +143,14 @@ const Headers = struct {
|
|||
else
|
||||
sep + 1;
|
||||
const value = buf[vstart..end];
|
||||
ret.parse_one(name, value);
|
||||
try ret.parse_one(name, value);
|
||||
buf = if (end < buf.len - 2) buf[end + 2 ..] else return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_one(self: *Headers, name: []const u8, value: []const u8) void {
|
||||
fn parse_one(self: *Headers, name: []const u8, value: []const u8) !void {
|
||||
if (std.mem.eql(u8, "Content-Length", name)) {
|
||||
self.content_length = std.fmt.parseInt(@TypeOf(self.content_length), value, 10);
|
||||
self.content_length = try std.fmt.parseInt(@TypeOf(self.content_length), value, 10);
|
||||
} else if (std.mem.eql(u8, "Content-Type", name)) {
|
||||
self.content_type = value;
|
||||
}
|
84
src/Project.zig
Normal file
84
src/Project.zig
Normal file
|
@ -0,0 +1,84 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
|
||||
const Lsp = @import("Lsp.zig");
|
||||
|
||||
a: std.mem.Allocator,
|
||||
name: []const u8,
|
||||
files: std.ArrayList(File),
|
||||
open_time: i64,
|
||||
lsp: ?Lsp = null,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
const File = struct {
|
||||
path: []const u8,
|
||||
mtime: i128,
|
||||
};
|
||||
|
||||
pub fn init(a: std.mem.Allocator, name: []const u8) error{OutOfMemory}!Self {
|
||||
return .{
|
||||
.a = a,
|
||||
.name = try a.dupe(u8, name),
|
||||
.files = std.ArrayList(File).init(a),
|
||||
.open_time = std.time.milliTimestamp(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
for (self.files.items) |file| self.a.free(file.path);
|
||||
self.files.deinit();
|
||||
if (self.lsp) |*lsp| lsp.deinit();
|
||||
self.a.free(self.name);
|
||||
}
|
||||
|
||||
fn get_lsp(self: *Self) !Lsp {
|
||||
if (self.lsp) |lsp| return lsp;
|
||||
self.lsp = try Lsp.open(self.a, tp.message.fmt(.{"zls"}), "LSP");
|
||||
return self.lsp.?;
|
||||
}
|
||||
|
||||
pub fn add_file(self: *Self, path: []const u8, mtime: i128) error{OutOfMemory}!void {
|
||||
(try self.files.addOne()).* = .{ .path = try self.a.dupe(u8, path), .mtime = mtime };
|
||||
}
|
||||
|
||||
pub fn sort_files_by_mtime(self: *Self) void {
|
||||
const less_fn = struct {
|
||||
fn less_fn(_: void, lhs: File, rhs: File) bool {
|
||||
return lhs.mtime > rhs.mtime;
|
||||
}
|
||||
}.less_fn;
|
||||
std.mem.sort(File, self.files.items, {}, less_fn);
|
||||
}
|
||||
|
||||
pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) error{ OutOfMemory, Exit }!void {
|
||||
defer from.send(.{ "PRJ", "recent_done", "" }) catch {};
|
||||
for (self.files.items, 0..) |file, i| {
|
||||
try from.send(.{ "PRJ", "recent", file.path });
|
||||
if (i >= max) return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) error{ OutOfMemory, Exit }!usize {
|
||||
var i: usize = 0;
|
||||
defer from.send(.{ "PRJ", "recent_done", query }) catch {};
|
||||
for (self.files.items) |file| {
|
||||
if (file.path.len < query.len) continue;
|
||||
if (std.mem.indexOf(u8, file.path, query)) |_| {
|
||||
try from.send(.{ "PRJ", "recent", file.path });
|
||||
i += 1;
|
||||
if (i >= max) return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
pub fn goto_definition(self: *Self, from: tp.pid_ref, file_path: []const u8, file_type: []const u8, row: usize, col: usize) tp.result {
|
||||
const lsp = self.get_lsp() catch |e| return tp.exit_error(e);
|
||||
_ = from;
|
||||
_ = file_path;
|
||||
_ = file_type;
|
||||
_ = row;
|
||||
_ = col;
|
||||
_ = lsp;
|
||||
}
|
|
@ -4,6 +4,8 @@ const cbor = @import("cbor");
|
|||
const log = @import("log");
|
||||
const tracy = @import("tracy");
|
||||
|
||||
const Project = @import("Project.zig");
|
||||
|
||||
pid: tp.pid_ref,
|
||||
|
||||
const Self = @This();
|
||||
|
@ -55,6 +57,13 @@ pub fn query_recent_files(max: usize, query: []const u8) tp.result {
|
|||
return (try get()).pid.send(.{ "query_recent_files", project, max, query });
|
||||
}
|
||||
|
||||
pub fn goto_definition(file_path: []const u8, file_type: []const u8, row: usize, col: usize) tp.result {
|
||||
const project = tp.env.get().str("project");
|
||||
if (project.len == 0)
|
||||
return tp.exit("No project");
|
||||
return (try get()).pid.send(.{ "goto_definition", project, file_path, file_type, row, col });
|
||||
}
|
||||
|
||||
const Process = struct {
|
||||
a: std.mem.Allocator,
|
||||
parent: tp.pid,
|
||||
|
@ -101,9 +110,12 @@ const Process = struct {
|
|||
var project_directory: []const u8 = undefined;
|
||||
var path: []const u8 = undefined;
|
||||
var query: []const u8 = undefined;
|
||||
var file_type: []const u8 = undefined;
|
||||
var high: i64 = 0;
|
||||
var low: i64 = 0;
|
||||
var max: usize = 0;
|
||||
var row: usize = 0;
|
||||
var col: usize = 0;
|
||||
|
||||
if (try m.match(.{ "walk_tree_entry", tp.extract(&project_directory), tp.extract(&path), tp.extract(&high), tp.extract(&low) })) {
|
||||
const mtime = (@as(i128, @intCast(high)) << 64) | @as(i128, @intCast(low));
|
||||
|
@ -126,6 +138,8 @@ const Process = struct {
|
|||
self.request_recent_files(from, project_directory, max) catch |e| return from.send_raw(tp.exit_message(e));
|
||||
} else if (try m.match(.{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
|
||||
self.query_recent_files(from, project_directory, max, query) catch |e| return from.send_raw(tp.exit_message(e));
|
||||
} else if (try m.match(.{ "goto_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&file_type), tp.extract(&row), tp.extract(&col) })) {
|
||||
self.goto_definition(from, project_directory, path, file_type, row, col) catch |e| return from.send_raw(tp.exit_message(e));
|
||||
} else if (try m.match(.{"shutdown"})) {
|
||||
if (self.walker) |pid| pid.send(.{"stop"}) catch {};
|
||||
try from.send(.{ "project_manager", "shutdown" });
|
||||
|
@ -161,67 +175,10 @@ const Process = struct {
|
|||
_ = matched;
|
||||
// self.logger.print("queried: {s} for {s} match {d} in {d} ms", .{ project_directory, query, matched, std.time.milliTimestamp() - start_time });
|
||||
}
|
||||
};
|
||||
|
||||
const Project = struct {
|
||||
a: std.mem.Allocator,
|
||||
name: []const u8,
|
||||
files: std.ArrayList(File),
|
||||
open_time: i64,
|
||||
|
||||
const File = struct {
|
||||
path: []const u8,
|
||||
mtime: i128,
|
||||
};
|
||||
|
||||
fn init(a: std.mem.Allocator, name: []const u8) error{OutOfMemory}!Project {
|
||||
return .{
|
||||
.a = a,
|
||||
.name = try a.dupe(u8, name),
|
||||
.files = std.ArrayList(File).init(a),
|
||||
.open_time = std.time.milliTimestamp(),
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: *Project) void {
|
||||
for (self.files.items) |file| self.a.free(file.path);
|
||||
self.files.deinit();
|
||||
self.a.free(self.name);
|
||||
}
|
||||
|
||||
fn add_file(self: *Project, path: []const u8, mtime: i128) error{OutOfMemory}!void {
|
||||
(try self.files.addOne()).* = .{ .path = try self.a.dupe(u8, path), .mtime = mtime };
|
||||
}
|
||||
|
||||
fn sort_files_by_mtime(self: *Project) void {
|
||||
const less_fn = struct {
|
||||
fn less_fn(_: void, lhs: File, rhs: File) bool {
|
||||
return lhs.mtime > rhs.mtime;
|
||||
}
|
||||
}.less_fn;
|
||||
std.mem.sort(File, self.files.items, {}, less_fn);
|
||||
}
|
||||
|
||||
fn request_recent_files(self: *Project, from: tp.pid_ref, max: usize) error{ OutOfMemory, Exit }!void {
|
||||
defer from.send(.{ "PRJ", "recent_done", "" }) catch {};
|
||||
for (self.files.items, 0..) |file, i| {
|
||||
try from.send(.{ "PRJ", "recent", file.path });
|
||||
if (i >= max) return;
|
||||
}
|
||||
}
|
||||
|
||||
fn query_recent_files(self: *Project, from: tp.pid_ref, max: usize, query: []const u8) error{ OutOfMemory, Exit }!usize {
|
||||
var i: usize = 0;
|
||||
defer from.send(.{ "PRJ", "recent_done", query }) catch {};
|
||||
for (self.files.items) |file| {
|
||||
if (file.path.len < query.len) continue;
|
||||
if (std.mem.indexOf(u8, file.path, query)) |_| {
|
||||
try from.send(.{ "PRJ", "recent", file.path });
|
||||
i += 1;
|
||||
if (i >= max) return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
fn goto_definition(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, file_type: []const u8, row: usize, col: usize) tp.result {
|
||||
const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project");
|
||||
return project.goto_definition(from, file_path, file_type, row, col);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ const ripgrep = @import("ripgrep");
|
|||
const tracy = @import("tracy");
|
||||
const text_manip = @import("text_manip");
|
||||
const syntax = @import("syntax");
|
||||
const project_manager = @import("project_manager");
|
||||
|
||||
const scrollbar_v = @import("scrollbar_v.zig");
|
||||
const editor_gutter = @import("editor_gutter.zig");
|
||||
|
@ -3146,6 +3147,13 @@ pub const Editor = struct {
|
|||
try self.send_editor_jump_destination();
|
||||
}
|
||||
|
||||
pub fn goto_definition(self: *Self, _: command.Context) tp.result {
|
||||
const file_path = self.file_path orelse return;
|
||||
const primary = self.get_primary();
|
||||
const file_type = (self.syntax orelse return).file_type.name;
|
||||
return project_manager.goto_definition(file_path, file_type, primary.cursor.row, primary.cursor.col);
|
||||
}
|
||||
|
||||
pub fn select(self: *Self, ctx: command.Context) tp.result {
|
||||
var sel: Selection = .{};
|
||||
if (!try ctx.args.match(.{ tp.extract(&sel.begin.row), tp.extract(&sel.begin.col), tp.extract(&sel.end.row), tp.extract(&sel.end.col) }))
|
||||
|
|
|
@ -186,7 +186,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result {
|
|||
key.F09 => self.cmd("theme_prev", .{}),
|
||||
key.F10 => self.cmd("theme_next", .{}),
|
||||
key.F11 => self.cmd("toggle_logview", .{}),
|
||||
key.F12 => self.cmd("toggle_inputview", .{}),
|
||||
key.F12 => self.cmd("goto_definition", .{}),
|
||||
key.F34 => self.cmd("toggle_whitespace", .{}), // C-F10
|
||||
key.ESC => self.cmd("cancel", .{}),
|
||||
key.ENTER => self.cmd("smart_insert_line", .{}),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue