diff --git a/build.zig b/build.zig index b2c46749..4df9709c 100644 --- a/build.zig +++ b/build.zig @@ -114,21 +114,17 @@ fn build_release( all_targets: bool, test_filters: []const []const u8, ) void { - const targets: []const struct { std.Target.Query, Renderer } = if (all_targets) &.{ - .{ .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, .terminal }, - // .{ .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = null }, .gui }, - .{ .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .musl }, .terminal }, - .{ .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .musl }, .terminal }, - // .{ .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = null }, .gui }, - .{ .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabihf }, .terminal }, - .{ .{ .cpu_arch = .x86_64, .os_tag = .macos }, .terminal }, - .{ .{ .cpu_arch = .aarch64, .os_tag = .macos }, .terminal }, - .{ .{ .cpu_arch = .x86_64, .os_tag = .windows }, .terminal }, - .{ .{ .cpu_arch = .x86_64, .os_tag = .windows }, .d3d11 }, - .{ .{ .cpu_arch = .aarch64, .os_tag = .windows }, .terminal }, - .{ .{ .cpu_arch = .aarch64, .os_tag = .windows }, .d3d11 }, - .{ .{ .cpu_arch = .x86_64, .os_tag = .freebsd }, .terminal }, - .{ .{ .cpu_arch = .aarch64, .os_tag = .freebsd }, .terminal }, + const targets: []const std.Target.Query = if (all_targets) &.{ + .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .musl }, + .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabihf }, + .{ .cpu_arch = .x86_64, .os_tag = .macos }, + .{ .cpu_arch = .aarch64, .os_tag = .macos }, + .{ .cpu_arch = .x86_64, .os_tag = .windows }, + .{ .cpu_arch = .aarch64, .os_tag = .windows }, + .{ .cpu_arch = .x86_64, .os_tag = .freebsd }, + .{ .cpu_arch = .aarch64, .os_tag = .freebsd }, } else blk: { const maybe_triple = b.option( []const u8, @@ -137,18 +133,8 @@ fn build_release( ); const triple = maybe_triple orelse { const native_target = b.resolveTargetQuery(.{}).result; - break :blk switch (native_target.os.tag) { - .linux => &.{ - .{ .{ .cpu_arch = native_target.cpu.arch, .os_tag = native_target.os.tag, .abi = .musl }, .terminal }, - // .{ .{ .cpu_arch = native_target.cpu.arch, .os_tag = native_target.os.tag, .abi = null }, .gui }, - }, - .windows => &.{ - .{ .{ .cpu_arch = native_target.cpu.arch, .os_tag = native_target.os.tag }, .terminal }, - .{ .{ .cpu_arch = native_target.cpu.arch, .os_tag = native_target.os.tag }, .d3d11 }, - }, - else => &.{ - .{ .{ .cpu_arch = native_target.cpu.arch, .os_tag = native_target.os.tag }, .terminal }, - }, + break :blk &.{ + .{ .cpu_arch = native_target.cpu.arch, .os_tag = native_target.os.tag }, }; }; const selected_target = std.Build.parseTargetQuery(.{ @@ -156,18 +142,8 @@ fn build_release( }) catch |err| switch (err) { error.ParseFailed => @panic("unknown target"), }; - break :blk switch (selected_target.os_tag.?) { - .linux => &.{ - .{ .{ .cpu_arch = selected_target.cpu_arch, .os_tag = selected_target.os_tag, .abi = .musl }, .terminal }, - // .{ .{ .cpu_arch = selected_target.cpu_arch, .os_tag = selected_target.os_tag, .abi = .gnu }, .gui }, - }, - .windows => &.{ - .{ .{ .cpu_arch = selected_target.cpu_arch, .os_tag = selected_target.os_tag, .abi = selected_target.abi }, .terminal }, - .{ .{ .cpu_arch = selected_target.cpu_arch, .os_tag = selected_target.os_tag, .abi = selected_target.abi }, .d3d11 }, - }, - else => &.{ - .{ .{ .cpu_arch = selected_target.cpu_arch, .os_tag = selected_target.os_tag, .abi = selected_target.abi }, .terminal }, - }, + break :blk &.{ + .{ .cpu_arch = selected_target.cpu_arch, .os_tag = selected_target.os_tag, .abi = selected_target.abi }, }; }; const optimize = b.standardOptimizeOption(.{}); @@ -179,9 +155,8 @@ fn build_release( b.getInstallStep().dependOn(&b.addInstallFile(version_file, "version").step); for (targets) |t| { - const renderer = t.@"1"; - const target = b.resolveTargetQuery(t.@"0"); - var triple = std.mem.splitScalar(u8, t.@"0".zigTriple(b.allocator) catch unreachable, '-'); + const target = b.resolveTargetQuery(t); + var triple = std.mem.splitScalar(u8, t.zigTriple(b.allocator) catch unreachable, '-'); const arch = triple.next() orelse unreachable; const os = triple.next() orelse unreachable; const target_path = std.mem.join(b.allocator, "-", &[_][]const u8{ os, arch }) catch unreachable; @@ -201,7 +176,7 @@ fn build_release( true, // strip release builds use_llvm, pie, - renderer, + .terminal, version, test_filters, ); @@ -220,10 +195,50 @@ fn build_release( false, // don't strip debug builds use_llvm, pie, - renderer, + .terminal, version, test_filters, ); + + if (t.os_tag == .windows) { + build_exe( + b, + run_step, + check_step, + test_step, + lint_step, + target, + optimize_release, + .{ .dest_dir = .{ .override = .{ .custom = target_path } } }, + tracy_enabled, + use_tree_sitter, + true, // strip release builds + use_llvm, + pie, + .d3d11, + version, + test_filters, + ); + + build_exe( + b, + run_step, + check_step, + test_step, + lint_step, + target, + optimize_debug, + .{ .dest_dir = .{ .override = .{ .custom = target_path_debug } } }, + tracy_enabled, + use_tree_sitter, + false, // don't strip debug builds + use_llvm, + pie, + .d3d11, + version, + test_filters, + ); + } } } @@ -491,10 +506,6 @@ pub fn build_exe( .d3d11 => { const win32_dep = b.lazyDependency("win32", .{}) orelse break :blk tui_renderer_mod; const win32_mod = win32_dep.module("win32"); - const gui_xy_mod = b.createModule(.{ .root_source_file = b.path("src/gui/xy.zig") }); - const gui_cell_mod = b.createModule(.{ .root_source_file = b.path("src/gui/Cell.zig") }); - const gui_glyph_cache_mod = b.createModule(.{ .root_source_file = b.path("src/gui/GlyphIndexCache.zig") }); - const gui_xterm_mod = b.createModule(.{ .root_source_file = b.path("src/gui/xterm.zig") }); const gui_mod = b.createModule(.{ .root_source_file = b.path("src/win32/gui.zig"), .imports = &.{ @@ -508,10 +519,6 @@ pub fn build_exe( .{ .name = "color", .module = color_mod }, .{ .name = "gui_config", .module = gui_config_mod }, .{ .name = "tracy", .module = tracy_mod }, - .{ .name = "xy", .module = gui_xy_mod }, - .{ .name = "Cell", .module = gui_cell_mod }, - .{ .name = "GlyphIndexCache", .module = gui_glyph_cache_mod }, - .{ .name = "xterm", .module = gui_xterm_mod }, }, }); gui_mod.addIncludePath(b.path("src/win32")); diff --git a/src/gui/gpu/builtin.glsl.zig b/src/gui/gpu/builtin.glsl.zig index eb1b3873..88fb7501 100644 --- a/src/gui/gpu/builtin.glsl.zig +++ b/src/gui/gpu/builtin.glsl.zig @@ -15,14 +15,6 @@ pub const FsParams = extern struct { col_count: i32, row_count: i32, viewport_height: i32, - // Primary cursor (position + appearance) - cursor_col: i32, - cursor_row: i32, - cursor_shape: i32, // 0=block, 1=beam, 2=underline - cursor_vis: i32, // 0=hidden, 1=visible - cursor_color: [4]f32, // RGBA normalized [0,1] - // Secondary cursor colour (positions encoded in ShaderCell._pad) - sec_cursor_color: [4]f32, // RGBA normalized [0,1] }; const vs_src = @@ -42,12 +34,6 @@ const fs_src = \\uniform int col_count; \\uniform int row_count; \\uniform int viewport_height; - \\uniform int cursor_col; - \\uniform int cursor_row; - \\uniform int cursor_shape; - \\uniform int cursor_vis; - \\uniform vec4 cursor_color; - \\uniform vec4 sec_cursor_color; \\uniform sampler2D glyph_tex_glyph_smp; \\uniform usampler2D cell_tex_cell_smp; \\out vec4 frag_color; @@ -73,7 +59,7 @@ const fs_src = \\ return; \\ } \\ - \\ // Fetch cell: texel = (glyph_index, bg_packed, fg_packed, cursor_flag) + \\ // Fetch cell: texel = (glyph_index, bg_packed, fg_packed, 0) \\ uvec4 cell = texelFetch(cell_tex_cell_smp, ivec2(col, row), 0); \\ vec4 bg = unpack_rgba(cell.g); \\ vec4 fg = unpack_rgba(cell.b); @@ -92,31 +78,9 @@ const fs_src = \\ gr * cell_size_y + cell_px_y); \\ float glyph_alpha = texelFetch(glyph_tex_glyph_smp, atlas_coord, 0).r; \\ - \\ // Cursor detection - \\ bool is_primary = (cursor_vis != 0) && (col == cursor_col) && (row == cursor_row); - \\ bool is_secondary = (cell.a != 0u); - \\ - \\ vec3 final_bg = bg.rgb; - \\ vec3 final_fg = fg.rgb; - \\ - \\ if (is_primary || is_secondary) { - \\ vec4 cur = is_primary ? cursor_color : sec_cursor_color; - \\ int shape = cursor_shape; - \\ - \\ if (shape == 1) { - \\ // Beam: 2px vertical bar at left edge of cell - \\ if (cell_px_x < 2) { frag_color = vec4(cur.rgb, 1.0); return; } - \\ } else if (shape == 2) { - \\ // Underline: 2px horizontal bar at bottom of cell - \\ if (cell_px_y >= cell_size_y - 2) { frag_color = vec4(cur.rgb, 1.0); return; } - \\ } else { - \\ // Block: cursor colour as bg, inverted for glyph contrast - \\ final_bg = cur.rgb; - \\ final_fg = vec3(1.0) - cur.rgb; - \\ } - \\ } - \\ - \\ frag_color = vec4(mix(final_bg, final_fg, fg.a * glyph_alpha), 1.0); + \\ // Blend fg over bg + \\ vec3 color = mix(bg.rgb, fg.rgb, fg.a * glyph_alpha); + \\ frag_color = vec4(color, 1.0); \\} ; @@ -127,7 +91,7 @@ pub fn shaderDesc(backend: sg.Backend) sg.ShaderDesc { desc.vertex_func.source = vs_src; desc.fragment_func.source = fs_src; - // Fragment uniform block: individual uniforms (GLCORE uses glUniform* calls) + // Fragment uniform block: 4 individual INT uniforms desc.uniform_blocks[0].stage = .FRAGMENT; desc.uniform_blocks[0].size = @sizeOf(FsParams); desc.uniform_blocks[0].layout = .NATIVE; @@ -136,12 +100,6 @@ pub fn shaderDesc(backend: sg.Backend) sg.ShaderDesc { desc.uniform_blocks[0].glsl_uniforms[2] = .{ .type = .INT, .glsl_name = "col_count" }; desc.uniform_blocks[0].glsl_uniforms[3] = .{ .type = .INT, .glsl_name = "row_count" }; desc.uniform_blocks[0].glsl_uniforms[4] = .{ .type = .INT, .glsl_name = "viewport_height" }; - desc.uniform_blocks[0].glsl_uniforms[5] = .{ .type = .INT, .glsl_name = "cursor_col" }; - desc.uniform_blocks[0].glsl_uniforms[6] = .{ .type = .INT, .glsl_name = "cursor_row" }; - desc.uniform_blocks[0].glsl_uniforms[7] = .{ .type = .INT, .glsl_name = "cursor_shape" }; - desc.uniform_blocks[0].glsl_uniforms[8] = .{ .type = .INT, .glsl_name = "cursor_vis" }; - desc.uniform_blocks[0].glsl_uniforms[9] = .{ .type = .FLOAT4, .glsl_name = "cursor_color" }; - desc.uniform_blocks[0].glsl_uniforms[10] = .{ .type = .FLOAT4, .glsl_name = "sec_cursor_color" }; // Glyph atlas texture: R8 → sample_type = FLOAT desc.views[0].texture = .{ diff --git a/src/gui/gpu/gpu.zig b/src/gui/gpu/gpu.zig index 7c75b181..d741adbc 100644 --- a/src/gui/gpu/gpu.zig +++ b/src/gui/gpu/gpu.zig @@ -18,16 +18,6 @@ pub const Cell = gui_cell.Cell; pub const Color = gui_cell.Rgba8; const Rgba8 = gui_cell.Rgba8; -pub const CursorShape = enum(i32) { block = 0, beam = 1, underline = 2 }; - -pub const CursorInfo = struct { - vis: bool = false, - row: u16 = 0, - col: u16 = 0, - shape: CursorShape = .block, - color: Color = Color.initRgb(255, 255, 255), -}; - const log = std.log.scoped(.gpu); // Maximum glyph atlas dimension. 4096 is universally supported and gives @@ -360,8 +350,6 @@ pub fn paint( col_count: u16, top: u16, cells: []const Cell, - cursor: CursorInfo, - secondary_cursors: []const CursorInfo, ) void { const shader_col_count: u16 = @intCast(@divTrunc(client_size.x, font.cell_size.x)); const shader_row_count: u16 = @intCast(@divTrunc(client_size.y, font.cell_size.y)); @@ -400,13 +388,6 @@ pub fn paint( } } - // Mark secondary cursor cells in the _pad field (read by fragment shader). - for (secondary_cursors) |sc| { - if (!sc.vis) continue; - if (sc.row >= shader_row_count or sc.col >= shader_col_count) continue; - shader_cells[@as(usize, sc.row) * shader_col_count + sc.col]._pad = 1; - } - // Upload glyph atlas to GPU if any new glyphs were rasterized this frame. if (state.glyph_atlas_dirty) flushGlyphAtlas(state); @@ -448,23 +429,12 @@ pub fn paint( bindings.samplers[1] = global.cell_sampler; sg.applyBindings(bindings); - const sec_color: Color = if (secondary_cursors.len > 0) - secondary_cursors[0].color - else - Color.initRgb(255, 255, 255); - const fs_params = builtin_shader.FsParams{ .cell_size_x = font.cell_size.x, .cell_size_y = font.cell_size.y, .col_count = shader_col_count, .row_count = shader_row_count, .viewport_height = @intCast(client_size.y), - .cursor_col = cursor.col, - .cursor_row = cursor.row, - .cursor_shape = @intFromEnum(cursor.shape), - .cursor_vis = if (cursor.vis) 1 else 0, - .cursor_color = colorToVec4(cursor.color), - .sec_cursor_color = colorToVec4(sec_color), }; sg.applyUniforms(0, .{ .ptr = &fs_params, @@ -476,15 +446,6 @@ pub fn paint( // Note: caller (app.zig) calls sg.commit() and window.swapBuffers() } -fn colorToVec4(c: Color) [4]f32 { - return .{ - @as(f32, @floatFromInt(c.r)) / 255.0, - @as(f32, @floatFromInt(c.g)) / 255.0, - @as(f32, @floatFromInt(c.b)) / 255.0, - @as(f32, @floatFromInt(c.a)) / 255.0, - }; -} - fn oom(e: error{OutOfMemory}) noreturn { @panic(@errorName(e)); } diff --git a/src/gui/wio/app.zig b/src/gui/wio/app.zig index 0f8c4b2b..0b1e06bd 100644 --- a/src/gui/wio/app.zig +++ b/src/gui/wio/app.zig @@ -22,12 +22,6 @@ const gui_config = @import("gui_config"); const log = std.log.scoped(.wio_app); -// Re-export cursor types so renderer.zig (which imports 'app' but not 'gpu') -// can use them without a direct dependency on the gpu module. -pub const CursorInfo = gpu.CursorInfo; -pub const CursorShape = gpu.CursorShape; -pub const GpuColor = gpu.Color; - // ── Shared state (protected by screen_mutex) ────────────────────────────── const ScreenSnapshot = struct { @@ -37,9 +31,6 @@ const ScreenSnapshot = struct { widths: []u8, width: u16, height: u16, - // Cursor state (set by renderer thread, consumed by wio thread) - cursor: gpu.CursorInfo, - secondary_cursors: []gpu.CursorInfo, // heap-allocated, freed with snapshot }; var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{}; @@ -101,11 +92,7 @@ pub fn stop() void { } /// Called from the tui thread to push a new screen to the GPU thread. -pub fn updateScreen( - vx_screen: *const vaxis.Screen, - cursor: gpu.CursorInfo, - secondary_cursors: []const gpu.CursorInfo, -) void { +pub fn updateScreen(vx_screen: *const vaxis.Screen) void { const allocator = gpa.allocator(); const cell_count: usize = @as(usize, vx_screen.width) * @as(usize, vx_screen.height); @@ -119,13 +106,6 @@ pub fn updateScreen( allocator.free(new_codepoints); return; }; - const new_sec = allocator.alloc(gpu.CursorInfo, secondary_cursors.len) catch { - allocator.free(new_cells); - allocator.free(new_codepoints); - allocator.free(new_widths); - return; - }; - @memcpy(new_sec, secondary_cursors); // Convert vaxis cells → gpu.Cell (colours only; glyph indices filled on GPU thread). for (vx_screen.buf[0..cell_count], new_cells, new_codepoints, new_widths) |*vc, *gc, *cp, *wt| { @@ -151,7 +131,6 @@ pub fn updateScreen( allocator.free(old.cells); allocator.free(old.codepoints); allocator.free(old.widths); - allocator.free(old.secondary_cursors); } screen_snap = .{ .cells = new_cells, @@ -159,8 +138,6 @@ pub fn updateScreen( .widths = new_widths, .width = vx_screen.width, .height = vx_screen.height, - .cursor = cursor, - .secondary_cursors = new_sec, }; screen_pending.store(true, .release); @@ -534,14 +511,8 @@ fn wioLoop() void { const cp = pixelToCellPos(mouse_pos); tui_pid.send(.{ "RDR", "B", @as(u8, 1), btn_id, cp.col, cp.row, cp.xoff, cp.yoff }) catch {}; }, - .focused => { - window.enableTextInput(.{}); - tui_pid.send(.{"focus_in"}) catch {}; - }, - .unfocused => { - window.disableTextInput(); - tui_pid.send(.{"focus_out"}) catch {}; - }, + .focused => window.enableTextInput(.{}), + .unfocused => window.disableTextInput(), else => {}, } } @@ -590,7 +561,6 @@ fn wioLoop() void { allocator.free(s.cells); allocator.free(s.codepoints); allocator.free(s.widths); - allocator.free(s.secondary_cursors); } state.size = .{ .x = win_size.width, .y = win_size.height }; @@ -625,8 +595,6 @@ fn wioLoop() void { s.width, 0, cells_with_glyphs, - s.cursor, - s.secondary_cursors, ); sg.commit(); window.swapBuffers(); diff --git a/src/renderer/gui/renderer.zig b/src/renderer/gui/renderer.zig index 2cc582f2..bb3d0675 100644 --- a/src/renderer/gui/renderer.zig +++ b/src/renderer/gui/renderer.zig @@ -3,7 +3,7 @@ pub const log_name = "renderer"; const std = @import("std"); const cbor = @import("cbor"); -pub const vaxis = @import("vaxis"); +const vaxis = @import("vaxis"); const Style = @import("theme").Style; const Color = @import("theme").Color; pub const CursorShape = vaxis.Cell.CursorShape; @@ -56,20 +56,6 @@ dispatch_event: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null, thread: ?std.Thread = null, window_ready: bool = false, -cursor_info: app.CursorInfo = .{}, -cursor_color: app.GpuColor = app.GpuColor.initRgb(255, 255, 255), -secondary_cursors: std.ArrayListUnmanaged(app.CursorInfo) = .{}, -secondary_color: app.GpuColor = app.GpuColor.initRgb(255, 255, 255), - -cursor_blink: bool = false, -blink_on: bool = true, -blink_epoch: i64 = 0, -blink_period_us: i64 = 500_000, -blink_idle_us: i64 = 15_000_000, -blink_last_change: i64 = 0, -prev_cursor: app.CursorInfo = .{}, -prev_cursor_blink: bool = false, - const global = struct { var init_called: bool = false; }; @@ -106,7 +92,6 @@ pub fn init( .dispatch_initialized = dispatch_initialized, }; result.vx.caps.unicode = .unicode; - result.vx.caps.multi_cursor = true; result.vx.screen.width_method = .unicode; return result; } @@ -116,7 +101,6 @@ pub fn deinit(self: *Self) void { var drop: std.Io.Writer.Discarding = .init(&.{}); self.vx.deinit(self.allocator, &drop.writer); self.event_buffer.deinit(); - self.secondary_cursors.deinit(self.allocator); } pub fn run(self: *Self) Error!void { @@ -137,47 +121,9 @@ fn fmtmsg(self: *Self, value: anytype) std.Io.Writer.Error![]const u8 { return self.event_buffer.written(); } -pub fn render(self: *Self) error{}!bool { - if (!self.window_ready) return false; - - var cursor = self.cursor_info; - - // Detect changes since the last rendered frame. Reset blink epoch and idle - // timer on any meaningful change so the cursor snaps to visible immediately. - if (cursor.vis != self.prev_cursor.vis or - cursor.row != self.prev_cursor.row or - cursor.col != self.prev_cursor.col or - cursor.shape != self.prev_cursor.shape or - self.cursor_blink != self.prev_cursor_blink) - { - const now = std.time.microTimestamp(); - if (cursor.vis) { - self.blink_epoch = now; - self.blink_on = true; - } - self.blink_last_change = now; - } - self.prev_cursor = cursor; - self.prev_cursor_blink = self.cursor_blink; - - // Apply blink unless the cursor has been idle for too long. - if (cursor.vis and self.cursor_blink) { - const now = std.time.microTimestamp(); - const idle = now - self.blink_last_change; - if (idle < self.blink_idle_us) { - const elapsed = @mod(now - self.blink_epoch, self.blink_period_us * 2); - self.blink_on = elapsed < self.blink_period_us; - cursor.vis = self.blink_on; - } else { - cursor.vis = true; // freeze visible after idle timeout - } - } - - app.updateScreen(&self.vx.screen, cursor, self.secondary_cursors.items); - - if (!self.cursor_info.vis or !self.cursor_blink) return false; - const idle = std.time.microTimestamp() - self.blink_last_change; - return idle < self.blink_idle_us; +pub fn render(self: *Self) error{}!void { + if (!self.window_ready) return; + app.updateScreen(&self.vx.screen); } pub fn sigwinch(self: *Self) !void { @@ -468,11 +414,13 @@ pub fn get_fontfaces(self: *Self) void { } pub fn set_terminal_cursor_color(self: *Self, color: Color) void { - self.cursor_color = themeColorToGpu(color); + _ = self; + _ = color; } pub fn set_terminal_secondary_cursor_color(self: *Self, color: Color) void { - self.secondary_color = themeColorToGpu(color); + _ = self; + _ = color; } pub fn set_terminal_working_directory(self: *Self, absolute_path: []const u8) void { @@ -514,56 +462,24 @@ pub fn request_mouse_cursor_default(self: *Self, push_or_pop: bool) void { } pub fn cursor_enable(self: *Self, y: i32, x: i32, shape: CursorShape) !void { - self.cursor_blink = isBlink(shape); - self.cursor_info = .{ - .vis = true, - .row = if (y < 0) 0 else @intCast(y), - .col = if (x < 0) 0 else @intCast(x), - .shape = vaxisCursorShape(shape), - .color = self.cursor_color, - }; + _ = self; + _ = y; + _ = x; + _ = shape; } pub fn cursor_disable(self: *Self) void { - self.cursor_info.vis = false; + _ = self; } pub fn clear_all_multi_cursors(self: *Self) !void { - self.secondary_cursors.clearRetainingCapacity(); + _ = self; } pub fn show_multi_cursor_yx(self: *Self, y: i32, x: i32) !void { - try self.secondary_cursors.append(self.allocator, .{ - .vis = true, - .row = if (y < 0) 0 else @intCast(y), - .col = if (x < 0) 0 else @intCast(x), - .shape = self.cursor_info.shape, - .color = self.secondary_color, - }); -} - -fn themeColorToGpu(color: Color) app.GpuColor { - return .{ - .r = @truncate(color.color >> 16), - .g = @truncate(color.color >> 8), - .b = @truncate(color.color), - .a = color.alpha, - }; -} - -fn isBlink(shape: CursorShape) bool { - return switch (shape) { - .default, .block_blink, .beam_blink, .underline_blink => true, - else => false, - }; -} - -fn vaxisCursorShape(shape: CursorShape) app.CursorShape { - return switch (shape) { - .default, .block, .block_blink => .block, - .beam, .beam_blink => .beam, - .underline, .underline_blink => .underline, - }; + _ = self; + _ = y; + _ = x; } pub fn copy_to_system_clipboard(self: *Self, text: []const u8) void { diff --git a/src/renderer/vaxis/renderer.zig b/src/renderer/vaxis/renderer.zig index 30710f43..95025892 100644 --- a/src/renderer/vaxis/renderer.zig +++ b/src/renderer/vaxis/renderer.zig @@ -219,11 +219,10 @@ pub fn run(self: *Self) Error!void { try self.loop.start(); } -pub fn render(self: *Self) !bool { - if (in_panic.load(.acquire)) return false; +pub fn render(self: *Self) !void { + if (in_panic.load(.acquire)) return; try self.vx.render(self.tty.writer()); try self.tty.writer().flush(); - return false; } pub fn sigwinch(self: *Self) !void { diff --git a/src/renderer/win32/renderer.zig b/src/renderer/win32/renderer.zig index 40e4d6a1..94827b6e 100644 --- a/src/renderer/win32/renderer.zig +++ b/src/renderer/win32/renderer.zig @@ -165,10 +165,9 @@ fn fmtmsg(self: *Self, value: anytype) std.Io.Writer.Error![]const u8 { return self.event_buffer.written(); } -pub fn render(self: *Self) error{}!bool { - const hwnd = self.hwnd orelse return false; +pub fn render(self: *Self) error{}!void { + const hwnd = self.hwnd orelse return; _ = gui.updateScreen(hwnd, &self.vx.screen); - return false; } pub fn stop(self: *Self) void { // this is guaranteed because stop won't be called until after diff --git a/src/tui/InputBox.zig b/src/tui/InputBox.zig index 3a4cd8af..8a06b094 100644 --- a/src/tui/InputBox.zig +++ b/src/tui/InputBox.zig @@ -51,7 +51,7 @@ pub fn Options(context: type) type { } if (self.cursor) |cursor| { const pos: c_int = @intCast(cursor); - if (tui.has_native_cursor()) { + if (tui.config().enable_terminal_cursor) { const y, const x = self.plane.rel_yx_to_abs(0, pos + self.opts.padding + self.icon_width); tui.rdr().cursor_enable(y, x, tui.get_cursor_shape()) catch {}; } else { diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 23bd9f60..9f49c1a9 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -376,7 +376,7 @@ pub const Editor = struct { animation_lag: f64, animation_last_time: i64, - software_rendered_cursor: bool, + enable_terminal_cursor: bool, render_whitespace: WhitespaceMode, indent_size: usize, tab_width: usize, @@ -639,7 +639,7 @@ pub const Editor = struct { .animation_frame_rate = frame_rate, .animation_last_time = time.microTimestamp(), .enable_format_on_save = tui.config().enable_format_on_save, - .software_rendered_cursor = !tui.has_native_cursor(), + .enable_terminal_cursor = tui.config().enable_terminal_cursor, .render_whitespace = tui.config().whitespace_mode, }; self.add_default_symbol_triggers(); @@ -1307,7 +1307,7 @@ pub const Editor = struct { fn render_cursors(self: *Self, theme: *const Widget.Theme, cell_map: CellMap, focused: bool) !void { const frame = tracy.initZone(@src(), .{ .name = "editor render cursors" }); defer frame.deinit(); - if (focused and !self.software_rendered_cursor and tui.rdr().vx.caps.multi_cursor) + if (focused and tui.config().enable_terminal_cursor and tui.rdr().vx.caps.multi_cursor) tui.rdr().clear_all_multi_cursors() catch {}; for (self.cursels.items[0 .. self.cursels.items.len - 1]) |*cursel_| if (cursel_.*) |*cursel| { const cursor = cursel.cursor; @@ -1332,7 +1332,7 @@ pub const Editor = struct { const focused = focused_ or self.cursor_focus_override; - if (focused and !self.software_rendered_cursor) { + if (focused and self.enable_terminal_cursor) { if (screen_pos) |pos| { self.render_term_cursor(pos, cursor_shape); } else if (tui.is_mainview_focused() and tui.rdr().vx.caps.multi_cursor and self.has_secondary_cursors()) { @@ -1345,7 +1345,7 @@ pub const Editor = struct { fn render_cursor_secondary(self: *Self, cursor: *const Cursor, theme: *const Widget.Theme, cell_map: CellMap, focused: bool) !void { const pos = self.screen_cursor(cursor) orelse return; set_cell_map_cursor(cell_map, pos.row, pos.col); - if (focused and !self.software_rendered_cursor and tui.rdr().vx.caps.multi_cursor) + if (focused and self.enable_terminal_cursor and tui.rdr().vx.caps.multi_cursor) self.render_term_cursor_secondary(pos) else self.render_soft_cursor(pos, theme.editor_cursor_secondary); diff --git a/src/tui/mode/overlay/completion_dropdown.zig b/src/tui/mode/overlay/completion_dropdown.zig index 94fc7e05..a9a20786 100644 --- a/src/tui/mode/overlay/completion_dropdown.zig +++ b/src/tui/mode/overlay/completion_dropdown.zig @@ -200,7 +200,7 @@ pub fn on_render_menu(self: *Type, button: *Type.ButtonType, theme: *const Widge const icon_: []const u8 = values.kind.icon(); const color: u24 = 0x0; - if (tui.has_native_cursor()) blk: { + if (tui.config().enable_terminal_cursor) blk: { const cursor = self.value.editor.get_primary_abs() orelse break :blk; tui.rdr().cursor_enable(@intCast(cursor.row), @intCast(cursor.col), tui.get_cursor_shape()) catch {}; } diff --git a/src/tui/status/filestate.zig b/src/tui/status/filestate.zig index 337e5cac..3425d59a 100644 --- a/src/tui/status/filestate.zig +++ b/src/tui/status/filestate.zig @@ -117,7 +117,7 @@ fn render_mini_mode(plane: *Plane, theme: *const Widget.Theme) void { _ = plane.putstr_unicode(mini_mode.text) catch {}; if (mini_mode.cursor) |cursor| { const pos: c_int = @intCast(cursor); - if (tui.has_native_cursor()) { + if (tui.config().enable_terminal_cursor) { const y, const x = plane.rel_yx_to_abs(0, pos + 1); tui.rdr().cursor_enable(y, x, tui.get_cursor_shape()) catch {}; } else { diff --git a/src/tui/terminal_view.zig b/src/tui/terminal_view.zig index 9f9d4350..8b80de76 100644 --- a/src/tui/terminal_view.zig +++ b/src/tui/terminal_view.zig @@ -87,7 +87,6 @@ pub fn run_cmd(self: *Self, ctx: command.Context) !void { var argv_list: std.ArrayListUnmanaged([]const u8) = .empty; defer argv_list.deinit(self.allocator); - var have_cmd = false; if (argv_msg) |msg| { var iter = msg.buf; var len = try cbor.decodeArrayHeader(&iter); @@ -95,7 +94,6 @@ pub fn run_cmd(self: *Self, ctx: command.Context) !void { var arg: []const u8 = undefined; if (try cbor.matchValue(&iter, cbor.extract(&arg))) try argv_list.append(self.allocator, arg); - have_cmd = true; } } else { const default_shell = if (builtin.os.tag == .windows) @@ -112,7 +110,7 @@ pub fn run_cmd(self: *Self, ctx: command.Context) !void { const rows: u16 = @intCast(@max(24, self.plane.dim_y())); if (global_vt) |*vt| { - if (!vt.process_exited and have_cmd) { + if (!vt.process_exited) { var msg: std.Io.Writer.Allocating = .init(self.allocator); defer msg.deinit(); try msg.writer.writeAll("terminal is already running '"); @@ -120,9 +118,10 @@ pub fn run_cmd(self: *Self, ctx: command.Context) !void { try msg.writer.writeAll("'"); return tp.exit(msg.written()); } - } else { - try Vt.init(self.allocator, argv_list.items, env, rows, cols, on_exit); + vt.deinit(self.allocator); + global_vt = null; } + try Vt.init(self.allocator, argv_list.items, env, rows, cols, on_exit); self.vt = &global_vt.?; if (self.last_cmd) |cmd| { @@ -380,7 +379,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool { } // Blit the terminal's front screen into our vaxis.Window. - const software_cursor = !tui.has_native_cursor(); + const software_cursor = build_options.gui or !tui.config().enable_terminal_cursor; const focused_cursor_color: ?[3]u8 = if (theme.editor_cursor.bg) |bg| RGB.to_u8s(RGB.from_u24(bg.color)) else null; const unfocused_cursor_color: ?[3]u8 = if (theme.editor_cursor_secondary.bg) |bg| RGB.to_u8s(RGB.from_u24(bg.color)) else focused_cursor_color; self.vt.vt.draw(self.allocator, self.plane.window, self.focused and tui.terminal_has_focus(), software_cursor, focused_cursor_color, unfocused_cursor_color) catch |e| { diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 54896607..6626cf4d 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -164,6 +164,7 @@ fn init(allocator: Allocator) InitError!*Self { conf.theme = dark_theme.name; const light_theme = Widget.get_theme_by_name(allocator, conf.light_theme) orelse Widget.get_theme_by_name(allocator, "default-light") orelse return error.UnknownTheme; conf.light_theme = light_theme.name; + if (build_options.gui) conf.enable_terminal_cursor = false; const frame_rate: usize = @intCast(tp.env.get().num("frame-rate")); if (frame_rate != 0) @@ -658,7 +659,7 @@ fn render(self: *Self) void { defer frame.deinit(); self.rdr_.stdplane().erase(); const theme_ = self.current_theme(); - if (has_native_cursor()) { + if (self.config_.enable_terminal_cursor) { self.rdr_.cursor_disable(); if (self.rdr_.vx.caps.multi_cursor) self.rdr_.clear_all_multi_cursors() catch {}; self.rdr_.set_terminal_cursor_color(theme_.editor_cursor.bg.?); @@ -681,17 +682,13 @@ fn render(self: *Self) void { top_layer_.draw(self.rdr_.stdplane()); } - const renderer_more = ret: { + { const frame = tracy.initZone(@src(), .{ .name = renderer.log_name ++ " render" }); defer frame.deinit(); - const m = self.rdr_.render() catch |e| blk: { - self.logger.err("render", e); - break :blk false; - }; + self.rdr_.render() catch |e| self.logger.err("render", e); tracy.frameMark(); self.unrendered_input_events_count = 0; - break :ret m; - }; + } self.top_layer_reset(); self.idle_frame_count = if (self.unrendered_input_events_count > 0) @@ -699,7 +696,7 @@ fn render(self: *Self) void { else self.idle_frame_count + 1; - if (more or renderer_more or self.idle_frame_count < idle_frames or self.no_sleep) { + if (more or self.idle_frame_count < idle_frames or self.no_sleep) { if (!self.frame_clock_running) { self.frame_clock.start() catch {}; self.frame_clock_running = true; @@ -2174,12 +2171,7 @@ pub fn get_cursor_shape() renderer.CursorShape { default_cursor else default_cursor; - const shape = if (build_options.gui and shape_ == .default) - .beam - else if (self.rdr_.vx.caps.multi_cursor and shape_ == .default) - .beam_blink - else - shape_; + const shape = if (self.rdr_.vx.caps.multi_cursor and shape_ == .default) .beam_blink else shape_; return switch (shape) { .default => .default, .block_blink => .block_blink, @@ -2198,10 +2190,6 @@ pub fn is_cursor_beam() bool { }; } -pub fn has_native_cursor() bool { - return current().config_.enable_terminal_cursor; -} - pub fn get_selection_style() @import("Buffer").Selection.Style { return if (current().input_mode_) |mode| mode.selection_style else .normal; } diff --git a/src/win32/DwriteRenderer.zig b/src/win32/DwriteRenderer.zig index 943b08ac..003a2949 100644 --- a/src/win32/DwriteRenderer.zig +++ b/src/win32/DwriteRenderer.zig @@ -5,7 +5,7 @@ const win32 = @import("win32").everything; const win32ext = @import("win32ext.zig"); const dwrite = @import("dwrite.zig"); -const XY = @import("xy").XY; +const XY = @import("../gui/xy.zig").XY; pub const Font = dwrite.Font; pub const Fonts = dwrite.Fonts; diff --git a/src/win32/d3d11.zig b/src/win32/d3d11.zig index f36fc9cb..d7cd4359 100644 --- a/src/win32/d3d11.zig +++ b/src/win32/d3d11.zig @@ -4,11 +4,11 @@ const win32 = @import("win32").everything; const win32ext = @import("win32ext.zig"); const dwrite = @import("dwrite.zig"); -const GlyphIndexCache = @import("GlyphIndexCache"); +const GlyphIndexCache = @import("../gui/GlyphIndexCache.zig"); const TextRenderer = @import("DwriteRenderer.zig"); -const XY = @import("xy").XY; -const gui_cell = @import("Cell"); +const XY = @import("../gui/xy.zig").XY; +const gui_cell = @import("../gui/Cell.zig"); pub const Font = TextRenderer.Font; pub const Fonts = TextRenderer.Fonts; diff --git a/src/win32/dwrite.zig b/src/win32/dwrite.zig index e6405689..5ac809d8 100644 --- a/src/win32/dwrite.zig +++ b/src/win32/dwrite.zig @@ -2,7 +2,7 @@ const std = @import("std"); const win32 = @import("win32").everything; const FontFace = @import("FontFace.zig"); -const XY = @import("xy").XY; +const XY = @import("xy.zig").XY; const global = struct { var init_called: bool = false; diff --git a/src/win32/gui.zig b/src/win32/gui.zig index 766032a5..6b8c4efb 100644 --- a/src/win32/gui.zig +++ b/src/win32/gui.zig @@ -18,10 +18,10 @@ const input = @import("input"); const windowmsg = @import("windowmsg.zig"); const render = @import("d3d11.zig"); -const xterm = @import("xterm"); +const xterm = @import("../gui/xterm.zig"); const FontFace = @import("FontFace.zig"); -const XY = @import("xy").XY; +const XY = @import("../gui/xy.zig").XY; const WM_APP_EXIT = win32.WM_APP + 1; const WM_APP_SET_BACKGROUND = win32.WM_APP + 2;