diff --git a/README.md b/README.md index d2a557c..9773609 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ The following options are currently available. |`include_at_in_builtins`|`bool`|`false`| Whether the @ sign should be part of the completion of builtins. |`max_detail_length`|`usize`|`1024 * 1024`| The detail field of completions is truncated to be no longer than this (in bytes). | `skip_std_references` | `bool` | `false` | When true, skips searching for references in std. Improves lookup speed for functions in user's code. Renaming and go-to-definition will continue to work as is. +| `highlight_global_var_declarations` | `bool` | `false` | Whether to highlight global var declarations. ### Per-build Configuration Options diff --git a/schema.json b/schema.json index 2673418..2d0fd0f 100644 --- a/schema.json +++ b/schema.json @@ -94,6 +94,11 @@ "description": "When true, skips searching for references in std. Improves lookup speed for functions in user's code. Renaming and go-to-definition will continue to work as is", "type": "boolean", "default": "false" + }, + "highlight_global_var_declarations": { + "description": "Whether to highlight global var declarations", + "type": "boolean", + "default": "false" } } } diff --git a/src/Config.zig b/src/Config.zig index 623ce88..642a096 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -76,6 +76,9 @@ skip_std_references: bool = false, /// Path to "builtin;" useful for debugging, automatically set if let null builtin_path: ?[]const u8 = null, +/// Whether to highlight global var declarations. +highlight_global_var_declarations: bool = false, + pub fn loadFromFile(allocator: std.mem.Allocator, file_path: []const u8) ?Config { const tracy_zone = tracy.trace(@src()); defer tracy_zone.end(); diff --git a/src/Server.zig b/src/Server.zig index 3842236..1200a62 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -175,6 +175,24 @@ fn publishDiagnostics(server: *Server, writer: anytype, handle: DocumentStore.Ha }); } + for (handle.cimports) |cimport| { + if (cimport.result != .failure) continue; + const stderr = std.mem.trim(u8, cimport.result.failure, " "); + + var pos_and_diag_iterator = std.mem.split(u8, stderr, ":"); + _ = pos_and_diag_iterator.next(); // skip file path + _ = pos_and_diag_iterator.next(); // skip line + _ = pos_and_diag_iterator.next(); // skip character + + try diagnostics.append(allocator, .{ + .range = offsets.nodeToRange(handle.tree, cimport.node, server.offset_encoding), + .severity = .Error, + .code = "cImport", + .source = "zls", + .message = try allocator.dupe(u8, pos_and_diag_iterator.rest()), + }); + } + if (server.config.enable_ast_check_diagnostics and tree.errors.len == 0) { try getAstCheckDiagnostics(server, handle, &diagnostics); } @@ -270,6 +288,34 @@ fn publishDiagnostics(server: *Server, writer: anytype, handle: DocumentStore.Ha .source = "zls", .message = try allocator.dupe(u8, pos_and_diag_iterator.rest()), }); + + if (server.config.highlight_global_var_declarations) { + const main_tokens = tree.nodes.items(.main_token); + const tags = tree.tokens.items(.tag); + for (tree.rootDecls()) |decl| { + const decl_tag = tree.nodes.items(.tag)[decl]; + const decl_main_token = tree.nodes.items(.main_token)[decl]; + + switch (decl_tag) { + .simple_var_decl, + .aligned_var_decl, + .local_var_decl, + .global_var_decl, + => { + if (tags[main_tokens[decl]] != .keyword_var) continue; // skip anything immutable + // uncomment this to get a list :) + //log.debug("possible global variable \"{s}\"", .{tree.tokenSlice(decl_main_token + 1)}); + try diagnostics.append(allocator, .{ + .range = offsets.tokenToRange(tree, decl_main_token, server.offset_encoding), + .severity = .Hint, + .code = "highlight_global_var_declarations", + .source = "zls", + .message = "Global var declaration", + }); + }, + else => {}, + } + } } try send(writer, server.arena.allocator(), types.Notification{ diff --git a/src/analysis.zig b/src/analysis.zig index 168683d..d7a9605 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -2825,7 +2825,9 @@ fn makeScopeInternal(allocator: std.mem.Allocator, context: ScopeContext, node_i } }, .switch_case, + .switch_case_inline, .switch_case_one, + .switch_case_inline_one, .switch_range, => { return; diff --git a/src/ast.zig b/src/ast.zig index 29d433a..5056a9c 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -437,6 +437,8 @@ pub fn lastToken(tree: Ast, node: Ast.Node.Index) Ast.TokenIndex { .array_type, .switch_case_one, .switch_case, + .switch_case_inline_one, + .switch_case_inline, .switch_range, => n = datas[n].rhs, diff --git a/src/inlay_hints.zig b/src/inlay_hints.zig index 2c66e69..3609881 100644 --- a/src/inlay_hints.zig +++ b/src/inlay_hints.zig @@ -548,8 +548,10 @@ fn writeNodeInlayHint(builder: *Builder, arena: *std.heap.ArenaAllocator, store: .switch_case_one, .switch_case, + .switch_case_inline_one, + .switch_case_inline, => { - const switch_case = if (tag == .switch_case) tree.switchCase(node) else tree.switchCaseOne(node); + const switch_case = if (tag == .switch_case or tag == .switch_case_inline) tree.switchCase(node) else tree.switchCaseOne(node); try callWriteNodeInlayHint(allocator, .{ builder, arena, store, switch_case.ast.target_expr, range }); }, diff --git a/src/references.zig b/src/references.zig index b155955..0c1e973 100644 --- a/src/references.zig +++ b/src/references.zig @@ -176,13 +176,17 @@ fn symbolReferencesInternal( try symbolReferencesInternal(builder, case, handle); } }, - .switch_case_one => { + .switch_case_one, + .switch_case_inline_one, + => { const case_one = tree.switchCaseOne(node); try symbolReferencesInternal(builder, case_one.ast.target_expr, handle); for (case_one.ast.values) |val| try symbolReferencesInternal(builder, val, handle); }, - .switch_case => { + .switch_case, + .switch_case_inline, + => { const case = tree.switchCase(node); try symbolReferencesInternal(builder, case.ast.target_expr, handle); for (case.ast.values) |val| diff --git a/src/semantic_tokens.zig b/src/semantic_tokens.zig index 244fd8f..7d548c9 100644 --- a/src/semantic_tokens.zig +++ b/src/semantic_tokens.zig @@ -354,7 +354,9 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) WriteTokensEr } else { try writeTokenMod(builder, var_decl.ast.mut_token + 1, .variable, .{ .declaration = true }); } - try writeToken(builder, var_decl.ast.mut_token + 2, .operator); + if (token_tags[var_decl.ast.mut_token + 2] == .equal) { + try writeToken(builder, var_decl.ast.mut_token + 2, .operator); + } try callWriteNodeTokens(allocator, .{ builder, var_decl.ast.type_node }); try callWriteNodeTokens(allocator, .{ builder, var_decl.ast.align_node }); @@ -518,8 +520,11 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) WriteTokensEr }, .switch_case_one, .switch_case, + .switch_case_inline_one, + .switch_case_inline, => { - const switch_case = if (tag == .switch_case) tree.switchCase(node) else tree.switchCaseOne(node); + const switch_case = if (tag == .switch_case or tag == .switch_case_inline) tree.switchCase(node) else tree.switchCaseOne(node); + try writeToken(builder, switch_case.inline_token, .keyword); for (switch_case.ast.values) |item_node| try callWriteNodeTokens(allocator, .{ builder, item_node }); // check it it's 'else' if (switch_case.ast.values.len == 0) try writeToken(builder, switch_case.ast.arrow_token - 1, .keyword);