use textDocument/willSaveWaitUntil for autofix (#780)
This commit is contained in:
parent
29679ee6f8
commit
aa14772cfe
@ -52,6 +52,8 @@ const ClientCapabilities = struct {
|
|||||||
supports_snippets: bool = false,
|
supports_snippets: bool = false,
|
||||||
supports_semantic_tokens: bool = false,
|
supports_semantic_tokens: bool = false,
|
||||||
supports_inlay_hints: bool = false,
|
supports_inlay_hints: bool = false,
|
||||||
|
supports_will_save: bool = false,
|
||||||
|
supports_will_save_wait_until: 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,
|
||||||
@ -445,6 +447,36 @@ fn getAstCheckDiagnostics(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// caller owns returned memory.
|
||||||
|
fn autofix(server: *Server, allocator: std.mem.Allocator, handle: *const DocumentStore.Handle) !std.ArrayListUnmanaged(types.TextEdit) {
|
||||||
|
var diagnostics = std.ArrayListUnmanaged(types.Diagnostic){};
|
||||||
|
try getAstCheckDiagnostics(server, handle.*, &diagnostics);
|
||||||
|
|
||||||
|
var builder = code_actions.Builder{
|
||||||
|
.arena = &server.arena,
|
||||||
|
.document_store = &server.document_store,
|
||||||
|
.handle = handle,
|
||||||
|
.offset_encoding = server.offset_encoding,
|
||||||
|
};
|
||||||
|
|
||||||
|
var actions = std.ArrayListUnmanaged(types.CodeAction){};
|
||||||
|
for (diagnostics.items) |diagnostic| {
|
||||||
|
try builder.generateCodeAction(diagnostic, &actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
var text_edits = std.ArrayListUnmanaged(types.TextEdit){};
|
||||||
|
for (actions.items) |action| {
|
||||||
|
if (action.kind != .SourceFixAll) continue;
|
||||||
|
|
||||||
|
if (action.edit.changes.size != 1) continue;
|
||||||
|
const edits = action.edit.changes.get(handle.uri) orelse continue;
|
||||||
|
|
||||||
|
try text_edits.appendSlice(allocator, edits.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
return text_edits;
|
||||||
|
}
|
||||||
|
|
||||||
fn typeToCompletion(
|
fn typeToCompletion(
|
||||||
server: *Server,
|
server: *Server,
|
||||||
list: *std.ArrayListUnmanaged(types.CompletionItem),
|
list: *std.ArrayListUnmanaged(types.CompletionItem),
|
||||||
@ -1580,6 +1612,10 @@ fn initializeHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(textDocument.synchronization) |synchronization| {
|
||||||
|
server.client_capabilities.supports_will_save = synchronization.willSave.value;
|
||||||
|
server.client_capabilities.supports_will_save_wait_until = synchronization.willSaveWaitUntil.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: everything is initialized, we got the client capabilities
|
// NOTE: everything is initialized, we got the client capabilities
|
||||||
@ -1608,6 +1644,8 @@ fn initializeHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
.openClose = true,
|
.openClose = true,
|
||||||
.change = .Incremental,
|
.change = .Incremental,
|
||||||
.save = true,
|
.save = true,
|
||||||
|
.willSave = true,
|
||||||
|
.willSaveWaitUntil = true,
|
||||||
},
|
},
|
||||||
.renameProvider = true,
|
.renameProvider = true,
|
||||||
.completionProvider = .{ .resolveProvider = false, .triggerCharacters = &[_][]const u8{ ".", ":", "@", "]" }, .completionItem = .{ .labelDetailsSupport = true } },
|
.completionProvider = .{ .resolveProvider = false, .triggerCharacters = &[_][]const u8{ ".", ":", "@", "]" }, .completionItem = .{ .labelDetailsSupport = true } },
|
||||||
@ -1832,31 +1870,10 @@ fn saveDocumentHandler(server: *Server, writer: anytype, id: types.RequestId, re
|
|||||||
if (handle.tree.errors.len != 0) return;
|
if (handle.tree.errors.len != 0) return;
|
||||||
if (!server.config.enable_ast_check_diagnostics) return;
|
if (!server.config.enable_ast_check_diagnostics) return;
|
||||||
if (!server.config.enable_autofix) 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 diagnostics = std.ArrayListUnmanaged(types.Diagnostic){};
|
const text_edits = try server.autofix(allocator, handle);
|
||||||
try getAstCheckDiagnostics(server, handle.*, &diagnostics);
|
|
||||||
|
|
||||||
var builder = code_actions.Builder{
|
|
||||||
.arena = &server.arena,
|
|
||||||
.document_store = &server.document_store,
|
|
||||||
.handle = handle,
|
|
||||||
.offset_encoding = server.offset_encoding,
|
|
||||||
};
|
|
||||||
|
|
||||||
var actions = std.ArrayListUnmanaged(types.CodeAction){};
|
|
||||||
for (diagnostics.items) |diagnostic| {
|
|
||||||
try builder.generateCodeAction(diagnostic, &actions);
|
|
||||||
}
|
|
||||||
|
|
||||||
var text_edits = std.ArrayListUnmanaged(types.TextEdit){};
|
|
||||||
for (actions.items) |action| {
|
|
||||||
if (action.kind != .SourceFixAll) continue;
|
|
||||||
|
|
||||||
if (action.edit.changes.size != 1) continue;
|
|
||||||
const edits = action.edit.changes.get(uri) orelse continue;
|
|
||||||
|
|
||||||
try text_edits.appendSlice(allocator, edits.items);
|
|
||||||
}
|
|
||||||
|
|
||||||
var workspace_edit = types.WorkspaceEdit{ .changes = .{} };
|
var workspace_edit = types.WorkspaceEdit{ .changes = .{} };
|
||||||
try workspace_edit.changes.putNoClobber(allocator, uri, text_edits);
|
try workspace_edit.changes.putNoClobber(allocator, uri, text_edits);
|
||||||
@ -1885,6 +1902,35 @@ fn closeDocumentHandler(server: *Server, writer: anytype, id: types.RequestId, r
|
|||||||
server.document_store.closeDocument(req.params.textDocument.uri);
|
server.document_store.closeDocument(req.params.textDocument.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn willSaveHandler(server: *Server, writer: anytype, id: types.RequestId, req: requests.WillSave) !void {
|
||||||
|
const tracy_zone = tracy.trace(@src());
|
||||||
|
defer tracy_zone.end();
|
||||||
|
|
||||||
|
if(server.client_capabilities.supports_will_save_wait_until) return;
|
||||||
|
try willSaveWaitUntilHandler(server, writer, id, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn willSaveWaitUntilHandler(server: *Server, writer: anytype, id: types.RequestId, req: requests.WillSave) !void {
|
||||||
|
const tracy_zone = tracy.trace(@src());
|
||||||
|
defer tracy_zone.end();
|
||||||
|
|
||||||
|
if (!server.config.enable_ast_check_diagnostics) return;
|
||||||
|
if (!server.config.enable_autofix) return;
|
||||||
|
|
||||||
|
const allocator = server.arena.allocator();
|
||||||
|
const uri = req.params.textDocument.uri;
|
||||||
|
|
||||||
|
const handle = server.document_store.getHandle(uri) orelse return;
|
||||||
|
if (handle.tree.errors.len != 0) return;
|
||||||
|
|
||||||
|
var text_edits = try server.autofix(allocator, handle);
|
||||||
|
|
||||||
|
return try send(writer, allocator, types.Response{
|
||||||
|
.id = id,
|
||||||
|
.result = .{.TextEdits = text_edits.toOwnedSlice(allocator)},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn semanticTokensFullHandler(server: *Server, writer: anytype, id: types.RequestId, req: requests.SemanticTokensFull) !void {
|
fn semanticTokensFullHandler(server: *Server, writer: anytype, id: types.RequestId, req: requests.SemanticTokensFull) !void {
|
||||||
const tracy_zone = tracy.trace(@src());
|
const tracy_zone = tracy.trace(@src());
|
||||||
defer tracy_zone.end();
|
defer tracy_zone.end();
|
||||||
@ -2764,7 +2810,6 @@ pub fn processJsonRpc(server: *Server, writer: anytype, json: []const u8) !void
|
|||||||
const method_map = .{
|
const method_map = .{
|
||||||
.{ "initialized", void, initializedHandler },
|
.{ "initialized", void, initializedHandler },
|
||||||
.{"$/cancelRequest"},
|
.{"$/cancelRequest"},
|
||||||
.{"textDocument/willSave"},
|
|
||||||
.{ "initialize", requests.Initialize, initializeHandler },
|
.{ "initialize", requests.Initialize, initializeHandler },
|
||||||
.{ "shutdown", void, shutdownHandler },
|
.{ "shutdown", void, shutdownHandler },
|
||||||
.{ "exit", void, exitHandler },
|
.{ "exit", void, exitHandler },
|
||||||
@ -2772,6 +2817,8 @@ pub fn processJsonRpc(server: *Server, writer: anytype, json: []const u8) !void
|
|||||||
.{ "textDocument/didChange", requests.ChangeDocument, changeDocumentHandler },
|
.{ "textDocument/didChange", requests.ChangeDocument, changeDocumentHandler },
|
||||||
.{ "textDocument/didSave", requests.SaveDocument, saveDocumentHandler },
|
.{ "textDocument/didSave", requests.SaveDocument, saveDocumentHandler },
|
||||||
.{ "textDocument/didClose", requests.CloseDocument, closeDocumentHandler },
|
.{ "textDocument/didClose", requests.CloseDocument, closeDocumentHandler },
|
||||||
|
.{"textDocument/willSave", requests.WillSave, willSaveHandler},
|
||||||
|
.{"textDocument/willSaveWaitUntil", requests.WillSave, willSaveWaitUntilHandler},
|
||||||
.{ "textDocument/semanticTokens/full", requests.SemanticTokensFull, semanticTokensFullHandler },
|
.{ "textDocument/semanticTokens/full", requests.SemanticTokensFull, semanticTokensFullHandler },
|
||||||
.{ "textDocument/inlayHint", requests.InlayHint, inlayHintHandler },
|
.{ "textDocument/inlayHint", requests.InlayHint, inlayHintHandler },
|
||||||
.{ "textDocument/completion", requests.Completion, completionHandler },
|
.{ "textDocument/completion", requests.Completion, completionHandler },
|
||||||
|
@ -154,6 +154,11 @@ pub const Initialize = struct {
|
|||||||
workspaceFolders: Default(bool, false),
|
workspaceFolders: Default(bool, false),
|
||||||
},
|
},
|
||||||
textDocument: ?struct {
|
textDocument: ?struct {
|
||||||
|
synchronization: ?struct {
|
||||||
|
willSave: Default(bool, false),
|
||||||
|
willSaveWaitUntil: Default(bool, false),
|
||||||
|
didSave: Default(bool, false),
|
||||||
|
},
|
||||||
semanticTokens: Exists,
|
semanticTokens: Exists,
|
||||||
inlayHint: Exists,
|
inlayHint: Exists,
|
||||||
hover: ?struct {
|
hover: ?struct {
|
||||||
@ -230,6 +235,19 @@ const TextDocumentIdentifierPositionRequest = struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const SaveReason = enum(u32) {
|
||||||
|
Manual = 1,
|
||||||
|
AfterDelay = 2,
|
||||||
|
FocusOut = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const WillSave = struct {
|
||||||
|
params: struct {
|
||||||
|
textDocument: TextDocumentIdentifier,
|
||||||
|
reason: SaveReason,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub const SignatureHelp = struct {
|
pub const SignatureHelp = struct {
|
||||||
params: struct {
|
params: struct {
|
||||||
textDocument: TextDocumentIdentifier,
|
textDocument: TextDocumentIdentifier,
|
||||||
|
@ -441,6 +441,8 @@ const InitializeResult = struct {
|
|||||||
textDocumentSync: struct {
|
textDocumentSync: struct {
|
||||||
openClose: bool,
|
openClose: bool,
|
||||||
change: TextDocumentSyncKind,
|
change: TextDocumentSyncKind,
|
||||||
|
willSave: bool,
|
||||||
|
willSaveWaitUntil: bool,
|
||||||
save: bool,
|
save: bool,
|
||||||
},
|
},
|
||||||
renameProvider: bool,
|
renameProvider: bool,
|
||||||
|
Loading…
Reference in New Issue
Block a user