diff --git a/build.zig.zon b/build.zig.zon index 3f6490c..e5e8458 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -16,8 +16,8 @@ .hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362", }, .thespian = .{ - .url = "https://github.com/neurocyte/thespian/archive/3db5b9ad969beeb3a543e443bec12b6c953f4be4.tar.gz", - .hash = "1220954570adc1d9efe3a2bee2c9680ec344ee4bcc569fa3144c0bfc76fec7937f8c", + .url = "https://github.com/neurocyte/thespian/archive/3ace3163087a0260b30e2c420de76235dd82451f.tar.gz", + .hash = "1220ffbfff37c24b68424a3c9223cf57daed5debdbb6b7751a36b9dca318825cff4c", }, .themes = .{ .url = "https://github.com/neurocyte/flow-themes/releases/download/master-15e8cad1619429bf2547a6819b5b999510d5c1e5/flow-themes.tar.gz", diff --git a/src/LSP.zig b/src/LSP.zig index e8345e4..bc92919 100644 --- a/src/LSP.zig +++ b/src/LSP.zig @@ -420,3 +420,31 @@ const Headers = struct { } } }; + +pub const CompletionItemKind = enum(u8) { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, +}; diff --git a/src/Project.zig b/src/Project.zig index 187bb22..bdc1989 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -452,6 +452,17 @@ fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const } } +pub fn completion(self: *Self, _: tp.pid_ref, file_path: []const u8, row: usize, col: usize) !void { + const lsp = try self.get_file_lsp(file_path); + const uri = self.make_URI(file_path) catch |e| return tp.exit_error(e); + defer self.a.free(uri); + const response = try lsp.send_request(self.a, "textDocument/completion", .{ + .textDocument = .{ .uri = uri }, + .position = .{ .line = row, .character = col }, + }); + defer self.a.free(response.buf); +} + pub fn publish_diagnostics(self: *Self, to: tp.pid_ref, params_cb: []const u8) !void { var uri: ?[]const u8 = null; var diagnostics: []const u8 = &.{}; diff --git a/src/project_manager.zig b/src/project_manager.zig index 5d093f6..820fa7c 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -98,6 +98,13 @@ pub fn goto_definition(file_path: []const u8, row: usize, col: usize) tp.result return (try get()).pid.send(.{ "goto_definition", project, file_path, row, col }); } +pub fn completion(file_path: []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(.{ "completion", project, file_path, row, col }); +} + pub fn update_mru(file_path: []const u8, row: usize, col: usize) tp.result { const project = tp.env.get().str("project"); if (project.len == 0) @@ -220,6 +227,8 @@ const Process = struct { self.did_close(project_directory, path) catch |e| return from.forward_error(e); } else if (try m.match(.{ "goto_definition", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) { self.goto_definition(from, project_directory, path, row, col) catch |e| return from.forward_error(e); + } else if (try m.match(.{ "completion", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) { + self.completion(from, project_directory, path, row, col) catch |e| return from.forward_error(e); } else if (try m.match(.{ "get_mru_position", tp.extract(&project_directory), tp.extract(&path) })) { self.get_mru_position(from, project_directory, path) catch |e| return from.forward_error(e); } else if (try m.match(.{"shutdown"})) { @@ -308,6 +317,13 @@ const Process = struct { return project.goto_definition(from, file_path, row, col) catch |e| tp.exit_error(e); } + fn completion(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8, row: usize, col: usize) tp.result { + const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".completion" }); + defer frame.deinit(); + const project = if (self.projects.get(project_directory)) |p| p else return tp.exit("No project"); + return project.completion(from, file_path, row, col) catch |e| tp.exit_error(e); + } + fn get_mru_position(self: *Process, from: tp.pid_ref, project_directory: []const u8, file_path: []const u8) tp.result { const frame = tracy.initZone(@src(), .{ .name = module_name ++ ".get_mru_position" }); defer frame.deinit(); diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 3aa8c90..0ad3665 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -3391,6 +3391,12 @@ pub const Editor = struct { return project_manager.goto_definition(file_path, primary.cursor.row, primary.cursor.col); } + pub fn completion(self: *Self, _: command.Context) tp.result { + const file_path = self.file_path orelse return; + const primary = self.get_primary(); + return project_manager.completion(file_path, primary.cursor.row, primary.cursor.col); + } + pub fn clear_diagnostics(self: *Self, ctx: command.Context) tp.result { var file_path: []const u8 = undefined; if (!try ctx.args.match(.{tp.extract(&file_path)})) return tp.exit_error(error.InvalidArgument); diff --git a/src/tui/mode/input/flow.zig b/src/tui/mode/input/flow.zig index 6d7ee1b..34eebb3 100644 --- a/src/tui/mode/input/flow.zig +++ b/src/tui/mode/input/flow.zig @@ -105,7 +105,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { 'I' => self.insert_bytes("\t"), '/' => self.cmd("toggle_comment", .{}), key.ENTER => self.cmd("smart_insert_line_after", .{}), - key.SPACE => self.cmd("selections_reverse", .{}), + key.SPACE => self.cmd("completion", .{}), key.END => self.cmd("move_buffer_end", .{}), key.HOME => self.cmd("move_buffer_begin", .{}), key.UP => self.cmd("move_scroll_up", .{}), @@ -137,6 +137,7 @@ fn mapPress(self: *Self, keypress: u32, egc: u32, modifiers: u32) tp.result { key.DOWN => self.cmd("select_scroll_down", .{}), key.LEFT => self.cmd("select_word_left", .{}), key.RIGHT => self.cmd("select_word_right", .{}), + key.SPACE => self.cmd("selections_reverse", .{}), else => {}, }, mod.ALT => switch (keynormal) {