Added label renaming

This commit is contained in:
Alexandros Naskos 2020-06-27 03:16:14 +03:00
parent 4952c34481
commit beb900f1d9
3 changed files with 104 additions and 13 deletions

View File

@ -1218,7 +1218,7 @@ fn tokenRangeAppend(prev: SourceRange, token: std.zig.Token) SourceRange {
pub fn documentPositionContext(allocator: *std.mem.Allocator, document: types.TextDocument, position: types.Position) !PositionContext {
const line = try document.getLine(@intCast(usize, position.line));
const pos_char = @intCast(usize, position.character) + 1;
const pos_char = @intCast(usize, position.character);
const idx = if (pos_char > line.len) line.len else pos_char;
var arena = std.heap.ArenaAllocator.init(allocator);

View File

@ -9,6 +9,10 @@ const data = @import("data/" ++ build_options.data_version ++ ".zig");
const types = @import("types.zig");
const analysis = @import("analysis.zig");
const URI = @import("uri.zig");
const rename = @import("rename.zig");
// TODO Fix LSP -> byte and byte -> LSP offsets
// Implement clangd extension for utf8 offsets as well.
pub const log_level: std.log.Level = switch (std.builtin.mode) {
.Debug => .debug,
@ -35,9 +39,11 @@ pub fn log(
};
send(types.Notification{
.method = "window/showMessage",
.params = types.NotificationParams{ .ShowMessageParams = .{
.params = types.NotificationParams{
.ShowMessageParams = .{
.type = message_type,
.message = message, },
.message = message,
},
},
}) catch |err| {
std.debug.print("Failed to send show message notification (error: {}).", .{err});
@ -50,9 +56,11 @@ pub fn log(
send(types.Notification{
.method = "window/logMessage",
.params = types.NotificationParams{ .LogMessageParams = .{
.params = types.NotificationParams{
.LogMessageParams = .{
.type = message_type,
.message = message, },
.message = message,
},
},
}) catch |err| {
std.debug.print("Failed to send show message notification (error: {}).", .{err});
@ -78,7 +86,7 @@ const ClientCapabilities = struct {
var client_capabilities = ClientCapabilities{};
const initialize_response =
\\,"result": {"capabilities": {"signatureHelpProvider": {"triggerCharacters": ["(",","]},"textDocumentSync": 1,"completionProvider": {"resolveProvider": false,"triggerCharacters": [".",":","@"]},"documentHighlightProvider": false,"hoverProvider": true,"codeActionProvider": false,"declarationProvider": true,"definitionProvider": true,"typeDefinitionProvider": true,"implementationProvider": false,"referencesProvider": false,"documentSymbolProvider": true,"colorProvider": false,"documentFormattingProvider": true,"documentRangeFormattingProvider": false,"foldingRangeProvider": false,"selectionRangeProvider": false,"workspaceSymbolProvider": false,"rangeProvider": false,"documentProvider": true,"workspace": {"workspaceFolders": {"supported": true,"changeNotifications": true}},"semanticTokensProvider": {"documentProvider": true,"legend": {"tokenTypes": ["type","struct","enum","union","parameter","variable","tagField","field","errorTag","function","keyword","comment","string","number","operator","builtin","label"],"tokenModifiers": ["definition","async","documentation", "generic"]}}}}}
\\,"result": {"capabilities": {"signatureHelpProvider": {"triggerCharacters": ["(",","]},"textDocumentSync": 1,"renameProvider":true,"completionProvider": {"resolveProvider": false,"triggerCharacters": [".",":","@"]},"documentHighlightProvider": false,"hoverProvider": true,"codeActionProvider": false,"declarationProvider": true,"definitionProvider": true,"typeDefinitionProvider": true,"implementationProvider": false,"referencesProvider": false,"documentSymbolProvider": true,"colorProvider": false,"documentFormattingProvider": true,"documentRangeFormattingProvider": false,"foldingRangeProvider": false,"selectionRangeProvider": false,"workspaceSymbolProvider": false,"rangeProvider": false,"documentProvider": true,"workspace": {"workspaceFolders": {"supported": true,"changeNotifications": true}},"semanticTokensProvider": {"documentProvider": true,"legend": {"tokenTypes": ["type","struct","enum","union","parameter","variable","tagField","field","errorTag","function","keyword","comment","string","number","operator","builtin","label"],"tokenModifiers": ["definition","async","documentation", "generic"]}}}}}
;
const not_implemented_response =
@ -110,7 +118,7 @@ fn send(reqOrRes: var) !void {
defer arena.deinit();
var arr = std.ArrayList(u8).init(&arena.allocator);
try std.json.stringify(reqOrRes, .{}, arr.outStream());
try std.json.stringify(reqOrRes, .{}, arr.writer());
const stdout_stream = stdout.outStream();
try stdout_stream.print("Content-Length: {}\r\n\r\n", .{arr.items.len});
@ -709,6 +717,32 @@ fn gotoDefinitionString(id: types.RequestId, pos_index: usize, handle: *Document
});
}
fn renameDefinitionGlobal(id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, new_name: []const u8) !void {
// @TODO
}
fn renameDefinitionFieldAccess(id: types.RequestId, handle: *DocumentStore.Handle, position: types.Position, new_name: []const u8) !void {
// @TODO
}
fn renameDefinitionLabel(id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, new_name: []const u8) !void {
// @TODO
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{
.changes = std.StringHashMap([]types.TextEdit).init(&arena.allocator),
};
try rename.renameLabel(&arena, decl, new_name, &workspace_edit.changes.?);
try send(types.Response{
.id = id,
.result = .{ .WorkspaceEdit = workspace_edit },
});
}
const DeclToCompletionContext = struct {
completions: *std.ArrayList(types.CompletionItem),
config: *const Config,
@ -1140,7 +1174,7 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config, ke
const pos = types.Position{
.line = position.getValue("line").?.Integer,
.character = position.getValue("character").?.Integer - 1,
.character = position.getValue("character").?.Integer,
};
if (pos.character >= 0) {
const pos_index = try handle.document.positionToIndex(pos);
@ -1206,7 +1240,7 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config, ke
const pos = types.Position{
.line = position.getValue("line").?.Integer,
.character = position.getValue("character").?.Integer - 1,
.character = position.getValue("character").?.Integer,
};
if (pos.character >= 0) {
const resolve_alias = !std.mem.eql(u8, method, "textDocument/declaration");
@ -1236,7 +1270,7 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config, ke
const pos = types.Position{
.line = position.getValue("line").?.Integer,
.character = position.getValue("character").?.Integer - 1,
.character = position.getValue("character").?.Integer,
};
if (pos.character >= 0) {
const pos_index = try handle.document.positionToIndex(pos);
@ -1307,6 +1341,36 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config, ke
}
}
return try respondGeneric(id, null_result_response);
} else if (std.mem.eql(u8, method, "textDocument/rename")) {
const params = root.Object.getValue("params").?.Object;
const document = params.getValue("textDocument").?.Object;
const uri = document.getValue("uri").?.String;
const position = params.getValue("position").?.Object;
const handle = document_store.getHandle(uri) orelse {
std.log.debug(.main, "Trying to got to definition in non existent document {}", .{uri});
return try respondGeneric(id, null_result_response);
};
// @TODO
const pos = types.Position{
.line = position.getValue("line").?.Integer,
.character = position.getValue("character").?.Integer,
};
if (pos.character >= 0) {
const new_name = params.getValue("newName").?.String;
const pos_index = try handle.document.positionToIndex(pos);
const pos_context = try analysis.documentPositionContext(allocator, handle.document, pos);
switch (pos_context) {
.var_access => try renameDefinitionGlobal(id, handle, pos_index, new_name),
.field_access => try renameDefinitionFieldAccess(id, handle, pos, new_name),
.label => try renameDefinitionLabel(id, handle, pos_index, new_name),
else => try respondGeneric(id, null_result_response),
}
} else {
try respondGeneric(id, null_result_response);
}
} else if (std.mem.eql(u8, method, "textDocument/references") or
std.mem.eql(u8, method, "textDocument/documentHighlight") or
std.mem.eql(u8, method, "textDocument/codeAction") or
@ -1314,7 +1378,6 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config, ke
std.mem.eql(u8, method, "textDocument/documentLink") or
std.mem.eql(u8, method, "textDocument/rangeFormatting") or
std.mem.eql(u8, method, "textDocument/onTypeFormatting") or
std.mem.eql(u8, method, "textDocument/rename") or
std.mem.eql(u8, method, "textDocument/prepareRename") or
std.mem.eql(u8, method, "textDocument/foldingRange") or
std.mem.eql(u8, method, "textDocument/selectionRange"))

View File

@ -61,6 +61,7 @@ pub const ResponseParams = union(enum) {
DocumentSymbols: []DocumentSymbol,
SemanticTokens: struct { data: []const u32 },
TextEdits: []TextEdit,
WorkspaceEdit: WorkspaceEdit,
};
/// JSONRPC error
@ -201,6 +202,33 @@ pub const TextDocument = struct {
}
};
pub const WorkspaceEdit = struct {
changes: ?std.StringHashMap([]TextEdit),
pub fn jsonStringify(
self: WorkspaceEdit,
options: std.json.StringifyOptions,
writer: var,
) @TypeOf(writer).Error!void {
try writer.writeByte('{');
if (self.changes) |changes| {
try writer.writeAll("\"changes\": {");
var it = changes.iterator();
var idx: usize = 0;
while (it.next()) |entry| : (idx += 1) {
if (idx != 0) try writer.writeAll(", ");
try writer.writeByte('"');
try writer.writeAll(entry.key);
try writer.writeAll("\":");
try std.json.stringify(entry.value, options, writer);
}
try writer.writeByte('}');
}
try writer.writeByte('}');
}
};
pub const TextEdit = struct {
range: Range,
newText: String,