Autofix improvements (#879)
* improve autofix stability and client support * run zig fmt
This commit is contained in:
parent
9badc745c5
commit
c718e12d16
@ -653,7 +653,7 @@ fn createDocument(self: *DocumentStore, uri: Uri, text: [:0]u8, open: bool) erro
|
|||||||
self.build_files.swapRemoveAt(gop.index);
|
self.build_files.swapRemoveAt(gop.index);
|
||||||
log.debug("Failed to load build file {s}: (error: {})", .{ uri, err });
|
log.debug("Failed to load build file {s}: (error: {})", .{ uri, err });
|
||||||
}
|
}
|
||||||
if(!gop.found_existing) {
|
if (!gop.found_existing) {
|
||||||
const duped_uri = try self.allocator.dupe(u8, uri);
|
const duped_uri = try self.allocator.dupe(u8, uri);
|
||||||
gop.value_ptr.* = try self.createBuildFile(duped_uri);
|
gop.value_ptr.* = try self.createBuildFile(duped_uri);
|
||||||
gop.key_ptr.* = gop.value_ptr.uri;
|
gop.key_ptr.* = gop.value_ptr.uri;
|
||||||
|
@ -49,9 +49,9 @@ pub fn parse(allocator: std.mem.Allocator, include_carriage_return: bool, reader
|
|||||||
|
|
||||||
pub fn write(header: Header, include_carriage_return: bool, writer: anytype) @TypeOf(writer).Error!void {
|
pub fn write(header: Header, include_carriage_return: bool, writer: anytype) @TypeOf(writer).Error!void {
|
||||||
const seperator: []const u8 = if (include_carriage_return) "\r\n" else "\n";
|
const seperator: []const u8 = if (include_carriage_return) "\r\n" else "\n";
|
||||||
try writer.print("Content-Length: {}{s}", .{header.content_length, seperator});
|
try writer.print("Content-Length: {}{s}", .{ header.content_length, seperator });
|
||||||
if (header.content_type) |content_type| {
|
if (header.content_type) |content_type| {
|
||||||
try writer.print("Content-Type: {s}{s}", .{content_type, seperator});
|
try writer.print("Content-Type: {s}{s}", .{ content_type, seperator });
|
||||||
}
|
}
|
||||||
try writer.writeAll(seperator);
|
try writer.writeAll(seperator);
|
||||||
}
|
}
|
||||||
|
@ -53,13 +53,13 @@ status: enum {
|
|||||||
|
|
||||||
// Code was based off of https://github.com/andersfr/zig-lsp/blob/master/server.zig
|
// Code was based off of https://github.com/andersfr/zig-lsp/blob/master/server.zig
|
||||||
|
|
||||||
const ClientCapabilities = struct {
|
const ClientCapabilities = packed struct {
|
||||||
supports_snippets: bool = false,
|
supports_snippets: bool = false,
|
||||||
supports_semantic_tokens: bool = false,
|
supports_apply_edits: bool = false,
|
||||||
supports_inlay_hints: bool = false,
|
|
||||||
supports_will_save: bool = false,
|
supports_will_save: bool = false,
|
||||||
supports_will_save_wait_until: bool = false,
|
supports_will_save_wait_until: bool = false,
|
||||||
supports_publish_diagnostics: bool = false,
|
supports_publish_diagnostics: bool = false,
|
||||||
|
supports_code_action_fixall: bool = false,
|
||||||
hover_supports_md: bool = false,
|
hover_supports_md: bool = false,
|
||||||
completion_doc_supports_md: bool = false,
|
completion_doc_supports_md: bool = false,
|
||||||
label_details_support: bool = false,
|
label_details_support: bool = false,
|
||||||
@ -469,8 +469,26 @@ fn getAstCheckDiagnostics(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getAutofixMode(server: *Server) enum {
|
||||||
|
on_save,
|
||||||
|
will_save_wait_until,
|
||||||
|
fixall,
|
||||||
|
none,
|
||||||
|
} {
|
||||||
|
if (!server.config.enable_autofix) return .none;
|
||||||
|
if (server.client_capabilities.supports_code_action_fixall) return .fixall;
|
||||||
|
if (server.client_capabilities.supports_apply_edits) {
|
||||||
|
if (server.client_capabilities.supports_will_save_wait_until) return .will_save_wait_until;
|
||||||
|
return .on_save;
|
||||||
|
}
|
||||||
|
return .none;
|
||||||
|
}
|
||||||
|
|
||||||
/// caller owns returned memory.
|
/// caller owns returned memory.
|
||||||
fn autofix(server: *Server, allocator: std.mem.Allocator, handle: *const DocumentStore.Handle) !std.ArrayListUnmanaged(types.TextEdit) {
|
fn autofix(server: *Server, allocator: std.mem.Allocator, handle: *const DocumentStore.Handle) !std.ArrayListUnmanaged(types.TextEdit) {
|
||||||
|
if (!server.config.enable_ast_check_diagnostics) return .{};
|
||||||
|
|
||||||
|
if (handle.tree.errors.len != 0) return .{};
|
||||||
var diagnostics = std.ArrayListUnmanaged(types.Diagnostic){};
|
var diagnostics = std.ArrayListUnmanaged(types.Diagnostic){};
|
||||||
try getAstCheckDiagnostics(server, handle.*, &diagnostics);
|
try getAstCheckDiagnostics(server, handle.*, &diagnostics);
|
||||||
|
|
||||||
@ -1564,11 +1582,16 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) !types.In
|
|||||||
const tracy_zone = tracy.trace(@src());
|
const tracy_zone = tracy.trace(@src());
|
||||||
defer tracy_zone.end();
|
defer tracy_zone.end();
|
||||||
|
|
||||||
|
var skip_set_fixall = false;
|
||||||
|
|
||||||
if (request.clientInfo) |clientInfo| {
|
if (request.clientInfo) |clientInfo| {
|
||||||
log.info("client is '{s}-{s}'", .{ clientInfo.name, clientInfo.version orelse "<no version>" });
|
log.info("client is '{s}-{s}'", .{ clientInfo.name, clientInfo.version orelse "<no version>" });
|
||||||
|
|
||||||
if (std.mem.eql(u8, clientInfo.name, "Sublime Text LSP")) blk: {
|
if (std.mem.eql(u8, clientInfo.name, "Sublime Text LSP")) blk: {
|
||||||
server.config.max_detail_length = 256;
|
server.config.max_detail_length = 256;
|
||||||
|
// TODO investigate why fixall doesn't work in sublime text
|
||||||
|
server.client_capabilities.supports_code_action_fixall = false;
|
||||||
|
skip_set_fixall = true;
|
||||||
|
|
||||||
const version_str = clientInfo.version orelse break :blk;
|
const version_str = clientInfo.version orelse break :blk;
|
||||||
const version = std.SemanticVersion.parse(version_str) catch break :blk;
|
const version = std.SemanticVersion.parse(version_str) catch break :blk;
|
||||||
@ -1577,6 +1600,9 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) !types.In
|
|||||||
if (version.major == 0) {
|
if (version.major == 0) {
|
||||||
server.config.include_at_in_builtins = true;
|
server.config.include_at_in_builtins = true;
|
||||||
}
|
}
|
||||||
|
} else if (std.mem.eql(u8, clientInfo.name, "Visual Studio Code")) {
|
||||||
|
server.client_capabilities.supports_code_action_fixall = true;
|
||||||
|
skip_set_fixall = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1604,8 +1630,6 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) !types.In
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request.capabilities.textDocument) |textDocument| {
|
if (request.capabilities.textDocument) |textDocument| {
|
||||||
server.client_capabilities.supports_semantic_tokens = textDocument.semanticTokens != null;
|
|
||||||
server.client_capabilities.supports_inlay_hints = textDocument.inlayHint != null;
|
|
||||||
server.client_capabilities.supports_publish_diagnostics = textDocument.publishDiagnostics != null;
|
server.client_capabilities.supports_publish_diagnostics = textDocument.publishDiagnostics != null;
|
||||||
if (textDocument.hover) |hover| {
|
if (textDocument.hover) |hover| {
|
||||||
if (hover.contentFormat) |content_format| {
|
if (hover.contentFormat) |content_format| {
|
||||||
@ -1635,6 +1659,14 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) !types.In
|
|||||||
server.client_capabilities.supports_will_save = synchronization.willSave orelse false;
|
server.client_capabilities.supports_will_save = synchronization.willSave orelse false;
|
||||||
server.client_capabilities.supports_will_save_wait_until = synchronization.willSaveWaitUntil orelse false;
|
server.client_capabilities.supports_will_save_wait_until = synchronization.willSaveWaitUntil orelse false;
|
||||||
}
|
}
|
||||||
|
if (textDocument.codeAction) |codeaction| {
|
||||||
|
if (codeaction.codeActionLiteralSupport) |literlSupport| {
|
||||||
|
if (!skip_set_fixall) {
|
||||||
|
const fixall = std.mem.indexOfScalar(types.CodeActionKind, literlSupport.codeActionKind.valueSet, .@"source.fixAll") != null;
|
||||||
|
server.client_capabilities.supports_code_action_fixall = fixall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: everything is initialized, we got the client capabilities
|
// NOTE: everything is initialized, we got the client capabilities
|
||||||
@ -1646,6 +1678,7 @@ fn initializeHandler(server: *Server, request: types.InitializeParams) !types.In
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request.capabilities.workspace) |workspace| {
|
if (request.capabilities.workspace) |workspace| {
|
||||||
|
server.client_capabilities.supports_apply_edits = workspace.applyEdit orelse false;
|
||||||
server.client_capabilities.supports_configuration = workspace.configuration orelse false;
|
server.client_capabilities.supports_configuration = workspace.configuration orelse false;
|
||||||
if (workspace.didChangeConfiguration) |did_change| {
|
if (workspace.didChangeConfiguration) |did_change| {
|
||||||
if (did_change.dynamicRegistration orelse false) {
|
if (did_change.dynamicRegistration orelse false) {
|
||||||
@ -1943,12 +1976,7 @@ fn saveDocumentHandler(server: *Server, notification: types.DidSaveTextDocumentP
|
|||||||
const handle = server.document_store.getHandle(uri) orelse return;
|
const handle = server.document_store.getHandle(uri) orelse return;
|
||||||
try server.document_store.applySave(handle);
|
try server.document_store.applySave(handle);
|
||||||
|
|
||||||
if (handle.tree.errors.len != 0) return;
|
if (server.getAutofixMode() == .on_save) {
|
||||||
if (!server.config.enable_ast_check_diagnostics) return;
|
|
||||||
if (!server.config.enable_autofix) return;
|
|
||||||
if (server.client_capabilities.supports_will_save) return;
|
|
||||||
if (server.client_capabilities.supports_will_save_wait_until) return;
|
|
||||||
|
|
||||||
var text_edits = try server.autofix(allocator, handle);
|
var text_edits = try server.autofix(allocator, handle);
|
||||||
|
|
||||||
var workspace_edit = types.WorkspaceEdit{ .changes = .{} };
|
var workspace_edit = types.WorkspaceEdit{ .changes = .{} };
|
||||||
@ -1962,6 +1990,7 @@ fn saveDocumentHandler(server: *Server, notification: types.DidSaveTextDocumentP
|
|||||||
.edit = workspace_edit,
|
.edit = workspace_edit,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closeDocumentHandler(server: *Server, notification: types.DidCloseTextDocumentParams) error{}!void {
|
fn closeDocumentHandler(server: *Server, notification: types.DidCloseTextDocumentParams) error{}!void {
|
||||||
@ -1971,27 +2000,15 @@ fn closeDocumentHandler(server: *Server, notification: types.DidCloseTextDocumen
|
|||||||
server.document_store.closeDocument(notification.textDocument.uri);
|
server.document_store.closeDocument(notification.textDocument.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn willSaveHandler(server: *Server, request: types.WillSaveTextDocumentParams) !?[]types.TextEdit {
|
|
||||||
const tracy_zone = tracy.trace(@src());
|
|
||||||
defer tracy_zone.end();
|
|
||||||
|
|
||||||
if (server.client_capabilities.supports_will_save_wait_until) return null;
|
|
||||||
return try willSaveWaitUntilHandler(server, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn willSaveWaitUntilHandler(server: *Server, request: types.WillSaveTextDocumentParams) !?[]types.TextEdit {
|
fn willSaveWaitUntilHandler(server: *Server, request: types.WillSaveTextDocumentParams) !?[]types.TextEdit {
|
||||||
const tracy_zone = tracy.trace(@src());
|
const tracy_zone = tracy.trace(@src());
|
||||||
defer tracy_zone.end();
|
defer tracy_zone.end();
|
||||||
|
|
||||||
const allocator = server.arena.allocator();
|
const allocator = server.arena.allocator();
|
||||||
|
|
||||||
if (!server.config.enable_ast_check_diagnostics) return null;
|
if (server.getAutofixMode() != .will_save_wait_until) return null;
|
||||||
if (!server.config.enable_autofix) return null;
|
|
||||||
|
|
||||||
const uri = request.textDocument.uri;
|
const handle = server.document_store.getHandle(request.textDocument.uri) orelse return null;
|
||||||
|
|
||||||
const handle = server.document_store.getHandle(uri) orelse return null;
|
|
||||||
if (handle.tree.errors.len != 0) return null;
|
|
||||||
|
|
||||||
var text_edits = try server.autofix(allocator, handle);
|
var text_edits = try server.autofix(allocator, handle);
|
||||||
|
|
||||||
@ -2422,15 +2439,15 @@ fn codeActionHandler(server: *Server, request: types.CodeActionParams) !?[]types
|
|||||||
.offset_encoding = server.offset_encoding,
|
.offset_encoding = server.offset_encoding,
|
||||||
};
|
};
|
||||||
|
|
||||||
var actions = std.ArrayListUnmanaged(types.CodeAction){};
|
// as of right now, only ast-check errors may get a code action
|
||||||
|
var diagnostics = std.ArrayListUnmanaged(types.Diagnostic){};
|
||||||
for (request.context.diagnostics) |diagnostic| {
|
if (server.config.enable_ast_check_diagnostics and handle.tree.errors.len == 0) {
|
||||||
try builder.generateCodeAction(diagnostic, &actions);
|
try getAstCheckDiagnostics(server, handle.*, &diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (actions.items) |*action| {
|
var actions = std.ArrayListUnmanaged(types.CodeAction){};
|
||||||
// TODO query whether SourceFixAll is supported by the server
|
for (diagnostics.items) |diagnostic| {
|
||||||
if (action.kind.? == .@"source.fixAll") action.kind = .quickfix;
|
try builder.generateCodeAction(diagnostic, &actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions.items;
|
return actions.items;
|
||||||
@ -2981,7 +2998,6 @@ fn processMessage(server: *Server, message: Message) Error!void {
|
|||||||
.{ "textDocument/didChange", changeDocumentHandler },
|
.{ "textDocument/didChange", changeDocumentHandler },
|
||||||
.{ "textDocument/didSave", saveDocumentHandler },
|
.{ "textDocument/didSave", saveDocumentHandler },
|
||||||
.{ "textDocument/didClose", closeDocumentHandler },
|
.{ "textDocument/didClose", closeDocumentHandler },
|
||||||
.{ "textDocument/willSave", willSaveHandler },
|
|
||||||
.{ "textDocument/willSaveWaitUntil", willSaveWaitUntilHandler },
|
.{ "textDocument/willSaveWaitUntil", willSaveWaitUntilHandler },
|
||||||
.{ "textDocument/semanticTokens/full", semanticTokensFullHandler },
|
.{ "textDocument/semanticTokens/full", semanticTokensFullHandler },
|
||||||
.{ "textDocument/inlayHint", inlayHintHandler },
|
.{ "textDocument/inlayHint", inlayHintHandler },
|
||||||
|
@ -1466,7 +1466,7 @@ pub fn getImportStr(tree: Ast, node: Ast.Node.Index, source_index: usize) ?[]con
|
|||||||
|
|
||||||
if (params.len != 1) return null;
|
if (params.len != 1) return null;
|
||||||
|
|
||||||
if(node_tags[params[0]] != .string_literal) return null;
|
if (node_tags[params[0]] != .string_literal) return null;
|
||||||
|
|
||||||
const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]);
|
const import_str = tree.tokenSlice(tree.nodes.items(.main_token)[params[0]]);
|
||||||
return import_str[1 .. import_str.len - 1];
|
return import_str[1 .. import_str.len - 1];
|
||||||
|
@ -539,7 +539,7 @@ pub fn lastToken(tree: Ast, node: Ast.Node.Index) Ast.TokenIndex {
|
|||||||
.container_decl_arg_trailing,
|
.container_decl_arg_trailing,
|
||||||
.switch_comma,
|
.switch_comma,
|
||||||
=> {
|
=> {
|
||||||
if(datas[n].rhs != 0) {
|
if (datas[n].rhs != 0) {
|
||||||
const members = tree.extraData(datas[n].rhs, Node.SubRange);
|
const members = tree.extraData(datas[n].rhs, Node.SubRange);
|
||||||
std.debug.assert(members.end - members.start > 0);
|
std.debug.assert(members.end - members.start > 0);
|
||||||
end_offset += 2; // for the comma + rbrace
|
end_offset += 2; // for the comma + rbrace
|
||||||
|
@ -188,14 +188,14 @@ fn generateVSCodeConfigFile(allocator: std.mem.Allocator, config: Config, path:
|
|||||||
configuration.putAssumeCapacityNoClobber("trace.server", .{
|
configuration.putAssumeCapacityNoClobber("trace.server", .{
|
||||||
.scope = "window",
|
.scope = "window",
|
||||||
.type = "string",
|
.type = "string",
|
||||||
.@"enum" = &.{"off", "message", "verbose"},
|
.@"enum" = &.{ "off", "message", "verbose" },
|
||||||
.description = "Traces the communication between VS Code and the language server.",
|
.description = "Traces the communication between VS Code and the language server.",
|
||||||
.default = .{.String = "off"},
|
.default = .{ .String = "off" },
|
||||||
});
|
});
|
||||||
configuration.putAssumeCapacityNoClobber("check_for_update", .{
|
configuration.putAssumeCapacityNoClobber("check_for_update", .{
|
||||||
.type = "boolean",
|
.type = "boolean",
|
||||||
.description = "Whether to automatically check for new updates",
|
.description = "Whether to automatically check for new updates",
|
||||||
.default = .{.Bool = true},
|
.default = .{ .Bool = true },
|
||||||
});
|
});
|
||||||
configuration.putAssumeCapacityNoClobber("path", .{
|
configuration.putAssumeCapacityNoClobber("path", .{
|
||||||
.type = "string",
|
.type = "string",
|
||||||
@ -214,7 +214,7 @@ fn generateVSCodeConfigFile(allocator: std.mem.Allocator, config: Config, path:
|
|||||||
.type = try zigTypeToTypescript(option.type),
|
.type = try zigTypeToTypescript(option.type),
|
||||||
.description = option.description,
|
.description = option.description,
|
||||||
.format = if (std.mem.indexOf(u8, option.name, "path") != null) "path" else null,
|
.format = if (std.mem.indexOf(u8, option.name, "path") != null) "path" else null,
|
||||||
.default = if(default == .Null) null else default,
|
.default = if (default == .Null) null else default,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user