diff --git a/build.zig.zon b/build.zig.zon index a1cbb89b..d6b97940 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -43,15 +43,18 @@ .lazy = true, }, .wio = .{ - .path = "../flow-deps/wio", + .url = "git+https://github.com/neurocyte/wio?ref=master#6186501162ace8645036e71fdb7ebad76a0dca71", + .hash = "wio-0.0.0-8xHrr8XzBQAYPvWczIC0RU40hP-cVH2HR1zcTVfP7r8l", .lazy = true, }, .sokol = .{ - .path = "../flow-deps/sokol-zig", + .url = "git+https://github.com/floooh/sokol-zig?ref=master#fa5aa645f6fa9cca1d70bb93a89312b4b7022ac3", + .hash = "sokol-0.1.0-pb1HK-HUNgDWWepemJMSKWMTj87v3aTfqnptRonvR9pm", .lazy = true, }, .TrueType = .{ - .path = "../flow-deps/TrueType", + .url = "git+https://codeberg.org/andrewrk/TrueType?ref=main#8b5dbf3a3bfbb84190377385f5e609c8788a5450", + .hash = "TrueType-0.0.0-Ne-mWLVxAQAvMshfhjrJh3GbRHBLSNtF-zXZ0Zt_bHGP", .lazy = true, }, .diffz = .{ diff --git a/src/gui/wio/app.zig b/src/gui/wio/app.zig index 0f8c4b2b..e38f4b73 100644 --- a/src/gui/wio/app.zig +++ b/src/gui/wio/app.zig @@ -68,6 +68,10 @@ var title_buf: [512]u8 = undefined; var title_len: usize = 0; var title_dirty: std.atomic.Value(bool) = .init(false); +// Window class / app_id - read on wio thread during window creation +var window_class_buf: [256]u8 = undefined; +var window_class_len: usize = 0; + // Clipboard write (heap-allocated, transferred to wio thread) var clipboard_mutex: std.Thread.Mutex = .{}; var clipboard_write: ?[]u8 = null; @@ -90,8 +94,13 @@ var wio_font: gpu.Font = .{ .cell_size = .{ .x = 8, .y = 16 }, .backend = .{ .fr pub fn start() !std.Thread { tui_pid = thespian.self_pid().clone(); font_name_len = 0; + window_class_len = 0; stop_requested.store(false, .release); loadConfig(); + const class = thespian.env.get().str("window-class"); + const copy_len = @min(class.len, window_class_buf.len); + @memcpy(window_class_buf[0..copy_len], class[0..copy_len]); + window_class_len = copy_len; return std.Thread.spawn(.{}, wioLoop, .{}); } @@ -380,6 +389,7 @@ fn wioLoop() void { var window = wio.createWindow(.{ .title = "flow", + .app_id = if (window_class_len > 0) window_class_buf[0..window_class_len] else "flow", .size = .{ .width = 1280, .height = 720 }, .scale = 1.0, .opengl = .{ @@ -658,7 +668,7 @@ fn sendKey(kind: u8, codepoint: u21, shifted_codepoint: u21, mods: input_transla // Text is the character that would be typed: empty when ctrl/alt active, // shifted_codepoint when shift is held, otherwise codepoint. const text_cp: u21 = if (mods.shift) shifted_codepoint else codepoint; - const text_len: usize = if (!mods.ctrl and !mods.alt and text_cp >= 0x20 and text_cp != 0x7f) + const text_len: usize = if (!mods.ctrl and !mods.alt and text_cp >= 0x20 and text_cp != 0x7f and text_cp < 0xE000) std.unicode.utf8Encode(text_cp, &text_buf) catch 0 else 0; diff --git a/src/keybind/builtin/flow.json b/src/keybind/builtin/flow.json index c6424938..5fbfeb81 100644 --- a/src/keybind/builtin/flow.json +++ b/src/keybind/builtin/flow.json @@ -26,6 +26,10 @@ ["ctrl+`", "open_terminal"], ["ctrl+j", "toggle_panel"], ["ctrl+shift+j", "toggle_maximize_panel"], + ["ctrl+alt+home", "grow_panel"], + ["ctrl+shift+alt+home", "grow_panel", 3], + ["ctrl+alt+end", "shrink_panel"], + ["ctrl+shift+alt+end", "shrink_panel", 3], ["ctrl+q", "quit"], ["ctrl+w", "close_split"], ["ctrl+o", "open_file"], @@ -354,6 +358,10 @@ ["alt+!", "add_task"], ["ctrl+j", "toggle_panel"], ["ctrl+shift+j", "toggle_maximize_panel"], + ["ctrl+alt+home", "grow_panel"], + ["ctrl+shift+alt+home", "grow_panel", 3], + ["ctrl+alt+end", "shrink_panel"], + ["ctrl+shift+alt+end", "shrink_panel", 3], ["ctrl+q", "quit"], ["ctrl+w", "close_file"], ["ctrl+shift+f", "find_in_files"], @@ -523,6 +531,10 @@ ["ctrl+alt+?", "scroll_keybind_hints"], ["alt+f9", "panel_next_widget_style"], ["ctrl+shift+j", "toggle_maximize_panel"], + ["ctrl+alt+home", "grow_panel"], + ["ctrl+shift+alt+home", "grow_panel", 3], + ["ctrl+alt+end", "shrink_panel"], + ["ctrl+shift+alt+end", "shrink_panel", 3], ["ctrl+q", "quit"], ["ctrl+v", "system_paste"], ["ctrl+u", "mini_mode_reset"], @@ -600,10 +612,16 @@ ["ctrl+7", "focus_split", 6], ["ctrl+8", "focus_split", 7], ["ctrl+`", "unfocus_terminal"], - ["ctrl+j", "toggle_panel"], ["ctrl+shift+page_down", "terminal_scroll_down"], ["ctrl+shift+page_up", "terminal_scroll_up"], + ["ctrl+alt+page_down", "terminal_scroll_down"], + ["ctrl+alt+page_up", "terminal_scroll_up"], + ["ctrl+j", "toggle_panel"], ["ctrl+shift+j", "toggle_maximize_panel"], + ["ctrl+alt+home", "grow_panel"], + ["ctrl+shift+alt+home", "grow_panel", 3], + ["ctrl+alt+end", "shrink_panel"], + ["ctrl+shift+alt+end", "shrink_panel", 3], ["ctrl+shift+p", "open_command_palette"], ["alt+shift+p", "open_command_palette"], ["alt+x", "open_command_palette"], diff --git a/src/main.zig b/src/main.zig index 054340ca..41cd98e6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -83,9 +83,10 @@ pub fn main() anyerror!void { .dark = "Use dark color scheme", .light = "Use light color scheme", .version = "Show build version and exit", + .class = "Set window class", }; - pub const formats = .{ .frame_rate = "num", .trace_level = "num", .exec = "cmds" }; + pub const formats = .{ .frame_rate = "num", .trace_level = "num", .exec = "cmds", .class = "name" }; pub const switches = .{ .project = 'p', @@ -123,6 +124,7 @@ pub fn main() anyerror!void { dark: bool, light: bool, version: bool, + class: ?[]const u8, positional: struct { trailing: []const []const u8, @@ -247,6 +249,7 @@ pub fn main() anyerror!void { if (args.frame_rate) |s| env.num_set("frame-rate", @intCast(s)); env.proc_set("log", log_proc.ref()); if (args.language) |s| env.str_set("language", s); + if (args.class) |s| env.str_set("window-class", s); var eh = thespian.make_exit_handler({}, print_exit_status); const tui_proc = try tui.spawn(a, &ctx, &eh, &env); diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 078cdaca..e09a81e3 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -280,20 +280,39 @@ fn handle_bottom_bar_event(self: *Self, _: tp.pid_ref, m: tp.message) tp.result } fn bottom_bar_primary_drag(self: *Self, y: usize) tp.result { + const h = @max(1, self.plane.dim_y() -| y); + return self.set_panel_height_abs(h); +} + +fn set_panel_height_abs(self: *Self, y: usize) tp.result { const panels = self.panels orelse blk: { cmds.toggle_panel(self, .{}) catch return; break :blk self.panels.?; }; - const h = self.plane.dim_y(); - self.panel_height = @max(1, h - @min(h, y + 1)); + const max_h = self.box().h -| 1; + std.log.debug("set_panel_height: {?d} {d}", .{ self.panel_height, y }); + self.panel_height = @max(1, @min(max_h, y)); self.panel_maximized = false; panels.layout_ = .{ .static = self.panel_height.? }; - if (self.panel_height == 1) { + const panel_height = self.panel_height orelse return; + if (panel_height == 1) { self.panel_height = null; command.executeName("toggle_panel", .{}) catch {}; + } else if (panel_height >= max_h) { + self.panel_maximized = true; + panels.layout_ = .{ .static = max_h }; + self.panel_height = null; } } +fn set_panel_height_rel(self: *Self, y: isize) tp.result { + if (self.panels == null and y < 0) return; + if (self.panel_maximized and y > 0) return; + const panel_h: isize = @intCast(self.get_panel_height()); + const h = @max(1, panel_h +| y); + return self.set_panel_height_abs(h); +} + pub fn get_panel_height(self: *Self) usize { return self.panel_height orelse self.box().h / 5; } @@ -942,7 +961,11 @@ const cmds = struct { pub const toggle_panel_meta: Meta = .{ .description = "Toggle panel" }; pub fn toggle_maximize_panel(self: *Self, _: Ctx) Result { - const panels = self.panels orelse return; + const panels = self.panels orelse blk: { + cmds.toggle_panel(self, .{}) catch return; + self.panel_maximized = false; + break :blk self.panels.?; + }; const max_h = self.box().h -| 1; if (self.panel_maximized) { // Restore previous height @@ -957,6 +980,21 @@ const cmds = struct { } pub const toggle_maximize_panel_meta: Meta = .{ .description = "Toggle maximize panel" }; + pub fn grow_panel(self: *Self, ctx: Ctx) Result { + var n: usize = 1; + _ = try ctx.args.match(.{tp.extract(&n)}); + return self.set_panel_height_rel(@intCast(n)); + } + pub const grow_panel_meta: Meta = .{ .description = "Make the panel larger" }; + + pub fn shrink_panel(self: *Self, ctx: Ctx) Result { + var n: usize = 1; + _ = try ctx.args.match(.{tp.extract(&n)}); + const neg_n = 0 - @as(isize, @intCast(n)); + return self.set_panel_height_rel(neg_n); + } + pub const shrink_panel_meta: Meta = .{ .description = "Make the panel smaller" }; + pub fn toggle_logview(self: *Self, _: Ctx) Result { try self.toggle_panel_view(logview, .toggle); }