Add language format and code action edits
This commit is contained in:
+91
@@ -23,6 +23,8 @@ pub const Error = error{
|
||||
InvalidProvider,
|
||||
MissingProvider,
|
||||
AmbiguousProvider,
|
||||
StaleEdit,
|
||||
OverlappingEdit,
|
||||
};
|
||||
|
||||
pub const ProviderKind = enum {
|
||||
@@ -209,6 +211,95 @@ pub fn compactSignatureCardAlloc(allocator: std.mem.Allocator, row: []const u8)
|
||||
return std.fmt.allocPrint(allocator, "[{s}] {s}", .{ provider, body });
|
||||
}
|
||||
|
||||
pub const ProviderEdit = struct {
|
||||
provider: []const u8,
|
||||
capability: ProviderCapability,
|
||||
version: u64,
|
||||
start: usize,
|
||||
end: usize,
|
||||
replacement: []const u8,
|
||||
};
|
||||
|
||||
pub fn providerCapabilityFromName(name: []const u8) !ProviderCapability {
|
||||
if (std.mem.eql(u8, name, "format")) return .format;
|
||||
if (std.mem.eql(u8, name, "organize_imports")) return .organize_imports;
|
||||
if (std.mem.eql(u8, name, "code_action")) return .code_action;
|
||||
return Error.InvalidProvider;
|
||||
}
|
||||
|
||||
pub fn editRowAlloc(
|
||||
allocator: std.mem.Allocator,
|
||||
provider: []const u8,
|
||||
capability: ProviderCapability,
|
||||
version: u64,
|
||||
start: usize,
|
||||
end: usize,
|
||||
replacement: []const u8,
|
||||
) ![]u8 {
|
||||
if (provider.len == 0 or start > end) return Error.InvalidEdit;
|
||||
return std.fmt.allocPrint(allocator, "provider:{s}:edit:{s}:{d}:{d}:{d}:{s}", .{ provider, @tagName(capability), version, start, end, replacement });
|
||||
}
|
||||
|
||||
pub fn parseProviderEditRow(row: []const u8) !ProviderEdit {
|
||||
const provider = try providerIdFromRow(row);
|
||||
const payload = try providerPayloadFromRow(row);
|
||||
if (!std.mem.startsWith(u8, payload, "edit:")) return Error.InvalidEdit;
|
||||
var parts = std.mem.splitScalar(u8, payload, ':');
|
||||
_ = parts.next() orelse return Error.InvalidEdit;
|
||||
const capability_name = parts.next() orelse return Error.InvalidEdit;
|
||||
const version_text = parts.next() orelse return Error.InvalidEdit;
|
||||
const start_text = parts.next() orelse return Error.InvalidEdit;
|
||||
const end_text = parts.next() orelse return Error.InvalidEdit;
|
||||
const replacement = parts.rest();
|
||||
const start = std.fmt.parseUnsigned(usize, start_text, 10) catch return Error.InvalidEdit;
|
||||
const end = std.fmt.parseUnsigned(usize, end_text, 10) catch return Error.InvalidEdit;
|
||||
if (start > end) return Error.InvalidEdit;
|
||||
return .{
|
||||
.provider = provider,
|
||||
.capability = try providerCapabilityFromName(capability_name),
|
||||
.version = std.fmt.parseUnsigned(u64, version_text, 10) catch return Error.InvalidEdit,
|
||||
.start = start,
|
||||
.end = end,
|
||||
.replacement = replacement,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn validateEditBatch(rows: []const []const u8, document_version: u64, document_len: usize) !void {
|
||||
var previous_start: ?usize = null;
|
||||
var previous_end: ?usize = null;
|
||||
for (rows) |row| {
|
||||
const edit = try parseProviderEditRow(row);
|
||||
if (edit.version != document_version) return Error.StaleEdit;
|
||||
if (edit.end > document_len) return Error.InvalidEdit;
|
||||
if (previous_start) |start| {
|
||||
if (!(edit.end <= start or edit.start >= previous_end.?)) return Error.OverlappingEdit;
|
||||
}
|
||||
previous_start = edit.start;
|
||||
previous_end = edit.end;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn actionPanelRowAlloc(allocator: std.mem.Allocator, row: []const u8) ![]const u8 {
|
||||
const edit = try parseProviderEditRow(row);
|
||||
return std.fmt.allocPrint(allocator, "action:{s}:provider:{s}:scope:{d}-{d}:apply", .{ @tagName(edit.capability), edit.provider, edit.start, edit.end });
|
||||
}
|
||||
|
||||
pub fn providerFromActionPanelRow(row: []const u8) ![]const u8 {
|
||||
const marker = ":provider:";
|
||||
const start = std.mem.indexOf(u8, row, marker) orelse return Error.InvalidProvider;
|
||||
const rest = row[start + marker.len ..];
|
||||
const end = std.mem.indexOfScalar(u8, rest, ':') orelse return Error.InvalidProvider;
|
||||
if (end == 0) return Error.InvalidProvider;
|
||||
return rest[0..end];
|
||||
}
|
||||
|
||||
pub fn capabilityFromActionPanelRow(row: []const u8) !ProviderCapability {
|
||||
if (!std.mem.startsWith(u8, row, "action:")) return Error.InvalidProvider;
|
||||
const rest = row[7..];
|
||||
const end = std.mem.indexOfScalar(u8, rest, ':') orelse return Error.InvalidProvider;
|
||||
return providerCapabilityFromName(rest[0..end]);
|
||||
}
|
||||
|
||||
pub fn providerPickerRowsAlloc(allocator: std.mem.Allocator, capability: ProviderCapability, providers: []const Provider) ![][]const u8 {
|
||||
var rows = std.ArrayList([]const u8).empty;
|
||||
errdefer {
|
||||
|
||||
Reference in New Issue
Block a user