Skip to content

Commit 3b23f78

Browse files
committed
Merge branch 'master' into personal
2 parents 0a28113 + 85a29f1 commit 3b23f78

9 files changed

Lines changed: 91 additions & 75 deletions

File tree

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ Hat is a **ha**ckable modal **t**ext editor for modern terminals.
6565

6666
## Philosophy
6767

68-
Based on [suckless](https://suckless.org/philosophy/) and
69-
[unix](https://en.wikipedia.org/wiki/Unix_philosophy) philosophies.
70-
7168
Software is:
7269
- doing not more and not less than what the user needs
7370
* Every feature is implemented in the most simple and straightforward form: keep it simple, fast, and clear
@@ -78,10 +75,12 @@ Software is:
7875
- distributed as source code, compiled by the user
7976
- not meant to be developed forever and its final state should be described by its feature set from
8077
the beginning
81-
- extended either by the user directly or by applying
82-
[source code patches](https://en.wikipedia.org/wiki/Patch_(computing)#Source_code_patching), distributed as diff files
78+
- extended either by the user directly, or by applying [source code patches](https://en.wikipedia.org/wiki/Patch_(computing)#Source_code_patching)
79+
distributed as diff files
8380
* It is encouraged to share your extensions with others who can find it useful
8481

82+
See [Hackable software](http://blog.ivnj.org/post/hackable-software.html) for details.
83+
8584
## Build, install, usage, configuration
8685

8786
See [`HACKING.md`](HACKING.md).

src/color.zig

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const std = @import("std");
2+
const lsp = @import("lsp");
23

34
pub const RgbColor = struct {
45
r: u8,
@@ -46,7 +47,7 @@ pub const AnsiColor = enum(u8) {
4647
}
4748
};
4849

49-
pub const Color = struct {
50+
pub const color = struct {
5051
pub const black = RgbColor.fromHex(0x000000);
5152
pub const gray1 = RgbColor.fromHex(0x1b1b1d);
5253
pub const gray2 = RgbColor.fromHex(0x2a2a2d);
@@ -63,14 +64,14 @@ pub const Color = struct {
6364
pub const magenta = RgbColor.fromHex(0xd3a8ef);
6465
};
6566

66-
pub const Attr = union(enum) {
67+
pub const Attribute = union(enum) {
6768
fg: RgbColor,
6869
bg: RgbColor,
6970
underline: RgbColor,
7071
curly_underline,
7172
bold,
7273

73-
pub fn write(self: Attr, writer: *std.io.Writer) !void {
74+
pub fn write(self: Attribute, writer: *std.io.Writer) !void {
7475
switch (self) {
7576
.fg => |c| try writer.print("\x1b[38;2;{};{};{}m", .{ c.r, c.g, c.b }),
7677
.bg => |c| try writer.print("\x1b[48;2;{};{};{}m", .{ c.r, c.g, c.b }),
@@ -79,31 +80,41 @@ pub const Attr = union(enum) {
7980
.bold => _ = try writer.write("\x1b[1m"),
8081
}
8182
}
82-
};
8383

84-
pub const Attributes = struct {
85-
pub const text = &[_]Attr{.{ .fg = Color.white }};
86-
pub const selection = &[_]Attr{.{ .bg = Color.gray3 }};
87-
pub const selection_normal = &[_]Attr{.{ .bg = Color.gray2 }};
88-
pub const highlight = &[_]Attr{.{ .bg = Color.gray3 }};
89-
pub const keyword = &[_]Attr{.{ .fg = Color.magenta }};
90-
pub const string = &[_]Attr{.{ .fg = Color.green }};
91-
pub const literal = &[_]Attr{.{ .fg = Color.yellow }};
92-
pub const comment = &[_]Attr{.{ .fg = Color.gray7 }};
93-
pub const diagnostic_error = &[_]Attr{ .curly_underline, .{ .underline = Color.red } };
94-
pub const completion_menu = &[_]Attr{.{ .bg = Color.gray2 }};
95-
pub const completion_menu_active = &[_]Attr{.{ .bg = Color.gray4 }};
96-
pub const overlay = &[_]Attr{.{ .bg = Color.gray2 }};
97-
pub const message = &[_]Attr{.{ .bg = Color.gray2 }};
98-
pub const command_line = &[_]Attr{.{ .bg = Color.gray2 }};
99-
pub const number_line = &[_]Attr{.{ .fg = Color.gray4 }};
100-
pub const git_added = &[_]Attr{ .{ .fg = Color.green }, .bold };
101-
pub const git_modified = &[_]Attr{ .{ .fg = Color.yellow }, .bold };
102-
pub const git_deleted = &[_]Attr{ .{ .fg = Color.red }, .bold };
84+
pub const text = &[_]Attribute{.{ .fg = color.white }};
85+
pub const selection = &[_]Attribute{.{ .bg = color.gray3 }};
86+
pub const selection_normal = &[_]Attribute{.{ .bg = color.gray2 }};
87+
pub const highlight = &[_]Attribute{.{ .bg = color.gray3 }};
88+
pub const keyword = &[_]Attribute{.{ .fg = color.magenta }};
89+
pub const string = &[_]Attribute{.{ .fg = color.green }};
90+
pub const literal = &[_]Attribute{.{ .fg = color.yellow }};
91+
pub const comment = &[_]Attribute{.{ .fg = color.gray7 }};
92+
pub const completion_menu = &[_]Attribute{.{ .bg = color.gray2 }};
93+
pub const completion_menu_active = &[_]Attribute{.{ .bg = color.gray4 }};
94+
pub const overlay = &[_]Attribute{.{ .bg = color.gray2 }};
95+
pub const message = &[_]Attribute{.{ .bg = color.gray2 }};
96+
pub const command_line = &[_]Attribute{.{ .bg = color.gray2 }};
97+
pub const number_line = &[_]Attribute{.{ .fg = color.gray4 }};
98+
pub const git_added = &[_]Attribute{ .{ .fg = color.green }, .bold };
99+
pub const git_modified = &[_]Attribute{ .{ .fg = color.yellow }, .bold };
100+
pub const git_deleted = &[_]Attribute{ .{ .fg = color.red }, .bold };
101+
pub const diagnostic_error = &[_]Attribute{ .curly_underline, .{ .underline = color.red } };
102+
pub const diagnostic_warn = &[_]Attribute{ .curly_underline, .{ .underline = color.yellow } };
103+
pub const diagnostic_info = &[_]Attribute{ .curly_underline, .{ .underline = color.magenta } };
104+
pub const diagnostic_hint = &[_]Attribute{.{ .fg = color.gray6 }};
103105

104-
pub fn write(attrs: []const Attr, writer: *std.io.Writer) !void {
106+
pub fn writeSlice(attrs: []const Attribute, writer: *std.io.Writer) !void {
105107
for (attrs) |attr| {
106108
try attr.write(writer);
107109
}
108110
}
111+
112+
pub fn diagnosticSeverity(severity: lsp.types.DiagnosticSeverity) []const Attribute {
113+
return switch (severity) {
114+
.Warning => diagnostic_warn,
115+
.Information => diagnostic_info,
116+
.Hint => diagnostic_hint,
117+
else => diagnostic_error,
118+
};
119+
}
109120
};

src/lsp.zig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub const LspConnection = struct {
103103
stdin_buf: [2 << 12]u8 = undefined,
104104
stdin_writer: std.fs.File.Writer,
105105
/// Updates left for connection to terminate until forced termination
106-
wait_fuel: usize = 30,
106+
wait_fuel: usize = 10,
107107
allocator: Allocator,
108108

109109
pub fn connect(allocator: Allocator, config: LspConfig) !LspConnection {
@@ -702,7 +702,9 @@ pub const LspConnection = struct {
702702
if (main.editor.findBufferByUri(params_typed.value.uri)) |buffer| {
703703
buffer.clearDiagnostics();
704704
for (params_typed.value.diagnostics) |diagnostic| {
705-
try buffer.diagnostics.append(self.allocator, try dia.Diagnostic.fromLsp(buffer.allocator, diagnostic));
705+
var d = try dia.Diagnostic.fromLsp(buffer.allocator, diagnostic);
706+
if (std.meta.eql(d.span.start, d.span.end)) d.span.end.col += 1;
707+
try buffer.diagnostics.append(self.allocator, d);
706708
}
707709
std.mem.sort(dia.Diagnostic, buffer.diagnostics.items, {}, dia.Diagnostic.lessThan);
708710
log.debug(@This(), "got {} diagnostics\n", .{buffer.diagnostics.items.len});

src/printer.zig

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,22 @@ pub fn printBuffer(buffer: *buf.Buffer, writer: *std.io.Writer, highlight: ?High
6262
if (buffer.ts_state) |ts_state| {
6363
if (ts_state.highlight) |hi| {
6464
const highlight_spans = hi.spans.items;
65-
const ch_attrs: []const co.Attr = b: while (span_index < highlight_spans.len) {
65+
const ch_attrs: []const co.Attribute = b: while (span_index < highlight_spans.len) {
6666
const span = highlight_spans[span_index];
67-
if (span.span.start > byte) break :b co.Attributes.text;
67+
if (span.span.start > byte) break :b co.Attribute.text;
6868
if (byte >= span.span.start and byte < span.span.end) {
6969
break :b span.attrs;
7070
}
7171
span_index += 1;
7272
} else {
73-
break :b co.Attributes.text;
73+
break :b co.Attribute.text;
7474
};
75-
try co.Attributes.write(ch_attrs, &attrs_writer);
75+
try co.Attribute.writeSlice(ch_attrs, &attrs_writer);
7676
}
7777
}
7878

7979
const hi_line = highlight != null and row == highlight.?.highlight_line;
80-
if (hi_line) try co.Attributes.write(co.Attributes.selection, &attrs_writer);
80+
if (hi_line) try co.Attribute.writeSlice(co.Attribute.selection, &attrs_writer);
8181

8282
attrs = attrs_writer.buffered();
8383
if (last_attrs == null or !std.mem.eql(u8, attrs, last_attrs.?)) {

src/signal.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ const log = @import("log.zig");
44
const main = @import("main.zig");
55
const ter = @import("terminal.zig");
66

7-
pub const SigHandle = struct { sig: u8, handle: std.posix.Sigaction.handler_fn };
7+
pub const SigHandle = struct {
8+
sig: u8,
9+
handle: std.posix.Sigaction.handler_fn,
10+
};
811

912
pub const sig_handle = .{
1013
.int = SigHandle{ .sig = std.posix.SIG.INT, .handle = handleSigInt },

src/terminal.zig

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ pub const Terminal = struct {
127127
try self.writer.writeAll(if (enable) "\x1b[?7h" else "\x1b[?7l");
128128
}
129129

130-
fn resetAttributes(self: *Terminal) !void {
130+
fn resetAttribute(self: *Terminal) !void {
131131
try self.writer.writeAll("\x1b[0m");
132132
}
133133

@@ -140,8 +140,8 @@ pub const Terminal = struct {
140140
}
141141

142142
fn drawNumberLine(self: *Terminal, buffer: *buf.Buffer, area: Area) !void {
143-
try co.Attributes.write(co.Attributes.number_line, self.writer);
144-
defer self.resetAttributes() catch {};
143+
try co.Attribute.writeSlice(co.Attribute.number_line, self.writer);
144+
defer self.resetAttribute() catch {};
145145
const cursor_row = buffer.cursor.row;
146146
for (@intCast(area.pos.row)..@as(usize, @intCast(area.pos.row)) + area.dims.height) |term_row| {
147147
const buffer_row = @as(i32, @intCast(term_row)) + buffer.offset.row;
@@ -194,15 +194,15 @@ pub const Terminal = struct {
194194
try self.moveCursor(.{ .row = @intCast(term_row), .col = area.pos.col });
195195
switch (hunk.type) {
196196
.add => {
197-
try co.Attributes.write(co.Attributes.git_added, self.writer);
197+
try co.Attribute.writeSlice(co.Attribute.git_added, self.writer);
198198
try self.writer.writeAll("┃");
199199
},
200200
.delete => {
201-
try co.Attributes.write(co.Attributes.git_deleted, self.writer);
201+
try co.Attribute.writeSlice(co.Attribute.git_deleted, self.writer);
202202
try self.writer.writeAll("▁");
203203
},
204204
.modify => {
205-
try co.Attributes.write(co.Attributes.git_modified, self.writer);
205+
try co.Attribute.writeSlice(co.Attribute.git_modified, self.writer);
206206
try self.writer.writeAll("┃");
207207
},
208208
}
@@ -252,30 +252,30 @@ pub const Terminal = struct {
252252
if (buffer.ts_state) |ts_state| {
253253
if (ts_state.highlight) |hi| {
254254
const highlight_spans = hi.spans.items;
255-
const ch_attrs: []const co.Attr = b: while (span_index < highlight_spans.len) {
255+
const ch_attrs: []const co.Attribute = b: while (span_index < highlight_spans.len) {
256256
const span = highlight_spans[span_index];
257-
if (span.span.start > byte) break :b co.Attributes.text;
257+
if (span.span.start > byte) break :b co.Attribute.text;
258258
if (byte >= span.span.start and byte < span.span.end) {
259259
break :b span.attrs;
260260
}
261261
span_index += 1;
262262
} else {
263-
break :b co.Attributes.text;
263+
break :b co.Attribute.text;
264264
};
265-
try co.Attributes.write(ch_attrs, &attrs_writer);
265+
try co.Attribute.writeSlice(ch_attrs, &attrs_writer);
266266
}
267267
}
268268

269269
if (buffer.selection) |selection| {
270270
if (selection.inRange(.{ .row = buffer_row, .col = buffer_col })) {
271-
const attr = if (buffer.mode.isSelect()) co.Attributes.selection else co.Attributes.selection_normal;
272-
try co.Attributes.write(attr, &attrs_writer);
271+
const attr = if (buffer.mode.isSelect()) co.Attribute.selection else co.Attribute.selection_normal;
272+
try co.Attribute.writeSlice(attr, &attrs_writer);
273273
}
274274
} else {
275275
if (buffer.mode == .normal) {
276276
for (buffer.highlights.items) |hi| {
277277
if (hi.inRange(.{ .row = buffer_row, .col = buffer_col })) {
278-
try co.Attributes.write(co.Attributes.highlight, &attrs_writer);
278+
try co.Attribute.writeSlice(co.Attribute.highlight, &attrs_writer);
279279
}
280280
}
281281
}
@@ -286,15 +286,15 @@ pub const Terminal = struct {
286286
const span = diagnostic.span;
287287

288288
if (span.inRange(.{ .row = buffer_row, .col = buffer_col })) {
289-
try co.Attributes.write(co.Attributes.diagnostic_error, &attrs_writer);
289+
try co.Attribute.writeSlice(co.Attribute.diagnosticSeverity(diagnostic.severity), &attrs_writer);
290290
break;
291291
}
292292
}
293293
}
294294

295295
attrs = attrs_writer.buffered();
296296
if (last_attrs == null or !std.mem.eql(u8, attrs, last_attrs.?)) {
297-
self.resetAttributes() catch {};
297+
self.resetAttribute() catch {};
298298
try self.writer.writeAll(attrs);
299299
@memcpy(&last_attrs_buf, &attrs_buf);
300300
last_attrs = last_attrs_buf[0..attrs.len];
@@ -308,7 +308,7 @@ pub const Terminal = struct {
308308
if (col_width > 1) try self.moveCursor(.{ .row = @intCast(term_row), .col = area.pos.col + area_col });
309309
}
310310
// reached line end
311-
try self.resetAttributes();
311+
try self.resetAttribute();
312312
last_attrs = null;
313313
}
314314
}
@@ -337,7 +337,7 @@ pub const Terminal = struct {
337337
const menu_width = @min(max_width, longest_item + 1);
338338

339339
{
340-
try self.resetAttributes();
340+
try self.resetAttribute();
341341

342342
for (0..cmp_menu.display_items.items.len) |menu_row| {
343343
const idx = cmp_menu.display_items.items[menu_row];
@@ -347,9 +347,9 @@ pub const Terminal = struct {
347347
.col = menu_pos.col,
348348
});
349349
if (menu_row == cmp_menu.active_item) {
350-
try co.Attributes.write(co.Attributes.completion_menu_active, self.writer);
350+
try co.Attribute.writeSlice(co.Attribute.completion_menu_active, self.writer);
351351
} else {
352-
try co.Attributes.write(co.Attributes.completion_menu, self.writer);
352+
try co.Attribute.writeSlice(co.Attribute.completion_menu, self.writer);
353353
}
354354
try self.writer.writeAll(cmp_item.label[0..@min(cmp_item.label.len, menu_width)]);
355355

@@ -360,7 +360,7 @@ pub const Terminal = struct {
360360
}
361361
}
362362
}
363-
try self.resetAttributes();
363+
try self.resetAttribute();
364364
}
365365

366366
{
@@ -436,8 +436,8 @@ pub const Terminal = struct {
436436
/// Draw a box on top of the editor's content, containing `lines`
437437
/// Box width is min(longest line, available area)
438438
fn drawOverlay(self: *Terminal, lines: []const []const u8, pos: Cursor) !void {
439-
try co.Attributes.write(co.Attributes.overlay, self.writer);
440-
defer self.resetAttributes() catch {};
439+
try co.Attribute.writeSlice(co.Attribute.overlay, self.writer);
440+
defer self.resetAttribute() catch {};
441441

442442
const max_doc_width = 90;
443443
var longest_line: usize = 0;
@@ -466,21 +466,21 @@ pub const Terminal = struct {
466466
const message = main.editor.messages.items[main.editor.message_read_idx];
467467
const message_height = std.mem.count(u8, message, "\n") + 1;
468468
try self.moveCursor(.{ .row = @intCast(self.dimensions.height - message_height) });
469-
try co.Attributes.write(co.Attributes.message, self.writer);
469+
try co.Attribute.writeSlice(co.Attribute.message, self.writer);
470470
try self.writer.writeAll(message);
471-
try self.resetAttributes();
471+
try self.resetAttribute();
472472
}
473473

474474
fn drawCmd(self: *Terminal, command_line: *const cmd.CommandLine) !void {
475475
const last_row = self.dimensions.height - 1;
476476
const prefix = command_line.command.?.prefix();
477477
try self.moveCursor(.{ .row = @intCast(last_row) });
478-
try co.Attributes.write(co.Attributes.command_line, self.writer);
478+
try co.Attribute.writeSlice(co.Attribute.command_line, self.writer);
479479
try self.writer.writeAll(prefix);
480480
for (command_line.content.items) |ch| {
481481
try uni.unicodeToBytesWrite(self.writer, &.{ch});
482482
}
483-
try self.resetAttributes();
483+
try self.resetAttribute();
484484
try self.moveCursor(.{ .row = @intCast(last_row), .col = @intCast(prefix.len + command_line.cursor) });
485485
}
486486
};

src/ts.zig

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ pub const State = struct {
169169

170170
pub const AttrsSpan = struct {
171171
span: SpanFlat,
172-
attrs: []const col.Attr,
172+
attrs: []const col.Attribute,
173173

174174
/// Capture name is a dot-separated list of ts node types, forming hierarchy, e.g. `identifier.type`
175175
/// @see https://tree-sitter.github.io/tree-sitter/using-parsers/queries/2-operators.html#capturing-nodes
@@ -185,7 +185,7 @@ pub const AttrsSpan = struct {
185185
/// * check `identifier.type`
186186
/// * check `identifier`
187187
/// * null
188-
pub fn findAttrs(capture_name: []const u8) ?[]const col.Attr {
188+
pub fn findAttrs(capture_name: []const u8) ?[]const col.Attribute {
189189
if (node_highlights_exact.get(capture_name)) |a| return a;
190190
if (node_highlights.get(capture_name)) |a| return a;
191191
if (!std.mem.containsAtLeastScalar(u8, capture_name, 1, '.')) return null;
@@ -201,16 +201,16 @@ pub const AttrsSpan = struct {
201201
}
202202
};
203203

204-
pub const node_highlights = std.StaticStringMap([]const col.Attr).initComptime(.{
205-
.{ "keyword", col.Attributes.keyword },
206-
.{ "string", col.Attributes.string },
207-
.{ "number", col.Attributes.literal },
208-
.{ "boolean", col.Attributes.literal },
209-
.{ "comment", col.Attributes.comment },
204+
pub const node_highlights = std.StaticStringMap([]const col.Attribute).initComptime(.{
205+
.{ "keyword", col.Attribute.keyword },
206+
.{ "string", col.Attribute.string },
207+
.{ "number", col.Attribute.literal },
208+
.{ "boolean", col.Attribute.literal },
209+
.{ "comment", col.Attribute.comment },
210210
});
211211

212-
pub const node_highlights_exact = std.StaticStringMap([]const col.Attr).initComptime(.{
213-
.{ "tag", col.Attributes.keyword },
212+
pub const node_highlights_exact = std.StaticStringMap([]const col.Attribute).initComptime(.{
213+
.{ "tag", col.Attribute.keyword },
214214
});
215215

216216
pub fn firstSmallestDescendentInSpan(node: ts.TSNode, span: SpanFlat) ?ts.TSNode {

0 commit comments

Comments
 (0)