feat: preparations for additionalTextEdits support in completions
This commit is contained in:
parent
8476f613c2
commit
9ea32d46e2
2 changed files with 58 additions and 28 deletions
|
@ -1054,9 +1054,9 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col:
|
||||||
var documentation_kind: []const u8 = "";
|
var documentation_kind: []const u8 = "";
|
||||||
var sortText: []const u8 = "";
|
var sortText: []const u8 = "";
|
||||||
var insertTextFormat: usize = 0;
|
var insertTextFormat: usize = 0;
|
||||||
var textEdit_newText: []const u8 = "";
|
var textEdit: TextEdit = .{};
|
||||||
var textEdit_insert: ?Range = null;
|
var additionalTextEdits: [32]TextEdit = undefined;
|
||||||
var textEdit_replace: ?Range = null;
|
var additionalTextEdits_len: usize = 0;
|
||||||
|
|
||||||
var iter = item;
|
var iter = item;
|
||||||
var len = cbor.decodeMapHeader(&iter) catch return;
|
var len = cbor.decodeMapHeader(&iter) catch return;
|
||||||
|
@ -1098,30 +1098,22 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col:
|
||||||
} else if (std.mem.eql(u8, field_name, "insertTextFormat")) {
|
} else if (std.mem.eql(u8, field_name, "insertTextFormat")) {
|
||||||
if (!(try cbor.matchValue(&iter, cbor.extract(&insertTextFormat)))) return invalid_field("insertTextFormat");
|
if (!(try cbor.matchValue(&iter, cbor.extract(&insertTextFormat)))) return invalid_field("insertTextFormat");
|
||||||
} else if (std.mem.eql(u8, field_name, "textEdit")) {
|
} else if (std.mem.eql(u8, field_name, "textEdit")) {
|
||||||
// var textEdit: []const u8 = ""; // { "newText": "wait_expired(${1:timeout_ns: isize})", "insert": Range, "replace": Range },
|
textEdit = try read_textEdit(&iter);
|
||||||
var len_ = cbor.decodeMapHeader(&iter) catch return;
|
} else if (std.mem.eql(u8, field_name, "additionalTextEdits")) {
|
||||||
|
var len_ = cbor.decodeArrayHeader(&iter) catch return;
|
||||||
|
additionalTextEdits_len = len_;
|
||||||
|
var idx: usize = 0;
|
||||||
while (len_ > 0) : (len_ -= 1) {
|
while (len_ > 0) : (len_ -= 1) {
|
||||||
if (!(try cbor.matchString(&iter, &field_name))) return invalid_field("textEdit");
|
additionalTextEdits[idx] = try read_textEdit(&iter);
|
||||||
if (std.mem.eql(u8, field_name, "newText")) {
|
idx += 1;
|
||||||
if (!(try cbor.matchValue(&iter, cbor.extract(&textEdit_newText)))) return invalid_field("textEdit.newText");
|
}
|
||||||
} else if (std.mem.eql(u8, field_name, "insert")) {
|
try cbor.skipValue(&iter);
|
||||||
var range_: []const u8 = undefined;
|
|
||||||
if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return invalid_field("textEdit.insert");
|
|
||||||
textEdit_insert = try read_range(range_);
|
|
||||||
} else if (std.mem.eql(u8, field_name, "replace") or std.mem.eql(u8, field_name, "range")) {
|
|
||||||
var range_: []const u8 = undefined;
|
|
||||||
if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return invalid_field("textEdit.replace");
|
|
||||||
textEdit_replace = try read_range(range_);
|
|
||||||
} else {
|
} else {
|
||||||
try cbor.skipValue(&iter);
|
try cbor.skipValue(&iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
const insert = textEdit.insert orelse Range{ .start = .{ .line = 0, .character = 0 }, .end = .{ .line = 0, .character = 0 } };
|
||||||
try cbor.skipValue(&iter);
|
const replace = textEdit.replace orelse Range{ .start = .{ .line = 0, .character = 0 }, .end = .{ .line = 0, .character = 0 } };
|
||||||
}
|
|
||||||
}
|
|
||||||
const insert = textEdit_insert orelse Range{ .start = .{ .line = 0, .character = 0 }, .end = .{ .line = 0, .character = 0 } };
|
|
||||||
const replace = textEdit_replace orelse Range{ .start = .{ .line = 0, .character = 0 }, .end = .{ .line = 0, .character = 0 } };
|
|
||||||
return to.send(.{
|
return to.send(.{
|
||||||
"cmd", "add_completion", .{
|
"cmd", "add_completion", .{
|
||||||
file_path,
|
file_path,
|
||||||
|
@ -1137,7 +1129,7 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col:
|
||||||
documentation_kind,
|
documentation_kind,
|
||||||
sortText,
|
sortText,
|
||||||
insertTextFormat,
|
insertTextFormat,
|
||||||
textEdit_newText,
|
textEdit.newText,
|
||||||
insert.start.line,
|
insert.start.line,
|
||||||
insert.start.character,
|
insert.start.character,
|
||||||
insert.end.line,
|
insert.end.line,
|
||||||
|
@ -1146,10 +1138,42 @@ fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col:
|
||||||
replace.start.character,
|
replace.start.character,
|
||||||
replace.end.line,
|
replace.end.line,
|
||||||
replace.end.character,
|
replace.end.character,
|
||||||
|
additionalTextEdits[0..additionalTextEdits_len],
|
||||||
},
|
},
|
||||||
}) catch error.ClientFailed;
|
}) catch error.ClientFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_textEdit(iter: *[]const u8) !TextEdit {
|
||||||
|
var field_name: []const u8 = undefined;
|
||||||
|
var newText: []const u8 = "";
|
||||||
|
var insert: ?Range = null;
|
||||||
|
var replace: ?Range = null;
|
||||||
|
var len_ = cbor.decodeMapHeader(iter) catch return invalid_field("textEdit");
|
||||||
|
while (len_ > 0) : (len_ -= 1) {
|
||||||
|
if (!(try cbor.matchString(iter, &field_name))) return invalid_field("textEdit");
|
||||||
|
if (std.mem.eql(u8, field_name, "newText")) {
|
||||||
|
if (!(try cbor.matchValue(iter, cbor.extract(&newText)))) return invalid_field("textEdit.newText");
|
||||||
|
} else if (std.mem.eql(u8, field_name, "insert")) {
|
||||||
|
var range_: []const u8 = undefined;
|
||||||
|
if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range_)))) return invalid_field("textEdit.insert");
|
||||||
|
insert = try read_range(range_);
|
||||||
|
} else if (std.mem.eql(u8, field_name, "replace") or std.mem.eql(u8, field_name, "range")) {
|
||||||
|
var range_: []const u8 = undefined;
|
||||||
|
if (!(try cbor.matchValue(iter, cbor.extract_cbor(&range_)))) return invalid_field("textEdit.replace");
|
||||||
|
replace = try read_range(range_);
|
||||||
|
} else {
|
||||||
|
try cbor.skipValue(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .{ .newText = newText, .insert = insert, .replace = replace };
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextEdit = struct {
|
||||||
|
newText: []const u8 = &.{},
|
||||||
|
insert: ?Range = null,
|
||||||
|
replace: ?Range = null,
|
||||||
|
};
|
||||||
|
|
||||||
const Rename = struct {
|
const Rename = struct {
|
||||||
uri: []const u8,
|
uri: []const u8,
|
||||||
new_text: []const u8,
|
new_text: []const u8,
|
||||||
|
|
|
@ -40,7 +40,7 @@ pub fn load_entries(palette: *Type) !usize {
|
||||||
|
|
||||||
var max_label_len: usize = 0;
|
var max_label_len: usize = 0;
|
||||||
for (palette.entries.items) |*item| {
|
for (palette.entries.items) |*item| {
|
||||||
const label_, const sort_text, _, const maybe_replace = get_values(item.cbor);
|
const label_, const sort_text, _, const maybe_replace, _ = get_values(item.cbor);
|
||||||
if (get_replace_selection(maybe_replace)) |replace| {
|
if (get_replace_selection(maybe_replace)) |replace| {
|
||||||
if (palette.value.replace == null) palette.value.replace = replace;
|
if (palette.value.replace == null) palette.value.replace = replace;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonState, theme: *const Widget.
|
||||||
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&item_cbor)) catch false)) return false;
|
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&item_cbor)) catch false)) return false;
|
||||||
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) return false;
|
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) return false;
|
||||||
|
|
||||||
const label_, _, const kind, _ = get_values(item_cbor);
|
const label_, _, const kind, _, _ = get_values(item_cbor);
|
||||||
const icon_: []const u8 = kind_icon(@enumFromInt(kind));
|
const icon_: []const u8 = kind_icon(@enumFromInt(kind));
|
||||||
const color: u24 = 0x0;
|
const color: u24 = 0x0;
|
||||||
const indicator: []const u8 = &.{};
|
const indicator: []const u8 = &.{};
|
||||||
|
@ -99,11 +99,12 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonState, theme: *const Widget.
|
||||||
return tui.render_file_item(&button.plane, label_, icon_, color, indicator, matches_cbor, button.active, selected, button.hover, theme);
|
return tui.render_file_item(&button.plane, label_, icon_, color, indicator, matches_cbor, button.active, selected, button.hover, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer.Selection } {
|
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer.Selection, []const u8 } {
|
||||||
var label_: []const u8 = "";
|
var label_: []const u8 = "";
|
||||||
var sort_text: []const u8 = "";
|
var sort_text: []const u8 = "";
|
||||||
var kind: u8 = 0;
|
var kind: u8 = 0;
|
||||||
var replace: Buffer.Selection = .{};
|
var replace: Buffer.Selection = .{};
|
||||||
|
var additionalTextEdits: []const u8 = &.{};
|
||||||
_ = cbor.match(item_cbor, .{
|
_ = cbor.match(item_cbor, .{
|
||||||
cbor.any, // file_path
|
cbor.any, // file_path
|
||||||
cbor.any, // row
|
cbor.any, // row
|
||||||
|
@ -127,10 +128,15 @@ fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer
|
||||||
cbor.extract(&replace.begin.col), // replace.begin.col
|
cbor.extract(&replace.begin.col), // replace.begin.col
|
||||||
cbor.extract(&replace.end.row), // replace.end.row
|
cbor.extract(&replace.end.row), // replace.end.row
|
||||||
cbor.extract(&replace.end.col), // replace.end.col
|
cbor.extract(&replace.end.col), // replace.end.col
|
||||||
|
cbor.extract_cbor(&additionalTextEdits),
|
||||||
}) catch false;
|
}) catch false;
|
||||||
return .{ label_, sort_text, kind, replace };
|
return .{ label_, sort_text, kind, replace, additionalTextEdits };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TextEdit = struct { newText: []const u8 = &.{}, insert: ?Range = null, replace: ?Range = null };
|
||||||
|
const Range = struct { start: Position, end: Position };
|
||||||
|
const Position = struct { line: usize, character: usize };
|
||||||
|
|
||||||
fn get_replace_selection(replace: Buffer.Selection) ?Buffer.Selection {
|
fn get_replace_selection(replace: Buffer.Selection) ?Buffer.Selection {
|
||||||
return if (tui.get_active_editor()) |edt|
|
return if (tui.get_active_editor()) |edt|
|
||||||
edt.selection_pos_to_width(replace)
|
edt.selection_pos_to_width(replace)
|
||||||
|
@ -141,14 +147,14 @@ fn get_replace_selection(replace: Buffer.Selection) ?Buffer.Selection {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select(menu: **Type.MenuState, button: *Type.ButtonState) void {
|
fn select(menu: **Type.MenuState, button: *Type.ButtonState) void {
|
||||||
const label_, _, _, _ = get_values(button.opts.label);
|
const label_, _, _, _, _ = get_values(button.opts.label);
|
||||||
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
tp.self_pid().send(.{ "cmd", "insert_chars", .{label_} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
tp.self_pid().send(.{ "cmd", "insert_chars", .{label_} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updated(palette: *Type, button_: ?*Type.ButtonState) !void {
|
pub fn updated(palette: *Type, button_: ?*Type.ButtonState) !void {
|
||||||
const button = button_ orelse return cancel(palette);
|
const button = button_ orelse return cancel(palette);
|
||||||
_, _, _, const replace = get_values(button.opts.label);
|
_, _, _, const replace, _ = get_values(button.opts.label);
|
||||||
const editor = tui.get_active_editor() orelse return error.NotFound;
|
const editor = tui.get_active_editor() orelse return error.NotFound;
|
||||||
editor.get_primary().selection = get_replace_selection(replace);
|
editor.get_primary().selection = get_replace_selection(replace);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue