refactor: lazy parse injections
This commit is contained in:
parent
7f18430932
commit
02c26ba48f
1 changed files with 34 additions and 17 deletions
|
|
@ -28,15 +28,19 @@ errors_query: *Query,
|
||||||
injections: ?*Query,
|
injections: ?*Query,
|
||||||
tree: ?*treez.Tree = null,
|
tree: ?*treez.Tree = null,
|
||||||
injection_list: std.ArrayListUnmanaged(Injection) = .{},
|
injection_list: std.ArrayListUnmanaged(Injection) = .{},
|
||||||
|
content: ?[]u8 = null,
|
||||||
|
|
||||||
pub const Injection = struct {
|
pub const Injection = struct {
|
||||||
lang_name: []const u8,
|
lang_name: []const u8,
|
||||||
|
file_type: FileType,
|
||||||
start_point: Point,
|
start_point: Point,
|
||||||
end_row: u32,
|
end_row: u32,
|
||||||
syntax: *Self,
|
start_byte: u32,
|
||||||
|
end_byte: u32,
|
||||||
|
syntax: ?*Self = null,
|
||||||
|
|
||||||
fn deinit(self: *Injection, allocator: std.mem.Allocator) void {
|
fn deinit(self: *Injection, allocator: std.mem.Allocator) void {
|
||||||
self.syntax.destroy();
|
if (self.syntax) |syn| syn.destroy();
|
||||||
allocator.free(self.lang_name);
|
allocator.free(self.lang_name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -78,6 +82,7 @@ pub fn create_guess_file_type_static(allocator: std.mem.Allocator, content: []co
|
||||||
pub fn destroy(self: *Self) void {
|
pub fn destroy(self: *Self) void {
|
||||||
self.clear_injections();
|
self.clear_injections();
|
||||||
self.injection_list.deinit(self.allocator);
|
self.injection_list.deinit(self.allocator);
|
||||||
|
if (self.content) |c| self.allocator.free(c);
|
||||||
if (self.tree) |tree| tree.destroy();
|
if (self.tree) |tree| tree.destroy();
|
||||||
self.query_cache.release(self.query, .highlights);
|
self.query_cache.release(self.query, .highlights);
|
||||||
self.query_cache.release(self.errors_query, .highlights);
|
self.query_cache.release(self.errors_query, .highlights);
|
||||||
|
|
@ -88,6 +93,8 @@ pub fn destroy(self: *Self) void {
|
||||||
|
|
||||||
pub fn reset(self: *Self) void {
|
pub fn reset(self: *Self) void {
|
||||||
self.clear_injections();
|
self.clear_injections();
|
||||||
|
if (self.content) |c| self.allocator.free(c);
|
||||||
|
self.content = null;
|
||||||
if (self.tree) |tree| {
|
if (self.tree) |tree| {
|
||||||
tree.destroy();
|
tree.destroy();
|
||||||
self.tree = null;
|
self.tree = null;
|
||||||
|
|
@ -101,8 +108,12 @@ fn clear_injections(self: *Self) void {
|
||||||
|
|
||||||
pub fn refresh_full(self: *Self, content: []const u8) !void {
|
pub fn refresh_full(self: *Self, content: []const u8) !void {
|
||||||
self.clear_injections();
|
self.clear_injections();
|
||||||
|
if (self.content) |c| self.allocator.free(c);
|
||||||
|
self.content = null;
|
||||||
if (self.tree) |tree| tree.destroy();
|
if (self.tree) |tree| tree.destroy();
|
||||||
self.tree = try self.parser.parseString(null, content);
|
self.tree = try self.parser.parseString(null, content);
|
||||||
|
const content_copy = try self.allocator.dupe(u8, content);
|
||||||
|
self.content = content_copy;
|
||||||
try self.refresh_injections(content);
|
try self.refresh_injections(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,6 +178,10 @@ pub fn refresh_from_string(self: *Self, content: [:0]const u8) !void {
|
||||||
.encoding = .utf_8,
|
.encoding = .utf_8,
|
||||||
};
|
};
|
||||||
self.tree = try self.parser.parse(old_tree, input);
|
self.tree = try self.parser.parse(old_tree, input);
|
||||||
|
if (self.content) |c| self.allocator.free(c);
|
||||||
|
self.content = null;
|
||||||
|
const content_copy = try self.allocator.dupe(u8, content);
|
||||||
|
self.content = content_copy;
|
||||||
try self.refresh_injections(content);
|
try self.refresh_injections(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,8 +210,6 @@ pub fn refresh_injections(self: *Self, content: []const u8) !void {
|
||||||
|
|
||||||
const crange = content_range orelse continue;
|
const crange = content_range orelse continue;
|
||||||
|
|
||||||
// Determine language name: dynamic @injection.language capture takes priority,
|
|
||||||
// then fall back to a static #set! injection.language predicate.
|
|
||||||
const lang_name: []const u8 = if (lang_range) |lr|
|
const lang_name: []const u8 = if (lang_range) |lr|
|
||||||
extract_node_text(content, lr) orelse continue
|
extract_node_text(content, lr) orelse continue
|
||||||
else
|
else
|
||||||
|
|
@ -211,21 +224,17 @@ pub fn refresh_injections(self: *Self, content: []const u8) !void {
|
||||||
const start_byte = crange.start_byte;
|
const start_byte = crange.start_byte;
|
||||||
const end_byte = crange.end_byte;
|
const end_byte = crange.end_byte;
|
||||||
if (start_byte >= end_byte or end_byte > content.len) continue;
|
if (start_byte >= end_byte or end_byte > content.len) continue;
|
||||||
const child_content = content[start_byte..end_byte];
|
|
||||||
|
|
||||||
const child = try Self.create(file_type, self.allocator, self.query_cache);
|
|
||||||
errdefer child.destroy();
|
|
||||||
if (child.tree) |t| t.destroy();
|
|
||||||
child.tree = try child.parser.parseString(null, child_content);
|
|
||||||
|
|
||||||
const lang_name_owned = try self.allocator.dupe(u8, lang_name);
|
const lang_name_owned = try self.allocator.dupe(u8, lang_name);
|
||||||
errdefer self.allocator.free(lang_name_owned);
|
errdefer self.allocator.free(lang_name_owned);
|
||||||
|
|
||||||
try self.injection_list.append(self.allocator, .{
|
try self.injection_list.append(self.allocator, .{
|
||||||
.lang_name = lang_name_owned,
|
.lang_name = lang_name_owned,
|
||||||
|
.file_type = file_type,
|
||||||
.start_point = crange.start_point,
|
.start_point = crange.start_point,
|
||||||
.end_row = crange.end_point.row,
|
.end_row = crange.end_point.row,
|
||||||
.syntax = child,
|
.start_byte = start_byte,
|
||||||
|
.end_byte = end_byte,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -350,15 +359,26 @@ fn CallBack(comptime T: type) type {
|
||||||
return fn (ctx: T, sel: Range, scope: []const u8, id: u32, capture_idx: usize, node: *const Node) error{Stop}!void;
|
return fn (ctx: T, sel: Range, scope: []const u8, id: u32, capture_idx: usize, node: *const Node) error{Stop}!void;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx)), range: ?Range) !void {
|
pub fn render(self: *Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx)), range: ?Range) !void {
|
||||||
try self.render_highlights_only(ctx, cb, range);
|
try self.render_highlights_only(ctx, cb, range);
|
||||||
|
|
||||||
|
const content = self.content orelse return;
|
||||||
for (self.injection_list.items) |*inj| {
|
for (self.injection_list.items) |*inj| {
|
||||||
if (range) |r| {
|
if (range) |r| {
|
||||||
if (inj.end_row < r.start_point.row) continue;
|
if (inj.end_row < r.start_point.row) continue;
|
||||||
if (inj.start_point.row > r.end_point.row) continue;
|
if (inj.start_point.row > r.end_point.row) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inj.syntax == null) {
|
||||||
|
const child_content = content[inj.start_byte..inj.end_byte];
|
||||||
|
const child = try Self.create(inj.file_type, self.allocator, self.query_cache);
|
||||||
|
errdefer child.destroy();
|
||||||
|
if (child.tree) |t| t.destroy();
|
||||||
|
child.tree = try child.parser.parseString(null, child_content);
|
||||||
|
inj.syntax = child;
|
||||||
|
}
|
||||||
|
const child_syn = inj.syntax.?;
|
||||||
|
|
||||||
const child_range: ?Range = if (range) |r| blk: {
|
const child_range: ?Range = if (range) |r| blk: {
|
||||||
const child_start_row: u32 = if (r.start_point.row > inj.start_point.row)
|
const child_start_row: u32 = if (r.start_point.row > inj.start_point.row)
|
||||||
r.start_point.row - inj.start_point.row
|
r.start_point.row - inj.start_point.row
|
||||||
|
|
@ -373,8 +393,7 @@ pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx
|
||||||
};
|
};
|
||||||
} else null;
|
} else null;
|
||||||
|
|
||||||
// Wrap the context so we can translate local ranges to absolute
|
// Wrap the context to translate local ranges to document coordinates
|
||||||
// document coordinates before forwarding to the callback
|
|
||||||
const InjCtx = struct {
|
const InjCtx = struct {
|
||||||
parent_ctx: @TypeOf(ctx),
|
parent_ctx: @TypeOf(ctx),
|
||||||
inj: *const Injection,
|
inj: *const Injection,
|
||||||
|
|
@ -389,12 +408,10 @@ pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx
|
||||||
) error{Stop}!void {
|
) error{Stop}!void {
|
||||||
const start_row = child_sel.start_point.row + self_.inj.start_point.row;
|
const start_row = child_sel.start_point.row + self_.inj.start_point.row;
|
||||||
const end_row = child_sel.end_point.row + self_.inj.start_point.row;
|
const end_row = child_sel.end_point.row + self_.inj.start_point.row;
|
||||||
// Column offset only applies on the very first line of the injection
|
|
||||||
const start_col = child_sel.start_point.column +
|
const start_col = child_sel.start_point.column +
|
||||||
if (child_sel.start_point.row == 0) self_.inj.start_point.column else 0;
|
if (child_sel.start_point.row == 0) self_.inj.start_point.column else 0;
|
||||||
const end_col = child_sel.end_point.column +
|
const end_col = child_sel.end_point.column +
|
||||||
if (child_sel.end_point.row == 0) self_.inj.start_point.column else 0;
|
if (child_sel.end_point.row == 0) self_.inj.start_point.column else 0;
|
||||||
|
|
||||||
const doc_range: Range = .{
|
const doc_range: Range = .{
|
||||||
.start_point = .{ .row = start_row, .column = start_col },
|
.start_point = .{ .row = start_row, .column = start_col },
|
||||||
.end_point = .{ .row = end_row, .column = end_col },
|
.end_point = .{ .row = end_row, .column = end_col },
|
||||||
|
|
@ -406,7 +423,7 @@ pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx
|
||||||
};
|
};
|
||||||
|
|
||||||
var inj_ctx: InjCtx = .{ .parent_ctx = ctx, .inj = inj };
|
var inj_ctx: InjCtx = .{ .parent_ctx = ctx, .inj = inj };
|
||||||
try inj.syntax.render_highlights_only(&inj_ctx, InjCtx.translated_cb, child_range);
|
try child_syn.render_highlights_only(&inj_ctx, InjCtx.translated_cb, child_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue