Skip to content

Commit 5bad1ee

Browse files
committed
Merge branch 'master' into relative-number
2 parents 201a801 + 9e70426 commit 5bad1ee

18 files changed

Lines changed: 557 additions & 341 deletions

File tree

patch/auto-indent/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Tree-sitter powered insert mode auto-indenting.
44

55
Adds editor options:
66

7-
- `.indent_newline`: auto-indent inserted newline
8-
- `.reindent_block_end`: reindent current line upon insertion of one of `reindent_block_end_chars`
7+
- `indent_newline`: auto-indent inserted newline
8+
- `reindent_block_end_chars`: reindent current line upon insertion of one of these chars
99

1010
## Usage
1111

12-
Configure auto-indent fields in `config` in `editor.zig`:
12+
Configure auto-indent fields in `Config` in `editor.zig`:
1313

1414
```zig
15-
.indent_newline = true,
16-
.reindent_block_end = true,
15+
pub const indent_newline: bool = true;
16+
pub const reindent_block_end_chars: ?[]const u21 = &.{ '}', ']', ')' };
1717
```

patch/auto-indent/auto-indent.diff

Lines changed: 138 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,121 @@
11
diff --git a/src/buffer.zig b/src/buffer.zig
2-
index 5b1c666..249c012 100644
2+
index f3c72f9..92ff3eb 100644
33
--- a/src/buffer.zig
44
+++ b/src/buffer.zig
5-
@@ -534,6 +534,23 @@ pub const Buffer = struct {
6-
}
5+
@@ -564,62 +564,87 @@ pub const Buffer = struct {
6+
log.trace(@This(), "line byte positions: {any}\n", .{self.line_positions.items});
77
}
88

