From b7897d344dd4d36ffec2687a41ef23cdbea241f3 Mon Sep 17 00:00:00 2001 From: rootiest Date: Tue, 1 Oct 2024 10:52:37 -0400 Subject: [PATCH] Test multiplatform support Testing changes to better support other platforms --- battery.lua | 233 +++++++++++++++++++++++++++++++++++ configs.lua | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++++ plugins.lua | 9 +- wezterm.lua | 13 +- 4 files changed, 597 insertions(+), 3 deletions(-) create mode 100644 battery.lua create mode 100644 configs.lua diff --git a/battery.lua b/battery.lua new file mode 100644 index 0000000..1a9ae7d --- /dev/null +++ b/battery.lua @@ -0,0 +1,233 @@ +--- Battery module for Wezterm. +---@module "battery" + +---@class M The battery module +---@field invert boolean Whether to invert colors +---@function get_batteries() Get the list of batteries +---@function get_battery_icons() Get the battery icons +---@function get_battery_stats() Get the battery stats + +local M = {} + +local wezterm = require("wezterm") + +--- Whether to invert the colors for light backgrounds. +M.invert = false + +--- Converts a hex color to its opposite brightness. +---@param hex_color string The hex color in the format "#RRGGBB". +---@param invert? boolean Whether to invert the colors (optional). +---@return string hex_color The hex color with the opposite brightness. +local function invert_color_brightness(hex_color, invert) + if invert == nil then + invert = M.invert + end + if invert == false then + return hex_color + end + -- Validate the input hex_color format. + if not hex_color:match("^#%x%x%x%x%x%x$") then + error("Invalid hex color format. Use #RRGGBB.") + end + + -- Convert hex to RGB. + local r = tonumber(hex_color:sub(2, 3), 16) + local g = tonumber(hex_color:sub(4, 5), 16) + local b = tonumber(hex_color:sub(6, 7), 16) + + -- Validate RGB values. + if not (r and g and b and r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255) then + error("Invalid RGB values extracted from hex color.") + end + + -- Calculate brightness. + local brightness = (r * 0.299 + g * 0.587 + b * 0.114) + + -- Invert color based on brightness. + if brightness < 128 then + -- Dark color: make it lighter. + r = math.min(r + (255 - r) * 0.33, 255) + g = math.min(g + (255 - g) * 0.33, 255) + b = math.min(b + (255 - b) * 0.33, 255) + else + -- Light color: make it darker. + r = math.max(r - r * 0.66, 0) + g = math.max(g - g * 0.66, 0) + b = math.max(b - b * 0.66, 0) + end + + -- Convert RGB back to hex. + return string.format("#%02x%02x%02x", math.floor(r + 0.5), math.floor(g + 0.5), math.floor(b + 0.5)) +end + +--- RGBColor class representing an RGB color. +---@class RGBColor +---@field r number Red value (0-255). +---@field g number Green value (0-255). +---@field b number Blue value (0-255). + +--- Blends two RGB colors together based on a blend factor. +---@param color1 RGBColor The first RGB color. +---@param color2 RGBColor The second RGB color. +---@param factor number The blend factor (between 0 and 1). +---@return RGBColor color The blended RGB color. +local function blend_color(color1, color2, factor) + return { + r = color1.r + (color2.r - color1.r) * factor, + g = color1.g + (color2.g - color1.g) * factor, + b = color1.b + (color2.b - color1.b) * factor, + } +end + +--- Rounds a decimal value to the nearest integer. +---@param val number The value to round. +---@return integer The rounded value. +local function round(val) + return math.floor(val + 0.5) +end + +--- Converts an RGB color to a hex string. +---@param color RGBColor The RGB color to convert. +---@return string hex_color The hex string representation of the color. +local function rgb_to_hex(color) + return string.format("#%02x%02x%02x", round(color.r), round(color.g), round(color.b)) +end + +--- Gets the color representing a battery charge level. +---@param charge number The charge level (0.0 to 1.0). +---@return string hex_color The corresponding hex color. +local function get_charge_color(charge) + local red = { r = 255, g = 0, b = 0 } + local yellow = { r = 255, g = 255, b = 0 } + local green = { r = 0, g = 255, b = 0 } + local color = {} + + if charge <= 0.5 then + local factor = charge / 0.5 + color = blend_color(red, yellow, factor) + else + local factor = (charge - 0.5) / 0.5 + color = blend_color(yellow, green, factor) + end + + return invert_color_brightness(rgb_to_hex(color)) +end + +--- BatteryComponent class representing battery information. +---@class BatteryComponent +---@field battery string The battery icon and percentage. (e.g. "󰂉 100%") +---@field remaining fun(): string The remaining time as a string. (e.g. "10:00") +---@field icon string The icon representing the battery status. (e.g. "󰢜 ") +---@field percent number The battery percentage. (0.0 to 1.0) +---@field time number The remaining time in minutes. +---@field condition string The battery condition ("Full", "Empty", "Charging", "Discharging", "Unknown"). + +--- Returns battery components for each battery. +--- If no batteries are detected, an empty table is returned. +---@return BatteryComponent[] batteries A list of battery components. +---@see BatteryComponent +function M.get_batteries() + local batteries = {} + local battery_info = wezterm.battery_info() + + local icons_charging = + { "󰢟 ", "󰢜 ", "󰂆 ", "󰂇 ", "󰂈 ", "󰢝 ", "󰂉 ", "󰢞 ", "󰂊 ", "󰂋 ", "󰂅 " } + local icons_discharging = + { "󰂎 ", "󰁺 ", "󰁻 ", "󰁼 ", "󰁽 ", "󰁾 ", "󰁿 ", "󰂀 ", "󰂁 ", "󰂂 ", "󰁹 " } + + for _, b in ipairs(battery_info) do + local condition = b.state + local charge = b.state_of_charge + local remaining = 0 + local percent = charge * 100 + local icon = -- Default battery state is Unknown + wezterm.format({ { Foreground = { Color = invert_color_brightness("#232634") } }, { Text = "󰂑 " } }) + + if condition == "Full" then -- Battery is 100% charged + icon = + wezterm.format({ { Foreground = { Color = invert_color_brightness("#93e398") } }, { Text = "󰁹 " } }) + elseif condition == "Empty" then -- Battery is 0% charged + icon = + wezterm.format({ { Foreground = { Color = invert_color_brightness("#f37ca0") } }, { Text = "󱃍 " } }) + elseif condition == "Charging" then -- Battery is charging + remaining = b.time_to_full + icon = wezterm.format({ + { Foreground = { Color = get_charge_color(charge) } }, + { Text = icons_charging[math.min(math.ceil(charge * 10), 11)] }, + }) + elseif condition == "Discharging" then -- Battery is discharging + remaining = b.time_to_empty + icon = wezterm.format({ + { Foreground = { Color = get_charge_color(charge) } }, + { Text = icons_discharging[math.min(math.ceil(charge * 10), 11)] }, + }) + elseif condition == "Unknown" and charge > 0.5 then -- Battery is (probably) at charge limit + icon = + wezterm.format({ { Foreground = { Color = invert_color_brightness("#93e398") } }, { Text = "󱈑 " } }) + end + + table.insert(batteries, { + battery = icon .. string.format("%.2f%%", percent), + remaining = function() + if remaining and remaining > 0 then + return string.format("%d:%02d", math.floor(remaining / 60), math.floor(remaining % 60)) + else + return "" + end + end, + icon = icon, + percent = percent, + time = remaining, + condition = condition, + }) + end + + return batteries +end + +--- Returns battery icons for all batteries. +--- If no batteries are detected, an empty string is returned. +---@return string battery_icons A formatted string containing the battery icons. +function M.get_battery_icons() + local battery_states = M.get_batteries() + + if #battery_states == 0 then + return "" + end + + local result = {} + for _, state in ipairs(battery_states) do + table.insert(result, state.icon) + end + + return table.concat(result, " | ") +end + +--- Returns battery statistics for all batteries. +--- If no batteries are detected, an empty string is returned. +---@return string battery_stats A formatted string containing the battery stats. +function M.get_battery_stats() + local battery_states = M.get_batteries() + + if #battery_states == 0 then + return "" + end + + local result = {} + for _, state in ipairs(battery_states) do + local color = get_charge_color(state.percent / 100) + local percent = wezterm.format({ + { Foreground = { Color = color } }, + { Text = string.format(" (%.2f%%)", state.percent) }, + }) + local remaining_time = wezterm.format({ + { Foreground = { Color = color } }, + { Text = state.remaining() }, + }) + table.insert(result, string.format("%s%s", state.icon, percent) .. remaining_time) + end + + return table.concat(result, " | ") +end + +return M diff --git a/configs.lua b/configs.lua new file mode 100644 index 0000000..a0a50cc --- /dev/null +++ b/configs.lua @@ -0,0 +1,345 @@ +-- ╭─────────────────────────────────────────────────────────╮ +-- │ CONFIG │ +-- ╰─────────────────────────────────────────────────────────╯ +local wezterm = WEZTERM +local act = wezterm.action +local gpus = wezterm.gui.enumerate_gpus() +local types = require("types") + +local cur_hour = wezterm.time.now():format("%H") + +local hour_angle = require("funcs").get_hour_angle(cur_hour) + +return { + -- Color Scheme + color_scheme = "Catppuccin Mocha", + -- Tab Bar Colors + colors = { + -- Compose Cursor + compose_cursor = "#a5e3a0", + -- Visual Bell + visual_bell = "#E78284", + }, + -- Command Palette Colors + command_palette_bg_color = "#232634", -- Command Palette Background + command_palette_fg_color = "#C6D0F5", -- Command Palette Foreground + -- Titlebar and Frame Colors + window_frame = { + active_titlebar_bg = "#232634", + inactive_titlebar_bg = "#303446", + inactive_titlebar_fg = "#484D69", + active_titlebar_fg = "#C6D0F5", + inactive_titlebar_border_bottom = "#3b3052", + active_titlebar_border_bottom = "#3b3052", + button_fg = "#C6D0F5", + button_bg = "#3b3052", + button_hover_fg = "#C6D0F5", + button_hover_bg = "#2b2042", + font = wezterm.font(types.win_font), + -- Tab Font Size + font_size = 10, + }, + -- Inactive Pane Filter + inactive_pane_hsb = { + saturation = 1.0, + brightness = 0.5, + }, + window_background_gradient = { + orientation = { + Linear = { + angle = hour_angle, + }, + }, + colors = { + -- "#303446", + "#24273a", + "#1e1e2e", + }, + interpolation = "CatmullRom", + blend = "Oklab", + noise = 128, + segment_size = 7, + segment_smoothness = 1.0, + }, + -- Terminal Font Size + font_size = 12.0, + -- Terminal Font + font = wezterm.font_with_fallback(types.rootiest_font), + -- Cell Sizing + cell_width = 1.0, + line_height = 1.0, + -- ANSI Colors + bold_brightens_ansi_colors = "BrightAndBold", + -- FreeType Load Flags + freetype_load_flags = "DEFAULT", + -- FreeType Load Target + freetype_load_target = "Normal", + -- Default Cursor Shape + default_cursor_style = "BlinkingBar", + -- Set the initial size + initial_cols = 180, + initial_rows = 38, + + tab_max_width = 60, + tab_bar_at_bottom = false, + + unicode_version = 14, + + -- Resize by cell + use_resize_increments = true, + + -- Use Retro tab bar + use_fancy_tab_bar = false, + + -- Set the window padding + window_padding = { + left = "0%", + right = "0%", + top = "0%", + bottom = "0%", + }, + + -- Set the animation framerate + animation_fps = 120, + + -- Window Decorations + window_decorations = "TITLE | RESIZE", + + -- Visual Bell + visual_bell = { + fade_in_duration_ms = 75, + fade_out_duration_ms = 75, + target = "CursorColor", + }, + + -- Audible Bell + audible_bell = "SystemBeep", + + -- Terminal Variable + term = "wezterm", + + --Honor kitty protocol inputs + enable_kitty_keyboard = true, + + -- Rendering + front_end = "WebGpu", + -- front_end = "OpenGL", + webgpu_power_preference = "HighPerformance", + webgpu_preferred_adapter = gpus[1], + -- Scrollback Lines + scrollback_lines = 20000, + -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Leader key ━━━━━━━━━━━━━━━━━━━━━━━━━━ + leader = { key = " ", mods = "CTRL", timeout_milliseconds = 1500 }, + -- ━━━━━━━━━━━━━━━━━━━━━━━━━ Global Key Mappings ━━━━━━━━━━━━━━━━━━━━━ + keys = { + -- Close window + { key = "q", mods = "LEADER|SHIFT|CTRL", action = act.QuitApplication }, + -- Split pane + { key = "|", mods = "LEADER|SHIFT", action = act.SplitHorizontal({ domain = "CurrentPaneDomain" }) }, + { key = "_", mods = "LEADER|SHIFT", action = act.SplitVertical({ domain = "CurrentPaneDomain" }) }, + + -- Move pane + { key = "h", mods = "SHIFT|CTRL", action = act.ActivatePaneDirection("Left") }, + { key = "j", mods = "SHIFT|CTRL", action = act.ActivatePaneDirection("Down") }, + { key = "k", mods = "SHIFT|CTRL", action = act.ActivatePaneDirection("Up") }, + { key = "l", mods = "SHIFT|CTRL", action = act.ActivatePaneDirection("Right") }, + -- Move pane to new window + { + key = "!", + mods = "LEADER | SHIFT", + action = wezterm.action_callback(function(_, pane) + pane:move_to_new_window() + end), + }, + + -- Toggle pane zoom + { + key = "z", + mods = "SHIFT|CTRL", + action = act.TogglePaneZoomState, + }, + { + key = "z", + mods = "LEADER", + action = act.TogglePaneZoomState, + }, + + -- Close pane + { key = "q", mods = "LEADER", action = act.CloseCurrentPane({ confirm = true }) }, + { key = "q", mods = "SHIFT|CTRL", action = act.CloseCurrentPane({ confirm = true }) }, + + -- Resize pane + { key = "h", mods = "ALT", action = act.AdjustPaneSize({ "Left", 1 }) }, + { key = "j", mods = "ALT", action = act.AdjustPaneSize({ "Down", 1 }) }, + { key = "k", mods = "ALT", action = act.AdjustPaneSize({ "Up", 1 }) }, + { key = "l", mods = "ALT", action = act.AdjustPaneSize({ "Right", 1 }) }, + -- Resize pane mode + { key = "r", mods = "LEADER", action = act.ActivateKeyTable({ name = "resize_mode", one_shot = false }) }, + { key = "p", mods = "LEADER", action = act.ActivateKeyTable({ name = "window_mode", one_shot = false }) }, + + -- Tab Manipulation + { key = "PageUp", mods = "CTRL", action = act.ActivateTabRelative(1) }, + { key = "PageUp", mods = "SHIFT|CTRL", action = act.MoveTabRelative(1) }, + { key = "PageDown", mods = "CTRL", action = act.ActivateTabRelative(-1) }, + { key = "PageDown", mods = "SHIFT|CTRL", action = act.MoveTabRelative(-1) }, + + { -- Quick launch + key = "x", + mods = "LEADER|CTRL", + action = act.ShowLauncherArgs({ + title = "Quick Launch", + flags = "FUZZY|TABS|DOMAINS|WORKSPACES|COMMANDS|LAUNCH_MENU_ITEMS|KEY_ASSIGNMENTS", + }), + }, + + -- Search + { key = "f", mods = "LEADER", action = act.Search("CurrentSelectionOrEmptyString") }, + { key = "f", mods = "SHIFT|CTRL", action = act.Search("CurrentSelectionOrEmptyString") }, + + -- Miscellaneous + { key = "a", mods = "LEADER|CTRL", action = act.SendKey({ key = "a", mods = "CTRL" }) }, + { key = ";", mods = "CTRL", action = act.ActivateCommandPalette }, + { key = "F1", mods = "LEADER", action = act.ShowDebugOverlay }, + { + key = "u", + mods = "LEADER|CTRL", + action = act.AttachDomain("SSH:aws-discord"), + }, + { + key = "s", + mods = "LEADER|CTRL", + action = act.ShowLauncherArgs({ title = "Connect to SSH server", flags = "FUZZY|DOMAINS" }), + }, + { key = "z", mods = "LEADER|CTRL", action = act.TogglePaneZoomState }, + { key = "n", mods = "LEADER|CTRL", action = act.SpawnWindow }, + { key = "x", mods = "LEADER", action = act.ActivateCopyMode }, + + -- Naming + { -- Rename [W]orkspace + key = "w", + mods = "LEADER|CTRL", + action = act.PromptInputLine({ + description = "Enter new name for the workspace:", + action = wezterm.action_callback(function(window, _, line) + if line then + wezterm.mux.rename_workspace(window:active_workspace(), line) + end + end), + }), + }, + { -- Rename [T]ab + key = "t", + mods = "LEADER|CTRL", + action = act.PromptInputLine({ + description = "Enter new name for the tab:", + action = wezterm.action_callback(function(_, pane, line) + if line then + local tab = pane:tab() + tab:set_title(line) + end + end), + }), + }, + { -- [S]ave Session + key = "s", + mods = "ALT", + action = act.Multiple({ + wezterm.action_callback(function(_, _) + RESURRECT.save_state(RESURRECT.workspace_state.get_workspace_state()) + RESURRECT.window_state.save_window_action() + end), + }), + }, + { -- [R]estore Session + key = "r", + mods = "ALT", + action = wezterm.action_callback(function(win, pane) + RESURRECT.fuzzy_load(win, pane, function(id) + local type = string.match(id, "^([^/]+)") -- match before '/' + id = string.match(id, "([^/]+)$") -- match after '/' + id = string.match(id, "(.+)%..+$") -- remove file extension + local state + if type == "workspace" then + state = RESURRECT.load_state(id, "workspace") + RESURRECT.workspace_state.restore_workspace(state, { + relative = true, + restore_text = true, + on_pane_restore = RESURRECT.tab_state.default_on_pane_restore, + }) + elseif type == "window" then + state = RESURRECT.load_state(id, "window") + RESURRECT.window_state.restore_window(pane:window(), state, { + relative = true, + restore_text = true, + on_pane_restore = RESURRECT.tab_state.default_on_pane_restore, + -- uncomment this line to use active tab when restoring + -- tab = win:active_tab(), + }) + end + end) + end), + }, + }, + + -- ━━━━━━━━━━━━━━━━━━━━━━ Conditional Key Mappings ━━━━━━━━━━━━━━━━━━━ + key_tables = { + resize_mode = { ---------- Resize Pane Mode ------------------------- + { key = "LeftArrow", action = act.AdjustPaneSize({ "Left", 1 }) }, + { key = "h", action = act.AdjustPaneSize({ "Left", 1 }) }, + + { key = "RightArrow", action = act.AdjustPaneSize({ "Right", 1 }) }, + { key = "l", action = act.AdjustPaneSize({ "Right", 1 }) }, + + { key = "UpArrow", action = act.AdjustPaneSize({ "Up", 1 }) }, + { key = "k", action = act.AdjustPaneSize({ "Up", 1 }) }, + + { key = "DownArrow", action = act.AdjustPaneSize({ "Down", 1 }) }, + { key = "j", action = act.AdjustPaneSize({ "Down", 1 }) }, + + -- Cancel the mode by pressing escape + { key = "Escape", action = "PopKeyTable" }, + }, + window_mode = { --------- Activate Pane Mode ---------------------- + { key = "LeftArrow", action = act.ActivatePaneDirection("Left") }, + { key = "h", action = act.ActivatePaneDirection("Left") }, + + { key = "RightArrow", action = act.ActivatePaneDirection("Right") }, + { key = "l", action = act.ActivatePaneDirection("Right") }, + + { key = "UpArrow", action = act.ActivatePaneDirection("Up") }, + { key = "k", action = act.ActivatePaneDirection("Up") }, + + { key = "DownArrow", action = act.ActivatePaneDirection("Down") }, + { key = "j", action = act.ActivatePaneDirection("Down") }, + }, + }, + + -- ━━━━━━━━━━━━━━━━━━━━━━━━━━━ Mouse Bindings ━━━━━━━━━━━━━━━━━━━━━━━━ + mouse_bindings = { + { -- Left-Click: (Up) Select Text + event = { Up = { streak = 1, button = "Left" } }, + mods = "NONE", + action = act.CompleteSelection("ClipboardAndPrimarySelection"), + }, + { -- Ctrl+Left-Click: (Up) Open Hyperlink + event = { Up = { streak = 1, button = "Left" } }, + mods = "CTRL", + action = act.OpenLinkAtMouseCursor, + }, + -- { -- Ctrl+Double-Left-Click: (Up) Open Hyperlink + -- event = { Up = { streak = 2, button = "Left" } }, + -- mods = "CTRL", + -- action = act.OpenLinkAtMouseCursor, + -- }, + { -- Ctrl+WheelUp: Go to previous tab + event = { Down = { streak = 1, button = { WheelUp = 1 } } }, + mods = "CTRL", + action = act.ActivateTabRelative(-1), + }, + { -- Ctrl+WheelDown: Go to next tab + event = { Down = { streak = 1, button = { WheelDown = 1 } } }, + mods = "CTRL", + action = act.ActivateTabRelative(1), + }, + }, +} diff --git a/plugins.lua b/plugins.lua index 365d7ea..e2f1907 100644 --- a/plugins.lua +++ b/plugins.lua @@ -35,6 +35,13 @@ function M.require_plugins(dir) pfile:close() end +function M.require_plugs() + require("plugins.hyperlinks") + require("plugins.resurrect") + require("plugins.smart_splits") + require("plugins.tabline") +end + -- Function to update all plugins function M.update_plugins() WEZTERM.plugin.update_all() @@ -42,7 +49,7 @@ end function M.setup() -- Load all plugins from the 'plugins' directory - M.require_plugins() + M.require_plugs() end return M diff --git a/wezterm.lua b/wezterm.lua index 7ff1c6d..fbff392 100644 --- a/wezterm.lua +++ b/wezterm.lua @@ -16,10 +16,19 @@ WEZTERM = require("wezterm") CONFIG = WEZTERM.config_builder() -- Load Options -require("options").setup() +--require("options").setup() + +local configs = require("configs") + +for k, v in pairs(configs) do + CONFIG[k] = v +end -- Load Plugins -require("plugins").setup() +require("plugins.hyperlinks") +require("plugins.resurrect") +require("plugins.smart_splits") +require("plugins.tabline") --------- Update Plugins ---------- ---Running this may cause slowdowns