summaryrefslogtreecommitdiff
path: root/src/edit.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 18:07:32 -0300
committerGabriel Schneider <[email protected]>2026-10-01 19:57:27 -0300
commit6ee4c3caa6faf42b9825dca39e9130ac83f425a8 (patch)
tree65b92aa4faa3161ee507a66c6d755186681541a0 /src/edit.zig
parent7f748c657121c801f219b28680373729fefce82a (diff)
downloadpardes-6ee4c3caa6faf42b9825dca39e9130ac83f425a8.tar.gz
pardes-6ee4c3caa6faf42b9825dca39e9130ac83f425a8.zip
Enter, o and O give the new line the old one's indent as it is, tabs and all, as acme's autoindent does; a level more after an opening delimiter is a tab where the indent is tabs
The indent was rebuilt as spaces, partial levels dropped, so a tab-indented line went on with spaces (or with one space, after Enter). Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/edit.zig')
-rw-r--r--src/edit.zig34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/edit.zig b/src/edit.zig
index 3e3ba341..bf65935e 100644
--- a/src/edit.zig
+++ b/src/edit.zig
@@ -899,11 +899,18 @@ fn insertEdit(p: *Pardes, t: *Text, key: Key) void {
t.show();
return;
}
- const indent = modal.newlineIndentWidth(line, c.col);
+ // The line's own indent, as it is (tabs stay tabs), and a
+ // level more after an opening delimiter: a tab where the
+ // indent is tabs, else spaces.
+ const lead = modal.indentText(line);
+ const more = modal.newlineIndentWidth(line, c.col) - lead.len;
+ const tabbed = std.mem.indexOfScalar(u8, lead, '\t') != null;
+ const indent = lead.len + (if (more == 0) 0 else if (tabbed) 1 else more);
const arena = p.scratch.allocator();
const block = arena.alloc(u8, 1 + indent) catch return;
block[0] = '\n';
- @memset(block[1..], ' ');
+ @memcpy(block[1..][0..lead.len], lead);
+ @memset(block[1 + lead.len ..], if (tabbed) '\t' else ' ');
// a tag keeps its blanks: they part its words, and the last
// may be its read-only prefix's
const kept = if (t.what == .body) std.mem.trimEnd(u8, before, " \t").len else c.col;
@@ -2136,6 +2143,29 @@ test "insert newline adds one indent level after a closing call" {
try std.testing.expectEqual(@as(i32, 8), pane.body.cur_col);
}
+test "Enter in insert mode keeps a tab-indented line's tabs, as o and O do" {
+ const gpa = std.testing.allocator;
+ const p = try Pardes.init(gpa, .{ .tty_only = true });
+ defer p.deinit();
+ while (p.nextEffect()) |_| {}
+ const pane = try p.setTestFile("\t\tvalue = 1;\n\tif (x) {\n");
+ pane.body.mode = .insert;
+ pane.body.cur_col = 12;
+ p.update(.{ .key = .{ .cp = Key.enter } });
+ try std.testing.expectEqualStrings("\t\tvalue = 1;\n\t\t\n\tif (x) {\n", pane.file.?.content);
+ try std.testing.expectEqual(@as(i32, 2), pane.body.cur_col);
+ // After an opening brace, a level more: a tab, as the indent is tabs.
+ pane.body.cur_row = 2;
+ pane.body.cur_col = 9;
+ p.update(.{ .key = .{ .cp = Key.enter } });
+ try std.testing.expectEqualStrings("\t\tvalue = 1;\n\t\t\n\tif (x) {\n\t\t\n", pane.file.?.content);
+ // o opens a line with the indent as it is.
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ pane.body.cur_row = 0;
+ p.update(.{ .key = .{ .cp = 'o' } });
+ try std.testing.expect(std.mem.startsWith(u8, pane.file.?.content, "\t\tvalue = 1;\n\t\t\n"));
+}
+
test "insert and normal modes edit complete Unicode graphemes" {
const gpa = std.testing.allocator;
const p = try Pardes.init(gpa, .{ .cols = 60, .rows = 12 });