9+
- pub fn updateIndents(self: *Buffer) FatalError!void {
10+
- if (self.ts_state == null or self.ts_state.?.indent == null) return;
11+
- try self.reparse();
12+
-
13+
- self.indents.clearRetainingCapacity();
14+
- for (0..self.line_byte_positions.items.len) |row| {
15+
- try self.indents.append(self.allocator, try self.lineIndent(row));
16+
- }
17+
- log.debug(@This(), "indents: {any}\n", .{self.indents.items});
18+
- }
19+
-
20+
pub fn lineIndent(self: *Buffer, row: usize) FatalError!usize {
21+
const ts_state = if (self.ts_state) |ts_state| ts_state else return 0;
22+
const query = ts_state.indent orelse return 0;
23+
- if (self.lineLength(row) == 0 and row > 0) return self.lineIndent(row - 1);
24+
const root_node = ts.ts.ts_tree_root_node(ts_state.tree);
25+
26+
const line_span = SpanFlat{
27+
.start = if (row == 0) 0 else self.line_byte_positions.items[row - 1],
28+
.end = self.line_byte_positions.items[row],
29+
};
30+
- if (ts.firstSmallestDescendentInSpan(root_node, line_span)) |node| {
31+
- log.trace(@This(), "line {} {}\n", .{ row + 1, line_span });
32+
- var n = node;
33+
- var indent: i32 = 0;
34+
- var processed_rows = std.AutoHashMap(usize, void).init(self.allocator);
35+
- defer processed_rows.deinit();
36+
- while (!ts.ts.ts_node_is_null(n)) {
37+
- const span = SpanFlat{
38+
- .start = ts.ts.ts_node_start_byte(n),
39+
- .end = ts.ts.ts_node_end_byte(n),
40+
- };
41+
- log.trace(@This(), "node {}\n", .{span});
42+
- if (query.captures.get(@intFromPtr(n.id))) |cap| c: {
43+
- const pos = Span.fromSpanFlat(self, span);
44+
+ log.trace(@This(), "indent line {} {}\n", .{ row + 1, line_span });
45+
46+
+ var n: ?ts.ts.TSNode = null;
47+
+ if (line_span.start > 2 and self.lineLength(row) == 0) {
48+
+ // assumes no trailing spaces on prev line
49+
+ const prev_line_end_span = SpanFlat{ .start = line_span.start - 2, .end = line_span.start - 1 };
50+
+ n = ts.firstSmallestDescendentInSpan(root_node, prev_line_end_span);
51+
+ if (n) |n_| {
52+
+ if (query.captures.get(@intFromPtr(n_.id))) |cap| {
53+
var capture_name_len: u32 = undefined;
54+
const capture_name_buf = ts.ts.ts_query_capture_name_for_id(query.query.?, cap.index, &capture_name_len);
55+
const capture_name = capture_name_buf[0..capture_name_len];
56+
- log.trace(@This(), "capture {s} [{}-{}]\n", .{ capture_name, span.start, span.end });
57+
-
58+
- if (processed_rows.contains(@intCast(pos.start.row))) break :c;
59+
- if (pos.start.row != pos.end.row and pos.start.row != row and std.mem.eql(u8, capture_name, "indent.begin")) {
60+
- indent += 1;
61+
- try processed_rows.put(@intCast(pos.start.row), {});
62+
- } else if (std.mem.eql(u8, capture_name, "indent.end") or std.mem.eql(u8, capture_name, "indent.branch")) {
63+
- indent -= 1;
64+
+ if (std.mem.eql(u8, capture_name, "indent.end") or std.mem.eql(u8, capture_name, "indent.branch")) {
65+
+ n = ts.firstSmallestDescendentInSpan(root_node, line_span);
66+
}
67+
}
68+
- n = ts.ts.ts_node_parent(n);
69+
}
70+
- return if (indent < 0) 0 else @intCast(indent);
71+
} else {
72+
- log.trace(@This(), "line {}[{}-{}] no node\n", .{ row + 1, line_span.start, line_span.end });
73+
+ n = ts.firstSmallestDescendentInSpan(root_node, line_span);
74+
+ }
75+
+ if (n == null) {
76+
+ log.warn(@This(), "no node\n", .{});
77+
return 0;
78+
}
79+
+ var node = n.?;
80+
+ const indent_row: usize = @intCast(self.posToCursor(ts.ts.ts_node_start_byte(node)).row);
81+
+
82+
+ var indent: i32 = 0;
83+
+ var processed_rows = std.AutoHashMap(usize, void).init(self.allocator);
84+
+ defer processed_rows.deinit();
85+
+ while (!ts.ts.ts_node_is_null(node)) {
86+
+ const span = SpanFlat{
87+
+ .start = ts.ts.ts_node_start_byte(node),
88+
+ .end = ts.ts.ts_node_end_byte(node),
89+
+ };
90+
+ log.trace(@This(), "node {}\n", .{span});
91+
+ if (query.captures.get(@intFromPtr(node.id))) |cap| c: {
92+
+ const pos = Span.fromSpanFlat(self, span);
93+
+
94+
+ var capture_name_len: u32 = undefined;
95+
+ const capture_name_buf = ts.ts.ts_query_capture_name_for_id(query.query.?, cap.index, &capture_name_len);
96+
+ const capture_name = capture_name_buf[0..capture_name_len];
97+
+ log.trace(@This(), "capture {s} [{}-{}]\n", .{ capture_name, span.start, span.end });
98+
+
99+
+ if (processed_rows.contains(@intCast(pos.start.row))) break :c;
100+
+ if (pos.start.row != pos.end.row and pos.start.row != indent_row and std.mem.eql(u8, capture_name, "indent.begin")) {
101+
+ indent += 1;
102+
+ try processed_rows.put(@intCast(pos.start.row), {});
103+
+ } else if (std.mem.eql(u8, capture_name, "indent.end") or std.mem.eql(u8, capture_name, "indent.branch")) {
104+
+ indent -= 1;
105+
+ }
106+
+ }
107+
+ node = ts.ts.ts_node_parent(node);
108+
+ }
109+
+ return if (indent < 0) 0 else @intCast(indent);
110+
+ }
111+
+
9112
+ pub fn indentEmptyLine(self: *Buffer) FatalError!void {
10113
+ if (self.ts_state == null) return;
11114
+ std.debug.assert(self.cursor.col == 0);
115+
+ try self.reparse();
12116
+ if (self.lineLength(@intCast(self.cursor.row)) != 0) return;
13-
+ try self.updateIndents();
14117
+
15-
+ const correct_indent: usize = self.indents.items[@intCast(self.cursor.row)];
118+
+ const correct_indent: usize = try self.lineIndent(@intCast(self.cursor.row));
16119
+ const correct_indent_spaces = correct_indent * self.file_type.indent_spaces;
17120
+ if (correct_indent_spaces > 0) {
18121
+ const indent_text = try self.allocator.alloc(u21, correct_indent_spaces);
@@ -21,50 +124,38 @@ index 5b1c666..249c012 100644
21124
+ var indent_change = try cha.Change.initInsert(self.allocator, self, self.cursor, indent_text);
22125
+ try self.appendChange(&indent_change);
23126
+ }
24-
+ }
25-
+
127+
}
128+
26129
pub fn undo(self: *Buffer) !void {
27-
log.debug(@This(), "undo: {?}/{}\n", .{ self.history_index, self.history.items.len });
28-
if (self.history_index) |h_idx| {
29130
diff --git a/src/editor.zig b/src/editor.zig
30-
index 9e47642..b7d7987 100644
131+
index 8986a02..eaa0bf0 100644
31132
--- a/src/editor.zig
32133
+++ b/src/editor.zig
33-
@@ -19,12 +19,20 @@ const ur = @import("uri.zig");
34-
35-
pub const config = Config{
36-
.end_of_buffer_char = null,
37-
+ .indent_newline = false,
38-
+ .reindent_block_end = false,
39-
};
40-
41-
pub const Config = struct {
42-
/// Char to denote terminal lines after end of buffer
43-
/// See vim's :h fillchars -> eob
44-
end_of_buffer_char: ?u8,
134+
@@ -24,6 +24,10 @@ pub const Config = struct {
135+
/// Attempt to find matching pair when cursor is over one of these [start, end] chars
136+
/// If start == end, will only check forward until first encountered match
137+
pub const matching_pair_chars: ?[]const [2]u21 = &.{ .{ '{', '}' }, .{ '[', ']' }, .{ '(', ')' }, .{ '<', '>' }, .{ '|', '|' } };
45138
+ /// In buffers with TS indent support, autoindent inserted newline
46-
+ indent_newline: bool,
47-
+ /// In buffers with TS indent support, reindent current line upon insertion of one of `reindent_block_end_chars`
48-
+ reindent_block_end: bool,
49-
+
50-
+ pub const reindent_block_end_chars: []const u21 = &.{ '}', ']', ')' };
139+
+ pub const indent_newline: bool = false;
140+
+ /// In buffers with TS indent support, reindent current line upon insertion of one of these chars
141+
+ pub const reindent_block_end_chars: ?[]const u21 = null;
51142
};
52143

53144
pub const Dirty = struct {
54145
diff --git a/src/main.zig b/src/main.zig
55-
index bab23db..281d62b 100644
146+
index d117195..44b359a 100644
56147
--- a/src/main.zig
57148
+++ b/src/main.zig
58-
@@ -216,6 +216,17 @@ pub fn startEditor(allocator: std.mem.Allocator) FatalError!void {
149+
@@ -220,6 +220,17 @@ pub fn startEditor(allocator: std.mem.Allocator) FatalError!void {
59150
if (next_key != null and next_key.?.printable != null) {
60151
try printable.append(allocator, next_key.?.printable.?);
61152
keys_consumed += 1;
62-
+ if (edi.config.indent_newline and keys_consumed == 1 and next_key.?.printable == '\n') {
153+
+ if (edi.Config.indent_newline and keys_consumed == 1 and next_key.?.printable == '\n') {
63154
+ try buffer.changeInsertText(try printable.toOwnedSlice(allocator));
64155
+ try buffer.indentEmptyLine();
65156
+ }
66-
+ if (edi.config.reindent_block_end and
67-
+ std.mem.containsAtLeastScalar(u21, edi.Config.reindent_block_end_chars, 1, next_key.?.printable.?))
157+
+ if (edi.Config.reindent_block_end_chars != null and
158+
+ std.mem.containsAtLeastScalar(u21, edi.Config.reindent_block_end_chars.?, 1, next_key.?.printable.?))
68159
+ {
69160
+ try buffer.changeInsertText(try printable.toOwnedSlice(allocator));
70161
+ log.warn(@This(), "align!!!\n", .{});
@@ -73,13 +164,26 @@ index bab23db..281d62b 100644
73164
} else {
74165
break;
75166
}
76-
@@ -359,6 +370,9 @@ pub fn startEditor(allocator: std.mem.Allocator) FatalError!void {
167+
@@ -427,6 +438,9 @@ pub fn startEditor(allocator: std.mem.Allocator) FatalError!void {
77168
var change = try cha.Change.initInsert(allocator, buffer, pos, &.{'\n'});
78169
try buffer.appendChange(&change);
79170
if (!below) buffer.moveCursor(.{ .row = row });
80-
+ if (edi.config.indent_newline) {
171+
+ if (edi.Config.indent_newline) {
81172
+ try buffer.indentEmptyLine();
82173
+ }
83174
} else if (buffer.mode == .normal and eql(u8, key, "J")) {
84175
for (0..@intCast(repeat_or_1)) |_| {
85176
if (buffer.cursor.row + 1 < buffer.line_positions.items.len) {
177+
diff --git a/src/ts.zig b/src/ts.zig
178+
index a7de638..bfd6d5e 100644
179+
--- a/src/ts.zig
180+
+++ b/src/ts.zig
181+
@@ -213,7 +213,7 @@ pub fn firstSmallestDescendentInSpan(node: ts.TSNode, span: SpanFlat) ?ts.TSNode
182+
183+
if (node_end < span.start) return null;
184+
const child_count = ts.ts_node_child_count(node);
185+
- if (child_count == 0 and node_start >= span.start and node_end <= span.end) return node;
186+
+ if (child_count == 0 and node_start >= span.start) return node;
187+
188+
for (0..child_count) |child_idx| {
189+
const child_candidate = ts.ts_node_child(node, @intCast(child_idx));

patch/autosave/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Autosave
22

3-
Adds editor option `.autosave`.
3+
Adds editor option `autosave`.
44

55
When enabled, every `Buffer.commitChanges` will be followed by write to disk.
66

77
## Usage
88

9-
Configure autosave fields in `config` in `editor.zig`:
9+
Configure autosave fields in `Config` in `editor.zig`:
1010

1111
```zig
12-
.autosave = true,
12+
pub const autosave: bool = true;
1313
```

patch/autosave/autosave.diff

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
diff --git a/src/buffer.zig b/src/buffer.zig
2-
index 5b1c666..d0d94e1 100644
2+
index f3c72f9..1d100d8 100644
33
--- a/src/buffer.zig
44
+++ b/src/buffer.zig
5-
@@ -223,14 +223,6 @@ pub const Buffer = struct {
5+
@@ -241,14 +241,6 @@ pub const Buffer = struct {
66
_ = try self.syncFs();
77

88
self.file_history_index = self.history_index;
@@ -17,58 +17,51 @@ index 5b1c666..d0d94e1 100644
1717
}
1818

1919
pub fn moveCursor(self: *Buffer, new_cursor: Cursor) void {
20-
@@ -428,6 +420,11 @@ pub const Buffer = struct {
20+
@@ -498,6 +490,11 @@ pub const Buffer = struct {
2121
self.history_index = self.history.items.len - 1;
2222

2323
main.editor.dotRepeatCommitReady();
2424
+
25-
+ if (edi.config.autosave) {
25+
+ if (edi.Config.autosave) {
2626
+ log.debug(@This(), "autosave {s}\n", .{self.path});
2727
+ self.write() catch |e| log.err(@This(), "write buffer error: {}", .{e});
2828
+ }
2929
}
3030

3131
pub fn changeInsertText(self: *Buffer, text: []const u21) FatalError!void {
32-
@@ -546,6 +543,11 @@ pub const Buffer = struct {
32+
@@ -634,6 +631,11 @@ pub const Buffer = struct {
3333
self.moveCursor(inv_change.new_span.?.start);
3434
}
3535
self.history_index = if (h_idx > 0) h_idx - 1 else null;
3636
+
37-
+ if (edi.config.autosave) {
37+
+ if (edi.Config.autosave) {
3838
+ self.write() catch |e| log.err(@This(), "write buffer error: {}", .{e});
3939
+ log.debug(@This(), "autosave {s}\n", .{self.path});
4040
+ }
4141
}
4242
}
4343

44-
@@ -561,6 +563,11 @@ pub const Buffer = struct {
44+
@@ -649,6 +651,11 @@ pub const Buffer = struct {
4545
self.moveCursor(change.new_span.?.start);
4646
}
4747
self.history_index = redo_idx;
4848
+
49-
+ if (edi.config.autosave) {
49+
+ if (edi.Config.autosave) {
5050
+ self.write() catch |e| log.err(@This(), "write buffer error: {}", .{e});
5151
+ log.debug(@This(), "autosave {s}\n", .{self.path});
5252
+ }
5353
}
5454

5555
pub fn textAt(self: *const Buffer, span: Span) []const u21 {
5656
diff --git a/src/editor.zig b/src/editor.zig
57-
index 9e47642..cfa00fa 100644
57+
index 8986a02..8d412aa 100644
5858
--- a/src/editor.zig
5959
+++ b/src/editor.zig
60-
@@ -19,12 +19,14 @@ const ur = @import("uri.zig");
61-
62-
pub const config = Config{
63-
.end_of_buffer_char = null,
64-
+ .autosave = false,
65-
};
66-
67-
pub const Config = struct {
68-
/// Char to denote terminal lines after end of buffer
69-
/// See vim's :h fillchars -> eob
70-
end_of_buffer_char: ?u8,
71-
+ autosave: bool,
60+
@@ -24,6 +24,7 @@ pub const Config = struct {
61+
/// Attempt to find matching pair when cursor is over one of these [start, end] chars
62+
/// If start == end, will only check forward until first encountered match
63+
pub const matching_pair_chars: ?[]const [2]u21 = &.{ .{ '{', '}' }, .{ '[', ']' }, .{ '(', ')' }, .{ '<', '>' }, .{ '|', '|' } };
64+
+ pub const autosave: bool = false;
7265
};
7366

7467
pub const Dirty = struct {

patch/buffer-centering/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# Buffer centering
22

3-
Adds editor option `.centering_width`
3+
Adds editor option `centering_width`
44

5-
* `.centering_width = N` means that the buffer will be left padded, so that line with N width is horizontally
5+
* `centering_width = N` means that the buffer will be left padded, so that line with N width is horizontally
66
centered within the terminal
7-
* `.centering_width = null` means do not pad, default behavior
7+
* `centering_width = null` means do not pad, default behavior
88

99
## Usage
1010

11-
Configure fields in `config` in `editor.zig`:
11+
Configure fields in `Config` in `editor.zig`:
1212

1313
```zig
14-
.centering_width = 140,
14+
pub const centering_width: ?usize = 140;
1515
```
1616

1717
## Screenshots

0 commit comments

Comments
 (0)