Compare commits
13 commits
872f8cdcb8
...
4391d6d0f0
| Author | SHA1 | Date | |
|---|---|---|---|
| 4391d6d0f0 | |||
| b1cc9193fe | |||
| e01d9c13b7 | |||
| a6b3da2d16 | |||
| cde7e4c6f5 | |||
| 80988915d6 | |||
| 36ac002481 | |||
| be4f939b26 | |||
| 8190380e79 | |||
| 0eb2e848c0 | |||
| 347ce61f5d | |||
| 76ed87f87b | |||
| fb135afe16 |
13 changed files with 169 additions and 76 deletions
21
build.zig
21
build.zig
|
|
@ -492,7 +492,12 @@ pub fn build_exe(
|
|||
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_cell_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/gui/cell.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "color", .module = color_mod },
|
||||
},
|
||||
});
|
||||
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(.{
|
||||
|
|
@ -509,7 +514,7 @@ pub fn build_exe(
|
|||
.{ .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 = "cell", .module = gui_cell_mod },
|
||||
.{ .name = "GlyphIndexCache", .module = gui_glyph_cache_mod },
|
||||
.{ .name = "xterm", .module = gui_xterm_mod },
|
||||
},
|
||||
|
|
@ -550,7 +555,12 @@ pub fn build_exe(
|
|||
const sokol_mod = sokol_dep.module("sokol");
|
||||
|
||||
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_cell_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/gui/cell.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "color", .module = color_mod },
|
||||
},
|
||||
});
|
||||
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") });
|
||||
|
||||
|
|
@ -609,10 +619,11 @@ pub fn build_exe(
|
|||
const gpu_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/gui/gpu/gpu.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "color", .module = color_mod },
|
||||
.{ .name = "sokol", .module = sokol_mod },
|
||||
.{ .name = "rasterizer", .module = combined_rasterizer_mod },
|
||||
.{ .name = "xy", .module = gui_xy_mod },
|
||||
.{ .name = "Cell", .module = gui_cell_mod },
|
||||
.{ .name = "cell", .module = gui_cell_mod },
|
||||
.{ .name = "GlyphIndexCache", .module = gui_glyph_cache_mod },
|
||||
},
|
||||
});
|
||||
|
|
@ -620,6 +631,7 @@ pub fn build_exe(
|
|||
const app_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/gui/wio/app.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "color", .module = color_mod },
|
||||
.{ .name = "wio", .module = wio_mod },
|
||||
.{ .name = "sokol", .module = sokol_mod },
|
||||
.{ .name = "gpu", .module = gpu_mod },
|
||||
|
|
@ -635,6 +647,7 @@ pub fn build_exe(
|
|||
const mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/renderer/gui/renderer.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "color", .module = color_mod },
|
||||
.{ .name = "theme", .module = themes_dep.module("theme") },
|
||||
.{ .name = "cbor", .module = cbor_mod },
|
||||
.{ .name = "thespian", .module = thespian_mod },
|
||||
|
|
|
|||
|
|
@ -22,16 +22,16 @@
|
|||
.hash = "thespian-0.0.1-owFOjlgiBgC8w4XqkCOegxz5vMy6kNErcssWQWf2QHeE",
|
||||
},
|
||||
.themes = .{
|
||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-80ac47f701dc4fab73dafb5c0da10b0c9e395052/flow-themes.tar.gz",
|
||||
.hash = "N-V-__8AAIjCKwDJwoOzcI3233UAVqIaOTOOLMgQK1FnFDfx",
|
||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-9114e2d9ff4e01064ba1da4f780b0c5448b0f0ef/flow-themes.tar.gz",
|
||||
.hash = "N-V-__8AAJZfLAAP6zSuW13nEIrBBHZM9pbeMRwhvQ-8qqx1",
|
||||
},
|
||||
.fuzzig = .{
|
||||
.url = "https://github.com/fjebaker/fuzzig/archive/4251fe4230d38e721514394a485db62ee1667ff3.tar.gz",
|
||||
.hash = "fuzzig-0.1.1-Ji0xivxIAQBD0g8O_NV_0foqoPf3elsg9Sc3pNfdVH4D",
|
||||
},
|
||||
.vaxis = .{
|
||||
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#cecc97d9ff8da9df13499da0d0b19c5cd18742c3",
|
||||
.hash = "vaxis-0.5.1-BWNV_BcgCgDG3wpSPxCHxaRAZukEfnnKrBa-52zjnjex",
|
||||
.url = "git+https://github.com/neurocyte/libvaxis?ref=main#9fc042aa0fc8b08d15fce1c897bc65ed4a4c65ed",
|
||||
.hash = "vaxis-0.5.1-BWNV_GgiCgCimbrqWwG7XRgYXNFWFBcH9dTmxx-8Gs-2",
|
||||
},
|
||||
.zeit = .{
|
||||
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
|
||||
|
|
|
|||
|
|
@ -106,6 +106,47 @@ pub const RGBf = struct {
|
|||
const GAMMA = 2.4;
|
||||
};
|
||||
|
||||
// Packed RGBA color type used by GPUs
|
||||
pub const RGBA = packed struct(u32) {
|
||||
a: u8,
|
||||
b: u8,
|
||||
g: u8,
|
||||
r: u8,
|
||||
|
||||
pub fn init(r: u8, g: u8, b: u8, a: u8) RGBA {
|
||||
return .{ .r = r, .g = g, .b = b, .a = a };
|
||||
}
|
||||
|
||||
pub fn from_RGB(v: RGB) RGBA {
|
||||
return .{ .r = v.r, .g = v.g, .b = v.b, .a = 255 };
|
||||
}
|
||||
|
||||
pub inline fn from_u32(v: u32) RGBA {
|
||||
return @bitCast(v);
|
||||
}
|
||||
|
||||
pub inline fn from_u24(v: u24) RGBA {
|
||||
return from_RGB(RGB.from_u24(v));
|
||||
}
|
||||
|
||||
pub inline fn from_u8s(v: [3]u8) RGBA {
|
||||
return .{ .r = v[0], .g = v[1], .b = v[2], .a = 255 };
|
||||
}
|
||||
|
||||
pub inline fn to_u32(v: RGBA) u32 {
|
||||
return @bitCast(v);
|
||||
}
|
||||
|
||||
pub fn to_vec4(c: RGBA) [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,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn u24_to_u8s(v: u24) [3]u8 {
|
||||
return .{ @truncate(v >> 16), @truncate(v >> 8), @truncate(v) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
// Shared GPU cell types used by all GPU renderer backends.
|
||||
|
||||
pub const Rgba8 = packed struct(u32) {
|
||||
a: u8,
|
||||
b: u8,
|
||||
g: u8,
|
||||
r: u8,
|
||||
pub fn initRgb(r: u8, g: u8, b: u8) Rgba8 {
|
||||
return .{ .r = r, .g = g, .b = b, .a = 255 };
|
||||
}
|
||||
pub fn initRgba(r: u8, g: u8, b: u8, a: u8) Rgba8 {
|
||||
return .{ .r = r, .g = g, .b = b, .a = a };
|
||||
}
|
||||
};
|
||||
|
||||
pub const Cell = extern struct {
|
||||
glyph_index: u32,
|
||||
background: Rgba8,
|
||||
foreground: Rgba8,
|
||||
};
|
||||
9
src/gui/cell.zig
Normal file
9
src/gui/cell.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Shared GPU cell types used by all GPU renderer backends.
|
||||
|
||||
const RGBA = @import("color").RGBA;
|
||||
|
||||
pub const Cell = extern struct {
|
||||
glyph_index: u32,
|
||||
background: RGBA,
|
||||
foreground: RGBA,
|
||||
};
|
||||
|
|
@ -23,6 +23,8 @@ pub const FsParams = extern struct {
|
|||
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]
|
||||
// Background fill for border area outside the cell grid
|
||||
bg_color: [4]f32, // RGBA normalized [0,1]
|
||||
};
|
||||
|
||||
const vs_src =
|
||||
|
|
@ -48,6 +50,7 @@ const fs_src =
|
|||
\\uniform int cursor_vis;
|
||||
\\uniform vec4 cursor_color;
|
||||
\\uniform vec4 sec_cursor_color;
|
||||
\\uniform vec4 bg_color;
|
||||
\\uniform sampler2D glyph_tex_glyph_smp;
|
||||
\\uniform usampler2D cell_tex_cell_smp;
|
||||
\\out vec4 frag_color;
|
||||
|
|
@ -69,7 +72,7 @@ const fs_src =
|
|||
\\ int row = py / cell_size_y;
|
||||
\\
|
||||
\\ if (col >= col_count || row >= row_count || row < 0 || col < 0) {
|
||||
\\ frag_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
\\ frag_color = vec4(bg_color.rgb, 1.0);
|
||||
\\ return;
|
||||
\\ }
|
||||
\\
|
||||
|
|
@ -142,6 +145,7 @@ pub fn shaderDesc(backend: sg.Backend) sg.ShaderDesc {
|
|||
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" };
|
||||
desc.uniform_blocks[0].glsl_uniforms[11] = .{ .type = .FLOAT4, .glsl_name = "bg_color" };
|
||||
|
||||
// Glyph atlas texture: R8 → sample_type = FLOAT
|
||||
desc.views[0].texture = .{
|
||||
|
|
|
|||
|
|
@ -7,16 +7,14 @@ const std = @import("std");
|
|||
const sg = @import("sokol").gfx;
|
||||
const Rasterizer = @import("rasterizer");
|
||||
const GlyphIndexCache = @import("GlyphIndexCache");
|
||||
const gui_cell = @import("Cell");
|
||||
const XY = @import("xy").XY;
|
||||
const builtin_shader = @import("builtin.glsl.zig");
|
||||
|
||||
pub const Font = Rasterizer.Font;
|
||||
pub const GlyphKind = Rasterizer.GlyphKind;
|
||||
pub const RasterizerBackend = Rasterizer.Backend;
|
||||
pub const Cell = gui_cell.Cell;
|
||||
pub const Color = gui_cell.Rgba8;
|
||||
const Rgba8 = gui_cell.Rgba8;
|
||||
pub const Cell = @import("cell").Cell;
|
||||
pub const RGBA = @import("color").RGBA;
|
||||
|
||||
pub const CursorShape = enum(i32) { block = 0, beam = 1, underline = 2 };
|
||||
|
||||
|
|
@ -25,7 +23,7 @@ pub const CursorInfo = struct {
|
|||
row: u16 = 0,
|
||||
col: u16 = 0,
|
||||
shape: CursorShape = .block,
|
||||
color: Color = Color.initRgb(255, 255, 255),
|
||||
color: RGBA = .init(255, 255, 255, 255),
|
||||
};
|
||||
|
||||
const log = std.log.scoped(.gpu);
|
||||
|
|
@ -44,7 +42,7 @@ fn getAtlasCellCount(cell_size: XY(u16)) XY(u16) {
|
|||
// Shader cell layout for the RGBA32UI cell texture.
|
||||
// Each texel encodes one terminal cell:
|
||||
// .r = glyph_index (u32)
|
||||
// .g = bg packed (Rgba8 bit-cast to u32: r<<24|g<<16|b<<8|a)
|
||||
// .g = bg packed (RGBA bit-cast to u32: r<<24|g<<16|b<<8|a)
|
||||
// .b = fg packed (same)
|
||||
// .a = 0 (reserved)
|
||||
const ShaderCell = extern struct {
|
||||
|
|
@ -61,7 +59,7 @@ const global = struct {
|
|||
var glyph_sampler: sg.Sampler = .{};
|
||||
var cell_sampler: sg.Sampler = .{};
|
||||
var glyph_cache_arena: std.heap.ArenaAllocator = undefined;
|
||||
var background: Rgba8 = .{ .r = 19, .g = 19, .b = 19, .a = 255 };
|
||||
var background: RGBA = .init(0, 255, 255, 255); // default is warning yellow
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) !void {
|
||||
|
|
@ -118,10 +116,14 @@ pub fn setFontWeight(font: *Font, w: u8) void {
|
|||
Rasterizer.setFontWeight(font, w);
|
||||
}
|
||||
|
||||
pub fn setBackground(color: Rgba8) void {
|
||||
pub fn setBackground(color: RGBA) void {
|
||||
global.background = color;
|
||||
}
|
||||
|
||||
pub fn getBackground() RGBA {
|
||||
return global.background;
|
||||
}
|
||||
|
||||
// ── WindowState ────────────────────────────────────────────────────────────
|
||||
|
||||
pub const WindowState = struct {
|
||||
|
|
@ -387,15 +389,15 @@ pub fn paint(
|
|||
const src = cells[src_row_offset + ci];
|
||||
shader_cells[dst_row_offset + ci] = .{
|
||||
.glyph_index = src.glyph_index,
|
||||
.bg = @bitCast(src.background),
|
||||
.fg = @bitCast(src.foreground),
|
||||
.bg = src.background.to_u32(),
|
||||
.fg = src.foreground.to_u32(),
|
||||
};
|
||||
}
|
||||
for (copy_len..shader_col_count) |ci| {
|
||||
shader_cells[dst_row_offset + ci] = .{
|
||||
.glyph_index = blank_glyph_index,
|
||||
.bg = @bitCast(global.background),
|
||||
.fg = @bitCast(global.background),
|
||||
.bg = global.background.to_u32(),
|
||||
.fg = global.background.to_u32(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -448,10 +450,10 @@ pub fn paint(
|
|||
bindings.samplers[1] = global.cell_sampler;
|
||||
sg.applyBindings(bindings);
|
||||
|
||||
const sec_color: Color = if (secondary_cursors.len > 0)
|
||||
const sec_color: RGBA = if (secondary_cursors.len > 0)
|
||||
secondary_cursors[0].color
|
||||
else
|
||||
Color.initRgb(255, 255, 255);
|
||||
.init(255, 255, 255, 255);
|
||||
|
||||
const fs_params = builtin_shader.FsParams{
|
||||
.cell_size_x = font.cell_size.x,
|
||||
|
|
@ -463,8 +465,9 @@ pub fn paint(
|
|||
.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),
|
||||
.cursor_color = cursor.color.to_vec4(),
|
||||
.sec_cursor_color = sec_color.to_vec4(),
|
||||
.bg_color = global.background.to_vec4(),
|
||||
};
|
||||
sg.applyUniforms(0, .{
|
||||
.ptr = &fs_params,
|
||||
|
|
@ -476,15 +479,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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const gpu = @import("gpu");
|
|||
const thespian = @import("thespian");
|
||||
const cbor = @import("cbor");
|
||||
const vaxis = @import("vaxis");
|
||||
const RGBA = @import("color").RGBA;
|
||||
|
||||
const input_translate = @import("input.zig");
|
||||
const root = @import("soft_root").root;
|
||||
|
|
@ -26,7 +27,6 @@ const log = std.log.scoped(.wio_app);
|
|||
// 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) ──────────────────────────────
|
||||
|
||||
|
|
@ -55,6 +55,11 @@ var font_backend: gpu.RasterizerBackend = .freetype;
|
|||
var font_dirty: std.atomic.Value(bool) = .init(true);
|
||||
var stop_requested: std.atomic.Value(bool) = .init(false);
|
||||
|
||||
// Background color (written from TUI thread, applied by wio thread on each paint).
|
||||
// Stored as packed RGBA u32 to allow atomic reads/writes.
|
||||
var background_color: std.atomic.Value(u32) = .init(RGBA.init(0, 255, 255, 255).to_u32()); // warning yellow, we should never see the default
|
||||
var background_dirty: std.atomic.Value(bool) = .init(false);
|
||||
|
||||
var config_arena_instance: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
const config_arena = config_arena_instance.allocator();
|
||||
|
||||
|
|
@ -311,6 +316,13 @@ fn saveConfig() void {
|
|||
log.err("failed to write gui config file", .{});
|
||||
}
|
||||
|
||||
pub fn setBackground(color: RGBA) void {
|
||||
const color_u32: u32 = (@as(u32, color.r) << 24) | (@as(u32, color.g) << 16) | (@as(u32, color.b) << 8) | color.a;
|
||||
background_color.store(color_u32, .release);
|
||||
background_dirty.store(true, .release);
|
||||
wio.cancelWait();
|
||||
}
|
||||
|
||||
pub fn requestAttention() void {
|
||||
attention_pending.store(true, .release);
|
||||
wio.cancelWait();
|
||||
|
|
@ -359,19 +371,11 @@ fn maybeReloadFont(win_size: wio.Size, state: *gpu.WindowState, cell_width: *u16
|
|||
}
|
||||
}
|
||||
|
||||
fn colorFromVaxis(color: vaxis.Cell.Color) gpu.Color {
|
||||
fn colorFromVaxis(color: vaxis.Cell.Color) RGBA {
|
||||
return switch (color) {
|
||||
.default => gpu.Color.initRgb(0, 0, 0),
|
||||
.index => |idx| blk: {
|
||||
const xterm = @import("xterm");
|
||||
const rgb24 = xterm.colors[idx];
|
||||
break :blk gpu.Color.initRgb(
|
||||
@truncate(rgb24 >> 16),
|
||||
@truncate(rgb24 >> 8),
|
||||
@truncate(rgb24),
|
||||
);
|
||||
},
|
||||
.rgb => |rgb| gpu.Color.initRgb(rgb[0], rgb[1], rgb[2]),
|
||||
.default => gpu.getBackground(),
|
||||
.index => |idx| .from_u24(@import("xterm").colors[idx]),
|
||||
.rgb => |rgb| .from_u8s(rgb),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -635,6 +639,16 @@ fn wioLoop() void {
|
|||
state.size = .{ .x = win_size.width, .y = win_size.height };
|
||||
const font = wio_font;
|
||||
|
||||
if (background_dirty.swap(false, .acq_rel)) {
|
||||
const color_u32 = background_color.load(.acquire);
|
||||
gpu.setBackground(.{
|
||||
.r = @truncate(color_u32 >> 24),
|
||||
.g = @truncate(color_u32 >> 16),
|
||||
.b = @truncate(color_u32 >> 8),
|
||||
.a = @truncate(color_u32),
|
||||
});
|
||||
}
|
||||
|
||||
// Regenerate glyph indices using the GPU state.
|
||||
// For double-wide characters vaxis emits width=2 for the left
|
||||
// cell and width=0 (continuation) for the right cell. The
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@
|
|||
["alt+shift+p", "open_command_palette"],
|
||||
["alt+n", "goto_next_file_or_diagnostic"],
|
||||
["alt+p", "goto_prev_file_or_diagnostic"],
|
||||
["alt+l", "toggle_panel"],
|
||||
["alt+i", "toggle_inputview"],
|
||||
["alt+k", "toggle_keybindview"],
|
||||
["alt+x", "open_command_palette"],
|
||||
|
|
@ -56,7 +55,7 @@
|
|||
["ctrl+k ctrl+s", "insert_command_name"],
|
||||
["f9", "theme_prev"],
|
||||
["f10", "theme_next"],
|
||||
["f11", "toggle_panel"],
|
||||
["f11", "show_logview"],
|
||||
["alt+f11", "toggle_color_scheme"],
|
||||
["alt+f9", "panel_next_widget_style"],
|
||||
["shift+alt+f9", "hint_window_next_widget_style"],
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ pub const log_name = "renderer";
|
|||
|
||||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const RGBA = @import("color").RGBA;
|
||||
pub const vaxis = @import("vaxis");
|
||||
const Style = @import("theme").Style;
|
||||
const Color = @import("theme").Color;
|
||||
|
|
@ -57,9 +58,9 @@ thread: ?std.Thread = null,
|
|||
window_ready: bool = false,
|
||||
|
||||
cursor_info: app.CursorInfo = .{},
|
||||
cursor_color: app.GpuColor = app.GpuColor.initRgb(255, 255, 255),
|
||||
cursor_color: RGBA = .init(255, 255, 255, 255),
|
||||
secondary_cursors: std.ArrayListUnmanaged(app.CursorInfo) = .{},
|
||||
secondary_color: app.GpuColor = app.GpuColor.initRgb(255, 255, 255),
|
||||
secondary_color: RGBA = .init(255, 255, 255, 255),
|
||||
|
||||
cursor_blink: bool = false,
|
||||
blink_on: bool = true,
|
||||
|
|
@ -378,6 +379,7 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
|
|||
})) {
|
||||
self.window_ready = true;
|
||||
self.dispatch_initialized(self.handler_ctx);
|
||||
if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"capability_detection_complete"}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -409,7 +411,7 @@ pub fn set_terminal_title(self: *Self, text: []const u8) void {
|
|||
|
||||
pub fn set_terminal_style(self: *Self, style_: Style) void {
|
||||
_ = self;
|
||||
_ = style_;
|
||||
if (style_.bg) |bg| app.setBackground(themeColorToGpu(bg));
|
||||
}
|
||||
|
||||
pub fn adjust_fontsize(self: *Self, amount: f32) void {
|
||||
|
|
@ -545,7 +547,7 @@ pub fn show_multi_cursor_yx(self: *Self, y: i32, x: i32) !void {
|
|||
});
|
||||
}
|
||||
|
||||
fn themeColorToGpu(color: Color) app.GpuColor {
|
||||
fn themeColorToGpu(color: Color) RGBA {
|
||||
return .{
|
||||
.r = @truncate(color.color >> 16),
|
||||
.g = @truncate(color.color >> 8),
|
||||
|
|
|
|||
|
|
@ -76,6 +76,12 @@ pub fn run_cmd(self: *Self, ctx: command.Context) !void {
|
|||
errdefer env.deinit();
|
||||
if (env.get("TERM") == null)
|
||||
try env.put("TERM", "xterm-256color");
|
||||
try env.put("COLORTERM", "truecolor");
|
||||
// COLORFGBG tells apps whether the terminal background is dark or light
|
||||
try env.put("COLORFGBG", switch (tui.active_color_scheme()) {
|
||||
.dark => "15;0",
|
||||
.light => "0;15",
|
||||
});
|
||||
|
||||
var cmd_arg: []const u8 = "";
|
||||
var on_exit: TerminalOnExit = tui.config().terminal_on_exit;
|
||||
|
|
@ -531,6 +537,10 @@ const Vt = struct {
|
|||
&self.write_buf,
|
||||
);
|
||||
|
||||
const theme = tui.active_theme();
|
||||
if (theme.editor.fg) |fg| self.vt.fg_color = color.u24_to_u8s(fg.color);
|
||||
if (theme.editor.bg) |bg| self.vt.bg_color = color.u24_to_u8s(bg.color);
|
||||
|
||||
try self.vt.spawn();
|
||||
self.pty_pid = try pty.spawn(allocator, &self.vt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ query_cache_: *syntax.QueryCache,
|
|||
frames_rendered_: usize = 0,
|
||||
clipboard: ?std.ArrayList(ClipboardEntry) = null,
|
||||
clipboard_current_group_number: usize = 0,
|
||||
color_scheme: enum { dark, light } = .dark,
|
||||
color_scheme: ColorScheme = .dark,
|
||||
color_scheme_locked: bool = false,
|
||||
hint_mode: HintMode = .prefix,
|
||||
last_palette: ?LastPalette = null,
|
||||
|
|
@ -97,6 +97,8 @@ jump_mode_: bool = false,
|
|||
|
||||
auto_run_timer: ?tp.Cancellable = null,
|
||||
|
||||
pub const ColorScheme = enum { dark, light };
|
||||
|
||||
const HintMode = enum { none, prefix, all };
|
||||
|
||||
const LastPalette = struct {
|
||||
|
|
@ -1068,14 +1070,14 @@ fn set_theme_by_name(self: *Self, name: []const u8, action: enum { none, store }
|
|||
}
|
||||
}
|
||||
|
||||
fn force_color_scheme(self: *Self, color_scheme: @TypeOf(self.color_scheme)) void {
|
||||
fn force_color_scheme(self: *Self, color_scheme: ColorScheme) void {
|
||||
self.color_scheme = color_scheme;
|
||||
self.color_scheme_locked = true;
|
||||
self.set_terminal_style(self.current_theme());
|
||||
self.logger.print("color scheme: {t} ({s})", .{ self.color_scheme, self.current_theme().name });
|
||||
}
|
||||
|
||||
fn set_color_scheme(self: *Self, color_scheme: @TypeOf(self.color_scheme)) void {
|
||||
fn set_color_scheme(self: *Self, color_scheme: ColorScheme) void {
|
||||
if (self.color_scheme_locked) return;
|
||||
self.color_scheme = color_scheme;
|
||||
self.set_terminal_style(self.current_theme());
|
||||
|
|
@ -1931,6 +1933,14 @@ pub fn config() *const @import("config") {
|
|||
return ¤t().config_;
|
||||
}
|
||||
|
||||
pub fn active_theme() *const Widget.Theme {
|
||||
return current().current_theme();
|
||||
}
|
||||
|
||||
pub fn active_color_scheme() ColorScheme {
|
||||
return current().color_scheme;
|
||||
}
|
||||
|
||||
pub fn get_tab_width() usize {
|
||||
const self = current();
|
||||
return self.session_tab_width orelse self.config_.tab_width;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||
const color = @import("color");
|
||||
|
||||
const RGB = color.RGB;
|
||||
const RGBA = color.RGBA;
|
||||
const rgb = RGB.from_u24;
|
||||
|
||||
test "contrast white/yellow" {
|
||||
|
|
@ -41,3 +42,19 @@ test "best contrast black/white to blue" {
|
|||
const best = color.max_contrast(0x0000FF, 0xFFFFFF, 0x000000);
|
||||
try std.testing.expectEqual(best, 0xFFFFFF);
|
||||
}
|
||||
|
||||
test "verify RGBA byte order" {
|
||||
const v1: RGBA = .init(0xA, 0xB, 0xC, 0xD);
|
||||
const v1_u32: u32 = @bitCast(v1);
|
||||
const v2: RGBA = .{
|
||||
.r = @truncate(v1_u32 >> 24),
|
||||
.g = @truncate(v1_u32 >> 16),
|
||||
.b = @truncate(v1_u32 >> 8),
|
||||
.a = @truncate(v1_u32),
|
||||
};
|
||||
const v3: RGBA = @bitCast(v1_u32);
|
||||
|
||||
const testing = @import("std").testing;
|
||||
try testing.expectEqual(v1, v2);
|
||||
try testing.expectEqual(v1, v3);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue