feat: load and edit key bindings in config directory
This commit is contained in:
parent
3af2b09891
commit
dc914ba562
5 changed files with 61 additions and 1 deletions
|
@ -175,6 +175,7 @@
|
||||||
["r", "open_recent_project"],
|
["r", "open_recent_project"],
|
||||||
["p", "open_command_palette"],
|
["p", "open_command_palette"],
|
||||||
["c", "open_config"],
|
["c", "open_config"],
|
||||||
|
["k", "open_keybind_config"],
|
||||||
["t", "change_theme"],
|
["t", "change_theme"],
|
||||||
["q", "quit"],
|
["q", "quit"],
|
||||||
["f1", "open_help"],
|
["f1", "open_help"],
|
||||||
|
|
|
@ -7,6 +7,7 @@ const tp = @import("thespian");
|
||||||
const cbor = @import("cbor");
|
const cbor = @import("cbor");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const log = @import("log");
|
const log = @import("log");
|
||||||
|
const root = @import("root");
|
||||||
|
|
||||||
const input = @import("input");
|
const input = @import("input");
|
||||||
const command = @import("command");
|
const command = @import("command");
|
||||||
|
@ -235,7 +236,12 @@ const BindingSet = struct {
|
||||||
.command = self.allocator.dupe(u8, "toggle_input_mode") catch @panic("failed to add toggle_input_mode fallback"),
|
.command = self.allocator.dupe(u8, "toggle_input_mode") catch @panic("failed to add toggle_input_mode fallback"),
|
||||||
.args = "",
|
.args = "",
|
||||||
}) catch {};
|
}) catch {};
|
||||||
const json_string: []const u8 = builtin_keybinds.get(namespace_name) orelse return error.NotFound;
|
var free_json_string = true;
|
||||||
|
const json_string = root.read_keybind_namespace(self.allocator, namespace_name) orelse blk: {
|
||||||
|
free_json_string = false;
|
||||||
|
break :blk builtin_keybinds.get(namespace_name) orelse return error.NotFound;
|
||||||
|
};
|
||||||
|
defer if (free_json_string) self.allocator.free(json_string);
|
||||||
const parsed = try std.json.parseFromSlice(std.json.Value, self.allocator, json_string, .{});
|
const parsed = try std.json.parseFromSlice(std.json.Value, self.allocator, json_string, .{});
|
||||||
defer parsed.deinit();
|
defer parsed.deinit();
|
||||||
if (parsed.value != .object) return error.NotAnObject;
|
if (parsed.value != .object) return error.NotAnObject;
|
||||||
|
@ -504,6 +510,18 @@ pub const CursorShape = enum {
|
||||||
beam,
|
beam,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn get_or_create_namespace_config_file(allocator: std.mem.Allocator, namespace_name: []const u8) ![]const u8 {
|
||||||
|
if (root.read_keybind_namespace(allocator, namespace_name)) |content| {
|
||||||
|
allocator.free(content);
|
||||||
|
} else {
|
||||||
|
try root.write_keybind_namespace(
|
||||||
|
namespace_name,
|
||||||
|
builtin_keybinds.get(namespace_name) orelse builtin_keybinds.get("flow").?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return try root.get_keybind_namespace_file_name(namespace_name);
|
||||||
|
}
|
||||||
|
|
||||||
const expectEqual = std.testing.expectEqual;
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
|
||||||
const parse_test_cases = .{
|
const parse_test_cases = .{
|
||||||
|
|
27
src/main.zig
27
src/main.zig
|
@ -438,6 +438,20 @@ fn write_json_file(comptime T: type, data: T, allocator: std.mem.Allocator, file
|
||||||
try cbor.JsonStream(std.fs.File).jsonWriteValue(&s, &iter);
|
try cbor.JsonStream(std.fs.File).jsonWriteValue(&s, &iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_keybind_namespace(allocator: std.mem.Allocator, namespace_name: []const u8) ?[]const u8 {
|
||||||
|
const file_name = get_keybind_namespace_file_name(namespace_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_keybind_namespace(namespace_name: []const u8, content: []const u8) !void {
|
||||||
|
const file_name = try get_keybind_namespace_file_name(namespace_name);
|
||||||
|
var file = try std.fs.createFileAbsolute(file_name, .{ .truncate = true });
|
||||||
|
defer file.close();
|
||||||
|
return file.writeAll(content);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_config_dir() ![]const u8 {
|
pub fn get_config_dir() ![]const u8 {
|
||||||
return get_app_config_dir(application_name);
|
return get_app_config_dir(application_name);
|
||||||
}
|
}
|
||||||
|
@ -478,6 +492,10 @@ fn get_app_config_dir(appname: []const u8) ![]const u8 {
|
||||||
error.PathAlreadyExists => {},
|
error.PathAlreadyExists => {},
|
||||||
else => return e,
|
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 {};
|
||||||
|
|
||||||
return config_dir;
|
return config_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,6 +622,15 @@ pub fn get_restore_file_name() ![]const u8 {
|
||||||
return restore_file;
|
return restore_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const keybind_dir = "keys";
|
||||||
|
|
||||||
|
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}/{s}.json", .{ try get_app_config_dir(application_name), keybind_dir, namespace_name });
|
||||||
|
}
|
||||||
|
|
||||||
fn restart() noreturn {
|
fn restart() noreturn {
|
||||||
const argv = [_]?[*:0]const u8{
|
const argv = [_]?[*:0]const u8{
|
||||||
std.os.argv[0],
|
std.os.argv[0],
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget {
|
||||||
try self.menu.add_item_with_handler("Open recent project ········ :r", menu_action_open_recent_project);
|
try self.menu.add_item_with_handler("Open recent project ········ :r", menu_action_open_recent_project);
|
||||||
try self.menu.add_item_with_handler("Show/Run commands ·········· :p", menu_action_show_commands);
|
try self.menu.add_item_with_handler("Show/Run commands ·········· :p", menu_action_show_commands);
|
||||||
try self.menu.add_item_with_handler("Open config file ··········· :c", menu_action_open_config);
|
try self.menu.add_item_with_handler("Open config file ··········· :c", menu_action_open_config);
|
||||||
|
try self.menu.add_item_with_handler("Open key bindings file ····· :k", menu_action_open_keybind_config);
|
||||||
try self.menu.add_item_with_handler("Change theme ··············· :t", menu_action_change_theme);
|
try self.menu.add_item_with_handler("Change theme ··············· :t", menu_action_change_theme);
|
||||||
try self.menu.add_item_with_handler("Quit/Close ················· :q", menu_action_quit);
|
try self.menu.add_item_with_handler("Quit/Close ················· :q", menu_action_quit);
|
||||||
self.menu.resize(.{ .y = 15, .x = 9, .w = 32 });
|
self.menu.resize(.{ .y = 15, .x = 9, .w = 32 });
|
||||||
|
@ -125,6 +126,10 @@ fn menu_action_open_config(_: **Menu.State(*Self), _: *Button.State(*Menu.State(
|
||||||
command.executeName("open_config", .{}) catch {};
|
command.executeName("open_config", .{}) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn menu_action_open_keybind_config(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||||
|
command.executeName("open_keybind_config", .{}) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
fn menu_action_change_theme(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
fn menu_action_change_theme(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void {
|
||||||
command.executeName("change_theme", .{}) catch {};
|
command.executeName("change_theme", .{}) catch {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -807,6 +807,15 @@ const cmds = struct {
|
||||||
self.mini_mode = null;
|
self.mini_mode = null;
|
||||||
}
|
}
|
||||||
pub const exit_mini_mode_meta = .{ .interactive = false };
|
pub const exit_mini_mode_meta = .{ .interactive = false };
|
||||||
|
|
||||||
|
pub fn open_keybind_config(self: *Self, _: Ctx) Result {
|
||||||
|
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 = .{ .description = "Edit key bindings" };
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MiniMode = struct {
|
pub const MiniMode = struct {
|
||||||
|
|
Loading…
Add table
Reference in a new issue