Implement semantic tokens for regular comments
This commit is contained in:
parent
ac8a00342e
commit
e2f4bbf2f3
@ -1785,8 +1785,19 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: ast.Tree, nod
|
|||||||
if (name.len == 0)
|
if (name.len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const start_loc = context.prev_loc.add(try offsets.tokenRelativeLocation(tree, context.prev_loc.offset, tree.firstToken(node), context.encoding));
|
const starts = tree.tokens.items(.start);
|
||||||
const end_loc = start_loc.add(try offsets.tokenRelativeLocation(tree, start_loc.offset, tree.lastToken(node), context.encoding));
|
const start_loc = context.prev_loc.add(try offsets.tokenRelativeLocation(
|
||||||
|
tree,
|
||||||
|
context.prev_loc.offset,
|
||||||
|
starts[tree.firstToken(node)],
|
||||||
|
context.encoding,
|
||||||
|
));
|
||||||
|
const end_loc = start_loc.add(try offsets.tokenRelativeLocation(
|
||||||
|
tree,
|
||||||
|
start_loc.offset,
|
||||||
|
starts[tree.lastToken(node)],
|
||||||
|
context.encoding,
|
||||||
|
));
|
||||||
context.prev_loc = end_loc;
|
context.prev_loc = end_loc;
|
||||||
const range = types.Range{
|
const range = types.Range{
|
||||||
.start = .{
|
.start = .{
|
||||||
@ -1908,7 +1919,7 @@ pub const DeclWithHandle = struct {
|
|||||||
|
|
||||||
pub fn location(self: DeclWithHandle, encoding: offsets.Encoding) !offsets.TokenLocation {
|
pub fn location(self: DeclWithHandle, encoding: offsets.Encoding) !offsets.TokenLocation {
|
||||||
const tree = self.handle.tree;
|
const tree = self.handle.tree;
|
||||||
return try offsets.tokenRelativeLocation(tree, 0, self.nameToken(), encoding);
|
return try offsets.tokenRelativeLocation(tree, 0, tree.tokens.items(.start)[self.nameToken()], encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isPublic(self: DeclWithHandle) bool {
|
fn isPublic(self: DeclWithHandle) bool {
|
||||||
|
@ -28,4 +28,4 @@ operator_completions: bool = true,
|
|||||||
|
|
||||||
/// Skips references to std. This will improve lookup speeds.
|
/// Skips references to std. This will improve lookup speeds.
|
||||||
/// Going to definition however will continue to work
|
/// Going to definition however will continue to work
|
||||||
skip_std_references: bool = true,
|
skip_std_references: bool = false,
|
||||||
|
@ -554,7 +554,7 @@ fn gotoDefinitionSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, de
|
|||||||
|
|
||||||
const name_token = analysis.getDeclNameToken(handle.tree, node) orelse
|
const name_token = analysis.getDeclNameToken(handle.tree, node) orelse
|
||||||
return try respondGeneric(id, null_result_response);
|
return try respondGeneric(id, null_result_response);
|
||||||
break :block offsets.tokenRelativeLocation(handle.tree, 0, name_token, offset_encoding) catch return;
|
break :block offsets.tokenRelativeLocation(handle.tree, 0, handle.tree.tokens.items(.start)[name_token], offset_encoding) catch return;
|
||||||
},
|
},
|
||||||
else => decl_handle.location(offset_encoding) catch return,
|
else => decl_handle.location(offset_encoding) catch return,
|
||||||
};
|
};
|
||||||
|
@ -71,8 +71,8 @@ pub const TokenLocation = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn tokenRelativeLocation(tree: ast.Tree, start_index: usize, token: ast.TokenIndex, encoding: Encoding) !TokenLocation {
|
pub fn tokenRelativeLocation(tree: ast.Tree, start_index: usize, next_token_index: usize, encoding: Encoding) !TokenLocation {
|
||||||
const start = tree.tokens.items(.start)[token];
|
const start = next_token_index;
|
||||||
|
|
||||||
var loc = TokenLocation{
|
var loc = TokenLocation{
|
||||||
.line = 0,
|
.line = 0,
|
||||||
|
@ -14,7 +14,7 @@ fn tokenReference(
|
|||||||
context: anytype,
|
context: anytype,
|
||||||
comptime handler: anytype,
|
comptime handler: anytype,
|
||||||
) !void {
|
) !void {
|
||||||
const loc = offsets.tokenRelativeLocation(handle.tree, 0, tok, encoding) catch return;
|
const loc = offsets.tokenRelativeLocation(handle.tree, 0, handle.tree.tokens.items(.start)[tok], encoding) catch return;
|
||||||
try handler(context, types.Location{
|
try handler(context, types.Location{
|
||||||
.uri = handle.uri(),
|
.uri = handle.uri(),
|
||||||
.range = .{
|
.range = .{
|
||||||
|
@ -48,11 +48,21 @@ pub const TokenModifiers = packed struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Comment = struct {
|
||||||
|
/// Length of the comment
|
||||||
|
length: u32,
|
||||||
|
/// Source index of the comment
|
||||||
|
start: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CommentList = std.ArrayList(Comment);
|
||||||
|
|
||||||
const Builder = struct {
|
const Builder = struct {
|
||||||
handle: *DocumentStore.Handle,
|
handle: *DocumentStore.Handle,
|
||||||
current_token: ?ast.TokenIndex,
|
current_token: ?ast.TokenIndex,
|
||||||
arr: std.ArrayList(u32),
|
arr: std.ArrayList(u32),
|
||||||
encoding: offsets.Encoding,
|
encoding: offsets.Encoding,
|
||||||
|
comments: CommentList,
|
||||||
|
|
||||||
fn init(allocator: *std.mem.Allocator, handle: *DocumentStore.Handle, encoding: offsets.Encoding) Builder {
|
fn init(allocator: *std.mem.Allocator, handle: *DocumentStore.Handle, encoding: offsets.Encoding) Builder {
|
||||||
return Builder{
|
return Builder{
|
||||||
@ -60,6 +70,7 @@ const Builder = struct {
|
|||||||
.current_token = null,
|
.current_token = null,
|
||||||
.arr = std.ArrayList(u32).init(allocator),
|
.arr = std.ArrayList(u32).init(allocator),
|
||||||
.encoding = encoding,
|
.encoding = encoding,
|
||||||
|
.comments = CommentList.init(allocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +84,21 @@ const Builder = struct {
|
|||||||
if (start_idx > starts[token])
|
if (start_idx > starts[token])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const delta_loc = offsets.tokenRelativeLocation(self.handle.tree, start_idx, token, self.encoding) catch return;
|
const delta_loc = if (self.findCommentBetween(start_idx, starts[token])) |comment| blk: {
|
||||||
|
const old_loc = self.handle.tree.tokenLocation(0, self.current_token orelse 0);
|
||||||
|
const comment_delta = offsets.tokenRelativeLocation(self.handle.tree, start_idx, comment.start, self.encoding) catch return;
|
||||||
|
|
||||||
|
try self.arr.appendSlice(&[_]u32{
|
||||||
|
@truncate(u32, comment_delta.line),
|
||||||
|
@truncate(u32, comment_delta.column),
|
||||||
|
comment.length,
|
||||||
|
@enumToInt(TokenType.comment),
|
||||||
|
0,
|
||||||
|
});
|
||||||
|
|
||||||
|
break :blk offsets.tokenRelativeLocation(self.handle.tree, comment.start, starts[token], self.encoding) catch return;
|
||||||
|
} else offsets.tokenRelativeLocation(self.handle.tree, start_idx, starts[token], self.encoding) catch return;
|
||||||
|
|
||||||
try self.arr.appendSlice(&[_]u32{
|
try self.arr.appendSlice(&[_]u32{
|
||||||
@truncate(u32, delta_loc.line),
|
@truncate(u32, delta_loc.line),
|
||||||
@truncate(u32, delta_loc.column),
|
@truncate(u32, delta_loc.column),
|
||||||
@ -87,6 +112,15 @@ const Builder = struct {
|
|||||||
fn toOwnedSlice(self: *Builder) []u32 {
|
fn toOwnedSlice(self: *Builder) []u32 {
|
||||||
return self.arr.toOwnedSlice();
|
return self.arr.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Based on a given start and end index, returns a `Comment` between the positions
|
||||||
|
/// Returns `null` if none was fone
|
||||||
|
fn findCommentBetween(self: Builder, from: u32, to: u32) ?Comment {
|
||||||
|
return for (self.comments.items) |comment| {
|
||||||
|
if (comment.start > from and comment.start < to)
|
||||||
|
break comment;
|
||||||
|
} else null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn writeToken(
|
fn writeToken(
|
||||||
@ -1011,8 +1045,12 @@ fn writeNodeTokens(
|
|||||||
pub fn writeAllSemanticTokens(arena: *std.heap.ArenaAllocator, store: *DocumentStore, handle: *DocumentStore.Handle, encoding: offsets.Encoding) ![]u32 {
|
pub fn writeAllSemanticTokens(arena: *std.heap.ArenaAllocator, store: *DocumentStore, handle: *DocumentStore.Handle, encoding: offsets.Encoding) ![]u32 {
|
||||||
var builder = Builder.init(arena.child_allocator, handle, encoding);
|
var builder = Builder.init(arena.child_allocator, handle, encoding);
|
||||||
|
|
||||||
|
// as line comments are not nodes, we parse the text then generate the tokens for them
|
||||||
|
try findComments(&builder, handle.tree.source, encoding);
|
||||||
|
|
||||||
// reverse the ast from the root declarations
|
// reverse the ast from the root declarations
|
||||||
var gap_highlighter = GapHighlighter.init(&builder, 0);
|
var gap_highlighter = GapHighlighter.init(&builder, 0);
|
||||||
|
|
||||||
var buf: [2]ast.Node.Index = undefined;
|
var buf: [2]ast.Node.Index = undefined;
|
||||||
for (analysis.declMembers(handle.tree, .root, 0, &buf)) |child| {
|
for (analysis.declMembers(handle.tree, .root, 0, &buf)) |child| {
|
||||||
try gap_highlighter.next(child);
|
try gap_highlighter.next(child);
|
||||||
@ -1020,7 +1058,57 @@ pub fn writeAllSemanticTokens(arena: *std.heap.ArenaAllocator, store: *DocumentS
|
|||||||
}
|
}
|
||||||
|
|
||||||
try gap_highlighter.end(@truncate(u32, handle.tree.tokens.len) - 1);
|
try gap_highlighter.end(@truncate(u32, handle.tree.tokens.len) - 1);
|
||||||
// pass root node, which always has index '0'
|
|
||||||
// try writeNodeTokens(&builder, arena, store, 0);
|
|
||||||
return builder.toOwnedSlice();
|
return builder.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// As the AST does not contain nodes for comments
|
||||||
|
/// this will parse through the entire file to search for comments
|
||||||
|
/// and generate semantic tokens for them
|
||||||
|
fn findComments(builder: *Builder, source: []const u8, encoding: offsets.Encoding) !void {
|
||||||
|
var state: enum { none, comment, doc_comment } = .none;
|
||||||
|
|
||||||
|
var prev: u8 = 0;
|
||||||
|
var start: usize = 0;
|
||||||
|
for (source) |c, i| {
|
||||||
|
if (state == .comment and c == '/') {
|
||||||
|
state = .none;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == .none and c == '/' and prev == '/') {
|
||||||
|
state = .comment;
|
||||||
|
start = i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
if (state == .comment) {
|
||||||
|
state = .none;
|
||||||
|
|
||||||
|
const len = if (encoding == .utf8)
|
||||||
|
i - start
|
||||||
|
else blk: {
|
||||||
|
var index: usize = start;
|
||||||
|
var utf16_len: usize = 0;
|
||||||
|
while (index < i) {
|
||||||
|
const n = std.unicode.utf8ByteSequenceLength(source[index]) catch unreachable;
|
||||||
|
const codepoint = std.unicode.utf8Decode(source[index .. index + n]) catch unreachable;
|
||||||
|
if (codepoint < 0x10000) {
|
||||||
|
utf16_len += 1;
|
||||||
|
} else {
|
||||||
|
utf16_len += 2;
|
||||||
|
}
|
||||||
|
index += n;
|
||||||
|
}
|
||||||
|
break :blk utf16_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
try builder.comments.append(.{
|
||||||
|
.length = @truncate(u32, len),
|
||||||
|
.start = @truncate(u32, start),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user