feat(lsp): initial support for textDocument/rename
flow keybinds: changes f2 from toggle_input_mode to rename_symbol and moves toggle_input_mode command to ctrl+shift+f2 (since ctrl+f2 is already bound to insert_command_name) the replacement text is hard coded for now. i've checked that replace works with zls and pylsp which send WorkspaceEdit response messages in different shapes - zls sends shape `{"changes": {}}` while pylsp sends `{"documentChanges": []}`. currently the 'rename_symbol_item' commands are sent one at a time. however they should be buffered and be performed between one buf_for_update, update_buf pair. this will be addressed in a follow up.
This commit is contained in:
parent
7558a63819
commit
1fd4455adb
5 changed files with 172 additions and 1 deletions
|
@ -4222,6 +4222,13 @@ pub const Editor = struct {
|
|||
}
|
||||
pub const completion_meta = .{ .description = "Language: Show completions at cursor" };
|
||||
|
||||
pub fn rename_symbol(self: *Self, _: Context) Result {
|
||||
const file_path = self.file_path orelse return;
|
||||
const primary = self.get_primary();
|
||||
return project_manager.rename_symbol(file_path, primary.cursor.row, primary.cursor.col);
|
||||
}
|
||||
pub const rename_symbol_meta = .{ .description = "Language: Rename symbol at cursor" };
|
||||
|
||||
pub fn hover(self: *Self, _: Context) Result {
|
||||
const primary = self.get_primary();
|
||||
return self.hover_at(primary.cursor.row, primary.cursor.col);
|
||||
|
@ -4316,6 +4323,15 @@ pub const Editor = struct {
|
|||
self.need_render();
|
||||
}
|
||||
|
||||
pub fn rename_symbol_item(self: *Self, sel: Selection, new_text: []const u8) Result {
|
||||
self.get_primary().selection = sel;
|
||||
const buf = try self.buf_for_update();
|
||||
const r1 = try self.delete_selection(buf.root, self.get_primary(), self.allocator);
|
||||
const r2 = try self.insert(r1, self.get_primary(), new_text, self.allocator);
|
||||
try self.update_buf(r2);
|
||||
self.need_render();
|
||||
}
|
||||
|
||||
pub fn select(self: *Self, ctx: Context) 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) }))
|
||||
|
|
|
@ -554,6 +554,32 @@ const cmds = struct {
|
|||
}
|
||||
pub const add_diagnostic_meta = .{ .arguments = &.{ .string, .string, .string, .string, .integer, .integer, .integer, .integer, .integer } };
|
||||
|
||||
pub fn rename_symbol_item(self: *Self, ctx: Ctx) Result {
|
||||
var file_uri: []const u8 = undefined;
|
||||
var sel: ed.Selection = .{};
|
||||
var new_text: []const u8 = undefined;
|
||||
if (!try ctx.args.match(.{
|
||||
tp.extract(&file_uri),
|
||||
tp.extract(&sel.begin.row),
|
||||
tp.extract(&sel.begin.col),
|
||||
tp.extract(&sel.end.row),
|
||||
tp.extract(&sel.end.col),
|
||||
tp.extract(&new_text),
|
||||
})) return error.InvalidRenameSymbolArgument;
|
||||
file_uri = project_manager.normalize_file_path(file_uri);
|
||||
if (self.get_active_editor()) |editor| {
|
||||
// TODO match correctly. endsWith() isn't correct because path is a
|
||||
// short, relative path while file_uri is an absolute path starting with 'file://'
|
||||
const match = if (editor.file_path) |path| std.mem.endsWith(u8, file_uri, path) else false;
|
||||
if (match) {
|
||||
try editor.rename_symbol_item(sel, new_text);
|
||||
} else {
|
||||
// TODO perform renames in other files
|
||||
}
|
||||
}
|
||||
}
|
||||
pub const rename_symbol_item_meta = .{ .arguments = &.{ .string, .integer, .integer, .integer, .integer, .string } };
|
||||
|
||||
pub fn clear_diagnostics(self: *Self, ctx: Ctx) Result {
|
||||
var file_path: []const u8 = undefined;
|
||||
if (!try ctx.args.match(.{tp.extract(&file_path)})) return error.InvalidClearDiagnosticsArgument;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue