2021-03-29 10:28:52 +01:00
|
|
|
//! This file contains request types zls handles.
|
|
|
|
//! Note that the parameter types may be incomplete.
|
|
|
|
//! We only define what we actually use.
|
|
|
|
|
2020-06-29 23:34:21 +01:00
|
|
|
const std = @import("std");
|
2022-07-15 17:06:18 +01:00
|
|
|
const types = @import("types.zig");
|
2020-06-29 23:34:21 +01:00
|
|
|
|
|
|
|
/// Only check for the field's existence.
|
|
|
|
const Exists = struct {
|
|
|
|
exists: bool,
|
|
|
|
};
|
|
|
|
|
|
|
|
fn Default(comptime T: type, comptime default_value: T) type {
|
|
|
|
return struct {
|
|
|
|
pub const value_type = T;
|
|
|
|
pub const default = default_value;
|
|
|
|
value: T,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-01 12:14:49 +01:00
|
|
|
pub fn ErrorUnwrappedReturnOf(comptime func: anytype) type {
|
|
|
|
return switch (@typeInfo(@TypeOf(func))) {
|
|
|
|
.Fn, .BoundFn => |fn_info| switch (@typeInfo(fn_info.return_type.?)) {
|
|
|
|
.ErrorUnion => |err_union| err_union.payload,
|
|
|
|
else => |T| return T,
|
|
|
|
},
|
|
|
|
else => unreachable,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-07-12 20:12:09 +01:00
|
|
|
fn Transform(comptime Original: type, comptime transform_fn: anytype) type {
|
2020-06-29 23:34:21 +01:00
|
|
|
return struct {
|
|
|
|
pub const original_type = Original;
|
|
|
|
pub const transform = transform_fn;
|
|
|
|
|
2021-04-01 12:14:49 +01:00
|
|
|
value: ErrorUnwrappedReturnOf(transform_fn),
|
2020-06-29 23:34:21 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-02-15 10:04:22 +00:00
|
|
|
fn fromDynamicTreeInternal(arena: *std.heap.ArenaAllocator, value: std.json.Value, out: anytype) error{ MalformedJson, OutOfMemory }!void {
|
2020-06-29 23:34:21 +01:00
|
|
|
const T = comptime std.meta.Child(@TypeOf(out));
|
|
|
|
|
|
|
|
if (comptime std.meta.trait.is(.Struct)(T)) {
|
|
|
|
if (value != .Object) return error.MalformedJson;
|
|
|
|
|
|
|
|
var err = false;
|
|
|
|
inline for (std.meta.fields(T)) |field| {
|
|
|
|
const is_exists = field.field_type == Exists;
|
|
|
|
|
|
|
|
const is_optional = comptime std.meta.trait.is(.Optional)(field.field_type);
|
|
|
|
const actual_type = if (is_optional) std.meta.Child(field.field_type) else field.field_type;
|
|
|
|
|
|
|
|
const is_struct = comptime std.meta.trait.is(.Struct)(actual_type);
|
2021-10-01 02:45:45 +01:00
|
|
|
const is_default = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ "default", "value_type" }) else false;
|
|
|
|
const is_transform = comptime if (is_struct) std.meta.trait.hasDecls(actual_type, .{ "original_type", "transform" }) else false;
|
2020-06-29 23:34:21 +01:00
|
|
|
|
2020-07-05 22:56:41 +01:00
|
|
|
if (value.Object.get(field.name)) |json_field| {
|
2020-06-29 23:34:21 +01:00
|
|
|
if (is_exists) {
|
|
|
|
@field(out, field.name) = Exists{ .exists = true };
|
|
|
|
} else if (is_transform) {
|
|
|
|
var original_value: actual_type.original_type = undefined;
|
|
|
|
try fromDynamicTreeInternal(arena, json_field, &original_value);
|
2021-03-29 10:28:52 +01:00
|
|
|
@field(out, field.name) = actual_type{
|
|
|
|
.value = actual_type.transform(original_value) catch
|
|
|
|
return error.MalformedJson,
|
|
|
|
};
|
2020-06-29 23:34:21 +01:00
|
|
|
} else if (is_default) {
|
|
|
|
try fromDynamicTreeInternal(arena, json_field, &@field(out, field.name).value);
|
|
|
|
} else if (is_optional) {
|
|
|
|
if (json_field == .Null) {
|
|
|
|
@field(out, field.name) = null;
|
|
|
|
} else {
|
|
|
|
var actual_value: actual_type = undefined;
|
|
|
|
try fromDynamicTreeInternal(arena, json_field, &actual_value);
|
|
|
|
@field(out, field.name) = actual_value;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
try fromDynamicTreeInternal(arena, json_field, &@field(out, field.name));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (is_exists) {
|
|
|
|
@field(out, field.name) = Exists{ .exists = false };
|
|
|
|
} else if (is_optional) {
|
|
|
|
@field(out, field.name) = null;
|
|
|
|
} else if (is_default) {
|
|
|
|
@field(out, field.name) = actual_type{ .value = actual_type.default };
|
|
|
|
} else {
|
|
|
|
err = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (err) return error.MalformedJson;
|
|
|
|
} else if (comptime (std.meta.trait.isSlice(T) and T != []const u8)) {
|
|
|
|
if (value != .Array) return error.MalformedJson;
|
|
|
|
const Child = std.meta.Child(T);
|
|
|
|
|
|
|
|
if (value.Array.items.len == 0) {
|
|
|
|
out.* = &[0]Child{};
|
|
|
|
} else {
|
2021-12-02 05:16:15 +00:00
|
|
|
var slice = try arena.allocator().alloc(Child, value.Array.items.len);
|
2020-06-29 23:34:21 +01:00
|
|
|
for (value.Array.items) |arr_item, idx| {
|
|
|
|
try fromDynamicTreeInternal(arena, arr_item, &slice[idx]);
|
|
|
|
}
|
|
|
|
out.* = slice;
|
|
|
|
}
|
|
|
|
} else if (T == std.json.Value) {
|
|
|
|
out.* = value;
|
2021-04-01 12:14:49 +01:00
|
|
|
} else if (comptime std.meta.trait.is(.Enum)(T)) {
|
|
|
|
const info = @typeInfo(T).Enum;
|
|
|
|
if (info.layout != .Auto)
|
|
|
|
@compileError("Only auto layout enums are allowed");
|
|
|
|
|
|
|
|
const TagType = info.tag_type;
|
|
|
|
if (value != .Integer) return error.MalformedJson;
|
|
|
|
out.* = std.meta.intToEnum(
|
|
|
|
T,
|
2022-05-29 18:17:43 +01:00
|
|
|
std.math.cast(TagType, value.Integer) orelse return error.MalformedJson,
|
2021-04-01 12:14:49 +01:00
|
|
|
) catch return error.MalformedJson;
|
|
|
|
} else if (comptime std.meta.trait.is(.Int)(T)) {
|
|
|
|
if (value != .Integer) return error.MalformedJson;
|
2022-05-29 18:17:43 +01:00
|
|
|
out.* = std.math.cast(T, value.Integer) orelse return error.MalformedJson;
|
2021-04-01 12:14:49 +01:00
|
|
|
} else switch (T) {
|
|
|
|
bool => {
|
|
|
|
if (value != .Bool) return error.MalformedJson;
|
|
|
|
out.* = value.Bool;
|
|
|
|
},
|
|
|
|
f64 => {
|
|
|
|
if (value != .Float) return error.MalformedJson;
|
|
|
|
out.* = value.Float;
|
|
|
|
},
|
|
|
|
[]const u8 => {
|
|
|
|
if (value != .String) return error.MalformedJson;
|
|
|
|
out.* = value.String;
|
|
|
|
},
|
|
|
|
else => @compileError("Invalid type " ++ @typeName(T)),
|
2020-06-29 23:34:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fromDynamicTree(arena: *std.heap.ArenaAllocator, comptime T: type, value: std.json.Value) error{ MalformedJson, OutOfMemory }!T {
|
|
|
|
var out: T = undefined;
|
|
|
|
try fromDynamicTreeInternal(arena, value, &out);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2021-03-29 10:28:52 +01:00
|
|
|
const MaybeStringArray = Default([]const []const u8, &.{});
|
2020-06-29 23:34:21 +01:00
|
|
|
|
|
|
|
pub const Initialize = struct {
|
|
|
|
pub const ClientCapabilities = struct {
|
|
|
|
workspace: ?struct {
|
2021-12-17 01:41:21 +00:00
|
|
|
configuration: Default(bool, false),
|
2022-07-11 14:45:31 +01:00
|
|
|
didChangeConfiguration: ?struct {
|
|
|
|
dynamicRegistration: Default(bool, false), // NOTE: Should this be true? Seems like this critical feature should be nearly universal
|
|
|
|
},
|
2020-06-29 23:34:21 +01:00
|
|
|
workspaceFolders: Default(bool, false),
|
|
|
|
},
|
|
|
|
textDocument: ?struct {
|
|
|
|
semanticTokens: Exists,
|
2022-07-24 12:38:13 +01:00
|
|
|
inlayHint: Exists,
|
2020-06-29 23:34:21 +01:00
|
|
|
hover: ?struct {
|
|
|
|
contentFormat: MaybeStringArray,
|
|
|
|
},
|
|
|
|
completion: ?struct {
|
|
|
|
completionItem: ?struct {
|
|
|
|
snippetSupport: Default(bool, false),
|
2022-06-23 15:44:01 +01:00
|
|
|
labelDetailsSupport: Default(bool, true),
|
2020-06-29 23:34:21 +01:00
|
|
|
documentationFormat: MaybeStringArray,
|
|
|
|
},
|
|
|
|
},
|
2022-05-08 04:03:40 +01:00
|
|
|
documentHighlight: Exists,
|
2020-06-29 23:34:21 +01:00
|
|
|
},
|
2020-07-03 10:00:00 +01:00
|
|
|
offsetEncoding: MaybeStringArray,
|
2020-06-29 23:34:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
params: struct {
|
|
|
|
capabilities: ClientCapabilities,
|
|
|
|
workspaceFolders: ?[]const types.WorkspaceFolder,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const WorkspaceFoldersChange = struct {
|
|
|
|
params: struct {
|
|
|
|
event: struct {
|
|
|
|
added: []const types.WorkspaceFolder,
|
|
|
|
removed: []const types.WorkspaceFolder,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const OpenDocument = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: struct {
|
2020-11-06 08:08:20 +00:00
|
|
|
uri: []const u8,
|
|
|
|
text: []const u8,
|
2020-06-29 23:34:21 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const TextDocumentIdentifier = struct {
|
2020-11-06 08:08:20 +00:00
|
|
|
uri: []const u8,
|
2020-06-29 23:34:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
pub const ChangeDocument = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
contentChanges: std.json.Value,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const TextDocumentIdentifierRequest = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const SaveDocument = TextDocumentIdentifierRequest;
|
|
|
|
pub const CloseDocument = TextDocumentIdentifierRequest;
|
2020-09-25 22:24:10 +01:00
|
|
|
pub const SemanticTokensFull = TextDocumentIdentifierRequest;
|
2020-06-30 13:46:43 +01:00
|
|
|
|
|
|
|
const TextDocumentIdentifierPositionRequest = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
position: types.Position,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-04-01 12:14:49 +01:00
|
|
|
pub const SignatureHelp = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
position: types.Position,
|
|
|
|
context: ?struct {
|
2021-06-24 11:38:01 +01:00
|
|
|
triggerKind: enum(u32) {
|
2021-04-01 12:14:49 +01:00
|
|
|
invoked = 1,
|
|
|
|
trigger_character = 2,
|
|
|
|
content_change = 3,
|
|
|
|
},
|
|
|
|
triggerCharacter: ?[]const u8,
|
|
|
|
isRetrigger: bool,
|
|
|
|
activeSignatureHelp: ?types.SignatureHelp,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-06-30 13:46:43 +01:00
|
|
|
pub const Completion = TextDocumentIdentifierPositionRequest;
|
|
|
|
pub const GotoDefinition = TextDocumentIdentifierPositionRequest;
|
|
|
|
pub const GotoDeclaration = TextDocumentIdentifierPositionRequest;
|
|
|
|
pub const Hover = TextDocumentIdentifierPositionRequest;
|
|
|
|
pub const DocumentSymbols = TextDocumentIdentifierRequest;
|
|
|
|
pub const Formatting = TextDocumentIdentifierRequest;
|
2022-05-08 04:03:40 +01:00
|
|
|
pub const DocumentHighlight = TextDocumentIdentifierPositionRequest;
|
2020-06-30 13:46:43 +01:00
|
|
|
pub const Rename = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
position: types.Position,
|
2020-11-06 08:08:20 +00:00
|
|
|
newName: []const u8,
|
2020-06-30 13:46:43 +01:00
|
|
|
},
|
|
|
|
};
|
2020-07-05 22:35:52 +01:00
|
|
|
|
2020-07-05 23:32:14 +01:00
|
|
|
pub const References = struct {
|
2020-07-05 22:35:52 +01:00
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
position: types.Position,
|
2020-07-05 23:32:14 +01:00
|
|
|
context: struct {
|
|
|
|
includeDeclaration: bool,
|
|
|
|
},
|
2020-07-05 22:35:52 +01:00
|
|
|
},
|
|
|
|
};
|
2021-12-17 01:41:21 +00:00
|
|
|
|
2022-07-24 12:38:13 +01:00
|
|
|
pub const InlayHint = struct {
|
|
|
|
params: struct {
|
|
|
|
textDocument: TextDocumentIdentifier,
|
|
|
|
range: types.Range,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-12-17 01:41:21 +00:00
|
|
|
pub const Configuration = struct {
|
|
|
|
params: struct {
|
|
|
|
settings: struct {
|
|
|
|
enable_snippets: ?bool,
|
2022-07-08 09:13:46 +01:00
|
|
|
enable_unused_variable_warnings: ?bool,
|
2022-07-09 10:22:02 +01:00
|
|
|
enable_import_embedfile_argument_completions: ?bool,
|
2021-12-17 01:41:21 +00:00
|
|
|
zig_lib_path: ?[]const u8,
|
|
|
|
zig_exe_path: ?[]const u8,
|
|
|
|
warn_style: ?bool,
|
|
|
|
build_runner_path: ?[]const u8,
|
|
|
|
build_runner_cache_path: ?[]const u8,
|
|
|
|
enable_semantic_tokens: ?bool,
|
2022-07-24 12:38:13 +01:00
|
|
|
enable_inlay_hints: ?bool,
|
|
|
|
inlay_hints_show_builtin: ?bool,
|
|
|
|
inlay_hints_exclude_single_argument: ?bool,
|
2021-12-17 01:41:21 +00:00
|
|
|
operator_completions: ?bool,
|
|
|
|
include_at_in_builtins: ?bool,
|
|
|
|
max_detail_length: ?usize,
|
|
|
|
skip_std_references: ?bool,
|
2022-06-05 18:26:56 +01:00
|
|
|
builtin_path: ?[]const u8,
|
2021-12-17 01:41:21 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|