Skip to content

Commit 00ab7f2

Browse files
widget: add background fill support to Text widget
The Text widget was not filling its background, causing modal UI elements like the session picker and rename dialogs to display with incorrect background colors. Add a style field to the Text struct that enables background fill when a non-default bg color is specified. Update modal Text widgets to include bg = THEME.bg1 for consistent styling. Amp-Thread-ID: https://ampcode.com/threads/T-019b2544-2017-714d-b567-15becd7ca0df Co-authored-by: Amp <amp@ampcode.com>
1 parent 9777c48 commit 00ab7f2

File tree

3 files changed

+31
-162
lines changed

3 files changed

+31
-162
lines changed

src/lua/prise.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,14 @@ function M.Text(opts)
115115
return {
116116
type = "text",
117117
content = { opts },
118+
style = opts.style,
118119
}
119120
end
120121

121122
return {
122123
type = "text",
123124
content = opts.content or {},
125+
style = opts.style,
124126
show_cursor = opts.show_cursor,
125127
}
126128
end

src/lua/tiling.lua

Lines changed: 11 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,164 +2036,7 @@ function M.update(event)
20362036
state.pending_command = true
20372037
prise.request_frame()
20382038

2039-
<<<<<<< HEAD
20402039
-- Cancel existing timeout and start new one
2041-
=======
2042-
-- Handle pending command mode (after Super/Cmd+k)
2043-
if state.pending_command then
2044-
local handled = false
2045-
local k = event.data.key
2046-
2047-
-- Leader twice sends leader to inner shell (like tmux)
2048-
if matches_keybind(event.data, config.keybinds.leader) then
2049-
local pty = get_focused_pty()
2050-
if pty then
2051-
pty:send_key(event.data)
2052-
end
2053-
if state.timer then
2054-
state.timer:cancel()
2055-
state.timer = nil
2056-
end
2057-
state.pending_command = false
2058-
prise.request_frame()
2059-
return
2060-
end
2061-
2062-
if k == "h" then
2063-
move_focus("left")
2064-
handled = true
2065-
elseif k == "l" then
2066-
move_focus("right")
2067-
handled = true
2068-
elseif k == "j" then
2069-
move_focus("down")
2070-
handled = true
2071-
elseif k == "k" then
2072-
move_focus("up")
2073-
handled = true
2074-
elseif k == "H" then
2075-
resize_pane("width", -RESIZE_STEP)
2076-
handled = true
2077-
elseif k == "L" then
2078-
resize_pane("width", RESIZE_STEP)
2079-
handled = true
2080-
elseif k == "J" then
2081-
resize_pane("height", RESIZE_STEP)
2082-
handled = true
2083-
elseif k == "K" then
2084-
resize_pane("height", -RESIZE_STEP)
2085-
handled = true
2086-
elseif k == "%" or k == "v" then
2087-
-- Split horizontal (side-by-side)
2088-
local pty = get_focused_pty()
2089-
state.pending_split = { direction = "row" }
2090-
prise.spawn({ cwd = pty and pty:cwd() })
2091-
handled = true
2092-
elseif k == '"' or k == "'" or k == "s" then
2093-
-- Split vertical (top-bottom)
2094-
local pty = get_focused_pty()
2095-
state.pending_split = { direction = "col" }
2096-
prise.spawn({ cwd = pty and pty:cwd() })
2097-
handled = true
2098-
elseif k == "d" then
2099-
-- Detach from session
2100-
detach_session()
2101-
handled = true
2102-
elseif k == "t" then
2103-
-- New tab
2104-
local pty = get_focused_pty()
2105-
state.pending_new_tab = true
2106-
prise.spawn({ cwd = pty and pty:cwd() })
2107-
handled = true
2108-
elseif k == "n" then
2109-
-- Next tab
2110-
if #state.tabs > 1 then
2111-
local next_idx = state.active_tab % #state.tabs + 1
2112-
set_active_tab_index(next_idx)
2113-
end
2114-
handled = true
2115-
elseif k == "p" then
2116-
-- Previous tab
2117-
if #state.tabs > 1 then
2118-
local prev_idx = (state.active_tab - 2 + #state.tabs) % #state.tabs + 1
2119-
set_active_tab_index(prev_idx)
2120-
end
2121-
handled = true
2122-
elseif k == "c" then
2123-
-- Close current tab
2124-
close_current_tab()
2125-
handled = true
2126-
elseif k == "r" then
2127-
-- Rename current tab
2128-
open_rename_tab()
2129-
handled = true
2130-
elseif k == "S" then
2131-
-- Switch/swap session
2132-
open_session_picker()
2133-
handled = true
2134-
elseif k == "R" then
2135-
-- Rename session
2136-
open_rename()
2137-
handled = true
2138-
elseif k >= "1" and k <= "9" then
2139-
-- Switch to tab N
2140-
local idx = math.tointeger(tonumber(k))
2141-
if idx and idx <= #state.tabs then
2142-
set_active_tab_index(idx)
2143-
end
2144-
handled = true
2145-
elseif k == "0" then
2146-
-- Switch to tab 10
2147-
if 10 <= #state.tabs then
2148-
set_active_tab_index(10)
2149-
end
2150-
handled = true
2151-
elseif k == "w" then
2152-
-- Close current pane
2153-
local root = get_active_root()
2154-
local path = state.focused_id and find_node_path(root, state.focused_id)
2155-
if path then
2156-
local pane = path[#path]
2157-
pane.pty:close()
2158-
local was_last = remove_pane_by_id(pane.id)
2159-
if not was_last then
2160-
prise.save()
2161-
end
2162-
handled = true
2163-
end
2164-
elseif k == "q" then
2165-
-- Quit
2166-
detach_session()
2167-
handled = true
2168-
elseif k == "z" then
2169-
-- Toggle zoom
2170-
if state.zoomed_pane_id then
2171-
state.zoomed_pane_id = nil
2172-
elseif state.focused_id then
2173-
state.zoomed_pane_id = state.focused_id
2174-
end
2175-
handled = true
2176-
elseif k == "Enter" or k == "\r" or k == "\n" then
2177-
local pty = get_focused_pty()
2178-
state.pending_split = { direction = get_auto_split_direction() }
2179-
prise.spawn({ cwd = pty and pty:cwd() })
2180-
handled = true
2181-
elseif k == "Escape" then
2182-
handled = true
2183-
end
2184-
2185-
if handled then
2186-
if state.timer then
2187-
state.timer:cancel()
2188-
state.timer = nil
2189-
end
2190-
state.pending_command = false
2191-
prise.request_frame()
2192-
return
2193-
end
2194-
2195-
-- Reset timeout
2196-
>>>>>>> c0e82165ba9e (Add session picker)
21972040
if state.timer then
21982041
state.timer:cancel()
21992042
end
@@ -2621,7 +2464,10 @@ local function build_palette()
26212464
input = state.palette.input,
26222465
style = input_style,
26232466
}),
2624-
prise.Text({ text = string.rep("", PALETTE_WIDTH), style = { fg = THEME.bg3 } }),
2467+
prise.Text({
2468+
text = string.rep("", PALETTE_WIDTH),
2469+
style = { fg = THEME.bg3, bg = THEME.bg1 },
2470+
}),
26252471
prise.List({
26262472
items = items,
26272473
selected = state.palette.selected,
@@ -2661,7 +2507,7 @@ local function build_rename()
26612507
child = prise.Column({
26622508
cross_axis_align = "stretch",
26632509
children = {
2664-
prise.Text({ text = "Rename Session", style = { fg = THEME.fg_dim } }),
2510+
prise.Text({ text = "Rename Session", style = { fg = THEME.fg_dim, bg = THEME.bg1 } }),
26652511
prise.TextInput({
26662512
input = state.rename.input,
26672513
style = input_style,
@@ -2698,7 +2544,7 @@ local function build_rename_tab()
26982544
child = prise.Column({
26992545
cross_axis_align = "stretch",
27002546
children = {
2701-
prise.Text({ text = "Rename Tab", style = { fg = THEME.fg_dim } }),
2547+
prise.Text({ text = "Rename Tab", style = { fg = THEME.fg_dim, bg = THEME.bg1 } }),
27022548
prise.TextInput({
27032549
input = state.rename_tab.input,
27042550
style = input_style,
@@ -2773,13 +2619,16 @@ local function build_session_picker()
27732619
child = prise.Column({
27742620
cross_axis_align = "stretch",
27752621
children = {
2776-
prise.Text({ text = "Switch Session", style = { fg = THEME.fg_dim } }),
2622+
prise.Text({ text = "Switch Session", style = { fg = THEME.fg_dim, bg = THEME.bg1 } }),
27772623
prise.TextInput({
27782624
input = state.session_picker.input,
27792625
style = input_style,
27802626
focus = true,
27812627
}),
2782-
prise.Text({ text = string.rep("", PALETTE_WIDTH), style = { fg = THEME.bg3 } }),
2628+
prise.Text({
2629+
text = string.rep("", PALETTE_WIDTH),
2630+
style = { fg = THEME.bg3, bg = THEME.bg1 },
2631+
}),
27832632
prise.List({
27842633
items = items,
27852634
selected = state.session_picker.selected,

src/widget.zig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,15 @@ pub const Widget = struct {
269269
while (try iter.next()) |line| {
270270
defer allocator.free(line.segments);
271271

272+
if (text.style.bg != .default) {
273+
for (0..win.width) |c| {
274+
win.writeCell(@intCast(c), @intCast(row), .{
275+
.char = .{ .grapheme = " ", .width = 1 },
276+
.style = text.style,
277+
});
278+
}
279+
}
280+
272281
var col: usize = 0;
273282

274283
const free_space = if (win.width > line.width) win.width - line.width else 0;
@@ -812,6 +821,7 @@ pub const Text = struct {
812821
wrap: Wrap = .none,
813822
// We must quote align because it is a keyword
814823
@"align": Align = .left,
824+
style: vaxis.Style = .{},
815825

816826
pub const Span = struct {
817827
text: []const u8,
@@ -1397,10 +1407,18 @@ pub fn parseWidget(lua: *ziglua.Lua, allocator: std.mem.Allocator, index: i32) !
13971407
}
13981408
lua.pop(1);
13991409

1410+
var text_style = vaxis.Style{};
1411+
_ = lua.getField(index, "style");
1412+
if (lua.typeOf(-1) == .table) {
1413+
text_style = parseStyle(lua, -1) catch .{};
1414+
}
1415+
lua.pop(1);
1416+
14001417
return .{ .ratio = ratio, .id = id, .focus = focus, .kind = .{ .text = .{
14011418
.spans = try spans.toOwnedSlice(allocator),
14021419
.wrap = wrap,
14031420
.@"align" = @"align",
1421+
.style = text_style,
14041422
} } };
14051423
} else if (std.mem.eql(u8, widget_type, "stack")) {
14061424
_ = lua.getField(index, "children");

0 commit comments

Comments
 (0)