Compare commits
No commits in common. "e7118763a1790300f428edb82486a59ba0ef4e00" and "9b33f4cbe3e6a58f72795f10adeada60836c1443" have entirely different histories.
e7118763a1
...
9b33f4cbe3
3 changed files with 22 additions and 225 deletions
|
|
@ -414,10 +414,6 @@ pub fn build_exe(
|
||||||
.root_source_file = b.path("src/bin_path.zig"),
|
.root_source_file = b.path("src/bin_path.zig"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const snippet_mod = b.createModule(.{
|
|
||||||
.root_source_file = b.path("src/snippet.zig"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const Buffer_mod = b.createModule(.{
|
const Buffer_mod = b.createModule(.{
|
||||||
.root_source_file = b.path("src/buffer/Buffer.zig"),
|
.root_source_file = b.path("src/buffer/Buffer.zig"),
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
|
|
@ -634,7 +630,6 @@ pub fn build_exe(
|
||||||
.{ .name = "zeit", .module = zeit_mod },
|
.{ .name = "zeit", .module = zeit_mod },
|
||||||
.{ .name = "VcsStatus", .module = VcsStatus_mod },
|
.{ .name = "VcsStatus", .module = VcsStatus_mod },
|
||||||
.{ .name = "bin_path", .module = bin_path_mod },
|
.{ .name = "bin_path", .module = bin_path_mod },
|
||||||
.{ .name = "snippet", .module = snippet_mod },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
162
src/snippet.zig
162
src/snippet.zig
|
|
@ -1,162 +0,0 @@
|
||||||
text: []const u8,
|
|
||||||
tabstops: [][]Range,
|
|
||||||
|
|
||||||
const Snippet = @This();
|
|
||||||
const Range = struct { begin: Position, end: ?Position = null };
|
|
||||||
const Position = struct { usize };
|
|
||||||
|
|
||||||
const Tabstop = struct {
|
|
||||||
id: usize,
|
|
||||||
range: Range,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn deinit(self: *const Snippet, allocator: std.mem.Allocator) void {
|
|
||||||
for (self.tabstops) |tabstop| allocator.free(tabstop);
|
|
||||||
allocator.free(self.tabstops);
|
|
||||||
allocator.free(self.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(allocator: std.mem.Allocator, snippet: []const u8) Error!Snippet {
|
|
||||||
var tabstops: std.ArrayList(struct { id: usize, range: Range }) = .empty;
|
|
||||||
defer tabstops.deinit(allocator);
|
|
||||||
var id: ?usize = null;
|
|
||||||
var content_begin: ?Position = null;
|
|
||||||
var max_id: usize = 0;
|
|
||||||
var text: std.Io.Writer.Allocating = .init(allocator);
|
|
||||||
defer text.deinit();
|
|
||||||
|
|
||||||
var state: enum {
|
|
||||||
initial,
|
|
||||||
escape,
|
|
||||||
tabstop,
|
|
||||||
placeholder,
|
|
||||||
content,
|
|
||||||
content_escape,
|
|
||||||
} = .initial;
|
|
||||||
|
|
||||||
var iter = snippet;
|
|
||||||
while (iter.len > 0) : (iter = iter[1..]) {
|
|
||||||
const c = iter[0];
|
|
||||||
fsm: switch (state) {
|
|
||||||
.initial => switch (c) {
|
|
||||||
'\\' => {
|
|
||||||
state = .escape;
|
|
||||||
},
|
|
||||||
'$' => {
|
|
||||||
state = .tabstop;
|
|
||||||
},
|
|
||||||
else => try text.writer.writeByte(c),
|
|
||||||
},
|
|
||||||
.escape => {
|
|
||||||
try text.writer.writeByte(c);
|
|
||||||
state = .initial;
|
|
||||||
},
|
|
||||||
.tabstop => switch (c) {
|
|
||||||
'{' => {
|
|
||||||
state = .placeholder;
|
|
||||||
},
|
|
||||||
'0'...'9' => {
|
|
||||||
const digit: usize = @intCast(c - '0');
|
|
||||||
id = if (id) |id_| (id_ * 10) + digit else digit;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
const pos = snippet.len - iter.len;
|
|
||||||
if (id == null)
|
|
||||||
return invalid(snippet, pos, error.InvalidIdValue);
|
|
||||||
(try tabstops.addOne(allocator)).* = .{
|
|
||||||
.id = id orelse unreachable,
|
|
||||||
.range = .{ .begin = .{text.written().len} },
|
|
||||||
};
|
|
||||||
max_id = @max(id orelse unreachable, max_id);
|
|
||||||
id = null;
|
|
||||||
state = .initial;
|
|
||||||
break :fsm;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.placeholder => switch (c) {
|
|
||||||
'0'...'9' => {
|
|
||||||
const digit: usize = @intCast(c - '0');
|
|
||||||
id = if (id) |id_| (id_ * 10) + digit else digit;
|
|
||||||
},
|
|
||||||
':' => {
|
|
||||||
const pos = snippet.len - iter.len;
|
|
||||||
if (id == null)
|
|
||||||
return invalid(snippet, pos, error.InvalidIdValue);
|
|
||||||
content_begin = .{text.written().len};
|
|
||||||
state = .content;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
const pos = snippet.len - iter.len;
|
|
||||||
return invalid(snippet, pos, error.InvalidIdValue);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.content => switch (c) {
|
|
||||||
'\\' => {
|
|
||||||
state = .content_escape;
|
|
||||||
},
|
|
||||||
'}' => {
|
|
||||||
const pos = snippet.len - iter.len;
|
|
||||||
if (id == null)
|
|
||||||
return invalid(snippet, pos, error.InvalidIdValue);
|
|
||||||
if (content_begin == null)
|
|
||||||
return invalid(snippet, pos, error.InvalidPlaceholderValue);
|
|
||||||
(try tabstops.addOne(allocator)).* = .{
|
|
||||||
.id = id orelse unreachable,
|
|
||||||
.range = .{
|
|
||||||
.begin = content_begin orelse unreachable,
|
|
||||||
.end = .{text.written().len},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
max_id = @max(id orelse unreachable, max_id);
|
|
||||||
id = null;
|
|
||||||
content_begin = null;
|
|
||||||
state = .initial;
|
|
||||||
},
|
|
||||||
else => try text.writer.writeByte(c),
|
|
||||||
},
|
|
||||||
.content_escape => {
|
|
||||||
try text.writer.writeByte(c);
|
|
||||||
state = .content;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state != .initial) {
|
|
||||||
const pos = snippet.len - iter.len;
|
|
||||||
if (id == null)
|
|
||||||
return invalid(snippet, pos, error.UnexpectedEndOfDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result: std.ArrayList([]Range) = .empty;
|
|
||||||
defer result.deinit(allocator);
|
|
||||||
var n: usize = 1;
|
|
||||||
while (n <= max_id) : (n += 1) {
|
|
||||||
var tabstop: std.ArrayList(Range) = .empty;
|
|
||||||
errdefer tabstop.deinit(allocator);
|
|
||||||
for (tabstops.items) |item| if (item.id == n) {
|
|
||||||
(try tabstop.addOne(allocator)).* = item.range;
|
|
||||||
};
|
|
||||||
(try result.addOne(allocator)).* = try tabstop.toOwnedSlice(allocator);
|
|
||||||
}
|
|
||||||
return .{
|
|
||||||
.text = try text.toOwnedSlice(),
|
|
||||||
.tabstops = try result.toOwnedSlice(allocator),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalid(snippet: []const u8, pos: usize, e: Error) Error {
|
|
||||||
log.err("invalid snippet: {s}", .{snippet});
|
|
||||||
log.err("{t} at pos {d}", .{ e, pos });
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Error = error{
|
|
||||||
WriteFailed,
|
|
||||||
OutOfMemory,
|
|
||||||
InvalidIdValue,
|
|
||||||
InvalidPlaceholderValue,
|
|
||||||
UnexpectedEndOfDocument,
|
|
||||||
};
|
|
||||||
|
|
||||||
const log = std.log.scoped(.snippet);
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
@ -45,18 +45,18 @@ pub fn load_entries(palette: *Type) !usize {
|
||||||
max_description = 0;
|
max_description = 0;
|
||||||
var max_label_len: usize = 0;
|
var max_label_len: usize = 0;
|
||||||
for (palette.entries.items) |*item| {
|
for (palette.entries.items) |*item| {
|
||||||
const values = get_values(item.cbor);
|
const label_, const sort_text, _, const maybe_replace, _, const label_detail, const label_description, _, _ = get_values(item.cbor);
|
||||||
if (get_replace_selection(values.replace)) |replace| {
|
if (get_replace_selection(maybe_replace)) |replace| {
|
||||||
if (palette.value.replace == null) palette.value.replace = replace;
|
if (palette.value.replace == null) palette.value.replace = replace;
|
||||||
}
|
}
|
||||||
item.label = values.label;
|
item.label = label_;
|
||||||
item.sort_text = values.sort_text;
|
item.sort_text = sort_text;
|
||||||
|
|
||||||
var lines = std.mem.splitScalar(u8, values.label_description, '\n');
|
var lines = std.mem.splitScalar(u8, label_description, '\n');
|
||||||
const label_description_len = if (lines.next()) |desc| desc.len else values.label_description.len;
|
const label_description_len = if (lines.next()) |desc| desc.len else label_description.len;
|
||||||
|
|
||||||
max_label_len = @max(max_label_len, item.label.len);
|
max_label_len = @max(max_label_len, item.label.len);
|
||||||
max_description = @max(max_description, label_description_len + values.label_detail.len);
|
max_description = @max(max_description, label_description_len + label_detail.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
const less_fn = struct {
|
const less_fn = struct {
|
||||||
|
|
@ -102,17 +102,17 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonType, theme: *const Widget.T
|
||||||
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&item_cbor)) catch false)) return false;
|
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&item_cbor)) catch false)) return false;
|
||||||
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) return false;
|
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) return false;
|
||||||
|
|
||||||
const values = get_values(item_cbor);
|
const label_, _, const kind, _, _, const label_detail, const label_description, _, _ = get_values(item_cbor);
|
||||||
const icon_: []const u8 = kind_icon(@enumFromInt(values.kind));
|
const icon_: []const u8 = kind_icon(@enumFromInt(kind));
|
||||||
const color: u24 = 0x0;
|
const color: u24 = 0x0;
|
||||||
|
|
||||||
return tui.render_symbol(
|
return tui.render_symbol(
|
||||||
&button.plane,
|
&button.plane,
|
||||||
values.label,
|
label_,
|
||||||
icon_,
|
icon_,
|
||||||
color,
|
color,
|
||||||
values.label_detail,
|
label_detail,
|
||||||
values.label_description,
|
label_description,
|
||||||
matches_cbor,
|
matches_cbor,
|
||||||
button.active,
|
button.active,
|
||||||
selected,
|
selected,
|
||||||
|
|
@ -121,21 +121,7 @@ pub fn on_render_menu(_: *Type, button: *Type.ButtonType, theme: *const Widget.T
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Values = struct {
|
fn get_values(item_cbor: []const u8) struct { []const u8, []const u8, u8, Buffer.Selection, []const u8, []const u8, []const u8, []const u8, []const u8 } {
|
||||||
label: []const u8,
|
|
||||||
sort_text: []const u8,
|
|
||||||
kind: u8,
|
|
||||||
replace: Buffer.Selection,
|
|
||||||
additionalTextEdits: []const u8,
|
|
||||||
label_detail: []const u8,
|
|
||||||
label_description: []const u8,
|
|
||||||
detail: []const u8,
|
|
||||||
documentation: []const u8,
|
|
||||||
insertTextFormat: usize,
|
|
||||||
textEdit_newText: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn get_values(item_cbor: []const u8) Values {
|
|
||||||
var label_: []const u8 = "";
|
var label_: []const u8 = "";
|
||||||
var label_detail: []const u8 = "";
|
var label_detail: []const u8 = "";
|
||||||
var label_description: []const u8 = "";
|
var label_description: []const u8 = "";
|
||||||
|
|
@ -172,19 +158,7 @@ fn get_values(item_cbor: []const u8) Values {
|
||||||
cbor.extract(&replace.end.col), // replace.end.col
|
cbor.extract(&replace.end.col), // replace.end.col
|
||||||
cbor.extract_cbor(&additionalTextEdits),
|
cbor.extract_cbor(&additionalTextEdits),
|
||||||
}) catch false;
|
}) catch false;
|
||||||
return .{
|
return .{ label_, sort_text, kind, replace, additionalTextEdits, label_detail, label_description, detail, documentation };
|
||||||
.label = label_,
|
|
||||||
.sort_text = sort_text,
|
|
||||||
.kind = kind,
|
|
||||||
.replace = replace,
|
|
||||||
.additionalTextEdits = additionalTextEdits,
|
|
||||||
.label_detail = label_detail,
|
|
||||||
.label_description = label_description,
|
|
||||||
.detail = detail,
|
|
||||||
.documentation = documentation,
|
|
||||||
.insertTextFormat = insertTextFormat,
|
|
||||||
.textEdit_newText = textEdit_newText,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TextEdit = struct { newText: []const u8 = &.{}, insert: ?Range = null, replace: ?Range = null };
|
const TextEdit = struct { newText: []const u8 = &.{}, insert: ?Range = null, replace: ?Range = null };
|
||||||
|
|
@ -201,35 +175,25 @@ fn get_replace_selection(replace: Buffer.Selection) ?Buffer.Selection {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select(menu: **Type.MenuType, button: *Type.ButtonType, _: Type.Pos) void {
|
fn select(menu: **Type.MenuType, button: *Type.ButtonType, _: Type.Pos) void {
|
||||||
const values = get_values(button.opts.label);
|
const label_, _, _, _, _, _, _, _, _ = get_values(button.opts.label);
|
||||||
switch (values.insertTextFormat) {
|
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
2 => {
|
tp.self_pid().send(.{ "cmd", "insert_chars", .{label_} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
const snippet = @import("snippet").parse(menu.*.opts.ctx.allocator, values.textEdit_newText) catch return;
|
|
||||||
defer snippet.deinit(menu.*.opts.ctx.allocator);
|
|
||||||
tp.self_pid().send(.{ "cmd", "insert_chars", .{snippet.text} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
tp.self_pid().send(.{ "cmd", "insert_chars", .{values.label} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const mv = tui.mainview() orelse return;
|
const mv = tui.mainview() orelse return;
|
||||||
mv.cancel_info_content() catch {};
|
mv.cancel_info_content() catch {};
|
||||||
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updated(palette: *Type, button_: ?*Type.ButtonType) !void {
|
pub fn updated(palette: *Type, button_: ?*Type.ButtonType) !void {
|
||||||
const button = button_ orelse return cancel(palette);
|
const button = button_ orelse return cancel(palette);
|
||||||
const values = get_values(button.opts.label);
|
const label_, _, _, const replace, _, _, _, const detail, const documentation = get_values(button.opts.label);
|
||||||
const editor = tui.get_active_editor() orelse return error.NotFound;
|
const editor = tui.get_active_editor() orelse return error.NotFound;
|
||||||
editor.get_primary().selection = get_replace_selection(values.replace);
|
editor.get_primary().selection = get_replace_selection(replace);
|
||||||
|
|
||||||
const mv = tui.mainview() orelse return;
|
const mv = tui.mainview() orelse return;
|
||||||
try mv.set_info_content(values.label, .replace);
|
try mv.set_info_content(label_, .replace);
|
||||||
try mv.set_info_content(" ", .append); // blank line
|
try mv.set_info_content(" ", .append); // blank line
|
||||||
try mv.set_info_content(values.detail, .append);
|
try mv.set_info_content(detail, .append);
|
||||||
// try mv.set_info_content(values.textEdit_newText, .append);
|
|
||||||
try mv.set_info_content(" ", .append); // blank line
|
try mv.set_info_content(" ", .append); // blank line
|
||||||
try mv.set_info_content(values.documentation, .append);
|
try mv.set_info_content(documentation, .append);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cancel(palette: *Type) !void {
|
pub fn cancel(palette: *Type) !void {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue