diff --git a/home/modules/wezterm.nix b/home/modules/wezterm.nix new file mode 100644 index 0000000..fe0a483 --- /dev/null +++ b/home/modules/wezterm.nix @@ -0,0 +1,33 @@ +{ lib, config, pkgs, ... }: + +let + cfg = config.snowhawk.wezterm; + macos = config.snowhawk.macos.enable; +in +{ + options.snowhawk.wezterm = { + enable = lib.mkEnableOption "kitty home-manager module"; + }; + + config = lib.mkIf cfg.enable { + home.packages = with pkgs; [ + wezterm + fd + ]; + + programs.wezterm = { + enable = true; + extraConfig = /* lua */'' + return require 'modules' + ''; + }; + + xdg.configFile = { + wezterm = { + source = ../../home/wezterm; + recursive = true; + executable = true; + }; + }; + }; +} diff --git a/home/wezterm/modules/colors.lua b/home/wezterm/modules/colors.lua new file mode 100644 index 0000000..df8f95b --- /dev/null +++ b/home/wezterm/modules/colors.lua @@ -0,0 +1,50 @@ +local wezterm = require("wezterm") + +-- This is the M table that we will export +local M = {} + +-- define a function in the M table. +-- Only functions defined in `M` will be exported to +-- code that imports this M. +-- The suggested convention for making Ms that update +-- the config is for them to export an `apply_to_config` +-- function that accepts the config object, like this: +function M.apply_to_config(config) + config.colors = { + foreground = "#d8d8d8", + background = "#050505", + + selection_fg = "#e0def4", + selection_bg = "#403d52", + + cursor_bg = "#524f67", + cursor_fg = "#e0def4", + + cursor_border = "#524f67", + + ansi = { + "#181818", + "#ac4242", + "#90a959", + "#f4bf75", + "#6a8fb5", + "#aa759f", + "#75b5aa", + "#d8d8d8", + }, + + brights = { + "#6b6b6b", + "#c55555", + "#aac474", + "#fcea88", + "#82b8c8", + "#c28cb8", + "#93d3c3", + "#f8f8f8", + }, + } +end + +-- return our M table +return M diff --git a/home/wezterm/modules/init.lua b/home/wezterm/modules/init.lua new file mode 100644 index 0000000..2669693 --- /dev/null +++ b/home/wezterm/modules/init.lua @@ -0,0 +1,49 @@ +local wezterm = require("wezterm") +local config = wezterm.config_builder() + +local colors = require("modules/colors") +colors.apply_to_config(config) + +config.unix_domains = { { name = "unix" } } +config.default_gui_startup_args = { "connect", "unix" } + +config.font = wezterm.font("JetBrainsMono Nerd Font") + +config.use_fancy_tab_bar = false +config.tab_bar_at_bottom = true + +-- https://github.com/wez/wezterm/issues/5990 +config.front_end = "WebGpu" + +local act = wezterm.action +local sessionizer = require("modules/sessionizer") +local navigator = require("modules/navigator") + +-- timeout_milliseconds defaults to 1000 and can be omitted +config.leader = { key = "b", mods = "CTRL", timeout_milliseconds = 1000 } + +config.keys = { + { key = "b", mods = "LEADER|CTRL", action = act.ActivateLastTab }, + { key = "p", mods = "LEADER", action = act.ActivateTabRelative(-1) }, + { key = "p", mods = "LEADER|CTRL", action = act.ActivateTabRelative(-1) }, + { key = "n", mods = "LEADER", action = act.ActivateTabRelative(1) }, + { key = "n", mods = "LEADER|CTRL", action = act.ActivateTabRelative(1) }, + { key = "s", mods = "LEADER", action = act.ShowLauncherArgs({ flags = "WORKSPACES" }) }, + + { key = "\\", mods = "LEADER", action = act.SplitHorizontal({ domain = "CurrentPaneDomain" }) }, + { key = "-", mods = "LEADER", action = act.SplitVertical({ domain = "CurrentPaneDomain" }) }, + { key = "c", mods = "LEADER", action = act.SpawnTab("CurrentPaneDomain") }, + + { key = "a", mods = "LEADER", action = act.AttachDomain("unix") }, + { key = "d", mods = "LEADER|CTRL", action = act.DetachDomain("CurrentPaneDomain") }, + + -- Integration with neovim panes + -- { key = "h", mods = "CTRL", action = act.EmitEvent("ActivatePaneDirection-left") }, + -- { key = "j", mods = "CTRL", action = act.EmitEvent("ActivatePaneDirection-down") }, + -- { key = "k", mods = "CTRL", action = act.EmitEvent("ActivatePaneDirection-up") }, + -- { key = "l", mods = "CTRL", action = act.EmitEvent("ActivatePaneDirection-right") }, + + { key = "f", mods = "LEADER", action = wezterm.action_callback(sessionizer.toggle) }, +} + +return config diff --git a/home/wezterm/modules/navigator.lua b/home/wezterm/modules/navigator.lua new file mode 100644 index 0000000..7062464 --- /dev/null +++ b/home/wezterm/modules/navigator.lua @@ -0,0 +1,53 @@ +local wezterm = require("wezterm") +local M = {} + +-- https://github.com/lrvdijk/dotfiles/blob/master/wezterm/wezterm.lua +-- Integration with neovim panes +function M.isViProcess(pane) + -- get_foreground_process_name On Linux, macOS and Windows, + -- the process can be queried to determine this path. Other operating systems + -- (notably, FreeBSD and other unix systems) are not currently supported + -- return pane:get_foreground_process_name():find('n?vim') ~= nil + -- Use get_title as it works for multiplexed sessions too + return pane:get_title():find("n?vim") ~= nil +end + +function M.conditionalActivatePane(window, pane, pane_direction, vim_direction) + local vim_pane_changed = false + + if M.isViProcess(pane) then + local before = pane:get_cursor_position() + window:perform_action( + -- This should match the keybinds you set in Neovim. + wezterm.action.SendKey({ key = vim_direction, mods = "CTRL" }), + pane + ) + wezterm.sleep_ms(50) + local after = pane:get_cursor_position() + + if before.x ~= after.x and before.y ~= after.y then + vim_pane_changed = true + end + end + + if not vim_pane_changed then + window:perform_action(wezterm.action.ActivatePaneDirection(pane_direction), pane) + end +end + +function M.apply_to_config(config) + wezterm.on("ActivatePaneDirection-right", function(window, pane) + M.conditionalActivatePane(window, pane, "Right", "l") + end) + wezterm.on("ActivatePaneDirection-left", function(window, pane) + M.conditionalActivatePane(window, pane, "Left", "h") + end) + wezterm.on("ActivatePaneDirection-up", function(window, pane) + M.conditionalActivatePane(window, pane, "Up", "k") + end) + wezterm.on("ActivatePaneDirection-down", function(window, pane) + M.conditionalActivatePane(window, pane, "Down", "j") + end) +end + +return M diff --git a/home/wezterm/modules/sessionizer.lua b/home/wezterm/modules/sessionizer.lua new file mode 100644 index 0000000..fc3e5aa --- /dev/null +++ b/home/wezterm/modules/sessionizer.lua @@ -0,0 +1,52 @@ +local wezterm = require("wezterm") +local act = wezterm.action + +local M = {} + +local fd = "~/.nix-profile/bin/fd" + +M.toggle = function(window, pane) + local projects = {} + + local success, stdout, stderr = wezterm.run_child_process({ + fd, + "-HI", + "^.git$", + "--max-depth=4", + "--prune", + os.getenv("HOME") .. "/projects", + os.getenv("HOME") .. "/.config", + os.getenv("HOME") .. "/src", + }) + + if not success then + wezterm.log_error("Failed to run fd: " .. stderr) + return + end + + for line in stdout:gmatch("([^\n]*)\n?") do + local project = line:gsub("/.git.*$", "") + local label = project + local id = project:gsub(".*/", "") + table.insert(projects, { label = tostring(label), id = tostring(id) }) + end + + window:perform_action( + act.InputSelector({ + action = wezterm.action_callback(function(win, _, id, label) + if not id and not label then + wezterm.log_info("Cancelled") + else + wezterm.log_info("Selected " .. label) + win:perform_action(act.SwitchToWorkspace({ name = id, spawn = { cwd = label } }), pane) + end + end), + fuzzy = true, + title = "Select project", + choices = projects, + }), + pane + ) +end + +return M diff --git a/hosts/snowhawk/home.nix b/hosts/snowhawk/home.nix index 28c0dbe..9b9325f 100644 --- a/hosts/snowhawk/home.nix +++ b/hosts/snowhawk/home.nix @@ -14,6 +14,7 @@ flameshot.enable = true; playerctl.enable = true; kitty.enable = true; + wezterm.enable = true; defaultPrograms.enable = true; pipewire-controller.enable = true;