From 108a2dbd64f764d414940870c6193642506e1e44 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Sat, 27 Jun 2020 20:45:58 +0300 Subject: [PATCH] Semantic highlighting improvements --- src/analysis.zig | 31 +++++++++++++++++++++++++++++++ src/main.zig | 2 +- src/semantic_tokens.zig | 24 +++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index f93fc24..bfb06f1 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -153,6 +153,15 @@ pub fn isTypeFunction(tree: *ast.Tree, func: *ast.Node.FnProto) bool { } } +// @TODO +pub fn isGenericFunction(tree: *ast.Tree, func: *ast.Node.FnProto) bool { + for (func.paramsConst()) |param| { + if (param.param_type == .var_type or param.comptime_token != null) { + return true; + } + } + return false; +} // STYLE pub fn isCamelCase(name: []const u8) bool { @@ -899,6 +908,16 @@ pub const TypeWithHandle = struct { return self.isContainer(.Keyword_struct) or self.isRoot(); } + pub fn isNamespace(self: TypeWithHandle) bool { + if (!self.isStructType()) return false; + var idx: usize = 0; + while (self.type.data.other.iterate(idx)) |child| : (idx += 1) { + if (child.id == .ContainerField) + return false; + } + return true; + } + pub fn isEnumType(self: TypeWithHandle) bool { return self.isContainer(.Keyword_enum); } @@ -919,6 +938,18 @@ pub const TypeWithHandle = struct { } } + pub fn isGenericFunc(self: TypeWithHandle) bool { + switch (self.type.data) { + .other => |n| { + if (n.cast(ast.Node.FnProto)) |fn_proto| { + return isGenericFunction(self.handle.tree, fn_proto); + } + return false; + }, + else => return false, + } + } + pub fn isFunc(self: TypeWithHandle) bool { switch (self.type.data) { .other => |n| { diff --git a/src/main.zig b/src/main.zig index 7f7176b..40c3670 100644 --- a/src/main.zig +++ b/src/main.zig @@ -86,7 +86,7 @@ const ClientCapabilities = struct { var client_capabilities = ClientCapabilities{}; const initialize_response = - \\,"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"]}}}}} + \\,"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": ["namespace","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 = diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index b5b967d..1f68f41 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -4,6 +4,7 @@ const analysis = @import("analysis.zig"); const ast = std.zig.ast; const TokenType = enum(u32) { + namespace, type, @"struct", @"enum", @@ -165,7 +166,9 @@ const GapHighlighter = struct { fn colorIdentifierBasedOnType(builder: *Builder, type_node: analysis.TypeWithHandle, target_tok: ast.TokenIndex, tok_mod: TokenModifiers) !void { if (type_node.type.is_type_val) { - const tok_type = if (type_node.isStructType()) + const tok_type = if (type_node.isNamespace()) + .namespace + else if (type_node.isStructType()) .@"struct" else if (type_node.isEnumType()) .@"enum" @@ -178,7 +181,11 @@ fn colorIdentifierBasedOnType(builder: *Builder, type_node: analysis.TypeWithHan } else if (type_node.isTypeFunc()) { try writeTokenMod(builder, target_tok, .type, tok_mod); } else if (type_node.isFunc()) { - try writeTokenMod(builder, target_tok, .function, tok_mod); + var new_tok_mod = tok_mod; + if (type_node.isGenericFunc()) { + new_tok_mod.set("generic"); + } + try writeTokenMod(builder, target_tok, .function, new_tok_mod); } else { try writeTokenMod(builder, target_tok, .variable, tok_mod); } @@ -334,7 +341,13 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D .type else .function; - try writeToken(builder, fn_proto.name_token, func_name_tok_type); + + const tok_mod = if (analysis.isGenericFunction(handle.tree, fn_proto)) + TokenModifiers{ .generic = true } + else + TokenModifiers{}; + + try writeTokenMod(builder, fn_proto.name_token, func_name_tok_type, tok_mod); for (fn_proto.paramsConst()) |param_decl| { if (param_decl.doc_comments) |docs| try writeDocComments(builder, handle.tree, docs); @@ -618,6 +631,11 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D const call = node.cast(ast.Node.Call).?; try writeToken(builder, call.async_token, .keyword); try await @asyncCall(child_frame, {}, writeNodeTokens, builder, arena, store, call.lhs); + if (builder.current_token) |curr_tok| { + if (curr_tok != call.lhs.lastToken() and handle.tree.token_ids[call.lhs.lastToken()] == .Identifier) { + try writeToken(builder, call.lhs.lastToken(), .function); + } + } for (call.paramsConst()) |param| try await @asyncCall(child_frame, {}, writeNodeTokens, builder, arena, store, param); }, .SuffixOp => {