Compare commits
7 commits
aee7c30c65
...
ab0a8f3c2c
| Author | SHA1 | Date | |
|---|---|---|---|
| ab0a8f3c2c | |||
| b913b8ad87 | |||
| 8789e8b89c | |||
| de6ca62f6d | |||
| 72d97f61f5 | |||
| ca33259ba4 | |||
| 680c6f770e |
9 changed files with 266 additions and 95 deletions
|
|
@ -8,6 +8,7 @@ const Buffer = @import("Buffer");
|
|||
const fuzzig = @import("fuzzig");
|
||||
const tracy = @import("tracy");
|
||||
const git = @import("git");
|
||||
const file_type_config = @import("file_type_config");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const LSP = @import("LSP.zig");
|
||||
|
|
@ -52,6 +53,9 @@ pub const LspOrClientError = (LspError || ClientError);
|
|||
|
||||
const File = struct {
|
||||
path: []const u8,
|
||||
type: []const u8,
|
||||
icon: []const u8,
|
||||
color: u24,
|
||||
mtime: i128,
|
||||
pos: FilePos = .{},
|
||||
visited: bool = false,
|
||||
|
|
@ -341,7 +345,7 @@ pub fn request_n_most_recent_file(self: *Self, from: tp.pid_ref, n: usize) Clien
|
|||
pub fn request_recent_files(self: *Self, from: tp.pid_ref, max: usize) ClientError!void {
|
||||
defer from.send(.{ "PRJ", "recent_done", self.longest_file_path, "" }) catch {};
|
||||
for (self.files.items, 0..) |file, i| {
|
||||
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path }) catch return error.ClientFailed;
|
||||
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color }) catch return error.ClientFailed;
|
||||
if (i >= max) return;
|
||||
}
|
||||
}
|
||||
|
|
@ -356,7 +360,7 @@ fn simple_query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: [
|
|||
defer self.allocator.free(matches);
|
||||
var n: usize = 0;
|
||||
while (n < query.len) : (n += 1) matches[n] = idx + n;
|
||||
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, matches }) catch return error.ClientFailed;
|
||||
from.send(.{ "PRJ", "recent", self.longest_file_path, file.path, file.type, file.icon, file.color, matches }) catch return error.ClientFailed;
|
||||
i += 1;
|
||||
if (i >= max) return i;
|
||||
}
|
||||
|
|
@ -379,6 +383,9 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co
|
|||
|
||||
const Match = struct {
|
||||
path: []const u8,
|
||||
type: []const u8,
|
||||
icon: []const u8,
|
||||
color: u24,
|
||||
score: i32,
|
||||
matches: []const usize,
|
||||
};
|
||||
|
|
@ -389,6 +396,9 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co
|
|||
if (match.score) |score| {
|
||||
(try matches.addOne()).* = .{
|
||||
.path = file.path,
|
||||
.type = file.type,
|
||||
.icon = file.icon,
|
||||
.color = file.color,
|
||||
.score = score,
|
||||
.matches = try self.allocator.dupe(usize, match.matches),
|
||||
};
|
||||
|
|
@ -404,13 +414,24 @@ pub fn query_recent_files(self: *Self, from: tp.pid_ref, max: usize, query: []co
|
|||
std.mem.sort(Match, matches.items, {}, less_fn);
|
||||
|
||||
for (matches.items[0..@min(max, matches.items.len)]) |match|
|
||||
from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.matches }) catch return error.ClientFailed;
|
||||
from.send(.{ "PRJ", "recent", self.longest_file_path, match.path, match.type, match.icon, match.color, match.matches }) catch return error.ClientFailed;
|
||||
return @min(max, matches.items.len);
|
||||
}
|
||||
|
||||
pub fn walk_tree_entry(self: *Self, file_path: []const u8, mtime: i128) OutOfMemoryError!void {
|
||||
pub fn walk_tree_entry(
|
||||
self: *Self,
|
||||
file_path: []const u8,
|
||||
mtime: i128,
|
||||
) OutOfMemoryError!void {
|
||||
const file_type: []const u8, const file_icon: []const u8, const file_color: u24 = guess_file_type(file_path);
|
||||
self.longest_file_path = @max(self.longest_file_path, file_path.len);
|
||||
(try self.pending.addOne(self.allocator)).* = .{ .path = try self.allocator.dupe(u8, file_path), .mtime = mtime };
|
||||
(try self.pending.addOne(self.allocator)).* = .{
|
||||
.path = try self.allocator.dupe(u8, file_path),
|
||||
.type = file_type,
|
||||
.icon = file_icon,
|
||||
.color = file_color,
|
||||
.mtime = mtime,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn walk_tree_done(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void {
|
||||
|
|
@ -420,6 +441,35 @@ pub fn walk_tree_done(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void {
|
|||
return self.loaded(parent);
|
||||
}
|
||||
|
||||
fn default_ft() struct { []const u8, []const u8, u24 } {
|
||||
return .{
|
||||
file_type_config.default.name,
|
||||
file_type_config.default.icon,
|
||||
file_type_config.default.color,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn guess_path_file_type(path: []const u8, file_name: []const u8) struct { []const u8, []const u8, u24 } {
|
||||
var buf: [4096]u8 = undefined;
|
||||
const file_path = std.fmt.bufPrint(&buf, "{s}{}{s}", .{ path, std.fs.path.sep, file_name }) catch return default_ft();
|
||||
return guess_file_type(file_path);
|
||||
}
|
||||
|
||||
pub fn guess_file_type(file_path: []const u8) struct { []const u8, []const u8, u24 } {
|
||||
var buf: [1024]u8 = undefined;
|
||||
const content: []const u8 = blk: {
|
||||
const file = std.fs.cwd().openFile(file_path, .{ .mode = .read_only }) catch break :blk &.{};
|
||||
defer file.close();
|
||||
const size = file.read(&buf) catch break :blk &.{};
|
||||
break :blk buf[0..size];
|
||||
};
|
||||
return if (file_type_config.guess_file_type(file_path, content)) |ft| .{
|
||||
ft.name,
|
||||
ft.icon orelse file_type_config.default.icon,
|
||||
ft.color orelse file_type_config.default.color,
|
||||
} else default_ft();
|
||||
}
|
||||
|
||||
fn merge_pending_files(self: *Self) OutOfMemoryError!void {
|
||||
defer self.sort_files_by_mtime();
|
||||
const existing = try self.files.toOwnedSlice(self.allocator);
|
||||
|
|
@ -469,9 +519,13 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi
|
|||
}
|
||||
return;
|
||||
}
|
||||
const file_type: []const u8, const file_icon: []const u8, const file_color: u24 = guess_file_type(file_path);
|
||||
if (row != 0) {
|
||||
(try self.files.addOne(self.allocator)).* = .{
|
||||
.path = try self.allocator.dupe(u8, file_path),
|
||||
.type = file_type,
|
||||
.icon = file_icon,
|
||||
.color = file_color,
|
||||
.mtime = mtime,
|
||||
.pos = .{ .row = row, .col = col },
|
||||
.visited = true,
|
||||
|
|
@ -479,6 +533,9 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi
|
|||
} else {
|
||||
(try self.files.addOne(self.allocator)).* = .{
|
||||
.path = try self.allocator.dupe(u8, file_path),
|
||||
.type = file_type,
|
||||
.icon = file_icon,
|
||||
.color = file_color,
|
||||
.mtime = mtime,
|
||||
};
|
||||
}
|
||||
|
|
@ -1941,7 +1998,14 @@ 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.extract(&path) })) {
|
||||
self.longest_file_path = @max(self.longest_file_path, path.len);
|
||||
const stat = std.fs.cwd().statFile(path) catch return;
|
||||
(try self.pending.addOne(self.allocator)).* = .{ .path = try self.allocator.dupe(u8, path), .mtime = stat.mtime };
|
||||
const file_type: []const u8, const file_icon: []const u8, const file_color: u24 = guess_file_type(path);
|
||||
(try self.pending.addOne(self.allocator)).* = .{
|
||||
.path = try self.allocator.dupe(u8, path),
|
||||
.type = file_type,
|
||||
.icon = file_icon,
|
||||
.color = file_color,
|
||||
.mtime = stat.mtime,
|
||||
};
|
||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.null_ })) {
|
||||
self.state.workspace_files = .done;
|
||||
try self.loaded(parent);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ pub const default = struct {
|
|||
pub const color = 0x000000;
|
||||
};
|
||||
|
||||
pub const folder_icon = "";
|
||||
|
||||
fn from_file_type(file_type: syntax.FileType) @This() {
|
||||
return .{
|
||||
.name = file_type.name,
|
||||
|
|
@ -84,7 +86,7 @@ pub fn get(file_type_name: []const u8) !?@This() {
|
|||
break :file_type if (syntax.FileType.get_by_name_static(file_type_name)) |ft| from_file_type(ft) else null;
|
||||
}
|
||||
};
|
||||
try cache.put(cache_allocator, file_type_name, file_type);
|
||||
try cache.put(cache_allocator, try cache_allocator.dupe(u8, file_type_name), file_type);
|
||||
break :self file_type;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
31
src/log.zig
31
src/log.zig
|
|
@ -11,6 +11,8 @@ subscriber: ?tp.pid,
|
|||
heap: [32 + 1024]u8,
|
||||
fba: std.heap.FixedBufferAllocator,
|
||||
msg_store: MsgStoreT,
|
||||
no_stdout: bool = false,
|
||||
no_stderr: bool = false,
|
||||
|
||||
const MsgStoreT = std.DoublyLinkedList([]u8);
|
||||
const Receiver = tp.Receiver(*Self);
|
||||
|
|
@ -79,12 +81,23 @@ fn store_reset(self: *Self) void {
|
|||
|
||||
fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
|
||||
errdefer self.deinit();
|
||||
if (try m.match(.{ "log", tp.more })) {
|
||||
var output: []const u8 = undefined;
|
||||
if (try m.match(.{ "log", "error", tp.string, "std.log", "->", tp.extract(&output) })) {
|
||||
if (self.subscriber) |subscriber| {
|
||||
subscriber.send_raw(m) catch {};
|
||||
} else {
|
||||
self.store(m);
|
||||
}
|
||||
if (!self.no_stderr)
|
||||
std.io.getStdErr().writer().print("{s}\n", .{output}) catch {};
|
||||
} else if (try m.match(.{ "log", tp.string, tp.extract(&output) })) {
|
||||
if (self.subscriber) |subscriber| {
|
||||
subscriber.send_raw(m) catch {};
|
||||
} else {
|
||||
self.store(m);
|
||||
}
|
||||
if (!self.no_stdout)
|
||||
std.io.getStdOut().writer().print("{s}\n", .{output}) catch {};
|
||||
} else if (try m.match(.{"subscribe"})) {
|
||||
// log("subscribed");
|
||||
if (self.subscriber) |*s| s.deinit();
|
||||
|
|
@ -95,6 +108,14 @@ fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
|
|||
if (self.subscriber) |*s| s.deinit();
|
||||
self.subscriber = null;
|
||||
self.store_reset();
|
||||
} else if (try m.match(.{ "stdout", "enable" })) {
|
||||
self.no_stdout = false;
|
||||
} else if (try m.match(.{ "stdout", "disable" })) {
|
||||
self.no_stdout = true;
|
||||
} else if (try m.match(.{ "stderr", "enable" })) {
|
||||
self.no_stderr = false;
|
||||
} else if (try m.match(.{ "stderr", "disable" })) {
|
||||
self.no_stderr = true;
|
||||
} else if (try m.match(.{"shutdown"})) {
|
||||
return tp.exit_normal();
|
||||
}
|
||||
|
|
@ -202,6 +223,14 @@ pub fn unsubscribe() tp.result {
|
|||
return tp.env.get().proc("log").send(.{"unsubscribe"});
|
||||
}
|
||||
|
||||
pub fn stdout(state: enum { enable, disable }) void {
|
||||
tp.env.get().proc("log").send(.{ "stdout", state }) catch {};
|
||||
}
|
||||
|
||||
pub fn stderr(state: enum { enable, disable }) void {
|
||||
tp.env.get().proc("log").send(.{ "stderr", state }) catch {};
|
||||
}
|
||||
|
||||
var std_log_pid: ?tp.pid_ref = null;
|
||||
|
||||
pub fn set_std_log_pid(pid: ?tp.pid_ref) void {
|
||||
|
|
|
|||
76
src/main.zig
76
src/main.zig
|
|
@ -6,6 +6,7 @@ const color = @import("color");
|
|||
const flags = @import("flags");
|
||||
const builtin = @import("builtin");
|
||||
const bin_path = @import("bin_path");
|
||||
const sep = std.fs.path.sep;
|
||||
|
||||
const list_languages = @import("list_languages.zig");
|
||||
pub const file_link = @import("file_link.zig");
|
||||
|
|
@ -398,7 +399,7 @@ fn trace_to_file(m: thespian.message.c_buffer_type) callconv(.C) void {
|
|||
const a = std.heap.c_allocator;
|
||||
var path = std.ArrayList(u8).init(a);
|
||||
defer path.deinit();
|
||||
path.writer().print("{s}/trace.log", .{get_state_dir() catch return}) catch return;
|
||||
path.writer().print("{s}{c}trace.log", .{ get_state_dir() catch return, sep }) catch return;
|
||||
const file = std.fs.createFileAbsolute(path.items, .{ .truncate = true }) catch return;
|
||||
State.state = .{
|
||||
.file = file,
|
||||
|
|
@ -502,12 +503,12 @@ pub fn parse_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, b
|
|||
lineno += 1;
|
||||
if (line.len == 0 or line[0] == '#')
|
||||
continue;
|
||||
const sep = std.mem.indexOfScalar(u8, line, ' ') orelse {
|
||||
const spc = std.mem.indexOfScalar(u8, line, ' ') orelse {
|
||||
std.log.err("{s}:{}: {s} missing value", .{ file_name, lineno, line });
|
||||
continue;
|
||||
};
|
||||
const name = line[0..sep];
|
||||
const value_str = line[sep + 1 ..];
|
||||
const name = line[0..spc];
|
||||
const value_str = line[spc + 1 ..];
|
||||
const cb = cbor.fromJsonAlloc(allocator, value_str) catch {
|
||||
std.log.err("{s}:{}: {s} has bad value: {s}", .{ file_name, lineno, name, value_str });
|
||||
continue;
|
||||
|
|
@ -781,6 +782,11 @@ pub const ConfigDirError = error{
|
|||
AppConfigDirUnavailable,
|
||||
};
|
||||
|
||||
fn make_dir_error(path: []const u8, err: anytype) @TypeOf(err) {
|
||||
std.log.err("failed to create directory: '{s}'", .{path});
|
||||
return err;
|
||||
}
|
||||
|
||||
fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
||||
const a = std.heap.c_allocator;
|
||||
const local = struct {
|
||||
|
|
@ -791,22 +797,22 @@ fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
|||
dir
|
||||
else if (std.process.getEnvVarOwned(a, "XDG_CONFIG_HOME") catch null) |xdg| ret: {
|
||||
defer a.free(xdg);
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ xdg, appname });
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}{c}{s}", .{ xdg, sep, appname });
|
||||
} else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: {
|
||||
defer a.free(home);
|
||||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config", .{home});
|
||||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}{c}.config", .{ home, sep });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeHomeConfigDirFailed,
|
||||
else => return make_dir_error(dir, error.MakeHomeConfigDirFailed),
|
||||
};
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config/{s}", .{ home, appname });
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}{c}.config{c}{s}", .{ home, sep, sep, appname });
|
||||
} else if (builtin.os.tag == .windows) ret: {
|
||||
if (std.process.getEnvVarOwned(a, "APPDATA") catch null) |appdata| {
|
||||
defer a.free(appdata);
|
||||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ appdata, appname });
|
||||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}{c}{s}", .{ appdata, sep, appname });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeAppConfigDirFailed,
|
||||
else => return make_dir_error(dir, error.MakeAppConfigDirFailed),
|
||||
};
|
||||
break :ret dir;
|
||||
} else return error.AppConfigDirUnavailable;
|
||||
|
|
@ -815,14 +821,14 @@ 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 make_dir_error(config_dir, error.MakeConfigDirFailed),
|
||||
};
|
||||
|
||||
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 {};
|
||||
std.fs.makeDirAbsolute(try std.fmt.bufPrint(&keybind_dir_buffer, "{s}{c}{s}", .{ config_dir, sep, 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 {};
|
||||
std.fs.makeDirAbsolute(try std.fmt.bufPrint(&theme_dir_buffer, "{s}{c}{s}", .{ config_dir, sep, theme_dir })) catch {};
|
||||
|
||||
return config_dir;
|
||||
}
|
||||
|
|
@ -841,22 +847,22 @@ fn get_app_cache_dir(appname: []const u8) ![]const u8 {
|
|||
dir
|
||||
else if (std.process.getEnvVarOwned(a, "XDG_CACHE_HOME") catch null) |xdg| ret: {
|
||||
defer a.free(xdg);
|
||||
break :ret try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/{s}", .{ xdg, appname });
|
||||
break :ret try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}{c}{s}", .{ xdg, sep, appname });
|
||||
} else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: {
|
||||
defer a.free(home);
|
||||
const dir = try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/.cache", .{home});
|
||||
const dir = try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}{c}.cache", .{ home, sep });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(dir, e),
|
||||
};
|
||||
break :ret try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/.cache/{s}", .{ home, appname });
|
||||
break :ret try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}{c}.cache{c}{s}", .{ home, sep, sep, appname });
|
||||
} else if (builtin.os.tag == .windows) ret: {
|
||||
if (std.process.getEnvVarOwned(a, "APPDATA") catch null) |appdata| {
|
||||
defer a.free(appdata);
|
||||
const dir = try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}/{s}", .{ appdata, appname });
|
||||
const dir = try std.fmt.bufPrint(&local.cache_dir_buffer, "{s}{c}{s}", .{ appdata, sep, appname });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(dir, e),
|
||||
};
|
||||
break :ret dir;
|
||||
} else return error.AppCacheDirUnavailable;
|
||||
|
|
@ -865,7 +871,7 @@ fn get_app_cache_dir(appname: []const u8) ![]const u8 {
|
|||
local.cache_dir = cache_dir;
|
||||
std.fs.makeDirAbsolute(cache_dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(cache_dir, e),
|
||||
};
|
||||
return cache_dir;
|
||||
}
|
||||
|
|
@ -884,27 +890,27 @@ fn get_app_state_dir(appname: []const u8) ![]const u8 {
|
|||
dir
|
||||
else if (std.process.getEnvVarOwned(a, "XDG_STATE_HOME") catch null) |xdg| ret: {
|
||||
defer a.free(xdg);
|
||||
break :ret try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/{s}", .{ xdg, appname });
|
||||
break :ret try std.fmt.bufPrint(&local.state_dir_buffer, "{s}{c}{s}", .{ xdg, sep, appname });
|
||||
} else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: {
|
||||
defer a.free(home);
|
||||
var dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/.local", .{home});
|
||||
var dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}{c}.local", .{ home, sep });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(dir, e),
|
||||
};
|
||||
dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/.local/state", .{home});
|
||||
dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}{c}.local{c}state", .{ home, sep, sep });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(dir, e),
|
||||
};
|
||||
break :ret try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/.local/state/{s}", .{ home, appname });
|
||||
break :ret try std.fmt.bufPrint(&local.state_dir_buffer, "{s}{c}.local{c}state{c}{s}", .{ home, sep, sep, sep, appname });
|
||||
} else if (builtin.os.tag == .windows) ret: {
|
||||
if (std.process.getEnvVarOwned(a, "APPDATA") catch null) |appdata| {
|
||||
defer a.free(appdata);
|
||||
const dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}/{s}", .{ appdata, appname });
|
||||
const dir = try std.fmt.bufPrint(&local.state_dir_buffer, "{s}{c}{s}", .{ appdata, sep, appname });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(dir, e),
|
||||
};
|
||||
break :ret dir;
|
||||
} else return error.AppCacheDirUnavailable;
|
||||
|
|
@ -913,7 +919,7 @@ fn get_app_state_dir(appname: []const u8) ![]const u8 {
|
|||
local.state_dir = state_dir;
|
||||
std.fs.makeDirAbsolute(state_dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
else => return make_dir_error(state_dir, e),
|
||||
};
|
||||
return state_dir;
|
||||
}
|
||||
|
|
@ -926,7 +932,7 @@ fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name:
|
|||
const local = struct {
|
||||
var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
return std.fmt.bufPrint(&local.config_file_buffer, "{s}/{s}", .{ try get_app_config_dir(appname), config_file_name });
|
||||
return std.fmt.bufPrint(&local.config_file_buffer, "{s}{c}{s}", .{ try get_app_config_dir(appname), sep, config_file_name });
|
||||
}
|
||||
|
||||
pub fn get_config_file_name(T: type) ![]const u8 {
|
||||
|
|
@ -942,7 +948,7 @@ pub fn get_restore_file_name() ![]const u8 {
|
|||
const restore_file = if (local.restore_file) |file|
|
||||
file
|
||||
else
|
||||
try std.fmt.bufPrint(&local.restore_file_buffer, "{s}/{s}", .{ try get_app_state_dir(application_name), restore_file_name });
|
||||
try std.fmt.bufPrint(&local.restore_file_buffer, "{s}{c}{s}", .{ try get_app_state_dir(application_name), sep, restore_file_name });
|
||||
local.restore_file = restore_file;
|
||||
return restore_file;
|
||||
}
|
||||
|
|
@ -958,7 +964,7 @@ fn get_keybind_namespaces_directory() ![]const u8 {
|
|||
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), keybind_dir });
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}{c}{s}", .{ try get_app_config_dir(application_name), sep, keybind_dir });
|
||||
}
|
||||
|
||||
pub fn get_keybind_namespace_file_name(namespace_name: []const u8) ![]const u8 {
|
||||
|
|
@ -966,7 +972,7 @@ pub fn get_keybind_namespace_file_name(namespace_name: []const u8) ![]const u8 {
|
|||
const local = struct {
|
||||
var file_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
return try std.fmt.bufPrint(&local.file_buffer, "{s}/{s}.json", .{ dir, namespace_name });
|
||||
return try std.fmt.bufPrint(&local.file_buffer, "{s}{c}{s}.json", .{ dir, sep, namespace_name });
|
||||
}
|
||||
|
||||
const theme_dir = "themes";
|
||||
|
|
@ -980,7 +986,7 @@ fn get_theme_directory() ![]const u8 {
|
|||
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 });
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}{c}{s}", .{ try get_app_config_dir(application_name), sep, theme_dir });
|
||||
}
|
||||
|
||||
pub fn get_theme_file_name(theme_name: []const u8) ![]const u8 {
|
||||
|
|
@ -988,7 +994,7 @@ pub fn get_theme_file_name(theme_name: []const u8) ![]const u8 {
|
|||
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 });
|
||||
return try std.fmt.bufPrint(&local.file_buffer, "{s}{c}{s}.json", .{ dir, sep, theme_name });
|
||||
}
|
||||
|
||||
fn restart() noreturn {
|
||||
|
|
|
|||
|
|
@ -793,12 +793,19 @@ fn request_path_files_async(a_: std.mem.Allocator, parent_: tp.pid_ref, project_
|
|||
var iter = self.dir.iterateAssumeFirstIteration();
|
||||
errdefer |e| self.parent.send(.{ "PRJ", "path_error", self.project_name, self.path, e }) catch {};
|
||||
while (try iter.next()) |entry| {
|
||||
switch (entry.kind) {
|
||||
.directory => try self.parent.send(.{ "PRJ", "path_entry", self.project_name, self.path, "DIR", entry.name }),
|
||||
.sym_link => try self.parent.send(.{ "PRJ", "path_entry", self.project_name, self.path, "LINK", entry.name }),
|
||||
.file => try self.parent.send(.{ "PRJ", "path_entry", self.project_name, self.path, "FILE", entry.name }),
|
||||
const event_type = switch (entry.kind) {
|
||||
.directory => "DIR",
|
||||
.sym_link => "LINK",
|
||||
.file => "FILE",
|
||||
else => continue,
|
||||
}
|
||||
};
|
||||
const default = file_type_config.default;
|
||||
const file_type, const icon, const color = switch (entry.kind) {
|
||||
.directory => .{ "directory", file_type_config.folder_icon, default.color },
|
||||
.sym_link, .file => Project.guess_path_file_type(self.path, entry.name),
|
||||
else => .{ default.name, default.icon, default.color },
|
||||
};
|
||||
try self.parent.send(.{ "PRJ", "path_entry", self.project_name, self.path, event_type, entry.name, file_type, icon, color });
|
||||
count += 1;
|
||||
if (count >= self.max) break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1315,7 +1315,7 @@ pub fn write_restore_info(self: *Self) void {
|
|||
|
||||
fn read_restore_info(self: *Self) !void {
|
||||
const file_name = try root.get_restore_file_name();
|
||||
const file = try std.fs.cwd().openFile(file_name, .{ .mode = .read_only });
|
||||
const file = try std.fs.openFileAbsolute(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
const stat = try file.stat();
|
||||
var buf = try self.allocator.alloc(u8, @intCast(stat.size));
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||
const tp = @import("thespian");
|
||||
const cbor = @import("cbor");
|
||||
const log = @import("log");
|
||||
const file_type_config = @import("file_type_config");
|
||||
const root = @import("root");
|
||||
|
||||
const input = @import("input");
|
||||
|
|
@ -20,6 +21,7 @@ pub fn Create(options: type) type {
|
|||
return struct {
|
||||
allocator: std.mem.Allocator,
|
||||
file_path: std.ArrayList(u8),
|
||||
rendered_mini_buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||
query: std.ArrayList(u8),
|
||||
match: std.ArrayList(u8),
|
||||
entries: std.ArrayList(Entry),
|
||||
|
|
@ -33,8 +35,12 @@ pub fn Create(options: type) type {
|
|||
|
||||
const Entry = struct {
|
||||
name: []const u8,
|
||||
type: enum { dir, file, link },
|
||||
type: EntryType,
|
||||
file_type: []const u8,
|
||||
icon: []const u8,
|
||||
color: u24,
|
||||
};
|
||||
const EntryType = enum { dir, file, link };
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } {
|
||||
const self = try allocator.create(Self);
|
||||
|
|
@ -66,6 +72,7 @@ pub fn Create(options: type) type {
|
|||
self.match.deinit();
|
||||
self.query.deinit();
|
||||
self.file_path.deinit();
|
||||
self.rendered_mini_buffer.deinit(self.allocator);
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +87,11 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
|
||||
fn clear_entries(self: *Self) void {
|
||||
for (self.entries.items) |entry| self.allocator.free(entry.name);
|
||||
for (self.entries.items) |entry| {
|
||||
self.allocator.free(entry.name);
|
||||
self.allocator.free(entry.file_type);
|
||||
self.allocator.free(entry.icon);
|
||||
}
|
||||
self.entries.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
|
|
@ -112,14 +123,11 @@ pub fn Create(options: type) type {
|
|||
self.complete_trigger_count = 0;
|
||||
self.file_path.clearRetainingCapacity();
|
||||
if (self.match.items.len > 0) {
|
||||
try self.construct_path(self.query.items, .{ .name = self.match.items, .type = .file }, 0);
|
||||
try self.construct_path(self.query.items, self.match.items, .file, 0);
|
||||
} else {
|
||||
try self.file_path.appendSlice(self.query.items);
|
||||
}
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.file_path.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 1);
|
||||
}
|
||||
self.update_mini_mode_text();
|
||||
return;
|
||||
}
|
||||
self.complete_trigger_count -= 1;
|
||||
|
|
@ -139,12 +147,7 @@ pub fn Create(options: type) type {
|
|||
}
|
||||
|
||||
fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||
defer {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.file_path.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 1);
|
||||
}
|
||||
}
|
||||
defer self.update_mini_mode_text();
|
||||
var count: usize = undefined;
|
||||
if (try cbor.match(m.buf, .{ "PRJ", "path_entry", tp.more })) {
|
||||
return self.process_path_entry(m);
|
||||
|
|
@ -158,18 +161,31 @@ pub fn Create(options: type) type {
|
|||
fn process_path_entry(self: *Self, m: tp.message) MessageFilter.Error!void {
|
||||
var path: []const u8 = undefined;
|
||||
var file_name: []const u8 = undefined;
|
||||
if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "DIR", tp.extract(&file_name) })) {
|
||||
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .dir };
|
||||
} else if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "LINK", tp.extract(&file_name) })) {
|
||||
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .link };
|
||||
} else if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "FILE", tp.extract(&file_name) })) {
|
||||
(try self.entries.addOne()).* = .{ .name = try self.allocator.dupe(u8, file_name), .type = .file };
|
||||
var file_type: []const u8 = undefined;
|
||||
var icon: []const u8 = undefined;
|
||||
var color: u24 = undefined;
|
||||
if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "DIR", tp.extract(&file_name), tp.extract(&file_type), tp.extract(&icon), tp.extract(&color) })) {
|
||||
try self.add_entry(file_name, .dir, file_type, icon, color);
|
||||
} else if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "LINK", tp.extract(&file_name), tp.extract(&file_type), tp.extract(&icon), tp.extract(&color) })) {
|
||||
try self.add_entry(file_name, .link, file_type, icon, color);
|
||||
} else if (try cbor.match(m.buf, .{ tp.any, tp.any, tp.any, tp.extract(&path), "FILE", tp.extract(&file_name), tp.extract(&file_type), tp.extract(&icon), tp.extract(&color) })) {
|
||||
try self.add_entry(file_name, .file, file_type, icon, color);
|
||||
} else {
|
||||
log.logger("file_browser").err("receive", tp.unexpected(m));
|
||||
}
|
||||
tui.need_render();
|
||||
}
|
||||
|
||||
fn add_entry(self: *Self, file_name: []const u8, entry_type: EntryType, file_type: []const u8, icon: []const u8, color: u24) !void {
|
||||
(try self.entries.addOne()).* = .{
|
||||
.name = try self.allocator.dupe(u8, file_name),
|
||||
.type = entry_type,
|
||||
.file_type = try self.allocator.dupe(u8, file_type),
|
||||
.icon = try self.allocator.dupe(u8, icon),
|
||||
.color = color,
|
||||
};
|
||||
}
|
||||
|
||||
fn do_complete(self: *Self) !void {
|
||||
self.complete_trigger_count = @min(self.complete_trigger_count, self.entries.items.len);
|
||||
self.file_path.clearRetainingCapacity();
|
||||
|
|
@ -179,9 +195,10 @@ pub fn Create(options: type) type {
|
|||
if (self.total_matches == 1)
|
||||
self.complete_trigger_count = 0;
|
||||
} else if (self.entries.items.len > 0) {
|
||||
try self.construct_path(self.query.items, self.entries.items[self.complete_trigger_count - 1], self.complete_trigger_count - 1);
|
||||
const entry = self.entries.items[self.complete_trigger_count - 1];
|
||||
try self.construct_path(self.query.items, entry.name, entry.type, self.complete_trigger_count - 1);
|
||||
} else {
|
||||
try self.construct_path(self.query.items, .{ .name = "", .type = .file }, 0);
|
||||
try self.construct_path(self.query.items, "", .file, 0);
|
||||
}
|
||||
if (self.match.items.len > 0)
|
||||
if (self.total_matches > 1)
|
||||
|
|
@ -192,14 +209,14 @@ pub fn Create(options: type) type {
|
|||
message("{d}/{d}", .{ self.matched_entry + 1, self.entries.items.len });
|
||||
}
|
||||
|
||||
fn construct_path(self: *Self, path_: []const u8, entry: Entry, entry_no: usize) error{OutOfMemory}!void {
|
||||
fn construct_path(self: *Self, path_: []const u8, entry_name: []const u8, entry_type: EntryType, entry_no: usize) error{OutOfMemory}!void {
|
||||
self.matched_entry = entry_no;
|
||||
const path = project_manager.normalize_file_path(path_);
|
||||
try self.file_path.appendSlice(path);
|
||||
if (path.len > 0 and path[path.len - 1] != std.fs.path.sep)
|
||||
try self.file_path.append(std.fs.path.sep);
|
||||
try self.file_path.appendSlice(entry.name);
|
||||
if (entry.type == .dir)
|
||||
try self.file_path.appendSlice(entry_name);
|
||||
if (entry_type == .dir)
|
||||
try self.file_path.append(std.fs.path.sep);
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +229,7 @@ pub fn Create(options: type) type {
|
|||
if (try prefix_compare_icase(self.allocator, self.match.items, entry.name)) {
|
||||
matched += 1;
|
||||
if (matched == self.complete_trigger_count) {
|
||||
try self.construct_path(self.query.items, entry, i);
|
||||
try self.construct_path(self.query.items, entry.name, entry.type, i);
|
||||
found_match = i;
|
||||
}
|
||||
last = entry;
|
||||
|
|
@ -222,11 +239,11 @@ pub fn Create(options: type) type {
|
|||
self.total_matches = matched;
|
||||
if (found_match) |_| return;
|
||||
if (last) |entry| {
|
||||
try self.construct_path(self.query.items, entry, last_no);
|
||||
try self.construct_path(self.query.items, entry.name, entry.type, last_no);
|
||||
self.complete_trigger_count = matched;
|
||||
} else {
|
||||
message("no match for '{s}'", .{self.match.items});
|
||||
try self.construct_path(self.query.items, .{ .name = self.match.items, .type = .file }, 0);
|
||||
try self.construct_path(self.query.items, self.match.items, .file, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -264,8 +281,15 @@ pub fn Create(options: type) type {
|
|||
|
||||
fn update_mini_mode_text(self: *Self) void {
|
||||
if (tui.mini_mode()) |mini_mode| {
|
||||
mini_mode.text = self.file_path.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 1);
|
||||
const icon = if (self.entries.items.len > 0 and self.complete_trigger_count > 0)
|
||||
self.entries.items[self.complete_trigger_count - 1].icon
|
||||
else
|
||||
" ";
|
||||
self.rendered_mini_buffer.clearRetainingCapacity();
|
||||
const writer = self.rendered_mini_buffer.writer(self.allocator);
|
||||
writer.print("{s} {s}", .{ icon, self.file_path.items }) catch {};
|
||||
mini_mode.text = self.rendered_mini_buffer.items;
|
||||
mini_mode.cursor = tui.egc_chunk_width(self.file_path.items, 0, 1) + 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ 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 root = @import("root");
|
||||
|
||||
const Plane = @import("renderer").Plane;
|
||||
|
|
@ -111,13 +112,25 @@ fn on_render_menu(self: *Self, button: *Button.State(*Menu.State(*Self)), theme:
|
|||
button.plane.home();
|
||||
}
|
||||
var file_path: []const u8 = undefined;
|
||||
var file_type: []const u8 = undefined;
|
||||
var file_icon: []const u8 = undefined;
|
||||
var file_color: u24 = undefined;
|
||||
var iter = button.opts.label; // label contains cbor, first the file name, then multiple match indexes
|
||||
if (!(cbor.matchString(&iter, &file_path) catch false))
|
||||
file_path = "#ERROR#";
|
||||
if (!(cbor.matchString(&iter, &file_path) catch false)) file_path = "#ERROR#";
|
||||
if (!(cbor.matchString(&iter, &file_type) catch false)) file_type = file_type_config.default.name;
|
||||
if (!(cbor.matchString(&iter, &file_icon) catch false)) file_icon = file_type_config.default.icon;
|
||||
if (!(cbor.matchInt(u24, &iter, &file_color) catch false)) file_icon = file_type_config.default.icon;
|
||||
|
||||
button.plane.set_style(style_keybind);
|
||||
const dirty = if (self.buffer_manager) |bm| if (bm.is_buffer_dirty(file_path)) "" else " " else " ";
|
||||
const pointer = if (selected) "⏵" else dirty;
|
||||
_ = button.plane.print("{s}", .{pointer}) catch {};
|
||||
|
||||
if (tui.config().show_fileicons) {
|
||||
tui.render_file_icon(&button.plane, file_icon, file_color);
|
||||
_ = button.plane.print(" ", .{}) catch {};
|
||||
}
|
||||
|
||||
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
var removed_prefix: usize = 0;
|
||||
const max_len = max_menu_width() - 2;
|
||||
|
|
@ -125,25 +138,17 @@ fn on_render_menu(self: *Self, button: *Button.State(*Menu.State(*Self)), theme:
|
|||
_ = button.plane.print("{s} ", .{
|
||||
if (file_path.len > max_len) root.shorten_path(&buf, file_path, &removed_prefix, max_len) else file_path,
|
||||
}) catch {};
|
||||
|
||||
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) {
|
||||
const cell_idx = if (index < removed_prefix) 1 else index + 1 - removed_prefix;
|
||||
render_cell(&button.plane, 0, cell_idx, theme.editor_match) catch break;
|
||||
tui.render_match_cell(&button.plane, 0, index + 4, theme) catch break;
|
||||
} else break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn render_cell(plane: *Plane, y: usize, x: usize, style: Widget.Theme.Style) !void {
|
||||
plane.cursor_move_yx(@intCast(y), @intCast(x)) catch return;
|
||||
var cell = plane.cell_init();
|
||||
_ = plane.at_cursor_cell(&cell) catch return;
|
||||
cell.set_style(style);
|
||||
_ = plane.putc(&cell) catch {};
|
||||
}
|
||||
|
||||
fn on_resize_menu(self: *Self, _: *Menu.State(*Self), _: Widget.Box) void {
|
||||
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
||||
}
|
||||
|
|
@ -156,11 +161,21 @@ fn menu_action_open_file(menu: **Menu.State(*Self), button: *Button.State(*Menu.
|
|||
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, matches: ?[]const u8) !void {
|
||||
fn add_item(
|
||||
self: *Self,
|
||||
file_name: []const u8,
|
||||
file_type: []const u8,
|
||||
file_icon: []const u8,
|
||||
file_color: u24,
|
||||
matches: ?[]const u8,
|
||||
) !void {
|
||||
var label = std.ArrayList(u8).init(self.allocator);
|
||||
defer label.deinit();
|
||||
const writer = label.writer();
|
||||
try cbor.writeValue(writer, file_name);
|
||||
try cbor.writeValue(writer, file_type);
|
||||
try cbor.writeValue(writer, file_icon);
|
||||
try cbor.writeValue(writer, file_color);
|
||||
if (matches) |cb| _ = try writer.write(cb);
|
||||
try self.menu.add_item_with_handler(label.items, menu_action_open_file);
|
||||
}
|
||||
|
|
@ -175,20 +190,40 @@ fn receive_project_manager(self: *Self, _: tp.pid_ref, m: tp.message) MessageFil
|
|||
|
||||
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 matches: []const u8 = undefined;
|
||||
var query: []const u8 = undefined;
|
||||
if (try cbor.match(m.buf, .{ "PRJ", "recent", tp.extract(&self.longest), tp.extract(&file_name), tp.extract_cbor(&matches) })) {
|
||||
if (try cbor.match(m.buf, .{
|
||||
"PRJ",
|
||||
"recent",
|
||||
tp.extract(&self.longest),
|
||||
tp.extract(&file_name),
|
||||
tp.extract(&file_type),
|
||||
tp.extract(&file_icon),
|
||||
tp.extract(&file_color),
|
||||
tp.extract_cbor(&matches),
|
||||
})) {
|
||||
if (self.need_reset) self.reset_results();
|
||||
try self.add_item(file_name, matches);
|
||||
try self.add_item(file_name, file_type, file_icon, file_color, matches);
|
||||
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
||||
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", "recent", tp.extract(&self.longest), tp.extract(&file_name) })) {
|
||||
} else if (try cbor.match(m.buf, .{
|
||||
"PRJ",
|
||||
"recent",
|
||||
tp.extract(&self.longest),
|
||||
tp.extract(&file_name),
|
||||
tp.extract(&file_type),
|
||||
tp.extract(&file_icon),
|
||||
tp.extract(&file_color),
|
||||
})) {
|
||||
if (self.need_reset) self.reset_results();
|
||||
try self.add_item(file_name, null);
|
||||
try self.add_item(file_name, file_type, file_icon, file_color, null);
|
||||
self.menu.resize(.{ .y = 0, .x = self.menu_pos_x(), .w = self.menu_width() });
|
||||
if (self.need_select_first) {
|
||||
self.menu.select_down();
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ const InitError = error{
|
|||
keybind.LoadError;
|
||||
|
||||
fn init(allocator: Allocator) InitError!*Self {
|
||||
log.stdout(.disable);
|
||||
|
||||
var conf, const conf_bufs = root.read_config(@import("config"), allocator);
|
||||
|
||||
if (@hasDecl(renderer, "install_crash_handler") and conf.start_debugger_on_crash)
|
||||
|
|
@ -157,6 +159,8 @@ fn init(allocator: Allocator) InitError!*Self {
|
|||
self.rdr_.dispatch_event = dispatch_event;
|
||||
try self.rdr_.run();
|
||||
|
||||
log.stderr(.disable);
|
||||
|
||||
try project_manager.start();
|
||||
|
||||
try frame_clock.start();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue