Before documentPositionContext returns .empty, check if an identifier

immediately follows the cursor and return .var_access if it does
  instead.
This allows hover and go to definition to work when the cursor is
  immediately before an identifier.
This commit is contained in:
Alexandros Naskos 2021-03-31 02:25:49 +03:00
parent 3c609ff47d
commit 8cf6029f1a
No known key found for this signature in database
GPG Key ID: 02BF2E72B0EA32D2
3 changed files with 45 additions and 12 deletions

View File

@ -1549,7 +1549,11 @@ fn tokenRangeAppend(prev: SourceRange, token: std.zig.Token) SourceRange {
const DocumentPosition = @import("offsets.zig").DocumentPosition; const DocumentPosition = @import("offsets.zig").DocumentPosition;
pub fn documentPositionContext(arena: *std.heap.ArenaAllocator, document: types.TextDocument, doc_position: DocumentPosition) !PositionContext { pub fn documentPositionContext(
arena: *std.heap.ArenaAllocator,
document: types.TextDocument,
doc_position: DocumentPosition,
) !PositionContext {
const line = doc_position.line; const line = doc_position.line;
var tokenizer = std.zig.Tokenizer.init(line[0..doc_position.line_index]); var tokenizer = std.zig.Tokenizer.init(line[0..doc_position.line_index]);
var stack = try std.ArrayList(StackState).initCapacity(&arena.allocator, 8); var stack = try std.ArrayList(StackState).initCapacity(&arena.allocator, 8);
@ -1639,7 +1643,30 @@ pub fn documentPositionContext(arena: *std.heap.ArenaAllocator, document: types.
} }
return block: { return block: {
if (stack.popOrNull()) |state| break :block state.ctx; if (stack.popOrNull()) |state| {
switch (state.ctx) {
.empty => {},
.label => |filled| {
// We need to check this because the state could be a filled
// label if only a space follows it
const last_char = line[doc_position.line_index - 1];
if (!filled or last_char != ' ') {
break :block state.ctx;
}
},
else => break :block state.ctx,
}
}
if (doc_position.line_index < line.len) {
switch (line[doc_position.line_index]) {
'a'...'z', 'A'...'Z', '_', '@' => {},
else => break :block .empty,
}
tokenizer = std.zig.Tokenizer.init(line[doc_position.line_index..]);
const tok = tokenizer.next();
if (tok.tag == .identifier)
break :block PositionContext{ .var_access = tok.loc };
}
break :block .empty; break :block .empty;
}; };
} }

View File

@ -357,8 +357,6 @@ fn nodeToCompletion(
const node_tags = tree.nodes.items(.tag); const node_tags = tree.nodes.items(.tag);
const datas = tree.nodes.items(.data); const datas = tree.nodes.items(.data);
const token_tags = tree.tokens.items(.tag); const token_tags = tree.tokens.items(.tag);
if (tree.errors.len > 0)
return;
const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md) const doc_kind: types.MarkupContent.Kind = if (client_capabilities.completion_doc_supports_md)
.Markdown .Markdown
@ -1681,17 +1679,17 @@ fn processJsonRpc(arena: *std.heap.ArenaAllocator, parser: *std.json.Parser, jso
logger.debug("Method without return value not implemented: {s}", .{method}); logger.debug("Method without return value not implemented: {s}", .{method});
} }
fn launchWizard() !void { fn launchWizard() !void {
const dest = const dest =
(try known_folders.getPath(allocator, .local_configuration)) (try known_folders.getPath(allocator, .local_configuration)) orelse (try known_folders.getPath(allocator, .executable_dir)) orelse return error.NoConfigPathFound;
orelse (try known_folders.getPath(allocator, .executable_dir))
orelse return error.NoConfigPathFound;
defer allocator.free(dest); defer allocator.free(dest);
try setup.wizard(allocator, dest); try setup.wizard(allocator, dest);
} }
const stack_frames = switch (std.builtin.mode) { .Debug => 10, else => 0 }; const stack_frames = switch (std.builtin.mode) {
.Debug => 10,
else => 0,
};
var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){}; var gpa_state = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = stack_frames }){};
pub fn main() anyerror!void { pub fn main() anyerror!void {
@ -1711,7 +1709,7 @@ pub fn main() anyerror!void {
std.debug.print("Enabled debug logging\n", .{}); std.debug.print("Enabled debug logging\n", .{});
} else if (std.mem.eql(u8, arg, "config")) { } else if (std.mem.eql(u8, arg, "config")) {
try launchWizard(); try launchWizard();
args_it.deinit(); args_it.deinit();
return; return;
} else { } else {
std.debug.print("Unrecognized argument {s}\n", .{arg}); std.debug.print("Unrecognized argument {s}\n", .{arg});

View File

@ -30,7 +30,11 @@ pub fn documentPosition(doc: types.TextDocument, position: types.Position, encod
if (index < 0 or index > @intCast(i64, doc.text.len)) { if (index < 0 or index > @intCast(i64, doc.text.len)) {
return error.InvalidParams; return error.InvalidParams;
} }
return DocumentPosition{ .line = line, .absolute_index = @intCast(usize, index), .line_index = @intCast(usize, position.character) }; return DocumentPosition{
.line = line,
.absolute_index = @intCast(usize, index),
.line_index = @intCast(usize, position.character),
};
} else { } else {
const utf8 = doc.text[line_start_idx..]; const utf8 = doc.text[line_start_idx..];
var utf8_idx: usize = 0; var utf8_idx: usize = 0;
@ -50,7 +54,11 @@ pub fn documentPosition(doc: types.TextDocument, position: types.Position, encod
} }
utf8_idx = next_utf8_idx; utf8_idx = next_utf8_idx;
} }
return DocumentPosition{ .line = line, .absolute_index = line_start_idx + utf8_idx, .line_index = utf8_idx }; return DocumentPosition{
.line = line,
.absolute_index = line_start_idx + utf8_idx,
.line_index = utf8_idx,
};
} }
} }