feat: auto detect indent size when loading buffers

closes #536
This commit is contained in:
CJ van den Berg 2026-04-14 23:55:44 +02:00
parent 0dc1774336
commit 8adab79d53
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
2 changed files with 46 additions and 1 deletions

View file

@ -52,6 +52,7 @@ file_exists: bool = true,
file_eol_mode: EolMode = .lf,
last_save_eol_mode: EolMode = .lf,
file_utf8_sanitized: bool = false,
detected_indent_size: ?usize = null,
hidden: bool = false,
ephemeral: bool = false,
auto_save: bool = false,
@ -1395,9 +1396,47 @@ pub fn load(self: *const Self, reader: *std.Io.Reader, eol_mode: *EolMode, utf8_
leaves[cur_leaf] = .{ .leaf = .{ .buf = line, .bol = true, .eol = false } };
if (leaves.len != cur_leaf + 1)
return error.Unexpected;
self_.detected_indent_size = detect_indent_size(leaves[0..@min(leaves.len, 1000)]);
return Node.merge_in_place(leaves, self.allocator);
}
fn detect_indent_size(leaves: []const Node) ?usize {
// frequency of each leading-space count (up to 16 spaces).
const max_spaces = 16;
var freq = std.mem.zeroes([max_spaces + 1]u32);
for (leaves) |leaf_node| {
const line = leaf_node.leaf.buf;
if (line.len == 0) continue;
if (line[0] == '\t') return 0;
var spaces: usize = 0;
for (line) |c| {
if (c == ' ') spaces += 1 else break;
}
if (spaces == 0 or spaces > max_spaces) continue;
freq[spaces] += 1;
}
// find the 3 most frequently occurring indent levels
var top = [3]usize{ 0, 0, 0 };
for (1..freq.len) |n| {
if (freq[n] > freq[top[2]]) {
top[2] = n;
if (freq[top[2]] > freq[top[1]]) std.mem.swap(usize, &top[1], &top[2]);
if (freq[top[1]] > freq[top[0]]) std.mem.swap(usize, &top[0], &top[1]);
}
}
// GCD of the top indent levels gives the base indent unit
var gcd: usize = 0;
for (top) |n| {
if (n == 0) continue;
gcd = if (gcd == 0) n else std.math.gcd(gcd, n);
}
return if (gcd > 0) gcd else null;
}
pub fn load_from_string(self: *const Self, s: []const u8, eol_mode: *EolMode, utf8_sanitized: *bool) LoadError!Root {
var reader = std.Io.Reader.fixed(s);
return self.load(&reader, eol_mode, utf8_sanitized);

View file

@ -831,6 +831,13 @@ pub const Editor = struct {
}
fn detect_indent_mode(self: *Self, content: []const u8) void {
if (self.buffer) |buf| {
if (buf.detected_indent_size) |detected_indent_size| {
self.indent_size = detected_indent_size;
self.indent_mode = .spaces;
return;
}
}
var it = std.mem.splitScalar(u8, content, '\n');
while (it.next()) |line| {
if (line.len == 0) continue;
@ -842,7 +849,6 @@ pub const Editor = struct {
}
self.indent_size = tui.config().indent_size;
self.indent_mode = .spaces;
return;
}
fn refresh_tab_width(self: *Self) void {