Compare commits
No commits in common. "61de5d89d704a1b337cc7a539d473b61e7ddd387" and "d6e9cec04d92fc889e4a1813e1fc4f381fe99d3c" have entirely different histories.
61de5d89d7
...
d6e9cec04d
7 changed files with 0 additions and 736 deletions
114
src/Project.zig
114
src/Project.zig
|
|
@ -19,10 +19,8 @@ const walk_tree = @import("walk_tree.zig");
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
files: std.ArrayListUnmanaged(File) = .empty,
|
files: std.ArrayListUnmanaged(File) = .empty,
|
||||||
new_or_modified_files: std.ArrayListUnmanaged(FileVcsStatus) = .empty,
|
|
||||||
pending: std.ArrayListUnmanaged(File) = .empty,
|
pending: std.ArrayListUnmanaged(File) = .empty,
|
||||||
longest_file_path: usize = 0,
|
longest_file_path: usize = 0,
|
||||||
longest_new_or_modified_file_path: usize = 0,
|
|
||||||
open_time: i64,
|
open_time: i64,
|
||||||
language_servers: std.StringHashMap(*const LSP),
|
language_servers: std.StringHashMap(*const LSP),
|
||||||
file_language_server_name: std.StringHashMap([]const u8),
|
file_language_server_name: std.StringHashMap([]const u8),
|
||||||
|
|
@ -43,7 +41,6 @@ state: struct {
|
||||||
current_branch: State = .none,
|
current_branch: State = .none,
|
||||||
workspace_files: State = .none,
|
workspace_files: State = .none,
|
||||||
status: State = .none,
|
status: State = .none,
|
||||||
vcs_new_or_modified_files: State = .none,
|
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
status: VcsStatus = .{},
|
status: VcsStatus = .{},
|
||||||
|
|
@ -69,14 +66,6 @@ const File = struct {
|
||||||
visited: bool = false,
|
visited: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FileVcsStatus = struct {
|
|
||||||
path: []const u8,
|
|
||||||
type: []const u8,
|
|
||||||
icon: []const u8,
|
|
||||||
color: u24,
|
|
||||||
vcs_status: u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const FilePos = struct {
|
pub const FilePos = struct {
|
||||||
row: usize = 0,
|
row: usize = 0,
|
||||||
col: usize = 0,
|
col: usize = 0,
|
||||||
|
|
@ -116,8 +105,6 @@ pub fn deinit(self: *Self) void {
|
||||||
self.allocator.free(p.key_ptr.*);
|
self.allocator.free(p.key_ptr.*);
|
||||||
p.value_ptr.*.term();
|
p.value_ptr.*.term();
|
||||||
}
|
}
|
||||||
for (self.new_or_modified_files.items) |file| self.allocator.free(file.path);
|
|
||||||
self.new_or_modified_files.deinit(self.allocator);
|
|
||||||
for (self.files.items) |file| self.allocator.free(file.path);
|
for (self.files.items) |file| self.allocator.free(file.path);
|
||||||
self.files.deinit(self.allocator);
|
self.files.deinit(self.allocator);
|
||||||
self.pending.deinit(self.allocator);
|
self.pending.deinit(self.allocator);
|
||||||
|
|
@ -385,84 +372,6 @@ pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) ClientErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple_query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize {
|
|
||||||
var i: usize = 0;
|
|
||||||
defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_file_path, query }) catch {};
|
|
||||||
for (self.new_or_modified_files.items) |file| {
|
|
||||||
if (file.path.len < query.len) continue;
|
|
||||||
if (std.mem.indexOf(u8, file.path, query)) |idx| {
|
|
||||||
var matches = try self.allocator.alloc(usize, query.len);
|
|
||||||
defer self.allocator.free(matches);
|
|
||||||
var n: usize = 0;
|
|
||||||
while (n < query.len) : (n += 1) matches[n] = idx + n;
|
|
||||||
from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status, matches }) catch return error.ClientFailed;
|
|
||||||
i += 1;
|
|
||||||
if (i >= max) return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn query_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize {
|
|
||||||
if (query.len < 3)
|
|
||||||
return self.simple_query_new_or_modified_files(from, max, query);
|
|
||||||
defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_file_path, query }) catch {};
|
|
||||||
|
|
||||||
var searcher = try fuzzig.Ascii.init(
|
|
||||||
self.allocator,
|
|
||||||
4096, // haystack max size
|
|
||||||
4096, // needle max size
|
|
||||||
.{ .case_sensitive = false },
|
|
||||||
);
|
|
||||||
defer searcher.deinit();
|
|
||||||
|
|
||||||
const Match = struct {
|
|
||||||
path: []const u8,
|
|
||||||
type: []const u8,
|
|
||||||
icon: []const u8,
|
|
||||||
color: u24,
|
|
||||||
vcs_status: u8,
|
|
||||||
score: i32,
|
|
||||||
matches: []const usize,
|
|
||||||
};
|
|
||||||
var matches: std.ArrayList(Match) = .empty;
|
|
||||||
|
|
||||||
for (self.new_or_modified_files.items) |file| {
|
|
||||||
const match = searcher.scoreMatches(file.path, query);
|
|
||||||
if (match.score) |score| {
|
|
||||||
(try matches.addOne(self.allocator)).* = .{
|
|
||||||
.path = file.path,
|
|
||||||
.type = file.type,
|
|
||||||
.icon = file.icon,
|
|
||||||
.color = file.color,
|
|
||||||
.vcs_status = file.vcs_status,
|
|
||||||
.score = score,
|
|
||||||
.matches = try self.allocator.dupe(usize, match.matches),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (matches.items.len == 0) return 0;
|
|
||||||
|
|
||||||
const less_fn = struct {
|
|
||||||
fn less_fn(_: void, lhs: Match, rhs: Match) bool {
|
|
||||||
return lhs.score > rhs.score;
|
|
||||||
}
|
|
||||||
}.less_fn;
|
|
||||||
std.mem.sort(Match, matches.items, {}, less_fn);
|
|
||||||
|
|
||||||
for (matches.items[0..@min(max, matches.items.len)]) |match|
|
|
||||||
from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, match.path, match.type, match.icon, match.color, match.vcs_status, match.matches }) catch return error.ClientFailed;
|
|
||||||
return @min(max, matches.items.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_new_or_modified_files(self: *Self, from: tp.pid_ref, max: usize) ClientError!void {
|
|
||||||
defer from.send(.{ "PRJ", "new_or_modified_files_done", self.longest_new_or_modified_file_path, "" }) catch {};
|
|
||||||
for (self.new_or_modified_files.items, 0..) |file, i| {
|
|
||||||
from.send(.{ "PRJ", "new_or_modified_files", self.longest_new_or_modified_file_path, file.path, file.type, file.icon, file.color, file.vcs_status }) catch return error.ClientFailed;
|
|
||||||
if (i >= max) return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize {
|
fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []const u8) ClientError!usize {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {};
|
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, query }) catch {};
|
||||||
|
|
@ -635,8 +544,6 @@ fn loaded(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void {
|
||||||
std.time.milliTimestamp() - self.open_time,
|
std.time.milliTimestamp() - self.open_time,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.logger.print("vcs outstanding files: {d}", .{self.new_or_modified_files.items.len});
|
|
||||||
|
|
||||||
parent.send(.{ "PRJ", "open_done", self.name, self.longest_file_path, self.files.items.len }) catch {};
|
parent.send(.{ "PRJ", "open_done", self.name, self.longest_file_path, self.files.items.len }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2173,13 +2080,6 @@ pub fn query_git(self: *Self) void {
|
||||||
git.status(@intFromPtr(self)) catch {
|
git.status(@intFromPtr(self)) catch {
|
||||||
self.state.status = .failed;
|
self.state.status = .failed;
|
||||||
};
|
};
|
||||||
// TODO: This needs to be invoked when there are identified changes in the fs
|
|
||||||
for (self.new_or_modified_files.items) |file| self.allocator.free(file.path);
|
|
||||||
self.new_or_modified_files.clearRetainingCapacity();
|
|
||||||
self.state.vcs_new_or_modified_files = .running;
|
|
||||||
git.new_or_modified_files(@intFromPtr(self)) catch {
|
|
||||||
self.state.vcs_new_or_modified_files = .failed;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_walker(self: *Self) void {
|
fn start_walker(self: *Self) void {
|
||||||
|
|
@ -2193,7 +2093,6 @@ fn start_walker(self: *Self) void {
|
||||||
pub fn process_git(self: *Self, parent: tp.pid_ref, m: tp.message) (OutOfMemoryError || error{Exit})!void {
|
pub fn process_git(self: *Self, parent: tp.pid_ref, m: tp.message) (OutOfMemoryError || error{Exit})!void {
|
||||||
var value: []const u8 = undefined;
|
var value: []const u8 = undefined;
|
||||||
var path: []const u8 = undefined;
|
var path: []const u8 = undefined;
|
||||||
var vcs_status: u8 = undefined;
|
|
||||||
if (try m.match(.{ tp.any, tp.any, "status", tp.more })) {
|
if (try m.match(.{ tp.any, tp.any, "status", tp.more })) {
|
||||||
return self.process_status(m);
|
return self.process_status(m);
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) {
|
} else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) {
|
||||||
|
|
@ -2232,19 +2131,6 @@ pub fn process_git(self: *Self, parent: tp.pid_ref, m: tp.message) (OutOfMemoryE
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.null_ })) {
|
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.null_ })) {
|
||||||
self.state.workspace_files = .done;
|
self.state.workspace_files = .done;
|
||||||
try self.loaded(parent);
|
try self.loaded(parent);
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "new_or_modified_files", tp.null_ })) {
|
|
||||||
self.state.vcs_new_or_modified_files = .done;
|
|
||||||
try self.loaded(parent);
|
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "new_or_modified_files", tp.extract(&vcs_status), tp.extract(&path) })) {
|
|
||||||
self.longest_new_or_modified_file_path = @max(self.longest_new_or_modified_file_path, path.len);
|
|
||||||
const file_type: []const u8, const file_icon: []const u8, const file_color: u24 = guess_file_type(path);
|
|
||||||
(try self.new_or_modified_files.addOne(self.allocator)).* = .{
|
|
||||||
.path = try self.allocator.dupe(u8, path),
|
|
||||||
.type = file_type,
|
|
||||||
.icon = file_icon,
|
|
||||||
.color = file_color,
|
|
||||||
.vcs_status = vcs_status,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
self.logger_git.err("git", tp.unexpected(m));
|
self.logger_git.err("git", tp.unexpected(m));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
99
src/git.zig
99
src/git.zig
|
|
@ -174,105 +174,6 @@ pub fn status(context_: usize) Error!void {
|
||||||
}.result, exit_null(tag));
|
}.result, exit_null(tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_or_modified_files(context_: usize) Error!void {
|
|
||||||
const tag = @src().fn_name;
|
|
||||||
try git_err(context_, .{
|
|
||||||
"--no-optional-locks",
|
|
||||||
"status",
|
|
||||||
"--porcelain=v2",
|
|
||||||
"--null",
|
|
||||||
}, struct {
|
|
||||||
fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
|
|
||||||
var it_ = std.mem.splitScalar(u8, output, 0);
|
|
||||||
var counter: u8 = 0;
|
|
||||||
|
|
||||||
while (it_.next()) |line| {
|
|
||||||
var it = std.mem.splitScalar(u8, line, ' ');
|
|
||||||
const rec_type = if (it.next()) |type_tag|
|
|
||||||
std.meta.stringToEnum(StatusRecordType, type_tag) orelse {
|
|
||||||
if (type_tag.len > 0)
|
|
||||||
std.log.debug("found {s}, it happens when a file is renamed and not modified. Check `git --no-optional-locks status --porcelain=v2`", .{type_tag});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
switch (rec_type) {
|
|
||||||
.@"1" => { // ordinary file: <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
|
|
||||||
const sub = it.next() orelse return;
|
|
||||||
const mH = it.next() orelse return;
|
|
||||||
var vcs_status: u8 = undefined;
|
|
||||||
if (sub[0] == 'A') {
|
|
||||||
// New staged file is shown as new
|
|
||||||
vcs_status = '+';
|
|
||||||
} else if (sub[0] == 'M' or sub[1] == 'M') {
|
|
||||||
if (mH[0] == 'S') {
|
|
||||||
// We do not handle submodules, yet
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vcs_status = '~';
|
|
||||||
} else {
|
|
||||||
// We will not edit deleted files
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (0..5) |_| {
|
|
||||||
_ = it.next() orelse return;
|
|
||||||
}
|
|
||||||
var path: std.ArrayListUnmanaged(u8) = .empty;
|
|
||||||
defer path.deinit(allocator);
|
|
||||||
while (it.next()) |path_part| {
|
|
||||||
if (path.items.len > 0) path.append(allocator, ' ') catch return;
|
|
||||||
path.appendSlice(allocator, path_part) catch return;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.send(.{ module_name, context, tag, vcs_status, path.items }) catch {};
|
|
||||||
counter += 1;
|
|
||||||
},
|
|
||||||
.@"2" => {
|
|
||||||
const sub = it.next() orelse return;
|
|
||||||
if (sub[0] != 'R') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// An staged file is editable
|
|
||||||
// renamed: <XY> <sub> <mH> <mI> <mW> <hH> <hI> <rn> <path>
|
|
||||||
for (0..7) |_| {
|
|
||||||
_ = it.next() orelse return;
|
|
||||||
}
|
|
||||||
var path: std.ArrayListUnmanaged(u8) = .empty;
|
|
||||||
defer path.deinit(allocator);
|
|
||||||
while (it.next()) |path_part| {
|
|
||||||
if (path.items.len > 0) path.append(allocator, ' ') catch return;
|
|
||||||
path.appendSlice(allocator, path_part) catch return;
|
|
||||||
}
|
|
||||||
parent.send(.{ module_name, context, tag, '+', path.items }) catch {};
|
|
||||||
counter += 1;
|
|
||||||
},
|
|
||||||
.@"?" => { // untracked file: <path>
|
|
||||||
var path: std.ArrayListUnmanaged(u8) = .empty;
|
|
||||||
defer path.deinit(allocator);
|
|
||||||
while (it.next()) |path_part| {
|
|
||||||
if (path.items.len > 0) path.append(allocator, ' ') catch return;
|
|
||||||
path.appendSlice(allocator, path_part) catch return;
|
|
||||||
}
|
|
||||||
parent.send(.{ module_name, context, tag, '+', path.items }) catch {};
|
|
||||||
counter += 1;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
// Omit showing other statuses
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std.log.info("git: {} changed files", .{counter});
|
|
||||||
}
|
|
||||||
}.result, struct {
|
|
||||||
fn result(_: usize, _: tp.pid_ref, output: []const u8) void {
|
|
||||||
var it = std.mem.splitScalar(u8, output, '\n');
|
|
||||||
while (it.next()) |line| if (line.len > 0)
|
|
||||||
std.log.err("{s}: {s}", .{ module_name, line });
|
|
||||||
}
|
|
||||||
}.result, exit_null(tag));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn git_line_output(context_: usize, comptime tag: []const u8, cmd: anytype) Error!void {
|
fn git_line_output(context_: usize, comptime tag: []const u8, cmd: anytype) Error!void {
|
||||||
try git_err(context_, cmd, struct {
|
try git_err(context_, cmd, struct {
|
||||||
fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
|
fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,6 @@
|
||||||
["space R", "replace_selections_with_clipboard"],
|
["space R", "replace_selections_with_clipboard"],
|
||||||
["space ?", "open_command_palette"],
|
["space ?", "open_command_palette"],
|
||||||
["space f", "find_file"],
|
["space f", "find_file"],
|
||||||
["space g", "show_vcs_status"],
|
|
||||||
["space b", "switch_buffers"],
|
["space b", "switch_buffers"],
|
||||||
["space j", "jumplist_picker"],
|
["space j", "jumplist_picker"],
|
||||||
["space s", "symbol_picker"],
|
["space s", "symbol_picker"],
|
||||||
|
|
|
||||||
|
|
@ -98,20 +98,6 @@ pub fn request_recent_files(max: usize) (ProjectManagerError || ProjectError)!vo
|
||||||
return send(.{ "request_recent_files", project, max });
|
return send(.{ "request_recent_files", project, max });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_new_or_modified_files(max: usize) (ProjectManagerError || ProjectError)!void {
|
|
||||||
const project = tp.env.get().str("project");
|
|
||||||
if (project.len == 0)
|
|
||||||
return error.NoProject;
|
|
||||||
return send(.{ "request_new_or_modified_files", project, max });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_sync_with_vcs() (ProjectManagerError || ProjectError)!void {
|
|
||||||
const project = tp.env.get().str("project");
|
|
||||||
if (project.len == 0)
|
|
||||||
return error.NoProject;
|
|
||||||
return send(.{ "sync_with_vcs", project });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_recent_projects() (ProjectManagerError || ProjectError)!void {
|
pub fn request_recent_projects() (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
return send(.{ "request_recent_projects", project });
|
return send(.{ "request_recent_projects", project });
|
||||||
|
|
@ -124,13 +110,6 @@ pub fn query_recent_files(max: usize, query: []const u8) (ProjectManagerError ||
|
||||||
return send(.{ "query_recent_files", project, max, query });
|
return send(.{ "query_recent_files", project, max, query });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_new_or_modified_files(max: usize, query: []const u8) (ProjectManagerError || ProjectError)!void {
|
|
||||||
const project = tp.env.get().str("project");
|
|
||||||
if (project.len == 0)
|
|
||||||
return error.NoProject;
|
|
||||||
return send(.{ "query_new_or_modified_files", project, max, query });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn request_path_files(max: usize, path: []const u8) (ProjectManagerError || ProjectError)!void {
|
pub fn request_path_files(max: usize, path: []const u8) (ProjectManagerError || ProjectError)!void {
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
if (project.len == 0)
|
if (project.len == 0)
|
||||||
|
|
@ -391,16 +370,10 @@ const Process = struct {
|
||||||
self.request_n_most_recent_file(from, project_directory, n) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
self.request_n_most_recent_file(from, project_directory, n) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) {
|
} else if (try cbor.match(m.buf, .{ "request_recent_files", tp.extract(&project_directory), tp.extract(&max) })) {
|
||||||
self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
self.request_recent_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "request_new_or_modified_files", tp.extract(&project_directory), tp.extract(&max) })) {
|
|
||||||
self.request_new_or_modified_files(from, project_directory, max) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
|
||||||
} else if (try cbor.match(m.buf, .{ "sync_with_vcs", tp.extract(&project_directory) })) {
|
|
||||||
self.request_sync_with_vcs(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
|
||||||
} else if (try cbor.match(m.buf, .{ "request_recent_projects", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "request_recent_projects", tp.extract(&project_directory) })) {
|
||||||
self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
self.request_recent_projects(from, project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
|
} else if (try cbor.match(m.buf, .{ "query_recent_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
|
||||||
self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
self.query_recent_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "query_new_or_modified_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&query) })) {
|
|
||||||
self.query_new_or_modified_files(from, project_directory, max, query) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
|
||||||
} else if (try cbor.match(m.buf, .{ "request_path_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&path) })) {
|
} else if (try cbor.match(m.buf, .{ "request_path_files", tp.extract(&project_directory), tp.extract(&max), tp.extract(&path) })) {
|
||||||
self.request_path_files(from, project_directory, max, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
self.request_path_files(from, project_directory, max, path) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "request_tasks", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "request_tasks", tp.extract(&project_directory) })) {
|
||||||
|
|
@ -495,16 +468,6 @@ const Process = struct {
|
||||||
return project.request_recent_files(from, max);
|
return project.request_recent_files(from, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_sync_with_vcs(self: *Process, _: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
|
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
|
||||||
return project.query_git();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize) (ProjectError || Project.ClientError)!void {
|
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
|
||||||
return project.request_new_or_modified_files(from, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
|
fn request_recent_projects(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
|
||||||
var recent_projects: std.ArrayList(RecentProject) = .empty;
|
var recent_projects: std.ArrayList(RecentProject) = .empty;
|
||||||
defer recent_projects.deinit(self.allocator);
|
defer recent_projects.deinit(self.allocator);
|
||||||
|
|
@ -535,15 +498,6 @@ const Process = struct {
|
||||||
self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time });
|
self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_new_or_modified_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, query: []const u8) (ProjectError || Project.ClientError)!void {
|
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
|
||||||
const start_time = std.time.milliTimestamp();
|
|
||||||
const matched = try project.query_new_or_modified_files(from, max, query);
|
|
||||||
const query_time = std.time.milliTimestamp() - start_time;
|
|
||||||
if (query_time > 250)
|
|
||||||
self.logger.print("query \"{s}\" matched {d}/{d} in {d} ms", .{ query, matched, project.files.items.len, query_time });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) (ProjectError || SpawnError || std.fs.Dir.OpenError)!void {
|
fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) (ProjectError || SpawnError || std.fs.Dir.OpenError)!void {
|
||||||
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
const project = self.projects.get(project_directory) orelse return error.NoProject;
|
||||||
var buf: std.ArrayList(u8) = .empty;
|
var buf: std.ArrayList(u8) = .empty;
|
||||||
|
|
|
||||||
|
|
@ -1,391 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const tp = @import("thespian");
|
|
||||||
const log = @import("log");
|
|
||||||
const cbor = @import("cbor");
|
|
||||||
const file_type_config = @import("file_type_config");
|
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
|
||||||
const input = @import("input");
|
|
||||||
const keybind = @import("keybind");
|
|
||||||
const project_manager = @import("project_manager");
|
|
||||||
const command = @import("command");
|
|
||||||
const EventHandler = @import("EventHandler");
|
|
||||||
const BufferManager = @import("Buffer").Manager;
|
|
||||||
|
|
||||||
const tui = @import("../../tui.zig");
|
|
||||||
const MessageFilter = @import("../../MessageFilter.zig");
|
|
||||||
const Button = @import("../../Button.zig");
|
|
||||||
const InputBox = @import("../../InputBox.zig");
|
|
||||||
const Menu = @import("../../Menu.zig");
|
|
||||||
const Widget = @import("../../Widget.zig");
|
|
||||||
const ModalBackground = @import("../../ModalBackground.zig");
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
const max_recent_files: usize = 25;
|
|
||||||
const widget_type: Widget.Type = .palette;
|
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
f: usize = 0,
|
|
||||||
modal: *ModalBackground.State(*Self),
|
|
||||||
menu: *MenuType,
|
|
||||||
inputbox: *InputBox.State(*Self),
|
|
||||||
logger: log.Logger,
|
|
||||||
query_pending: bool = false,
|
|
||||||
need_reset: bool = false,
|
|
||||||
need_select_first: bool = true,
|
|
||||||
longest: usize,
|
|
||||||
commands: Commands = undefined,
|
|
||||||
buffer_manager: ?*BufferManager,
|
|
||||||
|
|
||||||
const inputbox_label = "Changed or untracked files";
|
|
||||||
const MenuType = Menu.Options(*Self).MenuType;
|
|
||||||
const ButtonType = MenuType.ButtonType;
|
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
|
||||||
const mv = tui.mainview() orelse return error.NotFound;
|
|
||||||
const self = try allocator.create(Self);
|
|
||||||
errdefer allocator.destroy(self);
|
|
||||||
self.* = .{
|
|
||||||
.allocator = allocator,
|
|
||||||
.modal = try ModalBackground.create(*Self, allocator, tui.mainview_widget(), .{ .ctx = self }),
|
|
||||||
.menu = try Menu.create(*Self, allocator, tui.plane(), .{
|
|
||||||
.ctx = self,
|
|
||||||
.style = widget_type,
|
|
||||||
.on_render = on_render_menu,
|
|
||||||
.prepare_resize = prepare_resize_menu,
|
|
||||||
}),
|
|
||||||
.logger = log.logger(@typeName(Self)),
|
|
||||||
.inputbox = (try self.menu.add_header(try InputBox.create(*Self, self.allocator, self.menu.menu.parent, .{
|
|
||||||
.ctx = self,
|
|
||||||
.label = inputbox_label,
|
|
||||||
.padding = 2,
|
|
||||||
.icon = " ",
|
|
||||||
}))).dynamic_cast(InputBox.State(*Self)) orelse unreachable,
|
|
||||||
.buffer_manager = tui.get_buffer_manager(),
|
|
||||||
.longest = inputbox_label.len,
|
|
||||||
};
|
|
||||||
try self.commands.init(self);
|
|
||||||
try tui.message_filters().add(MessageFilter.bind(self, receive_project_manager));
|
|
||||||
self.query_pending = true;
|
|
||||||
try project_manager.request_new_or_modified_files(max_recent_files);
|
|
||||||
self.do_resize();
|
|
||||||
try mv.floating_views.add(self.modal.widget());
|
|
||||||
try mv.floating_views.add(self.menu.container_widget);
|
|
||||||
var mode = try keybind.mode("overlay/palette", allocator, .{
|
|
||||||
.insert_command = "overlay_insert_bytes",
|
|
||||||
});
|
|
||||||
mode.event_handler = EventHandler.to_owned(self);
|
|
||||||
mode.name = " status";
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
|
||||||
self.commands.deinit();
|
|
||||||
tui.message_filters().remove_ptr(self);
|
|
||||||
if (tui.mainview()) |mv| {
|
|
||||||
mv.floating_views.remove(self.menu.container_widget);
|
|
||||||
mv.floating_views.remove(self.modal.widget());
|
|
||||||
}
|
|
||||||
self.logger.deinit();
|
|
||||||
self.allocator.destroy(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn menu_width(self: *Self) usize {
|
|
||||||
return @max(@min(self.longest + 3, max_menu_width()) + 5, inputbox_label.len + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn menu_pos_x(self: *Self) usize {
|
|
||||||
const screen_width = tui.screen().w;
|
|
||||||
const width = self.menu_width();
|
|
||||||
return if (screen_width <= width) 0 else (screen_width - width) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn max_menu_width() usize {
|
|
||||||
const width = tui.screen().w;
|
|
||||||
return @max(15, width - (width / 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_render_menu(_: *Self, button: *ButtonType, theme: *const Widget.Theme, selected: bool) bool {
|
|
||||||
return tui.render_file_vcs_item_cbor(&button.plane, button.opts.label, button.active, selected, button.hover, theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_resize_menu(self: *Self, _: *MenuType, _: Widget.Box) Widget.Box {
|
|
||||||
return self.prepare_resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_resize(self: *Self) Widget.Box {
|
|
||||||
const w = self.menu_width();
|
|
||||||
const x = self.menu_pos_x();
|
|
||||||
const h = self.menu.menu.widgets.items.len;
|
|
||||||
return .{ .y = 0, .x = x, .w = w, .h = h };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_resize(self: *Self) void {
|
|
||||||
self.menu.resize(self.prepare_resize());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn menu_action_open_file(menu: **MenuType, button: *ButtonType, _: Widget.Pos) void {
|
|
||||||
var file_path: []const u8 = undefined;
|
|
||||||
var iter = button.opts.label;
|
|
||||||
if (!(cbor.matchString(&iter, &file_path) catch false)) return;
|
|
||||||
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err("navigate", e);
|
|
||||||
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch |e| menu.*.opts.ctx.logger.err("navigate", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_item(
|
|
||||||
self: *Self,
|
|
||||||
file_name: []const u8,
|
|
||||||
file_icon: []const u8,
|
|
||||||
file_color: u24,
|
|
||||||
vcs_status: u8,
|
|
||||||
indicator: []const u8,
|
|
||||||
matches: ?[]const u8,
|
|
||||||
) !void {
|
|
||||||
var label: std.Io.Writer.Allocating = .init(self.allocator);
|
|
||||||
defer label.deinit();
|
|
||||||
const writer = &label.writer;
|
|
||||||
try cbor.writeValue(writer, file_name);
|
|
||||||
try cbor.writeValue(writer, file_icon);
|
|
||||||
try cbor.writeValue(writer, file_color);
|
|
||||||
try cbor.writeValue(writer, indicator);
|
|
||||||
try cbor.writeValue(writer, vcs_status);
|
|
||||||
if (matches) |cb| _ = try writer.write(cb) else try cbor.writeValue(writer, &[_]usize{});
|
|
||||||
try self.menu.add_item_with_handler(label.written(), menu_action_open_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool {
|
|
||||||
if (cbor.match(m.buf, .{ "PRJ", tp.more }) catch false) {
|
|
||||||
try self.process_project_manager(m);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void {
|
|
||||||
var file_name: []const u8 = undefined;
|
|
||||||
var file_type: []const u8 = undefined;
|
|
||||||
var file_icon: []const u8 = undefined;
|
|
||||||
var file_color: u24 = undefined;
|
|
||||||
var vcs_status: u8 = undefined;
|
|
||||||
var matches: []const u8 = undefined;
|
|
||||||
var query: []const u8 = undefined;
|
|
||||||
if (try cbor.match(m.buf, .{
|
|
||||||
"PRJ",
|
|
||||||
"new_or_modified_files",
|
|
||||||
tp.extract(&self.longest),
|
|
||||||
tp.extract(&file_name),
|
|
||||||
tp.extract(&file_type),
|
|
||||||
tp.extract(&file_icon),
|
|
||||||
tp.extract(&file_color),
|
|
||||||
tp.extract(&vcs_status),
|
|
||||||
tp.extract_cbor(&matches),
|
|
||||||
})) {
|
|
||||||
if (self.need_reset) self.reset_results();
|
|
||||||
const indicator = if (self.buffer_manager) |bm| tui.get_file_state_indicator(bm, file_name) else "";
|
|
||||||
try self.add_item(file_name, file_icon, file_color, vcs_status, indicator, matches);
|
|
||||||
self.do_resize();
|
|
||||||
if (self.need_select_first) {
|
|
||||||
self.menu.select_down();
|
|
||||||
self.need_select_first = false;
|
|
||||||
}
|
|
||||||
tui.need_render();
|
|
||||||
} else if (try cbor.match(m.buf, .{
|
|
||||||
"PRJ",
|
|
||||||
"new_or_modified_files",
|
|
||||||
tp.extract(&self.longest),
|
|
||||||
tp.extract(&file_name),
|
|
||||||
tp.extract(&file_type),
|
|
||||||
tp.extract(&file_icon),
|
|
||||||
tp.extract(&file_color),
|
|
||||||
tp.extract(&vcs_status),
|
|
||||||
})) {
|
|
||||||
if (self.need_reset) self.reset_results();
|
|
||||||
const indicator = if (self.buffer_manager) |bm| tui.get_file_state_indicator(bm, file_name) else "";
|
|
||||||
try self.add_item(file_name, file_icon, file_color, vcs_status, indicator, null);
|
|
||||||
self.do_resize();
|
|
||||||
if (self.need_select_first) {
|
|
||||||
self.menu.select_down();
|
|
||||||
self.need_select_first = false;
|
|
||||||
}
|
|
||||||
tui.need_render();
|
|
||||||
} else if (try cbor.match(m.buf, .{ "PRJ", "new_or_modified_files_done", tp.extract(&self.longest), tp.extract(&query) })) {
|
|
||||||
self.query_pending = false;
|
|
||||||
self.need_reset = true;
|
|
||||||
if (!std.mem.eql(u8, self.inputbox.text.items, query))
|
|
||||||
try self.start_query();
|
|
||||||
} else if (try cbor.match(m.buf, .{ "PRJ", "open_done", tp.string, tp.extract(&self.longest), tp.any })) {
|
|
||||||
self.query_pending = false;
|
|
||||||
self.need_reset = true;
|
|
||||||
try self.start_query();
|
|
||||||
} else {
|
|
||||||
self.logger.err("receive", tp.unexpected(m));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
|
||||||
var text: []const u8 = undefined;
|
|
||||||
|
|
||||||
if (try m.match(.{ "system_clipboard", tp.extract(&text) })) {
|
|
||||||
self.insert_bytes(text) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_results(self: *Self) void {
|
|
||||||
self.need_reset = false;
|
|
||||||
self.menu.reset_items();
|
|
||||||
self.menu.selected = null;
|
|
||||||
self.need_select_first = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_query(self: *Self) MessageFilter.Error!void {
|
|
||||||
if (self.query_pending) return;
|
|
||||||
self.query_pending = true;
|
|
||||||
try project_manager.query_new_or_modified_files(max_recent_files, self.inputbox.text.items);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_word(self: *Self) !void {
|
|
||||||
if (std.mem.lastIndexOfAny(u8, self.inputbox.text.items, "/\\. -_")) |pos| {
|
|
||||||
self.inputbox.text.shrinkRetainingCapacity(pos);
|
|
||||||
} else {
|
|
||||||
self.inputbox.text.shrinkRetainingCapacity(0);
|
|
||||||
}
|
|
||||||
self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8);
|
|
||||||
return self.start_query();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_code_point(self: *Self) !void {
|
|
||||||
if (self.inputbox.text.items.len > 0) {
|
|
||||||
self.inputbox.text.shrinkRetainingCapacity(self.inputbox.text.items.len - tui.egc_last(self.inputbox.text.items).len);
|
|
||||||
self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8);
|
|
||||||
}
|
|
||||||
return self.start_query();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_code_point(self: *Self, c: u32) !void {
|
|
||||||
var buf: [6]u8 = undefined;
|
|
||||||
const bytes = try input.ucs32_to_utf8(&[_]u32{c}, &buf);
|
|
||||||
try self.inputbox.text.appendSlice(self.allocator, buf[0..bytes]);
|
|
||||||
self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8);
|
|
||||||
return self.start_query();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_bytes(self: *Self, bytes: []const u8) !void {
|
|
||||||
try self.inputbox.text.appendSlice(self.allocator, bytes);
|
|
||||||
self.inputbox.cursor = tui.egc_chunk_width(self.inputbox.text.items, 0, 8);
|
|
||||||
return self.start_query();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd(_: *Self, name_: []const u8, ctx: command.Context) tp.result {
|
|
||||||
try command.executeName(name_, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn msg(_: *Self, text: []const u8) tp.result {
|
|
||||||
return tp.self_pid().send(.{ "log", "home", text });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmd_async(_: *Self, name_: []const u8) tp.result {
|
|
||||||
return tp.self_pid().send(.{ "cmd", name_ });
|
|
||||||
}
|
|
||||||
|
|
||||||
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_down(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.select_down();
|
|
||||||
}
|
|
||||||
pub const palette_menu_down_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn palette_menu_up(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.select_up();
|
|
||||||
}
|
|
||||||
pub const palette_menu_up_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn palette_menu_pagedown(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.select_last();
|
|
||||||
}
|
|
||||||
pub const palette_menu_pagedown_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn palette_menu_pageup(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.select_first();
|
|
||||||
}
|
|
||||||
pub const palette_menu_pageup_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn palette_menu_bottom(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.select_last();
|
|
||||||
}
|
|
||||||
pub const palette_menu_bottom_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn palette_menu_top(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.select_first();
|
|
||||||
}
|
|
||||||
pub const palette_menu_top_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn palette_menu_activate(self: *Self, _: Ctx) Result {
|
|
||||||
self.menu.activate_selected();
|
|
||||||
}
|
|
||||||
pub const palette_menu_activate_meta: 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 fn palette_menu_cancel(self: *Self, _: Ctx) Result {
|
|
||||||
try self.cmd("exit_overlay_mode", .{});
|
|
||||||
}
|
|
||||||
pub const palette_menu_cancel_meta: 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 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 fn overlay_insert_code_point(self: *Self, ctx: Ctx) Result {
|
|
||||||
var egc: u32 = 0;
|
|
||||||
if (!try ctx.args.match(.{tp.extract(&egc)}))
|
|
||||||
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 fn overlay_insert_bytes(self: *Self, ctx: Ctx) Result {
|
|
||||||
var bytes: []const u8 = undefined;
|
|
||||||
if (!try ctx.args.match(.{tp.extract(&bytes)}))
|
|
||||||
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 fn overlay_toggle_panel(self: *Self, _: Ctx) Result {
|
|
||||||
return self.cmd_async("toggle_panel");
|
|
||||||
}
|
|
||||||
pub const overlay_toggle_panel_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result {
|
|
||||||
return self.cmd_async("toggle_inputview");
|
|
||||||
}
|
|
||||||
pub const overlay_toggle_inputview_meta: Meta = .{};
|
|
||||||
|
|
||||||
pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result {
|
|
||||||
tui.set_next_style(widget_type);
|
|
||||||
self.do_resize();
|
|
||||||
tui.need_render();
|
|
||||||
try tui.save_config();
|
|
||||||
}
|
|
||||||
pub const overlay_next_widget_style_meta: 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} };
|
|
||||||
};
|
|
||||||
|
|
@ -56,7 +56,6 @@ pub fn ctx_deinit(self: *Self) void {
|
||||||
|
|
||||||
fn on_click(self: *Self, _: *ButtonType, _: Widget.Pos) void {
|
fn on_click(self: *Self, _: *ButtonType, _: Widget.Pos) void {
|
||||||
self.refresh_vcs_status();
|
self.refresh_vcs_status();
|
||||||
tui.sync_with_vcs() catch {};
|
|
||||||
command.executeName("show_vcs_status", .{}) catch {};
|
command.executeName("show_vcs_status", .{}) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1032,11 +1032,6 @@ const cmds = struct {
|
||||||
}
|
}
|
||||||
pub const open_recent_meta: Meta = .{ .description = "Open recent" };
|
pub const open_recent_meta: Meta = .{ .description = "Open recent" };
|
||||||
|
|
||||||
pub fn show_vcs_status(self: *Self, _: Ctx) Result {
|
|
||||||
return self.enter_overlay_mode(@import("mode/overlay/vcs_status.zig"));
|
|
||||||
}
|
|
||||||
pub const show_vcs_status_meta: Meta = .{ .description = "Show git status" };
|
|
||||||
|
|
||||||
pub fn open_recent_project(_: *Self, _: Ctx) Result {
|
pub fn open_recent_project(_: *Self, _: Ctx) Result {
|
||||||
try project_manager.request_recent_projects();
|
try project_manager.request_recent_projects();
|
||||||
}
|
}
|
||||||
|
|
@ -1370,10 +1365,6 @@ 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 sync_with_vcs() !void {
|
|
||||||
try project_manager.request_sync_with_vcs();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mainview_widget() Widget {
|
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");
|
||||||
}
|
}
|
||||||
|
|
@ -1688,15 +1679,6 @@ pub fn render_pointer(self: *renderer.Plane, selected: bool) void {
|
||||||
_ = self.print("{s}", .{pointer}) catch {};
|
_ = self.print("{s}", .{pointer}) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_pointer_vcs(self: *renderer.Plane, vcs_status: u8, selected: bool) void {
|
|
||||||
const pointer = "⏵";
|
|
||||||
if (selected) {
|
|
||||||
_ = self.print("{s}{c}", .{ pointer, vcs_status }) catch {};
|
|
||||||
} else {
|
|
||||||
_ = self.print("{c} ", .{vcs_status}) catch {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_file_item(
|
pub fn render_file_item(
|
||||||
self: *renderer.Plane,
|
self: *renderer.Plane,
|
||||||
file_path_: []const u8,
|
file_path_: []const u8,
|
||||||
|
|
@ -1760,72 +1742,6 @@ pub fn render_file_item_cbor(self: *renderer.Plane, file_item_cbor: []const u8,
|
||||||
return render_file_item(self, file_path_, icon, color, indicator, matches_cbor, active, selected, hover, theme_);
|
return render_file_item(self, file_path_, icon, color, indicator, matches_cbor, active, selected, hover, theme_);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_file_vcs_item(
|
|
||||||
self: *renderer.Plane,
|
|
||||||
file_path_: []const u8,
|
|
||||||
icon: []const u8,
|
|
||||||
color: u24,
|
|
||||||
indicator: []const u8,
|
|
||||||
vcs_status: u8,
|
|
||||||
matches_cbor: []const u8,
|
|
||||||
active: bool,
|
|
||||||
selected: bool,
|
|
||||||
hover: bool,
|
|
||||||
theme_: *const Widget.Theme,
|
|
||||||
) bool {
|
|
||||||
const style_base = theme_.editor_widget;
|
|
||||||
const style_label = if (active) theme_.editor_cursor else if (hover or selected) theme_.editor_selection else theme_.editor_widget;
|
|
||||||
const style_hint = if (find_scope_style(theme_, "entity.name")) |sty| sty.style else style_label;
|
|
||||||
self.set_base_style(style_base);
|
|
||||||
self.erase();
|
|
||||||
self.home();
|
|
||||||
self.set_style(style_label);
|
|
||||||
if (active or hover or selected) {
|
|
||||||
self.fill(" ");
|
|
||||||
self.home();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set_style(style_hint);
|
|
||||||
render_pointer_vcs(self, vcs_status, selected);
|
|
||||||
|
|
||||||
const icon_width = render_file_icon(self, icon, color);
|
|
||||||
|
|
||||||
self.set_style(style_label);
|
|
||||||
_ = self.print("{s} ", .{file_path_}) catch {};
|
|
||||||
|
|
||||||
self.set_style(style_hint);
|
|
||||||
_ = self.print_aligned_right(0, "{s} ", .{indicator}) catch {};
|
|
||||||
|
|
||||||
var iter = matches_cbor;
|
|
||||||
var index: usize = 0;
|
|
||||||
var len = cbor.decodeArrayHeader(&iter) catch return false;
|
|
||||||
while (len > 0) : (len -= 1) {
|
|
||||||
if (cbor.matchValue(&iter, cbor.extract(&index)) catch break) {
|
|
||||||
render_match_cell(self, 0, index + 2 + icon_width, theme_) catch break;
|
|
||||||
} else break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_file_vcs_item_cbor(self: *renderer.Plane, file_item_cbor: []const u8, active: bool, selected: bool, hover: bool, theme_: *const Widget.Theme) bool {
|
|
||||||
var iter = file_item_cbor;
|
|
||||||
var file_path_: []const u8 = undefined;
|
|
||||||
var icon: []const u8 = undefined;
|
|
||||||
var color: u24 = undefined;
|
|
||||||
var indicator: []const u8 = undefined;
|
|
||||||
var vcs_status: u8 = undefined;
|
|
||||||
var matches_cbor: []const u8 = undefined;
|
|
||||||
|
|
||||||
if (!(cbor.matchString(&iter, &file_path_) catch false)) @panic("invalid buffer file path");
|
|
||||||
if (!(cbor.matchString(&iter, &icon) catch false)) @panic("invalid buffer file type icon");
|
|
||||||
if (!(cbor.matchInt(u24, &iter, &color) catch false)) @panic("invalid buffer file type color");
|
|
||||||
if (!(cbor.matchString(&iter, &indicator) catch false)) indicator = "";
|
|
||||||
if (!(cbor.matchInt(u8, &iter, &vcs_status) catch false)) indicator = " ";
|
|
||||||
|
|
||||||
if (!(cbor.matchValue(&iter, cbor.extract_cbor(&matches_cbor)) catch false)) @panic("invalid matches cbor");
|
|
||||||
return render_file_vcs_item(self, file_path_, icon, color, indicator, vcs_status, matches_cbor, active, selected, hover, theme_);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_or_create_theme_file(self: *Self, allocator: std.mem.Allocator) ![]const u8 {
|
fn get_or_create_theme_file(self: *Self, allocator: std.mem.Allocator) ![]const u8 {
|
||||||
const theme_name = self.current_theme().name;
|
const theme_name = self.current_theme().name;
|
||||||
if (root.read_theme(allocator, theme_name)) |content| {
|
if (root.read_theme(allocator, theme_name)) |content| {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue