Compare commits
No commits in common. "master" and "zig-0.13" have entirely different histories.
77 changed files with 1343 additions and 3770 deletions
20
README.md
20
README.md
|
@ -15,28 +15,14 @@ https://github.com/neurocyte/flow/assets/1552770/97aae817-c209-4c08-bc65-0a0bf1f
|
|||
|
||||
# Download / Install
|
||||
|
||||
Binary release builds are found here: [neurocyte/flow/releases](https://github.com/neurocyte/flow/releases/latest)
|
||||
|
||||
Fetch and install the latest release to `/usr/local/bin` with the installation helper script:
|
||||
|
||||
```shell
|
||||
curl -fsSL https://flow-control.dev/install | sh
|
||||
```
|
||||
|
||||
Binary release builds are found here: [neurocyte/flow/releases](https://github.com/neurocyte/flow/releases/latest)
|
||||
|
||||
Nightly binary builds are found here: [neurocyte/flow-nightly/releases](https://github.com/neurocyte/flow-nightly/releases/latest)
|
||||
|
||||
Install latest nightly build and (optionally) specify the installation destination:
|
||||
|
||||
```
|
||||
curl -fsSL https://flow-control.dev/install | sh -s -- --nightly --dest ~/.local/bin
|
||||
```
|
||||
|
||||
See all avalable options for the installer script:
|
||||
|
||||
```
|
||||
curl -fsSL https://flow-control.dev/install | sh -s -- --help
|
||||
```
|
||||
|
||||
Or check your favorite local system package repository.
|
||||
|
||||
[](https://repology.org/project/flow-control/versions)
|
||||
|
@ -45,7 +31,7 @@ Or check your favorite local system package repository.
|
|||
|
||||
Make sure your system meets the requirements listed above.
|
||||
|
||||
Flow builds with zig 0.14.0 at this time. Build with:
|
||||
Flow builds with zig 0.13 at this time. Build with:
|
||||
|
||||
```shell
|
||||
zig build -Doptimize=ReleaseSafe
|
||||
|
|
51
build.zig
51
build.zig
|
@ -17,13 +17,6 @@ pub fn build(b: *std.Build) void {
|
|||
const test_step = b.step("test", "Run unit tests");
|
||||
const lint_step = b.step("lint", "Run lints");
|
||||
|
||||
var version = std.ArrayList(u8).init(b.allocator);
|
||||
defer version.deinit();
|
||||
gen_version(b, version.writer()) catch {
|
||||
version.clearAndFree();
|
||||
version.appendSlice("unknown") catch {};
|
||||
};
|
||||
|
||||
return (if (release) &build_release else &build_development)(
|
||||
b,
|
||||
run_step,
|
||||
|
@ -36,7 +29,6 @@ pub fn build(b: *std.Build) void {
|
|||
use_llvm,
|
||||
pie,
|
||||
gui,
|
||||
version.items,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -52,7 +44,6 @@ fn build_development(
|
|||
use_llvm: ?bool,
|
||||
pie: ?bool,
|
||||
gui: bool,
|
||||
version: []const u8,
|
||||
) void {
|
||||
const target = b.standardTargetOptions(.{ .default_target = .{ .abi = if (builtin.os.tag == .linux and !tracy_enabled) .musl else null } });
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
@ -72,7 +63,6 @@ fn build_development(
|
|||
use_llvm,
|
||||
pie,
|
||||
gui,
|
||||
version,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -88,7 +78,6 @@ fn build_release(
|
|||
use_llvm: ?bool,
|
||||
pie: ?bool,
|
||||
_: bool, //gui
|
||||
version: []const u8,
|
||||
) void {
|
||||
const targets: []const std.Target.Query = &.{
|
||||
.{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl },
|
||||
|
@ -102,8 +91,11 @@ fn build_release(
|
|||
};
|
||||
const optimize = .ReleaseFast;
|
||||
|
||||
var version = std.ArrayList(u8).init(b.allocator);
|
||||
defer version.deinit();
|
||||
gen_version(b, version.writer()) catch unreachable;
|
||||
const write_file_step = b.addWriteFiles();
|
||||
const version_file = write_file_step.add("version", version);
|
||||
const version_file = write_file_step.add("version", version.items);
|
||||
b.getInstallStep().dependOn(&b.addInstallFile(version_file, "version").step);
|
||||
|
||||
for (targets) |t| {
|
||||
|
@ -128,7 +120,6 @@ fn build_release(
|
|||
use_llvm,
|
||||
pie,
|
||||
false, //gui
|
||||
version,
|
||||
);
|
||||
|
||||
if (t.os_tag == .windows)
|
||||
|
@ -147,7 +138,6 @@ fn build_release(
|
|||
use_llvm,
|
||||
pie,
|
||||
true, //gui
|
||||
version,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +157,6 @@ pub fn build_exe(
|
|||
use_llvm: ?bool,
|
||||
pie: ?bool,
|
||||
gui: bool,
|
||||
version: []const u8,
|
||||
) void {
|
||||
const options = b.addOptions();
|
||||
options.addOption(bool, "enable_tracy", tracy_enabled);
|
||||
|
@ -194,8 +183,7 @@ pub fn build_exe(
|
|||
};
|
||||
|
||||
const wf = b.addWriteFiles();
|
||||
const version_file = wf.add("version", version);
|
||||
const version_info_file = wf.add("version_info", version_info.items);
|
||||
const version_info_file = wf.add("version", version_info.items);
|
||||
|
||||
const vaxis_dep = b.dependency("vaxis", .{
|
||||
.target = target,
|
||||
|
@ -225,12 +213,7 @@ pub fn build_exe(
|
|||
});
|
||||
|
||||
const thespian_mod = thespian_dep.module("thespian");
|
||||
|
||||
const cbor_dep = thespian_dep.builder.dependency("cbor", .{
|
||||
.target = target,
|
||||
.optimize = optimize_deps,
|
||||
});
|
||||
const cbor_mod = cbor_dep.module("cbor");
|
||||
const cbor_mod = thespian_dep.module("cbor");
|
||||
|
||||
const tracy_dep = if (tracy_enabled) thespian_dep.builder.dependency("tracy", .{
|
||||
.target = target,
|
||||
|
@ -305,10 +288,6 @@ pub fn build_exe(
|
|||
.root_source_file = b.path("src/color.zig"),
|
||||
});
|
||||
|
||||
const bin_path_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/bin_path.zig"),
|
||||
});
|
||||
|
||||
const Buffer_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/buffer/Buffer.zig"),
|
||||
.imports = &.{
|
||||
|
@ -424,16 +403,6 @@ pub fn build_exe(
|
|||
},
|
||||
});
|
||||
|
||||
const git_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/git.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "thespian", .module = thespian_mod },
|
||||
.{ .name = "cbor", .module = cbor_mod },
|
||||
.{ .name = "shell", .module = shell_mod },
|
||||
.{ .name = "bin_path", .module = bin_path_mod },
|
||||
},
|
||||
});
|
||||
|
||||
const ripgrep_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/ripgrep.zig"),
|
||||
.imports = &.{
|
||||
|
@ -461,7 +430,6 @@ pub fn build_exe(
|
|||
.{ .name = "syntax", .module = syntax_mod },
|
||||
.{ .name = "dizzy", .module = dizzy_dep.module("dizzy") },
|
||||
.{ .name = "fuzzig", .module = fuzzig_dep.module("fuzzig") },
|
||||
.{ .name = "git", .module = git_mod },
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -501,7 +469,6 @@ pub fn build_exe(
|
|||
.{ .name = "Buffer", .module = Buffer_mod },
|
||||
.{ .name = "keybind", .module = keybind_mod },
|
||||
.{ .name = "shell", .module = shell_mod },
|
||||
.{ .name = "git", .module = git_mod },
|
||||
.{ .name = "ripgrep", .module = ripgrep_mod },
|
||||
.{ .name = "theme", .module = themes_dep.module("theme") },
|
||||
.{ .name = "themes", .module = themes_dep.module("themes") },
|
||||
|
@ -544,8 +511,6 @@ pub fn build_exe(
|
|||
exe.root_module.addImport("input", input_mod);
|
||||
exe.root_module.addImport("syntax", syntax_mod);
|
||||
exe.root_module.addImport("color", color_mod);
|
||||
exe.root_module.addImport("bin_path", bin_path_mod);
|
||||
exe.root_module.addImport("version", b.createModule(.{ .root_source_file = version_file }));
|
||||
exe.root_module.addImport("version_info", b.createModule(.{ .root_source_file = version_info_file }));
|
||||
|
||||
if (target.result.os.tag == .windows) {
|
||||
|
@ -588,8 +553,6 @@ pub fn build_exe(
|
|||
check_exe.root_module.addImport("input", input_mod);
|
||||
check_exe.root_module.addImport("syntax", syntax_mod);
|
||||
check_exe.root_module.addImport("color", color_mod);
|
||||
check_exe.root_module.addImport("bin_path", bin_path_mod);
|
||||
check_exe.root_module.addImport("version", b.createModule(.{ .root_source_file = version_file }));
|
||||
check_exe.root_module.addImport("version_info", b.createModule(.{ .root_source_file = version_info_file }));
|
||||
check_step.dependOn(&check_exe.step);
|
||||
|
||||
|
@ -620,7 +583,7 @@ pub fn build_exe(
|
|||
});
|
||||
|
||||
lint_step.dependOn(&lints.step);
|
||||
b.default_step.dependOn(lint_step);
|
||||
// b.default_step.dependOn(lint_step);
|
||||
}
|
||||
|
||||
fn gen_version_info(
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.14.0
|
||||
0.13.0
|
||||
|
|
|
@ -1,42 +1,41 @@
|
|||
.{
|
||||
.name = .flow,
|
||||
.name = "flow",
|
||||
.version = "0.2.0",
|
||||
.minimum_zig_version = "0.14.0",
|
||||
.fingerprint = 0x52c0d670590aa80f,
|
||||
.minimum_zig_version = "0.13.0",
|
||||
|
||||
.dependencies = .{
|
||||
.syntax = .{ .path = "src/syntax" },
|
||||
.flags = .{
|
||||
.url = "https://github.com/n0s4/flags/archive/372501d1576b5723829bcba98e41361132c7b618.tar.gz",
|
||||
.hash = "flags-0.8.0-AAAAAJV0AACuGBBnpUnHqZzAhoGTp4ibFROBQQQZGRqx",
|
||||
.url = "https://github.com/n0s4/flags/archive/b3905aa990719ff567f1c5a2f89e6dd3292d8533.tar.gz",
|
||||
.hash = "1220930a42f8da3fb7f723e3ad3f6dcc6db76327dd8d26274566423192d53e91b2bb",
|
||||
},
|
||||
.dizzy = .{
|
||||
.url = "https://github.com/neurocyte/dizzy/archive/455d18369cbb2a0458ba70be919cd378338d695e.tar.gz",
|
||||
.hash = "dizzy-1.0.0-AAAAAM1wAAAiDbx_6RwcVEOBk8p2XOu8t9WPNc3K7kBK",
|
||||
.hash = "1220220dbc7fe91c1c54438193ca765cebbcb7d58f35cdcaee404a9d2245a42a4362",
|
||||
},
|
||||
.thespian = .{
|
||||
.url = "https://github.com/neurocyte/thespian/archive/42a98a44e7590fd6e952b75523e5c0f4fa0e6c97.tar.gz",
|
||||
.hash = "thespian-0.0.1-owFOjnUTBgBUlBtQ-SbN_6S7bXE6e2mKmCgk4A-RGBMA",
|
||||
.url = "https://github.com/neurocyte/thespian/archive/9ca04ddfc715e0f7d29d3f6b39269ad9bf174230.tar.gz",
|
||||
.hash = "1220b05b5949454bf155a802d5034c060431b8bf59f9d4d2d5241397e9fd201d78d9",
|
||||
},
|
||||
.themes = .{
|
||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-ac2e3fe2df3419b71276f86fa9c45fd39d668f23/flow-themes.tar.gz",
|
||||
.hash = "N-V-__8AAEtaFwAjAHCmWHRCrBxL7uSG4hQiIsSgS32Y67K6",
|
||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-59bf204551bcb238faddd06779063570e7e6d431/flow-themes.tar.gz",
|
||||
.hash = "12209a213a392ea80ea5c7dde125e7161bb0278ac4b99db9df2b7af783710bcb09f7",
|
||||
},
|
||||
.fuzzig = .{
|
||||
.url = "https://github.com/fjebaker/fuzzig/archive/44c04733c7c0fee3db83672aaaaf4ed03e943156.tar.gz",
|
||||
.hash = "fuzzig-0.1.1-AAAAALNIAQBmbHr-MPalGuR393Vem2pTQXI7_LXeNJgX",
|
||||
.url = "https://github.com/fjebaker/fuzzig/archive/0fd156d5097365151e85a85eef9d8cf0eebe7b00.tar.gz",
|
||||
.hash = "122019f077d09686b1ec47928ca2b4bf264422f3a27afc5b49dafb0129a4ceca0d01",
|
||||
},
|
||||
.vaxis = .{
|
||||
.url = "https://github.com/neurocyte/libvaxis/archive/386e554f275c82ebfde7f15765687aaa6e89f6f6.tar.gz",
|
||||
.hash = "vaxis-0.1.0-BWNV_FneCADwINyXfMcWHjv_vpQR-VOzrGSmH6BEP40y",
|
||||
.url = "https://github.com/neurocyte/libvaxis/archive/e518e139417a9773f59624961b02e05b8fffff35.tar.gz",
|
||||
.hash = "122045fec2cedf3f68c20f961c42f3ca1e901238aec5a0c7b3b632cd21ce3b621f76",
|
||||
},
|
||||
.zeit = .{
|
||||
.url = "https://github.com/rockorager/zeit/archive/8fd203f85f597f16e0a525c1f1ca1e0bffded809.tar.gz",
|
||||
.hash = "zeit-0.0.0-AAAAACVbAgAiIzg1rccZU1qOfO_dKQKme7-37xmEQcqc",
|
||||
.hash = "122022233835adc719535a8e7cefdd2902a67bbfb7ef198441ca9ce89c0593f488c2",
|
||||
},
|
||||
.win32 = .{
|
||||
.url = "https://github.com/marlersoft/zigwin32/archive/e8739b32a33ce48a3286aba31918b26a9dfc6ef0.tar.gz",
|
||||
.hash = "zigwin32-25.0.28-preview-AAAAAEEl_AMhnKSs-lgEyjmUX5JVTpNQewd8A2Bbekwc",
|
||||
.url = "https://github.com/marlersoft/zigwin32/archive/259b6f353a48968d7e3171573db4fd898b046188.tar.gz",
|
||||
.hash = "1220925614447b54ccc9894bbba8b202c6a8b750267890edab7732064867e46f3217",
|
||||
.lazy = true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -16,7 +16,7 @@ pub const VTable = struct {
|
|||
|
||||
pub fn to_owned(pimpl: anytype) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.pointer.child;
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
|
@ -56,7 +56,7 @@ var none = {};
|
|||
|
||||
pub fn to_unowned(pimpl: anytype) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.pointer.child;
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
|
@ -79,7 +79,7 @@ pub fn to_unowned(pimpl: anytype) Self {
|
|||
|
||||
pub fn bind(pimpl: anytype, comptime f: *const fn (ctx: @TypeOf(pimpl), from: tp.pid_ref, m: tp.message) tp.result) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.pointer.child;
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
|
|
133
src/LSP.zig
133
src/LSP.zig
|
@ -15,7 +15,7 @@ const debug_lsp = true;
|
|||
|
||||
const OutOfMemoryError = error{OutOfMemory};
|
||||
const SendError = error{SendFailed};
|
||||
const SpawnError = error{ThespianSpawnFailed};
|
||||
const CallError = tp.CallError;
|
||||
|
||||
pub fn open(allocator: std.mem.Allocator, project: []const u8, cmd: tp.message) (error{ ThespianSpawnFailed, InvalidLspCommand } || cbor.Error)!Self {
|
||||
return .{ .allocator = allocator, .pid = try Process.create(allocator, project, cmd) };
|
||||
|
@ -31,17 +31,12 @@ pub fn term(self: Self) void {
|
|||
self.pid.deinit();
|
||||
}
|
||||
|
||||
pub fn send_request(
|
||||
self: Self,
|
||||
allocator: std.mem.Allocator,
|
||||
method: []const u8,
|
||||
m: anytype,
|
||||
ctx: anytype,
|
||||
) (OutOfMemoryError || SpawnError)!void {
|
||||
pub fn send_request(self: Self, allocator: std.mem.Allocator, method: []const u8, m: anytype) CallError!tp.message {
|
||||
var cb = std.ArrayList(u8).init(self.allocator);
|
||||
defer cb.deinit();
|
||||
try cbor.writeValue(cb.writer(), m);
|
||||
return RequestContext(@TypeOf(ctx)).send(allocator, self.pid.ref(), ctx, tp.message.fmt(.{ "REQ", method, cb.items }));
|
||||
const request_timeout: u64 = @intCast(std.time.ns_per_s * tp.env.get().num("lsp-request-timeout"));
|
||||
return self.pid.call(allocator, request_timeout, .{ "REQ", method, cb.items });
|
||||
}
|
||||
|
||||
pub fn send_notification(self: Self, method: []const u8, m: anytype) (OutOfMemoryError || SendError)!void {
|
||||
|
@ -59,57 +54,6 @@ pub fn close(self: *Self) void {
|
|||
self.deinit();
|
||||
}
|
||||
|
||||
fn RequestContext(T: type) type {
|
||||
return struct {
|
||||
receiver: ReceiverT,
|
||||
ctx: T,
|
||||
to: tp.pid,
|
||||
request: tp.message,
|
||||
response: ?tp.message,
|
||||
a: std.mem.Allocator,
|
||||
|
||||
const Self = @This();
|
||||
const ReceiverT = tp.Receiver(*@This());
|
||||
|
||||
fn send(a: std.mem.Allocator, to: tp.pid_ref, ctx: T, request: tp.message) (OutOfMemoryError || SpawnError)!void {
|
||||
const self = try a.create(@This());
|
||||
self.* = .{
|
||||
.receiver = undefined,
|
||||
.ctx = if (@hasDecl(T, "clone")) ctx.clone() else ctx,
|
||||
.to = to.clone(),
|
||||
.request = try request.clone(std.heap.c_allocator),
|
||||
.response = null,
|
||||
.a = a,
|
||||
};
|
||||
self.receiver = ReceiverT.init(receive_, self);
|
||||
const proc = try tp.spawn_link(a, self, start, @typeName(@This()));
|
||||
defer proc.deinit();
|
||||
}
|
||||
|
||||
fn deinit(self: *@This()) void {
|
||||
self.ctx.deinit();
|
||||
std.heap.c_allocator.free(self.request.buf);
|
||||
self.to.deinit();
|
||||
self.a.destroy(self);
|
||||
}
|
||||
|
||||
fn start(self: *@This()) tp.result {
|
||||
_ = tp.set_trap(true);
|
||||
if (@hasDecl(T, "link")) try self.ctx.link();
|
||||
errdefer self.deinit();
|
||||
try self.to.link();
|
||||
try self.to.send_raw(self.request);
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
||||
fn receive_(self: *@This(), _: tp.pid_ref, m: tp.message) tp.result {
|
||||
defer self.deinit();
|
||||
self.ctx.receive(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
return tp.exit_normal();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const Process = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
cmd: tp.message,
|
||||
|
@ -123,10 +67,6 @@ const Process = struct {
|
|||
log_file: ?std.fs.File = null,
|
||||
next_id: i32 = 0,
|
||||
requests: std.StringHashMap(tp.pid),
|
||||
state: enum { init, running } = .init,
|
||||
init_queue: ?std.ArrayListUnmanaged(struct { tp.pid, []const u8, []const u8, InitQueueType }) = null,
|
||||
|
||||
const InitQueueType = enum { request, notify };
|
||||
|
||||
const Receiver = tp.Receiver(*Process);
|
||||
|
||||
|
@ -163,7 +103,6 @@ const Process = struct {
|
|||
}
|
||||
|
||||
fn deinit(self: *Process) void {
|
||||
self.free_init_queue();
|
||||
var i = self.requests.iterator();
|
||||
while (i.next()) |req| {
|
||||
self.allocator.free(req.key_ptr.*);
|
||||
|
@ -227,37 +166,24 @@ const Process = struct {
|
|||
UnsupportedType,
|
||||
ExitNormal,
|
||||
ExitUnexpected,
|
||||
InvalidMapType,
|
||||
});
|
||||
|
||||
fn receive_safe(self: *Process, from: tp.pid_ref, m: tp.message) Error!void {
|
||||
const frame = tracy.initZone(@src(), .{ .name = module_name });
|
||||
defer frame.deinit();
|
||||
errdefer self.deinit();
|
||||
var method: []const u8 = "";
|
||||
var bytes: []const u8 = "";
|
||||
var err: []const u8 = "";
|
||||
var method: []u8 = "";
|
||||
var bytes: []u8 = "";
|
||||
var err: []u8 = "";
|
||||
var code: u32 = 0;
|
||||
var cbor_id: []const u8 = "";
|
||||
|
||||
if (try cbor.match(m.buf, .{ "REQ", "initialize", tp.extract(&bytes) })) {
|
||||
try self.send_request(from, "initialize", bytes);
|
||||
} else if (try cbor.match(m.buf, .{ "REQ", tp.extract(&method), tp.extract(&bytes) })) {
|
||||
switch (self.state) {
|
||||
.init => try self.append_init_queue(from, method, bytes, .request), //queue requests
|
||||
.running => try self.send_request(from, method, bytes),
|
||||
}
|
||||
if (try cbor.match(m.buf, .{ "REQ", tp.extract(&method), tp.extract(&bytes) })) {
|
||||
try self.send_request(from, method, bytes);
|
||||
} else if (try cbor.match(m.buf, .{ "RSP", tp.extract_cbor(&cbor_id), tp.extract_cbor(&bytes) })) {
|
||||
try self.send_response(cbor_id, bytes);
|
||||
} else if (try cbor.match(m.buf, .{ "NTFY", "initialized", tp.extract(&bytes) })) {
|
||||
self.state = .running;
|
||||
try self.send_notification("initialized", bytes);
|
||||
try self.replay_init_queue();
|
||||
} else if (try cbor.match(m.buf, .{ "NTFY", tp.extract(&method), tp.extract(&bytes) })) {
|
||||
switch (self.state) {
|
||||
.init => try self.append_init_queue(from, method, bytes, .notify), //queue requests
|
||||
.running => try self.send_notification(method, bytes),
|
||||
}
|
||||
try self.send_notification(method, bytes);
|
||||
} else if (try cbor.match(m.buf, .{"close"})) {
|
||||
self.write_log("### LSP close ###\n", .{});
|
||||
try self.close();
|
||||
|
@ -281,43 +207,6 @@ const Process = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn append_init_queue(self: *Process, from: tp.pid_ref, method: []const u8, bytes: []const u8, type_: InitQueueType) !void {
|
||||
const queue = if (self.init_queue) |*queue| queue else blk: {
|
||||
self.init_queue = .empty;
|
||||
break :blk &self.init_queue.?;
|
||||
};
|
||||
const p = try queue.addOne(self.allocator);
|
||||
p.* = .{
|
||||
from.clone(),
|
||||
try self.allocator.dupe(u8, method),
|
||||
try self.allocator.dupe(u8, bytes),
|
||||
type_,
|
||||
};
|
||||
}
|
||||
|
||||
fn replay_init_queue(self: *Process) !void {
|
||||
defer self.free_init_queue();
|
||||
if (self.init_queue) |*queue| {
|
||||
for (queue.items) |*p|
|
||||
switch (p[3]) {
|
||||
.request => try self.send_request(p[0].ref(), p[1], p[2]),
|
||||
.notify => try self.send_notification(p[1], p[2]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn free_init_queue(self: *Process) void {
|
||||
if (self.init_queue) |*queue| {
|
||||
for (queue.items) |*p| {
|
||||
p[0].deinit();
|
||||
self.allocator.free(p[1]);
|
||||
self.allocator.free(p[2]);
|
||||
}
|
||||
queue.deinit(self.allocator);
|
||||
}
|
||||
self.init_queue = null;
|
||||
}
|
||||
|
||||
fn receive_lsp_message(self: *Process, cb: []const u8) Error!void {
|
||||
var iter = cb;
|
||||
|
||||
|
@ -370,7 +259,7 @@ const Process = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_output(self: *Process, bytes: []const u8) Error!void {
|
||||
fn handle_output(self: *Process, bytes: []u8) Error!void {
|
||||
try self.recv_buf.appendSlice(bytes);
|
||||
self.write_log("### RECV:\n{s}\n###\n", .{bytes});
|
||||
self.frame_message_recv() catch |e| {
|
||||
|
|
431
src/Project.zig
431
src/Project.zig
|
@ -7,7 +7,6 @@ const dizzy = @import("dizzy");
|
|||
const Buffer = @import("Buffer");
|
||||
const fuzzig = @import("fuzzig");
|
||||
const tracy = @import("tracy");
|
||||
const git = @import("git");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const LSP = @import("LSP.zig");
|
||||
|
@ -22,17 +21,13 @@ language_servers: std.StringHashMap(LSP),
|
|||
file_language_server: std.StringHashMap(LSP),
|
||||
tasks: std.ArrayList(Task),
|
||||
persistent: bool = false,
|
||||
logger_lsp: log.Logger,
|
||||
logger_git: log.Logger,
|
||||
|
||||
workspace: ?[]const u8 = null,
|
||||
branch: ?[]const u8 = null,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
const OutOfMemoryError = error{OutOfMemory};
|
||||
const CallError = tp.CallError;
|
||||
const SpawnError = (OutOfMemoryError || error{ThespianSpawnFailed});
|
||||
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI, InvalidMapType };
|
||||
pub const InvalidMessageError = error{ InvalidMessage, InvalidMessageField, InvalidTargetURI };
|
||||
pub const StartLspError = (error{ ThespianSpawnFailed, Timeout, InvalidLspCommand } || LspError || OutOfMemoryError || cbor.Error);
|
||||
pub const LspError = (error{ NoLsp, LspFailed } || OutOfMemoryError);
|
||||
pub const ClientError = (error{ClientFailed} || OutOfMemoryError);
|
||||
|
@ -65,14 +60,10 @@ pub fn init(allocator: std.mem.Allocator, name: []const u8) OutOfMemoryError!Sel
|
|||
.language_servers = std.StringHashMap(LSP).init(allocator),
|
||||
.file_language_server = std.StringHashMap(LSP).init(allocator),
|
||||
.tasks = std.ArrayList(Task).init(allocator),
|
||||
.logger_lsp = log.logger("lsp"),
|
||||
.logger_git = log.logger("git"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
if (self.workspace) |p| self.allocator.free(p);
|
||||
if (self.branch) |p| self.allocator.free(p);
|
||||
var i_ = self.file_language_server.iterator();
|
||||
while (i_.next()) |p| {
|
||||
self.allocator.free(p.key_ptr.*);
|
||||
|
@ -86,8 +77,6 @@ pub fn deinit(self: *Self) void {
|
|||
self.files.deinit();
|
||||
for (self.tasks.items) |task| self.allocator.free(task.command);
|
||||
self.tasks.deinit();
|
||||
self.logger_lsp.deinit();
|
||||
self.logger_git.deinit();
|
||||
self.allocator.free(self.name);
|
||||
}
|
||||
|
||||
|
@ -143,7 +132,7 @@ pub fn restore_state(self: *Self, data: []const u8) !void {
|
|||
var iter: []const u8 = data;
|
||||
_ = cbor.matchValue(&iter, tp.string) catch {};
|
||||
_ = cbor.decodeArrayHeader(&iter) catch |e| switch (e) {
|
||||
error.InvalidArrayType => return self.restore_state_v0(data),
|
||||
error.InvalidType => return self.restore_state_v0(data),
|
||||
else => return tp.trace(tp.channel.debug, .{ "restore_state", "unknown format", data }),
|
||||
};
|
||||
self.persistent = true;
|
||||
|
@ -203,18 +192,7 @@ pub fn restore_state_v1(self: *Self, data: []const u8) !void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn restore_state_v0(self: *Self, data: []const u8) error{
|
||||
OutOfMemory,
|
||||
IntegerTooLarge,
|
||||
IntegerTooSmall,
|
||||
InvalidType,
|
||||
TooShort,
|
||||
InvalidFloatType,
|
||||
InvalidArrayType,
|
||||
InvalidPIntType,
|
||||
JsonIncompatibleType,
|
||||
NotAnObject,
|
||||
}!void {
|
||||
pub fn restore_state_v0(self: *Self, data: []const u8) error{ OutOfMemory, IntegerTooLarge, IntegerTooSmall, InvalidType, TooShort }!void {
|
||||
tp.trace(tp.channel.debug, .{"restore_state_v0"});
|
||||
defer self.sort_files_by_mtime();
|
||||
var name: []const u8 = undefined;
|
||||
|
@ -256,8 +234,11 @@ fn get_language_server_instance(self: *Self, language_server: []const u8) StartL
|
|||
defer self.allocator.free(uri);
|
||||
const basename_begin = std.mem.lastIndexOfScalar(u8, self.name, std.fs.path.sep);
|
||||
const basename = if (basename_begin) |begin| self.name[begin + 1 ..] else self.name;
|
||||
|
||||
try self.send_lsp_init_request(lsp, self.name, basename, uri, language_server);
|
||||
const response = try self.send_lsp_init_request(lsp, self.name, basename, uri);
|
||||
defer self.allocator.free(response.buf);
|
||||
lsp.send_notification("initialized", .{}) catch return error.LspFailed;
|
||||
if (lsp.pid.expired()) return error.LspFailed;
|
||||
log.logger("lsp").print("initialized LSP: {s}", .{fmt_lsp_name_func(language_server)});
|
||||
try self.language_servers.put(try self.allocator.dupe(u8, language_server), lsp);
|
||||
return lsp;
|
||||
}
|
||||
|
@ -639,45 +620,27 @@ fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
|||
const lsp = try self.get_language_server(file_path);
|
||||
const uri = try self.make_URI(file_path);
|
||||
defer self.allocator.free(uri);
|
||||
|
||||
const handler: struct {
|
||||
from: tp.pid,
|
||||
name: []const u8,
|
||||
project: *Self,
|
||||
|
||||
pub fn deinit(self_: *@This()) void {
|
||||
std.heap.c_allocator.free(self_.name);
|
||||
self_.from.deinit();
|
||||
}
|
||||
|
||||
pub fn receive(self_: @This(), response: tp.message) !void {
|
||||
var link: []const u8 = undefined;
|
||||
var locations: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.array })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, .{tp.extract_cbor(&link)} })) {
|
||||
try navigate_to_location_link(self_.from.ref(), link);
|
||||
} else if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&locations) })) {
|
||||
try self_.project.send_reference_list(self_.from.ref(), locations, self_.name);
|
||||
}
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
return;
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&link) })) {
|
||||
try navigate_to_location_link(self_.from.ref(), link);
|
||||
}
|
||||
}
|
||||
} = .{
|
||||
.from = from.clone(),
|
||||
.name = try std.heap.c_allocator.dupe(u8, self.name),
|
||||
.project = self,
|
||||
};
|
||||
|
||||
lsp.send_request(self.allocator, method, .{
|
||||
const response = lsp.send_request(self.allocator, method, .{
|
||||
.textDocument = .{ .uri = uri },
|
||||
.position = .{ .line = row, .character = col },
|
||||
}, handler) catch return error.LspFailed;
|
||||
}) catch return error.LspFailed;
|
||||
defer self.allocator.free(response.buf);
|
||||
var link: []const u8 = undefined;
|
||||
var locations: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.array })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, .{tp.extract_cbor(&link)} })) {
|
||||
try self.navigate_to_location_link(from, link);
|
||||
} else if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&locations) })) {
|
||||
try self.send_reference_list(from, locations);
|
||||
}
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
return;
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&link) })) {
|
||||
try self.navigate_to_location_link(from, link);
|
||||
}
|
||||
}
|
||||
|
||||
fn navigate_to_location_link(from: tp.pid_ref, location_link: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn navigate_to_location_link(_: *Self, from: tp.pid_ref, location_link: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = location_link;
|
||||
var targetUri: ?[]const u8 = null;
|
||||
var targetRange: ?Range = null;
|
||||
|
@ -739,40 +702,23 @@ pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi
|
|||
const lsp = try self.get_language_server(file_path);
|
||||
const uri = try self.make_URI(file_path);
|
||||
defer self.allocator.free(uri);
|
||||
self.logger_lsp.print("finding references...", .{});
|
||||
log.logger("lsp").print("finding references...", .{});
|
||||
|
||||
const handler: struct {
|
||||
from: tp.pid,
|
||||
name: []const u8,
|
||||
project: *Self,
|
||||
|
||||
pub fn deinit(self_: *@This()) void {
|
||||
std.heap.c_allocator.free(self_.name);
|
||||
self_.from.deinit();
|
||||
}
|
||||
|
||||
pub fn receive(self_: @This(), response: tp.message) !void {
|
||||
var locations: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
return;
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&locations) })) {
|
||||
try self_.project.send_reference_list(self_.from.ref(), locations, self_.name);
|
||||
}
|
||||
}
|
||||
} = .{
|
||||
.from = from.clone(),
|
||||
.name = try std.heap.c_allocator.dupe(u8, self.name),
|
||||
.project = self,
|
||||
};
|
||||
|
||||
lsp.send_request(self.allocator, "textDocument/references", .{
|
||||
const response = lsp.send_request(self.allocator, "textDocument/references", .{
|
||||
.textDocument = .{ .uri = uri },
|
||||
.position = .{ .line = row, .character = col },
|
||||
.context = .{ .includeDeclaration = true },
|
||||
}, handler) catch return error.LspFailed;
|
||||
}) catch return error.LspFailed;
|
||||
defer self.allocator.free(response.buf);
|
||||
var locations: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
return;
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&locations) })) {
|
||||
try self.send_reference_list(from, locations);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8, name: []const u8) (ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error)!void {
|
||||
fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8) (ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error)!void {
|
||||
defer to.send(.{ "REF", "done" }) catch {};
|
||||
var iter = locations;
|
||||
var len = try cbor.decodeArrayHeader(&iter);
|
||||
|
@ -780,14 +726,13 @@ fn send_reference_list(self: *Self, to: tp.pid_ref, locations: []const u8, name:
|
|||
while (len > 0) : (len -= 1) {
|
||||
var location: []const u8 = undefined;
|
||||
if (try cbor.matchValue(&iter, cbor.extract_cbor(&location))) {
|
||||
try send_reference(to, location, name);
|
||||
try self.send_reference(to, location);
|
||||
} else return error.InvalidMessageField;
|
||||
}
|
||||
self.logger_lsp.print("found {d} references", .{count});
|
||||
log.logger("lsp").print("found {d} references", .{count});
|
||||
}
|
||||
|
||||
fn send_reference(to: tp.pid_ref, location: []const u8, name: []const u8) (ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error)!void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
fn send_reference(self: *Self, to: tp.pid_ref, location: []const u8) (ClientError || InvalidMessageError || GetLineOfFileError || cbor.Error)!void {
|
||||
var iter = location;
|
||||
var targetUri: ?[]const u8 = null;
|
||||
var targetRange: ?Range = null;
|
||||
|
@ -822,10 +767,10 @@ fn send_reference(to: tp.pid_ref, location: []const u8, name: []const u8) (Clien
|
|||
file_path[i] = '\\';
|
||||
};
|
||||
}
|
||||
const line = try get_line_of_file(allocator, file_path, targetRange.?.start.line);
|
||||
defer allocator.free(line);
|
||||
const file_path_ = if (file_path.len > name.len and std.mem.eql(u8, name, file_path[0..name.len]))
|
||||
file_path[name.len + 1 ..]
|
||||
const line = try self.get_line_of_file(self.allocator, file_path, targetRange.?.start.line);
|
||||
defer self.allocator.free(line);
|
||||
const file_path_ = if (file_path.len > self.name.len and std.mem.eql(u8, self.name, file_path[0..self.name.len]))
|
||||
file_path[self.name.len + 1 ..]
|
||||
else
|
||||
file_path;
|
||||
to.send(.{
|
||||
|
@ -843,44 +788,24 @@ pub fn completion(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi
|
|||
const lsp = try self.get_language_server(file_path);
|
||||
const uri = try self.make_URI(file_path);
|
||||
defer self.allocator.free(uri);
|
||||
|
||||
const handler: struct {
|
||||
from: tp.pid,
|
||||
file_path: []const u8,
|
||||
row: usize,
|
||||
col: usize,
|
||||
|
||||
pub fn deinit(self_: *@This()) void {
|
||||
std.heap.c_allocator.free(self_.file_path);
|
||||
self_.from.deinit();
|
||||
}
|
||||
|
||||
pub fn receive(self_: @This(), response: tp.message) !void {
|
||||
var result: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
try send_content_msg_empty(self_.from.ref(), "hover", self_.file_path, self_.row, self_.col);
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.array })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) }))
|
||||
try send_completion_items(self_.from.ref(), self_.file_path, self_.row, self_.col, result, false);
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.map })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) }))
|
||||
try send_completion_list(self_.from.ref(), self_.file_path, self_.row, self_.col, result);
|
||||
}
|
||||
}
|
||||
} = .{
|
||||
.from = from.clone(),
|
||||
.file_path = try std.heap.c_allocator.dupe(u8, file_path),
|
||||
.row = row,
|
||||
.col = col,
|
||||
};
|
||||
|
||||
lsp.send_request(self.allocator, "textDocument/completion", .{
|
||||
const response = lsp.send_request(self.allocator, "textDocument/completion", .{
|
||||
.textDocument = .{ .uri = uri },
|
||||
.position = .{ .line = row, .character = col },
|
||||
}, handler) catch return error.LspFailed;
|
||||
}) catch return error.LspFailed;
|
||||
defer self.allocator.free(response.buf);
|
||||
var result: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
try send_content_msg_empty(from, "hover", file_path, row, col);
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.array })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) }))
|
||||
try self.send_completion_items(from, file_path, row, col, result, false);
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.map })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) }))
|
||||
try self.send_completion_list(from, file_path, row, col, result);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_completion_list(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn send_completion_list(self: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = result;
|
||||
var len = cbor.decodeMapHeader(&iter) catch return;
|
||||
var items: []const u8 = "";
|
||||
|
@ -896,20 +821,20 @@ fn send_completion_list(to: tp.pid_ref, file_path: []const u8, row: usize, col:
|
|||
try cbor.skipValue(&iter);
|
||||
}
|
||||
}
|
||||
return send_completion_items(to, file_path, row, col, items, is_incomplete) catch error.ClientFailed;
|
||||
return self.send_completion_items(to, file_path, row, col, items, is_incomplete) catch error.ClientFailed;
|
||||
}
|
||||
|
||||
fn send_completion_items(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, items: []const u8, is_incomplete: bool) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn send_completion_items(self: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, items: []const u8, is_incomplete: bool) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = items;
|
||||
var len = cbor.decodeArrayHeader(&iter) catch return;
|
||||
var item: []const u8 = "";
|
||||
while (len > 0) : (len -= 1) {
|
||||
if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&item)))) return error.InvalidMessageField;
|
||||
send_completion_item(to, file_path, row, col, item, if (len > 1) true else is_incomplete) catch return error.ClientFailed;
|
||||
self.send_completion_item(to, file_path, row, col, item, if (len > 1) true else is_incomplete) catch return error.ClientFailed;
|
||||
}
|
||||
}
|
||||
|
||||
fn send_completion_item(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, item: []const u8, is_incomplete: bool) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn send_completion_item(_: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, item: []const u8, is_incomplete: bool) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var label: []const u8 = "";
|
||||
var label_detail: []const u8 = "";
|
||||
var label_description: []const u8 = "";
|
||||
|
@ -1023,74 +948,57 @@ pub fn rename_symbol(self: *Self, from: tp.pid_ref, file_path: []const u8, row:
|
|||
const lsp = try self.get_language_server(file_path);
|
||||
const uri = try self.make_URI(file_path);
|
||||
defer self.allocator.free(uri);
|
||||
|
||||
const handler: struct {
|
||||
from: tp.pid,
|
||||
file_path: []const u8,
|
||||
|
||||
pub fn deinit(self_: *@This()) void {
|
||||
std.heap.c_allocator.free(self_.file_path);
|
||||
self_.from.deinit();
|
||||
}
|
||||
|
||||
pub fn receive(self_: @This(), response: tp.message) !void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
var result: []const u8 = undefined;
|
||||
// buffer the renames in order to send as a single, atomic message
|
||||
var renames = std.ArrayList(Rename).init(allocator);
|
||||
defer renames.deinit();
|
||||
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.map })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) })) {
|
||||
try decode_rename_symbol_map(result, &renames);
|
||||
// write the renames message manually since there doesn't appear to be an array helper
|
||||
var msg_buf = std.ArrayList(u8).init(allocator);
|
||||
defer msg_buf.deinit();
|
||||
const w = msg_buf.writer();
|
||||
try cbor.writeArrayHeader(w, 3);
|
||||
try cbor.writeValue(w, "cmd");
|
||||
try cbor.writeValue(w, "rename_symbol_item");
|
||||
try cbor.writeArrayHeader(w, renames.items.len);
|
||||
for (renames.items) |rename| {
|
||||
if (!std.mem.eql(u8, rename.uri[0..7], "file://")) return error.InvalidTargetURI;
|
||||
var file_path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
var file_path_ = std.Uri.percentDecodeBackwards(&file_path_buf, rename.uri[7..]);
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (file_path_[0] == '/') file_path_ = file_path_[1..];
|
||||
for (file_path_, 0..) |c, i| if (c == '/') {
|
||||
file_path_[i] = '\\';
|
||||
};
|
||||
}
|
||||
const line = try get_line_of_file(allocator, self_.file_path, rename.range.start.line);
|
||||
try cbor.writeValue(w, .{
|
||||
file_path_,
|
||||
rename.range.start.line,
|
||||
rename.range.start.character,
|
||||
rename.range.end.line,
|
||||
rename.range.end.character,
|
||||
rename.new_text,
|
||||
line,
|
||||
});
|
||||
}
|
||||
self_.from.send_raw(.{ .buf = msg_buf.items }) catch return error.ClientFailed;
|
||||
}
|
||||
}
|
||||
}
|
||||
} = .{
|
||||
.from = from.clone(),
|
||||
.file_path = try std.heap.c_allocator.dupe(u8, file_path),
|
||||
};
|
||||
|
||||
lsp.send_request(self.allocator, "textDocument/rename", .{
|
||||
const response = lsp.send_request(self.allocator, "textDocument/rename", .{
|
||||
.textDocument = .{ .uri = uri },
|
||||
.position = .{ .line = row, .character = col },
|
||||
.newName = "PLACEHOLDER",
|
||||
}, handler) catch return error.LspFailed;
|
||||
}) catch return error.LspFailed;
|
||||
defer self.allocator.free(response.buf);
|
||||
var result: []const u8 = undefined;
|
||||
// buffer the renames in order to send as a single, atomic message
|
||||
var renames = std.ArrayList(Rename).init(self.allocator);
|
||||
defer renames.deinit();
|
||||
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.map })) {
|
||||
if (try cbor.match(response.buf, .{ tp.any, tp.any, tp.any, tp.extract_cbor(&result) })) {
|
||||
try self.decode_rename_symbol_map(result, &renames);
|
||||
// write the renames message manually since there doesn't appear to be an array helper
|
||||
var msg_buf = std.ArrayList(u8).init(self.allocator);
|
||||
defer msg_buf.deinit();
|
||||
const w = msg_buf.writer();
|
||||
try cbor.writeArrayHeader(w, 3);
|
||||
try cbor.writeValue(w, "cmd");
|
||||
try cbor.writeValue(w, "rename_symbol_item");
|
||||
try cbor.writeArrayHeader(w, renames.items.len);
|
||||
for (renames.items) |rename| {
|
||||
if (!std.mem.eql(u8, rename.uri[0..7], "file://")) return error.InvalidTargetURI;
|
||||
var file_path_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
var file_path_ = std.Uri.percentDecodeBackwards(&file_path_buf, rename.uri[7..]);
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (file_path_[0] == '/') file_path_ = file_path_[1..];
|
||||
for (file_path_, 0..) |c, i| if (c == '/') {
|
||||
file_path_[i] = '\\';
|
||||
};
|
||||
}
|
||||
const line = try self.get_line_of_file(self.allocator, file_path, rename.range.start.line);
|
||||
try cbor.writeValue(w, .{
|
||||
file_path_,
|
||||
rename.range.start.line,
|
||||
rename.range.start.character,
|
||||
rename.range.end.line,
|
||||
rename.range.end.character,
|
||||
rename.new_text,
|
||||
line,
|
||||
});
|
||||
}
|
||||
from.send_raw(.{ .buf = msg_buf.items }) catch return error.ClientFailed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decode a WorkspaceEdit record which may have shape {"changes": {}} or {"documentChanges": []}
|
||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit
|
||||
fn decode_rename_symbol_map(result: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn decode_rename_symbol_map(self: *Self, result: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = result;
|
||||
var len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage;
|
||||
var changes: []const u8 = "";
|
||||
|
@ -1099,11 +1007,11 @@ fn decode_rename_symbol_map(result: []const u8, renames: *std.ArrayList(Rename))
|
|||
if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidMessage;
|
||||
if (std.mem.eql(u8, field_name, "changes")) {
|
||||
if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&changes)))) return error.InvalidMessageField;
|
||||
try decode_rename_symbol_changes(changes, renames);
|
||||
try self.decode_rename_symbol_changes(changes, renames);
|
||||
return;
|
||||
} else if (std.mem.eql(u8, field_name, "documentChanges")) {
|
||||
if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&changes)))) return error.InvalidMessageField;
|
||||
try decode_rename_symbol_doc_changes(changes, renames);
|
||||
try self.decode_rename_symbol_doc_changes(changes, renames);
|
||||
return;
|
||||
} else {
|
||||
try cbor.skipValue(&iter);
|
||||
|
@ -1112,17 +1020,17 @@ fn decode_rename_symbol_map(result: []const u8, renames: *std.ArrayList(Rename))
|
|||
return error.ClientFailed;
|
||||
}
|
||||
|
||||
fn decode_rename_symbol_changes(changes: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn decode_rename_symbol_changes(self: *Self, changes: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = changes;
|
||||
var files_len = cbor.decodeMapHeader(&iter) catch return error.InvalidMessage;
|
||||
while (files_len > 0) : (files_len -= 1) {
|
||||
var file_uri: []const u8 = undefined;
|
||||
if (!(try cbor.matchString(&iter, &file_uri))) return error.InvalidMessage;
|
||||
try decode_rename_symbol_item(file_uri, &iter, renames);
|
||||
try decode_rename_symbol_item(self, file_uri, &iter, renames);
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn decode_rename_symbol_doc_changes(self: *Self, changes: []const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = changes;
|
||||
var changes_len = cbor.decodeArrayHeader(&iter) catch return error.InvalidMessage;
|
||||
while (changes_len > 0) : (changes_len -= 1) {
|
||||
|
@ -1142,14 +1050,14 @@ fn decode_rename_symbol_doc_changes(changes: []const u8, renames: *std.ArrayList
|
|||
}
|
||||
} else if (std.mem.eql(u8, field_name, "edits")) {
|
||||
if (file_uri.len == 0) return error.InvalidMessage;
|
||||
try decode_rename_symbol_item(file_uri, &iter, renames);
|
||||
try decode_rename_symbol_item(self, file_uri, &iter, renames);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit
|
||||
fn decode_rename_symbol_item(file_uri: []const u8, iter: *[]const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn decode_rename_symbol_item(_: *Self, file_uri: []const u8, iter: *[]const u8, renames: *std.ArrayList(Rename)) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var text_edits_len = cbor.decodeArrayHeader(iter) catch return error.InvalidMessage;
|
||||
while (text_edits_len > 0) : (text_edits_len -= 1) {
|
||||
var m_range: ?Range = null;
|
||||
|
@ -1178,41 +1086,22 @@ pub fn hover(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, c
|
|||
const lsp = try self.get_language_server(file_path);
|
||||
const uri = try self.make_URI(file_path);
|
||||
defer self.allocator.free(uri);
|
||||
// self.logger_lsp.print("fetching hover information...", .{});
|
||||
// log.logger("lsp").print("fetching hover information...", .{});
|
||||
|
||||
const handler: struct {
|
||||
from: tp.pid,
|
||||
file_path: []const u8,
|
||||
row: usize,
|
||||
col: usize,
|
||||
|
||||
pub fn deinit(self_: *@This()) void {
|
||||
self_.from.deinit();
|
||||
std.heap.c_allocator.free(self_.file_path);
|
||||
}
|
||||
|
||||
pub fn receive(self_: @This(), response: tp.message) !void {
|
||||
var result: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
try send_content_msg_empty(self_.from.ref(), "hover", self_.file_path, self_.row, self_.col);
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&result) })) {
|
||||
try send_hover(self_.from.ref(), self_.file_path, self_.row, self_.col, result);
|
||||
}
|
||||
}
|
||||
} = .{
|
||||
.from = from.clone(),
|
||||
.file_path = try std.heap.c_allocator.dupe(u8, file_path),
|
||||
.row = row,
|
||||
.col = col,
|
||||
};
|
||||
|
||||
lsp.send_request(self.allocator, "textDocument/hover", .{
|
||||
const response = lsp.send_request(self.allocator, "textDocument/hover", .{
|
||||
.textDocument = .{ .uri = uri },
|
||||
.position = .{ .line = row, .character = col },
|
||||
}, handler) catch return error.LspFailed;
|
||||
}) catch return error.LspFailed;
|
||||
defer self.allocator.free(response.buf);
|
||||
var result: []const u8 = undefined;
|
||||
if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) {
|
||||
try send_content_msg_empty(from, "hover", file_path, row, col);
|
||||
} else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&result) })) {
|
||||
try self.send_hover(from, file_path, row, col, result);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_hover(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
fn send_hover(self: *Self, to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, result: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void {
|
||||
var iter = result;
|
||||
var len = cbor.decodeMapHeader(&iter) catch return;
|
||||
var contents: []const u8 = "";
|
||||
|
@ -1231,10 +1120,11 @@ fn send_hover(to: tp.pid_ref, file_path: []const u8, row: usize, col: usize, res
|
|||
}
|
||||
}
|
||||
if (contents.len > 0)
|
||||
return send_contents(to, "hover", file_path, row, col, contents, range);
|
||||
return self.send_contents(to, "hover", file_path, row, col, contents, range);
|
||||
}
|
||||
|
||||
fn send_contents(
|
||||
self: *Self,
|
||||
to: tp.pid_ref,
|
||||
tag: []const u8,
|
||||
file_path: []const u8,
|
||||
|
@ -1257,7 +1147,7 @@ fn send_contents(
|
|||
};
|
||||
|
||||
if (is_list) {
|
||||
var content = std.ArrayList(u8).init(std.heap.c_allocator);
|
||||
var content = std.ArrayList(u8).init(self.allocator);
|
||||
defer content.deinit();
|
||||
while (len > 0) : (len -= 1) {
|
||||
if (try cbor.matchValue(&iter, cbor.extract(&value))) {
|
||||
|
@ -1428,7 +1318,7 @@ fn read_position(position: []const u8) !Position {
|
|||
return .{ .line = line.?, .character = character.? };
|
||||
}
|
||||
|
||||
pub fn show_message(self: *Self, _: tp.pid_ref, params_cb: []const u8) !void {
|
||||
pub fn show_message(_: *Self, _: tp.pid_ref, params_cb: []const u8) !void {
|
||||
var type_: i32 = 0;
|
||||
var message: ?[]const u8 = null;
|
||||
var iter = params_cb;
|
||||
|
@ -1445,10 +1335,12 @@ pub fn show_message(self: *Self, _: tp.pid_ref, params_cb: []const u8) !void {
|
|||
}
|
||||
}
|
||||
const msg = message orelse return;
|
||||
const logger = log.logger("lsp");
|
||||
defer logger.deinit();
|
||||
if (type_ <= 2)
|
||||
self.logger_lsp.err_msg("lsp", msg)
|
||||
logger.err_msg("lsp", msg)
|
||||
else
|
||||
self.logger_lsp.print("{s}", .{msg});
|
||||
logger.print("{s}", .{msg});
|
||||
}
|
||||
|
||||
pub fn register_capability(self: *Self, from: tp.pid_ref, cbor_id: []const u8, params_cb: []const u8) ClientError!void {
|
||||
|
@ -1472,32 +1364,8 @@ pub fn send_lsp_response(self: *Self, from: tp.pid_ref, cbor_id: []const u8, res
|
|||
from.send_raw(.{ .buf = cb.items }) catch return error.ClientFailed;
|
||||
}
|
||||
|
||||
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8, language_server: []const u8) !void {
|
||||
const handler: struct {
|
||||
language_server: []const u8,
|
||||
lsp: LSP,
|
||||
project: *Self,
|
||||
|
||||
pub fn deinit(self_: *@This()) void {
|
||||
self_.lsp.pid.deinit();
|
||||
std.heap.c_allocator.free(self_.language_server);
|
||||
}
|
||||
|
||||
pub fn receive(self_: @This(), _: tp.message) !void {
|
||||
self_.lsp.send_notification("initialized", .{}) catch return error.LspFailed;
|
||||
if (self_.lsp.pid.expired()) return error.LspFailed;
|
||||
self_.project.logger_lsp.print("initialized LSP: {s}", .{fmt_lsp_name_func(self_.language_server)});
|
||||
}
|
||||
} = .{
|
||||
.language_server = try std.heap.c_allocator.dupe(u8, language_server),
|
||||
.lsp = .{
|
||||
.allocator = lsp.allocator,
|
||||
.pid = lsp.pid.clone(),
|
||||
},
|
||||
.project = self,
|
||||
};
|
||||
|
||||
try lsp.send_request(self.allocator, "initialize", .{
|
||||
fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, project_basename: []const u8, project_uri: []const u8) CallError!tp.message {
|
||||
return lsp.send_request(self.allocator, "initialize", .{
|
||||
.processId = if (builtin.os.tag == .linux) std.os.linux.getpid() else null,
|
||||
.rootPath = project_path,
|
||||
.rootUri = project_uri,
|
||||
|
@ -1799,7 +1667,7 @@ fn send_lsp_init_request(self: *Self, lsp: LSP, project_path: []const u8, projec
|
|||
},
|
||||
},
|
||||
},
|
||||
}, handler);
|
||||
});
|
||||
}
|
||||
|
||||
fn fmt_lsp_name_func(bytes: []const u8) std.fmt.Formatter(format_lsp_name_func) {
|
||||
|
@ -1830,7 +1698,7 @@ const eol = '\n';
|
|||
|
||||
pub const GetLineOfFileError = (OutOfMemoryError || std.fs.File.OpenError || std.fs.File.Reader.Error);
|
||||
|
||||
fn get_line_of_file(allocator: std.mem.Allocator, file_path: []const u8, line_: usize) GetLineOfFileError![]const u8 {
|
||||
fn get_line_of_file(self: *Self, allocator: std.mem.Allocator, file_path: []const u8, line_: usize) GetLineOfFileError![]const u8 {
|
||||
const line = line_ + 1;
|
||||
const file = try std.fs.cwd().openFile(file_path, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
|
@ -1844,38 +1712,15 @@ fn get_line_of_file(allocator: std.mem.Allocator, file_path: []const u8, line_:
|
|||
var line_count: usize = 1;
|
||||
for (0..buf.len) |i| {
|
||||
if (line_count == line)
|
||||
return get_line(allocator, buf[i..]);
|
||||
return self.get_line(allocator, buf[i..]);
|
||||
if (buf[i] == eol) line_count += 1;
|
||||
}
|
||||
return allocator.dupe(u8, "");
|
||||
}
|
||||
|
||||
pub fn get_line(allocator: std.mem.Allocator, buf: []const u8) ![]const u8 {
|
||||
pub fn get_line(_: *Self, allocator: std.mem.Allocator, buf: []const u8) ![]const u8 {
|
||||
for (0..buf.len) |i| {
|
||||
if (buf[i] == eol) return allocator.dupe(u8, buf[0..i]);
|
||||
}
|
||||
return allocator.dupe(u8, buf);
|
||||
}
|
||||
|
||||
pub fn query_git(self: *Self) void {
|
||||
git.workspace_path(@intFromPtr(self)) catch {};
|
||||
git.current_branch(@intFromPtr(self)) catch {};
|
||||
}
|
||||
|
||||
pub fn process_git(self: *Self, m: tp.message) !void {
|
||||
var value: []const u8 = undefined;
|
||||
if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) {
|
||||
// no git workspace
|
||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.extract(&value) })) {
|
||||
if (self.workspace) |p| self.allocator.free(p);
|
||||
self.workspace = try self.allocator.dupe(u8, value);
|
||||
git.workspace_files(@intFromPtr(self)) catch {};
|
||||
} else if (try m.match(.{ tp.any, tp.any, "current_branch", tp.extract(&value) })) {
|
||||
if (self.branch) |p| self.allocator.free(p);
|
||||
self.branch = try self.allocator.dupe(u8, value);
|
||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.extract(&value) })) {
|
||||
// TODO
|
||||
} else {
|
||||
self.logger_git.err("git", tp.unexpected(m));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ file_type_icon: ?[]const u8 = null,
|
|||
file_type_color: ?u24 = null,
|
||||
|
||||
pub const EolMode = enum { lf, crlf };
|
||||
pub const EolModeTag = @typeInfo(EolMode).@"enum".tag_type;
|
||||
pub const EolModeTag = @typeInfo(EolMode).Enum.tag_type;
|
||||
|
||||
const UndoNode = struct {
|
||||
root: Root,
|
||||
|
@ -71,26 +71,26 @@ const UndoBranch = struct {
|
|||
};
|
||||
|
||||
pub const WalkerMut = struct {
|
||||
keep_walking_: bool = false,
|
||||
found_: bool = false,
|
||||
keep_walking: bool = false,
|
||||
found: bool = false,
|
||||
replace: ?Root = null,
|
||||
err: ?anyerror = null,
|
||||
|
||||
pub const keep_walking = WalkerMut{ .keep_walking_ = true };
|
||||
pub const stop = WalkerMut{ .keep_walking_ = false };
|
||||
pub const found = WalkerMut{ .found_ = true };
|
||||
pub const keep_walking = WalkerMut{ .keep_walking = true };
|
||||
pub const stop = WalkerMut{ .keep_walking = false };
|
||||
pub const found = WalkerMut{ .found = true };
|
||||
|
||||
const F = *const fn (ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) WalkerMut;
|
||||
};
|
||||
|
||||
pub const Walker = struct {
|
||||
keep_walking_: bool = false,
|
||||
found_: bool = false,
|
||||
keep_walking: bool = false,
|
||||
found: bool = false,
|
||||
err: ?anyerror = null,
|
||||
|
||||
pub const keep_walking = Walker{ .keep_walking_ = true };
|
||||
pub const stop = Walker{ .keep_walking_ = false };
|
||||
pub const found = Walker{ .found_ = true };
|
||||
pub const keep_walking = Walker{ .keep_walking = true };
|
||||
pub const stop = Walker{ .keep_walking = false };
|
||||
pub const found = Walker{ .found = true };
|
||||
|
||||
const F = *const fn (ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker;
|
||||
};
|
||||
|
@ -126,8 +126,8 @@ pub const Branch = struct {
|
|||
fn merge_results_const(_: *const Branch, left: Walker, right: Walker) Walker {
|
||||
var result = Walker{};
|
||||
result.err = if (left.err) |_| left.err else right.err;
|
||||
result.keep_walking_ = left.keep_walking_ and right.keep_walking_;
|
||||
result.found_ = left.found_ or right.found_;
|
||||
result.keep_walking = left.keep_walking and right.keep_walking;
|
||||
result.found = left.found or right.found;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -144,8 +144,8 @@ pub const Branch = struct {
|
|||
else
|
||||
Node.new(allocator, new_left, new_right) catch |e| return .{ .err = e };
|
||||
}
|
||||
result.keep_walking_ = left.keep_walking_ and right.keep_walking_;
|
||||
result.found_ = left.found_ or right.found_;
|
||||
result.keep_walking = left.keep_walking and right.keep_walking;
|
||||
result.found = left.found or right.found;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
@ -350,10 +350,10 @@ const Node = union(enum) {
|
|||
switch (self.*) {
|
||||
.node => |*node| {
|
||||
const left = node.left.walk_const(f, ctx, metrics);
|
||||
if (!left.keep_walking_) {
|
||||
if (!left.keep_walking) {
|
||||
var result = Walker{};
|
||||
result.err = left.err;
|
||||
result.found_ = left.found_;
|
||||
result.found = left.found;
|
||||
return result;
|
||||
}
|
||||
const right = node.right.walk_const(f, ctx, metrics);
|
||||
|
@ -367,10 +367,10 @@ const Node = union(enum) {
|
|||
switch (self.*) {
|
||||
.node => |*node| {
|
||||
const left = node.left.walk(allocator, f, ctx, metrics);
|
||||
if (!left.keep_walking_) {
|
||||
if (!left.keep_walking) {
|
||||
var result = WalkerMut{};
|
||||
result.err = left.err;
|
||||
result.found_ = left.found_;
|
||||
result.found = left.found;
|
||||
if (left.replace) |p| {
|
||||
result.replace = Node.new(allocator, p, node.right) catch |e| return .{ .err = e };
|
||||
}
|
||||
|
@ -390,14 +390,14 @@ const Node = union(enum) {
|
|||
if (line >= left_bols)
|
||||
return node.right.walk_from_line_begin_const_internal(line - left_bols, f, ctx, metrics);
|
||||
const left_result = node.left.walk_from_line_begin_const_internal(line, f, ctx, metrics);
|
||||
const right_result = if (left_result.found_ and left_result.keep_walking_) node.right.walk_const(f, ctx, metrics) else Walker{};
|
||||
const right_result = if (left_result.found and left_result.keep_walking) node.right.walk_const(f, ctx, metrics) else Walker{};
|
||||
return node.merge_results_const(left_result, right_result);
|
||||
},
|
||||
.leaf => |*l| {
|
||||
if (line == 0) {
|
||||
var result = f(ctx, l, metrics);
|
||||
if (result.err) |_| return result;
|
||||
result.found_ = true;
|
||||
result.found = true;
|
||||
return result;
|
||||
}
|
||||
return Walker.keep_walking;
|
||||
|
@ -408,7 +408,7 @@ const Node = union(enum) {
|
|||
pub fn walk_from_line_begin_const(self: *const Node, line: usize, f: Walker.F, ctx: *anyopaque, metrics: Metrics) !bool {
|
||||
const result = self.walk_from_line_begin_const_internal(line, f, ctx, metrics);
|
||||
if (result.err) |e| return e;
|
||||
return result.found_;
|
||||
return result.found;
|
||||
}
|
||||
|
||||
fn walk_from_line_begin_internal(self: *const Node, allocator: Allocator, line: usize, f: WalkerMut.F, ctx: *anyopaque, metrics: Metrics) WalkerMut {
|
||||
|
@ -420,8 +420,8 @@ const Node = union(enum) {
|
|||
if (right_result.replace) |p| {
|
||||
var result = WalkerMut{};
|
||||
result.err = right_result.err;
|
||||
result.found_ = right_result.found_;
|
||||
result.keep_walking_ = right_result.keep_walking_;
|
||||
result.found = right_result.found;
|
||||
result.keep_walking = right_result.keep_walking;
|
||||
result.replace = if (p.is_empty())
|
||||
node.left
|
||||
else
|
||||
|
@ -432,7 +432,7 @@ const Node = union(enum) {
|
|||
}
|
||||
}
|
||||
const left_result = node.left.walk_from_line_begin_internal(allocator, line, f, ctx, metrics);
|
||||
const right_result = if (left_result.found_ and left_result.keep_walking_) node.right.walk(allocator, f, ctx, metrics) else WalkerMut{};
|
||||
const right_result = if (left_result.found and left_result.keep_walking) node.right.walk(allocator, f, ctx, metrics) else WalkerMut{};
|
||||
return node.merge_results(allocator, left_result, right_result);
|
||||
},
|
||||
.leaf => |*l| {
|
||||
|
@ -442,7 +442,7 @@ const Node = union(enum) {
|
|||
result.replace = null;
|
||||
return result;
|
||||
}
|
||||
result.found_ = true;
|
||||
result.found = true;
|
||||
return result;
|
||||
}
|
||||
return WalkerMut.keep_walking;
|
||||
|
@ -453,7 +453,7 @@ const Node = union(enum) {
|
|||
pub fn walk_from_line_begin(self: *const Node, allocator: Allocator, line: usize, f: WalkerMut.F, ctx: *anyopaque, metrics: Metrics) !struct { bool, ?Root } {
|
||||
const result = self.walk_from_line_begin_internal(allocator, line, f, ctx, metrics);
|
||||
if (result.err) |e| return e;
|
||||
return .{ result.found_, result.replace };
|
||||
return .{ result.found, result.replace };
|
||||
}
|
||||
|
||||
fn find_line_node(self: *const Node, line: usize) ?*const Node {
|
||||
|
@ -508,12 +508,12 @@ const Node = union(enum) {
|
|||
if (ret.err) |e| return .{ .err = e };
|
||||
buf = buf[bytes..];
|
||||
ctx.abs_col += @intCast(cols);
|
||||
if (!ret.keep_walking_) return Walker.stop;
|
||||
if (!ret.keep_walking) return Walker.stop;
|
||||
}
|
||||
if (leaf.eol) {
|
||||
const ret = ctx.walker_f(ctx.walker_ctx, "\n", 1, metrics);
|
||||
if (ret.err) |e| return .{ .err = e };
|
||||
if (!ret.keep_walking_) return Walker.stop;
|
||||
if (!ret.keep_walking) return Walker.stop;
|
||||
ctx.abs_col = 0;
|
||||
}
|
||||
return Walker.keep_walking;
|
||||
|
@ -670,7 +670,7 @@ const Node = union(enum) {
|
|||
var result = WalkerMut.keep_walking;
|
||||
if (ctx.delete_next_bol and ctx.bytes == 0) {
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf, false, leaf.eol) catch |e| return .{ .err = e };
|
||||
result.keep_walking_ = false;
|
||||
result.keep_walking = false;
|
||||
ctx.delete_next_bol = false;
|
||||
return result;
|
||||
}
|
||||
|
@ -724,7 +724,7 @@ const Node = union(enum) {
|
|||
}
|
||||
}
|
||||
if (ctx.bytes == 0 and !ctx.delete_next_bol)
|
||||
result.keep_walking_ = false;
|
||||
result.keep_walking = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1211,9 +1211,6 @@ pub const LoadFromFileError = error{
|
|||
DanglingSurrogateHalf,
|
||||
ExpectedSecondSurrogateHalf,
|
||||
UnexpectedSecondSurrogateHalf,
|
||||
LockViolation,
|
||||
ProcessNotFound,
|
||||
Canceled,
|
||||
};
|
||||
|
||||
pub fn load_from_file(
|
||||
|
@ -1257,11 +1254,6 @@ pub fn reset_to_last_saved(self: *Self) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn refresh_from_file(self: *Self) LoadFromFileError!void {
|
||||
try self.load_from_file_and_update(self.file_path);
|
||||
self.update_last_used_time();
|
||||
}
|
||||
|
||||
pub fn store_to_string(self: *const Self, allocator: Allocator, eol_mode: EolMode) ![]u8 {
|
||||
var s = try ArrayList(u8).initCapacity(allocator, self.root.weights_sum().len);
|
||||
try self.root.store(s.writer(), eol_mode);
|
||||
|
@ -1310,7 +1302,6 @@ pub const StoreToFileError = error{
|
|||
PathAlreadyExists,
|
||||
PipeBusy,
|
||||
ProcessFdQuotaExceeded,
|
||||
ProcessNotFound,
|
||||
ReadOnlyFileSystem,
|
||||
RenameAcrossMountPoints,
|
||||
SharingViolation,
|
||||
|
|
|
@ -13,14 +13,10 @@ pub const Context = struct {
|
|||
args: tp.message = .{},
|
||||
|
||||
pub fn fmt(value: anytype) Context {
|
||||
context_buffer.clearRetainingCapacity();
|
||||
cbor.writeValue(context_buffer.writer(), value) catch @panic("command.Context.fmt failed");
|
||||
return .{ .args = .{ .buf = context_buffer.items } };
|
||||
return .{ .args = tp.message.fmtbuf(&context_buffer, value) catch @panic("command.Context.fmt failed") };
|
||||
}
|
||||
};
|
||||
|
||||
const context_buffer_allocator = std.heap.c_allocator;
|
||||
threadlocal var context_buffer: std.ArrayList(u8) = std.ArrayList(u8).init(context_buffer_allocator);
|
||||
threadlocal var context_buffer: [tp.max_message_size]u8 = undefined;
|
||||
pub const fmt = Context.fmt;
|
||||
|
||||
const Vtable = struct {
|
||||
|
@ -150,8 +146,13 @@ pub fn execute(id: ID, ctx: Context) tp.result {
|
|||
}
|
||||
|
||||
pub fn get_id(name: []const u8) ?ID {
|
||||
var id: ?ID = null;
|
||||
return get_id_cache(name, &id);
|
||||
for (commands.items) |cmd| {
|
||||
if (cmd) |p|
|
||||
if (std.mem.eql(u8, p.name, name))
|
||||
return p.id;
|
||||
}
|
||||
tp.trace(tp.channel.debug, .{ "command", "get_id", "failed", name });
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn get_name(id: ID) ?[]const u8 {
|
||||
|
@ -173,7 +174,6 @@ pub fn get_id_cache(name: []const u8, id: *?ID) ?ID {
|
|||
return p.id;
|
||||
};
|
||||
}
|
||||
tp.trace(tp.channel.debug, .{ "command", "get_id_cache", "failed", name });
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ fn getTargetType(comptime Namespace: type) type {
|
|||
fn getCommands(comptime Namespace: type) []const CmdDef(*getTargetType(Namespace)) {
|
||||
@setEvalBranchQuota(10_000);
|
||||
comptime switch (@typeInfo(Namespace)) {
|
||||
.@"struct" => |info| {
|
||||
.Struct => |info| {
|
||||
var count = 0;
|
||||
const Target = getTargetType(Namespace);
|
||||
// @compileLog(Namespace, Target);
|
||||
|
@ -257,14 +257,14 @@ pub fn Collection(comptime Namespace: type) type {
|
|||
fields_var[i] = .{
|
||||
.name = cmd.name,
|
||||
.type = Clsr,
|
||||
.default_value_ptr = null,
|
||||
.default_value = null,
|
||||
.is_comptime = false,
|
||||
.alignment = if (@sizeOf(Clsr) > 0) @alignOf(Clsr) else 0,
|
||||
};
|
||||
}
|
||||
const fields: [cmds.len]std.builtin.Type.StructField = fields_var;
|
||||
const Fields = @Type(.{
|
||||
.@"struct" = .{
|
||||
.Struct = .{
|
||||
.is_tuple = false,
|
||||
.layout = .auto,
|
||||
.decls = &.{},
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
|
||||
const OutOfMemoryError = error{OutOfMemory};
|
||||
const SpawnError = error{ThespianSpawnFailed};
|
||||
|
||||
pub fn send(
|
||||
allocator: std.mem.Allocator,
|
||||
to: tp.pid_ref,
|
||||
m: anytype,
|
||||
ctx: anytype,
|
||||
) (OutOfMemoryError || SpawnError)!void {
|
||||
return RequestContext(@TypeOf(ctx)).send(allocator, to, ctx, tp.message.fmt(m));
|
||||
}
|
||||
|
||||
fn RequestContext(T: type) type {
|
||||
return struct {
|
||||
receiver: ReceiverT,
|
||||
ctx: T,
|
||||
to: tp.pid,
|
||||
request: tp.message,
|
||||
response: ?tp.message,
|
||||
a: std.mem.Allocator,
|
||||
|
||||
const Self = @This();
|
||||
const ReceiverT = tp.Receiver(*@This());
|
||||
|
||||
fn send(a: std.mem.Allocator, to: tp.pid_ref, ctx: T, request: tp.message) (OutOfMemoryError || SpawnError)!void {
|
||||
const self = try a.create(@This());
|
||||
self.* = .{
|
||||
.receiver = undefined,
|
||||
.ctx = if (@hasDecl(T, "clone")) ctx.clone() else ctx,
|
||||
.to = to.clone(),
|
||||
.request = try request.clone(std.heap.c_allocator),
|
||||
.response = null,
|
||||
.a = a,
|
||||
};
|
||||
self.receiver = ReceiverT.init(receive_, self);
|
||||
const proc = try tp.spawn_link(a, self, start, @typeName(@This()));
|
||||
defer proc.deinit();
|
||||
}
|
||||
|
||||
fn deinit(self: *@This()) void {
|
||||
if (@hasDecl(T, "deinit")) self.ctx.deinit();
|
||||
std.heap.c_allocator.free(self.request.buf);
|
||||
self.to.deinit();
|
||||
self.a.destroy(self);
|
||||
}
|
||||
|
||||
fn start(self: *@This()) tp.result {
|
||||
_ = tp.set_trap(true);
|
||||
if (@hasDecl(T, "link")) try self.ctx.link();
|
||||
errdefer self.deinit();
|
||||
try self.to.link();
|
||||
try self.to.send_raw(self.request);
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
||||
fn receive_(self: *@This(), _: tp.pid_ref, m: tp.message) tp.result {
|
||||
defer self.deinit();
|
||||
self.ctx.receive(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
return tp.exit_normal();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -10,8 +10,6 @@ enable_terminal_cursor: bool = true,
|
|||
enable_terminal_color_scheme: bool = builtin.os.tag != .windows,
|
||||
highlight_current_line: bool = true,
|
||||
highlight_current_line_gutter: bool = true,
|
||||
highlight_columns: []const u8 = "80 100 120",
|
||||
highlight_columns_alpha: u8 = 240,
|
||||
whitespace_mode: []const u8 = "none",
|
||||
inline_diagnostics: bool = true,
|
||||
animation_min_lag: usize = 0, //milliseconds
|
||||
|
@ -27,7 +25,7 @@ bottom_bar: []const u8 = "mode file log selection diagnostics keybind linenumber
|
|||
show_scrollbars: bool = true,
|
||||
show_fileicons: bool = true,
|
||||
|
||||
start_debugger_on_crash: bool = false,
|
||||
lsp_request_timeout: usize = 10,
|
||||
|
||||
include_files: []const u8 = "",
|
||||
|
||||
|
|
122
src/git.zig
122
src/git.zig
|
@ -1,122 +0,0 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
const shell = @import("shell");
|
||||
const bin_path = @import("bin_path");
|
||||
|
||||
pub const Error = error{ OutOfMemory, GitNotFound, GitCallFailed };
|
||||
|
||||
const log_execute = false;
|
||||
|
||||
pub fn workspace_path(context_: usize) Error!void {
|
||||
const fn_name = @src().fn_name;
|
||||
try git(context_, .{ "rev-parse", "--show-toplevel" }, struct {
|
||||
fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |value| if (value.len > 0)
|
||||
parent.send(.{ module_name, context, fn_name, value }) catch {};
|
||||
}
|
||||
}.result, exit_null_on_error(fn_name));
|
||||
}
|
||||
|
||||
pub fn current_branch(context_: usize) Error!void {
|
||||
const fn_name = @src().fn_name;
|
||||
try git(context_, .{ "rev-parse", "--abbrev-ref", "HEAD" }, struct {
|
||||
fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |value| if (value.len > 0)
|
||||
parent.send(.{ module_name, context, fn_name, value }) catch {};
|
||||
}
|
||||
}.result, exit_null_on_error(fn_name));
|
||||
}
|
||||
|
||||
pub fn workspace_files(context_: usize) Error!void {
|
||||
const fn_name = @src().fn_name;
|
||||
try git_err(context_, .{ "ls-files", "--cached", "--others", "--exclude-standard" }, struct {
|
||||
fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |value| if (value.len > 0)
|
||||
parent.send(.{ module_name, context, fn_name, value }) catch {};
|
||||
}
|
||||
}.result, struct {
|
||||
fn result(_: usize, _: tp.pid_ref, output: []const u8) void {
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |line| std.log.err("{s}: {s}", .{ module_name, line });
|
||||
}
|
||||
}.result, exit_null_on_error(fn_name));
|
||||
}
|
||||
|
||||
fn git(
|
||||
context: usize,
|
||||
cmd: anytype,
|
||||
out: OutputHandler,
|
||||
exit: ExitHandler,
|
||||
) Error!void {
|
||||
return git_err(context, cmd, out, noop, exit);
|
||||
}
|
||||
|
||||
fn git_err(
|
||||
context: usize,
|
||||
cmd: anytype,
|
||||
out: OutputHandler,
|
||||
err: OutputHandler,
|
||||
exit: ExitHandler,
|
||||
) Error!void {
|
||||
const cbor = @import("cbor");
|
||||
const git_binary = get_git() orelse return error.GitNotFound;
|
||||
var buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||
const writer = buf.writer(allocator);
|
||||
switch (@typeInfo(@TypeOf(cmd))) {
|
||||
.@"struct" => |info| if (info.is_tuple) {
|
||||
try cbor.writeArrayHeader(writer, info.fields.len + 1);
|
||||
try cbor.writeValue(writer, git_binary);
|
||||
inline for (info.fields) |f|
|
||||
try cbor.writeValue(writer, @field(cmd, f.name));
|
||||
return shell.execute(allocator, .{ .buf = buf.items }, .{
|
||||
.context = context,
|
||||
.out = to_shell_output_handler(out),
|
||||
.err = to_shell_output_handler(err),
|
||||
.exit = exit,
|
||||
.log_execute = log_execute,
|
||||
}) catch error.GitCallFailed;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@compileError("git command should be a tuple: " ++ @typeName(@TypeOf(cmd)));
|
||||
}
|
||||
|
||||
fn exit_null_on_error(comptime tag: []const u8) shell.ExitHandler {
|
||||
return struct {
|
||||
fn exit(_: usize, parent: tp.pid_ref, _: []const u8, _: []const u8, exit_code: i64) void {
|
||||
if (exit_code > 0)
|
||||
parent.send(.{ module_name, tag, null }) catch {};
|
||||
}
|
||||
}.exit;
|
||||
}
|
||||
|
||||
const OutputHandler = fn (context: usize, parent: tp.pid_ref, output: []const u8) void;
|
||||
const ExitHandler = shell.ExitHandler;
|
||||
|
||||
fn to_shell_output_handler(handler: anytype) shell.OutputHandler {
|
||||
return struct {
|
||||
fn out(context: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
|
||||
handler(context, parent, output);
|
||||
}
|
||||
}.out;
|
||||
}
|
||||
|
||||
fn noop(_: usize, _: tp.pid_ref, _: []const u8) void {}
|
||||
|
||||
var git_path: ?struct {
|
||||
path: ?[:0]const u8 = null,
|
||||
} = null;
|
||||
|
||||
const allocator = std.heap.c_allocator;
|
||||
|
||||
fn get_git() ?[]const u8 {
|
||||
if (git_path) |p| return p.path;
|
||||
const path = bin_path.find_binary_in_path(allocator, module_name) catch null;
|
||||
git_path = .{ .path = path };
|
||||
return path;
|
||||
}
|
||||
|
||||
const module_name = @typeName(@This());
|
|
@ -47,17 +47,6 @@
|
|||
["ctrl+x ctrl+r", "open_recent"],
|
||||
["ctrl+space", "enter_mode", "select"],
|
||||
|
||||
["alt+0", "add_integer_argument_digit", 0],
|
||||
["alt+1", "add_integer_argument_digit", 1],
|
||||
["alt+2", "add_integer_argument_digit", 2],
|
||||
["alt+3", "add_integer_argument_digit", 3],
|
||||
["alt+4", "add_integer_argument_digit", 4],
|
||||
["alt+5", "add_integer_argument_digit", 5],
|
||||
["alt+6", "add_integer_argument_digit", 6],
|
||||
["alt+7", "add_integer_argument_digit", 7],
|
||||
["alt+8", "add_integer_argument_digit", 8],
|
||||
["alt+9", "add_integer_argument_digit", 9],
|
||||
|
||||
["ctrl+c l = =", "format"],
|
||||
["ctrl+c l = r", "format"],
|
||||
["ctrl+c l g g", "goto_definition"],
|
||||
|
@ -66,7 +55,6 @@
|
|||
["ctrl+c l g r", "references"],
|
||||
["ctrl+c l h h", "hover"],
|
||||
["ctrl+c l r r", "rename_symbol"],
|
||||
["ctrl+c f", "copy_file_name"],
|
||||
|
||||
["super+l = =", "format"],
|
||||
["super+l = r", "format"],
|
||||
|
|
|
@ -50,12 +50,10 @@
|
|||
["ctrl+l", "scroll_view_center_cycle"],
|
||||
["ctrl+n", "goto_next_match"],
|
||||
["ctrl+p", "goto_prev_match"],
|
||||
["ctrl+b", "move_to_char", "move_or_select_to_char_left"],
|
||||
["ctrl+t", "move_to_char", "move_or_select_to_char_right"],
|
||||
["ctrl+b", "move_to_char", "left"],
|
||||
["ctrl+t", "move_to_char", "right"],
|
||||
["ctrl+x", "cut"],
|
||||
["ctrl+c", "copy"],
|
||||
["alt+C", "copy_file_name"],
|
||||
["ctrl+k alt+c", "copy_file_name", "file_name_only"],
|
||||
["ctrl+v", "system_paste"],
|
||||
["ctrl+u", "pop_cursor"],
|
||||
["ctrl+k m", "change_file_type"],
|
||||
|
@ -192,17 +190,6 @@
|
|||
["«", "smart_insert_pair", "«", "»"],
|
||||
["»", "smart_insert_pair_close", "«", "»"],
|
||||
|
||||
["alt+0", "add_integer_argument_digit", 0],
|
||||
["alt+1", "add_integer_argument_digit", 1],
|
||||
["alt+2", "add_integer_argument_digit", 2],
|
||||
["alt+3", "add_integer_argument_digit", 3],
|
||||
["alt+4", "add_integer_argument_digit", 4],
|
||||
["alt+5", "add_integer_argument_digit", 5],
|
||||
["alt+6", "add_integer_argument_digit", 6],
|
||||
["alt+7", "add_integer_argument_digit", 7],
|
||||
["alt+8", "add_integer_argument_digit", 8],
|
||||
["alt+9", "add_integer_argument_digit", 9],
|
||||
|
||||
["left_control", "enable_jump_mode"],
|
||||
["right_control", "enable_jump_mode"],
|
||||
["left_alt", "enable_fast_scroll"],
|
||||
|
@ -400,7 +387,7 @@
|
|||
["f15", "goto_prev_match"],
|
||||
["f9", "theme_prev"],
|
||||
["f10", "theme_next"],
|
||||
["escape", "mini_mode_cancel"],
|
||||
["escape", "exit_mini_mode"],
|
||||
["enter", "mini_mode_select"],
|
||||
["backspace", "mini_mode_delete_backwards"]
|
||||
]
|
||||
|
|
|
@ -62,14 +62,14 @@
|
|||
|
||||
["shift+`", "switch_case"],
|
||||
["shift+t", "till_prev_char"],
|
||||
["shift+f", "move_to_char", "move_to_char_left"],
|
||||
["shift+f", "move_to_char", false],
|
||||
["shift+w", "move_next_long_word_start"],
|
||||
["shift+b", "move_prev_long_word_start"],
|
||||
["shift+e", "move_next_long_word_end"],
|
||||
|
||||
["shift+i", ["enter_mode", "insert"], ["smart_move_begin"]],
|
||||
["shift+a", ["enter_mode", "insert"], ["move_end"]],
|
||||
["shift+o", ["enter_mode", "insert"], ["smart_insert_line_before"]],
|
||||
["shift+i", ["smart_move_begin"], ["enter_mode", "insert"]],
|
||||
["shift+a", ["move_end"], ["enter_mode", "insert"]],
|
||||
["shift+o", ["smart_insert_line_before"], ["enter_mode", "insert"]],
|
||||
|
||||
["shift+c", "copy_selection_on_next_line"],
|
||||
["shift+s", "split_selection"],
|
||||
|
@ -107,7 +107,7 @@
|
|||
["l", "move_right"],
|
||||
|
||||
["t", "find_till_char"],
|
||||
["f", "move_to_char", "move_to_char_right"],
|
||||
["f", "move_to_char", true],
|
||||
|
||||
["`", "to_lower"],
|
||||
|
||||
|
@ -120,7 +120,7 @@
|
|||
|
||||
["v", "enter_mode", "select"],
|
||||
|
||||
["g g", "goto_line_vim"],
|
||||
["g g", "move_buffer_begin"],
|
||||
["g e", "move_buffer_end"],
|
||||
["g f", "goto_file"],
|
||||
["g h", "move_begin"],
|
||||
|
@ -143,11 +143,11 @@
|
|||
["g shift+d", "goto_declaration"],
|
||||
|
||||
["i", "enter_mode", "insert"],
|
||||
["a", ["enter_mode", "insert"], ["move_right"]],
|
||||
["o", ["enter_mode", "insert"], ["smart_insert_line_after"]],
|
||||
["a", ["move_right"], ["enter_mode", "insert"]],
|
||||
["o", ["smart_insert_line_after"], ["enter_mode", "insert"]],
|
||||
|
||||
["d", "cut_forward_internal_inclusive"],
|
||||
["c", ["enable_selection"], ["enter_mode", "insert"], ["cut_forward_internal_inclusive"]],
|
||||
["d", "cut"],
|
||||
["c", ["cut"], ["enter_mode", "insert"]],
|
||||
|
||||
["s", "select_regex"],
|
||||
[";", "collapse_selections"],
|
||||
|
@ -190,7 +190,7 @@
|
|||
["n", "goto_next_match"],
|
||||
["u", "undo"],
|
||||
|
||||
["y", ["enable_selection"], ["copy_helix"], ["enter_mode", "normal"]],
|
||||
["y", "copy"],
|
||||
["p", "paste_after"],
|
||||
|
||||
["q", "record_macro"],
|
||||
|
@ -204,13 +204,13 @@
|
|||
["page_up", "move_scroll_page_up"],
|
||||
["page_down", "move_scroll_page_down"],
|
||||
|
||||
["space shift+f", "find_file"],
|
||||
["space shift+f", "file_picker_in_current_directory"],
|
||||
["space shift+s", "workspace_symbol_picker"],
|
||||
["space shift+d", "workspace_diagnostics_picker"],
|
||||
["space shift+p", "system_paste"],
|
||||
["space shift+r", "replace_selections_with_clipboard"],
|
||||
["space shift+/", "open_command_palette"],
|
||||
["space f", "find_file"],
|
||||
["space f", "file_picker"],
|
||||
["space b", "buffer_picker"],
|
||||
["space j", "jumplist_picker"],
|
||||
["space s", "symbol_picker"],
|
||||
|
@ -225,24 +225,21 @@
|
|||
["space h", "select_references_to_symbol_under_cursor"],
|
||||
["space c", "toggle_comment"],
|
||||
|
||||
["0", "add_integer_argument_digit", 0],
|
||||
["1", "add_integer_argument_digit", 1],
|
||||
["2", "add_integer_argument_digit", 2],
|
||||
["3", "add_integer_argument_digit", 3],
|
||||
["4", "add_integer_argument_digit", 4],
|
||||
["5", "add_integer_argument_digit", 5],
|
||||
["6", "add_integer_argument_digit", 6],
|
||||
["7", "add_integer_argument_digit", 7],
|
||||
["8", "add_integer_argument_digit", 8],
|
||||
["9", "add_integer_argument_digit", 9]
|
||||
["1", "add_count", 1],
|
||||
["2", "add_count", 2],
|
||||
["3", "add_count", 3],
|
||||
["4", "add_count", 4],
|
||||
["5", "add_count", 5],
|
||||
["6", "add_count", 6],
|
||||
["7", "add_count", 7],
|
||||
["8", "add_count", 8],
|
||||
["9", "add_count", 9]
|
||||
]
|
||||
},
|
||||
"insert": {
|
||||
"name": "INS",
|
||||
"line_numbers": "absolute",
|
||||
"cursor": "beam",
|
||||
"init_command": ["pause_undo_history"],
|
||||
"deinit_command": ["resume_undo_history"],
|
||||
"press": [
|
||||
["ctrl+u", "move_scroll_page_up"],
|
||||
["ctrl+d", "move_scroll_page_down"],
|
||||
|
@ -257,7 +254,6 @@
|
|||
"line_numbers": "relative",
|
||||
"cursor": "block",
|
||||
"selection": "inclusive",
|
||||
"init_command": ["enable_selection"],
|
||||
"press": [
|
||||
["ctrl+b", "select_page_up"],
|
||||
["ctrl+f", "select_page_down"],
|
||||
|
@ -280,7 +276,7 @@
|
|||
["alt+`", "switch_to_uppercase"],
|
||||
|
||||
["alt+d", "delete_backward"],
|
||||
["alt+c", ["enter_mode", "insert"], ["delete_backward"]],
|
||||
["alt+c", ["delete_backward"], ["enter_mode", "insert"]],
|
||||
|
||||
["alt+s", "split_selection_on_newline"],
|
||||
["alt+-", "merge_selections"],
|
||||
|
@ -324,7 +320,7 @@
|
|||
["shift+`", "switch_case"],
|
||||
|
||||
["shift+t", "extend_till_prev_char"],
|
||||
["shift+f", "move_to_char", "select_to_char_left_vim"],
|
||||
["shift+f", "extend_prev_char"],
|
||||
|
||||
["shift+w", "extend_next_long_word_start"],
|
||||
["shift+b", "extend_prev_long_word_start"],
|
||||
|
@ -332,10 +328,10 @@
|
|||
|
||||
["shift+g", "move_buffer_end_or_count_line"],
|
||||
|
||||
["shift+i", ["enter_mode", "insert"], ["smart_move_begin"]],
|
||||
["shift+a", ["enter_mode", "insert"], ["move_end"]],
|
||||
["shift+i", ["smart_move_begin"], ["enter_mode", "insert"]],
|
||||
["shift+a", ["move_end"], ["enter_mode", "insert"]],
|
||||
|
||||
["shift+o", ["enter_mode", "insert"], ["smart_insert_line_before"]],
|
||||
["shift+o", ["smart_insert_line_before"], ["enter_mode", "insert"]],
|
||||
|
||||
["shift+c", "copy_selection_on_next_line"],
|
||||
|
||||
|
@ -373,17 +369,17 @@
|
|||
["shift+1", "shell_insert_output"],
|
||||
["shift+4", "shell_keep_pipe"],
|
||||
|
||||
["h", "select_left_helix"],
|
||||
["h", "select_left"],
|
||||
["j", "select_down"],
|
||||
["k", "select_up"],
|
||||
["l", "select_right_helix"],
|
||||
["l", "select_right"],
|
||||
["left", "select_left"],
|
||||
["down", "select_down"],
|
||||
["up", "select_up"],
|
||||
["right", "select_right"],
|
||||
|
||||
["t", "extend_till_char"],
|
||||
["f", "move_to_char", "select_to_char_right_helix"],
|
||||
["f", "extend_next_char"],
|
||||
|
||||
["`", "switch_to_lowercase"],
|
||||
|
||||
|
@ -400,7 +396,7 @@
|
|||
["g e", "move_buffer_end"],
|
||||
["g f", "goto_file"],
|
||||
["g h", "move_begin"],
|
||||
["g l", "select_end"],
|
||||
["g l", "move_end"],
|
||||
["g s", "smart_move_begin"],
|
||||
["g d", "goto_definition"],
|
||||
["g y", "goto_type_definition"],
|
||||
|
@ -419,11 +415,11 @@
|
|||
["g shift+d", "goto_declaration"],
|
||||
|
||||
["i", "enter_mode", "insert"],
|
||||
["a", ["enter_mode", "insert"], ["move_right"]],
|
||||
["o", ["enter_mode", "insert"], ["smart_insert_line_after"]],
|
||||
["a", ["move_right"], ["enter_mode", "insert"]],
|
||||
["o", ["smart_insert_line_after"], ["enter_mode", "insert"]],
|
||||
|
||||
["d", ["cut"], ["enter_mode", "normal"]],
|
||||
["c", ["enter_mode", "insert"], ["cut"]],
|
||||
["d", "cut"],
|
||||
["c", ["cut"], ["enter_mode", "insert"]],
|
||||
|
||||
["s", "select_regex"],
|
||||
[";", "collapse_selections"],
|
||||
|
@ -468,7 +464,7 @@
|
|||
["n", "goto_next_match"],
|
||||
["u", "undo"],
|
||||
|
||||
["y", ["copy_helix"], ["enter_mode", "normal"]],
|
||||
["y", "copy"],
|
||||
["p", "paste_after"],
|
||||
|
||||
["q", "record_macro"],
|
||||
|
@ -501,16 +497,15 @@
|
|||
["space h", "select_references_to_symbol_under_cursor"],
|
||||
["space c", "toggle_comment"],
|
||||
|
||||
["0", "add_integer_argument_digit", 0],
|
||||
["1", "add_integer_argument_digit", 1],
|
||||
["2", "add_integer_argument_digit", 2],
|
||||
["3", "add_integer_argument_digit", 3],
|
||||
["4", "add_integer_argument_digit", 4],
|
||||
["5", "add_integer_argument_digit", 5],
|
||||
["6", "add_integer_argument_digit", 6],
|
||||
["7", "add_integer_argument_digit", 7],
|
||||
["8", "add_integer_argument_digit", 8],
|
||||
["9", "add_integer_argument_digit", 9]
|
||||
["1", "add_count", 1],
|
||||
["2", "add_count", 2],
|
||||
["3", "add_count", 3],
|
||||
["4", "add_count", 4],
|
||||
["5", "add_count", 5],
|
||||
["6", "add_count", 6],
|
||||
["7", "add_count", 7],
|
||||
["8", "add_count", 8],
|
||||
["9", "add_count", 9]
|
||||
]
|
||||
},
|
||||
"home": {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
["B", "move_word_left"],
|
||||
["e", "move_word_right_end_vim"],
|
||||
["x", "cut_forward_internal"],
|
||||
["s", ["enter_mode", "insert"], ["cut_forward_internal"]],
|
||||
["s", ["cut_forward_internal"], ["enter_mode", "insert"]],
|
||||
["u", "undo"],
|
||||
|
||||
["j", "move_down_vim"],
|
||||
|
@ -27,11 +27,11 @@
|
|||
["<Space>", "move_right_vim"],
|
||||
|
||||
["i", "enter_mode", "insert"],
|
||||
["a", ["enter_mode", "insert"], ["move_right"]],
|
||||
["I", ["enter_mode", "insert"], ["smart_move_begin"]],
|
||||
["A", ["enter_mode", "insert"], ["move_end"]],
|
||||
["o", ["enter_mode", "insert"], ["smart_insert_line_after"]],
|
||||
["O", ["enter_mode", "insert"], ["smart_insert_line_before"]],
|
||||
["a", ["move_right"], ["enter_mode", "insert"]],
|
||||
["I", ["smart_move_begin"], ["enter_mode", "insert"]],
|
||||
["A", ["move_end"], ["enter_mode", "insert"]],
|
||||
["o", ["smart_insert_line_after"], ["enter_mode", "insert"]],
|
||||
["O", ["smart_insert_line_before"], ["enter_mode", "insert"]],
|
||||
|
||||
["<S-.><S-.>", "indent"],
|
||||
["<S-,><S-,>", "unindent"],
|
||||
|
@ -41,6 +41,7 @@
|
|||
|
||||
["n", "goto_next_match"],
|
||||
["N", "goto_prev_match"],
|
||||
["0", "move_begin"],
|
||||
["^", "smart_move_begin"],
|
||||
["$", "move_end"],
|
||||
[":", "open_command_palette"],
|
||||
|
@ -51,7 +52,7 @@
|
|||
["gd", "goto_definition"],
|
||||
["gi", "goto_implementation"],
|
||||
["gy", "goto_type_definition"],
|
||||
["gg", "goto_line_vim"],
|
||||
["gg", "move_buffer_begin"],
|
||||
["grn", "rename_symbol"],
|
||||
["gD", "goto_declaration"],
|
||||
["G", "move_buffer_end"],
|
||||
|
@ -62,11 +63,11 @@
|
|||
["dd", "cut_internal_vim"],
|
||||
["\"_dd", "delete_line"],
|
||||
|
||||
["cc", ["enter_mode", "insert"], ["cut_internal_vim"]],
|
||||
["C", ["enter_mode", "insert"], ["cut_to_end_vim"]],
|
||||
["cc", ["cut_internal_vim"], ["enter_mode", "insert"]],
|
||||
["C", ["cut_to_end_vim"], ["enter_mode", "insert"]],
|
||||
["D", "cut_to_end_vim"],
|
||||
["cw", ["enter_mode", "insert"], ["cut_word_right_vim"]],
|
||||
["cb", ["enter_mode", "insert"], ["cut_word_left_vim"]],
|
||||
["cw", ["cut_word_right_vim"], ["enter_mode", "insert"]],
|
||||
["cb", ["cut_word_left_vim"], ["enter_mode", "insert"]],
|
||||
|
||||
["yy", ["copy_line_internal_vim"], ["cancel"]],
|
||||
|
||||
|
@ -85,24 +86,11 @@
|
|||
|
||||
["<C-k>", "TODO"],
|
||||
|
||||
["F", "move_to_char", "move_to_char_left"],
|
||||
["f", "move_to_char", "move_to_char_right"],
|
||||
["T", "move_to_char", "move_till_char_left"],
|
||||
["t", "move_to_char", "move_till_char_right"],
|
||||
["F", "move_to_char", "left"],
|
||||
["f", "move_to_char", "right"],
|
||||
|
||||
["<C-CR>", ["move_down"], ["move_begin"]],
|
||||
["<CR>", ["move_down"], ["move_begin"]],
|
||||
|
||||
["0", "move_begin_or_add_integer_argument_zero"],
|
||||
["1", "add_integer_argument_digit", 1],
|
||||
["2", "add_integer_argument_digit", 2],
|
||||
["3", "add_integer_argument_digit", 3],
|
||||
["4", "add_integer_argument_digit", 4],
|
||||
["5", "add_integer_argument_digit", 5],
|
||||
["6", "add_integer_argument_digit", 6],
|
||||
["7", "add_integer_argument_digit", 7],
|
||||
["8", "add_integer_argument_digit", 8],
|
||||
["9", "add_integer_argument_digit", 9]
|
||||
["<CR>", ["move_down"], ["move_begin"]]
|
||||
]
|
||||
},
|
||||
"visual": {
|
||||
|
@ -112,7 +100,6 @@
|
|||
"line_numbers": "relative",
|
||||
"cursor": "block",
|
||||
"selection": "normal",
|
||||
"init_command": ["enable_selection"],
|
||||
"press": [
|
||||
["<Esc>", ["cancel"], ["enter_mode", "normal"]],
|
||||
["k", "select_up"],
|
||||
|
@ -128,13 +115,7 @@
|
|||
|
||||
["0", "move_begin"],
|
||||
["^", "smart_move_begin"],
|
||||
["$", "select_end"],
|
||||
[":", "open_command_palette"],
|
||||
|
||||
["f", "move_to_char", "select_to_char_right"],
|
||||
["F", "move_to_char", "select_to_char_left_vim"],
|
||||
["t", "move_to_char", "select_till_char_right"],
|
||||
["T", "move_to_char", "select_till_char_left_vim"],
|
||||
["$", "move_end"],
|
||||
|
||||
["p", ["paste_internal_vim"], ["enter_mode", "normal"]],
|
||||
["P", ["paste_internal_vim"], ["enter_mode", "normal"]],
|
||||
|
@ -150,10 +131,10 @@
|
|||
|
||||
["x", ["cut_forward_internal"], ["enter_mode", "normal"]],
|
||||
["d", ["cut_forward_internal"], ["enter_mode", "normal"]],
|
||||
["s", ["enter_mode", "insert"], ["cut_forward_internal"]],
|
||||
["s", ["cut_forward_internal"], ["enter_mode", "insert"]],
|
||||
|
||||
["c", ["enter_mode", "insert"], ["cut_forward_internal"]],
|
||||
["C", ["enter_mode", "insert"], ["cut_to_end_vim"]],
|
||||
["c", ["cut_forward_internal"], ["enter_mode", "insert"]],
|
||||
["C", ["cut_to_end_vim"], ["enter_mode", "insert"]],
|
||||
["D", "cut_to_end_vim"]
|
||||
]
|
||||
},
|
||||
|
@ -172,7 +153,6 @@
|
|||
["0", "move_begin"],
|
||||
["^", "smart_move_begin"],
|
||||
["$", "move_end"],
|
||||
[":", "open_command_palette"],
|
||||
|
||||
["p", ["paste_internal_vim"], ["enter_mode", "normal"]],
|
||||
["P", ["paste_internal_vim"], ["enter_mode", "normal"]],
|
||||
|
@ -187,10 +167,10 @@
|
|||
|
||||
["x", ["cut_internal_vim"], ["enter_mode", "normal"]],
|
||||
["d", ["cut_internal_vim"], ["enter_mode", "normal"]],
|
||||
["s", ["enter_mode", "insert"], ["cut_internal_vim"]],
|
||||
["s", ["cut_internal_vim"], ["enter_mode", "insert"]],
|
||||
|
||||
["c", ["enter_mode", "insert"], ["cut_internal_vim"]],
|
||||
["C", ["enter_mode", "insert"], ["cut_to_end_vim"]],
|
||||
["c", ["cut_internal_vim"], ["enter_mode", "insert"]],
|
||||
["C", ["cut_to_end_vim"], ["enter_mode", "insert"]],
|
||||
["D", "cut_to_end_vim"]
|
||||
]
|
||||
},
|
||||
|
@ -199,8 +179,6 @@
|
|||
"name": "INSERT",
|
||||
"line_numbers": "absolute",
|
||||
"cursor": "beam",
|
||||
"init_command": ["pause_undo_history"],
|
||||
"deinit_command": ["resume_undo_history"],
|
||||
"press": [
|
||||
["<Esc>", ["move_left_vim"], ["enter_mode", "normal"]],
|
||||
["<Del>", "delete_forward"],
|
||||
|
|
|
@ -25,31 +25,6 @@ const builtin_keybinds = std.static_string_map.StaticStringMap([]const u8).initC
|
|||
.{ "emacs", @embedFile("builtin/emacs.json") },
|
||||
});
|
||||
|
||||
var integer_argument: ?usize = null;
|
||||
|
||||
var commands: Commands = undefined;
|
||||
const Commands = command.Collection(struct {
|
||||
pub const Target = void;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn add_integer_argument_digit(_: *void, ctx: Ctx) Result {
|
||||
var digit: usize = undefined;
|
||||
if (!try ctx.args.match(.{tp.extract(&digit)}))
|
||||
return error.InvalidIntegerParameterArgument;
|
||||
if (digit > 9)
|
||||
return error.InvalidIntegerParameterDigit;
|
||||
integer_argument = if (integer_argument) |x| x * 10 + digit else digit;
|
||||
}
|
||||
pub const add_integer_argument_digit_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
});
|
||||
|
||||
pub fn init() !void {
|
||||
var v: void = {};
|
||||
try commands.init(&v);
|
||||
}
|
||||
|
||||
pub fn mode(mode_name: []const u8, allocator: std.mem.Allocator, opts: anytype) !Mode {
|
||||
return Handler.create(mode_name, allocator, opts) catch |e| switch (e) {
|
||||
error.NotFound => return error.Stop,
|
||||
|
@ -86,8 +61,6 @@ const Handler = struct {
|
|||
.line_numbers = self.bindings.line_numbers,
|
||||
.cursor_shape = self.bindings.cursor_shape,
|
||||
.selection_style = self.bindings.selection_style,
|
||||
.init_command = self.bindings.init_command,
|
||||
.deinit_command = self.bindings.deinit_command,
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *@This()) void {
|
||||
|
@ -109,20 +82,8 @@ pub const Mode = struct {
|
|||
keybind_hints: *const KeybindHints,
|
||||
cursor_shape: ?CursorShape = null,
|
||||
selection_style: SelectionStyle,
|
||||
init_command: ?Command = null,
|
||||
deinit_command: ?Command = null,
|
||||
initialized: bool = false,
|
||||
|
||||
pub fn run_init(self: *Mode) void {
|
||||
if (self.initialized) return;
|
||||
self.initialized = true;
|
||||
clear_integer_argument();
|
||||
if (self.init_command) |init_command| init_command.execute_const();
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Mode) void {
|
||||
if (self.deinit_command) |deinit_command|
|
||||
deinit_command.execute_const();
|
||||
self.allocator.free(self.mode);
|
||||
self.input_handler.deinit();
|
||||
if (self.event_handler) |eh| eh.deinit();
|
||||
|
@ -177,11 +138,19 @@ fn get_or_load_namespace(namespace_name: []const u8) LoadError!*const Namespace
|
|||
pub fn set_namespace(namespace_name: []const u8) LoadError!void {
|
||||
const new_namespace = try get_or_load_namespace(namespace_name);
|
||||
if (globals.current_namespace) |old_namespace|
|
||||
if (old_namespace.deinit_command) |deinit_command|
|
||||
deinit_command.execute_const();
|
||||
if (old_namespace.deinit_command) |deinit|
|
||||
deinit.execute_const() catch |e| {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("deinit_command", "ERROR: {s} {s}", .{ deinit.command, @errorName(e) });
|
||||
logger.deinit();
|
||||
};
|
||||
globals.current_namespace = new_namespace;
|
||||
if (new_namespace.init_command) |init_command|
|
||||
init_command.execute_const();
|
||||
if (new_namespace.init_command) |init|
|
||||
init.execute_const() catch |e| {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("init_command", "ERROR: {s} {s}", .{ init.command, @errorName(e) });
|
||||
logger.deinit();
|
||||
};
|
||||
}
|
||||
|
||||
fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadError!*const BindingSet {
|
||||
|
@ -198,7 +167,7 @@ fn get_mode_binding_set(mode_name: []const u8, insert_command: []const u8) LoadE
|
|||
return binding_set;
|
||||
}
|
||||
|
||||
pub const LoadError = (error{ NotFound, NotAnObject } || std.json.ParseError(std.json.Scanner) || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError);
|
||||
const LoadError = (error{ NotFound, NotAnObject } || std.json.ParseError(std.json.Scanner) || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError);
|
||||
|
||||
///A collection of modes that represent a switchable editor emulation
|
||||
const Namespace = struct {
|
||||
|
@ -295,29 +264,13 @@ const Command = struct {
|
|||
};
|
||||
var buf: [2048]u8 = undefined;
|
||||
@memcpy(buf[0..self.args.len], self.args);
|
||||
if (integer_argument) |int_arg| {
|
||||
if (cbor.match(self.args, .{}) catch false and has_integer_argument(id)) {
|
||||
integer_argument = null;
|
||||
try command.execute(id, command.fmt(.{int_arg}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
try command.execute(id, .{ .args = .{ .buf = buf[0..self.args.len] } });
|
||||
}
|
||||
|
||||
fn execute_const(self: *const @This()) void {
|
||||
fn execute_const(self: *const @This()) !void {
|
||||
var buf: [2048]u8 = undefined;
|
||||
@memcpy(buf[0..self.args.len], self.args);
|
||||
command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } }) catch |e| {
|
||||
const logger = log.logger("keybind");
|
||||
logger.print_err("init/deinit_command", "ERROR: {s} {s}", .{ self.command, @errorName(e) });
|
||||
logger.deinit();
|
||||
};
|
||||
}
|
||||
|
||||
fn has_integer_argument(id: command.ID) bool {
|
||||
const args = command.get_arguments(id) orelse return false;
|
||||
return args.len == 1 and args[0] == .integer;
|
||||
try command.executeName(self.command, .{ .args = .{ .buf = buf[0..self.args.len] } });
|
||||
}
|
||||
|
||||
fn load(allocator: std.mem.Allocator, tokens: []const std.json.Value) (parse_flow.ParseError || parse_vim.ParseError)!Command {
|
||||
|
@ -420,8 +373,6 @@ const BindingSet = struct {
|
|||
selection_style: SelectionStyle,
|
||||
insert_command: []const u8 = "",
|
||||
hints_map: KeybindHints = .{},
|
||||
init_command: ?Command = null,
|
||||
deinit_command: ?Command = null,
|
||||
|
||||
const KeySyntax = enum { flow, vim };
|
||||
const OnMatchFailure = enum { insert, ignore };
|
||||
|
@ -440,8 +391,6 @@ const BindingSet = struct {
|
|||
inherit: ?[]const u8 = null,
|
||||
inherits: ?[][]const u8 = null,
|
||||
selection: ?SelectionStyle = null,
|
||||
init_command: ?[]const std.json.Value = null,
|
||||
deinit_command: ?[]const std.json.Value = null,
|
||||
};
|
||||
const parsed = try std.json.parseFromValue(JsonConfig, allocator, mode_bindings, .{
|
||||
.ignore_unknown_fields = true,
|
||||
|
@ -453,8 +402,6 @@ const BindingSet = struct {
|
|||
self.line_numbers = parsed.value.line_numbers;
|
||||
self.cursor_shape = parsed.value.cursor;
|
||||
self.selection_style = parsed.value.selection orelse .normal;
|
||||
if (parsed.value.init_command) |cmd| self.init_command = try Command.load(allocator, cmd);
|
||||
if (parsed.value.deinit_command) |cmd| self.deinit_command = try Command.load(allocator, cmd);
|
||||
try self.load_event(allocator, &self.press, input.event.press, parsed.value.press);
|
||||
try self.load_event(allocator, &self.release, input.event.release, parsed.value.release);
|
||||
if (parsed.value.inherits) |sibling_fallbacks| {
|
||||
|
@ -769,14 +716,6 @@ pub fn current_key_event_sequence_fmt() KeyEventSequenceFmt {
|
|||
return .{ .key_events = globals.current_sequence.items };
|
||||
}
|
||||
|
||||
pub fn current_integer_argument() ?usize {
|
||||
return integer_argument;
|
||||
}
|
||||
|
||||
pub fn clear_integer_argument() void {
|
||||
integer_argument = null;
|
||||
}
|
||||
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
const parse_test_cases = .{
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn parse_key_events(allocator: std.mem.Allocator, str: []const u8) ParseErro
|
|||
var iter = std.mem.tokenizeScalar(u8, item, '+');
|
||||
loop: while (iter.next()) |part| {
|
||||
if (part.len == 0) return parse_error("empty part in '{s}'", .{str});
|
||||
const modsInfo = @typeInfo(input.ModSet).@"struct";
|
||||
const modsInfo = @typeInfo(input.ModSet).Struct;
|
||||
inline for (modsInfo.fields) |field| {
|
||||
if (std.mem.eql(u8, part, field.name)) {
|
||||
if (@field(mods, field.name)) return parse_error("duplicate modifier '{s}' in '{s}'", .{ part, str });
|
||||
|
|
|
@ -3,7 +3,7 @@ const syntax = @import("syntax");
|
|||
const builtin = @import("builtin");
|
||||
const RGB = @import("color").RGB;
|
||||
|
||||
const bin_path = @import("bin_path");
|
||||
const bin_path = @import("bin_path.zig");
|
||||
|
||||
const checkmark_width = if (builtin.os.tag != .windows) 2 else 3;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ pub const Selection = struct {
|
|||
end: Cursor = Cursor{},
|
||||
};
|
||||
|
||||
pub fn create() error{ OutOfMemory, ThespianSpawnFailed }!Self {
|
||||
pub fn create() !Self {
|
||||
return .{ .pid = try Process.create() };
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ const Process = struct {
|
|||
selection: ?Selection = null,
|
||||
};
|
||||
|
||||
pub fn create() error{ OutOfMemory, ThespianSpawnFailed }!tp.pid {
|
||||
pub fn create() !tp.pid {
|
||||
const self = try outer_a.create(Process);
|
||||
self.* = .{
|
||||
.arena = std.heap.ArenaAllocator.init(outer_a),
|
||||
|
@ -123,13 +123,13 @@ const Process = struct {
|
|||
|
||||
if (isdupe(self.backwards.getLastOrNull(), entry)) {
|
||||
if (self.current) |current| self.forwards.append(current) catch {};
|
||||
if (self.backwards.pop()) |top|
|
||||
self.allocator.free(top.file_path);
|
||||
const top = self.backwards.pop();
|
||||
self.allocator.free(top.file_path);
|
||||
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "back", entry.file_path, entry.cursor.row, entry.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
||||
} else if (isdupe(self.forwards.getLastOrNull(), entry)) {
|
||||
if (self.current) |current| self.backwards.append(current) catch {};
|
||||
if (self.forwards.pop()) |top|
|
||||
self.allocator.free(top.file_path);
|
||||
const top = self.forwards.pop();
|
||||
self.allocator.free(top.file_path);
|
||||
tp.trace(tp.channel.all, tp.message.fmt(.{ "location", "forward", entry.file_path, entry.cursor.row, entry.cursor.col, self.backwards.items.len, self.forwards.items.len }));
|
||||
} else if (self.current) |current| {
|
||||
try self.backwards.append(current);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
|
||||
const fba = std.heap.FixedBufferAllocator;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const max_log_message = tp.max_message_size - 128;
|
||||
|
@ -9,7 +11,7 @@ allocator: std.mem.Allocator,
|
|||
receiver: Receiver,
|
||||
subscriber: ?tp.pid,
|
||||
heap: [32 + 1024]u8,
|
||||
fba: std.heap.FixedBufferAllocator,
|
||||
fba: fba,
|
||||
msg_store: MsgStoreT,
|
||||
|
||||
const MsgStoreT = std.DoublyLinkedList([]u8);
|
||||
|
@ -37,7 +39,7 @@ fn init(args: StartArgs) !*Self {
|
|||
.receiver = Receiver.init(Self.receive, p),
|
||||
.subscriber = null,
|
||||
.heap = undefined,
|
||||
.fba = std.heap.FixedBufferAllocator.init(&p.heap),
|
||||
.fba = fba.init(&p.heap),
|
||||
.msg_store = MsgStoreT{},
|
||||
};
|
||||
return p;
|
||||
|
|
140
src/main.zig
140
src/main.zig
|
@ -1,11 +1,10 @@
|
|||
const std = @import("std");
|
||||
const tui = @import("tui");
|
||||
const cbor = @import("cbor");
|
||||
const thespian = @import("thespian");
|
||||
const flags = @import("flags");
|
||||
const builtin = @import("builtin");
|
||||
const bin_path = @import("bin_path");
|
||||
|
||||
const bin_path = @import("bin_path.zig");
|
||||
const list_languages = @import("list_languages.zig");
|
||||
pub const file_link = @import("file_link.zig");
|
||||
|
||||
|
@ -16,7 +15,6 @@ const c = @cImport({
|
|||
const build_options = @import("build_options");
|
||||
const log = @import("log");
|
||||
|
||||
pub const version = @embedFile("version");
|
||||
pub const version_info = @embedFile("version_info");
|
||||
|
||||
pub var max_diff_lines: usize = 50000;
|
||||
|
@ -27,7 +25,7 @@ pub const application_title = "Flow Control";
|
|||
pub const application_subtext = "a programmer's text editor";
|
||||
pub const application_description = application_title ++ ": " ++ application_subtext;
|
||||
|
||||
pub const std_options: std.Options = .{
|
||||
pub const std_options = .{
|
||||
// .log_level = if (builtin.mode == .Debug) .debug else .warn,
|
||||
.log_level = if (builtin.mode == .Debug) .info else .warn,
|
||||
.logFn = log.std_log_function,
|
||||
|
@ -35,11 +33,7 @@ pub const std_options: std.Options = .{
|
|||
|
||||
const renderer = @import("renderer");
|
||||
|
||||
pub const panic = if (@hasDecl(renderer, "panic")) renderer.panic else default_panic;
|
||||
|
||||
fn default_panic(msg: []const u8, _: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
|
||||
return std.debug.defaultPanic(msg, ret_addr);
|
||||
}
|
||||
pub const panic = if (@hasDecl(renderer, "panic")) renderer.panic else std.builtin.default_panic;
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
if (builtin.os.tag == .linux) {
|
||||
|
@ -58,7 +52,7 @@ pub fn main() anyerror!void {
|
|||
\\
|
||||
\\Pass in file names to be opened with an optional :LINE or :LINE:COL appended to the
|
||||
\\file name to specify a specific location, or pass +<LINE> separately to set the line.
|
||||
;
|
||||
;
|
||||
|
||||
pub const descriptions = .{
|
||||
.project = "Set project directory (default: cwd)",
|
||||
|
@ -305,27 +299,7 @@ pub fn main() anyerror!void {
|
|||
|
||||
if (args.exec) |exec_str| {
|
||||
var cmds = std.mem.splitScalar(u8, exec_str, ';');
|
||||
while (cmds.next()) |cmd| {
|
||||
var count_args_ = std.mem.splitScalar(u8, cmd, ':');
|
||||
var count: usize = 0;
|
||||
while (count_args_.next()) |_| count += 1;
|
||||
if (count == 0) break;
|
||||
|
||||
var msg = std.ArrayList(u8).init(a);
|
||||
defer msg.deinit();
|
||||
const writer = msg.writer();
|
||||
|
||||
var cmd_args = std.mem.splitScalar(u8, cmd, ':');
|
||||
const cmd_ = cmd_args.next();
|
||||
try cbor.writeArrayHeader(writer, 3);
|
||||
try cbor.writeValue(writer, "cmd");
|
||||
try cbor.writeValue(writer, cmd_);
|
||||
try cbor.writeArrayHeader(writer, count - 1);
|
||||
|
||||
while (cmd_args.next()) |arg| try cbor.writeValue(writer, arg);
|
||||
|
||||
try tui_proc.send_raw(.{ .buf = msg.items });
|
||||
}
|
||||
while (cmds.next()) |cmd| try tui_proc.send(.{ "cmd", cmd, .{} });
|
||||
}
|
||||
|
||||
ctx.run();
|
||||
|
@ -369,6 +343,7 @@ fn trace_json(json: thespian.message.json_string_view) callconv(.C) void {
|
|||
extern fn ___tracy_emit_message(txt: [*]const u8, size: usize, callstack: c_int) void;
|
||||
|
||||
fn trace_to_file(m: thespian.message.c_buffer_type) callconv(.C) void {
|
||||
const cbor = @import("cbor");
|
||||
const State = struct {
|
||||
file: std.fs.File,
|
||||
last_time: i64,
|
||||
|
@ -466,6 +441,7 @@ fn read_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]
|
|||
}
|
||||
|
||||
fn read_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
|
||||
const cbor = @import("cbor");
|
||||
var file = try std.fs.openFileAbsolute(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
const text = try file.readToEndAlloc(allocator, 64 * 1024);
|
||||
|
@ -501,6 +477,7 @@ fn read_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_:
|
|||
}
|
||||
|
||||
fn read_json_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
|
||||
const cbor = @import("cbor");
|
||||
var file = try std.fs.openFileAbsolute(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
const json = try file.readToEndAlloc(allocator, 64 * 1024);
|
||||
|
@ -521,6 +498,7 @@ fn read_cbor_config(
|
|||
file_name: []const u8,
|
||||
cb: []const u8,
|
||||
) !void {
|
||||
const cbor = @import("cbor");
|
||||
var iter = cb;
|
||||
var field_name: []const u8 = undefined;
|
||||
while (cbor.matchString(&iter, &field_name) catch |e| switch (e) {
|
||||
|
@ -528,7 +506,7 @@ fn read_cbor_config(
|
|||
else => return e,
|
||||
}) {
|
||||
var known = false;
|
||||
inline for (@typeInfo(T).@"struct".fields) |field_info|
|
||||
inline for (@typeInfo(T).Struct.fields) |field_info|
|
||||
if (comptime std.mem.eql(u8, "include_files", field_info.name)) {
|
||||
if (std.mem.eql(u8, field_name, field_info.name)) {
|
||||
known = true;
|
||||
|
@ -569,9 +547,7 @@ fn read_nested_include_files(T: type, allocator: std.mem.Allocator, conf: *T, bu
|
|||
};
|
||||
}
|
||||
|
||||
pub const ConfigWriteError = error{ CreateConfigFileFailed, WriteConfigFileFailed };
|
||||
|
||||
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) (ConfigDirError || ConfigWriteError)!void {
|
||||
pub fn write_config(conf: anytype, allocator: std.mem.Allocator) !void {
|
||||
config_mutex.lock();
|
||||
defer config_mutex.unlock();
|
||||
_ = allocator;
|
||||
|
@ -580,22 +556,16 @@ pub fn write_config(conf: anytype, allocator: std.mem.Allocator) (ConfigDirError
|
|||
// return write_json_file(@TypeOf(conf), conf, allocator, try get_app_config_file_name(application_name, @typeName(@TypeOf(conf))));
|
||||
}
|
||||
|
||||
fn write_text_config_file(comptime T: type, data: T, file_name: []const u8) ConfigWriteError!void {
|
||||
var file = std.fs.createFileAbsolute(file_name, .{ .truncate = true }) catch |e| {
|
||||
std.log.err("createFileAbsolute failed with {any} for: {s}", .{ e, file_name });
|
||||
return error.CreateConfigFileFailed;
|
||||
};
|
||||
fn write_text_config_file(comptime T: type, data: T, file_name: []const u8) !void {
|
||||
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
|
||||
defer file.close();
|
||||
const writer = file.writer();
|
||||
write_config_to_writer(T, data, writer) catch |e| {
|
||||
std.log.err("write file failed with {any} for: {s}", .{ e, file_name });
|
||||
return error.WriteConfigFileFailed;
|
||||
};
|
||||
return write_config_to_writer(T, data, writer);
|
||||
}
|
||||
|
||||
pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) @TypeOf(writer).Error!void {
|
||||
pub fn write_config_to_writer(comptime T: type, data: T, writer: anytype) !void {
|
||||
const default: T = .{};
|
||||
inline for (@typeInfo(T).@"struct".fields) |field_info| {
|
||||
inline for (@typeInfo(T).Struct.fields) |field_info| {
|
||||
if (config_eql(
|
||||
field_info.type,
|
||||
@field(data, field_info.name),
|
||||
|
@ -617,8 +587,8 @@ fn config_eql(comptime T: type, a: T, b: T) bool {
|
|||
else => {},
|
||||
}
|
||||
switch (@typeInfo(T)) {
|
||||
.bool, .int, .float, .@"enum" => return a == b,
|
||||
.optional => |info| {
|
||||
.Bool, .Int, .Float, .Enum => return a == b,
|
||||
.Optional => |info| {
|
||||
if (a == null and b == null)
|
||||
return true;
|
||||
if (a == null or b == null)
|
||||
|
@ -631,6 +601,7 @@ fn config_eql(comptime T: type, a: T, b: T) bool {
|
|||
}
|
||||
|
||||
fn write_json_file(comptime T: type, data: T, allocator: std.mem.Allocator, file_name: []const u8) !void {
|
||||
const cbor = @import("cbor");
|
||||
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
|
||||
defer file.close();
|
||||
|
||||
|
@ -671,47 +642,11 @@ pub fn list_keybind_namespaces(allocator: std.mem.Allocator) ![]const []const u8
|
|||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn read_theme(allocator: std.mem.Allocator, theme_name: []const u8) ?[]const u8 {
|
||||
const file_name = get_theme_file_name(theme_name) catch return null;
|
||||
var file = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch return null;
|
||||
defer file.close();
|
||||
return file.readToEndAlloc(allocator, 64 * 1024) catch null;
|
||||
}
|
||||
|
||||
pub fn write_theme(theme_name: []const u8, content: []const u8) !void {
|
||||
const file_name = try get_theme_file_name(theme_name);
|
||||
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
|
||||
defer file.close();
|
||||
return file.writeAll(content);
|
||||
}
|
||||
|
||||
pub fn list_themes(allocator: std.mem.Allocator) ![]const []const u8 {
|
||||
var dir = try std.fs.openDirAbsolute(try get_theme_directory(), .{ .iterate = true });
|
||||
defer dir.close();
|
||||
var result = std.ArrayList([]const u8).init(allocator);
|
||||
var iter = dir.iterateAssumeFirstIteration();
|
||||
while (try iter.next()) |entry| {
|
||||
switch (entry.kind) {
|
||||
.file, .sym_link => try result.append(try allocator.dupe(u8, std.fs.path.stem(entry.name))),
|
||||
else => continue,
|
||||
}
|
||||
}
|
||||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn get_config_dir() ![]const u8 {
|
||||
return get_app_config_dir(application_name);
|
||||
}
|
||||
|
||||
pub const ConfigDirError = error{
|
||||
NoSpaceLeft,
|
||||
MakeConfigDirFailed,
|
||||
MakeHomeConfigDirFailed,
|
||||
MakeAppConfigDirFailed,
|
||||
AppConfigDirUnavailable,
|
||||
};
|
||||
|
||||
fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
||||
fn get_app_config_dir(appname: []const u8) ![]const u8 {
|
||||
const a = std.heap.c_allocator;
|
||||
const local = struct {
|
||||
var config_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
|
@ -727,7 +662,7 @@ fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
|||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config", .{home});
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeHomeConfigDirFailed,
|
||||
else => return e,
|
||||
};
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config/{s}", .{ home, appname });
|
||||
} else if (builtin.os.tag == .windows) ret: {
|
||||
|
@ -736,7 +671,7 @@ fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
|||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ appdata, appname });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeAppConfigDirFailed,
|
||||
else => return e,
|
||||
};
|
||||
break :ret dir;
|
||||
} else return error.AppConfigDirUnavailable;
|
||||
|
@ -745,15 +680,12 @@ fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
|||
local.config_dir = config_dir;
|
||||
std.fs.makeDirAbsolute(config_dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeConfigDirFailed,
|
||||
else => return e,
|
||||
};
|
||||
|
||||
var keybind_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
std.fs.makeDirAbsolute(try std.fmt.bufPrint(&keybind_dir_buffer, "{s}/{s}", .{ config_dir, keybind_dir })) catch {};
|
||||
|
||||
var theme_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
std.fs.makeDirAbsolute(try std.fmt.bufPrint(&theme_dir_buffer, "{s}/{s}", .{ config_dir, theme_dir })) catch {};
|
||||
|
||||
return config_dir;
|
||||
}
|
||||
|
||||
|
@ -848,11 +780,11 @@ fn get_app_state_dir(appname: []const u8) ![]const u8 {
|
|||
return state_dir;
|
||||
}
|
||||
|
||||
fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ConfigDirError![]const u8 {
|
||||
fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ![]const u8 {
|
||||
return get_app_config_dir_file_name(appname, base_name ++ ".json");
|
||||
}
|
||||
|
||||
fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ConfigDirError![]const u8 {
|
||||
fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ![]const u8 {
|
||||
const local = struct {
|
||||
var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
|
@ -899,28 +831,6 @@ pub fn get_keybind_namespace_file_name(namespace_name: []const u8) ![]const u8 {
|
|||
return try std.fmt.bufPrint(&local.file_buffer, "{s}/{s}.json", .{ dir, namespace_name });
|
||||
}
|
||||
|
||||
const theme_dir = "themes";
|
||||
|
||||
fn get_theme_directory() ![]const u8 {
|
||||
const local = struct {
|
||||
var dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
const a = std.heap.c_allocator;
|
||||
if (std.process.getEnvVarOwned(a, "FLOW_THEMES_DIR") catch null) |dir| {
|
||||
defer a.free(dir);
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}", .{dir});
|
||||
}
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}/{s}", .{ try get_app_config_dir(application_name), theme_dir });
|
||||
}
|
||||
|
||||
pub fn get_theme_file_name(theme_name: []const u8) ![]const u8 {
|
||||
const dir = try get_theme_directory();
|
||||
const local = struct {
|
||||
var file_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
return try std.fmt.bufPrint(&local.file_buffer, "{s}/{s}.json", .{ dir, theme_name });
|
||||
}
|
||||
|
||||
fn restart() noreturn {
|
||||
var executable: [:0]const u8 = std.mem.span(std.os.argv[0]);
|
||||
var is_basename = true;
|
||||
|
|
|
@ -232,13 +232,16 @@ pub fn update_mru(file_path: []const u8, row: usize, col: usize, ephemeral: bool
|
|||
return send(.{ "update_mru", project, file_path, row, col });
|
||||
}
|
||||
|
||||
pub fn get_mru_position(allocator: std.mem.Allocator, file_path: []const u8, ctx: anytype) (ProjectManagerError || ProjectError)!void {
|
||||
pub fn get_mru_position(allocator: std.mem.Allocator, file_path: []const u8) (ProjectManagerError || ProjectError || CallError || cbor.Error)!?Project.FilePos {
|
||||
const frame = tracy.initZone(@src(), .{ .name = "get_mru_position" });
|
||||
defer frame.deinit();
|
||||
const project = tp.env.get().str("project");
|
||||
if (project.len == 0)
|
||||
return error.NoProject;
|
||||
|
||||
const cp = @import("completion.zig");
|
||||
return cp.send(allocator, (try get()).pid, .{ "get_mru_position", project, file_path }, ctx);
|
||||
const rsp = try (try get()).pid.call(allocator, request_timeout, .{ "get_mru_position", project, file_path });
|
||||
defer allocator.free(rsp.buf);
|
||||
var pos: Project.FilePos = undefined;
|
||||
return if (try cbor.match(rsp.buf, .{ tp.extract(&pos.row), tp.extract(&pos.col) })) pos else null;
|
||||
}
|
||||
|
||||
const Process = struct {
|
||||
|
@ -325,7 +328,6 @@ const Process = struct {
|
|||
var text_len: usize = 0;
|
||||
var n: usize = 0;
|
||||
var task: []const u8 = undefined;
|
||||
var context: usize = undefined;
|
||||
|
||||
var root_dst: usize = 0;
|
||||
var root_src: usize = 0;
|
||||
|
@ -342,9 +344,6 @@ const Process = struct {
|
|||
if (self.walker) |pid| pid.deinit();
|
||||
self.walker = null;
|
||||
self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||
} else if (try cbor.match(m.buf, .{ "git", tp.extract(&context), tp.more })) {
|
||||
const project: *Project = @ptrFromInt(context);
|
||||
project.process_git(m) catch {};
|
||||
} else if (try cbor.match(m.buf, .{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||
} else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
|
||||
|
@ -427,7 +426,6 @@ const Process = struct {
|
|||
self.walker = try walk_tree_async(self.allocator, project_directory);
|
||||
self.restore_project(project) catch |e| self.logger.err("restore_project", e);
|
||||
project.sort_files_by_mtime();
|
||||
project.query_git();
|
||||
} else {
|
||||
self.logger.print("switched to: {s}", .{project_directory});
|
||||
}
|
||||
|
@ -926,11 +924,10 @@ const FilteredWalker = struct {
|
|||
var containing = top;
|
||||
var dirname_len = top.dirname_len;
|
||||
if (top.iter.next() catch {
|
||||
var item_ = self.stack.pop();
|
||||
if (item_) |*item|
|
||||
if (self.stack.items.len != 0) {
|
||||
item.iter.dir.close();
|
||||
};
|
||||
var item = self.stack.pop();
|
||||
if (self.stack.items.len != 0) {
|
||||
item.iter.dir.close();
|
||||
}
|
||||
continue;
|
||||
}) |base| {
|
||||
self.name_buffer.shrinkRetainingCapacity(dirname_len);
|
||||
|
@ -961,11 +958,10 @@ const FilteredWalker = struct {
|
|||
else => continue,
|
||||
}
|
||||
} else {
|
||||
var item_ = self.stack.pop();
|
||||
if (item_) |*item|
|
||||
if (self.stack.items.len != 0) {
|
||||
item.iter.dir.close();
|
||||
};
|
||||
var item = self.stack.pop();
|
||||
if (self.stack.items.len != 0) {
|
||||
item.iter.dir.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -76,16 +76,8 @@ pub fn columns(self: *const Cell) usize {
|
|||
}
|
||||
|
||||
pub fn dim(self: *Cell, alpha: u8) void {
|
||||
self.dim_fg(alpha);
|
||||
self.dim_bg(alpha);
|
||||
}
|
||||
|
||||
pub fn dim_bg(self: *Cell, alpha: u8) void {
|
||||
self.cell.style.bg = apply_alpha_value(self.cell.style.bg, alpha);
|
||||
}
|
||||
|
||||
pub fn dim_fg(self: *Cell, alpha: u8) void {
|
||||
self.cell.style.fg = apply_alpha_value(self.cell.style.fg, alpha);
|
||||
self.cell.style.bg = apply_alpha_value(self.cell.style.bg, alpha);
|
||||
}
|
||||
|
||||
fn apply_alpha_value(c: vaxis.Cell.Color, a: u8) vaxis.Cell.Color {
|
||||
|
|
|
@ -37,7 +37,7 @@ pub const option = enum {
|
|||
};
|
||||
|
||||
pub fn init(nopts: *const Options, parent_: Plane) !Plane {
|
||||
const opts: vaxis.Window.ChildOptions = .{
|
||||
const opts = .{
|
||||
.x_off = @as(i17, @intCast(nopts.x)),
|
||||
.y_off = @as(i17, @intCast(nopts.y)),
|
||||
.width = @as(u16, @intCast(nopts.cols)),
|
||||
|
|
|
@ -2,15 +2,13 @@ const vaxis = @import("vaxis");
|
|||
|
||||
const meta = @import("std").meta;
|
||||
const utf8Encode = @import("std").unicode.utf8Encode;
|
||||
const utf8Decode = @import("std").unicode.utf8Decode;
|
||||
const utf8ValidateSlice = @import("std").unicode.utf8ValidateSlice;
|
||||
const FormatOptions = @import("std").fmt.FormatOptions;
|
||||
|
||||
pub const key = vaxis.Key;
|
||||
pub const Key = u21;
|
||||
|
||||
pub const Mouse = vaxis.Mouse.Button;
|
||||
pub const MouseType = @typeInfo(Mouse).@"enum".tag_type;
|
||||
pub const MouseType = @typeInfo(Mouse).Enum.tag_type;
|
||||
|
||||
pub const mouse = struct {
|
||||
pub const MOTION: Mouse = vaxis.Mouse.Button.none;
|
||||
|
@ -76,7 +74,6 @@ pub const KeyEvent = struct {
|
|||
}
|
||||
|
||||
pub fn eql_unshifted(self: @This(), other: @This()) bool {
|
||||
if (self.text.len > 0 or other.text.len > 0) return false;
|
||||
const self_mods = self.mods_no_caps();
|
||||
const other_mods = other.mods_no_caps();
|
||||
return self.key_unshifted == other.key_unshifted and self_mods == other_mods;
|
||||
|
@ -120,7 +117,7 @@ pub const KeyEvent = struct {
|
|||
pub fn from_message(
|
||||
event_: Event,
|
||||
keypress_: Key,
|
||||
keypress_shifted_: Key,
|
||||
keypress_shifted: Key,
|
||||
text: []const u8,
|
||||
modifiers: Mods,
|
||||
) @This() {
|
||||
|
@ -131,11 +128,6 @@ pub const KeyEvent = struct {
|
|||
key.left_alt, key.right_alt => modifiers & ~mod.alt,
|
||||
else => modifiers,
|
||||
};
|
||||
|
||||
var keypress_shifted: Key = keypress_shifted_;
|
||||
if (text.len > 0 and text.len < 5 and utf8ValidateSlice(text)) blk: {
|
||||
keypress_shifted = utf8Decode(text) catch break :blk;
|
||||
}
|
||||
const keypress, const mods = if (keypress_shifted == keypress_)
|
||||
map_key_to_unshifed_legacy(keypress_shifted, mods_)
|
||||
else
|
||||
|
|
|
@ -12,7 +12,6 @@ pub const Cell = @import("Cell.zig");
|
|||
pub const CursorShape = vaxis.Cell.CursorShape;
|
||||
|
||||
pub const style = @import("style.zig").StyleBits;
|
||||
pub const styles = @import("style.zig");
|
||||
|
||||
const Self = @This();
|
||||
pub const log_name = "vaxis";
|
||||
|
@ -26,7 +25,6 @@ no_alternate: bool,
|
|||
event_buffer: std.ArrayList(u8),
|
||||
input_buffer: std.ArrayList(u8),
|
||||
mods: vaxis.Key.Modifiers = .{},
|
||||
queries_done: bool,
|
||||
|
||||
bracketed_paste: bool = false,
|
||||
bracketed_paste_buffer: std.ArrayList(u8),
|
||||
|
@ -41,25 +39,7 @@ logger: log.Logger,
|
|||
|
||||
loop: Loop,
|
||||
|
||||
pub const Error = error{
|
||||
UnexpectedRendererEvent,
|
||||
OutOfMemory,
|
||||
IntegerTooLarge,
|
||||
IntegerTooSmall,
|
||||
InvalidType,
|
||||
TooShort,
|
||||
Utf8CannotEncodeSurrogateHalf,
|
||||
CodepointTooLarge,
|
||||
TtyInitError,
|
||||
TtyWriteError,
|
||||
InvalidFloatType,
|
||||
InvalidArrayType,
|
||||
InvalidPIntType,
|
||||
JsonIncompatibleType,
|
||||
NotAnObject,
|
||||
} || std.Thread.SpawnError;
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) Error!Self {
|
||||
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) !Self {
|
||||
const opts: vaxis.Vaxis.Options = .{
|
||||
.kitty_keyboard_flags = .{
|
||||
.disambiguate = true,
|
||||
|
@ -72,7 +52,7 @@ pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate:
|
|||
};
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.tty = vaxis.Tty.init() catch return error.TtyInitError,
|
||||
.tty = try vaxis.Tty.init(),
|
||||
.vx = try vaxis.init(allocator, opts),
|
||||
.no_alternate = no_alternate,
|
||||
.event_buffer = std.ArrayList(u8).init(allocator),
|
||||
|
@ -81,7 +61,6 @@ pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate:
|
|||
.handler_ctx = handler_ctx,
|
||||
.logger = log.logger(log_name),
|
||||
.loop = undefined,
|
||||
.queries_done = false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -101,29 +80,28 @@ var panic_cleanup: ?struct {
|
|||
vx: *vaxis.Vaxis,
|
||||
} = null;
|
||||
pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
|
||||
_ = error_return_trace; // TODO: what to do with this in zig-0.14?
|
||||
const cleanup = panic_cleanup;
|
||||
panic_cleanup = null;
|
||||
if (cleanup) |self| {
|
||||
self.vx.deinit(self.allocator, self.tty.anyWriter());
|
||||
self.tty.deinit();
|
||||
}
|
||||
return std.debug.defaultPanic(msg, ret_addr orelse @returnAddress());
|
||||
return std.builtin.default_panic(msg, error_return_trace, ret_addr orelse @returnAddress());
|
||||
}
|
||||
|
||||
pub fn run(self: *Self) Error!void {
|
||||
pub fn run(self: *Self) !void {
|
||||
self.vx.sgr = .legacy;
|
||||
self.vx.conpty_hacks = true;
|
||||
|
||||
panic_cleanup = .{ .allocator = self.allocator, .tty = &self.tty, .vx = &self.vx };
|
||||
if (!self.no_alternate) self.vx.enterAltScreen(self.tty.anyWriter()) catch return error.TtyWriteError;
|
||||
if (!self.no_alternate) try self.vx.enterAltScreen(self.tty.anyWriter());
|
||||
if (builtin.os.tag == .windows) {
|
||||
try self.resize(.{ .rows = 25, .cols = 80, .x_pixel = 0, .y_pixel = 0 }); // dummy resize to fully init vaxis
|
||||
} else {
|
||||
self.sigwinch() catch return error.TtyWriteError;
|
||||
try self.sigwinch();
|
||||
}
|
||||
self.vx.setBracketedPaste(self.tty.anyWriter(), true) catch return error.TtyWriteError;
|
||||
self.vx.queryTerminalSend(self.tty.anyWriter()) catch return error.TtyWriteError;
|
||||
try self.vx.setBracketedPaste(self.tty.anyWriter(), true);
|
||||
try self.vx.queryTerminalSend(self.tty.anyWriter());
|
||||
|
||||
self.loop = Loop.init(&self.tty, &self.vx);
|
||||
try self.loop.start();
|
||||
|
@ -140,8 +118,8 @@ pub fn sigwinch(self: *Self) !void {
|
|||
try self.resize(try vaxis.Tty.getWinsize(self.input_fd_blocking()));
|
||||
}
|
||||
|
||||
fn resize(self: *Self, ws: vaxis.Winsize) error{ TtyWriteError, OutOfMemory }!void {
|
||||
self.vx.resize(self.allocator, self.tty.anyWriter(), ws) catch return error.TtyWriteError;
|
||||
fn resize(self: *Self, ws: vaxis.Winsize) !void {
|
||||
try self.vx.resize(self.allocator, self.tty.anyWriter(), ws);
|
||||
self.vx.queueRefresh();
|
||||
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"resize"}));
|
||||
}
|
||||
|
@ -165,7 +143,7 @@ pub fn input_fd_blocking(self: Self) i32 {
|
|||
return self.tty.fd;
|
||||
}
|
||||
|
||||
pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
||||
pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
|
||||
var input_: []const u8 = undefined;
|
||||
var text_: []const u8 = undefined;
|
||||
if (!try cbor.match(msg, .{ "RDR", cbor.extract(&input_), cbor.extract(&text_) }))
|
||||
|
@ -174,15 +152,6 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
|||
const event = std.mem.bytesAsValue(vaxis.Event, input_);
|
||||
switch (event.*) {
|
||||
.key_press => |key__| {
|
||||
// Check for a cursor position response for our explicity width query. This will
|
||||
// always be an F3 key with shift = true, and we must be looking for queries
|
||||
if (key__.codepoint == vaxis.Key.f3 and key__.mods.shift and !self.queries_done) {
|
||||
self.logger.print("explicit width capability detected", .{});
|
||||
self.vx.caps.explicit_width = true;
|
||||
self.vx.caps.unicode = .unicode;
|
||||
self.vx.screen.width_method = .unicode;
|
||||
return;
|
||||
}
|
||||
const key_ = filter_mods(normalize_shifted_alphas(key__));
|
||||
try self.sync_mod_state(key_.codepoint, key_.mods);
|
||||
const cbor_msg = try self.fmtmsg(.{
|
||||
|
@ -284,9 +253,8 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
|||
self.vx.caps.sgr_pixels = true;
|
||||
},
|
||||
.cap_da1 => {
|
||||
self.queries_done = true;
|
||||
self.vx.enableDetectedFeatures(self.tty.anyWriter()) catch |e| self.logger.err("enable features", e);
|
||||
self.vx.setMouseMode(self.tty.anyWriter(), true) catch return error.TtyWriteError;
|
||||
try self.vx.setMouseMode(self.tty.anyWriter(), true);
|
||||
},
|
||||
.cap_kitty_keyboard => {
|
||||
self.logger.print("kitty keyboard capability detected", .{});
|
||||
|
@ -305,7 +273,7 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
|||
}
|
||||
}
|
||||
|
||||
fn fmtmsg(self: *Self, value: anytype) std.ArrayList(u8).Writer.Error![]const u8 {
|
||||
fn fmtmsg(self: *Self, value: anytype) ![]const u8 {
|
||||
self.event_buffer.clearRetainingCapacity();
|
||||
try cbor.writeValue(self.event_buffer.writer(), value);
|
||||
return self.event_buffer.items;
|
||||
|
@ -347,7 +315,7 @@ fn handle_bracketed_paste_end(self: *Self) !void {
|
|||
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", self.bracketed_paste_buffer.items }));
|
||||
}
|
||||
|
||||
fn handle_bracketed_paste_error(self: *Self, e: Error) !void {
|
||||
fn handle_bracketed_paste_error(self: *Self, e: anytype) !void {
|
||||
self.logger.err("bracketed paste", e);
|
||||
self.bracketed_paste_buffer.clearAndFree();
|
||||
self.bracketed_paste = false;
|
||||
|
@ -526,7 +494,7 @@ const Loop = struct {
|
|||
}
|
||||
|
||||
/// spawns the input thread to read input from the tty
|
||||
pub fn start(self: *Loop) std.Thread.SpawnError!void {
|
||||
pub fn start(self: *Loop) !void {
|
||||
if (self.thread) |_| return;
|
||||
self.thread = try std.Thread.spawn(.{}, Loop.ttyRun, .{self});
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ pub const StyleBits = packed struct(u5) {
|
|||
undercurl: bool = false,
|
||||
underline: bool = false,
|
||||
italic: bool = false,
|
||||
};
|
||||
|
||||
pub const struck: StyleBits = .{ .struck = true };
|
||||
pub const bold: StyleBits = .{ .bold = true };
|
||||
pub const undercurl: StyleBits = .{ .undercurl = true };
|
||||
pub const underline: StyleBits = .{ .underline = true };
|
||||
pub const italic: StyleBits = .{ .italic = true };
|
||||
pub const normal: StyleBits = .{};
|
||||
pub const struck: StyleBits = .{ .struck = true };
|
||||
pub const bold: StyleBits = .{ .bold = true };
|
||||
pub const undercurl: StyleBits = .{ .undercurl = true };
|
||||
pub const underline: StyleBits = .{ .underline = true };
|
||||
pub const italic: StyleBits = .{ .italic = true };
|
||||
pub const normal: StyleBits = .{};
|
||||
};
|
||||
|
|
|
@ -18,55 +18,8 @@ pub const StyleBits = @import("tuirenderer").style;
|
|||
const gui = @import("gui");
|
||||
const DropWriter = gui.DropWriter;
|
||||
pub const style = StyleBits;
|
||||
pub const styles = @import("tuirenderer").styles;
|
||||
|
||||
pub const Error = error{
|
||||
UnexpectedRendererEvent,
|
||||
OutOfMemory,
|
||||
IntegerTooLarge,
|
||||
IntegerTooSmall,
|
||||
InvalidType,
|
||||
TooShort,
|
||||
Utf8CannotEncodeSurrogateHalf,
|
||||
CodepointTooLarge,
|
||||
VaxisResizeError,
|
||||
InvalidFloatType,
|
||||
InvalidArrayType,
|
||||
InvalidPIntType,
|
||||
JsonIncompatibleType,
|
||||
NotAnObject,
|
||||
} || std.Thread.SpawnError;
|
||||
|
||||
pub const panic = messageBoxThenPanic(.{ .title = "Flow Panic" });
|
||||
|
||||
threadlocal var thread_is_panicing = false;
|
||||
fn messageBoxThenPanic(
|
||||
opt: struct {
|
||||
title: [:0]const u8,
|
||||
style: win32.MESSAGEBOX_STYLE = .{ .ICONASTERISK = 1 },
|
||||
// TODO: add option/logic to include the stacktrace in the messagebox
|
||||
},
|
||||
) std.builtin.PanicFn {
|
||||
return struct {
|
||||
pub fn panic(
|
||||
msg: []const u8,
|
||||
_: ?*std.builtin.StackTrace,
|
||||
ret_addr: ?usize,
|
||||
) noreturn {
|
||||
if (!thread_is_panicing) {
|
||||
thread_is_panicing = true;
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
const msg_z: [:0]const u8 = if (std.fmt.allocPrintZ(
|
||||
arena.allocator(),
|
||||
"{s}",
|
||||
.{msg},
|
||||
)) |msg_z| msg_z else |_| "failed allocate error message";
|
||||
_ = win32.MessageBoxA(null, msg_z, opt.title, opt.style);
|
||||
}
|
||||
std.debug.defaultPanic(msg, ret_addr);
|
||||
}
|
||||
}.panic;
|
||||
}
|
||||
pub const panic = win32.messageBoxThenPanic(.{ .title = "Flow Panic" });
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
vx: vaxis.Vaxis,
|
||||
|
@ -82,7 +35,7 @@ thread: ?std.Thread = null,
|
|||
|
||||
hwnd: ?win32.HWND = null,
|
||||
title_buf: std.ArrayList(u16),
|
||||
style_: ?Style = null,
|
||||
style: ?Style = null,
|
||||
|
||||
const global = struct {
|
||||
var init_called: bool = false;
|
||||
|
@ -97,7 +50,7 @@ pub fn init(
|
|||
handler_ctx: *anyopaque,
|
||||
no_alternate: bool,
|
||||
dispatch_initialized: *const fn (ctx: *anyopaque) void,
|
||||
) Error!Self {
|
||||
) !Self {
|
||||
std.debug.assert(!global.init_called);
|
||||
global.init_called = true;
|
||||
|
||||
|
@ -133,16 +86,16 @@ pub fn deinit(self: *Self) void {
|
|||
self.title_buf.deinit();
|
||||
}
|
||||
|
||||
pub fn run(self: *Self) Error!void {
|
||||
pub fn run(self: *Self) !void {
|
||||
if (self.thread) |_| return;
|
||||
|
||||
// dummy resize to fully init vaxis
|
||||
const drop_writer = DropWriter{};
|
||||
self.vx.resize(
|
||||
try self.vx.resize(
|
||||
self.allocator,
|
||||
drop_writer.writer().any(),
|
||||
.{ .rows = 25, .cols = 80, .x_pixel = 0, .y_pixel = 0 },
|
||||
) catch return error.VaxisResizeError;
|
||||
);
|
||||
|
||||
self.thread = try gui.start();
|
||||
}
|
||||
|
@ -181,7 +134,7 @@ pub fn stdplane(self: *Self) Plane {
|
|||
return plane;
|
||||
}
|
||||
|
||||
pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
||||
pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
|
||||
const Input = struct {
|
||||
kind: u8,
|
||||
codepoint: u21,
|
||||
|
@ -391,12 +344,12 @@ fn update_window_title(self: *Self) void {
|
|||
}
|
||||
|
||||
pub fn set_terminal_style(self: *Self, style_: Style) void {
|
||||
self.style_ = style_;
|
||||
self.style = style_;
|
||||
self.update_window_style();
|
||||
}
|
||||
fn update_window_style(self: *Self) void {
|
||||
const hwnd = self.hwnd orelse return;
|
||||
if (self.style_) |style_| {
|
||||
if (self.style) |style_| {
|
||||
if (style_.bg) |color| gui.set_window_background(hwnd, @intCast(color.color));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ const Process = struct {
|
|||
|
||||
fn receive(self: *Process, _: tp.pid_ref, m: tp.message) tp.result {
|
||||
errdefer self.deinit();
|
||||
var bytes: []const u8 = "";
|
||||
var bytes: []u8 = "";
|
||||
|
||||
if (try m.match(.{ "input", tp.extract(&bytes) })) {
|
||||
const sp = self.sp orelse return tp.exit_error(error.Closed, null);
|
||||
|
@ -155,7 +155,7 @@ const Process = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_output(self: *Process, bytes: []const u8) !void {
|
||||
fn handle_output(self: *Process, bytes: []u8) !void {
|
||||
try self.output.appendSlice(bytes);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,6 @@ pub const Error = error{
|
|||
IntegerTooSmall,
|
||||
InvalidType,
|
||||
TooShort,
|
||||
InvalidFloatType,
|
||||
InvalidArrayType,
|
||||
InvalidPIntType,
|
||||
JsonIncompatibleType,
|
||||
NotAnObject,
|
||||
};
|
||||
|
||||
pub const OutputHandler = fn (context: usize, parent: tp.pid_ref, arg0: []const u8, output: []const u8) void;
|
||||
|
@ -36,7 +31,6 @@ pub const Handlers = struct {
|
|||
out: *const OutputHandler,
|
||||
err: ?*const OutputHandler = null,
|
||||
exit: *const ExitHandler = log_exit_handler,
|
||||
log_execute: bool = true,
|
||||
};
|
||||
|
||||
pub fn execute(allocator: std.mem.Allocator, argv: tp.message, handlers: Handlers) Error!void {
|
||||
|
@ -96,7 +90,6 @@ pub fn log_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, output:
|
|||
_ = parent;
|
||||
_ = arg0;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
defer logger.deinit();
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |line| if (line.len > 0) logger.print("{s}", .{line});
|
||||
}
|
||||
|
@ -105,7 +98,6 @@ pub fn log_err_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, out
|
|||
_ = context;
|
||||
_ = parent;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
defer logger.deinit();
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |line| logger.print_err(arg0, "{s}", .{line});
|
||||
}
|
||||
|
@ -114,7 +106,6 @@ pub fn log_exit_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, er
|
|||
_ = context;
|
||||
_ = parent;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
defer logger.deinit();
|
||||
if (exit_code > 0) {
|
||||
logger.print_err(arg0, "'{s}' terminated {s} exitcode: {d}", .{ arg0, err_msg, exit_code });
|
||||
} else {
|
||||
|
@ -126,7 +117,6 @@ pub fn log_exit_err_handler(context: usize, parent: tp.pid_ref, arg0: []const u8
|
|||
_ = context;
|
||||
_ = parent;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
defer logger.deinit();
|
||||
if (exit_code > 0) {
|
||||
logger.print_err(arg0, "'{s}' terminated {s} exitcode: {d}", .{ arg0, err_msg, exit_code });
|
||||
}
|
||||
|
@ -190,15 +180,14 @@ const Process = struct {
|
|||
_ = tp.set_trap(true);
|
||||
var buf: [1024]u8 = undefined;
|
||||
const json = self.argv.to_json(&buf) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.handlers.log_execute)
|
||||
self.logger.print("shell: execute {s}", .{json});
|
||||
self.logger.print("shell: execute {s}", .{json});
|
||||
self.sp = tp.subprocess.init(self.allocator, self.argv, module_name, self.stdin_behavior) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
||||
fn receive(self: *Process, _: tp.pid_ref, m: tp.message) tp.result {
|
||||
errdefer self.deinit();
|
||||
var bytes: []const u8 = "";
|
||||
var bytes: []u8 = "";
|
||||
|
||||
if (try m.match(.{ "input", tp.extract(&bytes) })) {
|
||||
const sp = self.sp orelse return tp.exit_error(error.Closed, null);
|
||||
|
|
|
@ -9,139 +9,119 @@ pub fn build(b: *std.Build) void {
|
|||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const tree_sitter_dep = b.dependency("tree_sitter", .{
|
||||
const tree_sitter_dep = b.dependency("tree-sitter", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const tree_sitter_host_dep = b.dependency("tree_sitter", .{
|
||||
.target = b.graph.host,
|
||||
.optimize = optimize,
|
||||
});
|
||||
const imports: []const std.Build.Module.Import = if (use_tree_sitter) &.{
|
||||
.{ .name = "build_options", .module = options_mod },
|
||||
.{ .name = "treez", .module = tree_sitter_dep.module("treez") },
|
||||
ts_queryfile(b, tree_sitter_dep, "queries/cmake/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-agda/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-astro/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-bash/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-c-sharp/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-c/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-cpp/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-css/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-diff/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-dockerfile/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-elixir/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-git-rebase/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-gitcommit/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-gleam/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-go/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-fish/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-haskell/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-hare/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-html/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-java/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-javascript/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-jsdoc/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-json/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-julia/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-kdl/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-lua/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-mail/queries/mail/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-make/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown-inline/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nasm/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nim/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ninja/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nix/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nu/queries/nu/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ocaml/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-odin/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-openscad/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-org/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-php/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-python/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-purescript/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-regex/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ruby/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-rust/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ssh-config/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-scala/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-scheme/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-superhtml/tree-sitter-superhtml/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-sql/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-swift/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-toml/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-typescript/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-typst/queries/typst/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-vim/queries/vim/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-xml/queries/dtd/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-xml/queries/xml/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-yaml/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-zig/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ziggy/tree-sitter-ziggy/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ziggy/tree-sitter-ziggy-schema/queries/highlights.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "nvim-treesitter/queries/verilog/highlights.scm"),
|
||||
|
||||
const cbor_dep = b.dependency("cbor", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
ts_queryfile(b, tree_sitter_dep, "queries/cmake/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-astro/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-cpp/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-elixir/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-gitcommit/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-hare/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-html/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-javascript/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-kdl/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-lua/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown-inline/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nasm/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nix/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nu/queries/nu/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-odin/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-openscad/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-php/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-purescript/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-purescript/vim_queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-rust/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-superhtml/tree-sitter-superhtml/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-swift/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-typst/queries/typst/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-vim/queries/vim/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "tree-sitter-zig/queries/injections.scm"),
|
||||
ts_queryfile(b, tree_sitter_dep, "nvim-treesitter/queries/verilog/injections.scm"),
|
||||
} else &.{
|
||||
.{ .name = "build_options", .module = options_mod },
|
||||
};
|
||||
|
||||
const ts_bin_query_gen = b.addExecutable(.{
|
||||
.name = "ts_bin_query_gen",
|
||||
.target = b.graph.host,
|
||||
.root_source_file = b.path("src/ts_bin_query_gen.zig"),
|
||||
});
|
||||
ts_bin_query_gen.linkLibC();
|
||||
ts_bin_query_gen.root_module.addImport("cbor", cbor_dep.module("cbor"));
|
||||
ts_bin_query_gen.root_module.addImport("treez", tree_sitter_host_dep.module("treez"));
|
||||
ts_bin_query_gen.root_module.addImport("build_options", options_mod);
|
||||
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "queries/cmake/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-agda/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-astro/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-bash/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-c-sharp/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-c/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-cpp/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-css/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-diff/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-dockerfile/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-elixir/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-git-rebase/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-gitcommit/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-gleam/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-go/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-fish/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-haskell/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-hare/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-html/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-java/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-javascript/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-jsdoc/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-json/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-julia/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-kdl/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-lua/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-mail/queries/mail/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-make/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-markdown/tree-sitter-markdown/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-markdown/tree-sitter-markdown-inline/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nasm/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nim/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-ninja/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nix/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nu/queries/nu/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-ocaml/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-odin/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-openscad/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-org/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-php/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-python/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-purescript/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-regex/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-ruby/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-rust/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-ssh-config/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-scala/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-scheme/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-superhtml/tree-sitter-superhtml/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-sql/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-swift/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-toml/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-typescript/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-typst/queries/typst/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-vim/queries/vim/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-xml/queries/dtd/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-xml/queries/xml/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-yaml/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-zig/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-ziggy/tree-sitter-ziggy/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-ziggy/tree-sitter-ziggy-schema/queries/highlights.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "nvim-treesitter/queries/verilog/highlights.scm");
|
||||
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "queries/cmake/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-astro/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-cpp/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-elixir/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-gitcommit/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-hare/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-html/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-javascript/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-kdl/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-lua/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-markdown/tree-sitter-markdown-inline/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-markdown/tree-sitter-markdown/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nasm/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nix/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-nu/queries/nu/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-odin/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-openscad/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-php/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-purescript/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-purescript/vim_queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-rust/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-superhtml/tree-sitter-superhtml/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-swift/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-typst/queries/typst/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-vim/queries/vim/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "tree-sitter-zig/queries/injections.scm");
|
||||
ts_queryfile(b, tree_sitter_dep, ts_bin_query_gen, "nvim-treesitter/queries/verilog/injections.scm");
|
||||
|
||||
const syntax_mod = b.addModule("syntax", .{
|
||||
_ = b.addModule("syntax", .{
|
||||
.root_source_file = b.path("src/syntax.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "build_options", .module = options_mod },
|
||||
.{ .name = "cbor", .module = cbor_dep.module("cbor") },
|
||||
.{ .name = "treez", .module = tree_sitter_dep.module("treez") },
|
||||
},
|
||||
.imports = imports,
|
||||
});
|
||||
|
||||
if (use_tree_sitter) {
|
||||
const ts_bin_query_gen_step = b.addRunArtifact(ts_bin_query_gen);
|
||||
const output = ts_bin_query_gen_step.addOutputFileArg("bin_queries.cbor");
|
||||
syntax_mod.addAnonymousImport("syntax_bin_queries", .{ .root_source_file = output });
|
||||
}
|
||||
}
|
||||
|
||||
fn ts_queryfile(b: *std.Build, dep: *std.Build.Dependency, bin_gen: *std.Build.Step.Compile, comptime sub_path: []const u8) void {
|
||||
const module = b.createModule(.{ .root_source_file = dep.path(sub_path) });
|
||||
bin_gen.root_module.addImport(sub_path, module);
|
||||
fn ts_queryfile(b: *std.Build, dep: *std.Build.Dependency, comptime sub_path: []const u8) std.Build.Module.Import {
|
||||
return .{
|
||||
.name = sub_path,
|
||||
.module = b.createModule(.{
|
||||
.root_source_file = dep.path(sub_path),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
.{
|
||||
.name = .flow_syntax,
|
||||
.version = "0.1.0",
|
||||
.fingerprint = 0x3ba2584ea1cec85f,
|
||||
.minimum_zig_version = "0.14.0-dev.3451+d8d2aa9af",
|
||||
.name = "flow-syntax",
|
||||
.version = "0.0.1",
|
||||
|
||||
.dependencies = .{
|
||||
.tree_sitter = .{
|
||||
.@"tree-sitter" = .{
|
||||
.url = "https://github.com/neurocyte/tree-sitter/releases/download/master-86dd4d2536f2748c5b4ea0e1e70678039a569aac/source.tar.gz",
|
||||
.hash = "N-V-__8AACablCbp-6lsRoKDEp6Xd2dHLe4AsW81blkSQxzs",
|
||||
},
|
||||
.cbor = .{
|
||||
.url = "https://github.com/neurocyte/cbor/archive/1fccb83c70cd84e1dff57cc53f7db8fb99909a94.tar.gz",
|
||||
.hash = "cbor-1.0.0-RcQE_HvqAACcrLH7t3IDZOshgY2xqJA_UX330MvwSepb",
|
||||
.hash = "1220e9fba96c468283129e977767472dee00b16f356e5912431cec8f1a009b6691a2",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
|
|
|
@ -1,187 +0,0 @@
|
|||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
const treez = if (build_options.use_tree_sitter)
|
||||
@import("treez")
|
||||
else
|
||||
@import("treez_dummy.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const tss = @import("ts_serializer.zig");
|
||||
pub const FileType = @import("file_type.zig");
|
||||
const Query = treez.Query;
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
mutex: ?std.Thread.Mutex,
|
||||
highlights: std.StringHashMapUnmanaged(*CacheEntry) = .{},
|
||||
injections: std.StringHashMapUnmanaged(*CacheEntry) = .{},
|
||||
ref_count: usize = 1,
|
||||
|
||||
const CacheEntry = struct {
|
||||
mutex: ?std.Thread.Mutex,
|
||||
query: ?*Query,
|
||||
query_arena: ?*std.heap.ArenaAllocator,
|
||||
query_type: QueryType,
|
||||
file_type: *const FileType,
|
||||
|
||||
fn destroy(self: *@This(), allocator: std.mem.Allocator) void {
|
||||
if (self.query_arena) |a| {
|
||||
a.deinit();
|
||||
allocator.destroy(a);
|
||||
} else if (self.query) |q|
|
||||
q.destroy();
|
||||
self.query_arena = null;
|
||||
self.query = null;
|
||||
}
|
||||
};
|
||||
|
||||
pub const QueryType = enum {
|
||||
highlights,
|
||||
injections,
|
||||
};
|
||||
|
||||
const QueryParseError = error{
|
||||
InvalidSyntax,
|
||||
InvalidNodeType,
|
||||
InvalidField,
|
||||
InvalidCapture,
|
||||
InvalidStructure,
|
||||
InvalidLanguage,
|
||||
};
|
||||
|
||||
const CacheError = error{
|
||||
NotFound,
|
||||
OutOfMemory,
|
||||
};
|
||||
|
||||
pub const Error = CacheError || QueryParseError || QuerySerializeError;
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, opts: struct { lock: bool = false }) !*Self {
|
||||
const self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.mutex = if (opts.lock) .{} else null,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.release_ref_unlocked_and_maybe_destroy();
|
||||
}
|
||||
|
||||
fn add_ref_locked(self: *Self) void {
|
||||
std.debug.assert(self.ref_count > 0);
|
||||
self.ref_count += 1;
|
||||
}
|
||||
|
||||
fn release_ref_unlocked_and_maybe_destroy(self: *Self) void {
|
||||
{
|
||||
if (self.mutex) |*mtx| mtx.lock();
|
||||
defer if (self.mutex) |*mtx| mtx.unlock();
|
||||
self.ref_count -= 1;
|
||||
if (self.ref_count > 0) return;
|
||||
}
|
||||
|
||||
var iter_highlights = self.highlights.iterator();
|
||||
while (iter_highlights.next()) |p| {
|
||||
self.allocator.free(p.key_ptr.*);
|
||||
p.value_ptr.*.destroy(self.allocator);
|
||||
self.allocator.destroy(p.value_ptr.*);
|
||||
}
|
||||
var iter_injections = self.injections.iterator();
|
||||
while (iter_injections.next()) |p| {
|
||||
self.allocator.free(p.key_ptr.*);
|
||||
p.value_ptr.*.destroy(self.allocator);
|
||||
self.allocator.destroy(p.value_ptr.*);
|
||||
}
|
||||
self.highlights.deinit(self.allocator);
|
||||
self.injections.deinit(self.allocator);
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
fn get_cache_entry(self: *Self, file_type: *const FileType, comptime query_type: QueryType) CacheError!*CacheEntry {
|
||||
if (self.mutex) |*mtx| mtx.lock();
|
||||
defer if (self.mutex) |*mtx| mtx.unlock();
|
||||
|
||||
const hash = switch (query_type) {
|
||||
.highlights => &self.highlights,
|
||||
.injections => &self.injections,
|
||||
};
|
||||
|
||||
return if (hash.get(file_type.name)) |entry| entry else blk: {
|
||||
const entry_ = try hash.getOrPut(self.allocator, try self.allocator.dupe(u8, file_type.name));
|
||||
|
||||
const q = try self.allocator.create(CacheEntry);
|
||||
q.* = .{
|
||||
.query = null,
|
||||
.query_arena = null,
|
||||
.mutex = if (self.mutex) |_| .{} else null,
|
||||
.file_type = file_type,
|
||||
.query_type = query_type,
|
||||
};
|
||||
entry_.value_ptr.* = q;
|
||||
|
||||
break :blk q;
|
||||
};
|
||||
}
|
||||
|
||||
fn get_cached_query(self: *Self, entry: *CacheEntry) Error!?*Query {
|
||||
if (entry.mutex) |*mtx| mtx.lock();
|
||||
defer if (entry.mutex) |*mtx| mtx.unlock();
|
||||
|
||||
return if (entry.query) |query| query else blk: {
|
||||
const lang = entry.file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{entry.file_type.name});
|
||||
const queries = FileType.queries.get(entry.file_type.name) orelse return null;
|
||||
const query_bin = switch (entry.query_type) {
|
||||
.highlights => queries.highlights_bin,
|
||||
.injections => queries.injections_bin orelse return null,
|
||||
};
|
||||
const query, const arena = try deserialize_query(query_bin, lang, self.allocator);
|
||||
entry.query = query;
|
||||
entry.query_arena = arena;
|
||||
break :blk entry.query.?;
|
||||
};
|
||||
}
|
||||
|
||||
fn pre_load_internal(self: *Self, file_type: *const FileType, comptime query_type: QueryType) Error!void {
|
||||
_ = try self.get_cached_query(try self.get_cache_entry(file_type, query_type));
|
||||
}
|
||||
|
||||
pub fn pre_load(self: *Self, lang_name: []const u8) Error!void {
|
||||
const file_type = FileType.get_by_name(lang_name) orelse return;
|
||||
_ = try self.pre_load_internal(file_type, .highlights);
|
||||
_ = try self.pre_load_internal(file_type, .injections);
|
||||
}
|
||||
|
||||
fn ReturnType(comptime query_type: QueryType) type {
|
||||
return switch (query_type) {
|
||||
.highlights => *Query,
|
||||
.injections => ?*Query,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get(self: *Self, file_type: *const FileType, comptime query_type: QueryType) Error!ReturnType(query_type) {
|
||||
const query = try self.get_cached_query(try self.get_cache_entry(file_type, query_type));
|
||||
self.add_ref_locked();
|
||||
return switch (@typeInfo(ReturnType(query_type))) {
|
||||
.optional => |_| query,
|
||||
else => query.?,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn release(self: *Self, query: *Query, comptime query_type: QueryType) void {
|
||||
_ = query;
|
||||
_ = query_type;
|
||||
self.release_ref_unlocked_and_maybe_destroy();
|
||||
}
|
||||
|
||||
pub const QuerySerializeError = (tss.SerializeError || tss.DeserializeError);
|
||||
|
||||
fn deserialize_query(query_bin: []const u8, language: ?*const treez.Language, allocator: std.mem.Allocator) QuerySerializeError!struct { *Query, *std.heap.ArenaAllocator } {
|
||||
var ts_query_out, const arena = try tss.fromCbor(query_bin, allocator);
|
||||
ts_query_out.language = @intFromPtr(language);
|
||||
|
||||
const query_out: *Query = @alignCast(@ptrCast(ts_query_out));
|
||||
return .{ query_out, arena };
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
const treez = if (build_options.use_tree_sitter)
|
||||
|
@ -15,6 +14,8 @@ name: []const u8,
|
|||
description: []const u8,
|
||||
lang_fn: LangFn,
|
||||
extensions: []const []const u8,
|
||||
highlights: [:0]const u8,
|
||||
injections: ?[:0]const u8,
|
||||
first_line_matches: ?FirstLineMatch = null,
|
||||
comment: []const u8,
|
||||
formatter: ?[]const []const u8,
|
||||
|
@ -87,7 +88,7 @@ fn ft_func_name(comptime lang: []const u8) []const u8 {
|
|||
|
||||
const LangFn = *const fn () callconv(.C) ?*const treez.Language;
|
||||
|
||||
pub const FirstLineMatch = struct {
|
||||
const FirstLineMatch = struct {
|
||||
prefix: ?[]const u8 = null,
|
||||
content: ?[]const u8 = null,
|
||||
};
|
||||
|
@ -104,7 +105,7 @@ fn vec(comptime args: anytype) []const []const u8 {
|
|||
|
||||
fn load_file_types(comptime Namespace: type) []const FileType {
|
||||
comptime switch (@typeInfo(Namespace)) {
|
||||
.@"struct" => |info| {
|
||||
.Struct => |info| {
|
||||
var count = 0;
|
||||
for (info.decls) |_| {
|
||||
// @compileLog(decl.name, @TypeOf(@field(Namespace, decl.name)));
|
||||
|
@ -123,6 +124,22 @@ fn load_file_types(comptime Namespace: type) []const FileType {
|
|||
.lang_fn = if (@hasField(@TypeOf(args), "parser")) args.parser else get_parser(lang),
|
||||
.extensions = vec(args.extensions),
|
||||
.comment = args.comment,
|
||||
.highlights = if (build_options.use_tree_sitter)
|
||||
if (@hasField(@TypeOf(args), "highlights"))
|
||||
@embedFile(args.highlights)
|
||||
else if (@hasField(@TypeOf(args), "highlights_list"))
|
||||
@embedFile(args.highlights_list[0]) ++ "\n" ++ @embedFile(args.highlights_list[1])
|
||||
else
|
||||
@embedFile("tree-sitter-" ++ lang ++ "/queries/highlights.scm")
|
||||
else
|
||||
"",
|
||||
.injections = if (build_options.use_tree_sitter)
|
||||
if (@hasField(@TypeOf(args), "injections"))
|
||||
@embedFile(args.injections)
|
||||
else
|
||||
null
|
||||
else
|
||||
null,
|
||||
.first_line_matches = if (@hasField(@TypeOf(args), "first_line_matches")) args.first_line_matches else null,
|
||||
.formatter = if (@hasField(@TypeOf(args), "formatter")) vec(args.formatter) else null,
|
||||
.language_server = if (@hasField(@TypeOf(args), "language_server")) vec(args.language_server) else null,
|
||||
|
@ -135,63 +152,3 @@ fn load_file_types(comptime Namespace: type) []const FileType {
|
|||
else => @compileError("expected tuple or struct type"),
|
||||
};
|
||||
}
|
||||
|
||||
pub const FileTypeQueries = struct {
|
||||
highlights_bin: []const u8,
|
||||
injections_bin: ?[]const u8,
|
||||
};
|
||||
|
||||
pub const queries = std.static_string_map.StaticStringMap(FileTypeQueries).initComptime(load_queries());
|
||||
|
||||
fn load_queries() []const struct { []const u8, FileTypeQueries } {
|
||||
if (!build_options.use_tree_sitter) return &.{};
|
||||
@setEvalBranchQuota(16000);
|
||||
const queries_cb = @embedFile("syntax_bin_queries");
|
||||
var iter: []const u8 = queries_cb;
|
||||
var len = cbor.decodeMapHeader(&iter) catch |e| {
|
||||
@compileLog("cbor.decodeMapHeader", e);
|
||||
@compileError("invalid syntax_bin_queries");
|
||||
};
|
||||
var construct_types: [len]struct { []const u8, FileTypeQueries } = undefined;
|
||||
var i = 0;
|
||||
while (len > 0) : (len -= 1) {
|
||||
var lang: []const u8 = undefined;
|
||||
if (!try cbor.matchString(&iter, &lang))
|
||||
@compileError("invalid language name field");
|
||||
construct_types[i] = .{ lang, .{
|
||||
.highlights_bin = blk: {
|
||||
var iter_: []const u8 = iter;
|
||||
break :blk get_query_value_bin(&iter_, "highlights") orelse @compileError("missing highlights for " ++ lang);
|
||||
},
|
||||
.injections_bin = blk: {
|
||||
var iter_: []const u8 = iter;
|
||||
break :blk get_query_value_bin(&iter_, "injections");
|
||||
},
|
||||
} };
|
||||
try cbor.skipValue(&iter);
|
||||
i += 1;
|
||||
}
|
||||
const types = construct_types;
|
||||
return &types;
|
||||
}
|
||||
|
||||
fn get_query_value_bin(iter: *[]const u8, comptime query: []const u8) ?[]const u8 {
|
||||
var len = cbor.decodeMapHeader(iter) catch |e| {
|
||||
@compileLog("cbor.decodeMapHeader", e);
|
||||
@compileError("invalid query map in syntax_bin_queries");
|
||||
};
|
||||
while (len > 0) : (len -= 1) {
|
||||
var query_name: []const u8 = undefined;
|
||||
if (!try cbor.matchString(iter, &query_name))
|
||||
@compileError("invalid query name field");
|
||||
if (std.mem.eql(u8, query_name, query)) {
|
||||
var query_value: []const u8 = undefined;
|
||||
if (try cbor.matchValue(iter, cbor.extract(&query_value)))
|
||||
return query_value;
|
||||
@compileError("invalid query value field");
|
||||
} else {
|
||||
try cbor.skipValue(iter);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
const file_type = @import("file_type.zig");
|
||||
const FirstLineMatch = file_type.FirstLineMatch;
|
||||
|
||||
pub const agda = .{
|
||||
.description = "Agda",
|
||||
.extensions = .{"agda"},
|
||||
|
@ -21,7 +18,7 @@ pub const bash = .{
|
|||
.icon = "",
|
||||
.extensions = .{ "sh", "bash", ".profile" },
|
||||
.comment = "#",
|
||||
.first_line_matches = FirstLineMatch{ .prefix = "#!", .content = "sh" },
|
||||
.first_line_matches = .{ .prefix = "#!", .content = "sh" },
|
||||
.formatter = .{ "shfmt", "--indent", "4" },
|
||||
.language_server = .{ "bash-language-server", "start" },
|
||||
};
|
||||
|
@ -48,7 +45,7 @@ pub const conf = .{
|
|||
.description = "Config",
|
||||
.color = 0x000000,
|
||||
.icon = "",
|
||||
.extensions = .{ "conf", "log", "config", ".gitconfig", "gui_config" },
|
||||
.extensions = .{ "conf", "config", ".gitconfig", "gui_config" },
|
||||
.highlights = fish.highlights,
|
||||
.comment = "#",
|
||||
.parser = fish.parser,
|
||||
|
@ -256,7 +253,7 @@ pub const lua = .{
|
|||
.extensions = .{"lua"},
|
||||
.comment = "--",
|
||||
.injections = "tree-sitter-lua/queries/injections.scm",
|
||||
.first_line_matches = FirstLineMatch{ .prefix = "--", .content = "lua" },
|
||||
.first_line_matches = .{ .prefix = "--", .content = "lua" },
|
||||
.language_server = .{"lua-lsp"},
|
||||
};
|
||||
|
||||
|
@ -266,7 +263,7 @@ pub const mail = .{
|
|||
.extensions = .{ "eml", "mbox" },
|
||||
.comment = ">",
|
||||
.highlights = "tree-sitter-mail/queries/mail/highlights.scm",
|
||||
.first_line_matches = FirstLineMatch{ .prefix = "From" },
|
||||
.first_line_matches = .{ .prefix = "From" },
|
||||
};
|
||||
|
||||
pub const make = .{
|
||||
|
@ -410,7 +407,7 @@ pub const python = .{
|
|||
.icon = "",
|
||||
.extensions = .{ "py", "pyi" },
|
||||
.comment = "#",
|
||||
.first_line_matches = FirstLineMatch{ .prefix = "#!", .content = "python" },
|
||||
.first_line_matches = .{ .prefix = "#!", .content = "python" },
|
||||
.language_server = .{"pylsp"},
|
||||
};
|
||||
|
||||
|
@ -523,7 +520,7 @@ pub const xml = .{
|
|||
.extensions = .{"xml"},
|
||||
.comment = "<!--",
|
||||
.highlights = "tree-sitter-xml/queries/xml/highlights.scm",
|
||||
.first_line_matches = FirstLineMatch{ .prefix = "<?xml " },
|
||||
.first_line_matches = .{ .prefix = "<?xml " },
|
||||
.formatter = .{ "xmllint", "--format", "-" },
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ const Self = @This();
|
|||
|
||||
pub const Edit = treez.InputEdit;
|
||||
pub const FileType = @import("file_type.zig");
|
||||
pub const QueryCache = @import("QueryCache.zig");
|
||||
pub const Range = treez.Range;
|
||||
pub const Point = treez.Point;
|
||||
const Input = treez.Input;
|
||||
|
@ -24,40 +23,37 @@ lang: *const Language,
|
|||
file_type: *const FileType,
|
||||
parser: *Parser,
|
||||
query: *Query,
|
||||
injections: ?*Query,
|
||||
injections: *Query,
|
||||
tree: ?*treez.Tree = null,
|
||||
|
||||
pub fn create(file_type: *const FileType, allocator: std.mem.Allocator, query_cache: *QueryCache) !*Self {
|
||||
const query = try query_cache.get(file_type, .highlights);
|
||||
const injections = try query_cache.get(file_type, .injections);
|
||||
pub fn create(file_type: *const FileType, allocator: std.mem.Allocator) !*Self {
|
||||
const self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.lang = file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{file_type.name}),
|
||||
.file_type = file_type,
|
||||
.parser = try Parser.create(),
|
||||
.query = query,
|
||||
.injections = injections,
|
||||
.query = try Query.create(self.lang, file_type.highlights),
|
||||
.injections = try Query.create(self.lang, file_type.highlights),
|
||||
};
|
||||
errdefer self.destroy(query_cache);
|
||||
errdefer self.destroy();
|
||||
try self.parser.setLanguage(self.lang);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn create_file_type(allocator: std.mem.Allocator, lang_name: []const u8, query_cache: *QueryCache) !*Self {
|
||||
pub fn create_file_type(allocator: std.mem.Allocator, lang_name: []const u8) !*Self {
|
||||
const file_type = FileType.get_by_name(lang_name) orelse return error.NotFound;
|
||||
return create(file_type, allocator, query_cache);
|
||||
return create(file_type, allocator);
|
||||
}
|
||||
|
||||
pub fn create_guess_file_type(allocator: std.mem.Allocator, content: []const u8, file_path: ?[]const u8, query_cache: *QueryCache) !*Self {
|
||||
pub fn create_guess_file_type(allocator: std.mem.Allocator, content: []const u8, file_path: ?[]const u8) !*Self {
|
||||
const file_type = FileType.guess(file_path, content) orelse return error.NotFound;
|
||||
return create(file_type, allocator, query_cache);
|
||||
return create(file_type, allocator);
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Self, query_cache: *QueryCache) void {
|
||||
pub fn destroy(self: *Self) void {
|
||||
if (self.tree) |tree| tree.destroy();
|
||||
query_cache.release(self.query, .highlights);
|
||||
if (self.injections) |injections| query_cache.release(injections, .injections);
|
||||
self.query.destroy();
|
||||
self.parser.destroy();
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const treez = @import("treez");
|
||||
|
||||
pub const tss = @import("ts_serializer.zig");
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
const args = try std.process.argsAlloc(allocator);
|
||||
|
||||
var opt_output_file_path: ?[]const u8 = null;
|
||||
|
||||
var i: usize = 1;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (opt_output_file_path != null) fatal("duplicated {s} argument", .{arg});
|
||||
opt_output_file_path = args[i];
|
||||
}
|
||||
|
||||
const output_file_path = opt_output_file_path orelse fatal("missing output file", .{});
|
||||
var output_file = std.fs.cwd().createFile(output_file_path, .{}) catch |err| {
|
||||
fatal("unable to open '{s}': {s}", .{ output_file_path, @errorName(err) });
|
||||
};
|
||||
defer output_file.close();
|
||||
|
||||
var output = std.ArrayList(u8).init(allocator);
|
||||
defer output.deinit();
|
||||
const writer = output.writer();
|
||||
|
||||
try cbor.writeMapHeader(writer, file_types.len);
|
||||
|
||||
for (file_types) |file_type| {
|
||||
const lang = file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{file_type.name});
|
||||
|
||||
try cbor.writeValue(writer, file_type.name);
|
||||
try cbor.writeMapHeader(writer, if (file_type.injections) |_| 2 else 1);
|
||||
|
||||
const highlights_in = try treez.Query.create(lang, file_type.highlights);
|
||||
const ts_highlights_in: *tss.TSQuery = @alignCast(@ptrCast(highlights_in));
|
||||
|
||||
const highlights_cb = try tss.toCbor(ts_highlights_in, allocator);
|
||||
defer allocator.free(highlights_cb);
|
||||
|
||||
try cbor.writeValue(writer, "highlights");
|
||||
try cbor.writeValue(writer, highlights_cb);
|
||||
// std.log.info("file_type {s} highlights {d} bytes", .{ file_type.name, highlights_cb.len });
|
||||
|
||||
if (file_type.injections) |injections| {
|
||||
const injections_in = try treez.Query.create(lang, injections);
|
||||
const ts_injections_in: *tss.TSQuery = @alignCast(@ptrCast(injections_in));
|
||||
|
||||
const injections_cb = try tss.toCbor(ts_injections_in, allocator);
|
||||
defer allocator.free(injections_cb);
|
||||
|
||||
try cbor.writeValue(writer, "injections");
|
||||
try cbor.writeValue(writer, injections_cb);
|
||||
// std.log.info("file_type {s} injections {d} bytes", .{ file_type.name, injections_cb.len });
|
||||
}
|
||||
}
|
||||
|
||||
try output_file.writeAll(output.items);
|
||||
// std.log.info("file_types total {d} bytes", .{output.items.len});
|
||||
}
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.debug.print(format, args);
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
pub const file_types = load_file_types(@import("file_types.zig"));
|
||||
|
||||
const FileType = struct {
|
||||
name: []const u8,
|
||||
lang_fn: LangFn,
|
||||
highlights: [:0]const u8,
|
||||
injections: ?[:0]const u8,
|
||||
};
|
||||
const LangFn = *const fn () callconv(.C) ?*const treez.Language;
|
||||
|
||||
fn load_file_types(comptime Namespace: type) []const FileType {
|
||||
comptime switch (@typeInfo(Namespace)) {
|
||||
.@"struct" => |info| {
|
||||
var count = 0;
|
||||
for (info.decls) |_| count += 1;
|
||||
var construct_types: [count]FileType = undefined;
|
||||
var i = 0;
|
||||
for (info.decls) |decl| {
|
||||
const lang = decl.name;
|
||||
const args = @field(Namespace, lang);
|
||||
construct_types[i] = .{
|
||||
.name = lang,
|
||||
.lang_fn = if (@hasField(@TypeOf(args), "parser")) args.parser else get_parser(lang),
|
||||
.highlights = if (@hasField(@TypeOf(args), "highlights"))
|
||||
@embedFile(args.highlights)
|
||||
else if (@hasField(@TypeOf(args), "highlights_list"))
|
||||
@embedFile(args.highlights_list[0]) ++ "\n" ++ @embedFile(args.highlights_list[1])
|
||||
else
|
||||
@embedFile("tree-sitter-" ++ lang ++ "/queries/highlights.scm"),
|
||||
.injections = if (@hasField(@TypeOf(args), "injections"))
|
||||
@embedFile(args.injections)
|
||||
else
|
||||
null,
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
const types = construct_types;
|
||||
return &types;
|
||||
},
|
||||
else => @compileError("expected tuple or struct type"),
|
||||
};
|
||||
}
|
||||
|
||||
fn get_parser(comptime lang: []const u8) LangFn {
|
||||
const language_name = ft_func_name(lang);
|
||||
return @extern(?LangFn, .{ .name = "tree_sitter_" ++ language_name }) orelse @compileError(std.fmt.comptimePrint("Cannot find extern tree_sitter_{s}", .{language_name}));
|
||||
}
|
||||
|
||||
fn ft_func_name(comptime lang: []const u8) []const u8 {
|
||||
var transform: [lang.len]u8 = undefined;
|
||||
for (lang, 0..) |c, i|
|
||||
transform[i] = if (c == '-') '_' else c;
|
||||
const func_name = transform;
|
||||
return &func_name;
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
/// This file *MUST* be kept in sync with tree-sitter/lib/src/query.c
|
||||
/// It exactly represents the C structures in memory and must produce
|
||||
/// the exact same results as the C tree-sitter library version used.
|
||||
///
|
||||
/// Yes,... it is not a public API! Here be dragons!
|
||||
///
|
||||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const build_options = @import("build_options");
|
||||
const treez = if (build_options.use_tree_sitter) @import("treez") else @import("treez_dummy.zig");
|
||||
|
||||
pub const Slice = extern struct {
|
||||
offset: u32,
|
||||
length: u32,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.offset),
|
||||
cbor.extract(&self.length),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub fn Array(T: type) type {
|
||||
return extern struct {
|
||||
contents: ?*T,
|
||||
size: u32,
|
||||
capacity: u32,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
if (self.contents) |contents| {
|
||||
const arr: []T = @as([*]T, @ptrCast(contents))[0..self.size];
|
||||
try cbor.writeValue(writer, arr);
|
||||
return;
|
||||
}
|
||||
try cbor.writeValue(writer, null);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
||||
var iter_ = iter.*;
|
||||
if (cbor.matchValue(&iter_, cbor.null_) catch false) {
|
||||
iter.* = iter_;
|
||||
self.contents = null;
|
||||
self.size = 0;
|
||||
self.capacity = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (T == u8) {
|
||||
var arr: []const u8 = undefined;
|
||||
if (try cbor.matchValue(iter, cbor.extract(&arr))) {
|
||||
self.contents = @constCast(@ptrCast(arr.ptr));
|
||||
self.size = @intCast(arr.len);
|
||||
self.capacity = @intCast(arr.len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
var n = try cbor.decodeArrayHeader(iter);
|
||||
var arr: []T = try allocator.alloc(T, n);
|
||||
while (n > 0) : (n -= 1) {
|
||||
if (comptime cbor.isExtractableAlloc(T)) {
|
||||
if (!(cbor.matchValue(iter, cbor.extractAlloc(&arr[i], allocator)) catch return false))
|
||||
return false;
|
||||
} else {
|
||||
if (!(cbor.matchValue(iter, cbor.extract(&arr[i])) catch return false))
|
||||
return false;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
self.contents = @constCast(@ptrCast(arr.ptr));
|
||||
self.size = @intCast(arr.len);
|
||||
self.capacity = @intCast(arr.len);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const SymbolTable = extern struct {
|
||||
characters: Array(u8),
|
||||
slices: Array(Slice),
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extractAlloc(&self.characters, allocator),
|
||||
cbor.extractAlloc(&self.slices, allocator),
|
||||
});
|
||||
}
|
||||
};
|
||||
pub const CaptureQuantifiers = Array(u8);
|
||||
pub const PatternEntry = extern struct {
|
||||
step_index: u16,
|
||||
pattern_index: u16,
|
||||
is_rooted: bool,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.step_index),
|
||||
cbor.extract(&self.pattern_index),
|
||||
cbor.extract(&self.is_rooted),
|
||||
});
|
||||
}
|
||||
};
|
||||
pub const QueryPattern = extern struct {
|
||||
steps: Slice,
|
||||
predicate_steps: Slice,
|
||||
start_byte: u32,
|
||||
end_byte: u32,
|
||||
is_non_local: bool,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extractAlloc(&self.steps, allocator),
|
||||
cbor.extractAlloc(&self.predicate_steps, allocator),
|
||||
cbor.extract(&self.start_byte),
|
||||
cbor.extract(&self.end_byte),
|
||||
cbor.extract(&self.is_non_local),
|
||||
});
|
||||
}
|
||||
};
|
||||
pub const StepOffset = extern struct {
|
||||
byte_offset: u32,
|
||||
step_index: u16,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.byte_offset),
|
||||
cbor.extract(&self.step_index),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub const MAX_STEP_CAPTURE_COUNT = 3;
|
||||
|
||||
pub const TSSymbol = u16;
|
||||
pub const TSFieldId = u16;
|
||||
|
||||
pub const QueryStep = extern struct {
|
||||
symbol: TSSymbol,
|
||||
supertype_symbol: TSSymbol,
|
||||
field: TSFieldId,
|
||||
capture_ids: [MAX_STEP_CAPTURE_COUNT]u16,
|
||||
depth: u16,
|
||||
alternative_index: u16,
|
||||
negated_field_list_id: u16,
|
||||
// is_named: u1,
|
||||
// is_immediate: u1,
|
||||
// is_last_child: u1,
|
||||
// is_pass_through: u1,
|
||||
// is_dead_end: u1,
|
||||
// alternative_is_immediate: u1,
|
||||
// contains_captures: u1,
|
||||
// root_pattern_guaranteed: u1,
|
||||
flags8: u8,
|
||||
// parent_pattern_guaranteed: u1,
|
||||
flags16: u8,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.symbol),
|
||||
cbor.extract(&self.supertype_symbol),
|
||||
cbor.extract(&self.field),
|
||||
cbor.extract(&self.capture_ids),
|
||||
cbor.extract(&self.depth),
|
||||
cbor.extract(&self.alternative_index),
|
||||
cbor.extract(&self.negated_field_list_id),
|
||||
cbor.extract(&self.flags8),
|
||||
cbor.extract(&self.flags16),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub const PredicateStep = extern struct {
|
||||
pub const Type = enum(c_uint) {
|
||||
done,
|
||||
capture,
|
||||
string,
|
||||
};
|
||||
|
||||
type: Type,
|
||||
value_id: u32,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.type),
|
||||
cbor.extract(&self.value_id),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub const TSQuery = extern struct {
|
||||
captures: SymbolTable,
|
||||
predicate_values: SymbolTable,
|
||||
capture_quantifiers: Array(CaptureQuantifiers),
|
||||
steps: Array(QueryStep),
|
||||
pattern_map: Array(PatternEntry),
|
||||
predicate_steps: Array(PredicateStep),
|
||||
patterns: Array(QueryPattern),
|
||||
step_offsets: Array(StepOffset),
|
||||
negated_fields: Array(TSFieldId),
|
||||
string_buffer: Array(u8),
|
||||
repeat_symbols_with_rootless_patterns: Array(TSSymbol),
|
||||
language: usize,
|
||||
// language: ?*const treez.Language,
|
||||
wildcard_root_pattern_count: u16,
|
||||
|
||||
pub fn cborEncode(self: *const @This(), writer: anytype) !void {
|
||||
return cbor.writeArray(writer, self.*);
|
||||
}
|
||||
|
||||
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
||||
const result = cbor.matchValue(iter, .{
|
||||
cbor.extractAlloc(&self.captures, allocator),
|
||||
cbor.extractAlloc(&self.predicate_values, allocator),
|
||||
cbor.extractAlloc(&self.capture_quantifiers, allocator),
|
||||
cbor.extractAlloc(&self.steps, allocator),
|
||||
cbor.extractAlloc(&self.pattern_map, allocator),
|
||||
cbor.extractAlloc(&self.predicate_steps, allocator),
|
||||
cbor.extractAlloc(&self.patterns, allocator),
|
||||
cbor.extractAlloc(&self.step_offsets, allocator),
|
||||
cbor.extractAlloc(&self.negated_fields, allocator),
|
||||
cbor.extractAlloc(&self.string_buffer, allocator),
|
||||
cbor.extractAlloc(&self.repeat_symbols_with_rootless_patterns, allocator),
|
||||
cbor.extract(&self.language),
|
||||
cbor.extract(&self.wildcard_root_pattern_count),
|
||||
});
|
||||
self.language = 0;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
pub const SerializeError = error{OutOfMemory};
|
||||
|
||||
pub fn toCbor(query: *TSQuery, allocator: std.mem.Allocator) SerializeError![]const u8 {
|
||||
var cb: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer cb.deinit(allocator);
|
||||
try cbor.writeValue(cb.writer(allocator), query.*);
|
||||
return cb.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
pub const DeserializeError = error{
|
||||
OutOfMemory,
|
||||
IntegerTooLarge,
|
||||
IntegerTooSmall,
|
||||
InvalidType,
|
||||
TooShort,
|
||||
InvalidFloatType,
|
||||
InvalidArrayType,
|
||||
InvalidPIntType,
|
||||
JsonIncompatibleType,
|
||||
InvalidQueryCbor,
|
||||
NotAnObject,
|
||||
};
|
||||
|
||||
pub fn fromCbor(cb: []const u8, allocator: std.mem.Allocator) DeserializeError!struct { *TSQuery, *std.heap.ArenaAllocator } {
|
||||
var arena = try allocator.create(std.heap.ArenaAllocator);
|
||||
arena.* = std.heap.ArenaAllocator.init(allocator);
|
||||
errdefer arena.deinit();
|
||||
const query = try arena.allocator().create(TSQuery);
|
||||
query.* = undefined;
|
||||
var iter: []const u8 = cb;
|
||||
if (!try cbor.matchValue(&iter, cbor.extractAlloc(query, arena.allocator())))
|
||||
return error.InvalidQueryCbor;
|
||||
return .{ query, arena };
|
||||
}
|
|
@ -65,7 +65,7 @@ pub fn to_unowned(pimpl: anytype) Self {
|
|||
|
||||
pub fn bind(pimpl: anytype, comptime f: *const fn (ctx: @TypeOf(pimpl), from: tp.pid_ref, m: tp.message) Error!bool) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.pointer.child;
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.vtable = comptime &.{
|
||||
|
|
|
@ -55,7 +55,7 @@ pub const VTable = struct {
|
|||
|
||||
pub fn to(pimpl: anytype) Self {
|
||||
const impl = @typeInfo(@TypeOf(pimpl));
|
||||
const child: type = impl.pointer.child;
|
||||
const child: type = impl.Pointer.child;
|
||||
return .{
|
||||
.ptr = pimpl,
|
||||
.plane = &pimpl.plane,
|
||||
|
|
|
@ -23,7 +23,7 @@ plane: Plane,
|
|||
parent: Plane,
|
||||
allocator: Allocator,
|
||||
widgets: ArrayList(WidgetState),
|
||||
layout_: Layout,
|
||||
layout: Layout,
|
||||
direction: Direction,
|
||||
box: ?Widget.Box = null,
|
||||
ctx: ?*anyopaque = null,
|
||||
|
@ -31,7 +31,7 @@ on_render: *const fn (ctx: ?*anyopaque, theme: *const Widget.Theme) void = on_re
|
|||
after_render: *const fn (ctx: ?*anyopaque, theme: *const Widget.Theme) void = on_render_default,
|
||||
on_resize: *const fn (ctx: ?*anyopaque, self: *Self, pos_: Widget.Box) void = on_resize_default,
|
||||
|
||||
pub fn createH(allocator: Allocator, parent: Plane, name: [:0]const u8, layout_: Layout) error{OutOfMemory}!*Self {
|
||||
pub fn createH(allocator: Allocator, parent: Plane, name: [:0]const u8, layout_: Layout) !*Self {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = try init(allocator, parent, name, .horizontal, layout_, Box{});
|
||||
self.plane.hide();
|
||||
|
@ -58,7 +58,7 @@ fn init(allocator: Allocator, parent: Plane, name: [:0]const u8, dir: Direction,
|
|||
.parent = parent,
|
||||
.allocator = allocator,
|
||||
.widgets = ArrayList(WidgetState).init(allocator),
|
||||
.layout_ = layout_,
|
||||
.layout = layout_,
|
||||
.direction = dir,
|
||||
};
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ pub fn widget(self: *Self) Widget {
|
|||
}
|
||||
|
||||
pub fn layout(self: *Self) Widget.Layout {
|
||||
return self.layout_;
|
||||
return self.layout;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
|
@ -106,7 +106,7 @@ pub fn remove_all(self: *Self) void {
|
|||
}
|
||||
|
||||
pub fn pop(self: *Self) ?Widget {
|
||||
return if (self.widgets.pop()) |ws| ws.widget else null;
|
||||
return if (self.widgets.popOrNull()) |ws| ws.widget else null;
|
||||
}
|
||||
|
||||
pub fn empty(self: *const Self) bool {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,6 @@ const root = @import("root");
|
|||
|
||||
const Plane = @import("renderer").Plane;
|
||||
const style = @import("renderer").style;
|
||||
const styles = @import("renderer").styles;
|
||||
const input = @import("input");
|
||||
const command = @import("command");
|
||||
const EventHandler = @import("EventHandler");
|
||||
|
@ -34,7 +33,7 @@ highlight: bool,
|
|||
symbols: bool,
|
||||
width: usize = 4,
|
||||
editor: *ed.Editor,
|
||||
diff_: diff.AsyncDiffer,
|
||||
diff: diff.AsyncDiffer,
|
||||
diff_symbols: std.ArrayList(Symbol),
|
||||
|
||||
const Self = @This();
|
||||
|
@ -53,7 +52,7 @@ pub fn create(allocator: Allocator, parent: Widget, event_source: Widget, editor
|
|||
.highlight = tui.config().highlight_current_line_gutter,
|
||||
.symbols = tui.config().gutter_symbols,
|
||||
.editor = editor,
|
||||
.diff_ = try diff.create(),
|
||||
.diff = try diff.create(),
|
||||
.diff_symbols = std.ArrayList(Symbol).init(allocator),
|
||||
};
|
||||
try tui.message_filters().add(MessageFilter.bind(self, filter_receive));
|
||||
|
@ -183,10 +182,10 @@ pub fn render_linear(self: *Self, theme: *const Widget.Theme) void {
|
|||
if (linenum > self.lines) return;
|
||||
if (linenum == self.line + 1) {
|
||||
self.plane.set_style(.{ .fg = theme.editor_gutter_active.fg });
|
||||
self.plane.on_styles(styles.bold);
|
||||
self.plane.on_styles(style.bold);
|
||||
} else {
|
||||
self.plane.set_style(.{ .fg = theme.editor_gutter.fg });
|
||||
self.plane.off_styles(styles.bold);
|
||||
self.plane.off_styles(style.bold);
|
||||
}
|
||||
try self.plane.cursor_move_yx(@intCast(pos), 0);
|
||||
try self.print_digits(linenum, self.render_style);
|
||||
|
@ -341,7 +340,7 @@ fn diff_update(self: *Self) !void {
|
|||
const new = editor.get_current_root() orelse return;
|
||||
const old = if (editor.buffer) |buffer| buffer.last_save orelse return else return;
|
||||
const eol_mode = if (editor.buffer) |buffer| buffer.file_eol_mode else return;
|
||||
return self.diff_.diff(diff_result, new, old, eol_mode);
|
||||
return self.diff.diff(diff_result, new, old, eol_mode);
|
||||
}
|
||||
|
||||
fn diff_result(from: tp.pid_ref, edits: []diff.Diff) void {
|
||||
|
@ -439,7 +438,7 @@ fn int_width(n_: usize) usize {
|
|||
fn print_digits(self: *Self, n_: anytype, style_: DigitStyle) !void {
|
||||
var n = n_;
|
||||
var buf: [12][]const u8 = undefined;
|
||||
var digits: std.ArrayListUnmanaged([]const u8) = .initBuffer(&buf);
|
||||
var digits = std.ArrayListUnmanaged([]const u8).initBuffer(&buf);
|
||||
while (true) {
|
||||
digits.addOneAssumeCapacity().* = get_digit(n % 10, style_);
|
||||
n /= 10;
|
||||
|
|
|
@ -263,34 +263,33 @@ fn select_next(self: *Self, dir: enum { up, down }) void {
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn goto_prev_file(self: *Self, _: Ctx) Result {
|
||||
self.select_next(.up);
|
||||
self.menu.activate_selected();
|
||||
}
|
||||
pub const goto_prev_file_meta: Meta = .{ .description = "Navigate to previous file in the file list" };
|
||||
pub const goto_prev_file_meta = .{ .description = "Navigate to previous file in the file list" };
|
||||
|
||||
pub fn goto_next_file(self: *Self, _: Ctx) Result {
|
||||
self.select_next(.down);
|
||||
self.menu.activate_selected();
|
||||
}
|
||||
pub const goto_next_file_meta: Meta = .{ .description = "Navigate to next file in the file list" };
|
||||
pub const goto_next_file_meta = .{ .description = "Navigate to next file in the file list" };
|
||||
|
||||
pub fn select_prev_file(self: *Self, _: Ctx) Result {
|
||||
self.select_next(.up);
|
||||
}
|
||||
pub const select_prev_file_meta: Meta = .{ .description = "Select previous file in the file list" };
|
||||
pub const select_prev_file_meta = .{ .description = "Select previous file in the file list" };
|
||||
|
||||
pub fn select_next_file(self: *Self, _: Ctx) Result {
|
||||
self.select_next(.down);
|
||||
}
|
||||
pub const select_next_file_meta: Meta = .{ .description = "Select next file in the file list" };
|
||||
pub const select_next_file_meta = .{ .description = "Select next file in the file list" };
|
||||
|
||||
pub fn goto_selected_file(self: *Self, _: Ctx) Result {
|
||||
if (self.menu.selected == null) return tp.exit_error(error.NoSelectedFile, @errorReturnTrace());
|
||||
self.menu.activate_selected();
|
||||
}
|
||||
pub const goto_selected_file_meta: Meta = .{};
|
||||
pub const goto_selected_file_meta = .{};
|
||||
};
|
||||
|
|
|
@ -242,12 +242,6 @@ pub fn get_digit(n: anytype, style_: DigitStyle) []const u8 {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn get_digit_ascii(char: []const u8, style_: DigitStyle) []const u8 {
|
||||
if (char.len == 0) return " ";
|
||||
if (char[0] > '9' or char[0] < '0') return char;
|
||||
return get_digit(char[0] - '0', style_);
|
||||
}
|
||||
|
||||
const digits_ascii: [10][]const u8 = .{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
const digits_digtl: [10][]const u8 = .{ "🯰", "🯱", "🯲", "🯳", "🯴", "🯵", "🯶", "🯷", "🯸", "🯹" };
|
||||
const digits_subsc: [10][]const u8 = .{ "₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉" };
|
||||
|
|
|
@ -3,7 +3,6 @@ const build_options = @import("build_options");
|
|||
const tp = @import("thespian");
|
||||
const log = @import("log");
|
||||
const cbor = @import("cbor");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Plane = @import("renderer").Plane;
|
||||
const root = @import("root");
|
||||
|
@ -301,24 +300,8 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
const x = @min(self.plane.dim_x() -| 32, 8);
|
||||
self.position_menu(self.v_center(5, self.menu_len, 5), self.center(x, self.menu_w));
|
||||
}
|
||||
|
||||
self.plane.cursor_move_yx(
|
||||
@intCast(self.plane.dim_y() - 2),
|
||||
@intCast(@max(self.plane.dim_x(), root.version.len + 3) - root.version.len - 3),
|
||||
) catch {};
|
||||
self.plane.set_style_bg_transparent(style_subtext);
|
||||
_ = self.plane.print("{s}", .{root.version}) catch return false;
|
||||
if (builtin.mode == .Debug) {
|
||||
const debug_warning_text = "debug build";
|
||||
self.plane.cursor_move_yx(
|
||||
@intCast(self.plane.dim_y() - 3),
|
||||
@intCast(@max(self.plane.dim_x(), debug_warning_text.len + 3) - debug_warning_text.len - 3),
|
||||
) catch {};
|
||||
self.plane.set_style_bg_transparent(theme.editor_error);
|
||||
_ = self.plane.print("{s}", .{debug_warning_text}) catch return false;
|
||||
}
|
||||
|
||||
const more = self.menu.render(theme);
|
||||
|
||||
return more or self.fire != null;
|
||||
}
|
||||
|
||||
|
@ -359,29 +342,28 @@ const Commands = command.Collection(cmds);
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn save_all(_: *Self, _: Ctx) Result {
|
||||
if (tui.get_buffer_manager()) |bm|
|
||||
bm.save_all() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const save_all_meta: Meta = .{ .description = "Save all changed files" };
|
||||
pub const save_all_meta = .{ .description = "Save all changed files" };
|
||||
|
||||
pub fn home_menu_down(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_down();
|
||||
}
|
||||
pub const home_menu_down_meta: Meta = .{};
|
||||
pub const home_menu_down_meta = .{};
|
||||
|
||||
pub fn home_menu_up(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_up();
|
||||
}
|
||||
pub const home_menu_up_meta: Meta = .{};
|
||||
pub const home_menu_up_meta = .{};
|
||||
|
||||
pub fn home_menu_activate(self: *Self, _: Ctx) Result {
|
||||
self.menu.activate_selected();
|
||||
}
|
||||
pub const home_menu_activate_meta: Meta = .{};
|
||||
pub const home_menu_activate_meta = .{};
|
||||
|
||||
pub fn home_sheeran(self: *Self, _: Ctx) Result {
|
||||
self.fire = if (self.fire) |*fire| ret: {
|
||||
|
@ -389,7 +371,7 @@ const cmds = struct {
|
|||
break :ret null;
|
||||
} else try Fire.init(self.allocator, self.plane);
|
||||
}
|
||||
pub const home_sheeran_meta: Meta = .{};
|
||||
pub const home_sheeran_meta = .{};
|
||||
};
|
||||
|
||||
const Fire = @import("Fire.zig");
|
||||
|
|
|
@ -7,7 +7,6 @@ const syntax = @import("syntax");
|
|||
|
||||
const Plane = @import("renderer").Plane;
|
||||
const style = @import("renderer").style;
|
||||
const styles = @import("renderer").styles;
|
||||
const EventHandler = @import("EventHandler");
|
||||
|
||||
const tui = @import("tui.zig");
|
||||
|
@ -169,31 +168,31 @@ fn show_color(self: *Self, tag: []const u8, c_: ?Widget.Theme.Color) void {
|
|||
fn show_font(self: *Self, font: ?Widget.Theme.FontStyle) void {
|
||||
if (font) |fs| switch (fs) {
|
||||
.normal => {
|
||||
self.plane.set_styles(styles.normal);
|
||||
self.plane.set_styles(style.normal);
|
||||
_ = self.plane.print(" normal", .{}) catch return;
|
||||
},
|
||||
.bold => {
|
||||
self.plane.set_styles(styles.bold);
|
||||
self.plane.set_styles(style.bold);
|
||||
_ = self.plane.print(" bold", .{}) catch return;
|
||||
},
|
||||
.italic => {
|
||||
self.plane.set_styles(styles.italic);
|
||||
self.plane.set_styles(style.italic);
|
||||
_ = self.plane.print(" italic", .{}) catch return;
|
||||
},
|
||||
.underline => {
|
||||
self.plane.set_styles(styles.underline);
|
||||
self.plane.set_styles(style.underline);
|
||||
_ = self.plane.print(" underline", .{}) catch return;
|
||||
},
|
||||
.undercurl => {
|
||||
self.plane.set_styles(styles.undercurl);
|
||||
self.plane.set_styles(style.undercurl);
|
||||
_ = self.plane.print(" undercurl", .{}) catch return;
|
||||
},
|
||||
.strikethrough => {
|
||||
self.plane.set_styles(styles.struck);
|
||||
self.plane.set_styles(style.struck);
|
||||
_ = self.plane.print(" strikethrough", .{}) catch return;
|
||||
},
|
||||
};
|
||||
self.plane.set_styles(styles.normal);
|
||||
self.plane.set_styles(style.normal);
|
||||
}
|
||||
|
||||
fn reset_style(self: *Self) void {
|
||||
|
|
|
@ -48,7 +48,7 @@ views_widget: Widget,
|
|||
active_view: ?usize = 0,
|
||||
panels: ?*WidgetList = null,
|
||||
last_match_text: ?[]const u8 = null,
|
||||
location_history_: location_history,
|
||||
location_history: location_history,
|
||||
buffer_manager: Buffer.Manager,
|
||||
find_in_files_state: enum { init, adding, done } = .done,
|
||||
file_list_type: FileListType = .find_in_files,
|
||||
|
@ -60,9 +60,7 @@ const FileListType = enum {
|
|||
find_in_files,
|
||||
};
|
||||
|
||||
pub const CreateError = error{ OutOfMemory, ThespianSpawnFailed };
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator) CreateError!Widget {
|
||||
pub fn create(allocator: std.mem.Allocator) !Widget {
|
||||
const self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
|
@ -70,7 +68,7 @@ pub fn create(allocator: std.mem.Allocator) CreateError!Widget {
|
|||
.widgets = undefined,
|
||||
.widgets_widget = undefined,
|
||||
.floating_views = WidgetStack.init(allocator),
|
||||
.location_history_ = try location_history.create(),
|
||||
.location_history = try location_history.create(),
|
||||
.views = undefined,
|
||||
.views_widget = undefined,
|
||||
.buffer_manager = Buffer.Manager.init(allocator),
|
||||
|
@ -117,11 +115,6 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
var end_line: usize = undefined;
|
||||
var end_pos: usize = undefined;
|
||||
var lines: []const u8 = undefined;
|
||||
var same_file: bool = undefined;
|
||||
var goto_args: []const u8 = undefined;
|
||||
var line: i64 = undefined;
|
||||
var column: i64 = undefined;
|
||||
|
||||
if (try m.match(.{ "REF", tp.extract(&path), tp.extract(&begin_line), tp.extract(&begin_pos), tp.extract(&end_line), tp.extract(&end_pos), tp.extract(&lines) })) {
|
||||
try self.add_find_in_files_result(.references, path, begin_line, begin_pos, end_line, end_pos, lines, .Information);
|
||||
return true;
|
||||
|
@ -146,12 +139,6 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
.end = .{ .row = end_line, .col = end_pos },
|
||||
});
|
||||
return true;
|
||||
} else if (try m.match(.{ "navigate_complete", tp.extract(&same_file), tp.extract(&path), tp.extract(&goto_args), tp.extract(&line), tp.extract(&column) })) {
|
||||
cmds.navigate_complete(self, same_file, path, goto_args, line, column) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
return true;
|
||||
} else if (try m.match(.{ "navigate_complete", tp.extract(&same_file), tp.extract(&path), tp.extract(&goto_args), tp.null_, tp.null_ })) {
|
||||
cmds.navigate_complete(self, same_file, path, goto_args, null, null) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
return true;
|
||||
}
|
||||
return if (try self.floating_views.send(from_, m)) true else self.widgets.send(from_, m);
|
||||
}
|
||||
|
@ -193,7 +180,7 @@ fn bottom_bar_primary_drag(self: *Self, y: usize) tp.result {
|
|||
};
|
||||
const h = self.plane.dim_y();
|
||||
self.panel_height = @max(1, h - @min(h, y + 1));
|
||||
panels.layout_ = .{ .static = self.panel_height.? };
|
||||
panels.layout = .{ .static = self.panel_height.? };
|
||||
if (self.panel_height == 1) {
|
||||
self.panel_height = null;
|
||||
command.executeName("toggle_panel", .{}) catch {};
|
||||
|
@ -273,19 +260,19 @@ const cmds = struct {
|
|||
try self.check_all_not_dirty();
|
||||
try tp.self_pid().send("quit");
|
||||
}
|
||||
pub const quit_meta: Meta = .{ .description = "Quit" };
|
||||
pub const quit_meta = .{ .description = "Quit" };
|
||||
|
||||
pub fn quit_without_saving(_: *Self, _: Ctx) Result {
|
||||
try tp.self_pid().send("quit");
|
||||
}
|
||||
pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" };
|
||||
pub const quit_without_saving_meta = .{ .description = "Quit without saving" };
|
||||
|
||||
pub fn open_project_cwd(self: *Self, _: Ctx) Result {
|
||||
try project_manager.open(".");
|
||||
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
}
|
||||
pub const open_project_cwd_meta: Meta = .{};
|
||||
pub const open_project_cwd_meta = .{};
|
||||
|
||||
pub fn open_project_dir(self: *Self, ctx: Ctx) Result {
|
||||
var project_dir: []const u8 = undefined;
|
||||
|
@ -297,7 +284,7 @@ const cmds = struct {
|
|||
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||
}
|
||||
pub const open_project_dir_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const open_project_dir_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn close_project(_: *Self, ctx: Ctx) Result {
|
||||
var project_dir: []const u8 = undefined;
|
||||
|
@ -337,7 +324,7 @@ const cmds = struct {
|
|||
if (try project_manager.request_most_recent_file(self.allocator)) |file_path|
|
||||
self.show_file_async_and_free(file_path);
|
||||
}
|
||||
pub const change_project_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const change_project_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn navigate(self: *Self, ctx: Ctx) Result {
|
||||
tui.reset_drag_context();
|
||||
|
@ -384,42 +371,12 @@ const cmds = struct {
|
|||
const same_file = if (self.get_active_file_path()) |fp| std.mem.eql(u8, fp, f) else false;
|
||||
const have_editor_metadata = if (self.buffer_manager.get_buffer_for_file(f)) |_| true else false;
|
||||
|
||||
if (!same_file and !have_editor_metadata and line == null) {
|
||||
const ctx_: struct {
|
||||
allocator: std.mem.Allocator,
|
||||
from: tp.pid,
|
||||
same_file: bool,
|
||||
path: []const u8,
|
||||
goto_args: []const u8,
|
||||
|
||||
pub fn deinit(ctx_: *@This()) void {
|
||||
ctx_.from.deinit();
|
||||
ctx_.allocator.free(ctx_.path);
|
||||
ctx_.allocator.free(ctx_.goto_args);
|
||||
}
|
||||
pub fn receive(ctx_: @This(), rsp: tp.message) !void {
|
||||
var line_: ?i64 = null;
|
||||
var column_: ?i64 = null;
|
||||
_ = try cbor.match(rsp.buf, .{ tp.extract(&line_), tp.extract(&column_) });
|
||||
try ctx_.from.send(.{ "navigate_complete", ctx_.same_file, ctx_.path, ctx_.goto_args, line_, column_ });
|
||||
}
|
||||
} = .{
|
||||
.allocator = self.allocator,
|
||||
.from = tp.self_pid().clone(),
|
||||
.same_file = same_file,
|
||||
.path = try self.allocator.dupe(u8, f),
|
||||
.goto_args = try self.allocator.dupe(u8, goto_args),
|
||||
if (!same_file and !have_editor_metadata and line == null)
|
||||
if (try project_manager.get_mru_position(self.allocator, f)) |pos| {
|
||||
line = @intCast(pos.row);
|
||||
column = @intCast(pos.col);
|
||||
};
|
||||
|
||||
try project_manager.get_mru_position(self.allocator, f, ctx_);
|
||||
return;
|
||||
}
|
||||
|
||||
return cmds.navigate_complete(self, same_file, f, goto_args, line, column);
|
||||
}
|
||||
pub const navigate_meta: Meta = .{ .arguments = &.{.object} };
|
||||
|
||||
fn navigate_complete(self: *Self, same_file: bool, f: []const u8, goto_args: []const u8, line: ?i64, column: ?i64) Result {
|
||||
if (!same_file) {
|
||||
if (self.get_active_editor()) |editor| {
|
||||
editor.send_editor_jump_source() catch {};
|
||||
|
@ -438,6 +395,7 @@ const cmds = struct {
|
|||
}
|
||||
tui.need_render();
|
||||
}
|
||||
pub const navigate_meta = .{ .arguments = &.{.object} };
|
||||
|
||||
pub fn open_help(self: *Self, _: Ctx) Result {
|
||||
tui.reset_drag_context();
|
||||
|
@ -445,7 +403,7 @@ const cmds = struct {
|
|||
try command.executeName("open_scratch_buffer", command.fmt(.{ "help", @embedFile("help.md"), "markdown" }));
|
||||
tui.need_render();
|
||||
}
|
||||
pub const open_help_meta: Meta = .{ .description = "Open help" };
|
||||
pub const open_help_meta = .{ .description = "Open help" };
|
||||
|
||||
pub fn open_font_test_text(self: *Self, _: Ctx) Result {
|
||||
tui.reset_drag_context();
|
||||
|
@ -453,7 +411,7 @@ const cmds = struct {
|
|||
try command.executeName("open_scratch_buffer", command.fmt(.{ "font test", @import("fonts.zig").font_test_text, "text" }));
|
||||
tui.need_render();
|
||||
}
|
||||
pub const open_font_test_text_meta: Meta = .{ .description = "Open font glyph test text" };
|
||||
pub const open_font_test_text_meta = .{ .description = "Open font glyph test text" };
|
||||
|
||||
pub fn open_version_info(self: *Self, _: Ctx) Result {
|
||||
tui.reset_drag_context();
|
||||
|
@ -461,19 +419,19 @@ const cmds = struct {
|
|||
try command.executeName("open_scratch_buffer", command.fmt(.{ "version", root.version_info, "diff" }));
|
||||
tui.need_render();
|
||||
}
|
||||
pub const open_version_info_meta: Meta = .{ .description = "Version" };
|
||||
pub const open_version_info_meta = .{ .description = "Version" };
|
||||
|
||||
pub fn open_config(_: *Self, _: Ctx) Result {
|
||||
const file_name = try root.get_config_file_name(@import("config"));
|
||||
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name[0 .. file_name.len - 5] } });
|
||||
}
|
||||
pub const open_config_meta: Meta = .{ .description = "Edit configuration" };
|
||||
pub const open_config_meta = .{ .description = "Edit configuration" };
|
||||
|
||||
pub fn open_gui_config(_: *Self, _: Ctx) Result {
|
||||
const file_name = try root.get_config_file_name(@import("gui_config"));
|
||||
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name[0 .. file_name.len - ".json".len] } });
|
||||
}
|
||||
pub const open_gui_config_meta: Meta = .{ .description = "Edit gui configuration" };
|
||||
pub const open_gui_config_meta = .{ .description = "Edit gui configuration" };
|
||||
|
||||
pub fn open_tabs_style_config(self: *Self, _: Ctx) Result {
|
||||
try self.open_style_config(@import("status/tabs.zig").Style);
|
||||
|
@ -493,7 +451,7 @@ const cmds = struct {
|
|||
try command.executeName("open_scratch_buffer", .{ .args = args });
|
||||
tui.need_render();
|
||||
}
|
||||
pub const create_scratch_buffer_meta: Meta = .{ .arguments = &.{ .string, .string, .string } };
|
||||
pub const create_scratch_buffer_meta = .{ .arguments = &.{ .string, .string, .string } };
|
||||
|
||||
pub fn create_new_file(self: *Self, _: Ctx) Result {
|
||||
var n: usize = 1;
|
||||
|
@ -530,7 +488,7 @@ const cmds = struct {
|
|||
logger.print("deleted buffer {s}", .{file_path});
|
||||
tui.need_render();
|
||||
}
|
||||
pub const delete_buffer_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const delete_buffer_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn close_buffer(self: *Self, ctx: Ctx) Result {
|
||||
var file_path: []const u8 = undefined;
|
||||
|
@ -546,7 +504,7 @@ const cmds = struct {
|
|||
_ = self.buffer_manager.close_buffer(buffer);
|
||||
tui.need_render();
|
||||
}
|
||||
pub const close_buffer_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const close_buffer_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn restore_session(self: *Self, _: Ctx) Result {
|
||||
if (tp.env.get().str("project").len == 0) {
|
||||
|
@ -556,7 +514,7 @@ const cmds = struct {
|
|||
try self.read_restore_info();
|
||||
tui.need_render();
|
||||
}
|
||||
pub const restore_session_meta: Meta = .{};
|
||||
pub const restore_session_meta = .{};
|
||||
|
||||
pub fn toggle_panel(self: *Self, _: Ctx) Result {
|
||||
if (self.is_panel_view_showing(logview))
|
||||
|
@ -570,58 +528,52 @@ const cmds = struct {
|
|||
else
|
||||
try self.toggle_panel_view(logview, false);
|
||||
}
|
||||
pub const toggle_panel_meta: Meta = .{ .description = "Toggle panel" };
|
||||
pub const toggle_panel_meta = .{ .description = "Toggle panel" };
|
||||
|
||||
pub fn toggle_logview(self: *Self, _: Ctx) Result {
|
||||
try self.toggle_panel_view(logview, false);
|
||||
}
|
||||
pub const toggle_logview_meta: Meta = .{};
|
||||
pub const toggle_logview_meta = .{};
|
||||
|
||||
pub fn show_logview(self: *Self, _: Ctx) Result {
|
||||
try self.toggle_panel_view(logview, true);
|
||||
}
|
||||
pub const show_logview_meta: Meta = .{ .description = "View log" };
|
||||
pub const show_logview_meta = .{ .description = "View log" };
|
||||
|
||||
pub fn toggle_inputview(self: *Self, _: Ctx) Result {
|
||||
try self.toggle_panel_view(input_view, false);
|
||||
}
|
||||
pub const toggle_inputview_meta: Meta = .{ .description = "Toggle raw input log" };
|
||||
pub const toggle_inputview_meta = .{ .description = "Toggle raw input log" };
|
||||
|
||||
pub fn toggle_inspector_view(self: *Self, _: Ctx) Result {
|
||||
try self.toggle_panel_view(@import("inspector_view.zig"), false);
|
||||
}
|
||||
pub const toggle_inspector_view_meta: Meta = .{ .description = "Toggle inspector view" };
|
||||
pub const toggle_inspector_view_meta = .{ .description = "Toggle inspector view" };
|
||||
|
||||
pub fn show_inspector_view(self: *Self, _: Ctx) Result {
|
||||
try self.toggle_panel_view(@import("inspector_view.zig"), true);
|
||||
}
|
||||
pub const show_inspector_view_meta: Meta = .{};
|
||||
|
||||
pub fn close_find_in_files_results(self: *Self, _: Ctx) Result {
|
||||
if (self.file_list_type == .find_in_files and self.is_panel_view_showing(filelist_view))
|
||||
try self.toggle_panel_view(filelist_view, false);
|
||||
}
|
||||
pub const close_find_in_files_results_meta: Meta = .{ .description = "Close find in files results view" };
|
||||
pub const show_inspector_view_meta = .{};
|
||||
|
||||
pub fn jump_back(self: *Self, _: Ctx) Result {
|
||||
try self.location_history_.back(location_jump);
|
||||
try self.location_history.back(location_jump);
|
||||
}
|
||||
pub const jump_back_meta: Meta = .{ .description = "Navigate back to previous history location" };
|
||||
pub const jump_back_meta = .{ .description = "Navigate back to previous history location" };
|
||||
|
||||
pub fn jump_forward(self: *Self, _: Ctx) Result {
|
||||
try self.location_history_.forward(location_jump);
|
||||
try self.location_history.forward(location_jump);
|
||||
}
|
||||
pub const jump_forward_meta: Meta = .{ .description = "Navigate forward to next history location" };
|
||||
pub const jump_forward_meta = .{ .description = "Navigate forward to next history location" };
|
||||
|
||||
pub fn show_home(self: *Self, _: Ctx) Result {
|
||||
return self.create_home();
|
||||
}
|
||||
pub const show_home_meta: Meta = .{};
|
||||
pub const show_home_meta = .{};
|
||||
|
||||
pub fn add_split(self: *Self, _: Ctx) Result {
|
||||
return self.create_home_split();
|
||||
}
|
||||
pub const add_split_meta: Meta = .{};
|
||||
pub const add_split_meta = .{};
|
||||
|
||||
pub fn gutter_mode_next(self: *Self, _: Ctx) Result {
|
||||
const config = tui.config_mut();
|
||||
|
@ -638,7 +590,7 @@ const cmds = struct {
|
|||
gutter.mode = mode;
|
||||
}
|
||||
}
|
||||
pub const gutter_mode_next_meta: Meta = .{ .description = "Next gutter mode" };
|
||||
pub const gutter_mode_next_meta = .{ .description = "Next gutter mode" };
|
||||
|
||||
pub fn gutter_style_next(self: *Self, _: Ctx) Result {
|
||||
const config = tui.config_mut();
|
||||
|
@ -673,7 +625,7 @@ const cmds = struct {
|
|||
try command.executeName("goto_next_diagnostic", ctx);
|
||||
}
|
||||
}
|
||||
pub const goto_next_file_or_diagnostic_meta: Meta = .{ .description = "Navigate to next file or diagnostic location" };
|
||||
pub const goto_next_file_or_diagnostic_meta = .{ .description = "Navigate to next file or diagnostic location" };
|
||||
|
||||
pub fn goto_prev_file_or_diagnostic(self: *Self, ctx: Ctx) Result {
|
||||
if (self.is_panel_view_showing(filelist_view)) {
|
||||
|
@ -685,7 +637,7 @@ const cmds = struct {
|
|||
try command.executeName("goto_prev_diagnostic", ctx);
|
||||
}
|
||||
}
|
||||
pub const goto_prev_file_or_diagnostic_meta: Meta = .{ .description = "Navigate to previous file or diagnostic location" };
|
||||
pub const goto_prev_file_or_diagnostic_meta = .{ .description = "Navigate to previous file or diagnostic location" };
|
||||
|
||||
pub fn add_diagnostic(self: *Self, ctx: Ctx) Result {
|
||||
var file_path: []const u8 = undefined;
|
||||
|
@ -720,7 +672,7 @@ const cmds = struct {
|
|||
ed.Diagnostic.to_severity(severity),
|
||||
);
|
||||
}
|
||||
pub const add_diagnostic_meta: Meta = .{ .arguments = &.{ .string, .string, .string, .string, .integer, .integer, .integer, .integer, .integer } };
|
||||
pub const add_diagnostic_meta = .{ .arguments = &.{ .string, .string, .string, .string, .integer, .integer, .integer, .integer, .integer } };
|
||||
|
||||
pub fn rename_symbol_item(self: *Self, ctx: Ctx) Result {
|
||||
const editor = self.get_active_editor() orelse return;
|
||||
|
@ -764,8 +716,8 @@ const cmds = struct {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub const rename_symbol_item_meta: Meta = .{ .arguments = &.{.array} };
|
||||
pub const rename_symbol_item_elem_meta: Meta = .{ .arguments = &.{ .string, .integer, .integer, .integer, .integer, .string } };
|
||||
pub const rename_symbol_item_meta = .{ .arguments = &.{.array} };
|
||||
pub const rename_symbol_item_elem_meta = .{ .arguments = &.{ .string, .integer, .integer, .integer, .integer, .string } };
|
||||
|
||||
pub fn clear_diagnostics(self: *Self, ctx: Ctx) Result {
|
||||
var file_path: []const u8 = undefined;
|
||||
|
@ -778,7 +730,7 @@ const cmds = struct {
|
|||
if (self.file_list_type == .diagnostics and self.is_panel_view_showing(filelist_view))
|
||||
try self.toggle_panel_view(filelist_view, false);
|
||||
}
|
||||
pub const clear_diagnostics_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const clear_diagnostics_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn show_diagnostics(self: *Self, _: Ctx) Result {
|
||||
const editor = self.get_active_editor() orelse return;
|
||||
|
@ -796,12 +748,12 @@ const cmds = struct {
|
|||
);
|
||||
}
|
||||
}
|
||||
pub const show_diagnostics_meta: Meta = .{ .description = "Show diagnostics panel" };
|
||||
pub const show_diagnostics_meta = .{ .description = "Show diagnostics panel" };
|
||||
|
||||
pub fn open_previous_file(self: *Self, _: Ctx) Result {
|
||||
self.show_file_async(self.get_next_mru_buffer() orelse return error.Stop);
|
||||
}
|
||||
pub const open_previous_file_meta: Meta = .{ .description = "Open the previous file" };
|
||||
pub const open_previous_file_meta = .{ .description = "Open the previous file" };
|
||||
|
||||
pub fn system_paste(self: *Self, _: Ctx) Result {
|
||||
if (builtin.os.tag == .windows) {
|
||||
|
@ -811,7 +763,7 @@ const cmds = struct {
|
|||
}
|
||||
tui.rdr().request_system_clipboard();
|
||||
}
|
||||
pub const system_paste_meta: Meta = .{ .description = "Paste from system clipboard" };
|
||||
pub const system_paste_meta = .{ .description = "Paste from system clipboard" };
|
||||
|
||||
pub fn find_in_files_query(self: *Self, ctx: Ctx) Result {
|
||||
var query: []const u8 = undefined;
|
||||
|
@ -825,7 +777,7 @@ const cmds = struct {
|
|||
defer rg.deinit();
|
||||
self.find_in_files_state = .init;
|
||||
}
|
||||
pub const find_in_files_query_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const find_in_files_query_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn shell_execute_log(self: *Self, ctx: Ctx) Result {
|
||||
if (!try ctx.args.match(.{ tp.string, tp.more }))
|
||||
|
@ -837,7 +789,7 @@ const cmds = struct {
|
|||
.exit = shell.log_exit_err_handler,
|
||||
});
|
||||
}
|
||||
pub const shell_execute_log_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const shell_execute_log_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn shell_execute_insert(self: *Self, ctx: Ctx) Result {
|
||||
if (!try ctx.args.match(.{ tp.string, tp.more }))
|
||||
|
@ -863,7 +815,7 @@ const cmds = struct {
|
|||
};
|
||||
try shell.execute(self.allocator, cmd, .{ .out = handlers.out });
|
||||
}
|
||||
pub const shell_execute_insert_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const shell_execute_insert_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn shell_execute_stream(self: *Self, ctx: Ctx) Result {
|
||||
if (!try ctx.args.match(.{ tp.string, tp.more }))
|
||||
|
@ -891,7 +843,7 @@ const cmds = struct {
|
|||
const buffer_ref = self.buffer_manager.buffer_to_ref(buffer);
|
||||
try shell.execute(self.allocator, cmd, .{ .context = buffer_ref, .out = handlers.out, .err = handlers.out, .exit = handlers.exit });
|
||||
}
|
||||
pub const shell_execute_stream_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const shell_execute_stream_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn shell_execute_stream_output(self: *Self, ctx: Ctx) Result {
|
||||
var buffer_ref: usize = 0;
|
||||
|
@ -913,7 +865,7 @@ const cmds = struct {
|
|||
buffer.update(root_);
|
||||
tui.need_render();
|
||||
}
|
||||
pub const shell_execute_stream_output_meta: Meta = .{ .arguments = &.{ .integer, .string } };
|
||||
pub const shell_execute_stream_output_meta = .{ .arguments = &.{ .integer, .string } };
|
||||
|
||||
pub fn shell_execute_stream_output_complete(self: *Self, ctx: Ctx) Result {
|
||||
var buffer_ref: usize = 0;
|
||||
|
@ -927,7 +879,7 @@ const cmds = struct {
|
|||
buffer.mark_clean();
|
||||
tui.need_render();
|
||||
}
|
||||
pub const shell_execute_stream_output_complete_meta: Meta = .{ .arguments = &.{ .integer, .string } };
|
||||
pub const shell_execute_stream_output_complete_meta = .{ .arguments = &.{ .integer, .string } };
|
||||
|
||||
pub fn adjust_fontsize(_: *Self, ctx: Ctx) Result {
|
||||
var amount: f32 = undefined;
|
||||
|
@ -936,7 +888,7 @@ const cmds = struct {
|
|||
if (build_options.gui)
|
||||
tui.rdr().adjust_fontsize(amount);
|
||||
}
|
||||
pub const adjust_fontsize_meta: Meta = .{ .arguments = &.{.float} };
|
||||
pub const adjust_fontsize_meta = .{ .arguments = &.{.float} };
|
||||
|
||||
pub fn set_fontsize(_: *Self, ctx: Ctx) Result {
|
||||
var fontsize: f32 = undefined;
|
||||
|
@ -945,13 +897,13 @@ const cmds = struct {
|
|||
if (build_options.gui)
|
||||
tui.rdr().set_fontsize(fontsize);
|
||||
}
|
||||
pub const set_fontsize_meta: Meta = .{ .arguments = &.{.float} };
|
||||
pub const set_fontsize_meta = .{ .arguments = &.{.float} };
|
||||
|
||||
pub fn reset_fontsize(_: *Self, _: Ctx) Result {
|
||||
if (build_options.gui)
|
||||
tui.rdr().reset_fontsize();
|
||||
}
|
||||
pub const reset_fontsize_meta: Meta = .{ .description = "Reset font to configured size" };
|
||||
pub const reset_fontsize_meta = .{ .description = "Reset font to configured size" };
|
||||
|
||||
pub fn set_fontface(_: *Self, ctx: Ctx) Result {
|
||||
var fontface: []const u8 = undefined;
|
||||
|
@ -960,23 +912,23 @@ const cmds = struct {
|
|||
if (build_options.gui)
|
||||
tui.rdr().set_fontface(fontface);
|
||||
}
|
||||
pub const set_fontface_meta: Meta = .{ .arguments = &.{.float} };
|
||||
pub const set_fontface_meta = .{ .arguments = &.{.float} };
|
||||
|
||||
pub fn reset_fontface(_: *Self, _: Ctx) Result {
|
||||
if (build_options.gui)
|
||||
tui.rdr().reset_fontface();
|
||||
}
|
||||
pub const reset_fontface_meta: Meta = .{ .description = "Reset font to configured face" };
|
||||
pub const reset_fontface_meta = .{ .description = "Reset font to configured face" };
|
||||
|
||||
pub fn next_tab(self: *Self, _: Ctx) Result {
|
||||
_ = try self.widgets_widget.msg(.{"next_tab"});
|
||||
}
|
||||
pub const next_tab_meta: Meta = .{ .description = "Switch to next tab" };
|
||||
pub const next_tab_meta = .{ .description = "Switch to next tab" };
|
||||
|
||||
pub fn previous_tab(self: *Self, _: Ctx) Result {
|
||||
_ = try self.widgets_widget.msg(.{"previous_tab"});
|
||||
}
|
||||
pub const previous_tab_meta: Meta = .{ .description = "Switch to previous tab" };
|
||||
pub const previous_tab_meta = .{ .description = "Switch to previous tab" };
|
||||
};
|
||||
|
||||
pub fn handle_editor_event(self: *Self, _: tp.pid_ref, m: tp.message) tp.result {
|
||||
|
@ -1022,13 +974,13 @@ pub fn location_update(self: *Self, m: tp.message) tp.result {
|
|||
if (try m.match(.{ tp.any, tp.any, tp.any, tp.extract(&row), tp.extract(&col) })) {
|
||||
if (row == 0 and col == 0) return;
|
||||
project_manager.update_mru(file_path, row, col, ephemeral) catch {};
|
||||
return self.location_history_.update(file_path, .{ .row = row + 1, .col = col + 1 }, null);
|
||||
return self.location_history.update(file_path, .{ .row = row + 1, .col = col + 1 }, null);
|
||||
}
|
||||
|
||||
var sel: location_history.Selection = .{};
|
||||
if (try m.match(.{ tp.any, tp.any, tp.any, tp.extract(&row), tp.extract(&col), tp.extract(&sel.begin.row), tp.extract(&sel.begin.col), tp.extract(&sel.end.row), tp.extract(&sel.end.col) })) {
|
||||
project_manager.update_mru(file_path, row, col, ephemeral) catch {};
|
||||
return self.location_history_.update(file_path, .{ .row = row + 1, .col = col + 1 }, sel);
|
||||
return self.location_history.update(file_path, .{ .row = row + 1, .col = col + 1 }, sel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
const std = @import("std");
|
||||
const log = @import("log");
|
||||
const tp = @import("thespian");
|
||||
const location_history = @import("location_history");
|
||||
const command = @import("command");
|
||||
const cmd = command.executeName;
|
||||
|
||||
const tui = @import("../tui.zig");
|
||||
const Editor = @import("../editor.zig").Editor;
|
||||
const CurSel = @import("../editor.zig").CurSel;
|
||||
const Buffer = @import("Buffer");
|
||||
const Cursor = Buffer.Cursor;
|
||||
const Selection = Buffer.Selection;
|
||||
|
||||
var commands: Commands = undefined;
|
||||
|
||||
|
@ -27,39 +21,38 @@ const Commands = command.Collection(cmds_);
|
|||
const cmds_ = struct {
|
||||
pub const Target = void;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn w(_: *void, _: Ctx) Result {
|
||||
try cmd("save_file", .{});
|
||||
}
|
||||
pub const w_meta: Meta = .{ .description = "w (write/save file)" };
|
||||
pub const w_meta = .{ .description = "w (write/save file)" };
|
||||
|
||||
pub fn q(_: *void, _: Ctx) Result {
|
||||
try cmd("quit", .{});
|
||||
}
|
||||
pub const q_meta: Meta = .{ .description = "q (quit)" };
|
||||
pub const q_meta = .{ .description = "q (quit)" };
|
||||
|
||||
pub fn @"q!"(_: *void, _: Ctx) Result {
|
||||
try cmd("quit_without_saving", .{});
|
||||
}
|
||||
pub const @"q!_meta": Meta = .{ .description = "q! (quit without saving)" };
|
||||
pub const @"q!_meta" = .{ .description = "q! (quit without saving)" };
|
||||
|
||||
pub fn wq(_: *void, _: Ctx) Result {
|
||||
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
|
||||
}
|
||||
pub const wq_meta: Meta = .{ .description = "wq (write/save file and quit)" };
|
||||
pub const wq_meta = .{ .description = "wq (write/save file and quit)" };
|
||||
|
||||
pub fn o(_: *void, _: Ctx) Result {
|
||||
try cmd("open_file", .{});
|
||||
}
|
||||
pub const o_meta: Meta = .{ .description = "o (open file)" };
|
||||
pub const o_meta = .{ .description = "o (open file)" };
|
||||
|
||||
pub fn @"wq!"(_: *void, _: Ctx) Result {
|
||||
cmd("save_file", .{}) catch {};
|
||||
try cmd("quit_without_saving", .{});
|
||||
}
|
||||
pub const @"wq!_meta": Meta = .{ .description = "wq! (write/save file and quit without saving)" };
|
||||
pub const @"wq!_meta" = .{ .description = "wq! (write/save file and quit without saving)" };
|
||||
|
||||
pub fn save_selection(_: *void, _: Ctx) Result {
|
||||
const logger = log.logger("helix-mode");
|
||||
|
@ -72,279 +65,10 @@ const cmds_ = struct {
|
|||
.begin = .{ .row = sel.begin.row, .col = sel.begin.col },
|
||||
.end = .{ .row = sel.end.row, .col = sel.end.col },
|
||||
} else null;
|
||||
mv.location_history_.update(file_path, .{
|
||||
mv.location_history.update(file_path, .{
|
||||
.row = primary.cursor.row + 1,
|
||||
.col = primary.cursor.col + 1,
|
||||
}, sel);
|
||||
}
|
||||
pub const save_selection_meta: Meta = .{ .description = "Save current selection to location history" };
|
||||
|
||||
pub fn extend_line_below(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
var repeat: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
|
||||
while (repeat > 0) : (repeat -= 1) {
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
const sel = cursel.enable_selection_normal();
|
||||
sel.normalize();
|
||||
|
||||
try Editor.move_cursor_begin(root, &sel.begin, ed.metrics);
|
||||
try Editor.move_cursor_end(root, &sel.end, ed.metrics);
|
||||
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
|
||||
cursel.cursor = sel.end;
|
||||
};
|
||||
}
|
||||
|
||||
ed.clamp();
|
||||
}
|
||||
pub const extend_line_below_meta: Meta = .{ .arguments = &.{.integer}, .description = "Select current line, if already selected, extend to next line" };
|
||||
|
||||
pub fn move_next_word_start(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
cursel.selection = null;
|
||||
};
|
||||
|
||||
ed.with_selections_const_repeat(root, Editor.move_cursor_word_right_vim, ctx) catch {};
|
||||
ed.clamp();
|
||||
}
|
||||
pub const move_next_word_start_meta: Meta = .{ .description = "Move next word start", .arguments = &.{.integer} };
|
||||
|
||||
pub fn move_prev_word_start(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
cursel.selection = null;
|
||||
};
|
||||
|
||||
ed.with_selections_const_repeat(root, move_cursor_word_left_helix, ctx) catch {};
|
||||
ed.clamp();
|
||||
}
|
||||
pub const move_prev_word_start_meta: Meta = .{ .description = "Move previous word start", .arguments = &.{.integer} };
|
||||
|
||||
pub fn move_next_word_end(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
cursel.selection = null;
|
||||
};
|
||||
|
||||
ed.with_selections_const_repeat(root, move_cursor_word_right_end_helix, ctx) catch {};
|
||||
ed.clamp();
|
||||
}
|
||||
pub const move_next_word_end_meta: Meta = .{ .description = "Move next word end", .arguments = &.{.integer} };
|
||||
|
||||
pub fn cut_forward_internal_inclusive(_: *void, _: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const b = try ed.buf_for_update();
|
||||
const text, const root = try ed.cut_to(move_noop, b.root);
|
||||
ed.set_clipboard_internal(text);
|
||||
try ed.update_buf(root);
|
||||
ed.clamp();
|
||||
}
|
||||
pub const cut_forward_internal_inclusive_meta: Meta = .{ .description = "Cut next character to internal clipboard (inclusive)" };
|
||||
|
||||
pub fn select_right_helix(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
var repeat: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
|
||||
while (repeat > 0) : (repeat -= 1) {
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
const sel = try cursel.enable_selection(root, ed.metrics);
|
||||
|
||||
// handling left to right transition
|
||||
const sel_begin: i32 = @intCast(sel.begin.col);
|
||||
const sel_end: i32 = @intCast(sel.end.col);
|
||||
if ((sel_begin - sel_end) == 1 and sel.begin.row == sel.end.row) {
|
||||
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
|
||||
sel.begin.col -= 1;
|
||||
}
|
||||
|
||||
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
|
||||
cursel.cursor = sel.end;
|
||||
cursel.check_selection(root, ed.metrics);
|
||||
};
|
||||
}
|
||||
ed.clamp();
|
||||
}
|
||||
pub const select_right_helix_meta: Meta = .{ .description = "Select right", .arguments = &.{.integer} };
|
||||
|
||||
pub fn select_left_helix(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
var repeat: usize = 1;
|
||||
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
|
||||
while (repeat > 0) : (repeat -= 1) {
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
if (cursel.selection == null) {
|
||||
cursel.selection = Selection.from_cursor(&cursel.cursor);
|
||||
try cursel.selection.?.begin.move_right(root, ed.metrics);
|
||||
}
|
||||
if (cursel.selection) |*sel| {
|
||||
try Editor.move_cursor_left(root, &sel.end, ed.metrics);
|
||||
cursel.cursor = sel.end;
|
||||
|
||||
if (sel.begin.col == sel.end.col and sel.begin.row == sel.end.row) {
|
||||
try sel.begin.move_right(root, ed.metrics);
|
||||
try Editor.move_cursor_left(root, &sel.end, ed.metrics);
|
||||
cursel.cursor = sel.end;
|
||||
}
|
||||
}
|
||||
|
||||
cursel.check_selection(root, ed.metrics);
|
||||
};
|
||||
}
|
||||
ed.clamp();
|
||||
}
|
||||
pub const select_left_helix_meta: Meta = .{ .description = "Select left", .arguments = &.{.integer} };
|
||||
|
||||
pub fn select_to_char_right_helix(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = try ed.buf_root();
|
||||
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
const sel = try cursel.enable_selection(root, ed.metrics);
|
||||
try Editor.move_cursor_to_char_right(root, &sel.end, ctx, ed.metrics);
|
||||
try Editor.move_cursor_right(root, &sel.end, ed.metrics);
|
||||
cursel.cursor = sel.end;
|
||||
cursel.check_selection(root, ed.metrics);
|
||||
};
|
||||
ed.clamp();
|
||||
}
|
||||
pub const select_to_char_right_helix_meta: Meta = .{ .description = "Move to char right" };
|
||||
|
||||
pub fn copy_helix(_: *void, _: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
const root = ed.buf_root() catch return;
|
||||
var first = true;
|
||||
var text = std.ArrayList(u8).init(ed.allocator);
|
||||
|
||||
if (ed.get_primary().selection) |sel| if (sel.begin.col == 0 and sel.end.row > sel.begin.row) try text.appendSlice("\n");
|
||||
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
if (cursel.selection) |sel| {
|
||||
const copy_text = try Editor.copy_selection(root, sel, ed.allocator, ed.metrics);
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
try text.appendSlice("\n");
|
||||
}
|
||||
try text.appendSlice(copy_text);
|
||||
}
|
||||
};
|
||||
if (text.items.len > 0) {
|
||||
if (text.items.len > 100) {
|
||||
ed.logger.print("copy:{s}...", .{std.fmt.fmtSliceEscapeLower(text.items[0..100])});
|
||||
} else {
|
||||
ed.logger.print("copy:{s}", .{std.fmt.fmtSliceEscapeLower(text.items)});
|
||||
}
|
||||
ed.set_clipboard_internal(text.items);
|
||||
}
|
||||
}
|
||||
pub const copy_helix_meta: Meta = .{ .description = "Copy selection to clipboard (helix)" };
|
||||
|
||||
pub fn paste_after(_: *void, ctx: Ctx) Result {
|
||||
const mv = tui.mainview() orelse return;
|
||||
const ed = mv.get_active_editor() orelse return;
|
||||
|
||||
var text: []const u8 = undefined;
|
||||
if (!(ctx.args.buf.len > 0 and try ctx.args.match(.{tp.extract(&text)}))) {
|
||||
if (ed.clipboard) |text_| text = text_ else return;
|
||||
}
|
||||
|
||||
ed.logger.print("paste: {d} bytes", .{text.len});
|
||||
const b = try ed.buf_for_update();
|
||||
var root = b.root;
|
||||
|
||||
if (std.mem.eql(u8, text[text.len - 1 ..], "\n")) text = text[0 .. text.len - 1];
|
||||
|
||||
if (std.mem.indexOfScalar(u8, text, '\n') != null and text[0] == '\n') {
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
root = try insert_line(ed, root, cursel, text, b.allocator);
|
||||
};
|
||||
} else {
|
||||
for (ed.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||
root = try insert(ed, root, cursel, text, b.allocator);
|
||||
};
|
||||
}
|
||||
|
||||
try ed.update_buf(root);
|
||||
ed.clamp();
|
||||
ed.need_render();
|
||||
}
|
||||
pub const paste_after_meta: Meta = .{ .description = "Paste from clipboard after selection" };
|
||||
pub const save_selection_meta = .{ .description = "Save current selection to location history" };
|
||||
};
|
||||
|
||||
fn move_cursor_word_left_helix(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
|
||||
try Editor.move_cursor_left(root, cursor, metrics);
|
||||
|
||||
// Consume " "
|
||||
while (Editor.is_whitespace_at_cursor(root, cursor, metrics)) {
|
||||
try Editor.move_cursor_left(root, cursor, metrics);
|
||||
}
|
||||
|
||||
var next = cursor.*;
|
||||
next.move_left(root, metrics) catch return;
|
||||
var next_next = next;
|
||||
next_next.move_left(root, metrics) catch return;
|
||||
|
||||
const cur = next.test_at(root, Editor.is_not_word_char, metrics);
|
||||
const nxt = next_next.test_at(root, Editor.is_not_word_char, metrics);
|
||||
if (cur != nxt) {
|
||||
try Editor.move_cursor_left(root, cursor, metrics);
|
||||
return;
|
||||
} else {
|
||||
try move_cursor_word_left_helix(root, cursor, metrics);
|
||||
}
|
||||
}
|
||||
|
||||
fn move_noop(_: Buffer.Root, _: *Cursor, _: Buffer.Metrics) error{Stop}!void {}
|
||||
|
||||
fn move_cursor_word_right_end_helix(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
|
||||
try Editor.move_cursor_right(root, cursor, metrics);
|
||||
Editor.move_cursor_right_until(root, cursor, Editor.is_word_boundary_right_vim, metrics);
|
||||
try cursor.move_right(root, metrics);
|
||||
}
|
||||
|
||||
fn insert(ed: *Editor, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: std.mem.Allocator) !Buffer.Root {
|
||||
var root_ = root;
|
||||
const cursor = &cursel.cursor;
|
||||
if (cursel.selection == null) try cursor.move_right(root_, ed.metrics);
|
||||
const begin = cursel.cursor;
|
||||
cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, allocator, ed.metrics);
|
||||
cursor.target = cursor.col;
|
||||
ed.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, s.len);
|
||||
cursel.selection = Selection{ .begin = begin, .end = cursor.* };
|
||||
return root_;
|
||||
}
|
||||
|
||||
fn insert_line(ed: *Editor, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: std.mem.Allocator) !Buffer.Root {
|
||||
var root_ = root;
|
||||
const cursor = &cursel.cursor;
|
||||
cursel.disable_selection(root, ed.metrics);
|
||||
cursel.cursor.move_end(root, ed.metrics);
|
||||
var begin = cursel.cursor;
|
||||
try begin.move_right(root, ed.metrics);
|
||||
cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, allocator, ed.metrics);
|
||||
cursor.target = cursor.col;
|
||||
cursel.selection = Selection{ .begin = begin, .end = cursor.* };
|
||||
return root_;
|
||||
}
|
||||
|
|
|
@ -67,19 +67,18 @@ pub fn Create(options: type) type {
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn mini_mode_reset(self: *Self, _: Ctx) Result {
|
||||
self.input.clearRetainingCapacity();
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_reset_meta: Meta = .{ .description = "Clear input" };
|
||||
pub const mini_mode_reset_meta = .{ .description = "Clear input" };
|
||||
|
||||
pub fn mini_mode_cancel(_: *Self, _: Ctx) Result {
|
||||
command.executeName("exit_mini_mode", .{}) catch {};
|
||||
}
|
||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||
pub const mini_mode_cancel_meta = .{ .description = "Cancel input" };
|
||||
|
||||
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
if (self.input.items.len > 0) {
|
||||
|
@ -87,7 +86,7 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const mini_mode_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var egc: u32 = 0;
|
||||
|
@ -98,7 +97,7 @@ pub fn Create(options: type) type {
|
|||
try self.input.appendSlice(buf[0..bytes]);
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const mini_mode_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn mini_mode_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -107,18 +106,18 @@ pub fn Create(options: type) type {
|
|||
try self.input.appendSlice(bytes);
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn mini_mode_select(self: *Self, _: Ctx) Result {
|
||||
options.select(self);
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_select_meta: Meta = .{ .description = "Select" };
|
||||
pub const mini_mode_select_meta = .{ .description = "Select" };
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return mini_mode_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_paste_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -250,7 +250,6 @@ pub fn Create(options: type) type {
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn mini_mode_reset(self: *Self, _: Ctx) Result {
|
||||
|
@ -258,18 +257,18 @@ pub fn Create(options: type) type {
|
|||
self.file_path.clearRetainingCapacity();
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_reset_meta: Meta = .{ .description = "Clear input" };
|
||||
pub const mini_mode_reset_meta = .{ .description = "Clear input" };
|
||||
|
||||
pub fn mini_mode_cancel(_: *Self, _: Ctx) Result {
|
||||
command.executeName("exit_mini_mode", .{}) catch {};
|
||||
}
|
||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||
pub const mini_mode_cancel_meta = .{ .description = "Cancel input" };
|
||||
|
||||
pub fn mini_mode_delete_to_previous_path_segment(self: *Self, _: Ctx) Result {
|
||||
self.delete_to_previous_path_segment();
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_delete_to_previous_path_segment_meta: Meta = .{ .description = "Delete to previous path segment" };
|
||||
pub const mini_mode_delete_to_previous_path_segment_meta = .{ .description = "Delete to previous path segment" };
|
||||
|
||||
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
if (self.file_path.items.len > 0) {
|
||||
|
@ -278,25 +277,25 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const mini_mode_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn mini_mode_try_complete_file(self: *Self, _: Ctx) Result {
|
||||
self.try_complete_file() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_try_complete_file_meta: Meta = .{ .description = "Complete file" };
|
||||
pub const mini_mode_try_complete_file_meta = .{ .description = "Complete file" };
|
||||
|
||||
pub fn mini_mode_try_complete_file_forward(self: *Self, ctx: Ctx) Result {
|
||||
self.complete_trigger_count = 0;
|
||||
return mini_mode_try_complete_file(self, ctx);
|
||||
}
|
||||
pub const mini_mode_try_complete_file_forward_meta: Meta = .{ .description = "Complete file forward" };
|
||||
pub const mini_mode_try_complete_file_forward_meta = .{ .description = "Complete file forward" };
|
||||
|
||||
pub fn mini_mode_reverse_complete_file(self: *Self, _: Ctx) Result {
|
||||
self.reverse_complete_file() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_reverse_complete_file_meta: Meta = .{ .description = "Reverse complete file" };
|
||||
pub const mini_mode_reverse_complete_file_meta = .{ .description = "Reverse complete file" };
|
||||
|
||||
pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var egc: u32 = 0;
|
||||
|
@ -308,7 +307,7 @@ pub fn Create(options: type) type {
|
|||
try self.file_path.appendSlice(buf[0..bytes]);
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const mini_mode_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn mini_mode_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -318,18 +317,18 @@ pub fn Create(options: type) type {
|
|||
try self.file_path.appendSlice(bytes);
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn mini_mode_select(self: *Self, _: Ctx) Result {
|
||||
options.select(self);
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_select_meta: Meta = .{ .description = "Select" };
|
||||
pub const mini_mode_select_meta = .{ .description = "Select" };
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return mini_mode_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_paste_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ const name = " find";
|
|||
const Commands = command.Collection(cmds);
|
||||
|
||||
allocator: Allocator,
|
||||
input_: ArrayList(u8),
|
||||
input: ArrayList(u8),
|
||||
last_input: ArrayList(u8),
|
||||
start_view: ed.View,
|
||||
start_cursor: ed.Cursor,
|
||||
|
@ -31,7 +31,7 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.
|
|||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.input_ = ArrayList(u8).init(allocator),
|
||||
.input = ArrayList(u8).init(allocator),
|
||||
.last_input = ArrayList(u8).init(allocator),
|
||||
.start_view = editor.view,
|
||||
.start_cursor = editor.get_primary().cursor,
|
||||
|
@ -41,7 +41,7 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.
|
|||
if (editor.get_primary().selection) |sel| ret: {
|
||||
const text = editor.get_selection(sel, self.allocator) catch break :ret;
|
||||
defer self.allocator.free(text);
|
||||
try self.input_.appendSlice(text);
|
||||
try self.input.appendSlice(text);
|
||||
}
|
||||
var mode = try keybind.mode("mini/find", allocator, .{
|
||||
.insert_command = "mini_mode_insert_bytes",
|
||||
|
@ -52,7 +52,7 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.
|
|||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.commands.deinit();
|
||||
self.input_.deinit();
|
||||
self.input.deinit();
|
||||
self.last_input.deinit();
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
@ -73,24 +73,24 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
fn insert_code_point(self: *Self, c: u32) !void {
|
||||
var buf: [16]u8 = undefined;
|
||||
const bytes = input.ucs32_to_utf8(&[_]u32{c}, &buf) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
try self.input_.appendSlice(buf[0..bytes]);
|
||||
try self.input.appendSlice(buf[0..bytes]);
|
||||
}
|
||||
|
||||
fn insert_bytes(self: *Self, bytes: []const u8) !void {
|
||||
try self.input_.appendSlice(bytes);
|
||||
try self.input.appendSlice(bytes);
|
||||
}
|
||||
|
||||
fn flush_input(self: *Self) !void {
|
||||
if (self.input_.items.len > 0) {
|
||||
if (eql(u8, self.input_.items, self.last_input.items))
|
||||
if (self.input.items.len > 0) {
|
||||
if (eql(u8, self.input.items, self.last_input.items))
|
||||
return;
|
||||
self.last_input.clearRetainingCapacity();
|
||||
try self.last_input.appendSlice(self.input_.items);
|
||||
try self.last_input.appendSlice(self.input.items);
|
||||
self.editor.find_operation = .goto_next_match;
|
||||
const primary = self.editor.get_primary();
|
||||
primary.selection = null;
|
||||
primary.cursor = self.start_cursor;
|
||||
try self.editor.find_in_buffer(self.input_.items);
|
||||
try self.editor.find_in_buffer(self.input.items);
|
||||
} else {
|
||||
self.editor.get_primary().selection = null;
|
||||
self.editor.init_matches_update();
|
||||
|
@ -114,9 +114,9 @@ fn find_history_prev(self: *Self) void {
|
|||
if (pos > 0) self.history_pos = pos - 1;
|
||||
} else {
|
||||
self.history_pos = history.items.len - 1;
|
||||
if (self.input_.items.len > 0)
|
||||
self.editor.push_find_history(self.editor.allocator.dupe(u8, self.input_.items) catch return);
|
||||
if (eql(u8, history.items[self.history_pos.?], self.input_.items) and self.history_pos.? > 0)
|
||||
if (self.input.items.len > 0)
|
||||
self.editor.push_find_history(self.editor.allocator.dupe(u8, self.input.items) catch return);
|
||||
if (eql(u8, history.items[self.history_pos.?], self.input.items) and self.history_pos.? > 0)
|
||||
self.history_pos = self.history_pos.? - 1;
|
||||
}
|
||||
self.load_history(self.history_pos.?);
|
||||
|
@ -134,40 +134,39 @@ fn find_history_next(self: *Self) void {
|
|||
|
||||
fn load_history(self: *Self, pos: usize) void {
|
||||
if (self.editor.find_history) |*history| {
|
||||
self.input_.clearRetainingCapacity();
|
||||
self.input_.appendSlice(history.items[pos]) catch {};
|
||||
self.input.clearRetainingCapacity();
|
||||
self.input.appendSlice(history.items[pos]) catch {};
|
||||
}
|
||||
}
|
||||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.input_.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.input_.items, 0, 8);
|
||||
mini_mode.text = self.input.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.input.items, 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn mini_mode_reset(self: *Self, _: Ctx) Result {
|
||||
self.input_.clearRetainingCapacity();
|
||||
self.input.clearRetainingCapacity();
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_reset_meta: Meta = .{ .description = "Clear input" };
|
||||
pub const mini_mode_reset_meta = .{ .description = "Clear input" };
|
||||
|
||||
pub fn mini_mode_cancel(self: *Self, _: Ctx) Result {
|
||||
self.cancel();
|
||||
}
|
||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||
pub const mini_mode_cancel_meta = .{ .description = "Cancel input" };
|
||||
|
||||
pub fn mini_mode_select(self: *Self, _: Ctx) Result {
|
||||
self.editor.push_find_history(self.input_.items);
|
||||
self.editor.push_find_history(self.input.items);
|
||||
self.cmd("exit_mini_mode", .{}) catch {};
|
||||
}
|
||||
pub const mini_mode_select_meta: Meta = .{ .description = "Select" };
|
||||
pub const mini_mode_select_meta = .{ .description = "Select" };
|
||||
|
||||
pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var egc: u32 = 0;
|
||||
|
@ -176,7 +175,7 @@ const cmds = struct {
|
|||
self.insert_code_point(egc) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const mini_mode_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn mini_mode_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -185,28 +184,28 @@ const cmds = struct {
|
|||
self.insert_bytes(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
self.input_.resize(self.input_.items.len - tui.egc_last(self.input_.items).len) catch {};
|
||||
self.input.resize(self.input.items.len - tui.egc_last(self.input.items).len) catch {};
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const mini_mode_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn mini_mode_history_prev(self: *Self, _: Ctx) Result {
|
||||
self.find_history_prev();
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_history_prev_meta: Meta = .{ .description = "History previous" };
|
||||
pub const mini_mode_history_prev_meta = .{ .description = "History previous" };
|
||||
|
||||
pub fn mini_mode_history_next(self: *Self, _: Ctx) Result {
|
||||
self.find_history_next();
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_history_next_meta: Meta = .{ .description = "History next" };
|
||||
pub const mini_mode_history_next_meta = .{ .description = "History next" };
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return mini_mode_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_paste_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ const max_query_size = 1024;
|
|||
|
||||
allocator: Allocator,
|
||||
buf: [max_query_size]u8 = undefined,
|
||||
input_: []u8 = "",
|
||||
input: []u8 = "",
|
||||
last_buf: [max_query_size]u8 = undefined,
|
||||
last_input: []u8 = "",
|
||||
commands: Commands = undefined,
|
||||
|
@ -31,7 +31,7 @@ pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.
|
|||
if (tui.get_active_selection(self.allocator)) |text| {
|
||||
defer self.allocator.free(text);
|
||||
@memcpy(self.buf[0..text.len], text);
|
||||
self.input_ = self.buf[0..text.len];
|
||||
self.input = self.buf[0..text.len];
|
||||
}
|
||||
var mode = try keybind.mode("mini/find_in_files", allocator, .{
|
||||
.insert_command = "mini_mode_insert_bytes",
|
||||
|
@ -59,57 +59,55 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
}
|
||||
|
||||
fn insert_code_point(self: *Self, c: u32) !void {
|
||||
if (self.input_.len + 6 >= self.buf.len)
|
||||
if (self.input.len + 6 >= self.buf.len)
|
||||
return;
|
||||
const bytes = try input.ucs32_to_utf8(&[_]u32{c}, self.buf[self.input_.len..]);
|
||||
self.input_ = self.buf[0 .. self.input_.len + bytes];
|
||||
const bytes = try input.ucs32_to_utf8(&[_]u32{c}, self.buf[self.input.len..]);
|
||||
self.input = self.buf[0 .. self.input.len + bytes];
|
||||
}
|
||||
|
||||
fn insert_bytes(self: *Self, bytes_: []const u8) !void {
|
||||
const bytes = bytes_[0..@min(self.buf.len - self.input_.len, bytes_.len)];
|
||||
const newlen = self.input_.len + bytes.len;
|
||||
@memcpy(self.buf[self.input_.len..newlen], bytes);
|
||||
self.input_ = self.buf[0..newlen];
|
||||
const bytes = bytes_[0..@min(self.buf.len - self.input.len, bytes_.len)];
|
||||
const newlen = self.input.len + bytes.len;
|
||||
@memcpy(self.buf[self.input.len..newlen], bytes);
|
||||
self.input = self.buf[0..newlen];
|
||||
}
|
||||
|
||||
fn start_query(self: *Self) !void {
|
||||
if (self.input_.len < 2 or eql(u8, self.input_, self.last_input))
|
||||
if (self.input.len < 2 or eql(u8, self.input, self.last_input))
|
||||
return;
|
||||
@memcpy(self.last_buf[0..self.input_.len], self.input_);
|
||||
self.last_input = self.last_buf[0..self.input_.len];
|
||||
try command.executeName("find_in_files_query", command.fmt(.{self.input_}));
|
||||
@memcpy(self.last_buf[0..self.input.len], self.input);
|
||||
self.last_input = self.last_buf[0..self.input.len];
|
||||
try command.executeName("find_in_files_query", command.fmt(.{self.input}));
|
||||
}
|
||||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.input_;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.input_, 0, 8);
|
||||
mini_mode.text = self.input;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.input, 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn mini_mode_reset(self: *Self, _: Ctx) Result {
|
||||
self.input_ = "";
|
||||
self.input = "";
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_reset_meta: Meta = .{ .description = "Clear input" };
|
||||
pub const mini_mode_reset_meta = .{ .description = "Clear input" };
|
||||
|
||||
pub fn mini_mode_cancel(_: *Self, _: Ctx) Result {
|
||||
command.executeName("close_find_in_files_results", .{}) catch {};
|
||||
command.executeName("exit_mini_mode", .{}) catch {};
|
||||
}
|
||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||
pub const mini_mode_cancel_meta = .{ .description = "Cancel input" };
|
||||
|
||||
pub fn mini_mode_select(_: *Self, _: Ctx) Result {
|
||||
command.executeName("goto_selected_file", .{}) catch {};
|
||||
return command.executeName("exit_mini_mode", .{});
|
||||
}
|
||||
pub const mini_mode_select_meta: Meta = .{ .description = "Select" };
|
||||
pub const mini_mode_select_meta = .{ .description = "Select" };
|
||||
|
||||
pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var egc: u32 = 0;
|
||||
|
@ -118,7 +116,7 @@ const cmds = struct {
|
|||
self.insert_code_point(egc) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const mini_mode_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn mini_mode_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -127,16 +125,16 @@ const cmds = struct {
|
|||
self.insert_bytes(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
self.input_ = self.input_[0 .. self.input_.len - tui.egc_last(self.input_).len];
|
||||
self.input = self.input[0 .. self.input.len - tui.egc_last(self.input).len];
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const mini_mode_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return mini_mode_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_paste_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
|
|
|
@ -82,14 +82,13 @@ fn insert_bytes(self: *Self, bytes: []const u8) void {
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn mini_mode_reset(self: *Self, _: Ctx) Result {
|
||||
self.input = null;
|
||||
self.update_mini_mode_text();
|
||||
}
|
||||
pub const mini_mode_reset_meta: Meta = .{ .description = "Clear input" };
|
||||
pub const mini_mode_reset_meta = .{ .description = "Clear input" };
|
||||
|
||||
pub fn mini_mode_cancel(self: *Self, _: Ctx) Result {
|
||||
self.input = null;
|
||||
|
@ -97,7 +96,7 @@ const cmds = struct {
|
|||
self.goto();
|
||||
command.executeName("exit_mini_mode", .{}) catch {};
|
||||
}
|
||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||
pub const mini_mode_cancel_meta = .{ .description = "Cancel input" };
|
||||
|
||||
pub fn mini_mode_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
if (self.input) |linenum| {
|
||||
|
@ -107,7 +106,7 @@ const cmds = struct {
|
|||
self.goto();
|
||||
}
|
||||
}
|
||||
pub const mini_mode_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const mini_mode_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var keypress: usize = 0;
|
||||
|
@ -120,7 +119,7 @@ const cmds = struct {
|
|||
self.update_mini_mode_text();
|
||||
self.goto();
|
||||
}
|
||||
pub const mini_mode_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const mini_mode_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn mini_mode_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -130,10 +129,5 @@ const cmds = struct {
|
|||
self.update_mini_mode_text();
|
||||
self.goto();
|
||||
}
|
||||
pub const mini_mode_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return mini_mode_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
|
||||
const input = @import("input");
|
||||
|
@ -17,7 +16,6 @@ const Commands = command.Collection(cmds);
|
|||
allocator: Allocator,
|
||||
key: [6]u8 = undefined,
|
||||
direction: Direction,
|
||||
operation_command: []const u8,
|
||||
operation: Operation,
|
||||
commands: Commands = undefined,
|
||||
|
||||
|
@ -32,18 +30,14 @@ const Operation = enum {
|
|||
};
|
||||
|
||||
pub fn create(allocator: Allocator, ctx: command.Context) !struct { tui.Mode, tui.MiniMode } {
|
||||
var operation_command: []const u8 = undefined;
|
||||
_ = ctx.args.match(.{tp.extract(&operation_command)}) catch return error.InvalidMoveToCharArgument;
|
||||
|
||||
const direction: Direction = if (std.mem.indexOf(u8, operation_command, "_left")) |_| .left else .right;
|
||||
const operation: Operation = if (tui.get_active_editor()) |editor| if (editor.get_primary().selection) |_| .select else .move else .move;
|
||||
|
||||
var direction: Direction = undefined;
|
||||
const select = if (tui.get_active_editor()) |editor| if (editor.get_primary().selection) |_| true else false else false;
|
||||
_ = ctx.args.match(.{tp.extract(&direction)}) catch return error.InvalidMoveToCharArgument;
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.direction = direction,
|
||||
.operation_command = try allocator.dupe(u8, operation_command),
|
||||
.operation = operation,
|
||||
.operation = if (select) .select else .move,
|
||||
};
|
||||
try self.commands.init(self);
|
||||
var mode = try keybind.mode("mini/move_to_char", allocator, .{
|
||||
|
@ -55,7 +49,6 @@ pub fn create(allocator: Allocator, ctx: command.Context) !struct { tui.Mode, tu
|
|||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.commands.deinit();
|
||||
self.allocator.free(self.operation_command);
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
|
@ -77,14 +70,23 @@ pub fn receive(_: *Self, _: tp.pid_ref, _: tp.message) error{Exit}!bool {
|
|||
}
|
||||
|
||||
fn execute_operation(self: *Self, ctx: command.Context) command.Result {
|
||||
try command.executeName(self.operation_command, ctx);
|
||||
const cmd = switch (self.direction) {
|
||||
.left => switch (self.operation) {
|
||||
.move => "move_to_char_left",
|
||||
.select => "select_to_char_left",
|
||||
},
|
||||
.right => switch (self.operation) {
|
||||
.move => "move_to_char_right",
|
||||
.select => "select_to_char_right",
|
||||
},
|
||||
};
|
||||
try command.executeName(cmd, ctx);
|
||||
try command.executeName("exit_mini_mode", .{});
|
||||
}
|
||||
|
||||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn mini_mode_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
|
@ -95,7 +97,7 @@ const cmds = struct {
|
|||
const bytes = input.ucs32_to_utf8(&[_]u32{code_point}, &buf) catch return error.InvalidMoveToCharCodePoint;
|
||||
return self.execute_operation(command.fmt(.{buf[0..bytes]}));
|
||||
}
|
||||
pub const mini_mode_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const mini_mode_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn mini_mode_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -103,10 +105,10 @@ const cmds = struct {
|
|||
return error.InvalidMoveToCharInsertBytesArgument;
|
||||
return self.execute_operation(ctx);
|
||||
}
|
||||
pub const mini_mode_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn mini_mode_cancel(_: *Self, _: Ctx) Result {
|
||||
command.executeName("exit_mini_mode", .{}) catch {};
|
||||
}
|
||||
pub const mini_mode_cancel_meta: Meta = .{ .description = "Cancel input" };
|
||||
pub const mini_mode_cancel_meta = .{ .description = "Cancel input" };
|
||||
};
|
||||
|
|
|
@ -272,58 +272,57 @@ const Commands = command.Collection(cmds);
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn palette_menu_top(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_first();
|
||||
}
|
||||
pub const palette_menu_top_meta: Meta = .{};
|
||||
pub const palette_menu_top_meta = .{};
|
||||
|
||||
pub fn palette_menu_down(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_down();
|
||||
}
|
||||
pub const palette_menu_down_meta: Meta = .{};
|
||||
pub const palette_menu_down_meta = .{};
|
||||
|
||||
pub fn palette_menu_up(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_up();
|
||||
}
|
||||
pub const palette_menu_up_meta: Meta = .{};
|
||||
pub const palette_menu_up_meta = .{};
|
||||
|
||||
pub fn palette_menu_pagedown(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_last();
|
||||
}
|
||||
pub const palette_menu_pagedown_meta: Meta = .{};
|
||||
pub const palette_menu_pagedown_meta = .{};
|
||||
|
||||
pub fn palette_menu_pageup(self: *Self, _: Ctx) Result {
|
||||
self.menu.select_first();
|
||||
}
|
||||
pub const palette_menu_pageup_meta: Meta = .{};
|
||||
pub const palette_menu_pageup_meta = .{};
|
||||
|
||||
pub fn palette_menu_activate(self: *Self, _: Ctx) Result {
|
||||
self.menu.activate_selected();
|
||||
}
|
||||
pub const palette_menu_activate_meta: Meta = .{};
|
||||
pub const palette_menu_activate_meta = .{};
|
||||
|
||||
pub fn palette_menu_activate_quick(self: *Self, _: Ctx) Result {
|
||||
if (self.menu.selected orelse 0 > 0) self.menu.activate_selected();
|
||||
}
|
||||
pub const palette_menu_activate_quick_meta: Meta = .{};
|
||||
pub const palette_menu_activate_quick_meta = .{};
|
||||
|
||||
pub fn palette_menu_cancel(self: *Self, _: Ctx) Result {
|
||||
try self.cmd("exit_overlay_mode", .{});
|
||||
}
|
||||
pub const palette_menu_cancel_meta: Meta = .{};
|
||||
pub const palette_menu_cancel_meta = .{};
|
||||
|
||||
pub fn overlay_delete_word_left(self: *Self, _: Ctx) Result {
|
||||
self.delete_word() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_delete_word_left_meta: Meta = .{ .description = "Delete word to the left" };
|
||||
pub const overlay_delete_word_left_meta = .{ .description = "Delete word to the left" };
|
||||
|
||||
pub fn overlay_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
self.delete_code_point() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const overlay_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn overlay_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var egc: u32 = 0;
|
||||
|
@ -331,7 +330,7 @@ const cmds = struct {
|
|||
return error.InvalidOpenRecentInsertCodePointArgument;
|
||||
self.insert_code_point(egc) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const overlay_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn overlay_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -339,20 +338,20 @@ const cmds = struct {
|
|||
return error.InvalidOpenRecentInsertBytesArgument;
|
||||
self.insert_bytes(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const overlay_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn overlay_toggle_panel(self: *Self, _: Ctx) Result {
|
||||
return self.cmd_async("toggle_panel");
|
||||
}
|
||||
pub const overlay_toggle_panel_meta: Meta = .{};
|
||||
pub const overlay_toggle_panel_meta = .{};
|
||||
|
||||
pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result {
|
||||
return self.cmd_async("toggle_inputview");
|
||||
}
|
||||
pub const overlay_toggle_inputview_meta: Meta = .{};
|
||||
pub const overlay_toggle_inputview_meta = .{};
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return overlay_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_paste_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
|
|
|
@ -366,7 +366,6 @@ pub fn Create(options: type) type {
|
|||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn palette_menu_down(self: *Self, _: Ctx) Result {
|
||||
|
@ -384,7 +383,7 @@ pub fn Create(options: type) type {
|
|||
self.menu.select_down();
|
||||
self.selection_updated();
|
||||
}
|
||||
pub const palette_menu_down_meta: Meta = .{};
|
||||
pub const palette_menu_down_meta = .{};
|
||||
|
||||
pub fn palette_menu_up(self: *Self, _: Ctx) Result {
|
||||
if (self.menu.selected) |selected| {
|
||||
|
@ -399,7 +398,7 @@ pub fn Create(options: type) type {
|
|||
self.menu.select_up();
|
||||
self.selection_updated();
|
||||
}
|
||||
pub const palette_menu_up_meta: Meta = .{};
|
||||
pub const palette_menu_up_meta = .{};
|
||||
|
||||
pub fn palette_menu_pagedown(self: *Self, _: Ctx) Result {
|
||||
if (self.total_items > self.view_rows) {
|
||||
|
@ -411,7 +410,7 @@ pub fn Create(options: type) type {
|
|||
self.menu.select_last();
|
||||
self.selection_updated();
|
||||
}
|
||||
pub const palette_menu_pagedown_meta: Meta = .{};
|
||||
pub const palette_menu_pagedown_meta = .{};
|
||||
|
||||
pub fn palette_menu_pageup(self: *Self, _: Ctx) Result {
|
||||
if (self.view_pos > self.view_rows)
|
||||
|
@ -422,7 +421,7 @@ pub fn Create(options: type) type {
|
|||
self.menu.select_first();
|
||||
self.selection_updated();
|
||||
}
|
||||
pub const palette_menu_pageup_meta: Meta = .{};
|
||||
pub const palette_menu_pageup_meta = .{};
|
||||
|
||||
pub fn palette_menu_delete_item(self: *Self, _: Ctx) Result {
|
||||
if (@hasDecl(options, "delete_item")) {
|
||||
|
@ -437,33 +436,33 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub const palette_menu_delete_item_meta: Meta = .{};
|
||||
pub const palette_menu_delete_item_meta = .{};
|
||||
|
||||
pub fn palette_menu_activate(self: *Self, _: Ctx) Result {
|
||||
self.menu.activate_selected();
|
||||
}
|
||||
pub const palette_menu_activate_meta: Meta = .{};
|
||||
pub const palette_menu_activate_meta = .{};
|
||||
|
||||
pub fn palette_menu_activate_quick(self: *Self, _: Ctx) Result {
|
||||
if (self.menu.selected orelse 0 > 0) self.menu.activate_selected();
|
||||
}
|
||||
pub const palette_menu_activate_quick_meta: Meta = .{};
|
||||
pub const palette_menu_activate_quick_meta = .{};
|
||||
|
||||
pub fn palette_menu_cancel(self: *Self, _: Ctx) Result {
|
||||
if (@hasDecl(options, "cancel")) try options.cancel(self);
|
||||
try self.cmd("exit_overlay_mode", .{});
|
||||
}
|
||||
pub const palette_menu_cancel_meta: Meta = .{};
|
||||
pub const palette_menu_cancel_meta = .{};
|
||||
|
||||
pub fn overlay_delete_word_left(self: *Self, _: Ctx) Result {
|
||||
self.delete_word() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_delete_word_left_meta: Meta = .{ .description = "Delete word to the left" };
|
||||
pub const overlay_delete_word_left_meta = .{ .description = "Delete word to the left" };
|
||||
|
||||
pub fn overlay_delete_backwards(self: *Self, _: Ctx) Result {
|
||||
self.delete_code_point() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_delete_backwards_meta: Meta = .{ .description = "Delete backwards" };
|
||||
pub const overlay_delete_backwards_meta = .{ .description = "Delete backwards" };
|
||||
|
||||
pub fn overlay_insert_code_point(self: *Self, ctx: Ctx) Result {
|
||||
var egc: u32 = 0;
|
||||
|
@ -471,7 +470,7 @@ pub fn Create(options: type) type {
|
|||
return error.InvalidPaletteInsertCodePointArgument;
|
||||
self.insert_code_point(egc) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_insert_code_point_meta: Meta = .{ .arguments = &.{.integer} };
|
||||
pub const overlay_insert_code_point_meta = .{ .arguments = &.{.integer} };
|
||||
|
||||
pub fn overlay_insert_bytes(self: *Self, ctx: Ctx) Result {
|
||||
var bytes: []const u8 = undefined;
|
||||
|
@ -479,22 +478,22 @@ pub fn Create(options: type) type {
|
|||
return error.InvalidPaletteInsertBytesArgument;
|
||||
self.insert_bytes(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const overlay_insert_bytes_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn overlay_toggle_panel(self: *Self, _: Ctx) Result {
|
||||
return self.cmd_async("toggle_panel");
|
||||
}
|
||||
pub const overlay_toggle_panel_meta: Meta = .{};
|
||||
pub const overlay_toggle_panel_meta = .{};
|
||||
|
||||
pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result {
|
||||
return self.cmd_async("toggle_inputview");
|
||||
}
|
||||
pub const overlay_toggle_inputview_meta: Meta = .{};
|
||||
pub const overlay_toggle_inputview_meta = .{};
|
||||
|
||||
pub fn mini_mode_paste(self: *Self, ctx: Ctx) Result {
|
||||
return overlay_insert_bytes(self, ctx);
|
||||
}
|
||||
pub const mini_mode_paste_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const mini_mode_paste_meta = .{ .arguments = &.{.string} };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,42 +17,33 @@ const Commands = command.Collection(cmds_);
|
|||
const cmds_ = struct {
|
||||
pub const Target = void;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn w(_: *void, _: Ctx) Result {
|
||||
try cmd("save_file", .{});
|
||||
}
|
||||
pub const w_meta: Meta = .{ .description = "w (write file)" };
|
||||
pub const w_meta = .{ .description = "w (write file)" };
|
||||
|
||||
pub fn q(_: *void, _: Ctx) Result {
|
||||
try cmd("quit", .{});
|
||||
}
|
||||
pub const q_meta: Meta = .{ .description = "q (quit)" };
|
||||
pub const q_meta = .{ .description = "q (quit)" };
|
||||
|
||||
pub fn @"q!"(_: *void, _: Ctx) Result {
|
||||
try cmd("quit_without_saving", .{});
|
||||
}
|
||||
pub const @"q!_meta": Meta = .{ .description = "q! (quit without saving)" };
|
||||
pub const @"q!_meta" = .{ .description = "q! (quit without saving)" };
|
||||
|
||||
pub fn wq(_: *void, _: Ctx) Result {
|
||||
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
|
||||
}
|
||||
pub const wq_meta: Meta = .{ .description = "wq (write file and quit)" };
|
||||
pub const wq_meta = .{ .description = "wq (write file and quit)" };
|
||||
|
||||
pub fn @"wq!"(_: *void, _: Ctx) Result {
|
||||
cmd("save_file", .{}) catch {};
|
||||
try cmd("quit_without_saving", .{});
|
||||
}
|
||||
pub const @"wq!_meta": Meta = .{ .description = "wq! (write file and quit without saving)" };
|
||||
|
||||
pub fn move_begin_or_add_integer_argument_zero(_: *void, _: Ctx) Result {
|
||||
return if (@import("keybind").current_integer_argument()) |_|
|
||||
command.executeName("add_integer_argument_digit", command.fmt(.{0}))
|
||||
else
|
||||
command.executeName("move_begin", .{});
|
||||
}
|
||||
pub const move_begin_or_add_integer_argument_zero_meta: Meta = .{ .description = "Move cursor to beginning of line (vim)" };
|
||||
pub const @"wq!_meta" = .{ .description = "wq! (write file and quit without saving)" };
|
||||
|
||||
pub fn enter_mode_at_next_char(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -61,7 +52,7 @@ const cmds_ = struct {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
pub const enter_mode_at_next_char_meta: Meta = .{ .description = "Move forward one char and change mode" };
|
||||
pub const enter_mode_at_next_char_meta = .{ .description = "Move forward one char and change mode" };
|
||||
|
||||
pub fn enter_mode_on_newline_down(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -70,7 +61,7 @@ const cmds_ = struct {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
pub const enter_mode_on_newline_down_meta: Meta = .{ .description = "Insert a newline and change mode" };
|
||||
pub const enter_mode_on_newline_down_meta = .{ .description = "Insert a newline and change mode" };
|
||||
|
||||
pub fn enter_mode_on_newline_up(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -78,7 +69,7 @@ const cmds_ = struct {
|
|||
//TODO
|
||||
return undefined;
|
||||
}
|
||||
pub const enter_mode_on_newline_up_meta: Meta = .{ .description = "Insert a newline above the current line and change mode" };
|
||||
pub const enter_mode_on_newline_up_meta = .{ .description = "Insert a newline above the current line and change mode" };
|
||||
|
||||
pub fn enter_mode_at_line_begin(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -87,7 +78,7 @@ const cmds_ = struct {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
pub const enter_mode_at_line_begin_meta: Meta = .{ .description = "Goto line begin and change mode" };
|
||||
pub const enter_mode_at_line_begin_meta = .{ .description = "Goto line begin and change mode" };
|
||||
|
||||
pub fn enter_mode_at_line_end(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -95,7 +86,7 @@ const cmds_ = struct {
|
|||
//TODO
|
||||
return undefined;
|
||||
}
|
||||
pub const enter_mode_at_line_end_meta: Meta = .{ .description = "Goto line end and change mode" };
|
||||
pub const enter_mode_at_line_end_meta = .{ .description = "Goto line end and change mode" };
|
||||
|
||||
pub fn copy_line(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -104,7 +95,7 @@ const cmds_ = struct {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
pub const copy_line_meta: Meta = .{ .description = "Copies the current line" };
|
||||
pub const copy_line_meta = .{ .description = "Copies the current line" };
|
||||
|
||||
pub fn delete_line(self: *void, ctx: Ctx) Result {
|
||||
_ = self; // autofix
|
||||
|
@ -119,5 +110,5 @@ const cmds_ = struct {
|
|||
//try self.update_buf(root);
|
||||
//self.clamp();
|
||||
}
|
||||
pub const delete_line_meta: Meta = .{ .description = "Delete the current line without copying" };
|
||||
pub const delete_line_meta = .{ .description = "Delete the current line without copying" };
|
||||
};
|
||||
|
|
|
@ -8,17 +8,13 @@ const Plane = @import("renderer").Plane;
|
|||
|
||||
pub const Style = enum { none, grip };
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, config: []const u8, style: Style, event_handler: ?EventHandler) error{OutOfMemory}!Widget {
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, config: []const u8, style: Style, event_handler: ?EventHandler) !Widget {
|
||||
var w = try WidgetList.createH(allocator, parent, "statusbar", .{ .static = 1 });
|
||||
if (style == .grip) w.after_render = render_grip;
|
||||
w.ctx = w;
|
||||
var it = std.mem.splitScalar(u8, config, ' ');
|
||||
while (it.next()) |widget_name| {
|
||||
try w.add(status_widget.create(widget_name, allocator, w.plane, event_handler) catch |e| switch (e) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.WidgetInitFailed => null,
|
||||
} orelse continue);
|
||||
}
|
||||
while (it.next()) |widget_name|
|
||||
try w.add(try status_widget.create(widget_name, allocator, w.plane, event_handler) orelse continue);
|
||||
return w.widget();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,24 +6,18 @@ const EventHandler = @import("EventHandler");
|
|||
const Widget = @import("../Widget.zig");
|
||||
|
||||
plane: Plane,
|
||||
layout_: Widget.Layout,
|
||||
layout: Widget.Layout,
|
||||
on_event: ?EventHandler,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn Create(comptime layout_: Widget.Layout) @import("widget.zig").CreateFunction {
|
||||
return struct {
|
||||
fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
const layout__ = if (layout_ == .static) blk: {
|
||||
if (arg) |str_size| {
|
||||
const size = std.fmt.parseInt(usize, str_size, 10) catch break :blk layout_;
|
||||
break :blk Widget.Layout{ .static = size };
|
||||
} else break :blk layout_;
|
||||
} else layout_;
|
||||
fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
.layout_ = layout__,
|
||||
.layout = layout_,
|
||||
.on_event = event_handler,
|
||||
};
|
||||
return Widget.to(self);
|
||||
|
@ -37,7 +31,7 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||
}
|
||||
|
||||
pub fn layout(self: *Self) Widget.Layout {
|
||||
return self.layout_;
|
||||
return self.layout;
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
const std = @import("std");
|
||||
const tp = @import("thespian");
|
||||
|
||||
const EventHandler = @import("EventHandler");
|
||||
const Plane = @import("renderer").Plane;
|
||||
const git = @import("git");
|
||||
|
||||
const Widget = @import("../Widget.zig");
|
||||
const MessageFilter = @import("../MessageFilter.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
|
||||
const branch_symbol = "";
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
plane: Plane,
|
||||
branch: ?[]const u8 = null,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(
|
||||
allocator: std.mem.Allocator,
|
||||
parent: Plane,
|
||||
_: ?EventHandler,
|
||||
_: ?[]const u8,
|
||||
) @import("widget.zig").CreateError!Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
};
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_git));
|
||||
git.workspace_path(0) catch {};
|
||||
return Widget.to(self);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
if (self.branch) |p| self.allocator.free(p);
|
||||
self.plane.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
fn receive_git(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
||||
return if (try match(m.buf, .{ "git", more }))
|
||||
self.process_git(m)
|
||||
else
|
||||
false;
|
||||
}
|
||||
|
||||
fn process_git(
|
||||
self: *Self,
|
||||
m: tp.message,
|
||||
) MessageFilter.Error!bool {
|
||||
var branch: []const u8 = undefined;
|
||||
if (try match(m.buf, .{ any, any, "workspace_path", null_ })) {
|
||||
// do nothing, we do not have a git workspace
|
||||
} else if (try match(m.buf, .{ any, any, "workspace_path", string })) {
|
||||
git.current_branch(0) catch {};
|
||||
} else if (try match(m.buf, .{ any, any, "current_branch", extract(&branch) })) {
|
||||
if (self.branch) |p| self.allocator.free(p);
|
||||
self.branch = try self.allocator.dupe(u8, branch);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn layout(self: *Self) Widget.Layout {
|
||||
const branch = self.branch orelse return .{ .static = 0 };
|
||||
var buf: [256]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
const writer = fbs.writer();
|
||||
writer.print("{s} {s}", .{ branch_symbol, branch }) catch {};
|
||||
const len = self.plane.egc_chunk_width(fbs.getWritten(), 0, 1);
|
||||
return .{ .static = len };
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
const branch = self.branch orelse return false;
|
||||
self.plane.set_base_style(theme.editor);
|
||||
self.plane.erase();
|
||||
self.plane.home();
|
||||
self.plane.set_style(theme.statusbar);
|
||||
self.plane.fill(" ");
|
||||
self.plane.home();
|
||||
_ = self.plane.print("{s} {s}", .{ branch_symbol, branch }) catch {};
|
||||
return false;
|
||||
}
|
||||
|
||||
const match = cbor.match;
|
||||
const more = cbor.more;
|
||||
const null_ = cbor.null_;
|
||||
const string = cbor.string;
|
||||
const extract = cbor.extract;
|
||||
const any = cbor.any;
|
||||
|
||||
const cbor = @import("cbor");
|
|
@ -9,37 +9,24 @@ const Plane = @import("renderer").Plane;
|
|||
const Widget = @import("../Widget.zig");
|
||||
const MessageFilter = @import("../MessageFilter.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
const fonts = @import("../fonts.zig");
|
||||
|
||||
const DigitStyle = fonts.DigitStyle;
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
plane: Plane,
|
||||
tick_timer: ?tp.Cancellable = null,
|
||||
on_event: ?EventHandler,
|
||||
tz: zeit.timezone.TimeZone,
|
||||
style: ?DigitStyle,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
const style: ?DigitStyle = if (arg) |style| std.meta.stringToEnum(DigitStyle, style) orelse null else null;
|
||||
|
||||
var env = std.process.getEnvMap(allocator) catch |e| {
|
||||
std.log.err("clock: std.process.getEnvMap failed with {any}", .{e});
|
||||
return error.WidgetInitFailed;
|
||||
};
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
var env = std.process.getEnvMap(allocator) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
defer env.deinit();
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
.on_event = event_handler,
|
||||
.tz = zeit.local(allocator, &env) catch |e| {
|
||||
std.log.err("clock: zeit.local failed with {any}", .{e});
|
||||
return error.WidgetInitFailed;
|
||||
},
|
||||
.style = style,
|
||||
.tz = zeit.local(allocator, &env) catch |e| return tp.exit_error(e, @errorReturnTrace()),
|
||||
};
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_tick));
|
||||
self.update_tick_timer(.init);
|
||||
|
@ -81,14 +68,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
|
||||
const now = zeit.instant(.{ .timezone = &self.tz }) catch return false;
|
||||
const dt = now.time();
|
||||
|
||||
var buf: [64]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
const writer = fbs.writer();
|
||||
std.fmt.format(writer, "{d:0>2}:{d:0>2}", .{ dt.hour, dt.minute }) catch {};
|
||||
|
||||
const value_str = fbs.getWritten();
|
||||
for (value_str, 0..) |_, i| _ = self.plane.putstr(fonts.get_digit_ascii(value_str[i .. i + 1], self.style orelse .ascii)) catch {};
|
||||
_ = self.plane.print("{d:0>2}:{d:0>2}", .{ dt.hour, dt.minute }) catch {};
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ rendered: [:0]const u8 = "",
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
return Button.create_widget(Self, allocator, parent, .{
|
||||
.ctx = .{},
|
||||
.label = "",
|
||||
|
|
|
@ -7,7 +7,6 @@ const root = @import("root");
|
|||
|
||||
const Plane = @import("renderer").Plane;
|
||||
const style = @import("renderer").style;
|
||||
const styles = @import("renderer").styles;
|
||||
const command = @import("command");
|
||||
const EventHandler = @import("EventHandler");
|
||||
|
||||
|
@ -38,7 +37,7 @@ utf8_sanitized: bool = false,
|
|||
const project_icon = "";
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const btn = try Button.create(Self, allocator, parent, .{
|
||||
.ctx = .{
|
||||
.allocator = allocator,
|
||||
|
@ -102,7 +101,7 @@ pub fn render(self: *Self, btn: *Button.State(Self), theme: *const Widget.Theme)
|
|||
}
|
||||
|
||||
fn render_mini_mode(plane: *Plane, theme: *const Widget.Theme) void {
|
||||
plane.off_styles(styles.italic);
|
||||
plane.off_styles(style.italic);
|
||||
const mini_mode = tui.mini_mode() orelse return;
|
||||
_ = plane.print(" {s}", .{mini_mode.text}) catch {};
|
||||
if (mini_mode.cursor) |cursor| {
|
||||
|
@ -130,7 +129,7 @@ fn render_mini_mode(plane: *Plane, theme: *const Widget.Theme) void {
|
|||
// Content save cog
|
||||
// Content save all
|
||||
fn render_normal(self: *Self, plane: *Plane, theme: *const Widget.Theme) void {
|
||||
plane.on_styles(styles.italic);
|
||||
plane.on_styles(style.italic);
|
||||
_ = plane.putstr(" ") catch {};
|
||||
if (self.file_icon.len > 0 and tui.config().show_fileicons) {
|
||||
self.render_file_icon(plane, theme);
|
||||
|
@ -142,7 +141,7 @@ fn render_normal(self: *Self, plane: *Plane, theme: *const Widget.Theme) void {
|
|||
}
|
||||
|
||||
fn render_detailed(self: *Self, plane: *Plane, theme: *const Widget.Theme) void {
|
||||
plane.on_styles(styles.italic);
|
||||
plane.on_styles(style.italic);
|
||||
_ = plane.putstr(" ") catch {};
|
||||
if (self.file_icon.len > 0 and tui.config().show_fileicons) {
|
||||
self.render_file_icon(plane, theme);
|
||||
|
|
|
@ -11,7 +11,7 @@ plane: Plane,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, _: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
|
@ -29,12 +29,9 @@ pub fn layout(_: *Self) Widget.Layout {
|
|||
var buf: [256]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
const writer = fbs.writer();
|
||||
writer.print(" ", .{}) catch {};
|
||||
if (keybind.current_integer_argument()) |integer_argument|
|
||||
writer.print("{}", .{integer_argument}) catch {};
|
||||
writer.print("{} ", .{keybind.current_key_event_sequence_fmt()}) catch {};
|
||||
writer.print("{}", .{keybind.current_key_event_sequence_fmt()}) catch {};
|
||||
const len = fbs.getWritten().len;
|
||||
return .{ .static = if (len > 0) len else 0 };
|
||||
return .{ .static = if (len > 0) len + 2 else 0 };
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
|
@ -44,9 +41,6 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
|||
self.plane.set_style(theme.statusbar);
|
||||
self.plane.fill(" ");
|
||||
self.plane.home();
|
||||
_ = self.plane.print(" ", .{}) catch {};
|
||||
if (keybind.current_integer_argument()) |integer_argument|
|
||||
_ = self.plane.print("{}", .{integer_argument}) catch {};
|
||||
_ = self.plane.print("{} ", .{keybind.current_key_event_sequence_fmt()}) catch {};
|
||||
_ = self.plane.print(" {} ", .{keybind.current_key_event_sequence_fmt()}) catch {};
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ const Self = @This();
|
|||
const idle_msg = "🐶";
|
||||
pub const width = idle_msg.len + 20;
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const frame_rate = tp.env.get().num("frame-rate");
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
|
|
|
@ -9,9 +9,6 @@ const EventHandler = @import("EventHandler");
|
|||
|
||||
const Widget = @import("../Widget.zig");
|
||||
const Button = @import("../Button.zig");
|
||||
const fonts = @import("../fonts.zig");
|
||||
|
||||
const DigitStyle = fonts.DigitStyle;
|
||||
|
||||
const utf8_sanitized_warning = " UTF";
|
||||
|
||||
|
@ -22,32 +19,12 @@ buf: [256]u8 = undefined,
|
|||
rendered: [:0]const u8 = "",
|
||||
eol_mode: Buffer.EolMode = .lf,
|
||||
utf8_sanitized: bool = false,
|
||||
padding: ?usize,
|
||||
leader: ?Leader,
|
||||
style: ?DigitStyle,
|
||||
|
||||
const Leader = enum {
|
||||
space,
|
||||
zero,
|
||||
};
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
const padding: ?usize, const leader: ?Leader, const style: ?DigitStyle = if (arg) |fmt| blk: {
|
||||
var it = std.mem.splitScalar(u8, fmt, ',');
|
||||
break :blk .{
|
||||
if (it.next()) |size| std.fmt.parseInt(usize, size, 10) catch null else null,
|
||||
if (it.next()) |leader| std.meta.stringToEnum(Leader, leader) orelse null else null,
|
||||
if (it.next()) |style| std.meta.stringToEnum(DigitStyle, style) orelse null else null,
|
||||
};
|
||||
} else .{ null, null, null };
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
return Button.create_widget(Self, allocator, parent, .{
|
||||
.ctx = .{
|
||||
.padding = padding,
|
||||
.leader = leader,
|
||||
.style = style,
|
||||
},
|
||||
.ctx = .{},
|
||||
.label = "",
|
||||
.on_click = on_click,
|
||||
.on_layout = layout,
|
||||
|
@ -90,30 +67,11 @@ fn format(self: *Self) void {
|
|||
.lf => "",
|
||||
.crlf => " [␍␊]",
|
||||
};
|
||||
std.fmt.format(writer, "{s} Ln ", .{eol_mode}) catch {};
|
||||
self.format_count(writer, self.line + 1, self.padding orelse 0) catch {};
|
||||
std.fmt.format(writer, ", Col ", .{}) catch {};
|
||||
self.format_count(writer, self.column + 1, self.padding orelse 0) catch {};
|
||||
std.fmt.format(writer, " ", .{}) catch {};
|
||||
std.fmt.format(writer, "{s} Ln {d}, Col {d} ", .{ eol_mode, self.line + 1, self.column + 1 }) catch {};
|
||||
self.rendered = @ptrCast(fbs.getWritten());
|
||||
self.buf[self.rendered.len] = 0;
|
||||
}
|
||||
|
||||
fn format_count(self: *Self, writer: anytype, value: usize, width: usize) !void {
|
||||
var buf: [64]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
const writer_ = fbs.writer();
|
||||
try std.fmt.format(writer_, "{d}", .{value});
|
||||
const value_str = fbs.getWritten();
|
||||
|
||||
const char: []const u8 = switch (self.leader orelse .space) {
|
||||
.space => " ",
|
||||
.zero => "0",
|
||||
};
|
||||
for (0..(@max(value_str.len, width) - value_str.len)) |_| try writer.writeAll(fonts.get_digit_ascii(char, self.style orelse .ascii));
|
||||
for (value_str, 0..) |_, i| try writer.writeAll(fonts.get_digit_ascii(value_str[i .. i + 1], self.style orelse .ascii));
|
||||
}
|
||||
|
||||
pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||
var eol_mode: Buffer.EolModeTag = @intFromEnum(Buffer.EolMode.lf);
|
||||
if (try m.match(.{ "E", "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.extract(&self.column) })) {
|
||||
|
|
|
@ -26,7 +26,7 @@ const Level = enum {
|
|||
err,
|
||||
};
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
|
@ -35,7 +35,7 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
|
|||
};
|
||||
logview.init(allocator);
|
||||
try tui.message_filters().add(MessageFilter.bind(self, receive_log));
|
||||
log.subscribe() catch return error.WidgetInitFailed;
|
||||
try log.subscribe();
|
||||
return Widget.to(self);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ const Allocator = std.mem.Allocator;
|
|||
|
||||
const Plane = @import("renderer").Plane;
|
||||
const style = @import("renderer").style;
|
||||
const styles = @import("renderer").styles;
|
||||
const command = @import("command");
|
||||
const EventHandler = @import("EventHandler");
|
||||
|
||||
|
@ -12,7 +11,7 @@ const Button = @import("../Button.zig");
|
|||
const tui = @import("../tui.zig");
|
||||
const CreateError = @import("widget.zig").CreateError;
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) CreateError!Widget {
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!Widget {
|
||||
return Button.create_widget(void, allocator, parent, .{
|
||||
.ctx = {},
|
||||
.label = tui.get_mode(),
|
||||
|
@ -53,7 +52,7 @@ pub fn render(_: *void, self: *Button.State(void), theme: *const Widget.Theme) b
|
|||
self.plane.set_style(style_label);
|
||||
self.plane.fill(" ");
|
||||
self.plane.home();
|
||||
self.plane.on_styles(styles.bold);
|
||||
self.plane.on_styles(style.bold);
|
||||
var buf: [31:0]u8 = undefined;
|
||||
if (!is_mini_mode() and !is_overlay_mode()) {
|
||||
render_logo(self, theme, style_label);
|
||||
|
@ -61,7 +60,7 @@ pub fn render(_: *void, self: *Button.State(void), theme: *const Widget.Theme) b
|
|||
_ = self.plane.putstr(" ") catch {};
|
||||
}
|
||||
self.plane.set_style(style_label);
|
||||
self.plane.on_styles(styles.bold);
|
||||
self.plane.on_styles(style.bold);
|
||||
_ = self.plane.putstr(std.fmt.bufPrintZ(&buf, "{s} ", .{tui.get_mode()}) catch return false) catch {};
|
||||
if (is_mini_mode())
|
||||
render_separator(self, theme);
|
||||
|
|
|
@ -19,7 +19,7 @@ const Self = @This();
|
|||
|
||||
pub const width = 8;
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
|
|
|
@ -18,7 +18,7 @@ on_event: ?EventHandler,
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
|
|
|
@ -52,7 +52,7 @@ const @"style.config" = struct {
|
|||
};
|
||||
pub const Style = @"style.config";
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
|
||||
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) @import("widget.zig").CreateError!Widget {
|
||||
const self = try allocator.create(TabBar);
|
||||
self.* = try TabBar.init(allocator, parent, event_handler);
|
||||
return Widget.to(self);
|
||||
|
@ -428,7 +428,7 @@ const Tab = struct {
|
|||
|
||||
const spacer = struct {
|
||||
plane: Plane,
|
||||
layout_: Widget.Layout,
|
||||
layout: Widget.Layout,
|
||||
on_event: ?EventHandler,
|
||||
content: []const u8,
|
||||
fg: colors,
|
||||
|
@ -447,7 +447,7 @@ const spacer = struct {
|
|||
const self: *Self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
|
||||
.layout_ = .{ .static = self.plane.egc_chunk_width(content, 0, 1) },
|
||||
.layout = .{ .static = self.plane.egc_chunk_width(content, 0, 1) },
|
||||
.on_event = event_handler,
|
||||
.content = content,
|
||||
.fg = fg,
|
||||
|
@ -462,7 +462,7 @@ const spacer = struct {
|
|||
}
|
||||
|
||||
pub fn layout(self: *Self) Widget.Layout {
|
||||
return self.layout_;
|
||||
return self.layout;
|
||||
}
|
||||
|
||||
pub fn render(self: *Self, theme: *const Widget.Theme) bool {
|
||||
|
|
|
@ -19,27 +19,18 @@ const widgets = std.static_string_map.StaticStringMap(CreateFunction).initCompti
|
|||
.{ "clock", @import("clock.zig").create },
|
||||
.{ "keybind", @import("keybindstate.zig").create },
|
||||
.{ "tabs", @import("tabs.zig").create },
|
||||
.{ "branch", @import("branch.zig").create },
|
||||
});
|
||||
pub const CreateError = error{ OutOfMemory, WidgetInitFailed };
|
||||
pub const CreateFunction = *const fn (allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, arg: ?[]const u8) CreateError!Widget;
|
||||
|
||||
pub fn create(descriptor: []const u8, allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!?Widget {
|
||||
var it = std.mem.splitScalar(u8, descriptor, ':');
|
||||
const name = it.next() orelse {
|
||||
const logger = log.logger("statusbar");
|
||||
logger.print_err("config", "bad widget descriptor \"{s}\" (see log)", .{descriptor});
|
||||
return null;
|
||||
};
|
||||
const arg = it.next();
|
||||
pub const CreateError = error{ OutOfMemory, Exit };
|
||||
pub const CreateFunction = *const fn (allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!Widget;
|
||||
|
||||
pub fn create(name: []const u8, allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler) CreateError!?Widget {
|
||||
const create_ = widgets.get(name) orelse {
|
||||
const logger = log.logger("statusbar");
|
||||
logger.print_err("config", "unknown widget \"{s}\" (see log)", .{name});
|
||||
log_widgets(logger);
|
||||
return null;
|
||||
};
|
||||
return try create_(allocator, parent, event_handler, arg);
|
||||
return try create_(allocator, parent, event_handler);
|
||||
}
|
||||
|
||||
fn log_widgets(logger: anytype) void {
|
||||
|
|
452
src/tui/tui.zig
452
src/tui/tui.zig
|
@ -12,7 +12,6 @@ pub const renderer = @import("renderer");
|
|||
const command = @import("command");
|
||||
const EventHandler = @import("EventHandler");
|
||||
const keybind = @import("keybind");
|
||||
const syntax = @import("syntax");
|
||||
|
||||
const Widget = @import("Widget.zig");
|
||||
const MessageFilter = @import("MessageFilter.zig");
|
||||
|
@ -21,31 +20,29 @@ const MainView = @import("mainview.zig");
|
|||
const Allocator = std.mem.Allocator;
|
||||
|
||||
allocator: Allocator,
|
||||
rdr_: renderer,
|
||||
config_: @import("config"),
|
||||
highlight_columns_: []u16,
|
||||
rdr: renderer,
|
||||
config: @import("config"),
|
||||
frame_time: usize, // in microseconds
|
||||
frame_clock: tp.metronome,
|
||||
frame_clock_running: bool = false,
|
||||
frame_last_time: i64 = 0,
|
||||
receiver: Receiver,
|
||||
mainview_: ?Widget = null,
|
||||
message_filters_: MessageFilter.List,
|
||||
input_mode_: ?Mode = null,
|
||||
mainview: ?Widget = null,
|
||||
message_filters: MessageFilter.List,
|
||||
input_mode: ?Mode = null,
|
||||
delayed_init_done: bool = false,
|
||||
delayed_init_input_mode: ?Mode = null,
|
||||
input_mode_outer_: ?Mode = null,
|
||||
input_listeners_: EventHandler.List,
|
||||
input_mode_outer: ?Mode = null,
|
||||
input_listeners: EventHandler.List,
|
||||
keyboard_focus: ?Widget = null,
|
||||
mini_mode_: ?MiniMode = null,
|
||||
mini_mode: ?MiniMode = null,
|
||||
hover_focus: ?*Widget = null,
|
||||
last_hover_x: c_int = -1,
|
||||
last_hover_y: c_int = -1,
|
||||
commands: Commands = undefined,
|
||||
logger: log.Logger,
|
||||
drag_source: ?*Widget = null,
|
||||
theme_: Widget.Theme,
|
||||
parsed_theme: ?std.json.Parsed(Widget.Theme),
|
||||
theme: Widget.Theme,
|
||||
idle_frame_count: usize = 0,
|
||||
unrendered_input_events_count: usize = 0,
|
||||
init_timer: ?tp.timeout,
|
||||
|
@ -56,10 +53,9 @@ render_pending: bool = false,
|
|||
keepalive_timer: ?tp.Cancellable = null,
|
||||
mouse_idle_timer: ?tp.Cancellable = null,
|
||||
default_cursor: keybind.CursorShape = .default,
|
||||
fontface_: []const u8 = "",
|
||||
fontfaces_: std.ArrayListUnmanaged([]const u8) = .{},
|
||||
fontface: []const u8 = "",
|
||||
fontfaces: std.ArrayListUnmanaged([]const u8) = .{},
|
||||
enable_mouse_idle_timer: bool = false,
|
||||
query_cache_: *syntax.QueryCache,
|
||||
|
||||
const keepalive = std.time.us_per_day * 365; // one year
|
||||
const idle_frames = 0;
|
||||
|
@ -86,96 +82,61 @@ fn start(args: StartArgs) tp.result {
|
|||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
||||
const InitError = error{
|
||||
OutOfMemory,
|
||||
UnknownTheme,
|
||||
ThespianMetronomeInitFailed,
|
||||
ThespianMetronomeStartFailed,
|
||||
ThespianTimeoutInitFailed,
|
||||
ThespianSignalInitFailed,
|
||||
ThespianSpawnFailed,
|
||||
} || renderer.Error ||
|
||||
root.ConfigDirError ||
|
||||
root.ConfigWriteError ||
|
||||
keybind.LoadError;
|
||||
|
||||
fn init(allocator: Allocator) InitError!*Self {
|
||||
fn init(allocator: Allocator) !*Self {
|
||||
var conf, const conf_bufs = root.read_config(@import("config"), allocator);
|
||||
defer root.free_config(allocator, conf_bufs);
|
||||
|
||||
if (conf.start_debugger_on_crash)
|
||||
tp.install_debugger();
|
||||
|
||||
const theme_, const parsed_theme = get_theme_by_name(allocator, conf.theme) orelse get_theme_by_name(allocator, "dark_modern") orelse return error.UnknownTheme;
|
||||
const theme_ = get_theme_by_name(conf.theme) orelse get_theme_by_name("dark_modern") orelse return tp.exit("unknown theme");
|
||||
conf.theme = theme_.name;
|
||||
conf.whitespace_mode = try allocator.dupe(u8, conf.whitespace_mode);
|
||||
conf.input_mode = try allocator.dupe(u8, conf.input_mode);
|
||||
conf.top_bar = try allocator.dupe(u8, conf.top_bar);
|
||||
conf.bottom_bar = try allocator.dupe(u8, conf.bottom_bar);
|
||||
conf.include_files = try allocator.dupe(u8, conf.include_files);
|
||||
conf.highlight_columns = try allocator.dupe(u8, conf.highlight_columns);
|
||||
if (build_options.gui) conf.enable_terminal_cursor = false;
|
||||
|
||||
const frame_rate: usize = @intCast(tp.env.get().num("frame-rate"));
|
||||
if (frame_rate != 0)
|
||||
conf.frame_rate = frame_rate;
|
||||
tp.env.get().num_set("frame-rate", @intCast(conf.frame_rate));
|
||||
tp.env.get().num_set("lsp-request-timeout", @intCast(conf.lsp_request_timeout));
|
||||
const frame_time = std.time.us_per_s / conf.frame_rate;
|
||||
const frame_clock = try tp.metronome.init(frame_time);
|
||||
|
||||
const hl_cols: usize = blk: {
|
||||
var it = std.mem.splitScalar(u8, conf.highlight_columns, ' ');
|
||||
var idx: usize = 0;
|
||||
while (it.next()) |_|
|
||||
idx += 1;
|
||||
break :blk idx;
|
||||
};
|
||||
|
||||
var self = try allocator.create(Self);
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.config_ = conf,
|
||||
.highlight_columns_ = try allocator.alloc(u16, hl_cols),
|
||||
.rdr_ = try renderer.init(allocator, self, tp.env.get().is("no-alternate"), dispatch_initialized),
|
||||
.config = conf,
|
||||
.rdr = try renderer.init(allocator, self, tp.env.get().is("no-alternate"), dispatch_initialized),
|
||||
.frame_time = frame_time,
|
||||
.frame_clock = frame_clock,
|
||||
.frame_clock_running = true,
|
||||
.receiver = Receiver.init(receive, self),
|
||||
.message_filters_ = MessageFilter.List.init(allocator),
|
||||
.input_listeners_ = EventHandler.List.init(allocator),
|
||||
.message_filters = MessageFilter.List.init(allocator),
|
||||
.input_listeners = EventHandler.List.init(allocator),
|
||||
.logger = log.logger("tui"),
|
||||
.init_timer = if (build_options.gui) null else try tp.timeout.init_ms(init_delay, tp.message.fmt(
|
||||
.{"init"},
|
||||
)),
|
||||
.theme_ = theme_,
|
||||
.theme = theme_,
|
||||
.no_sleep = tp.env.get().is("no-sleep"),
|
||||
.query_cache_ = try syntax.QueryCache.create(allocator, .{}),
|
||||
.parsed_theme = parsed_theme,
|
||||
};
|
||||
instance_ = self;
|
||||
defer instance_ = null;
|
||||
|
||||
var it = std.mem.splitScalar(u8, conf.highlight_columns, ' ');
|
||||
var idx: usize = 0;
|
||||
while (it.next()) |arg| {
|
||||
self.highlight_columns_[idx] = std.fmt.parseInt(u16, arg, 10) catch 0;
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
self.default_cursor = std.meta.stringToEnum(keybind.CursorShape, conf.default_cursor) orelse .default;
|
||||
self.config_.default_cursor = @tagName(self.default_cursor);
|
||||
self.rdr_.handler_ctx = self;
|
||||
self.rdr_.dispatch_input = dispatch_input;
|
||||
self.rdr_.dispatch_mouse = dispatch_mouse;
|
||||
self.rdr_.dispatch_mouse_drag = dispatch_mouse_drag;
|
||||
self.rdr_.dispatch_event = dispatch_event;
|
||||
try self.rdr_.run();
|
||||
self.config.default_cursor = @tagName(self.default_cursor);
|
||||
self.rdr.handler_ctx = self;
|
||||
self.rdr.dispatch_input = dispatch_input;
|
||||
self.rdr.dispatch_mouse = dispatch_mouse;
|
||||
self.rdr.dispatch_mouse_drag = dispatch_mouse_drag;
|
||||
self.rdr.dispatch_event = dispatch_event;
|
||||
try self.rdr.run();
|
||||
|
||||
try project_manager.start();
|
||||
|
||||
try frame_clock.start();
|
||||
try self.commands.init(self);
|
||||
try keybind.init();
|
||||
errdefer self.deinit();
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
|
@ -185,7 +146,7 @@ fn init(allocator: Allocator) InitError!*Self {
|
|||
try self.listen_sigwinch();
|
||||
},
|
||||
}
|
||||
self.mainview_ = try MainView.create(allocator);
|
||||
self.mainview = try MainView.create(allocator);
|
||||
resize();
|
||||
self.set_terminal_style();
|
||||
try save_config();
|
||||
|
@ -197,20 +158,20 @@ fn init(allocator: Allocator) InitError!*Self {
|
|||
return self;
|
||||
}
|
||||
|
||||
fn init_input_namespace(self: *Self) InitError!void {
|
||||
var mode_parts = std.mem.splitScalar(u8, self.config_.input_mode, '/');
|
||||
fn init_input_namespace(self: *Self) !void {
|
||||
var mode_parts = std.mem.splitScalar(u8, self.config.input_mode, '/');
|
||||
const namespace_name = mode_parts.first();
|
||||
keybind.set_namespace(namespace_name) catch {
|
||||
self.logger.print_err("keybind", "unknown mode {s}", .{namespace_name});
|
||||
try keybind.set_namespace("flow");
|
||||
self.config_.input_mode = "flow";
|
||||
self.config.input_mode = "flow";
|
||||
try save_config();
|
||||
};
|
||||
}
|
||||
|
||||
fn init_delayed(self: *Self) command.Result {
|
||||
fn init_delayed(self: *Self) !void {
|
||||
self.delayed_init_done = true;
|
||||
if (self.input_mode_) |_| {} else {
|
||||
if (self.input_mode) |_| {} else {
|
||||
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
|
||||
try enter_input_mode(self, delayed_init_input_mode);
|
||||
self.delayed_init_input_mode = null;
|
||||
|
@ -231,32 +192,31 @@ fn deinit(self: *Self) void {
|
|||
t.deinit();
|
||||
self.keepalive_timer = null;
|
||||
}
|
||||
if (self.input_mode_) |*m| {
|
||||
if (self.input_mode) |*m| {
|
||||
m.deinit();
|
||||
self.input_mode_ = null;
|
||||
self.input_mode = null;
|
||||
}
|
||||
if (self.delayed_init_input_mode) |*m| {
|
||||
m.deinit();
|
||||
self.delayed_init_input_mode = null;
|
||||
}
|
||||
self.commands.deinit();
|
||||
if (self.mainview_) |*mv| mv.deinit(self.allocator);
|
||||
self.message_filters_.deinit();
|
||||
self.input_listeners_.deinit();
|
||||
if (self.mainview) |*mv| mv.deinit(self.allocator);
|
||||
self.message_filters.deinit();
|
||||
self.input_listeners.deinit();
|
||||
if (self.frame_clock_running)
|
||||
self.frame_clock.stop() catch {};
|
||||
if (self.sigwinch_signal) |sig| sig.deinit();
|
||||
self.frame_clock.deinit();
|
||||
self.rdr_.stop();
|
||||
self.rdr_.deinit();
|
||||
self.rdr.stop();
|
||||
self.rdr.deinit();
|
||||
self.logger.deinit();
|
||||
self.query_cache_.deinit();
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
fn listen_sigwinch(self: *Self) error{ThespianSignalInitFailed}!void {
|
||||
fn listen_sigwinch(self: *Self) tp.result {
|
||||
if (self.sigwinch_signal) |old| old.deinit();
|
||||
self.sigwinch_signal = try tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"}));
|
||||
self.sigwinch_signal = tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"})) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
|
||||
fn update_mouse_idle_timer(self: *Self) void {
|
||||
|
@ -293,7 +253,7 @@ fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
|
|||
|
||||
fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
||||
if (try m.match(.{ "RDR", tp.more })) {
|
||||
self.rdr_.process_renderer_event(m.buf) catch |e| switch (e) {
|
||||
self.rdr.process_renderer_event(m.buf) catch |e| switch (e) {
|
||||
error.UnexpectedRendererEvent => return tp.unexpected(m),
|
||||
else => return e,
|
||||
};
|
||||
|
@ -303,7 +263,7 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
|||
return;
|
||||
}
|
||||
|
||||
if (self.message_filters_.filter(from, m) catch |e| return self.logger.err("filter", e))
|
||||
if (self.message_filters.filter(from, m) catch |e| return self.logger.err("filter", e))
|
||||
return;
|
||||
|
||||
var cmd: []const u8 = undefined;
|
||||
|
@ -342,7 +302,7 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
|||
if (builtin.os.tag != .windows)
|
||||
if (try m.match(.{"sigwinch"})) {
|
||||
try self.listen_sigwinch();
|
||||
self.rdr_.sigwinch() catch |e| return self.logger.err("query_resize", e);
|
||||
self.rdr.sigwinch() catch |e| return self.logger.err("query_resize", e);
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -430,14 +390,14 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
|||
|
||||
var fontface_: []const u8 = undefined;
|
||||
if (try m.match(.{ "fontface", "current", tp.extract(&fontface_) })) {
|
||||
if (self.fontface_.len > 0) self.allocator.free(self.fontface_);
|
||||
self.fontface_ = "";
|
||||
self.fontface_ = try self.allocator.dupe(u8, fontface_);
|
||||
if (self.fontface.len > 0) self.allocator.free(self.fontface);
|
||||
self.fontface = "";
|
||||
self.fontface = try self.allocator.dupe(u8, fontface_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (try m.match(.{ "fontface", tp.extract(&fontface_) })) {
|
||||
try self.fontfaces_.append(self.allocator, try self.allocator.dupe(u8, fontface_));
|
||||
try self.fontfaces.append(self.allocator, try self.allocator.dupe(u8, fontface_));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -460,20 +420,20 @@ fn render(self: *Self) void {
|
|||
{
|
||||
const frame = tracy.initZone(@src(), .{ .name = "tui update" });
|
||||
defer frame.deinit();
|
||||
if (self.mainview_) |mv| mv.update();
|
||||
if (self.mainview) |mv| mv.update();
|
||||
}
|
||||
|
||||
const more = ret: {
|
||||
const frame = tracy.initZone(@src(), .{ .name = "tui render" });
|
||||
defer frame.deinit();
|
||||
self.rdr_.stdplane().erase();
|
||||
break :ret if (self.mainview_) |mv| mv.render(&self.theme_) else false;
|
||||
self.rdr.stdplane().erase();
|
||||
break :ret if (self.mainview) |mv| mv.render(&self.theme) else false;
|
||||
};
|
||||
|
||||
{
|
||||
const frame = tracy.initZone(@src(), .{ .name = renderer.log_name ++ " render" });
|
||||
defer frame.deinit();
|
||||
self.rdr_.render() catch |e| self.logger.err("render", e);
|
||||
self.rdr.render() catch |e| self.logger.err("render", e);
|
||||
tracy.frameMark();
|
||||
}
|
||||
|
||||
|
@ -497,13 +457,13 @@ fn render(self: *Self) void {
|
|||
}
|
||||
|
||||
fn active_event_handler(self: *Self) ?EventHandler {
|
||||
const mode = self.input_mode_ orelse return null;
|
||||
const mode = self.input_mode orelse return null;
|
||||
return mode.event_handler orelse mode.input_handler;
|
||||
}
|
||||
|
||||
fn dispatch_flush_input_event(self: *Self) error{ Exit, NoSpaceLeft }!void {
|
||||
fn dispatch_flush_input_event(self: *Self) !void {
|
||||
var buf: [32]u8 = undefined;
|
||||
const mode = self.input_mode_ orelse return;
|
||||
const mode = self.input_mode orelse return;
|
||||
try mode.input_handler.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"}));
|
||||
if (mode.event_handler) |eh| try eh.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"}));
|
||||
}
|
||||
|
@ -520,14 +480,14 @@ fn dispatch_input(ctx: *anyopaque, cbor_msg: []const u8) void {
|
|||
const m: tp.message = .{ .buf = cbor_msg };
|
||||
const from = tp.self_pid();
|
||||
self.unrendered_input_events_count += 1;
|
||||
self.input_listeners_.send(from, m) catch {};
|
||||
self.input_listeners.send(from, m) catch {};
|
||||
if (self.keyboard_focus) |w|
|
||||
if (w.send(from, m) catch |e| ret: {
|
||||
self.logger.err("focus", e);
|
||||
break :ret false;
|
||||
})
|
||||
return;
|
||||
if (self.input_mode_) |mode|
|
||||
if (self.input_mode) |mode|
|
||||
mode.input_handler.send(from, m) catch |e| self.logger.err("input handler", e);
|
||||
}
|
||||
|
||||
|
@ -575,7 +535,7 @@ fn find_coord_widget(self: *Self, y: usize, x: usize) ?*Widget {
|
|||
}
|
||||
};
|
||||
var ctx: Ctx = .{ .y = y, .x = x };
|
||||
if (self.mainview_) |*mv| _ = mv.walk(&ctx, Ctx.find);
|
||||
if (self.mainview) |*mv| _ = mv.walk(&ctx, Ctx.find);
|
||||
return ctx.widget;
|
||||
}
|
||||
|
||||
|
@ -592,7 +552,7 @@ fn is_live_widget_ptr(self: *Self, w_: *Widget) bool {
|
|||
}
|
||||
};
|
||||
var ctx: Ctx = .{ .w = w_ };
|
||||
return if (self.mainview_) |*mv| mv.walk(&ctx, Ctx.find) else false;
|
||||
return if (self.mainview) |*mv| mv.walk(&ctx, Ctx.find) else false;
|
||||
}
|
||||
|
||||
fn send_widgets(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||
|
@ -601,7 +561,7 @@ fn send_widgets(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
tp.trace(tp.channel.widget, m);
|
||||
return if (self.keyboard_focus) |w|
|
||||
w.send(from, m)
|
||||
else if (self.mainview_) |mv|
|
||||
else if (self.mainview) |mv|
|
||||
mv.send(from, m)
|
||||
else
|
||||
false;
|
||||
|
@ -609,7 +569,7 @@ fn send_widgets(self: *Self, from: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|||
|
||||
fn send_mouse(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.message) tp.result {
|
||||
tp.trace(tp.channel.input, m);
|
||||
_ = self.input_listeners_.send(from, m) catch {};
|
||||
_ = self.input_listeners.send(from, m) catch {};
|
||||
if (self.keyboard_focus) |w| {
|
||||
_ = try w.send(from, m);
|
||||
return;
|
||||
|
@ -620,7 +580,7 @@ fn send_mouse(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.message)
|
|||
|
||||
fn send_mouse_drag(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.message) tp.result {
|
||||
tp.trace(tp.channel.input, m);
|
||||
_ = self.input_listeners_.send(from, m) catch {};
|
||||
_ = self.input_listeners.send(from, m) catch {};
|
||||
if (self.keyboard_focus) |w| {
|
||||
_ = try w.send(from, m);
|
||||
return;
|
||||
|
@ -663,24 +623,23 @@ pub fn refresh_hover() void {
|
|||
_ = self.update_hover(self.last_hover_y, self.last_hover_x) catch {};
|
||||
}
|
||||
|
||||
pub fn save_config() (root.ConfigDirError || root.ConfigWriteError)!void {
|
||||
pub fn save_config() !void {
|
||||
const self = current();
|
||||
try root.write_config(self.config_, self.allocator);
|
||||
try root.write_config(self.config, self.allocator);
|
||||
}
|
||||
|
||||
pub fn is_mainview_focused() bool {
|
||||
const self = current();
|
||||
return self.mini_mode_ == null and self.input_mode_outer_ == null;
|
||||
return self.mini_mode == null and self.input_mode_outer == null;
|
||||
}
|
||||
|
||||
fn enter_overlay_mode(self: *Self, mode: type) command.Result {
|
||||
command.executeName("disable_fast_scroll", .{}) catch {};
|
||||
command.executeName("disable_jump_mode", .{}) catch {};
|
||||
if (self.mini_mode_) |_| try cmds.exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer_) |_| try cmds.exit_overlay_mode(self, .{});
|
||||
self.input_mode_outer_ = self.input_mode_;
|
||||
self.input_mode_ = try mode.create(self.allocator);
|
||||
if (self.input_mode_) |*m| m.run_init();
|
||||
if (self.mini_mode) |_| try cmds.exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer) |_| try cmds.exit_overlay_mode(self, .{});
|
||||
self.input_mode_outer = self.input_mode;
|
||||
self.input_mode = try mode.create(self.allocator);
|
||||
refresh_hover();
|
||||
}
|
||||
|
||||
|
@ -689,49 +648,35 @@ fn get_input_mode(self: *Self, mode_name: []const u8) !Mode {
|
|||
}
|
||||
|
||||
fn enter_input_mode(self: *Self, new_mode: Mode) command.Result {
|
||||
if (self.mini_mode_) |_| try cmds.exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer_) |_| try cmds.exit_overlay_mode(self, .{});
|
||||
if (self.input_mode_) |*m| {
|
||||
if (self.mini_mode) |_| try cmds.exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer) |_| try cmds.exit_overlay_mode(self, .{});
|
||||
if (self.input_mode) |*m| {
|
||||
m.deinit();
|
||||
self.input_mode_ = null;
|
||||
self.input_mode = null;
|
||||
}
|
||||
self.input_mode_ = new_mode;
|
||||
if (self.input_mode_) |*m| m.run_init();
|
||||
self.input_mode = new_mode;
|
||||
}
|
||||
|
||||
fn refresh_input_mode(self: *Self) command.Result {
|
||||
const mode = (self.input_mode_ orelse return).mode;
|
||||
const mode = (self.input_mode orelse return).mode;
|
||||
var new_mode = self.get_input_mode(mode) catch ret: {
|
||||
self.logger.print("unknown mode {s}", .{mode});
|
||||
break :ret try self.get_input_mode(keybind.default_mode);
|
||||
};
|
||||
errdefer new_mode.deinit();
|
||||
if (self.input_mode_) |*m| {
|
||||
if (self.input_mode) |*m| {
|
||||
m.deinit();
|
||||
self.input_mode_ = null;
|
||||
self.input_mode = null;
|
||||
}
|
||||
self.input_mode_ = new_mode;
|
||||
if (self.input_mode_) |*m| m.run_init();
|
||||
}
|
||||
|
||||
fn set_theme_by_name(self: *Self, name: []const u8) !void {
|
||||
const old = self.parsed_theme;
|
||||
defer if (old) |p| p.deinit();
|
||||
self.theme_, self.parsed_theme = get_theme_by_name(self.allocator, name) orelse {
|
||||
self.logger.print("theme not found: {s}", .{name});
|
||||
return;
|
||||
};
|
||||
self.config_.theme = self.theme_.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme_.description});
|
||||
try save_config();
|
||||
self.input_mode = new_mode;
|
||||
}
|
||||
pub const enter_mode_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
const cmds = struct {
|
||||
pub const Target = Self;
|
||||
const Ctx = command.Context;
|
||||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
const Meta = command.Metadata;
|
||||
|
||||
pub fn restart(_: *Self, _: Ctx) Result {
|
||||
try tp.self_pid().send("restart");
|
||||
|
@ -743,54 +688,67 @@ const cmds = struct {
|
|||
root.print_exit_status({}, "FORCE TERMINATE");
|
||||
root.exit(99);
|
||||
}
|
||||
pub const force_terminate_meta: Meta = .{ .description = "Force quit without saving" };
|
||||
pub const force_terminate_meta = .{ .description = "Force quit without saving" };
|
||||
|
||||
pub fn set_theme(self: *Self, ctx: Ctx) Result {
|
||||
var name: []const u8 = undefined;
|
||||
if (!try ctx.args.match(.{tp.extract(&name)}))
|
||||
return tp.exit_error(error.InvalidSetThemeArgument, null);
|
||||
return self.set_theme_by_name(name);
|
||||
self.theme = get_theme_by_name(name) orelse {
|
||||
self.logger.print("theme not found: {s}", .{name});
|
||||
return;
|
||||
};
|
||||
self.config.theme = self.theme.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme.description});
|
||||
try save_config();
|
||||
}
|
||||
pub const set_theme_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const set_theme_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn theme_next(self: *Self, _: Ctx) Result {
|
||||
const name = get_next_theme_by_name(self.theme_.name);
|
||||
return self.set_theme_by_name(name);
|
||||
self.theme = get_next_theme_by_name(self.theme.name);
|
||||
self.config.theme = self.theme.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme.description});
|
||||
try save_config();
|
||||
}
|
||||
pub const theme_next_meta: Meta = .{ .description = "Next color theme" };
|
||||
|
||||
pub fn theme_prev(self: *Self, _: Ctx) Result {
|
||||
const name = get_prev_theme_by_name(self.theme_.name);
|
||||
return self.set_theme_by_name(name);
|
||||
self.theme = get_prev_theme_by_name(self.theme.name);
|
||||
self.config.theme = self.theme.name;
|
||||
self.set_terminal_style();
|
||||
self.logger.print("theme: {s}", .{self.theme.description});
|
||||
try save_config();
|
||||
}
|
||||
pub const theme_prev_meta: Meta = .{ .description = "Previous color theme" };
|
||||
|
||||
pub fn toggle_whitespace_mode(self: *Self, _: Ctx) Result {
|
||||
self.config_.whitespace_mode = if (std.mem.eql(u8, self.config_.whitespace_mode, "none"))
|
||||
self.config.whitespace_mode = if (std.mem.eql(u8, self.config.whitespace_mode, "none"))
|
||||
"indent"
|
||||
else if (std.mem.eql(u8, self.config_.whitespace_mode, "indent"))
|
||||
else if (std.mem.eql(u8, self.config.whitespace_mode, "indent"))
|
||||
"leading"
|
||||
else if (std.mem.eql(u8, self.config_.whitespace_mode, "leading"))
|
||||
else if (std.mem.eql(u8, self.config.whitespace_mode, "leading"))
|
||||
"eol"
|
||||
else if (std.mem.eql(u8, self.config_.whitespace_mode, "eol"))
|
||||
else if (std.mem.eql(u8, self.config.whitespace_mode, "eol"))
|
||||
"tabs"
|
||||
else if (std.mem.eql(u8, self.config_.whitespace_mode, "tabs"))
|
||||
else if (std.mem.eql(u8, self.config.whitespace_mode, "tabs"))
|
||||
"visible"
|
||||
else if (std.mem.eql(u8, self.config_.whitespace_mode, "visible"))
|
||||
else if (std.mem.eql(u8, self.config.whitespace_mode, "visible"))
|
||||
"full"
|
||||
else
|
||||
"none";
|
||||
try save_config();
|
||||
var buf: [32]u8 = undefined;
|
||||
const m = try tp.message.fmtbuf(&buf, .{ "whitespace_mode", self.config_.whitespace_mode });
|
||||
const m = try tp.message.fmtbuf(&buf, .{ "whitespace_mode", self.config.whitespace_mode });
|
||||
_ = try self.send_widgets(tp.self_pid(), m);
|
||||
self.logger.print("whitespace rendering {s}", .{self.config_.whitespace_mode});
|
||||
self.logger.print("whitespace rendering {s}", .{self.config.whitespace_mode});
|
||||
}
|
||||
pub const toggle_whitespace_mode_meta: Meta = .{ .description = "Next whitespace mode" };
|
||||
|
||||
pub fn toggle_input_mode(self: *Self, _: Ctx) Result {
|
||||
var it = std.mem.splitScalar(u8, self.config_.input_mode, '/');
|
||||
self.config_.input_mode = it.first();
|
||||
var it = std.mem.splitScalar(u8, self.config.input_mode, '/');
|
||||
self.config.input_mode = it.first();
|
||||
|
||||
const namespaces = keybind.get_namespaces(self.allocator) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
defer {
|
||||
|
@ -798,15 +756,15 @@ const cmds = struct {
|
|||
self.allocator.free(namespaces);
|
||||
}
|
||||
var found = false;
|
||||
self.config_.input_mode = blk: for (namespaces) |namespace| {
|
||||
self.config.input_mode = blk: for (namespaces) |namespace| {
|
||||
if (found) break :blk try self.allocator.dupe(u8, namespace);
|
||||
if (std.mem.eql(u8, namespace, self.config_.input_mode))
|
||||
if (std.mem.eql(u8, namespace, self.config.input_mode))
|
||||
found = true;
|
||||
} else try self.allocator.dupe(u8, namespaces[0]);
|
||||
|
||||
try save_config();
|
||||
self.logger.print("input mode {s}", .{self.config_.input_mode});
|
||||
try keybind.set_namespace(self.config_.input_mode);
|
||||
self.logger.print("input mode {s}", .{self.config.input_mode});
|
||||
try keybind.set_namespace(self.config.input_mode);
|
||||
return self.refresh_input_mode();
|
||||
}
|
||||
pub const toggle_input_mode_meta: Meta = .{ .description = "Switch input mode" };
|
||||
|
@ -828,12 +786,12 @@ const cmds = struct {
|
|||
}
|
||||
return self.enter_input_mode(new_mode);
|
||||
}
|
||||
pub const enter_mode_meta: Meta = .{ .arguments = &.{.string} };
|
||||
pub const enter_mode_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn enter_mode_default(self: *Self, _: Ctx) Result {
|
||||
return enter_mode(self, Ctx.fmt(.{keybind.default_mode}));
|
||||
}
|
||||
pub const enter_mode_default_meta: Meta = .{};
|
||||
pub const enter_mode_default_meta = .{};
|
||||
|
||||
pub fn open_command_palette(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/command_palette.zig").Type);
|
||||
|
@ -863,7 +821,7 @@ const cmds = struct {
|
|||
pub fn switch_buffers(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/buffer_palette.zig").Type);
|
||||
}
|
||||
pub const switch_buffers_meta: Meta = .{ .description = "Switch buffers" };
|
||||
pub const switch_buffers_meta = .{ .description = "Switch buffers" };
|
||||
|
||||
pub fn select_task(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/task_palette.zig").Type);
|
||||
|
@ -896,7 +854,7 @@ const cmds = struct {
|
|||
return error.InvalidDeleteTaskArgument;
|
||||
project_manager.delete_task(task) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
}
|
||||
pub const delete_task_meta: Meta = .{};
|
||||
pub const delete_task_meta = .{};
|
||||
|
||||
pub fn change_theme(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/theme_palette.zig").Type);
|
||||
|
@ -906,23 +864,23 @@ const cmds = struct {
|
|||
pub fn change_file_type(self: *Self, _: Ctx) Result {
|
||||
return self.enter_overlay_mode(@import("mode/overlay/file_type_palette.zig").Type);
|
||||
}
|
||||
pub const change_file_type_meta: Meta = .{ .description = "Change file type" };
|
||||
pub const change_file_type_meta = .{ .description = "Change file type" };
|
||||
|
||||
pub fn change_fontface(self: *Self, _: Ctx) Result {
|
||||
if (build_options.gui)
|
||||
self.rdr_.get_fontfaces();
|
||||
self.rdr.get_fontfaces();
|
||||
}
|
||||
pub const change_fontface_meta: Meta = .{ .description = "Change font" };
|
||||
|
||||
pub fn exit_overlay_mode(self: *Self, _: Ctx) Result {
|
||||
self.rdr_.cursor_disable();
|
||||
if (self.input_mode_outer_ == null) return enter_mode_default(self, .{});
|
||||
if (self.input_mode_) |*mode| mode.deinit();
|
||||
self.input_mode_ = self.input_mode_outer_;
|
||||
self.input_mode_outer_ = null;
|
||||
self.rdr.cursor_disable();
|
||||
if (self.input_mode_outer == null) return enter_mode_default(self, .{});
|
||||
if (self.input_mode) |*mode| mode.deinit();
|
||||
self.input_mode = self.input_mode_outer;
|
||||
self.input_mode_outer = null;
|
||||
refresh_hover();
|
||||
}
|
||||
pub const exit_overlay_mode_meta: Meta = .{};
|
||||
pub const exit_overlay_mode_meta = .{};
|
||||
|
||||
pub fn find(self: *Self, ctx: Ctx) Result {
|
||||
return enter_mini_mode(self, @import("mode/mini/find.zig"), ctx);
|
||||
|
@ -937,7 +895,7 @@ const cmds = struct {
|
|||
pub fn goto(self: *Self, ctx: Ctx) Result {
|
||||
return enter_mini_mode(self, @import("mode/mini/goto.zig"), ctx);
|
||||
}
|
||||
pub const goto_meta: Meta = .{ .description = "Goto line" };
|
||||
pub const goto_meta = .{ .description = "Goto line" };
|
||||
|
||||
pub fn move_to_char(self: *Self, ctx: Ctx) Result {
|
||||
return enter_mini_mode(self, @import("mode/mini/move_to_char.zig"), ctx);
|
||||
|
@ -956,51 +914,43 @@ const cmds = struct {
|
|||
}
|
||||
return enter_mini_mode(self, @import("mode/mini/open_file.zig"), ctx);
|
||||
}
|
||||
pub const open_file_meta: Meta = .{ .description = "Open file" };
|
||||
pub const open_file_meta = .{ .description = "Open file" };
|
||||
|
||||
pub fn save_as(self: *Self, ctx: Ctx) Result {
|
||||
return enter_mini_mode(self, @import("mode/mini/save_as.zig"), ctx);
|
||||
}
|
||||
pub const save_as_meta: Meta = .{ .description = "Save as" };
|
||||
pub const save_as_meta = .{ .description = "Save as" };
|
||||
|
||||
fn enter_mini_mode(self: *Self, comptime mode: anytype, ctx: Ctx) !void {
|
||||
command.executeName("disable_fast_scroll", .{}) catch {};
|
||||
command.executeName("disable_jump_mode", .{}) catch {};
|
||||
const input_mode_, const mini_mode_ = try mode.create(self.allocator, ctx);
|
||||
if (self.mini_mode_) |_| try exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer_) |_| try exit_overlay_mode(self, .{});
|
||||
if (self.input_mode_outer_ != null) @panic("exit_overlay_mode failed");
|
||||
self.input_mode_outer_ = self.input_mode_;
|
||||
self.input_mode_ = input_mode_;
|
||||
self.mini_mode_ = mini_mode_;
|
||||
if (self.input_mode_) |*m| m.run_init();
|
||||
if (self.mini_mode) |_| try exit_mini_mode(self, .{});
|
||||
if (self.input_mode_outer) |_| try exit_overlay_mode(self, .{});
|
||||
if (self.input_mode_outer != null) @panic("exit_overlay_mode failed");
|
||||
self.input_mode_outer = self.input_mode;
|
||||
self.input_mode = input_mode_;
|
||||
self.mini_mode = mini_mode_;
|
||||
}
|
||||
|
||||
pub fn exit_mini_mode(self: *Self, _: Ctx) Result {
|
||||
self.rdr_.cursor_disable();
|
||||
if (self.mini_mode_) |_| {} else return;
|
||||
if (self.input_mode_) |*mode| mode.deinit();
|
||||
self.input_mode_ = self.input_mode_outer_;
|
||||
self.input_mode_outer_ = null;
|
||||
self.mini_mode_ = null;
|
||||
self.rdr.cursor_disable();
|
||||
if (self.mini_mode) |_| {} else return;
|
||||
if (self.input_mode) |*mode| mode.deinit();
|
||||
self.input_mode = self.input_mode_outer;
|
||||
self.input_mode_outer = null;
|
||||
self.mini_mode = null;
|
||||
}
|
||||
pub const exit_mini_mode_meta: Meta = .{};
|
||||
pub const exit_mini_mode_meta = .{};
|
||||
|
||||
pub fn open_keybind_config(self: *Self, _: Ctx) Result {
|
||||
var mode_parts = std.mem.splitScalar(u8, self.config_.input_mode, '/');
|
||||
var mode_parts = std.mem.splitScalar(u8, self.config.input_mode, '/');
|
||||
const namespace_name = mode_parts.first();
|
||||
const file_name = try keybind.get_or_create_namespace_config_file(self.allocator, namespace_name);
|
||||
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name } });
|
||||
self.logger.print("restart flow to use changed key bindings", .{});
|
||||
}
|
||||
pub const open_keybind_config_meta: Meta = .{ .description = "Edit key bindings" };
|
||||
|
||||
pub fn open_custom_theme(self: *Self, _: Ctx) Result {
|
||||
const file_name = try self.get_or_create_theme_file(self.allocator);
|
||||
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_name } });
|
||||
self.logger.print("restart flow to use changed theme", .{});
|
||||
}
|
||||
pub const open_custom_theme_meta: Meta = .{ .description = "Customize theme" };
|
||||
pub const open_keybind_config_meta = .{ .description = "Edit key bindings" };
|
||||
|
||||
pub fn run_async(self: *Self, ctx: Ctx) Result {
|
||||
var iter = ctx.args.buf;
|
||||
|
@ -1041,27 +991,27 @@ const cmds = struct {
|
|||
}
|
||||
try tp.self_pid().send_raw(.{ .buf = msg_cb.items });
|
||||
}
|
||||
pub const run_async_meta: Meta = .{};
|
||||
pub const run_async_meta = .{};
|
||||
|
||||
pub fn enter_vim_mode(_: *Self, _: Ctx) Result {
|
||||
try @import("mode/vim.zig").init();
|
||||
}
|
||||
pub const enter_vim_mode_meta: Meta = .{};
|
||||
pub const enter_vim_mode_meta = .{};
|
||||
|
||||
pub fn exit_vim_mode(_: *Self, _: Ctx) Result {
|
||||
@import("mode/vim.zig").deinit();
|
||||
}
|
||||
pub const exit_vim_mode_meta: Meta = .{};
|
||||
pub const exit_vim_mode_meta = .{};
|
||||
|
||||
pub fn enter_helix_mode(_: *Self, _: Ctx) Result {
|
||||
try @import("mode/helix.zig").init();
|
||||
}
|
||||
pub const enter_helix_mode_meta: Meta = .{};
|
||||
pub const enter_helix_mode_meta = .{};
|
||||
|
||||
pub fn exit_helix_mode(_: *Self, _: Ctx) Result {
|
||||
@import("mode/helix.zig").deinit();
|
||||
}
|
||||
pub const exit_helix_mode_meta: Meta = .{};
|
||||
pub const exit_helix_mode_meta = .{};
|
||||
};
|
||||
|
||||
pub const MiniMode = struct {
|
||||
|
@ -1080,51 +1030,43 @@ fn current() *Self {
|
|||
}
|
||||
|
||||
pub fn rdr() *renderer {
|
||||
return ¤t().rdr_;
|
||||
return ¤t().rdr;
|
||||
}
|
||||
|
||||
pub fn message_filters() *MessageFilter.List {
|
||||
return ¤t().message_filters_;
|
||||
return ¤t().message_filters;
|
||||
}
|
||||
|
||||
pub fn input_listeners() *EventHandler.List {
|
||||
return ¤t().input_listeners_;
|
||||
return ¤t().input_listeners;
|
||||
}
|
||||
|
||||
pub fn input_mode() ?*Mode {
|
||||
return if (current().input_mode_) |*p| p else null;
|
||||
return if (current().input_mode) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn input_mode_outer() ?*Mode {
|
||||
return if (current().input_mode_outer_) |*p| p else null;
|
||||
return if (current().input_mode_outer) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn mini_mode() ?*MiniMode {
|
||||
return if (current().mini_mode_) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn query_cache() *syntax.QueryCache {
|
||||
return current().query_cache_;
|
||||
return if (current().mini_mode) |*p| p else null;
|
||||
}
|
||||
|
||||
pub fn config() *const @import("config") {
|
||||
return ¤t().config_;
|
||||
}
|
||||
|
||||
pub fn highlight_columns() []const u16 {
|
||||
return current().highlight_columns_;
|
||||
return ¤t().config;
|
||||
}
|
||||
|
||||
pub fn config_mut() *@import("config") {
|
||||
return ¤t().config_;
|
||||
return ¤t().config;
|
||||
}
|
||||
|
||||
pub fn mainview() ?*MainView {
|
||||
return if (current().mainview_) |*mv| mv.dynamic_cast(MainView) else null;
|
||||
return if (current().mainview) |*mv| mv.dynamic_cast(MainView) else null;
|
||||
}
|
||||
|
||||
pub fn mainview_widget() Widget {
|
||||
return current().mainview_ orelse @panic("tui main view not found");
|
||||
return current().mainview orelse @panic("tui main view not found");
|
||||
}
|
||||
|
||||
pub fn get_active_editor() ?*@import("editor.zig").Editor {
|
||||
|
@ -1148,9 +1090,9 @@ fn context_check() void {
|
|||
}
|
||||
|
||||
pub fn get_mode() []const u8 {
|
||||
return if (current().mini_mode_) |m|
|
||||
return if (current().mini_mode) |m|
|
||||
m.name
|
||||
else if (current().input_mode_) |m|
|
||||
else if (current().input_mode) |m|
|
||||
m.name
|
||||
else
|
||||
"INI";
|
||||
|
@ -1158,7 +1100,7 @@ pub fn get_mode() []const u8 {
|
|||
|
||||
pub fn get_keybind_mode() ?Mode {
|
||||
const self = current();
|
||||
return self.input_mode_ orelse self.delayed_init_input_mode;
|
||||
return self.input_mode orelse self.delayed_init_input_mode;
|
||||
}
|
||||
|
||||
pub fn reset_drag_context() void {
|
||||
|
@ -1181,11 +1123,11 @@ pub fn resize() void {
|
|||
}
|
||||
|
||||
pub fn plane() renderer.Plane {
|
||||
return current().rdr_.stdplane();
|
||||
return current().rdr.stdplane();
|
||||
}
|
||||
|
||||
fn stdplane(self: *Self) renderer.Plane {
|
||||
return self.rdr_.stdplane();
|
||||
return self.rdr.stdplane();
|
||||
}
|
||||
|
||||
pub fn egc_chunk_width(chunk: []const u8, abs_col: usize, tab_width: usize) usize {
|
||||
|
@ -1201,49 +1143,44 @@ pub fn screen() Widget.Box {
|
|||
}
|
||||
|
||||
pub fn fontface() []const u8 {
|
||||
return current().fontface_;
|
||||
return current().fontface;
|
||||
}
|
||||
|
||||
pub fn fontfaces(allocator: std.mem.Allocator) error{OutOfMemory}![][]const u8 {
|
||||
return current().fontfaces_.toOwnedSlice(allocator);
|
||||
return current().fontfaces.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
pub fn theme() *const Widget.Theme {
|
||||
return ¤t().theme_;
|
||||
return ¤t().theme;
|
||||
}
|
||||
|
||||
pub fn get_theme_by_name(allocator: std.mem.Allocator, name: []const u8) ?struct { Widget.Theme, ?std.json.Parsed(Widget.Theme) } {
|
||||
if (load_theme_file(allocator, name) catch null) |parsed_theme| {
|
||||
std.log.info("loaded theme from file: {s}", .{name});
|
||||
return .{ parsed_theme.value, parsed_theme };
|
||||
}
|
||||
|
||||
pub fn get_theme_by_name(name: []const u8) ?Widget.Theme {
|
||||
for (Widget.themes) |theme_| {
|
||||
if (std.mem.eql(u8, theme_.name, name))
|
||||
return .{ theme_, null };
|
||||
return theme_;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn get_next_theme_by_name(name: []const u8) []const u8 {
|
||||
pub fn get_next_theme_by_name(name: []const u8) Widget.Theme {
|
||||
var next = false;
|
||||
for (Widget.themes) |theme_| {
|
||||
if (next)
|
||||
return theme_.name;
|
||||
return theme_;
|
||||
if (std.mem.eql(u8, theme_.name, name))
|
||||
next = true;
|
||||
}
|
||||
return Widget.themes[0].name;
|
||||
return Widget.themes[0];
|
||||
}
|
||||
|
||||
fn get_prev_theme_by_name(name: []const u8) []const u8 {
|
||||
pub fn get_prev_theme_by_name(name: []const u8) Widget.Theme {
|
||||
var prev: ?Widget.Theme = null;
|
||||
for (Widget.themes) |theme_| {
|
||||
if (std.mem.eql(u8, theme_.name, name))
|
||||
return (prev orelse Widget.themes[Widget.themes.len - 1]).name;
|
||||
return prev orelse Widget.themes[Widget.themes.len - 1];
|
||||
prev = theme_;
|
||||
}
|
||||
return Widget.themes[Widget.themes.len - 1].name;
|
||||
return Widget.themes[Widget.themes.len - 1];
|
||||
}
|
||||
|
||||
pub fn find_scope_style(theme_: *const Widget.Theme, scope: []const u8) ?Widget.Theme.Token {
|
||||
|
@ -1332,15 +1269,15 @@ pub const fallbacks: []const FallBack = &[_]FallBack{
|
|||
};
|
||||
|
||||
fn set_terminal_style(self: *Self) void {
|
||||
if (build_options.gui or self.config_.enable_terminal_color_scheme) {
|
||||
self.rdr_.set_terminal_style(self.theme_.editor);
|
||||
self.rdr_.set_terminal_cursor_color(self.theme_.editor_cursor.bg.?);
|
||||
if (build_options.gui or self.config.enable_terminal_color_scheme) {
|
||||
self.rdr.set_terminal_style(self.theme.editor);
|
||||
self.rdr.set_terminal_cursor_color(self.theme.editor_cursor.bg.?);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_shape() renderer.CursorShape {
|
||||
const self = current();
|
||||
const shape = if (self.input_mode_) |mode| mode.cursor_shape orelse self.default_cursor else self.default_cursor;
|
||||
const shape = if (self.input_mode) |mode| mode.cursor_shape orelse self.default_cursor else self.default_cursor;
|
||||
return switch (shape) {
|
||||
.default => .default,
|
||||
.block_blink => .block_blink,
|
||||
|
@ -1360,7 +1297,7 @@ pub fn is_cursor_beam() bool {
|
|||
}
|
||||
|
||||
pub fn get_selection_style() @import("Buffer").Selection.Style {
|
||||
return if (current().input_mode_) |mode| mode.selection_style else .normal;
|
||||
return if (current().input_mode) |mode| mode.selection_style else .normal;
|
||||
}
|
||||
|
||||
pub fn message(comptime fmt: anytype, args: anytype) void {
|
||||
|
@ -1386,32 +1323,3 @@ pub fn render_match_cell(self: *renderer.Plane, y: usize, x: usize, theme_: *con
|
|||
cell.set_style(theme_.editor_match);
|
||||
_ = self.putc(&cell) catch {};
|
||||
}
|
||||
|
||||
fn get_or_create_theme_file(self: *Self, allocator: std.mem.Allocator) ![]const u8 {
|
||||
const theme_name = self.theme_.name;
|
||||
if (root.read_theme(allocator, theme_name)) |content| {
|
||||
allocator.free(content);
|
||||
} else {
|
||||
var buf = std.ArrayList(u8).init(self.allocator);
|
||||
defer buf.deinit();
|
||||
try std.json.stringify(self.theme_, .{ .whitespace = .indent_2 }, buf.writer());
|
||||
try root.write_theme(
|
||||
theme_name,
|
||||
buf.items,
|
||||
);
|
||||
}
|
||||
return try root.get_theme_file_name(theme_name);
|
||||
}
|
||||
|
||||
fn load_theme_file(allocator: std.mem.Allocator, theme_name: []const u8) !?std.json.Parsed(Widget.Theme) {
|
||||
return load_theme_file_internal(allocator, theme_name) catch |e| {
|
||||
std.log.err("loaded theme from file failed: {}", .{e});
|
||||
return e;
|
||||
};
|
||||
}
|
||||
fn load_theme_file_internal(allocator: std.mem.Allocator, theme_name: []const u8) !?std.json.Parsed(Widget.Theme) {
|
||||
_ = std.json.Scanner;
|
||||
const json_str = root.read_theme(allocator, theme_name) orelse return null;
|
||||
defer allocator.free(json_str);
|
||||
return try std.json.parseFromSlice(Widget.Theme, allocator, json_str, .{ .allocate = .alloc_always });
|
||||
}
|
||||
|
|
|
@ -41,12 +41,12 @@ pub const Font = struct {
|
|||
);
|
||||
if (hr < 0) std.debug.panic(
|
||||
"CreateTextFormat '{}' height {d} failed, hresult=0x{x}",
|
||||
.{ std.unicode.fmtUtf16Le(face.slice()), size, @as(u32, @bitCast(hr)) },
|
||||
.{ std.unicode.fmtUtf16le(face.slice()), size, @as(u32, @bitCast(hr)) },
|
||||
);
|
||||
}
|
||||
errdefer _ = text_format.IUnknown.Release();
|
||||
|
||||
const cell_size: XY(u16) = blk: {
|
||||
const cell_size = blk: {
|
||||
var text_layout: *win32.IDWriteTextLayout = undefined;
|
||||
{
|
||||
const hr = global.dwrite_factory.CreateTextLayout(
|
||||
|
|
|
@ -143,7 +143,7 @@ fn getConfig() *gui_config {
|
|||
}
|
||||
|
||||
fn getFieldDefault(field: std.builtin.Type.StructField) ?*const field.type {
|
||||
return @alignCast(@ptrCast(field.default_value_ptr orelse return null));
|
||||
return @alignCast(@ptrCast(field.default_value orelse return null));
|
||||
}
|
||||
|
||||
fn getDefaultFontFace() FontFace {
|
||||
|
|
Loading…
Add table
Reference in a new issue