From 660a035a933e81b4891d010f81ee3e84fdaccbc2 Mon Sep 17 00:00:00 2001 From: winston Date: Sat, 4 Mar 2023 10:00:08 +0100 Subject: [PATCH] feat(wezterm): modular tab bar --- home/apps/wezterm/bar.lua | 299 ++++++++++++++++++++++++---------- home/apps/wezterm/extra.lua | 34 ++++ home/apps/wezterm/wezterm.lua | 31 +++- 3 files changed, 276 insertions(+), 88 deletions(-) create mode 100644 home/apps/wezterm/extra.lua diff --git a/home/apps/wezterm/bar.lua b/home/apps/wezterm/bar.lua index 1515115..3a05938 100644 --- a/home/apps/wezterm/bar.lua +++ b/home/apps/wezterm/bar.lua @@ -1,10 +1,115 @@ local wezterm = require("wezterm") -local DIVIDERS = { - LEFT = utf8.char(0xe0be), - RIGHT = utf8.char(0xe0bc), +local M = {} + +M.config = { + dividers = "slant_right", + indicator = { + leader = { + enabled = true, + off = " ", + on = " ", + }, + mode = { + enabled = true, + names = { + resize_mode = "RESIZE", + copy_mode = "VISUAL", + search_mode = "SEARCH", + }, + }, + }, + tabs = { + numerals = "arabic", + pane_count = "superscript", + brackets = { + active = { "", ":" }, + inactive = { "", ":" }, + }, + }, + clock = { + enabled = true, + format = "%H:%M", + }, } +local function tableMerge(t1, t2) + for k, v in pairs(t2) do + if type(v) == "table" then + if type(t1[k] or false) == "table" then + tableMerge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end + +local C = {} + +M.setup = function(config) + M.config = tableMerge(M.config, config) + local dividers = { + slant_right = { + left = utf8.char(0xe0be), + right = utf8.char(0xe0bc), + }, + slant_left = { + left = utf8.char(0xe0ba), + right = utf8.char(0xe0b8), + }, + arrows = { + left = utf8.char(0xe0b2), + right = utf8.char(0xe0b0), + }, + rounded = { + left = utf8.char(0xe0b6), + right = utf8.char(0xe0b4), + }, + } + + C.div = { + l = "", + r = "", + } + if M.config.dividers then + C.div.l = dividers[M.config.dividers].left + C.div.r = dividers[M.config.dividers].right + end + + C.leader = { + enabled = M.config.indicator.leader.enabled or true, + off = M.config.indicator.leader.off, + on = M.config.indicator.leader.on, + } + + C.mode = { + enabled = M.config.indicator.mode.enabled, + names = M.config.indicator.mode.names, + } + + C.tabs = { + numerals = M.config.tabs.numerals, + pane_count_style = M.config.tabs.pane_count, + brackets = { + active = M.config.tabs.brackets.active, + inactive = M.config.tabs.brackets.inactive, + }, + } + + C.clock = { + enabled = M.config.clock.enabled, + format = M.config.clock.format, + } + + C.p = (M.config.dividers == "rounded") and "" or " " + + wezterm.log_info(C) +end + -- superscript/subscript local function numberStyle(number, script) local scripts = { @@ -48,6 +153,21 @@ local function numberStyle(number, script) return result end +local roman_numerals = { + "Ⅰ", + "Ⅱ", + "Ⅲ", + "Ⅳ", + "Ⅴ", + "Ⅵ", + "Ⅶ", + "Ⅷ", + "Ⅸ", + "Ⅹ", + "Ⅺ", + "Ⅻ", +} + -- custom tab bar wezterm.on( "format-tab-title", @@ -109,29 +229,47 @@ wezterm.on( e_fg = inactive_bg end - local tabi = wezterm.mux.get_tab(tab.tab_id) - local muxpanes = tabi:panes() - local count = #muxpanes == 1 and "" or tostring(#muxpanes) - local index = tab.tab_index + 1 .. ": " - - -- start and end hardcoded numbers are the Powerline + " " padding - local fillerwidth = 2 + string.len(index) + string.len(count) + 2 - - local tabtitle = tab.active_pane.title - if (#tabtitle + fillerwidth) > config.tab_max_width then - tabtitle = string.sub( - tab.active_pane.title, - 1, - (config.tab_max_width - fillerwidth - 1) - ) .. "…" + local pane_count = "" + if C.tabs.pane_count_style then + local tabi = wezterm.mux.get_tab(tab.tab_id) + local muxpanes = tabi:panes() + local count = #muxpanes == 1 and "" or tostring(#muxpanes) + pane_count = numberStyle(count, C.tabs.pane_count_style) end - local title = string.format( - " %s%s%s ", - index, - tabtitle, - numberStyle(count, "superscript") - ) + local index_i + if C.tabs.numerals == "roman" then + index_i = roman_numerals[tab.tab_index + 1] + else + index_i = tab.tab_index + 1 + end + + if tab.is_active then + index = string.format( + "%s%s%s ", + C.tabs.brackets.active[1], + index_i, + C.tabs.brackets.active[2] + ) + else + index = string.format( + "%s%s%s ", + C.tabs.brackets.inactive[1], + index_i, + C.tabs.brackets.inactive[2] + ) + end + + -- start and end hardcoded numbers are the Powerline + " " padding + local fillerwidth = 2 + string.len(index) + string.len(pane_count) + 2 + + local tabtitle = tab.active_pane.title + local width = config.tab_max_width - fillerwidth - 1 + if (#tabtitle + fillerwidth) > config.tab_max_width then + tabtitle = wezterm.truncate_right(tabtitle, width) .. "…" + end + + local title = string.format(" %s%s%s%s", index, tabtitle, pane_count, C.p) return { { Background = { Color = s_bg } }, @@ -139,84 +277,71 @@ wezterm.on( { Text = title }, { Background = { Color = e_bg } }, { Foreground = { Color = e_fg } }, - { Text = DIVIDERS.RIGHT }, + { Text = C.div.r }, } end ) -local function arrContains(arr, val) - for _, v in ipairs(arr) do - if v == val then - return true - end - end - - return false -end - -local nonpadded_apps = { "nvim", "btop", "btm" } - -wezterm.on("smartpadding", function(window, pane) - local fgp = pane:get_foreground_process_info() - if fgp == nil then - return - elseif arrContains(nonpadded_apps, fgp.name) then - window:set_config_overrides({ - window_padding = { left = 0, right = 0, top = 0, bottom = 0 }, - }) - else - window:set_config_overrides({ - window_padding = wezterm.GLOBAL.smart_padding, - }) - end -end) - -- custom status wezterm.on("update-status", function(window, pane) - if wezterm.GLOBAL.smart_padding ~= nil then - wezterm.emit("smartpadding", window, pane) + local active_kt = window:active_key_table() ~= nil + local show = C.leader.enabled or (active_kt and C.mode.enabled) + if not show then + window:set_left_status("") + return end local palette = window:effective_config().resolved_palette + + local leader = "" + if C.leader.enabled then + local leader_text = C.leader.off + if window:leader_is_active() then + leader_text = C.leader.on + end + leader = wezterm.format({ + { Foreground = { Color = palette.background } }, + { Background = { Color = palette.ansi[5] } }, + { Text = " " .. leader_text .. C.p }, + }) + end + + local mode = "" + if C.mode.enabled then + local mode_text = "" + local active = window:active_key_table() + if C.mode.names[active] ~= nil then + mode_text = C.mode.names[active] .. "" + end + mode = wezterm.format({ + { Foreground = { Color = palette.background } }, + { Background = { Color = palette.ansi[5] } }, + { Attribute = { Intensity = "Bold" } }, + { Text = mode_text }, + "ResetAttributes", + }) + end + local first_tab_active = window:mux_window():tabs_with_info()[1].is_active - - local leader_text = "  " - if window:leader_is_active() then - leader_text = "  " - end - - local mode_text = "" - local mode = window:active_key_table() - local modes = { - resize_mode = "RESIZE", - } - if modes[mode] ~= nil then - mode_text = modes[mode] - end - local divider_bg = first_tab_active and palette.ansi[2] or palette.tab_bar.inactive_tab.bg_color - window:set_left_status(wezterm.format({ - { Foreground = { Color = palette.background } }, - { Background = { Color = palette.ansi[5] } }, - { Text = leader_text }, - { Attribute = { Intensity = "Bold" } }, - { Text = mode_text }, - "ResetAttributes", + local divider = wezterm.format({ { Background = { Color = divider_bg } }, { Foreground = { Color = palette.ansi[5] } }, - { Text = DIVIDERS.RIGHT }, - })) + { Text = C.div.r }, + }) - local time = wezterm.time.now():format("%H:%M") - local sun_is_up = wezterm.time.now():sun_times(48.2, 16.366667).up - local icon = sun_is_up and " " or " " - local text = string.format("%s %s", icon, time) + window:set_left_status(leader .. mode .. divider) - window:set_right_status(wezterm.format({ - { Background = { Color = palette.tab_bar.background } }, - { Foreground = { Color = palette.ansi[6] } }, - { Text = text }, - })) + if C.clock.enabled then + local time = wezterm.time.now():format(C.clock.format) + window:set_right_status(wezterm.format({ + { Background = { Color = palette.tab_bar.background } }, + { Foreground = { Color = palette.ansi[6] } }, + { Text = time }, + })) + end end) + +return M diff --git a/home/apps/wezterm/extra.lua b/home/apps/wezterm/extra.lua new file mode 100644 index 0000000..4f63835 --- /dev/null +++ b/home/apps/wezterm/extra.lua @@ -0,0 +1,34 @@ +local wezterm = require("wezterm") + +local function arrContains(arr, val) + for _, v in ipairs(arr) do + if v == val then + return true + end + end + + return false +end + +local nonpadded_apps = { "nvim", "btop", "btm" } + +wezterm.on("smartpadding", function(window, pane) + local fgp = pane:get_foreground_process_info() + if fgp == nil then + return + elseif arrContains(nonpadded_apps, fgp.name) then + window:set_config_overrides({ + window_padding = { left = 0, right = 0, top = 0, bottom = 0 }, + }) + else + window:set_config_overrides({ + window_padding = wezterm.GLOBAL.smart_padding, + }) + end +end) + +wezterm.on("update-status", function(window, pane) + if wezterm.GLOBAL.smart_padding ~= nil then + wezterm.emit("smartpadding", window, pane) + end +end) diff --git a/home/apps/wezterm/wezterm.lua b/home/apps/wezterm/wezterm.lua index b2cdc27..5a75246 100644 --- a/home/apps/wezterm/wezterm.lua +++ b/home/apps/wezterm/wezterm.lua @@ -1,6 +1,35 @@ local wezterm = require("wezterm") local theme = require("theme") -require("bar") +require("bar").setup({ + dividers = "slant_right", -- or "slant_left", "arrows", "rounded", false + indicator = { + leader = { + enabled = true, + icon_off = " ", + icon_on = " ", + }, + mode = { + enabled = true, + names = { + resize_mode = "RESIZE", + copy_mode = "VISUAL", + search_mode = "SEARCH", + }, + }, + }, + tabs = { + numerals = "arabic", -- or "roman" + pane_count = "superscript", -- or "subscript", false + brackets = { + active = { "", ":" }, + inactive = { "", ":" }, + }, + }, + clock = { -- note that this overrides the whole set_right_status + enabled = true, + format = "%H:%M", -- use https://wezfurlong.org/wezterm/config/lua/wezterm.time/Time/format.html + }, +}) wezterm.GLOBAL = { font = "berkeley",