feat: do a full reparse if tree-sitter reports syntax errors

This change will scan for tree-sitter errors after a partial reparse and do a
full reparse if there are are more errors than the error threshold (currently 5).
This helps prevent the tree-sitter syntax tree getting out of sync during
multi-cursor edits.
This commit is contained in:
CJ van den Berg 2025-04-24 21:09:51 +02:00
parent 4b84e35b9f
commit 05a14ae95c
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9

View file

@ -35,6 +35,7 @@ const scroll_cursor_min_border_distance = 5;
const double_click_time_ms = 350; const double_click_time_ms = 350;
const syntax_full_reparse_time_limit = 0; // ms (0 = always use incremental) const syntax_full_reparse_time_limit = 0; // ms (0 = always use incremental)
const syntax_full_reparse_error_threshold = 3; // number of tree-sitter errors that trigger a full reparse
pub const max_matches = if (builtin.mode == std.builtin.OptimizeMode.Debug) 10_000 else 100_000; pub const max_matches = if (builtin.mode == std.builtin.OptimizeMode.Debug) 10_000 else 100_000;
pub const max_match_lines = 15; pub const max_match_lines = 15;
@ -888,7 +889,7 @@ pub const Editor = struct {
self.style_cache_theme = theme.name; self.style_cache_theme = theme.name;
const cache: *StyleCache = &self.style_cache.?; const cache: *StyleCache = &self.style_cache.?;
self.render_screen(theme, cache); self.render_screen(theme, cache);
return self.scroll_dest != self.view.row; return self.scroll_dest != self.view.row or self.syntax_refresh_full;
} }
const CellType = enum { const CellType = enum {
@ -4480,7 +4481,7 @@ pub const Editor = struct {
fn update_syntax(self: *Self) !void { fn update_syntax(self: *Self) !void {
const root = try self.buf_root(); const root = try self.buf_root();
const eol_mode = try self.buf_eol_mode(); const eol_mode = try self.buf_eol_mode();
if (self.syntax_last_rendered_root == root) if (!self.syntax_refresh_full and self.syntax_last_rendered_root == root)
return; return;
var kind: enum { full, incremental, none } = .none; var kind: enum { full, incremental, none } = .none;
var edit_count: usize = 0; var edit_count: usize = 0;
@ -4491,6 +4492,7 @@ pub const Editor = struct {
defer frame.deinit(); defer frame.deinit();
syn.reset(); syn.reset();
self.syntax_last_rendered_root = null; self.syntax_last_rendered_root = null;
self.syntax_refresh_full = false;
return; return;
} }
if (!self.syntax_incremental_reparse) if (!self.syntax_incremental_reparse)
@ -4544,6 +4546,11 @@ pub const Editor = struct {
const frame = tracy.initZone(@src(), .{ .name = "editor refresh syntax" }); const frame = tracy.initZone(@src(), .{ .name = "editor refresh syntax" });
defer frame.deinit(); defer frame.deinit();
try syn.refresh_from_string(content); try syn.refresh_from_string(content);
const error_count = syn.count_error_nodes();
if (error_count >= syntax_full_reparse_error_threshold) {
self.logger.print("incremental syntax update has {d} errors -> full reparse", .{error_count});
self.syntax_refresh_full = true;
}
} }
self.syntax_last_rendered_root = root; self.syntax_last_rendered_root = root;
kind = .incremental; kind = .incremental;