From 847c9e64c0ac70723047b6a1f1e7357c652b4c24 Mon Sep 17 00:00:00 2001 From: James Dugan Date: Tue, 4 Feb 2025 21:06:01 -0700 Subject: [PATCH] First commit --- .config/bat/config | 6 + .config/bat/setup.sh | 20 + .config/hilbish/carapace.lua | 63 + .config/hilbish/fish_completer.lua | 54 + .config/hilbish/hinter.lua | 20 + .config/hilbish/homebrew.lua | 9 + .config/hilbish/init.lua | 77 ++ .config/hilbish/starship.lua | 64 + .config/hilbish/syntax.lua | 192 +++ .config/hilbish/utils.lua | 20 + .config/hilbish/vendor/json.lua | 388 ++++++ .config/kak/config/local_config.kak | 13 + .config/kak/config/mappings.kak | 8 + .config/kak/config/options.kak | 17 + .config/kak/config/plugins.kak | 122 ++ .config/kak/filetypes/go.kak | 22 + .config/kak/filetypes/kak.kak | 13 + .config/kak/filetypes/lua.kak | 10 + .config/kak/filetypes/python.kak | 22 + .config/kak/filetypes/sh.kak | 3 + .config/kak/filetypes/yaml.kak | 5 + .config/kak/kakrc | 47 + .config/kak/starship.toml | 175 +++ .config/kak/syntaxes/capnp.kak | 90 ++ .config/kak/syntaxes/kdl.kak | 97 ++ .config/kak/syntaxes/rainbow_csv.kak | 32 + .config/kak/syntaxes/sshconfig.kak | 116 ++ .config/kak/tools/lazygit.kak | 7 + .config/kak/tools/xplr.kak | 21 + .config/kak/utils/beacon.kak | 87 ++ .config/kak/utils/whitespace.kak | 22 + .config/lazygit/config.yml | 95 ++ .config/wezterm/colors/sonokai_andromeda.toml | 33 + .config/wezterm/config/appearance.lua | 34 + .config/wezterm/config/bindings.lua | 127 ++ .config/wezterm/config/general.lua | 11 + .config/wezterm/config/init.lua | 8 + .config/wezterm/events/format_tab_title.lua | 54 + .config/wezterm/events/update_status.lua | 56 + .config/wezterm/types/color.lua | 48 + .config/wezterm/types/gui.lua | 27 + .config/wezterm/types/init.lua | 217 +++ .config/wezterm/types/mux.lua | 47 + .config/wezterm/types/procinfo.lua | 20 + .config/wezterm/types/time.lua | 21 + .config/wezterm/types/types.lua | 1172 +++++++++++++++++ .config/wezterm/util/init.lua | 24 + .config/wezterm/wezterm.lua | 6 + .config/xplr/init.lua | 54 + .config/xplr/plugins.lua | 34 + .config/xplr/preview.lua | 128 ++ 51 files changed, 4058 insertions(+) create mode 100644 .config/bat/config create mode 100755 .config/bat/setup.sh create mode 100755 .config/hilbish/carapace.lua create mode 100755 .config/hilbish/fish_completer.lua create mode 100755 .config/hilbish/hinter.lua create mode 100755 .config/hilbish/homebrew.lua create mode 100755 .config/hilbish/init.lua create mode 100755 .config/hilbish/starship.lua create mode 100755 .config/hilbish/syntax.lua create mode 100755 .config/hilbish/utils.lua create mode 100755 .config/hilbish/vendor/json.lua create mode 100644 .config/kak/config/local_config.kak create mode 100644 .config/kak/config/mappings.kak create mode 100644 .config/kak/config/options.kak create mode 100644 .config/kak/config/plugins.kak create mode 100644 .config/kak/filetypes/go.kak create mode 100644 .config/kak/filetypes/kak.kak create mode 100644 .config/kak/filetypes/lua.kak create mode 100644 .config/kak/filetypes/python.kak create mode 100644 .config/kak/filetypes/sh.kak create mode 100644 .config/kak/filetypes/yaml.kak create mode 100644 .config/kak/kakrc create mode 100644 .config/kak/starship.toml create mode 100644 .config/kak/syntaxes/capnp.kak create mode 100644 .config/kak/syntaxes/kdl.kak create mode 100644 .config/kak/syntaxes/rainbow_csv.kak create mode 100644 .config/kak/syntaxes/sshconfig.kak create mode 100644 .config/kak/tools/lazygit.kak create mode 100644 .config/kak/tools/xplr.kak create mode 100644 .config/kak/utils/beacon.kak create mode 100644 .config/kak/utils/whitespace.kak create mode 100644 .config/lazygit/config.yml create mode 100644 .config/wezterm/colors/sonokai_andromeda.toml create mode 100644 .config/wezterm/config/appearance.lua create mode 100644 .config/wezterm/config/bindings.lua create mode 100644 .config/wezterm/config/general.lua create mode 100644 .config/wezterm/config/init.lua create mode 100644 .config/wezterm/events/format_tab_title.lua create mode 100644 .config/wezterm/events/update_status.lua create mode 100644 .config/wezterm/types/color.lua create mode 100644 .config/wezterm/types/gui.lua create mode 100644 .config/wezterm/types/init.lua create mode 100644 .config/wezterm/types/mux.lua create mode 100644 .config/wezterm/types/procinfo.lua create mode 100644 .config/wezterm/types/time.lua create mode 100644 .config/wezterm/types/types.lua create mode 100644 .config/wezterm/util/init.lua create mode 100644 .config/wezterm/wezterm.lua create mode 100644 .config/xplr/init.lua create mode 100644 .config/xplr/plugins.lua create mode 100644 .config/xplr/preview.lua diff --git a/.config/bat/config b/.config/bat/config new file mode 100644 index 0000000..96e8dce --- /dev/null +++ b/.config/bat/config @@ -0,0 +1,6 @@ +# Requires https://github.com/mhanberg/everforest-textmate installed in ~/.config/bat/themes/ +--theme="Everforest Dark" + +--style="full" + +--map-syntax="uv.lock:TOML" diff --git a/.config/bat/setup.sh b/.config/bat/setup.sh new file mode 100755 index 0000000..bf4a072 --- /dev/null +++ b/.config/bat/setup.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# Small bootstrap script that sets up the necessary syntax grammars and themes +# for this particular bat config. + +theme_dir="$(bat --config-dir)/themes" +syntax_dir="$(bat --config-dir)/syntaxes" + +# Themes +mkdir -p $theme_dir +cd $theme_dir +git clone https://github.com/mhanberg/everforest-textmate + +# Syntaxes +mkdir -p $syntax_dir +cd $syntax_dir +git clone https://github.com/eugenesvk/sublime-KDL + +# Build bat cache +bat cache --build diff --git a/.config/hilbish/carapace.lua b/.config/hilbish/carapace.lua new file mode 100755 index 0000000..cb4432c --- /dev/null +++ b/.config/hilbish/carapace.lua @@ -0,0 +1,63 @@ +local json = require "json" +local lunacolors = require "lunacolors" + +local M = {} + +M.fmt = function(str, style) + local styles = style:split(" ") + local formatStr = "" + for _, v in pairs(styles) do + formatStr = formatStr .. "{" .. v .. "}" + end + formatStr = formatStr .. str + return lunacolors.format(formatStr) +end + +M.complete_func = function(query, ctx, fields) + local carapace_arg = ctx + + -- If the ctx ends in a space, we need to append a "" to the carapace command + if ctx:sub(-1, -1):match("%s") ~= nil then + carapace_arg = carapace_arg .. '""' + end + + -- Run carapace + local carapace_cmd = "carapace " .. fields[1] .. " export " .. carapace_arg + local res = io.popen(carapace_cmd) + local out = res:read("*all") + + -- Extract completion items + local out_table = json.decode(out) + local values = {} + + if out_table["values"] ~= nil then + for _, v in pairs(out_table["values"]) do + -- Some completion items are styled; some aren't. + if v["style"] ~= nil then + if v["description"] ~= nil then + values[v["value"]] = { M.fmt(v["description"], v["style"]) } + else + table.insert(values, v["value"]) + end + else + if v["description"] ~= nil then + values[v["value"]] = { v["description"] } + else + table.insert(values, v["value"]) + end + end + end + end + + -- Construct completion items table + local comp = { + { + items = values, + type = "list" + } + } + + return comp, query +end + +return M diff --git a/.config/hilbish/fish_completer.lua b/.config/hilbish/fish_completer.lua new file mode 100755 index 0000000..242b84f --- /dev/null +++ b/.config/hilbish/fish_completer.lua @@ -0,0 +1,54 @@ +local M = {} + +M.fish_completer = function(query, ctx, fields) + -- Ensure any quotes in input are properly escaped + ctx = ctx:gsub('"', '\\"') + ctx = ctx:gsub("'", "\\'") + + -- Run fish + local cmd = "fish --command 'complete \"--do-complete=" .. ctx .. "\"'" + local res = io.popen(cmd) + local raw_str = res:read('*all') + + -- Extract completion items + -- local values = table.map(string.split(raw_str, "\n"), function(v) + -- return string.split(v, "\t") + -- end) + local values = string.split(raw_str, "\n") + local comp_items = {} + for _, v in pairs(values) do + local _, count = string.gsub(v, " ", "") + if count > 0 then + local split = string.split(v, "\t") + comp_items[split[1]] = { split[2] } + else + comp_items[#comp_items+1] = v + end + end + -- for _, v in pairs(string.split(raw_str, "\n")) do + -- local comp_val = string.split(v, "\t") + -- values[comp_val[1]] = comp_val[2] + -- end + + -- Only extract completions that start with given prefix + -- (fish doesn't consistently do this it seems) + -- if query ~= "" then + -- for i = #values,1,-1 do + -- if values[i]:find(query, 1, True) ~= 1 then + -- table.remove(values, i) + -- end + -- end + -- end + + -- Construct completion items table + local comp = { + { + items = comp_items, + type = 'list' + } + } + + return comp, query +end + +return M diff --git a/.config/hilbish/hinter.lua b/.config/hilbish/hinter.lua new file mode 100755 index 0000000..21b1008 --- /dev/null +++ b/.config/hilbish/hinter.lua @@ -0,0 +1,20 @@ +-- Basic shell history based hinter. +-- It's a bit buggy, but it works (TODO: fix) + +local hilbish = require "hilbish" + +local M = {} + +M.hinter = function(line) + local his = hilbish.history.all() + local his_vals = table.filter(his, function(v) + return v:find(line, 1, true) == 1 + end) + if #his_vals ~= 0 then + local base_val = his_vals[#his_vals] + return string.sub(base_val, string.len(line) + 1, -1) + end + return '' +end + +return M diff --git a/.config/hilbish/homebrew.lua b/.config/hilbish/homebrew.lua new file mode 100755 index 0000000..df83342 --- /dev/null +++ b/.config/hilbish/homebrew.lua @@ -0,0 +1,9 @@ +-- Homebrew support +local hilbish = require("hilbish") + +os.setenv("HOMEBREW_PREFIX", "/opt/homebrew") +os.setenv("HOMEBREW_REPOSITORY", "/opt/homebrew") +os.setenv("HOMEBREW_CELLAR", "/opt/homebrew") + +hilbish.appendPath("/opt/homebrew/bin") +hilbish.appendPath("/opt/homebrew/sbin") diff --git a/.config/hilbish/init.lua b/.config/hilbish/init.lua new file mode 100755 index 0000000..b6d5f85 --- /dev/null +++ b/.config/hilbish/init.lua @@ -0,0 +1,77 @@ +local bait = require('bait') +local ansikit = require('ansikit') +local hilbish = require('hilbish') + +-- For some reason, on MacOS Hilbish doesn't find lua modules correctly. +-- So, we need to tell it where to find stuff. +local home_dir = os.getenv("HOME") +package.path = home_dir .. "/.config/hilbish/?.lua;" .. package.path +package.path = home_dir .. "/.config/hilbish/vendor/?.lua;" .. package.path + +-- Path +hilbish.appendPath('~/bin') +hilbish.appendPath('~/.cargo/bin') +hilbish.appendPath('~/.local/bin') +hilbish.appendPath('~/.nimble/bin') +hilbish.appendPath('~/.luarocks/bin') +hilbish.appendPath('~/.rye/shims') +hilbish.appendPath('/usr/local/bin') +hilbish.appendPath('/opt/local/bin') + +local hinter = require('.hinter') +local syntax = require('.syntax') +local fish_completer = require('.fish_completer') +--local carapace_completer = require('.carapace') +local starship = require('.starship') + +require('homebrew') + +-- Shut up, hilbish +hilbish.opts['greeting'] = '' +hilbish.opts['motd'] = false +hilbish.opts['tips'] = false + +-- Prompt (starship) +starship.setup() + +-- Hooks +bait.catch('hilbish.vimMode', function(mode) + if mode ~= 'insert' then + ansikit.cursorStyle(ansikit.blockCursor) + else + ansikit.cursorStyle(ansikit.lineCursor) + end +end) + +-- Vim mode +hilbish.inputMode("vim") + +-- Aliases +hilbish.aliases.add('ls', 'lsd') +hilbish.aliases.add('la', 'exa --icons --all') +hilbish.aliases.add('ll', 'exa --long') +hilbish.aliases.add('lla', 'exa --long --all') +hilbish.aliases.add('lt', 'exa --icons --tree') +hilbish.aliases.add('lta', 'exa --icons --tree --all') + +-- dotfile management +hilbish.aliases.add('dotfiles', 'git --git-dir=' .. home_dir .. '/workspace/dippin-dotfiles/ --work-tree=' .. home_dir .. '/') + + +-- Other environment variables +os.setenv("KAKOUNE_POSIX_SHELL", "/bin/dash") +os.setenv("CARAPACE_BRIDGES", "zsh,fish,bash,inshellisense") + +-- Syntax highlighting +function hilbish.highlighter(line) + return syntax.sh(line) +end + +-- Hinter +function hilbish.hinter(line, _) + return hinter.hinter(line) +end + +-- Completers +hilbish.complete('command.git', fish_completer.fish_completer) +hilbish.complete('command.pacman', fish_completer.fish_completer) diff --git a/.config/hilbish/starship.lua b/.config/hilbish/starship.lua new file mode 100755 index 0000000..351ed73 --- /dev/null +++ b/.config/hilbish/starship.lua @@ -0,0 +1,64 @@ +-- Starship.rs support for Hilbish +-- Supports the following features: +-- * exit codes +-- * command duration (kind of - it usually works but is not 100% perfect) +-- * number of jobs +-- * continuation prompt (which some shells like fish don't even support!) +-- * anything else inherently handled by starship (git, username, etc) + +local bait = require 'bait' +local hilbish = require 'hilbish' + +local M = {} + +M.execTime = {} + +function M.doPrompt(status, num_jobs, num_secs) + -- Since lua by default only has second-resolution with its os.time() function, + -- we need to multiply by 1000 to get milliseconds elapsed. + -- This, of course, means we don't actually get millisecond-level resolution, but whatever - we work with what we got. + local time_ms = num_secs * 1000 + + local cmd = "starship prompt --status " .. status .. " --jobs " .. num_jobs .. " --cmd-duration " .. time_ms + local res = io.popen(cmd) + hilbish.prompt(res:read("*all")) +end + +function M.doCommandExit(code, cmdStr) + local cur_time = os.time() + local time_elapsed = 0 + + if cmdStr ~= nil then + if M.execTime[cmdStr] ~= nil then + time_elapsed = cur_time - M.execTime[cmdStr] + end + M.execTime[cmdStr] = nil + end + + local jobs = hilbish.jobs.all() + M.doPrompt(code, #jobs, time_elapsed) +end + +function M.doCommandPreExec(input) + if input ~= nil then + M.execTime[input] = os.time() + end +end + +function M.setup() + local cmd = "starship prompt --continuation" + local res = io.popen(cmd) + hilbish.multiprompt(res:read("*all")) + + M.doPrompt(0, 0, 0) + + bait.catch("command.preexec", function(input, _) + M.doCommandPreExec(input) + end) + + bait.catch('command.exit', function(code, cmdStr) + M.doCommandExit(code, cmdStr) + end) +end + +return M diff --git a/.config/hilbish/syntax.lua b/.config/hilbish/syntax.lua new file mode 100755 index 0000000..5291915 --- /dev/null +++ b/.config/hilbish/syntax.lua @@ -0,0 +1,192 @@ +-- Syntax highlighting implementation for Hilbish + +local colors = require "lunacolors" +local hilbish = require "hilbish" +local fs = require "fs" + +local utils = require ".utils" + +local M = {} + +local SQ = 0x27 -- U+0027 APORSTROPHE +local DQ = 0x22 -- U+0022 QUOTATION MARK +local SP = 0x20 -- U+0020 SPACE +local HT = 0x09 -- U+0009 CHARACTER TABULATION +local LF = 0x0A -- U+000A LINE FEED (LF) +local CR = 0x0D -- U+000D CARRIAGE RETURN (CR) +local BS = 0x5C -- U+005C BACKSLASH + +-- sh builtins +local sh_builtins = { + "admin", "aliasar", "asa", "at", "awk", "basename", "batch", "bc", "bg", "c99", "cal", "cat", "cd", "cflow", "chgrp", + "chmod", + "chown", "cksum", "cmp", "comm", "command", "compress", "cp", "crontab", "csplit", "ctags", "cut", "cxref", "date", + "dd", + "delta", "df", "diff", "dirname", "du", "echo", "ed", "env", "ex", "expand", "expr", "false", "fc", "fg", "file", + "find", "fold", + "fort77", "fuser", "gencat", "get", "getconf", "getopts", "grep", "hash", "head", "iconv", "id", "ipcrm", "ipcs", + "jobs", + "join", "kill", "lex", "link", "ln", "locale", "localedef", "logger", "logname", "lp", "ls", "m4", "mailx", "make", + "man", + "mesg", "mkdir", "mkfifo", "more", "mv", "newgrp", "nice", "nl", "nm", "nohup", "od", "paste", "patch", "pathchk", + "pax", + "pr", "printf", "prs", "ps", "pwd", "qalter", "qdel", "qhold", "qmove", "qmsg", "qrerun", "qrls", "qselect", "qsig", + "qstat", "qsub", "read", "renice", "rm", "rmdel", "rmdir", "sact", "sccs", "sed", "sh", "sleep", "sort", "split", + "strings", "strip", "stty", "tabs", "tail", "talk", "tee", "test", "time", "touch", "tput", "tr", "true", "tsort", + "tty", "type", "ulimit", "umask", "unalias", "uname", "uncompress", "unexpand", "unget", "uniq", "unlink", + "uucp", "uudecode", "uuencode", "uustat", "uux", "val", "vi", "wait", "wc", "what", "who", "write", "xargs", "yacc", + "zcat" +} + +-- sh keywords +local sh_keywords = { + "if", "then", "else", "elif", "fi", "case", "esac", "for", "select", "while", "until", "do", "done", "in", "function", + "time", "coproc" +} + +-- Determine if this string is a significant keyword, and if so, what it is +function M.is_cmd(str) + if utils.contains(sh_builtins, str) then + return "builtin" + elseif utils.contains(sh_keywords, str) then + return "keyword" + elseif hilbish.which(str) ~= nil then + return "cmd" + else + -- Try to use this as a filesystem glob + -- This may fail with an error, so we need to make sure that + -- doesn't happen first. + str = str:gsub("~", os.getenv("HOME")) + if pcall(fs.glob, str) then + local globs = fs.glob(str) + if #globs > 0 then + return "file" + end + end + end + return nil +end + +-- Crude sh lexer +function M.lex_sh(s) + local state = nil + local escape = false + local result = {} + local point = 0 + local index = 0 + -- Go through the string + for i = 1, #s do + index = i + local c = s:byte(i) + local v = string.char(c) + -- Single quoted string state + if state == SQ then + if c == SQ then + state = nil + result[#result + 1] = { string.sub(s, point, i), "string" } + point = i + 1 + end + -- Double quoted string state + elseif state == DQ then + if escape then + escape = false + else + if c == DQ then + state = nil + result[#result + 1] = { string.sub(s, point, i), "string" } + point = i + 1 + elseif c == BS then + escape = true + end + end + -- Default state + else + if escape then + escape = false + elseif c == SP or c == HT or c == LF or c == CR then + if point ~= i then + result[#result + 1] = { string.sub(s, point, i - 1), "other" } + end + result[#result + 1] = { v, "whitespace" } + point = i + 1 + elseif c == DQ then + state = DQ + if point ~= i then + result[#result + 1] = { string.sub(s, point, i - 1), "other" } + end + point = i + elseif c == SQ then + state = SQ + if point ~= i then + result[#result + 1] = { string.sub(s, point, i - 1), "other" } + end + point = i + elseif c == BS then + escape = true + end + end + end + -- If we are still in a string then say as such + if state ~= nil then + result[#result + 1] = { string.sub(s, point, index), "string" } + -- Otherwise, return the rest as a regular token + else + if point ~= index then + result[#result + 1] = { string.sub(s, point, index), "other" } + else + local c = s:byte(index) + -- If the final character isn't a space, render it anyway + -- This is a side effect of the space handling code. TODO: fix. + if c ~= SP and c ~= HT and c ~= LF and c ~= CR then + result[#result + 1] = { string.sub(s, point, index), "other" } + end + end + end + return result +end + +-- Sort the table's key pairs +function M.pairsByKeys(t, f) + local a = {} + for n in pairs(t) do table.insert(a, n) end + table.sort(a, f) + local i = 0 + local iter = function() + i = i + 1 + if a[i] == nil then + return nil + else + return a[i], t[a[i]] + end + end + return iter +end + +-- sh highlighter +function M.sh(str) + -- Parse the string + local table = M.lex_sh(str) + -- Construct the format string + local format_str = "" + for _, v in M.pairsByKeys(table) do + if v[2] == "string" then + format_str = format_str .. "{red}" .. v[1] + else + local cmd = M.is_cmd(v[1]) + if cmd == "cmd" then + format_str = format_str .. "{bold}{brightGreen}" .. v[1] .. "{reset}" + elseif cmd == "builtin" then + format_str = format_str .. "{bold}{brightBlue}" .. v[1] .. "{reset}" + elseif cmd == "keyword" then + format_str = format_str .. "{bold}{brightMagenta}" .. v[1] .. "{reset}" + elseif cmd == "file" then + format_str = format_str .. "{bold}{brightYellow}" .. v[1] .. "{reset}" + else + format_str = format_str .. "{brightWhite}" .. v[1] + end + end + end + return colors.format(format_str) +end + +return M diff --git a/.config/hilbish/utils.lua b/.config/hilbish/utils.lua new file mode 100755 index 0000000..a059736 --- /dev/null +++ b/.config/hilbish/utils.lua @@ -0,0 +1,20 @@ +-- Various utility functions. + +local utils = {} + +utils.contains = function(table, element) + for key, value in pairs(table) do + if type(key) == type(element) then + if key == element then + return true + end + else + if value == element then + return true + end + end + end + return false +end + +return utils diff --git a/.config/hilbish/vendor/json.lua b/.config/hilbish/vendor/json.lua new file mode 100755 index 0000000..711ef78 --- /dev/null +++ b/.config/hilbish/vendor/json.lua @@ -0,0 +1,388 @@ +-- +-- json.lua +-- +-- Copyright (c) 2020 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\", + [ "\"" ] = "\"", + [ "\b" ] = "b", + [ "\f" ] = "f", + [ "\n" ] = "n", + [ "\r" ] = "r", + [ "\t" ] = "t", +} + +local escape_char_map_inv = { [ "/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(1, 4), 16 ) + local n2 = tonumber( s:sub(7, 10), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local res = "" + local j = i + 1 + local k = j + + while j <= #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + + elseif x == 92 then -- `\`: Escape + res = res .. str:sub(k, j - 1) + j = j + 1 + local c = str:sub(j, j) + if c == "u" then + local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) + or str:match("^%x%x%x%x", j + 1) + or decode_error(str, j - 1, "invalid unicode escape in string") + res = res .. parse_unicode_escape(hex) + j = j + #hex + else + if not escape_chars[c] then + decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") + end + res = res .. escape_char_map_inv[c] + end + k = j + 1 + + elseif x == 34 then -- `"`: End of string + res = res .. str:sub(k, j - 1) + return res, j + 1 + end + + j = j + 1 + end + + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json diff --git a/.config/kak/config/local_config.kak b/.config/kak/config/local_config.kak new file mode 100644 index 0000000..52bb568 --- /dev/null +++ b/.config/kak/config/local_config.kak @@ -0,0 +1,13 @@ +# local-config +evaluate-commands %sh{ + cwd=$(pwd) + while [ $cwd != "/" ]; do + path="$cwd/.local.kak" + if [ -f $path ]; then + printf "%s\n" "source $path" + break + fi + cd .. + cwd=$(pwd) + done +} diff --git a/.config/kak/config/mappings.kak b/.config/kak/config/mappings.kak new file mode 100644 index 0000000..4b7b709 --- /dev/null +++ b/.config/kak/config/mappings.kak @@ -0,0 +1,8 @@ +map global normal :toggle-whitespace +map global normal :buffer-switcher +map global normal :xplr +map global normal :lazygit + +map global user 'p' 'pbpaste' -docstring 'Paste from clipboard' +map global user 'P' '!pbpaste' -docstring 'Paste from clipboard' +map global user 'y' 'pbcopy' -docstring 'Yank to clipboard' diff --git a/.config/kak/config/options.kak b/.config/kak/config/options.kak new file mode 100644 index 0000000..8bbe66f --- /dev/null +++ b/.config/kak/config/options.kak @@ -0,0 +1,17 @@ +colorscheme everforest-dark-soft + +set-option global ui_options terminal_set_title=no terminal_assistant=cat # The cat is critically important. + +set-option global tabstop 4 +set-option global indentwidth 4 + +add-highlighter global/ show-matching + +declare-option str windowing_placement horizontal +# With the way that Kakoune's windowing detection is currently set up, the wezterm module will never be loaded. +# So, we need to fix the order in which windowing modules are declared. +declare-option str-list windowing_modules 'tmux' 'screen' 'zellij' 'kitty' 'wezterm' 'iterm' 'appleterminal' 'sway' 'wayland' 'x11' + +hook global WinCreate .* %{ + add-highlighter window/number-lines number-lines -hlcursor +} diff --git a/.config/kak/config/plugins.kak b/.config/kak/config/plugins.kak new file mode 100644 index 0000000..cc2cb11 --- /dev/null +++ b/.config/kak/config/plugins.kak @@ -0,0 +1,122 @@ +source "%val{config}/bundle/kak-bundle/rc/kak-bundle.kak" +bundle-noload kak-bundle "ln -sf ~/workspace/kak-bundle/" + +bundle kakoune-lsp "https://github.com/kakoune-lsp/kakoune-lsp" %{ + set-option global lsp_diagnostic_line_error_sign  + set-option global lsp_diagnostic_line_hint_sign ? + set-option global lsp_diagnostic_line_info_sign ℹ + set-option global lsp_diagnostic_line_warning_sign  + + # kakoune-lsp doesn't have a command to enable auto-hover per buffer, + # only supporting enabling auto-hover globally, + # which causes issues in filetypes that don't have lsp set up. + # So, we need to define one ourselves. + define-command lsp-auto-hover-enable-buffer %{ + remove-hooks buffer lsp-auto-hover + hook -group lsp-auto-hover buffer NormalIdle .* %{ lsp-check-auto-hover lsp-hover } + } + + # Convenience commands for enabling lsp features + define-command lsp-semantic-tokens-enable %{ + hook window -group semantic-tokens BufReload .* lsp-semantic-tokens + hook window -group semantic-tokens NormalIdle .* lsp-semantic-tokens + hook window -group semantic-tokens InsertIdle .* lsp-semantic-tokens + hook -once -always window WinSetOption filetype=.* %{ + remove-hooks window semantic-tokens + } + } + define-command lsp-enable-buffer %{ + lsp-enable-window + lsp-auto-hover-enable-buffer + lsp-inlay-diagnostics-enable buffer + lsp-inlay-hints-enable buffer + } + + # We want to be explicit about lsp server settings per filetype + # So, we are disabling the default lsp server hooks + remove-hooks global lsp-filetype-.* +} +bundle-install-hook kakoune-lsp %{ + cargo install --locked --force --path . +} + +bundle-noload everforest.kak "ln -sf ~/workspace/everforest.kak/" +bundle-install-hook everforest.kak %{ + mkdir -p "${kak_config}/colors" + ln -sf "${kak_opt_bundle_path}/everforest.kak" "${kak_config}/colors/" +} +bundle-cleaner everforest.kak %{ + rm "${kak_config}/colors/everforest.kak" +} + +bundle luar "https://github.com/gustavo-hms/luar" %@ + require-module luar + + # Luar's highlighters are very subtly broken so we need to replace them + # TODO: submit a PR to luar with these fixes. + remove-highlighter shared/kakrc/lua1 + remove-highlighter shared/kakrc/lua2 + remove-highlighter shared/kakrc/lua3 + remove-highlighter shared/kakrc/lua4 + add-highlighter shared/kakrc/lua1 region -recurse '\{' '(^|\h)lua\s(([\s{}\w%/$-|''"])* )?%\{\K' '\}' ref lua + add-highlighter shared/kakrc/lua2 region -recurse '\(' '(^|\h)lua\s(([\s{}\w%/$-|''"])* )?%\(\K' '\)' ref lua + add-highlighter shared/kakrc/lua3 region -recurse '\[' '(^|\h)lua\s(([\s{}\w%/$-|''"])* )?%\[\K' '\]' ref lua + add-highlighter shared/kakrc/lua4 region -recurse '<' '(^|\h)lua\s(([\s{}\w%/$-|''"])* )?%<\K' '>' ref lua +@ + +bundle kakoune-buffer-switcher "https://github.com/occivink/kakoune-buffer-switcher" %{ + # Make the current buffer more visible + set-face global BufferSwitcherCurrent value +} + +bundle kakoune-focus "https://github.com/caksoylar/kakoune-focus" %{ + map global user ':focus-toggle' -docstring "toggle selections focus" +} + +bundle kakship https://github.com/eburghar/kakship %{ + kakship-enable +} +bundle-install-hook kakship %{ + cargo install --force --path . --root ~/.local + [ ! -e $kak_config/starship.toml ] && cp starship.toml $kak_config/ +} +bundle-cleaner kakship %{ + rm ~/.local/bin/kakship +} + +bundle popup.kak https://github.com/enricozb/popup.kak +bundle-install-hook popup.kak %{ + cargo install --force --path . +} +bundle-cleaner popup.kak %{ + cargo uninstall kak-popup +} + +bundle-customload kak-tree-sitter https://git.sr.ht/~hadronized/kak-tree-sitter %{ + evaluate-commands %sh{ kak-tree-sitter -dks --init $kak_session } +} +bundle-install-hook kak-tree-sitter %{ + cargo install --force --path ./kak-tree-sitter + cargo install --force --path ./ktsctl +} +bundle-cleaner kak-tree-sitter %{ + cargo uninstall kak-tree-sitter + cargo uninstall ktsctl +} + +bundle-noload kakeidoscope "git clone --recurse-submodules https://git.sr.ht/~orchid/kakeidoscope" +bundle-install-hook kakeidoscope %{ + cd src + make + mv kakeidoscope ~/.local/bin/ +} +bundle-cleaner kakeidoscope %{ + rm ~/.local/bin/kakeidoscope +} +bundle-updater kakeidoscope %{ + git pull --recurse-submodules +} + +bundle peneira https://github.com/gustavo-hms/peneira %{ + require-module peneira +} diff --git a/.config/kak/filetypes/go.kak b/.config/kak/filetypes/go.kak new file mode 100644 index 0000000..a3bc8e2 --- /dev/null +++ b/.config/kak/filetypes/go.kak @@ -0,0 +1,22 @@ +hook global WinSetOption filetype=go %{ + set-option buffer lsp_servers %{ + [gopls] + root_globs = ["go.mod", ".git", ".hg"] + command = "gopls" + [gopls.settings.gopls] + # See https://github.com/golang/tools/blob/master/gopls/doc/settings.md + # "build.buildFlags" = [] + gofumpt = true + hints.assignVariableTypes = true + hints.compositeLiteralFields = true + hints.compositeLiteralTypes = true + hints.constantValues = true + hints.functionTypeParameters = true + hints.parameterNames = true + hints.rangeVariableTypes = true + usePlaceholders = true + semanticTokens = true + } + lsp-enable-buffer + lsp-semantic-tokens-enable +} diff --git a/.config/kak/filetypes/kak.kak b/.config/kak/filetypes/kak.kak new file mode 100644 index 0000000..34a9579 --- /dev/null +++ b/.config/kak/filetypes/kak.kak @@ -0,0 +1,13 @@ +hook global WinSetOption filetype=kak %{ + softtab-enable +} + +hook global ModuleLoaded kak %@ + # toml highlighting for lsp_servers + require-module toml + try %~ + add-highlighter shared/kakrc/lsp_servers region -recurse '\{' '\blsp_servers\s+%\{' '\}' ref toml + ~ catch %$ + echo -debug "Error: kakrc: can't declare additional kakrc highlighters: %val{error}" + $ +@ diff --git a/.config/kak/filetypes/lua.kak b/.config/kak/filetypes/lua.kak new file mode 100644 index 0000000..f6ae202 --- /dev/null +++ b/.config/kak/filetypes/lua.kak @@ -0,0 +1,10 @@ +hook global WinSetOption filetype=lua %{ + set-option buffer lsp_servers %{ + [lua-language-server] + root_globs = [".luarc.json", ".git", ".hg"] + command = "lua-language-server" + } + lsp-semantic-tokens-enable + softtab-enable + lsp-enable-buffer +} diff --git a/.config/kak/filetypes/python.kak b/.config/kak/filetypes/python.kak new file mode 100644 index 0000000..0dddc0e --- /dev/null +++ b/.config/kak/filetypes/python.kak @@ -0,0 +1,22 @@ +hook global WinSetOption filetype=python %{ + set-option buffer lsp_servers %{ + [basedpyright] # pretty much a strict upgrade over vanilla pyright + root_globs = ["requirements.txt", "setup.py", "pyrightconfig.json", ".git", ".hg"] + command = "basedpyright-langserver" + args = ["--stdio"] + [ruff] + root_globs = ["requirements.txt", "setup.py", "pyrightconfig.json", ".git", ".hg"] + command = "ruff" + args = ["server", "--preview"] + } + lsp-enable-buffer + lsp-semantic-tokens-enable + softtab-enable +} + +hook global ModuleLoaded python %{ + # By default, Kakoune highlights the "import" and "from" keywords in the "meta" face. + # This is incorrect - they should be highlighted as keywords. + # So, we override the builtin highlighter with our own. + add-highlighter shared/python/code/ regex '\b(import|from)\b' 0:keyword +} diff --git a/.config/kak/filetypes/sh.kak b/.config/kak/filetypes/sh.kak new file mode 100644 index 0000000..3fdb2ac --- /dev/null +++ b/.config/kak/filetypes/sh.kak @@ -0,0 +1,3 @@ +hook global BufSetOption tree_sitter_lang=sh %{ + set-option buffer tree_sitter_lang bash +} diff --git a/.config/kak/filetypes/yaml.kak b/.config/kak/filetypes/yaml.kak new file mode 100644 index 0000000..8740ca4 --- /dev/null +++ b/.config/kak/filetypes/yaml.kak @@ -0,0 +1,5 @@ +hook global WinSetOption filetype=yaml %{ + set-option global tabstop 2 + set-option global indentwidth 2 + softtab +} diff --git a/.config/kak/kakrc b/.config/kak/kakrc new file mode 100644 index 0000000..500f244 --- /dev/null +++ b/.config/kak/kakrc @@ -0,0 +1,47 @@ +# Command for loading config files +# This helps to keep the config neat and tidy +define-command load -params 2 %{ + source "%val{config}/%arg{1}/%arg{2}.kak" +} + +# Plugins + +load config plugins + +# Additional syntaxes + +load syntaxes capnp +load syntaxes kdl +load syntaxes rainbow_csv +load syntaxes sshconfig + +# Utility commands + +load utils beacon +load utils whitespace + +# Tool integration + +load tools lazygit +load tools xplr + +# Colorscheme/options + +load config options + +# Mappings + +load config mappings + +# Filetype-specific configs + +load filetypes go +load filetypes kak +load filetypes lua +load filetypes python +load filetypes sh +load filetypes yaml + +# Local config (needs to come after everything else) + +load config local_config diff --git a/.config/kak/starship.toml b/.config/kak/starship.toml new file mode 100644 index 0000000..0459e04 --- /dev/null +++ b/.config/kak/starship.toml @@ -0,0 +1,175 @@ +add_newline = false +format = """\ +${custom.kaklsp_progress}\ +${custom.kaklsp_err}\ +${custom.kaklsp_warn}\ +${custom.kaklsp_hint}\ +${custom.kakcursor}\ +${custom.kakposition}\ +${custom.kakmode}\ +${custom.kakcontext}\ +$directory\ +${custom.kakfile}\ +${custom.kakfiletype}\ +${custom.kaklsp_code_actions}\ +$package\ +$git_branch\ +$git_commit\ +$git_state\ +$git_status\ +${custom.kaksession}""" + +[git_branch] +format = '[  $branch]($style)' +style = 'fg:bright-blue italic' +only_attached = false +always_show_remote = true +disabled = false + +[git_commit] +format = '[\($hash$tag\)]($style)' +style = 'fg:blue dimmed' +commit_hash_length = 7 +only_detached = false +tag_symbol = ' 笠' +tag_disabled = false +disabled = false + +[git_state] +format = '\( [$state($progress_current/$progress_total)]($style)\)' +style = 'fg:blue dimmed' +rebase = 'REBASING' +merge = 'MERGING' +revert = 'REVERTING' +cherry_pick = 'CHERRY-PICKING' +bisect = 'BISECTING' +am = 'AM' +am_or_rebase = 'AM/REBASE' +disabled = false + +[git_status] +format = '[\[$all_status$ahead_behind\]]($style)' +style = 'fg:cyan dimmed bold' +stashed = '\$' +ahead = '⇡${count}' +behind = '⇣${count}' +diverged = '⇕⇡${ahead_count}⇣${behind_count}' +conflicted = '=' +deleted = '✘' +renamed = '»' +modified = '!' +staged = '+' +untracked = '?' +disabled = false + +[directory] +format = '[$read_only]($read_only_style)[ $path]($style)' +truncation_length = 3 +truncate_to_repo = false +fish_style_pwd_dir_length = 0 +use_logical_path = true +style = 'bg:blue fg:black' +read_only_style = 'bg:blue fg:200' +read_only = '[]' +truncation_symbol = '…' +disabled = false + +[directory.substitutions] +"~/.config" = " " +"~/workspace" = " " +"~" = " " + +[custom.kakfile] +description = 'The current Kakoune buffername' +format = '[/$output ]($style)' +style = 'bold bg:blue fg:black' +command = 'printf ${kak_buffile##*/}' +when = 'true' +shell = ['sh'] +disabled = false + +[custom.kaksession] +description = 'The current Kakoune session' +format = '($style)[  %val{client}:%val{session} ]($style)' +style = 'bg:yellow fg:black italic' +when = '' +shell = ['true'] +disabled = false + +[custom.kakcursor] +description = 'The current Kakoune cursor position' +format = '[%val{cursor_line}:%val{cursor_char_column}]($style)' +style = 'fg:white' +when = '' +shell = ['true'] +disabled = false + +[custom.kakmode] +description = 'The current Kakoune mode' +format = ' {{mode_info}}' +when = '' +shell = ['true'] +disabled = false + +[custom.kakcontext] +description = 'The current Kakoune context' +format = ' {{context_info}}' +when = '' +shell = ['true'] +disabled = false + +[custom.kakfiletype] +description = 'The current buffer filetype' +format = ' \[%opt{filetype}\] ' +when = '' +shell = ['true'] +disabled = false + +[custom.kakposition] +description = 'Relative position of the cursor inside the buffer' +format = '[ $output]($style)' +style = 'white' +command = 'printf $(($kak_cursor_line * 100 / $kak_buf_line_count))%' +when = '[ -n "$kak_cursor_line" ]' +shell = ['sh'] +disabled = false + +[custom.kaklsp_err] +description = "Show errors number from kak-lsp if any" +format = "[  %opt{lsp_diagnostic_error_count}]($style)" +style = "red bold" +when = '[ -n "$kak_opt_lsp_diagnostic_error_count" -a "$kak_opt_lsp_diagnostic_error_count" -ne 0 ]' +shell = ['sh'] +disabled = false + +[custom.kaklsp_warn] +description = "Show warnings number from kak-lsp if any" +format = "[  %opt{lsp_diagnostic_warning_count}]($style)" +style = "yellow bold" +when = '[ -n "$kak_opt_lsp_diagnostic_warning_count" -a "$kak_opt_lsp_diagnostic_warning_count" -ne 0 ]' +shell = ['sh'] +disabled = false + +[custom.kaklsp_hint] +description = "Show hints number from kak-lsp if any" +format = "[ ﯦ %opt{lsp_diagnostic_hint_count}]($style)" +style = "white bold" +when = '[ -n "$kak_opt_lsp_diagnostic_hint_count" -a "$kak_opt_lsp_diagnostic_hint_count" -ne 0 ]' +shell = ['sh'] +disabled = false + +[custom.kaklsp_code_actions] +description = "Show lsp code actions" +format = "[ %opt{lsp_modeline_code_actions} ]($style)" +style = "yellow bold" +when = '[ -n "$kak_opt_lsp_modeline_code_actions" ]' +shell = ['sh'] +disabled = false + +[custom.kaklsp_progress] +description = "Show activity of kak-lsp if any" +format = "[ ]($style)" +style = "bright-white bold" +when = '[ -n "$kak_opt_lsp_modeline_progress" ]' +shell = ['sh'] +disabled = false diff --git a/.config/kak/syntaxes/capnp.kak b/.config/kak/syntaxes/capnp.kak new file mode 100644 index 0000000..089a6e1 --- /dev/null +++ b/.config/kak/syntaxes/capnp.kak @@ -0,0 +1,90 @@ +# https://capnproto.org/ + +hook global BufCreate .*[.](capnp) %{ + set-option buffer filetype capnp +} + +# Initialization +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +hook global WinSetOption filetype=capnp %{ + require-module capnp + + set-option window static_words %opt{capnp_static_words} + + hook window ModeChange pop:insert:.* -group capnp-trim-indent capnp-trim-indent + hook window InsertChar .* -group capnp-indent capnp-indent-on-char + hook window InsertChar \n -group capnp-indent capnp-indent-on-new-line + + hook -once -always window WinSetOption filetype=.* %{ remove-hooks window capnp-.+ } +} + +hook -group capnp-highlight global WinSetOption filetype=capnp %{ + add-highlighter window/capnp ref capnp + hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/capnp } +} + +provide-module capnp %@ + +# Highlighters +# ‾‾‾‾‾‾‾‾‾‾‾‾ + +add-highlighter shared/capnp regions +add-highlighter shared/capnp/code default-region group + +add-highlighter shared/capnp/line_comment region '#' '$' fill comment +add-highlighter shared/capnp/string region '"' (? d } +} + +define-command -hidden capnp-indent-on-char %< + evaluate-commands -draft -itersel %< + # align closer token to its opener when alone on a line + try %< execute-keys -draft ^\h+[\]}]$ m 1 > + > +> + +define-command -hidden capnp-indent-on-new-line %< + evaluate-commands -draft -itersel %< + # preserve previous line indent + try %{ execute-keys -draft K } + # filter previous line + try %{ execute-keys -draft k : capnp-trim-indent } + # indent after lines ending with opener token + try %< execute-keys -draft k x [[{]\h*$ j > + # deindent closer token(s) when after cursor + try %< execute-keys -draft x ^\h*[}\]] gh / [}\]] m 1 > + > +> + +@ diff --git a/.config/kak/syntaxes/kdl.kak b/.config/kak/syntaxes/kdl.kak new file mode 100644 index 0000000..d4a0266 --- /dev/null +++ b/.config/kak/syntaxes/kdl.kak @@ -0,0 +1,97 @@ +# https://kdl.dev + +hook global BufCreate .*[.](kdl) %{ + set-option buffer filetype kdl +} + +# Initialization +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +hook global WinSetOption filetype=kdl %{ + require-module kdl + + hook window ModeChange pop:insert:.* -group kdl-trim-indent kdl-trim-indent + hook window InsertChar .* -group kdl-indent kdl-indent-on-char + hook window InsertChar \n -group kdl-indent kdl-indent-on-new-line + + hook -once -always window WinSetOption filetype=.* %{ remove-hooks window kdl-.+ } +} + +hook -group kdl-highlight global WinSetOption filetype=kdl %{ + add-highlighter window/kdl ref kdl + hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/kdl } +} + +provide-module kdl %@ + +# Highlighters +# ‾‾‾‾‾‾‾‾‾‾‾‾ + +add-highlighter shared/kdl regions +add-highlighter shared/kdl/code default-region group + +add-highlighter shared/kdl/raw_string region -match-capture 'r(#*)"' '"(#*)' fill string + +add-highlighter shared/kdl/string region '"' (? d } +} + +define-command -hidden kdl-indent-on-char %< + evaluate-commands -draft -itersel %< + # align closer token to its opener when alone on a line + try %< execute-keys -draft ^\h+[\]}]$ m 1 > + > +> + +define-command -hidden kdl-indent-on-new-line %< + evaluate-commands -draft -itersel %< + # preserve previous line indent + try %{ execute-keys -draft K } + # filter previous line + try %{ execute-keys -draft k : kdl-trim-indent } + # indent after lines ending with opener token + try %< execute-keys -draft k x [[{]\h*$ j > + # deindent closer token(s) when after cursor + try %< execute-keys -draft x ^\h*[}\]] gh / [}\]] m 1 > + > +> + +@ diff --git a/.config/kak/syntaxes/rainbow_csv.kak b/.config/kak/syntaxes/rainbow_csv.kak new file mode 100644 index 0000000..9147fa1 --- /dev/null +++ b/.config/kak/syntaxes/rainbow_csv.kak @@ -0,0 +1,32 @@ +# Opinionated rainbow csv implementation + +hook global BufCreate .*[.](csv) %{ + set-option buffer filetype csv +} + +hook global WinSetOption filetype=csv %{ + try %{ + remove-highlighter window/csv + } + lua %{ + rgx = "(^[^\n,]*[,$])?" + -- These colors are designed to match the Everforest Dark colorscheme. + colors = {"blue", "green", "magenta", "rgb:e69875"} + faces = {} + for idx, color in pairs(colors) do + if idx > 1 then + rgx = rgx .. "([^\n,]*[,$])?" + end + faces[idx] = idx .. ":" .. color + end + kak.add_highlighter("window/csv", "regions") + kak.add_highlighter("window/csv/comment", "region", "^", "\n", "group") + kak.add_highlighter("window/csv/comment/", "regex", rgx, table.unpack(faces)) + } +} + +hook global WinSetOption filetype=(?!csv).* %{ + try %{ + remove-highlighter window/csv + } +} diff --git a/.config/kak/syntaxes/sshconfig.kak b/.config/kak/syntaxes/sshconfig.kak new file mode 100644 index 0000000..46da8d8 --- /dev/null +++ b/.config/kak/syntaxes/sshconfig.kak @@ -0,0 +1,116 @@ +hook global BufCreate .*/\.ssh/config %{ + set-option buffer filetype ssh +} + +# Initialization +# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +hook global WinSetOption filetype=ssh %{ + require-module ssh + + set-option window static_words %opt{ssh_static_words} + + hook window InsertChar \n -group ssh-insert ssh-insert-on-new-line + hook window InsertChar \n -group ssh-indent ssh-indent-on-new-line + + hook -once -always window WinSetOption filetype=.* %{ remove-hooks window ssh-.+ } +} + +hook -group ssh-highlight global WinSetOption filetype=ssh %{ + add-highlighter window/ssh ref ssh + hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/ssh } +} + +provide-module ssh %@ + +# Highlighters +# ‾‾‾‾‾‾‾‾‾‾‾‾ + +add-highlighter shared/ssh regions +add-highlighter shared/ssh/code default-region group + +add-highlighter shared/ssh/double_string region %{(? + try %{ + evaluate-commands -draft -save-regs '/"' %{ + # Ensure previous line is a comment + execute-keys -draft kxs^\h*#+\h* + + # now handle the coment continuation logic + try %{ + # try and match a regular block comment, copying the prefix + execute-keys -draft -save-regs '' k x 1s^(\h*#+\h*)\S.*$ y + execute-keys -draft P + } catch %{ + try %{ + # try and match a regular block comment followed by a single + # empty comment line + execute-keys -draft -save-regs '' kKx 1s^(\h*#+\h*)\S+\n\h*#+\h*$ y + execute-keys -draft P + } catch %{ + try %{ + # try and match a pair of empty comment lines, and delete + # them if we match + execute-keys -draft kKx ^\h*#+\h*\n\h*#+\h*$ + } catch %{ + # finally, we need a special case for a new line inserted + # into a file that consists of a single empty comment - in + # that case we can't expect to copy the trailing whitespace, + # so we add our own + execute-keys -draft -save-regs '' k x1s^(\h*#+)\h*$ y + execute-keys -draft P + execute-keys -draft i + } + } + } + } + + # trim trailing whitespace on the previous line + try %{ execute-keys -draft k x s\h+$ d } + } +} } + +define-command -hidden ssh-indent-on-new-line %< + evaluate-commands -draft -itersel %< + # preserve previous line indent + try %{ execute-keys -draft K } + # cleanup trailing whitespaces from previous line + try %{ execute-keys -draft k x s \h+$ d } + > +> + +@ diff --git a/.config/kak/tools/lazygit.kak b/.config/kak/tools/lazygit.kak new file mode 100644 index 0000000..3a78a65 --- /dev/null +++ b/.config/kak/tools/lazygit.kak @@ -0,0 +1,7 @@ +# https://github.com/jesseduffield/lazygit + +define-command lazygit %{ + popup lazygit +} + +alias global lg lazygit diff --git a/.config/kak/tools/xplr.kak b/.config/kak/tools/xplr.kak new file mode 100644 index 0000000..033e966 --- /dev/null +++ b/.config/kak/tools/xplr.kak @@ -0,0 +1,21 @@ +# https://xplr.dev/ +# Seriously, xplr is awesome. Get it if you haven't already. + +define-command xplr-open -params 1 %{ + evaluate-commands %sh{ + for xplr_file in $1; do + if [ -f "$xplr_file" ]; then + printf "%s\n" "edit $xplr_file" + fi + done + } +} -hidden + +define-command xplr -params ..1 %{ + popup --title open --kak-script %{ xplr-open %opt{popup_output} } -- xplr %arg{@} +} + +# Utility command to edit a kak config file with xplr +define-command edit-config %{ + xplr %val{config} +} diff --git a/.config/kak/utils/beacon.kak b/.config/kak/utils/beacon.kak new file mode 100644 index 0000000..be9a2f4 --- /dev/null +++ b/.config/kak/utils/beacon.kak @@ -0,0 +1,87 @@ +# This script flashes the current line when the cursor moves or the window is focused, +# to help highlight where the cursor is. +# Heavily inspired by the Beacon.nvim plugin: https://github.com/DanilaMihailov/beacon.nvim + +declare-option str beacon_final_bg "5c6a72" +declare-option str beacon_refresh_interval "0.03" +declare-option -hidden str beacon_transition + +declare-option -hidden str beacon_keys_normal " ( ) m M n N u U" +declare-option -hidden str beacon_keys_goto "g k j e ." + +lua %opt{beacon_final_bg} %{ + bg = tonumber(arg[1], 16) + colors = "" + + -- Split the background into individual bytes. + -- This will help ensure a smooth transition. + bg_left = bg >> 16 + bg_center = (bg >> 8) & 0xFF + bg_right = bg & 0xFF + + while true do + bg_left = bg_left + 0x11 + if bg_left > 0xFF then + break + end + + -- Prevent the center bytes and rightmost bytes from "overflowing" + -- and yielding an overall red color (which would look bad) + bg_center = bg_center + 0x11 + if bg_center > 0xFF then + bg_center = 0xFF + end + + bg_right = bg_right + 0x11 + if bg_right > 0xFF then + bg_right = 0xFF + end + + bg = bg_right + (bg_center << 8) + (bg_left << 16) + colors = "rgb:" .. string.format("%X", bg) .. " " .. colors + end + + kak.set_option("global", "beacon_transition", colors) +} + +define-command beacon %{ + # Since this requires running kak commands at a set time rather than all at the end, + # using %sh{} instead of %lua{} is better here. + nop %sh{ + ( + printf "%s\n" "evaluate-commands -client $kak_client %{ try %{ + add-highlighter buffer/beacon group + }}" | kak -p $kak_session + + for color in $kak_opt_beacon_transition; do + printf "%s\n" " + evaluate-commands -client $kak_client %{ + evaluate-commands -draft %{ + execute-keys x + declare-option range-specs beacon_range %val{timestamp} \"%val{selection_desc}|default,$color\" + } + try %{ add-highlighter buffer/beacon/$color ranges beacon_range } + }" | kak -p $kak_session + sleep $kak_opt_beacon_refresh_interval + done + + printf "%s\n" "evaluate-commands -client $kak_client %{ + try %{ remove-highlighter buffer/beacon } + }" | kak -p $kak_session + ) >/dev/null 2>&1 ") + end + for key in string.gmatch(arg[2], "[^%s]+") do + kak.map("window", "goto", key, key .. ":beacon") + end + } + hook window RawKey '' beacon +} diff --git a/.config/kak/utils/whitespace.kak b/.config/kak/utils/whitespace.kak new file mode 100644 index 0000000..5fb70c7 --- /dev/null +++ b/.config/kak/utils/whitespace.kak @@ -0,0 +1,22 @@ +add-highlighter global/indent show-whitespaces -tab "│" -indent "│" -spc " " -lf " " + +define-command softtab-enable %{ + hook buffer InsertChar \t %{ try %{ + execute-keys -draft "h\A\h+\z;%opt{indentwidth}@" + }} + + hook buffer InsertDelete ' ' %{ try %{ + execute-keys -draft 'h\A\h+\zi' + }} +} + +define-command toggle-whitespace %{ + try %{ + add-highlighter global/whitespaces show-whitespaces + remove-highlighter global/indent + } catch %{ + remove-highlighter global/whitespaces + add-highlighter global/indent show-whitespaces -tab "│" -indent "│" -spc " " -lf " " + } +} + diff --git a/.config/lazygit/config.yml b/.config/lazygit/config.yml new file mode 100644 index 0000000..9285640 --- /dev/null +++ b/.config/lazygit/config.yml @@ -0,0 +1,95 @@ +# Config relating to the Lazygit UI +gui: + # Nerd fonts version to use. + # One of: '2' | '3' | empty string (default) + # If empty, do not show icons. + nerdFontsVersion: "3" + + # If true (default), file icons are shown in the file views. Only relevant if NerdFontsVersion is not empty. + showFileIcons: true + + # Config relating to the spinner. + spinner: + # The frames of the spinner animation. + frames: + - '|' + - / + - '—' + - \ + + # The "speed" of the spinner in milliseconds. + rate: 50 + + # Config relating to colors and styles. + # See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#color-attributes + theme: + # Border color of focused window + activeBorderColor: + - magenta + - bold + + # Border color of non-focused windows + inactiveBorderColor: + - white + + # Border color of focused window when searching in that window + searchingActiveBorderColor: + - green + - bold + + # Color of keybindings help text in the bottom line + optionsTextColor: + - blue + + # Background color of selected line. + # See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#highlighting-the-selected-line + selectedLineBgColor: + - blue + + # Background color of selected line when view doesn't have focus. + inactiveViewSelectedLineBgColor: + - bold + + # Foreground color of copied commit + cherryPickedCommitFgColor: + - blue + + # Background color of copied commit + cherryPickedCommitBgColor: + - cyan + + # Foreground color of marked base commit (for rebase) + markedBaseCommitFgColor: + - blue + + # Background color of marked base commit (for rebase) + markedBaseCommitBgColor: + - yellow + + # Color for file with unstaged changes + unstagedChangesColor: + - red + + # Default text color + defaultFgColor: + - default + + # Window border style. + # One of 'rounded' (default) | 'single' | 'double' | 'hidden' + border: double + +# Config relating to things outside of Lazygit like how files are opened, copying to clipboard, etc +os: + # Command for editing a file. Should contain "{{filename}}". + edit: "kak \"{{filename}}\"" + + # Command for editing a file at a given line number. Should contain + # "{{filename}}", and may optionally contain "{{line}}". + editAtLine: "kak \"{{filename}}\" -e \"execute-keys '{{line}}g'\"" + +# What to do when opening Lazygit outside of a git repo. +# - 'prompt': (default) ask whether to initialize a new repo or open in the most recent repo +# - 'create': initialize a new repo +# - 'skip': open most recent repo +# - 'quit': exit Lazygit +notARepository: quit diff --git a/.config/wezterm/colors/sonokai_andromeda.toml b/.config/wezterm/colors/sonokai_andromeda.toml new file mode 100644 index 0000000..97a1d12 --- /dev/null +++ b/.config/wezterm/colors/sonokai_andromeda.toml @@ -0,0 +1,33 @@ +[colors] +foreground = "#e1e3e4" +background = "#2b2d3a" +selection_bg = "#3a3e4e" +selection_fg = "#c0caf5" +cursor_fg = "#2b2d3a" +cursor_bg = "#e1e3e4" +cursor_border = "#e1e3e4" + +ansi = ["#181a1c","#fb617e","#9ed06c","#f0c362","#6dcae8","#bb97ee","#f89860","#e1e3e4"] +brights = ["#7e8294","#fb617e","#9ed06c","#f0c362","#6dcae8","#bb97ee","#f89860","#e1e3e4"] + +[colors.tab_bar] +inactive_tab_edge = "#e1e3e4" +background = "#2b2d3a" + +[colors.tab_bar.inactive_tab] +fg_color = "#e1e3e4" +bg_color = "#7e8294" + +[colors.tab_bar.inactive_tab_hover] +fg_color = "#e1e3e4" +bg_color = "#7e8294" + +[colors.tab_bar.active_tab] +fg_color = "#7e8294" +bg_color = "#e1e3e4" +intensity = "Bold" + +[metadata] +aliases = [] +author = "jdugan" +name = "sonokai_andromeda" diff --git a/.config/wezterm/config/appearance.lua b/.config/wezterm/config/appearance.lua new file mode 100644 index 0000000..91c33ba --- /dev/null +++ b/.config/wezterm/config/appearance.lua @@ -0,0 +1,34 @@ +local wezterm = require("wezterm") + +local config = {} + +-- color scheme +config.color_scheme = "Everforest Dark Soft (Gogh)" +-- font +config.font = wezterm.font("Fantasque Sans Mono") +config.font_size = 14.0 +-- Ligatures in terminal/programming fonts IMO are a bad idea, +-- as they require the user to mentally translate what the ligature represents, +-- and in some cases, they misrepresent code semantics due to ligature substitution +-- being a dumb search/replace regardless of the context. +-- != isn't the not equal to operator in Lua for instance (that would be ~=), +-- but ligature fonts will render it as ≠ regardless, even in a string literal. +-- Even worse, some fonts also render <= and =< both as ≤, since there are languages +-- that use one or the other, even though only one is correct for any given language, +-- causing unnecessary ambiguity. +-- It's not a big deal, ultimately, but disabling ligatures avoids the above problems. +config.harfbuzz_features = { "calt=0", "clig=0", "liga=0" } +-- tab bar +config.show_new_tab_button_in_tab_bar = false +config.use_fancy_tab_bar = false +-- graphics +config.front_end = "WebGpu" +-- inactive panes +config.inactive_pane_hsb = { + saturation = 0.9, + brightness = 0.5 +} +-- scrollbar +config.enable_scroll_bar = true + +return config diff --git a/.config/wezterm/config/bindings.lua b/.config/wezterm/config/bindings.lua new file mode 100644 index 0000000..ee12f62 --- /dev/null +++ b/.config/wezterm/config/bindings.lua @@ -0,0 +1,127 @@ +local wezterm = require("wezterm") +local act = wezterm.action + +local keys = { + -- Tab Management + { key = "T", mods = "SHIFT|CTRL", action = act.SpawnTab "CurrentPaneDomain" }, + { + key = "T", + mods = "SHIFT|ALT", + action = act.PromptInputLine { + description = 'Enter new name for tab', + action = wezterm.action_callback(function(window, _, line) + if line then + window:active_tab():set_title(line) + end + end) + } + }, + { key = "W", mods = "SHIFT|CTRL", action = act.CloseCurrentTab { confirm = true } }, + { key = "LeftArrow", mods = "ALT", action = act.ActivateTabRelative(-1) }, + { key = "LeftArrow", mods = "SHIFT|ALT", action = act.MoveTabRelative(-1) }, + { key = "RightArrow", mods = "ALT", action = act.ActivateTabRelative(1) }, + { key = "RightArrow", mods = "SHIFT|ALT", action = act.MoveTabRelative(1) }, + -- Pane Management + { key = "-", mods = "CTRL|ALT", action = act.SplitVertical { domain = "CurrentPaneDomain" } }, + { key = "\\", mods = "CTRL|ALT", action = act.SplitHorizontal { domain = "CurrentPaneDomain" } }, + { key = "LeftArrow", mods = "CTRL", action = act.ActivatePaneDirection "Left" }, + { key = "LeftArrow", mods = "CTRL|SHIFT", action = act.AdjustPaneSize { "Left", 1 } }, + { key = "RightArrow", mods = "CTRL", action = act.ActivatePaneDirection "Right" }, + { key = "RightArrow", mods = "CTRL|SHIFT", action = act.AdjustPaneSize { "Right", 1 } }, + { key = "UpArrow", mods = "CTRL", action = act.ActivatePaneDirection "Up" }, + { key = "UpArrow", mods = "CTRL|SHIFT", action = act.AdjustPaneSize { "Up", 1 } }, + { key = "DownArrow", mods = "CTRL", action = act.ActivatePaneDirection "Down" }, + { key = "DownArrow", mods = "CTRL|SHIFT", action = act.AdjustPaneSize { "Down", 1 } }, + -- Default Actions + { key = "_", mods = "SHIFT|CTRL", action = act.DecreaseFontSize }, + { key = "+", mods = "SHIFT|CTRL", action = act.IncreaseFontSize }, + { key = "C", mods = "SHIFT|CTRL", action = act.CopyTo "Clipboard" }, + { key = "F", mods = "SHIFT|CTRL", action = act.Search "CurrentSelectionOrEmptyString" }, + { key = "K", mods = "SHIFT|CTRL", action = act.ClearScrollback "ScrollbackOnly" }, + { key = "L", mods = "SHIFT|CTRL", action = act.ShowDebugOverlay }, + { key = "R", mods = "SHIFT|CTRL", action = act.ReloadConfiguration }, + { key = "V", mods = "SHIFT|CTRL", action = act.PasteFrom "Clipboard" }, + { key = "X", mods = "SHIFT|CTRL", action = act.ActivateCopyMode }, + { key = "Z", mods = "SHIFT|CTRL", action = act.TogglePaneZoomState }, + { key = "phys:Space", mods = "SHIFT|CTRL", action = act.QuickSelect }, + { key = "PageUp", mods = "SHIFT", action = act.ScrollByPage(-1) }, + { key = "PageDown", mods = "SHIFT", action = act.ScrollByPage(1) }, + { key = "Insert", mods = "SHIFT", action = act.PasteFrom "PrimarySelection" }, + { key = "Insert", mods = "CTRL", action = act.CopyTo "PrimarySelection" }, + { key = "Copy", mods = "NONE", action = act.CopyTo "Clipboard" }, + { key = "Paste", mods = "NONE", action = act.PasteFrom "Clipboard" }, +} + +local key_tables = { + copy_mode = { + { key = "Tab", mods = "NONE", action = act.CopyMode "MoveForwardWord" }, + { key = "Tab", mods = "SHIFT", action = act.CopyMode "MoveBackwardWord" }, + { key = "Enter", mods = "NONE", action = act.CopyMode "MoveToStartOfNextLine" }, + { key = "Escape", mods = "NONE", action = act.CopyMode "Close" }, + { key = "Space", mods = "NONE", action = act.CopyMode { SetSelectionMode = "Cell" } }, + { key = "$", mods = "NONE", action = act.CopyMode "MoveToEndOfLineContent" }, + { key = "$", mods = "SHIFT", action = act.CopyMode "MoveToEndOfLineContent" }, + { key = "0", mods = "NONE", action = act.CopyMode "MoveToStartOfLine" }, + { key = "G", mods = "NONE", action = act.CopyMode "MoveToScrollbackBottom" }, + { key = "G", mods = "SHIFT", action = act.CopyMode "MoveToScrollbackBottom" }, + { key = "H", mods = "NONE", action = act.CopyMode "MoveToViewportTop" }, + { key = "H", mods = "SHIFT", action = act.CopyMode "MoveToViewportTop" }, + { key = "L", mods = "NONE", action = act.CopyMode "MoveToViewportBottom" }, + { key = "L", mods = "SHIFT", action = act.CopyMode "MoveToViewportBottom" }, + { key = "M", mods = "NONE", action = act.CopyMode "MoveToViewportMiddle" }, + { key = "M", mods = "SHIFT", action = act.CopyMode "MoveToViewportMiddle" }, + { key = "O", mods = "NONE", action = act.CopyMode "MoveToSelectionOtherEndHoriz" }, + { key = "O", mods = "SHIFT", action = act.CopyMode "MoveToSelectionOtherEndHoriz" }, + { key = "V", mods = "NONE", action = act.CopyMode { SetSelectionMode = "Line" } }, + { key = "V", mods = "SHIFT", action = act.CopyMode { SetSelectionMode = "Line" } }, + { key = "^", mods = "NONE", action = act.CopyMode "MoveToStartOfLineContent" }, + { key = "^", mods = "SHIFT", action = act.CopyMode "MoveToStartOfLineContent" }, + { key = "b", mods = "NONE", action = act.CopyMode "MoveBackwardWord" }, + { key = "b", mods = "ALT", action = act.CopyMode "MoveBackwardWord" }, + { key = "b", mods = "CTRL", action = act.CopyMode "PageUp" }, + { key = "c", mods = "CTRL", action = act.CopyMode "Close" }, + { key = "f", mods = "ALT", action = act.CopyMode "MoveForwardWord" }, + { key = "f", mods = "CTRL", action = act.CopyMode "PageDown" }, + { key = "g", mods = "NONE", action = act.CopyMode "MoveToScrollbackTop" }, + { key = "g", mods = "CTRL", action = act.CopyMode "Close" }, + { key = "h", mods = "NONE", action = act.CopyMode "MoveLeft" }, + { key = "j", mods = "NONE", action = act.CopyMode "MoveDown" }, + { key = "k", mods = "NONE", action = act.CopyMode "MoveUp" }, + { key = "l", mods = "NONE", action = act.CopyMode "MoveRight" }, + { key = "m", mods = "ALT", action = act.CopyMode "MoveToStartOfLineContent" }, + { key = "o", mods = "NONE", action = act.CopyMode "MoveToSelectionOtherEnd" }, + { key = "q", mods = "NONE", action = act.CopyMode "Close" }, + { key = "v", mods = "NONE", action = act.CopyMode { SetSelectionMode = "Cell" } }, + { key = "v", mods = "CTRL", action = act.CopyMode { SetSelectionMode = "Block" } }, + { key = "w", mods = "NONE", action = act.CopyMode "MoveForwardWord" }, + { key = "y", mods = "NONE", action = act.Multiple { { CopyTo = "ClipboardAndPrimarySelection" }, { CopyMode = "Close" } } }, + { key = "PageUp", mods = "NONE", action = act.CopyMode "PageUp" }, + { key = "PageDown", mods = "NONE", action = act.CopyMode "PageDown" }, + { key = "LeftArrow", mods = "NONE", action = act.CopyMode "MoveLeft" }, + { key = "LeftArrow", mods = "ALT", action = act.CopyMode "MoveBackwardWord" }, + { key = "RightArrow", mods = "NONE", action = act.CopyMode "MoveRight" }, + { key = "RightArrow", mods = "ALT", action = act.CopyMode "MoveForwardWord" }, + { key = "UpArrow", mods = "NONE", action = act.CopyMode "MoveUp" }, + { key = "DownArrow", mods = "NONE", action = act.CopyMode "MoveDown" }, + }, + + search_mode = { + { key = "Enter", mods = "NONE", action = act.CopyMode "PriorMatch" }, + { key = "Escape", mods = "NONE", action = act.CopyMode "Close" }, + { key = "n", mods = "CTRL", action = act.CopyMode "NextMatch" }, + { key = "p", mods = "CTRL", action = act.CopyMode "PriorMatch" }, + { key = "r", mods = "CTRL", action = act.CopyMode "CycleMatchType" }, + { key = "u", mods = "CTRL", action = act.CopyMode "ClearPattern" }, + { key = "PageUp", mods = "NONE", action = act.CopyMode "PriorMatchPage" }, + { key = "PageDown", mods = "NONE", action = act.CopyMode "NextMatchPage" }, + { key = "UpArrow", mods = "NONE", action = act.CopyMode "PriorMatch" }, + { key = "DownArrow", mods = "NONE", action = act.CopyMode "NextMatch" }, + } +} + +local config = {} +config.keys = keys +config.disable_default_key_bindings = true +config.key_tables = key_tables + +return config diff --git a/.config/wezterm/config/general.lua b/.config/wezterm/config/general.lua new file mode 100644 index 0000000..7fd70ac --- /dev/null +++ b/.config/wezterm/config/general.lua @@ -0,0 +1,11 @@ +local config = {} + +config.audible_bell = "Disabled" +config.ssh_backend = "LibSsh" +config.check_for_updates = false +config.exit_behavior = 'Close' +config.exit_behavior_messaging = 'Verbose' +config.status_update_interval = 25 +config.default_prog = { '/usr/local/bin/hilbish', '-l' } + +return config diff --git a/.config/wezterm/config/init.lua b/.config/wezterm/config/init.lua new file mode 100644 index 0000000..9058104 --- /dev/null +++ b/.config/wezterm/config/init.lua @@ -0,0 +1,8 @@ +local util = require "util" + +local config = {} +util.merge_tables(config, require("config.appearance")) +util.merge_tables(config, require("config.bindings")) +util.merge_tables(config, require("config.general")) + +return config diff --git a/.config/wezterm/events/format_tab_title.lua b/.config/wezterm/events/format_tab_title.lua new file mode 100644 index 0000000..897929f --- /dev/null +++ b/.config/wezterm/events/format_tab_title.lua @@ -0,0 +1,54 @@ +local wezterm = require("wezterm") +local util = require("util") + +local scheme = util.get_schemes()["Everforest Dark Soft (Gogh)"] + +local function tab_title(tab_info) + local title = tab_info.tab_title + -- if the tab title is explicitly set, take that + if title and #title > 0 then + return title + end + -- Otherwise, use the title from the active pane + -- in that tab + return tab_info.active_pane.title +end + +wezterm.on( + "format-tab-title", + function(tab, _, _, _, hover, max_width) + local LEFT_CIRCLE = "" + local RIGHT_CIRCLE = "" + + local edge_background = scheme.background + local background = scheme.brights[1] + local foreground = scheme.brights[8] + + -- ensure that the titles fit in the available space, + -- and that we have room for the edges. + local title = tab_title(tab) + title = wezterm.truncate_right(title, max_width - 2) + + if tab.is_active then + background = scheme.ansi[8] + foreground = scheme.ansi[1] + elseif hover then + background = scheme.brights[1] + foreground = scheme.brights[8] + end + + local edge_foreground = background + + return { + { Background = { Color = edge_background } }, + { Foreground = { Color = edge_foreground } }, + { Text = LEFT_CIRCLE }, + { Background = { Color = background } }, + { Foreground = { Color = foreground } }, + { Text = title }, + { Background = { Color = edge_background } }, + { Foreground = { Color = edge_foreground } }, + { Text = RIGHT_CIRCLE }, + } + end +) diff --git a/.config/wezterm/events/update_status.lua b/.config/wezterm/events/update_status.lua new file mode 100644 index 0000000..07d2a32 --- /dev/null +++ b/.config/wezterm/events/update_status.lua @@ -0,0 +1,56 @@ +local wezterm = require("wezterm") +local util = require("util") + +local scheme = util.get_schemes()["Everforest Dark Soft (Gogh)"] + +wezterm.on("update-status", function(window, pane) + local right_status = {} + + -- modes + local modes = { + copy_mode = { text = " 󰆏 COPY ", bg = scheme.brights[3] }, + search_mode = { text = " 󰍉 SEARCH ", bg = scheme.brights[4] } + } + local name = window:active_key_table() + local mode_fmt = {} + if name and modes[name] then + mode_fmt = modes[name] + table.insert(right_status, { Background = { Color = mode_fmt["bg"] } }) + table.insert(right_status, { Foreground = { Color = scheme.ansi[1] } }) + table.insert(right_status, { Attribute = { Intensity = "Bold" } }) + table.insert(right_status, { Attribute = { Italic = true } }) + table.insert(right_status, { Text = mode_fmt["text"] }) + end + + -- cwd + local cwd = pane:get_current_working_dir() + local cwd_path = "" + if cwd then + cwd_path = cwd.file_path + end + + local home_dir = os.getenv("HOME") + + local config_dir = os.getenv("XDG_CONFIG_HOME") or home_dir .. "/.config" + if cwd_path:find(config_dir, 1, true) == 1 then + cwd_path = string.gsub(cwd_path, config_dir, "  ") + end + + local dev_dir = home_dir .. "/workspace" + if cwd_path:find(dev_dir, 1, true) == 1 then + cwd_path = string.gsub(cwd_path, dev_dir, "  ") + end + + if home_dir and cwd_path:find(home_dir, 1, true) == 1 then + cwd_path = string.gsub(cwd_path, home_dir, "  ") + end + + table.insert(right_status, "ResetAttributes") + table.insert(right_status, { Background = { Color = scheme.ansi[8] } }) + table.insert(right_status, { Foreground = { Color = scheme.ansi[1] } }) + table.insert(right_status, { Attribute = { Intensity = "Bold" } }) + table.insert(right_status, { Text = cwd_path }) + + + window:set_right_status(wezterm.format(right_status)) +end) diff --git a/.config/wezterm/types/color.lua b/.config/wezterm/types/color.lua new file mode 100644 index 0000000..447a614 --- /dev/null +++ b/.config/wezterm/types/color.lua @@ -0,0 +1,48 @@ +---@meta + +local color = {} + +---@param filename string +---@param params? { fuzziness: number, num_colors: number, max_width: number, max_height: number, min_brightness: number, max_brightness: number, threshold: number, min_contrast: number } +function color.extract_colors_from_image(filename, params) end + +---@param h string | number +---@param s string | number +---@param l string | number +---@param a string | number +---@return _.wezterm.Color +function color.from_hsla(h, s, l, a) end + +---@return table +function color.get_builtin_schemes() end + +---@return _.wezterm.Palette +function color.get_default_colors() end + +---@param gradient _.wezterm.Gradient +---@param num_colors number +---@return _.wezterm.Color[] +function color.gradient(gradient, num_colors) end + +---@param file_name string +---@return _.wezterm.Palette, _.wezterm.ColorSchemeMetaData +function color.load_base16_scheme(file_name) end + +---@param file_name string +---@return _.wezterm.Palette, _.wezterm.ColorSchemeMetaData +function color.load_scheme(file_name) end + +---@param file_name string +---@return _.wezterm.Palette, _.wezterm.ColorSchemeMetaData +function color.load_terminal_sexy_scheme(file_name) end + +---@param string string +---@return _.wezterm.Color +function color.parse(string) end + +---@param colors _.wezterm.Palette +---@param metadata _.wezterm.ColorSchemeMetaData +---@param file_name string +function color.save_scheme(colors, metadata, file_name) end + +return color diff --git a/.config/wezterm/types/gui.lua b/.config/wezterm/types/gui.lua new file mode 100644 index 0000000..5181683 --- /dev/null +++ b/.config/wezterm/types/gui.lua @@ -0,0 +1,27 @@ +---@meta + +local gui = {} + +---@return table +function gui.default_key_tables() end + +---@return _.wezterm.KeyBinding[] +function gui.default_keys() end + +---@return _.wezterm.GpuInfo[] +function gui.enumerate_gpus() end + +---@return _.wezterm.Appearance +function gui.get_appearance() end + +---@param window_id number +---@return _.wezterm.Window | nil +function gui.gui_window_for_mux_window(window_id) end + +---@return _.wezterm.Window[] +function gui.gui_windows() end + +---@return { active: _.wezterm.ScreenInformation, by_name: table, main: _.wezterm.ScreenInformation, origin_x: number, origin_y: number, virtual_height: number, virtual_width: number } +function gui.screens() end + +return gui diff --git a/.config/wezterm/types/init.lua b/.config/wezterm/types/init.lua new file mode 100644 index 0000000..1b8af10 --- /dev/null +++ b/.config/wezterm/types/init.lua @@ -0,0 +1,217 @@ +---@meta + +---@class WezTerm +local wezterm = { + ---@module 'wezterm.color' + color = {}, + + ---@module 'wezterm.gui' + gui = {}, + + ---@module 'wezterm.mux' + mux = {}, + + ---@module 'wezterm.procinfo' + procinfo = {}, + + ---@module 'wezterm.time' + time = {}, + + ---@type table + GLOBAL = {}, + + ---@type _.wezterm.KeyAssignment + action = {}, + + ---@type string + config_dir = '', + + ---@type string + config_file = '', + + ---@type string + executable_dir = '', + + ---@type string + home_dir = '', + + ---@type table + nerdfonts = {}, + + ---@type string + target_triple = '', + + ---@type string + version = '', + + ---@param callback _.wezterm.ActionCallback + ---@return _.wezterm._CallbackAction + action_callback = function(callback) end, + + ---@param path string + add_to_config_reload_watch_list = function(path) end, + + ---@param args string[] + background_child_process = function(args) end, + + ---@return _.wezterm.BatteryInfo[] + battery_info = function() end, + + ---@param string string + ---@return number + column_width = function(string) end, + + ---@return _.wezterm.ConfigBuilder + config_builder = function() end, + + ---@return _.wezterm.HyperlinkRule[] + default_hyperlink_rules = function() end, + + ---@return _.wezterm.SshDomain[] + default_ssh_domains = function() end, + + ---@return _.wezterm.WslDomain[] + default_wsl_domains = function() end, + + ---@param event_name string + ---@param ... any + ---@return boolean + emit = function(event_name, ...) end, + + ---@param ssh_config_file_name? string + ---@return table + enumerate_ssh_hosts = function(ssh_config_file_name) end, + + ---@param family string + ---@param attributes? _.wezterm.FontAttributes + ---@return _.wezterm._Font + ---@overload fun(attributes: _.wezterm.FontAttributesExtended): _.wezterm._Font + font = function(family, attributes) end, + + ---@param families string[] + ---@param attributes? _.wezterm.FontAttributes + ---@return _.wezterm._Font + ---@overload fun(attributes: (string | _.wezterm.FontFallbackAttributesExtended)[]): _.wezterm._Font + font_with_fallback = function(families, attributes) end, + + ---@param format_items _.wezterm.FormatItem[] + ---@return string + format = function(format_items) end, + + ---@return table + get_builtin_color_schemes = function() end, + + ---@param pattern string + ---@param relative_to? string + ---@return string[] + glob = function(pattern, relative_to) end, + + ---@param gradient _.wezterm.Gradient + ---@param num_colors number + ---@return _.wezterm.Color[] + gradient_colors = function(gradient, num_colors) end, + + ---@param name string + ---@return boolean + has_action = function(name) end, + + ---@return string + hostname = function() end, + + ---@param value any + ---@return string + json_encode = function(value) end, + + ---@param arg string + ---@param ... any + log_error = function(arg, ...) end, + + ---@param arg string + ---@param ... any + log_info = function(arg, ...) end, + + ---@param arg string + ---@param ... any + log_warn = function(arg, ...) end, + + ---@overload fun(event_name: 'format-tab-title', callback: fun(tab: _.wezterm.TabInformation, tabs: _.wezterm.TabInformation[], panes: _.wezterm.PaneInformation, config: table, hover: boolean, max_width: integer): string | _.wezterm.FormatItem[]): nil + ---@overload fun(event_name: 'update-right-status', callback: fun(window: _.wezterm.Window, pane: _.wezterm.Pane): nil): nil + ---@overload fun(event_name: 'window-config-reloaded', callback: fun(window: _.wezterm.Window, pane: _.wezterm.Pane): nil): nil + on = function(event_name, callback) end, + + ---@param path_or_url string + ---@param application? string + open_with = function(path_or_url, application) end, + + ---@param string string + ---@param min_width number + ---@return string + pad_left = function(string, min_width) end, + + ---@param string string + ---@param min_width number + ---@return string + pad_right = function(string, min_width) end, + + ---@param table _.wezterm.MouseBindingBase + ---@return _.wezterm.MouseBinding ... + ---@overload fun(table: _.wezterm.KeyBindingBase): _.wezterm.KeyBinding ... + permute_any_mods = function(table) end, + + ---@param table _.wezterm.MouseBindingBase + ---@return _.wezterm.MouseBinding ... + ---@overload fun(table: _.wezterm.KeyBindingBase): _.wezterm.KeyBinding ... + permute_any_or_no_mods = function(table) end, + + ---@param path string + ---@return string[] + read_dir = function(path) end, + + reload_configuration = function() end, + + ---@param args string[] + ---@return boolean, string, string + run_child_process = function(args) end, + + ---@return boolean + running_under_wsl = function() end, + + ---@param args string[] + ---@return string + shell_join_args = function(args) end, + + ---@param line string + ---@return string|string[] + shell_quote_arg = function(line) end, + + ---@param milliseconds number + sleep_ms = function(milliseconds) end, + + ---@param str string + ---@return string[] + split_by_newlines = function(str) end, + + ---@param format string + ---@return string + strftime = function(format) end, + + ---@param format string + ---@return string + strftime_utc = function(format) end, + + ---@param string string + ---@param min_width number + ---@return string + truncate_left = function(string, min_width) end, + + ---@param string string + ---@param min_width number + ---@return string + truncate_right = function(string, min_width) end, + + ---@param str string + ---@return string + utf16_to_utf8 = function(str) end, +} + +return wezterm diff --git a/.config/wezterm/types/mux.lua b/.config/wezterm/types/mux.lua new file mode 100644 index 0000000..fd8c107 --- /dev/null +++ b/.config/wezterm/types/mux.lua @@ -0,0 +1,47 @@ +---@meta + +local mux = {} + +---@return _.wezterm.MuxDomain[] +function mux.all_domains() end + +---@return _.wezterm.MuxWindow[] +function mux.all_windows() end + +---@return string +function mux.get_active_workspace() end + +---@param name_or_id string | number | nil +---@return _.wezterm.MuxDomain | nil +function mux.get_domain(name_or_id) end + +---@param PANE_ID number +---@return _.wezterm.Pane | nil +function mux.get_pane(PANE_ID) end + +---@param TAB_ID number +---@return _.wezterm.MuxTab | nil +function mux.get_tab(TAB_ID) end + +---@param WINDOW_ID number +---@return _.wezterm.MuxWindow | nil +function mux.get_window(WINDOW_ID) end + +---@return string[] +function mux.get_workspace_names() end + +---@param old string +---@param new string +function mux.rename_workspace(old, new) end + +---@param WORKSPACE string +function mux.set_active_workspace(WORKSPACE) end + +---@param domain _.wezterm.MuxDomain +function mux.set_default_domain(domain) end + +---@param opts { args: string[], cwd: string, set_environment_variables: table, domain: { DomainName: string }, workspace: string[], position: { x: number, y: number, origin?: 'ScreenCoordinateSystem' | 'MainScreen' | 'ActiveScreen' | { Named: string } } } +---@return _.wezterm.MuxTab, _.wezterm.Pane, _.wezterm.MuxWindow +function mux.spawn_window(opts) end + +return mux diff --git a/.config/wezterm/types/procinfo.lua b/.config/wezterm/types/procinfo.lua new file mode 100644 index 0000000..9b577eb --- /dev/null +++ b/.config/wezterm/types/procinfo.lua @@ -0,0 +1,20 @@ +---@meta + +local procinfo = {} + +---@param pid number +---@return string | nil +function procinfo.current_working_dir_for_pid(pid) end + +---@param pid number +---@return string | nil +function procinfo.executable_path_for_pid(pid) end + +---@param pid number +---@return _.wezterm.LocalProcessInfo | nil +function procinfo.get_info_for_pid(pid) end + +---@return number +function procinfo.pid() end + +return procinfo diff --git a/.config/wezterm/types/time.lua b/.config/wezterm/types/time.lua new file mode 100644 index 0000000..08f6873 --- /dev/null +++ b/.config/wezterm/types/time.lua @@ -0,0 +1,21 @@ +---@meta + +local time = {} + +---@param interval_seconds number +---@param callback fun(): any +function time.call_after(interval_seconds, callback) end + +---@return _.wezterm.Time +function time.now() end + +---@param str string +---@param format string +---@return _.wezterm.Time +function time.parse(str, format) end + +---@param str string +---@return _.wezterm.Time +function time.parse_rfc3339(str) end + +return time diff --git a/.config/wezterm/types/types.lua b/.config/wezterm/types/types.lua new file mode 100644 index 0000000..743aac9 --- /dev/null +++ b/.config/wezterm/types/types.lua @@ -0,0 +1,1172 @@ +---@meta + +---@alias _.wezterm.ActionCallback fun(win: _.wezterm.Window, pane: _.wezterm.Pane, ...: any): (nil | false) +---@alias _.wezterm.AnsiColor 'Black' | 'Maroon' | 'Green' | 'Olive' | 'Navy' | 'Purple' | 'Teal' | 'Silver' | 'Grey' | 'Red' | 'Lime' | 'Yellow' | 'Blue' | 'Fuchsia' | 'Aqua' | 'White' +---@alias _.wezterm.Appearance 'Light' | 'Dark' | 'LightHighContrast' | 'DarkHighContrast' +---@alias _.wezterm.Clipboard 'Clipboard' | 'PrimarySelection' | 'ClipboardAndPrimarySelection' +---@alias _.wezterm.ColorSpec 'Default' | { AnsiColor: string } | { Color: string } +---@alias _.wezterm.CopyMode 'AcceptPattern' | 'ClearPattern' | 'ClearSelectionMode' | 'Close' | 'CycleMatchType' | 'EditPattern' | 'MoveBackwardSemanticZone' | { MoveBackwardSemanticZoneOfType: _.wezterm.SemanticZoneType } | 'MoveBackwardWord' | 'MoveDown' | 'MoveForwardSemanticZone' | { MoveForwardSemanticZoneOfType: _.wezterm.SemanticZoneType } | 'MoveForwardWord' | 'MoveForwardWordEnd' | 'MoveLeft' | 'MoveRight' | 'MoveToEndOfLineContent' | 'MoveToScrollbackBottom' | 'MoveToScrollbackTop' | 'MoveToSelectionOtherEnd' | 'MoveToSelectionOtherEndHoriz' | 'MoveToStartOfLine' | 'MoveToStartOfLineContent' | 'MoveToStartOfNextLine' | 'MoveToViewportBottom' | 'MoveToViewportMiddle' | 'MoveToViewportTop' | 'MoveUp' | 'NextMatch' | 'NextMatchPage' | 'PriorMatch' | 'PriorMatchPage' | { SetSelectionMode: _.wezterm.SelectionMode | 'SemanticZone' } +---@alias _.wezterm.CursorShape 'Default' | _.wezterm.CursorStyle +---@alias _.wezterm.CursorStyle 'BlinkingBlock' | 'SteadyBlock' | 'BlinkingUnderline' | 'SteadyUnderline' | 'BlinkingBar' | 'SteadyBar' +---@alias _.wezterm.CursorVisibility 'Hidden' | 'Visible' +---@alias _.wezterm.Direction 'Left' | 'Right' | 'Up' | 'Down' | 'Next' | 'Prev' +---@alias _.wezterm.EasingFunction 'Linear' | 'Ease' | 'EaseIn' | 'EaseInOut' | 'EaseOut' | { CubicBezier: number[] } | 'Constant' +---@alias _.wezterm.FreetypeLoadTarget 'Normal' | 'Light' | 'Mono' | 'HorizontalLcd' +---@alias _.wezterm.SelectionMode 'Cell' | 'Word' | 'Line' | 'Block' +---@alias _.wezterm.SemanticZoneType 'Prompt' | 'Input' | 'Output' +---@alias _.wezterm.Stretch 'UltraCondensed' | 'ExtraCondensed' | 'Condensed' | 'SemiCondensed' | 'Normal' | 'SemiExpanded' | 'Expanded' | 'ExtraExpanded' | 'UltraExpanded' +---@alias _.wezterm.Style 'Normal' | 'Italic' | 'Oblique' +---@alias _.wezterm.Weight 'Thin' | 'ExtraLight' | 'Light' | 'DemiLight' | 'Book' | 'Regular' | 'Medium' | 'DemiBold' | 'Bold' | 'ExtraBold' | 'Black' | 'ExtraBlack' + +---@class _.wezterm.ScreenInformation +---@field name string +---@field x number +---@field y number +---@field height number +---@field width number +---@field max_fps? number + +---@class _.wezterm.LocalProcessInfo +---@field pid number +---@field ppid number +---@field name string +---@field status 'Idle' | 'Run' | 'Sleep' | 'Stop' | 'Zombie' | 'Tracing' | 'Dead' | 'Wakekill' | 'Waking' | 'Parked' | 'LockBlocked' | 'Unknown' +---@field argv string[] +---@field executable string +---@field cwd string +---@field children table + +---@class _.wezterm.KeyBindingBase +---@field key string +---@field action _.wezterm._Action + +---@class _.wezterm.KeyBinding: _.wezterm.KeyBindingBase +---@field mods string + +---@class _.wezterm.MouseEventInfo +---@field streak number +---@field button 'Left' | 'Right' | 'Middle' | { WheelDown: number } | { WheelUp: number } + +---@class _.wezterm.MouseDownEvent +---@field Down _.wezterm.MouseEventInfo + +---@class _.wezterm.MouseUpEvent +---@field Up _.wezterm.MouseEventInfo + +---@class _.wezterm.MouseDragEvent +---@field Drag _.wezterm.MouseEventInfo + +---@alias _.wezterm.MouseEvent _.wezterm.MouseDownEvent | _.wezterm.MouseUpEvent | _.wezterm.MouseDragEvent + +---@class _.wezterm.MouseBindingBase +---@field event _.wezterm.MouseEvent +---@field action _.wezterm._Action +---@field mouse_reporting? boolean +---@field alt_screen? boolean | 'Any' + +---@class _.wezterm.MouseBinding: _.wezterm.MouseBindingBase +---@field mods string + +---@class _.wezterm.BatteryInfo +---@field state_of_charge number +---@field vendor string +---@field serial string +---@field time_to_full number | nil +---@field time_to_empty number | nil +---@field state 'Charging' | 'Discharging' | 'Empty' | 'Full' | 'Unknown' + +---@class _.wezterm.HyperlinkRule +---@field regex string +---@field format string +---@field highlight? number + +---@class _.wezterm.SshDomain +---@field name string +---@field remote_address string +---@field no_agent_auth? boolean +---@field username string +---@field connect_automatically? boolean +---@field timeout? number +---@field remote_wezterm_path? string +---@field ssh_option? table +---@field multiplexing? 'WezTerm' | 'None' +---@field assume_shell? 'Unknown' | 'Posix' +---@field default_prog? string[] +---@field local_echo_threshold_ms? number + +---@class _.wezterm.WslDomain +---@field name string +---@field distribution string +---@field username? string +---@field default_cwd? string +---@field default_prog? string[] + +---@class _.wezterm.FontAttributes +---@field stretch? _.wezterm.Stretch +---@field style? _.wezterm.Style +---@field weight? _.wezterm.Weight + +---@class _.wezterm.FontAttributesExtended: _.wezterm.FontAttributes +---@field family string +---@field harfbuzz_features? string[] +---@field freetype_load_target? _.wezterm.FreetypeLoadTarget +---@field freetype_render_target? _.wezterm.FreetypeLoadTarget +---@field freetype_load_flags? string +---@field assume_emoji_presentation? boolean + +---@class _.wezterm.FontFallbackAttributesExtended: _.wezterm.FontAttributesExtended +---@field scale? number + +---@class _.wezterm._Font + +---@class _.wezterm.FormatAttribute +---@field Attribute { Underline: 'None' | 'Single' | 'Double' | 'Curly' | 'Dotted' | 'Dashed' } | { Intensity: 'Normal' | 'Bold' | 'Half' } | { Italic: boolean } + +---@class _.wezterm.FormatForegroundColor +---@field Foreground { AnsiColor: _.wezterm.AnsiColor } | { Color: string } + +---@class _.wezterm.FormatBackgroundColor +---@field Background { AnsiColor: _.wezterm.AnsiColor } | { Color: string } + +---@alias _.wezterm.FormatItem _.wezterm.FormatAttribute | _.wezterm.FormatForegroundColor | _.wezterm.FormatBackgroundColor | { Text: string } | 'ResetAttributes' + +---@class _.wezterm.SpawnCommand +---@field label? string +---@field args? string[] +---@field cwd? string +---@field set_environment_variables? table +---@field domain? 'CurrentPaneDomain' | 'DefaultDomain' | { DomainName: string } +---@field position? { x: number, y: number, origin?: 'ScreenCoordinateSystem' | 'MainScreen' | 'ActivateScreen' | { Named: string } } + +---@class _.wezterm.Color +local Color = {} + +---@param degrees number +---@return _.wezterm.Color +function Color:adjust_hue_fixed(degrees) end + +---@param degrees number +---@return _.wezterm.Color +function Color:adjust_hue_fixed_ryb(degrees) end + +---@return _.wezterm.Color +function Color:complement() end + +---@return _.wezterm.Color +function Color:complement_ryb() end + +---@param color _.wezterm.Color +---@return number +function Color:contrast_ratio(color) end + +---@param factor number +---@return _.wezterm.Color +function Color:darken(factor) end + +---@param amount number +---@return _.wezterm.Color +function Color:darken_fixed(amount) end + +---@param color _.wezterm.Color +---@return number +function Color:delta_e(color) end + +---@param factor number +---@return _.wezterm.Color +function Color:desaturate(factor) end + +---@param amount number +---@return _.wezterm.Color +function Color:desaturate_fixed(amount) end + +---@return number, number, number, number +function Color:hsla() end + +---@return number, number, number, number +function Color:laba() end + +---@param factor number +---@return _.wezterm.Color +function Color:lighten(factor) end + +---@param amount number +---@return _.wezterm.Color +function Color:lighten_fixed(amount) end + +---@return number, number, number, number +function Color:linear_rgba() end + +---@param factor number +---@return _.wezterm.Color +function Color:saturate(factor) end + +---@param amount number +---@return _.wezterm.Color +function Color:saturate_fixed(amount) end + +---@return _.wezterm.Color, _.wezterm.Color, _.wezterm.Color +function Color:square() end + +---@return number, number, number, number +function Color:srgba_u8() end + +---@return _.wezterm.Color, _.wezterm.Color +function Color:triad() end + +---@class _.wezterm.TabBarColor +---@field bg_color string +---@field fg_color string +---@field intensity 'Half' | 'Normal' | 'Bold' +---@field italic boolean +---@field strikethrough boolean +---@field underline 'None' | 'Single' | 'Double' + +---@class _.wezterm.TabBarColors +---@field active_tab? _.wezterm.TabBarColor +---@field background? string +---@field inactive_tab? _.wezterm.TabBarColor +---@field inactive_tab_edge? string +---@field inactive_tab_edge_hover? string +---@field inactive_tab_hover? _.wezterm.TabBarColor +---@field new_tab? _.wezterm.TabBarColor +---@field new_tab_hover? _.wezterm.TabBarColor + +---@class _.wezterm.TabBarStyle +---@field active_tab_left? string +---@field active_tab_right? string +---@field inactive_tab_left? string +---@field inactive_tab_right? string +---@field inactive_tab_hover_left? string +---@field inactive_tab_hover_right? string +---@field new_tab_left? string +---@field new_tab_right? string +---@field new_tab_hover_left? string +---@field new_tab_hover_right? string +---@field window_hide? string +---@field window_hide_hover? string +---@field window_maximize? string +---@field window_maximize_hover? string +---@field window_close? string +---@field window_close_hover? string + +---@class _.wezterm.Palette +---@field ansi? string[] +---@field background? string +---@field brights? string[] +---@field cursor_bg? string +---@field cursor_border? string +---@field cursor_fg? string +---@field foreground? string +---@field indexed? table +---@field selection_bg? string +---@field selection_fg? string +---@field tab_bar? _.wezterm.TabBarColors +---@field scrollbar_thumb? string +---@field split? string +---@field visual_bell? string +---@field compose_cursor? string +---@field copy_mode_active_highlight_fg? _.wezterm.ColorSpec +---@field copy_mode_active_highlight_bg? _.wezterm.ColorSpec +---@field copy_mode_inactive_highlight_fg? _.wezterm.ColorSpec +---@field copy_mode_inactive_highlight_bg? _.wezterm.ColorSpec +---@field quick_select_label_fg? _.wezterm.ColorSpec +---@field quick_select_label_bg? _.wezterm.ColorSpec +---@field quick_select_match_fg? _.wezterm.ColorSpec +---@field quick_select_match_bg? _.wezterm.ColorSpec + +---@class _.wezterm.ColorSchemeMetaData +---@field name? string +---@field author? string +---@field origin_url? string +---@field wezterm_version? string +---@field aliases? string[] + +---@class _.wezterm.SemanticZone +---@field start_y number +---@field start_x number +---@field end_y number +---@field end_x number +---@field semantic_type _.wezterm.SemanticZoneType + +---@class _.wezterm.PresetGradient +---@field preset 'Blues' | 'BrBg' | 'BuGn' | 'BuPu' | 'Cividis' | 'Cool' | 'CubeHelixDefault' | 'GnBu' | 'Greens' | 'Greys' | 'Inferno' | 'Magma' | 'OrRd' | 'Oranges' | 'PiYg' | 'Plasma' | 'PrGn' | 'PuBu' | 'PuBuGn' | 'PuOr' | 'PuRd' | 'Purples' | 'Rainbow' | 'RdBu' | 'RdGy' | 'RdPu' | 'RdYlBu' | 'RdYlGn' | 'Reds' | 'Sinebow' | 'Spectral' | 'Turbo' | 'Viridis' | 'Warm' | 'YlGn' | 'YlGnBu' | 'YlOrBr' | 'YlOrRd' + +---@class _.wezterm.LinearGradientOrientation +---@field angle number + +---@class _.wezterm.RadialGradientOrientation +---@field radius? number +---@field cx? number +---@field cy? number + +---@class _.wezterm.Gradient +---@field colors string[] +---@field orientation? 'Horizontal' | 'Vertical' | { Linear: _.wezterm.LinearGradientOrientation } | { Radial: _.wezterm.RadialGradientOrientation } +---@field interpolation? 'Linear' | 'Basis' | 'CatmullRom' +---@field blend? 'Rgb' | 'LinearRgb' | 'Hsv' | 'Oklab' +---@field noise? number +---@field segment_size? number +---@field segment_smoothness? number + +---@alias _.wezterm.BackgroundSource { File: string | { path: string, speed: number } } | _.wezterm.Gradient | { Color: string } + +---@class _.wezterm.HsbTransform +---@field hue? number +---@field saturation? number +---@field brightness? number + +---@class _.wezterm.BackgroundLayer +---@field source _.wezterm.BackgroundSource +---@field attachment? 'Fixed' | 'Scroll' | { Parallax: number } +---@field repeat_x? 'Repeat' | 'Mirror' | 'NoRepeat' +---@field repeat_x_size? number | string +---@field repeat_y? 'Repeat' | 'Mirror' | 'NoRepeat' +---@field repeat_y_size? number | string +---@field vertical_align? 'Top' | 'Middle' | 'Bottom' +---@field vertical_offset? number | string +---@field horizontal_align? 'Left' | 'Center' | 'Right' +---@field horizontal_offset? number | string +---@field opacity? number +---@field hsb? _.wezterm.HsbTransform +---@field height? 'Cover' | 'Contain' | number | string +---@field width? 'Cover' | 'Contain' | number | string + +---@class _.wezterm.TlsDomainClient +---@field name string +---@field bootstrap_via_ssh string +---@field remote_address string +---@field pem_private_key? string +---@field pem_cert? string +---@field pem_ca? string +---@field pem_root_certs? string[] +---@field accept_invalid_hostnames? boolean +---@field expected_cn? string +---@field connect_automatically? boolean +---@field read_timeout? number +---@field write_timeout? number +---@field remote_wezterm_path? string + +---@class _.wezterm.TlsDomainServer +---@field bind_address string +---@field pem_private_key? string +---@field pem_cert? string +---@field pem_ca? string +---@field pem_root_certs? string[] + +---@class _.wezterm.MultiplexerDomain +---@field name string +---@field socket_path? string +---@field no_serve_automatically? boolean +---@field skip_permissions_check? boolean + +---@class _.wezterm.VisualBellConfig +---@field fade_in_duration_ms? number +---@field fade_out_duration_ms? number +---@field fade_in_function? _.wezterm.EasingFunction +---@field fade_out_function? _.wezterm.EasingFunction +---@field target? 'BackgroundColor' | 'CursorColor' + +---@class _.wezterm.GpuInfo +---@field backend string +---@field device number +---@field device_type string +---@field driver? string +---@field driver_info? string +---@field name string +---@field vendor number + +---@class _.wezterm.WindowFrame +---@field font _.wezterm._Font +---@field font_size number +---@field inactive_titlebar_bg? string +---@field active_titlebar_bg? string +---@field inactive_titlebar_fg? string +---@field active_titlebar_fg? string +---@field inactive_titlebar_border_bottom? string +---@field active_titlebar_border_bottom? string +---@field button_fg? string +---@field button_bg? string +---@field button_hover_fg? string +---@field button_hover_bg? string +---@field border_left_width? number | string +---@field border_right_width? number | string +---@field border_bottom_height? number | string +---@field border_top_height? number | string +---@field border_left_color? string +---@field border_right_color? string +---@field border_bottom_color? string +---@field border_top_color? string + +---@class _.wezterm.WindowPadding +---@field left? number +---@field right? number +---@field top? number +---@field bottom? number + +---@class _.wezterm.Pane +local Pane = {} + +---@return nil +function Pane:activate() end + +---@return string | nil +function Pane:get_current_working_dir() end + +---@return { x: number, y: number, shape: _.wezterm.CursorShape, visibility: _.wezterm.CursorVisibility } +function Pane:get_cursor_position() end + +---@return { cols: number, viewport_rows: number, scrollback_rows: number, physical_top: number, scrollback_top: number } +function Pane:get_dimensions() end + +---@return string | nil +function Pane:get_domain_name() end + +---@return _.wezterm.LocalProcessInfo | nil +function Pane:get_foreground_process_info() end + +---@return string | nil +function Pane:get_foreground_process_name() end + +---@param nlines? number +---@return string +function Pane:get_lines_as_text(nlines) end + +---@param nlines? number +---@return string +function Pane:get_logical_lines_as_text(nlines) end + +---@return { password_input?: boolean, is_tardy?: boolean, since_last_response_time?: number } | nil +function Pane:get_metadata() end + +---@param x number +---@param y number +---@return _.wezterm.SemanticZone | nil +function Pane:get_semantic_zone_at(x, y) end + +---@param zone_type _.wezterm.SemanticZoneType +---@return _.wezterm.SemanticZone[] +function Pane:get_semantic_zones(zone_type) end + +---@param start_x number +---@param start_y number +---@param end_x number +---@param end_y number +---@return string +function Pane:get_text_from_region(start_x, start_y, end_x, end_y) end + +---@param zone _.wezterm.SemanticZone +---@return string +function Pane:get_text_from_semantic_zone(zone) end + +---@return string +function Pane:get_title() end + +---@return string +function Pane:get_tty_name() end + +---@return table +function Pane:get_user_vars() end + +---@return boolean +function Pane:has_unseen_output() end + +---@param text string +function Pane:inject_output(text) end + +---@return boolean +function Pane:is_alt_screen_active() end + +---@return _.wezterm.MuxTab, _.wezterm.MuxWindow +function Pane:move_to_new_tab() end + +---@param workspace? string +---@return _.wezterm.MuxTab, _.wezterm.MuxWindow +function Pane:move_to_new_window(workspace) end + +---@return _.wezterm.Pane +function Pane:mux_pane() end + +---@return number +function Pane:pane_id() end + +---@param text string +function Pane:paste(text) end + +---@param text string +function Pane:send_paste(text) end + +---@param text string +function Pane:send_text(text) end + +---@param opts { args: string[], cwd: string; set_environment_variables: table, domain: 'DefaultDomain' | { DomainName: string }, direction: 'Right' | 'Left' | 'Up' | 'Down', top_level: boolean, size: number } +---@return _.wezterm.Pane +function Pane:split(opts) end + +---@return _.wezterm.MuxTab +function Pane:tab() end + +---@return _.wezterm.MuxWindow +function Pane:window() end + +---@class _.wezterm.MuxDomain +local MuxDomain = {} + +function MuxDomain:attach() end +function MuxDomain:detach() end + +---@return number +function MuxDomain:domain_id() end + +---@return boolean +function MuxDomain:has_any_panes() end + +---@return boolean +function MuxDomain:is_spawnable() end + +---@return string +function MuxDomain:label() end + +---@return string +function MuxDomain:name() end + +---@return 'Attached' | 'Detached' +function MuxDomain:state() end + +---@class _.wezterm.TabWthInfo +---@field index number +---@field is_active boolean +---@field tab _.wezterm.MuxTab + +---@class _.wezterm.PaneInformation +---@field pane_id integer +---@field pane_index integer +---@field is_active boolean +---@field is_zoomed boolean +---@field left integer +---@field top integer +---@field width integer +---@field height integer +---@field pixel_width integer +---@field pixel_height integer +---@field title string +---@field user_vars table + +---@class _.wezterm.TabInformation +---@field tab_id integer +---@field tab_index integer +---@field is_active boolean +---@field active_pane _.wezterm.PaneInformation +---@field window_id integer +---@field window_title string +---@field tab_title string + +---@class _.wezterm.MuxWindow +local MuxWindow = {} + +---@return _.wezterm.Pane | nil +function MuxWindow:active_pane() end + +---@return _.wezterm.MuxTab | nil +function MuxWindow:active_tab() end + +---@return string +function MuxWindow:get_title() end + +---@return string +function MuxWindow:get_workspace() end + +---@return _.wezterm.Window | nil +function MuxWindow:gui_window() end + +---@param TITLE string +function MuxWindow:set_title(TITLE) end + +---@param workspace string +function MuxWindow:set_workspace(workspace) end + +---@param opts { args: string[], cwd: string, set_environment_variables: table, domain: { DomainName: string } } +---@return _.wezterm.MuxTab, _.wezterm.Pane, _.wezterm.MuxWindow +function MuxWindow:spawn_tab(opts) end + +---@return _.wezterm.MuxTab[] +function MuxWindow:tabs() end + +---@return _.wezterm.TabWthInfo[] +function MuxWindow:tabs_with_info() end + +---@return number +function MuxWindow:window_id() end + +---@class _.wezterm.PaneWithInfo +---@field index number +---@field is_active boolean +---@field is_zoomed boolean +---@field left number +---@field top number +---@field width number +---@field height number +---@field pixel_width number +---@field pixel_height number +---@field pane _.wezterm.Pane + +---@class _.wezterm.MuxTab +local MuxTab = {} + +function MuxTab:activate() end + +---@return _.wezterm.Pane | nil +function MuxTab:active_pane() end + +---@param direction _.wezterm.Direction +---@return _.wezterm.Pane +function MuxTab:get_pane_direction(direction) end + +---@return { rows: number, cols: number, pixel_width: number, pixel_height: number, dpi: number } +function MuxTab:get_size() end + +---@return string +function MuxTab:get_title() end + +---@return _.wezterm.Pane[] +function MuxTab:panes() end + +---@return _.wezterm.PaneWithInfo[] +function MuxTab:panes_with_info() end + +function MuxTab:rotate_clockwise() end +function MuxTab:rotate_counter_clockwise() end + +---@param TITLE string +function MuxTab:set_title(TITLE) end + +---@param bool boolean +---@return boolean +function MuxTab:set_zoomed(bool) end + +---@return number +function MuxTab:tab_id() end + +---@return _.wezterm.MuxWindow | nil +function MuxTab:window() end + +---@class _.wezterm.Time +local Time = {} + +---@param format string +---@return string +function Time:format(format) end + +---@param format string +---@return string +function Time:format_utc(format) end + +---@param lat number +---@param lon number +---@return { progression: number, rise: _.wezterm.Time, set: _.wezterm.Time, up: boolean } +function Time:sun_times(lat, lon) end + +---@class _.wezterm.Window +local Window = {} + +---@return string | nil +function Window:active_key_table() end + +---@return _.wezterm.Pane +function Window:active_pane() end + +---@return _.wezterm.MuxTab +function Window:active_tab() end + +---@return string +function Window:active_workspace() end + +---@return string | nil +function Window:composition_status() end + +---@param text string +---@param clipboard? _.wezterm.Clipboard +function Window:copy_to_clipboard(text, clipboard) end + +---@return _.wezterm.MouseEvent +function Window:current_event() end + +---@return any +function Window:effective_config() end + +function Window:focus() end + +---@return _.wezterm.Appearance +function Window:get_appearance() end + +---@return any +function Window:get_config_overrides() end + +---@return { pixel_width: number, pixel_height: number, dpi: number, is_full_screen: boolean } +function Window:get_dimensions() end + +---@param pane _.wezterm.Pane +---@return string +function Window:get_selection_escapes_for_pane(pane) end + +---@param pane _.wezterm.Pane +---@return string +function Window:get_selection_text_for_pane(pane) end + +---@return boolean +function Window:is_focused() end + +---@return string, string +function Window:keyboard_modifiers() end + +---@return boolean +function Window:leader_is_active() end + +function Window:maximize() end + +---@return _.wezterm.MuxWindow +function Window:mux_window() end + +---@param key_assignment _.wezterm._Action +---@param pane _.wezterm.Pane +function Window:get_selection_text_for_pane(key_assignment, pane) end + +---@param key_assignment _.wezterm._Action +---@param pane _.wezterm.Pane +function Window:perform_action(key_assignment, pane) end + +function Window:restore() end + +---@param overrides any +function Window:set_config_overrides(overrides) end + +---@param width number +---@param height number +function Window:set_inner_size(width, height) end + +---@param status string +function Window:set_left_status(status) end + +---@param x number +---@param y number +function Window:set_position(x, y) end + +---@param status string +function Window:set_right_status(status) end + +---@param title string +---@param message string +---@param url? string | nil +---@param timeout_milliseconds? number +function Window:toast_notification( + title, + message, + url, + timeout_milliseconds +) +end + +function Window:toggle_fullscreen() end + +---@return number +function Window:window_id() end + +---@class _.wezterm._KeyAssignmentAction +---@class _.wezterm._CallbackAction + +---@alias _.wezterm._Action _.wezterm._KeyAssignmentAction | _.wezterm._CallbackAction + +---@class _.wezterm.KeyAssignment +---@field ActivateCommandPalette _.wezterm._KeyAssignmentAction +---@field ActivateCopyMode _.wezterm._KeyAssignmentAction +---@field ActivateLastTab _.wezterm._KeyAssignmentAction +---@field ClearKeyTableStack _.wezterm._KeyAssignmentAction +---@field ClearSelection _.wezterm._KeyAssignmentAction +---@field DecreaseFontSize _.wezterm._KeyAssignmentAction +---@field DisableDefaultAssignment _.wezterm._KeyAssignmentAction +---@field Hide _.wezterm._KeyAssignmentAction +---@field HideApplication _.wezterm._KeyAssignmentAction +---@field IncreaseFontSize _.wezterm._KeyAssignmentAction +---@field Nop _.wezterm._KeyAssignmentAction +---@field OpenLinkAtMouseCursor _.wezterm._KeyAssignmentAction +---@field PopKeyTable _.wezterm._KeyAssignmentAction +---@field QuickSelect _.wezterm._KeyAssignmentAction +---@field QuitApplication _.wezterm._KeyAssignmentAction +---@field ReloadConfiguration _.wezterm._KeyAssignmentAction +---@field ResetFontAndWindowSize _.wezterm._KeyAssignmentAction +---@field ResetFontSize _.wezterm._KeyAssignmentAction +---@field ResetTerminal _.wezterm._KeyAssignmentAction +---@field ScrollByCurrentEventWheelDelta _.wezterm._KeyAssignmentAction +---@field ScrollToBottom _.wezterm._KeyAssignmentAction +---@field ScrollToTop _.wezterm._KeyAssignmentAction +---@field Show _.wezterm._KeyAssignmentAction +---@field ShowDebugOverlay _.wezterm._KeyAssignmentAction +---@field ShowLauncher _.wezterm._KeyAssignmentAction +---@field ShowTabNavigator _.wezterm._KeyAssignmentAction +---@field SpawnWindow _.wezterm._KeyAssignmentAction +---@field StartWindowDrag _.wezterm._KeyAssignmentAction +---@field ToggleFullScreen _.wezterm._KeyAssignmentAction +---@field TogglePaneZoomState _.wezterm._KeyAssignmentAction +local KeyAssignment = {} + +---@param opts { name: string, timeout_milliseconds?: number, one_shot?: boolean, replace_current?: boolean, until_unknown?: boolean, prevent_fallback?: boolean } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateKeyTable(opts) end + +---@param index number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivatePaneByIndex(index) end + +---@param direction 'Left' | 'Right' | 'Up' | 'Down' | 'Next' | 'Prev' +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivatePaneDirection(direction) end + +---@param tab number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateTab(tab) end + +---@param tab number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateTabRelative(tab) end + +---@param tab number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateTabRelativeNoWrap(tab) end + +---@param window number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateWindow(window) end + +---@param window number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateWindowRelative(window) end + +---@param window number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ActivateWindowRelativeNoWrap(window) end + +---@param size_direction ('Left' | 'Down' | 'Up' | 'Right' | number)[] +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.AdjustPaneSize(size_direction) end + +---@param domain string +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.AttachDomain(domain) end + +---@class _.wezterm.CharSelectOpts +---@field copy_on_select? boolean +---@field copy_to? _.wezterm.Clipboard +---@field group? 'RecentlyUsed' | 'SmileysAndEmotion' | 'PeopleAndBody' | 'AnimalsAndNature' | 'FoodAndDrink' | 'TravelAndPlaces' | 'Activities' | 'Objects' | 'Symbols' | 'Flags' | 'NerdFonts' | 'UnicodeNames' + +---@param opts _.wezterm.CharSelectOpts +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CharSelect(opts) end + +---@param mode 'ScrollbackOnly' | 'ScrollbackAndViewport' +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ClearScrollback(mode) end + +---@param opts { confirm: boolean } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CloseCurrentPane(opts) end + +---@param opts { confirm: boolean } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CloseCurrentTab(opts) end + +---@param copy_to _.wezterm.Clipboard +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CompleteSelection(copy_to) end + +---@param copy_to _.wezterm.Clipboard +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CompleteSelectionOrOpenLinkAtMouseCursor(copy_to) end + +---@param copy_to _.wezterm.Clipboard +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CopyTo(copy_to) end + +---@param mode _.wezterm.CopyMode +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.CopyMode(mode) end + +---@param domain 'CurrentPaneDomain' | { DomainName: string } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.DetachDomain(domain) end + +---@param event string +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.EmitEvent(event) end + +---@param mode _.wezterm.SelectionMode +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ExtendSelectionToMouseCursor(mode) end + +---@param opts { title: string, choices: { id: string, label: string }[], action: _.wezterm._CallbackAction } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.InputSelector(opts) end + +---@param index number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.MoveTab(index) end + +---@param index number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.MoveTabRelative(index) end + +---@param actions _.wezterm._Action[] +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.Multiple(actions) end + +---@param opts { mode?: 'Activate' | 'SwapWithActive', alphabet?: string } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.PaneSelect(opts) end + +---@param source 'Clipboard' | 'PrimarySelection' +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.PasteFrom(source) end + +---@param opts { description: string, action: _.wezterm._CallbackAction } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.PromptInputLine(opts) end + +---@param args { patterns?: string[], alphabet?: string, action?: _.wezterm._Action, label?: string, scope_lines?: number } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.QuickSelectArgs(args) end + +---@param direction 'Clockwise' | 'CounterClockwise' +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.RotatePanes(direction) end + +---@param direction number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ScrollByLine(direction) end + +---@param direction number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ScrollByPage(direction) end + +---@param direction number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ScrollToPrompt(direction) end + +---@param pattern { Regex: string } | { CaseSensitiveString: string } | { CaseInSensitiveString: string } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.Search(pattern) end + +---@param mode _.wezterm.SelectionMode | 'SemanticZone' +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SelectTextAtMouseCursor(mode) end + +---@param key { key: string, mods: string } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SendKey(key) end + +---@param string string +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SendString(string) end + +---@param state boolean +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SetPaneZoomState(state) end + +---@param args { flags: string, title?: string } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.ShowLauncherArgs(args) end + +---@param args _.wezterm.SpawnCommand +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SpawnCommandInNewTab(args) end + +---@param args _.wezterm.SpawnCommand +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SpawnCommandInNewWindow(args) end + +---@param domain 'CurrentPaneDomain' | 'DefaultDomain' | { DomainName: string } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SpawnTab(domain) end + +---@param args _.wezterm.SpawnCommand +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SplitHorizontal(args) end + +---@param args { direction: 'Up' | 'Down' | 'Left' | 'Right', size?: { Cells: number } | { Percent: number }, command?: _.wezterm.SpawnCommand, top_level?: boolean } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SplitPane(args) end + +---@param args _.wezterm.SpawnCommand +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SplitVertical(args) end + +---@param args { name?: string, command?: _.wezterm.SpawnCommand } +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SwitchToWorkspace(args) end + +---@param direction number +---@return _.wezterm._KeyAssignmentAction +function KeyAssignment.SwitchWorkspaceRelative(direction) end + +---@class _.wezterm.ConfigBuilder +---@field adjust_window_size_when_changing_font_size boolean +---@field allow_square_glyphs_to_overflow_width 'WhenFollowedBySpace' | 'Always' | 'Never' +---@field allow_win32_input_mode boolean +---@field alternate_buffer_wheel_scroll_speed number +---@field animation_fps number +---@field audible_bell 'SystemBeep' | 'Disabled' +---@field automatically_reload_config boolean +---@field background _.wezterm.BackgroundLayer[] +---@field bold_brightens_ansi_colors boolean | 'No' | 'BrightAndBold' | 'BrightOnly' +---@field bypass_mouse_reporting_modifiers string +---@field canonicalize_pasted_newlines boolean | 'None' | 'LineFeed' | 'CarriageReturn' | 'CarriageReturnAndLineFeed' +---@field cell_width number +---@field check_for_updates boolean +---@field check_for_updates_interval_seconds number +---@field clean_exit_codes number[] +---@field color_scheme string +---@field color_schemes table +---@field colors _.wezterm.Palette +---@field command_palette_bg_color string +---@field command_palette_fg_color string +---@field command_palette_font_size number +---@field cursor_blink_ease_in _.wezterm.EasingFunction +---@field cursor_blink_ease_out _.wezterm.EasingFunction +---@field cursor_blink_rate number +---@field cursor_thickness number | string +---@field custom_block_glyphs boolean +---@field daemon_options { pid_file?: string, stdout?: string, stderr?: string } +---@field debug_key_events boolean +---@field default_cursor_style _.wezterm.CursorStyle +---@field default_cwd string +---@field default_domain 'local' | string +---@field default_gui_startup_args string[] +---@field default_prog string[] +---@field default_workspace 'default' | string +---@field detect_password_input boolean +---@field disable_default_key_bindings boolean +---@field disable_default_mouse_bindings boolean +---@field disable_default_quick_select_patterns boolean +---@field display_pixel_geometry 'RGB' | 'BGR' +---@field dpi number +---@field enable_csi_u_key_encoding boolean +---@field enable_kitty_keyboard boolean +---@field enable_scroll_bar boolean +---@field enable_tab_bar boolean +---@field enable_wayland boolean +---@field exit_behavior 'Close' | 'Hold' | 'CloseOnCleanExit' +---@field font _.wezterm._Font +---@field font_dirs string[] +---@field font_locator? 'ConfigDirsOnly' +---@field font_rasterizer 'FreeType' +---@field font_rules any[] +---@field font_shaper 'Harfbuzz' +---@field font_size number +---@field force_reverse_video_cursor boolean +---@field foreground_text_hsb _.wezterm.HsbTransform +---@field freetype_interpreter_version 35 | 38 | 40 +---@field freetype_load_flags string +---@field freetype_load_target _.wezterm.FreetypeLoadTarget +---@field freetype_pcf_long_family_names boolean +---@field freetype_render_target string +---@field front_end 'OpenGL' | 'Software' | 'WebGpu' +---@field harfbuzz_features string[] +---@field hide_mouse_cursor_when_typing boolean +---@field hide_tab_bar_if_only_one_tab boolean +---@field hyperlink_rules _.wezterm.HyperlinkRule[] +---@field ime_preedit_rendering 'Builtin' | 'System' +---@field inactive_pane_hsb _.wezterm.HsbTransform +---@field initial_cols number +---@field initial_rows number +---@field integrated_title_button_alignment 'Left' | 'Right' +---@field integrated_title_button_color 'Auto' | string +---@field integrated_title_button_style 'Windows' | 'Gnome' | 'MacOsNative' +---@field integrated_title_buttons ('Hide' | 'Maximize' | 'Close')[] +---@field key_map_preference 'Mapped' | 'Physical' +---@field key_tables table +---@field keys _.wezterm.KeyBinding[] +---@field launch_menu _.wezterm.SpawnCommand[] +---@field line_height number +---@field log_unknown_escape_sequences boolean +---@field macos_forward_to_ime_modifier_mask string +---@field macos_window_background_blur number +---@field max_fps number +---@field min_scroll_bar_height number | string +---@field mouse_bindings _.wezterm.MouseBinding[] +---@field mouse_wheel_scrolls_tabs boolean +---@field mux_env_remove string[] +---@field native_macos_fullscreen_mode boolean +---@field normalize_output_to_unicode_nfc boolean +---@field pane_focus_follows_mouse boolean +---@field prefer_egl boolean +---@field quick_select_alphabet string +---@field quick_select_patterns string[] +---@field quit_when_all_windows_are_closed boolean +---@field quote_dropped_files 'None' | 'SpacesOnly' | 'Posix' | 'Windows' | 'WindowsAlwaysQuoted' +---@field scroll_to_bottom_on_input boolean +---@field scrollback_lines number +---@field selection_word_boundary string +---@field send_composed_key_when_left_alt_is_pressed boolean +---@field send_composed_key_when_right_alt_is_pressed boolean +---@field serial_ports { name: string, port?: string, baud?: number }[] +---@field set_environment_variables table +---@field show_new_tab_button_in_tab_bar boolean +---@field show_tab_index_in_tab_bar boolean +---@field show_tabs_in_tab_bar boolean +---@field show_update_window boolean +---@field skip_close_confirmation_for_processes_named string[] +---@field ssh_backend 'Ssh2' | 'LibSsh' +---@field ssh_domains _.wezterm.SshDomain[] +---@field status_update_interval number +---@field strikethrough_position number | string +---@field swallow_mouse_click_on_pane_focus boolean +---@field swallow_mouse_click_on_window_focus boolean +---@field swap_backspace_and_delete boolean +---@field switch_to_last_active_tab_when_closing_tab boolean +---@field tab_and_split_indices_are_zero_based boolean +---@field tab_bar_at_bottom boolean +---@field tab_bar_style _.wezterm.TabBarStyle +---@field tab_max_width number +---@field term string +---@field text_background_opacity number +---@field text_blink_ease_in _.wezterm.EasingFunction +---@field text_blink_ease_out _.wezterm.EasingFunction +---@field text_blink_rapid_ease_in _.wezterm.EasingFunction +---@field text_blink_rapid_ease_out _.wezterm.EasingFunction +---@field text_blink_rate number +---@field text_blink_rate_rapid number +---@field tiling_desktop_environments string[] +---@field tls_clients _.wezterm.TlsDomainClient[] +---@field tls_servers _.wezterm.TlsDomainServer[] +---@field treat_east_asian_ambiguous_width_as_wide boolean +---@field treat_left_ctrlalt_as_altgr boolean +---@field ulimit_nofile number +---@field ulimit_nproc number +---@field underline_position number | string +---@field underline_thickness number | string +---@field unicode_version number +---@field unix_domains _.wezterm.MultiplexerDomain[] +---@field unzoom_on_switch_pane boolean +---@field use_cap_height_to_scale_fallback_fonts boolean +---@field use_dead_keys boolean +---@field use_fancy_tab_bar boolean +---@field use_ime boolean +---@field use_resize_increments boolean +---@field visual_bell _.wezterm.VisualBellConfig +---@field warn_about_missing_glyphs boolean +---@field webgpu_force_fallback_adapter boolean +---@field webgpu_power_preference 'LowPower' | 'HighPower' +---@field webgpu_preferred_adapter _.wezterm.GpuInfo +---@field win32_acrylic_accent_color string +---@field win32_system_backdrop 'Auto' | 'Disable' | 'Acrylic' | 'Mica' | 'Tabbed' +---@field window_background_image string +---@field window_background_image_hsb _.wezterm.HsbTransform +---@field window_background_gradient _.wezterm.Gradient[] +---@field window_background_opacity number +---@field window_close_confirmation 'NeverPrompt' | 'AlwaysPrompt' +---@field window_decorations string +---@field window_frame _.wezterm.WindowFrame +---@field window_padding _.wezterm.WindowPadding +---@field wsl_domains _.wezterm.WslDomain[] +---@field xim_im_name string +local ConfigBuilder = {} + +---@param strict_mode boolean +function ConfigBuilder:set_strict_mode(strict_mode) end diff --git a/.config/wezterm/util/init.lua b/.config/wezterm/util/init.lua new file mode 100644 index 0000000..cabee73 --- /dev/null +++ b/.config/wezterm/util/init.lua @@ -0,0 +1,24 @@ +local wezterm = require("wezterm") + +local M = {} + +M.merge_tables = function(a, b) + for k, v in pairs(b) do + if a[v] ~= nil then + wezterm.log_warn("Duplicate config option detected: ", { old = a[k], new = b[k]}) + end + a[k] = v + end +end + +M.get_schemes = function() + -- Only load color schemes once; store them for later use + local schemes = wezterm.GLOBAL.color_schemes + if schemes then + return schemes + end + wezterm.GLOBAL.color_schemes = wezterm.get_builtin_color_schemes() + return wezterm.GLOBAL.color_schemes +end + +return M diff --git a/.config/wezterm/wezterm.lua b/.config/wezterm/wezterm.lua new file mode 100644 index 0000000..2a41dbb --- /dev/null +++ b/.config/wezterm/wezterm.lua @@ -0,0 +1,6 @@ +local config = require('config') + +require("events.format_tab_title") +require("events.update_status") + +return config diff --git a/.config/xplr/init.lua b/.config/xplr/init.lua new file mode 100644 index 0000000..adcbcc8 --- /dev/null +++ b/.config/xplr/init.lua @@ -0,0 +1,54 @@ +version = "0.21.9" -- This needs to be global; ignore diagnostics that say otherwise + +---@diagnostic disable +local xplr = xplr +---@diagnostic enable + +-- General config +xplr.config.general.show_hidden = true + +-- This is necessary to be able to source lua files from within ~/.config/xplr +local home = os.getenv("HOME") +package.path = home + .. "/.config/xplr/?.lua;" + .. package.path + +-- Plugins +require("plugins") + +-- Preview +local preview = require("preview") +local split_preview = { + Horizontal = { + config = { + constraints = { + { Percentage = 60 }, + { Percentage = 40 }, + }, + }, + splits = { + "Table", + preview.preview_pane, + }, + }, +} +xplr.config.layouts.builtin.default = + xplr.util.layout_replace(xplr.config.layouts.builtin.default, "Table", split_preview) + +xplr.config.modes.builtin.default.key_bindings.on_key['*'] = { + help = "toggle exe", + messages = { + { + BashExecSilently0 = [===[ + f="$XPLR_FOCUS_PATH" + if [ -x "$f" ]; then + chmod -x "$f" + else + chmod +x "$f" + fi + "$XPLR" -m 'ExplorePwd' + "$XPLR" -m 'FocusPath: %q' "$f" + ]===], + }, + }, +} diff --git a/.config/xplr/plugins.lua b/.config/xplr/plugins.lua new file mode 100644 index 0000000..d2ad79d --- /dev/null +++ b/.config/xplr/plugins.lua @@ -0,0 +1,34 @@ +-- Plugins handled via xpm.xplr (https://github.com/dtomvan/xpm.xplr) + +local home = os.getenv("HOME") +local xpm_path = home .. "/.local/share/xplr/dtomvan/xpm.xplr" +local xpm_url = "https://github.com/dtomvan/xpm.xplr" + +package.path = package.path + .. ";" + .. xpm_path + .. "/?.lua;" + .. xpm_path + .. "/?/init.lua" + +os.execute( + string.format( + "[ -e '%s' ] || git clone '%s' '%s'", + xpm_path, + xpm_url, + xpm_path + ) +) + +require("xpm").setup({ + plugins = { + -- Let xpm manage itself + 'dtomvan/xpm.xplr', + -- Other plugins + 'gitlab:hartan/web-devicons.xplr', + 'sayanarijit/offline-docs.xplr', + 'duganchen/one-table-column.xplr', + }, + auto_install = true, + auto_cleanup = true +}) diff --git a/.config/xplr/preview.lua b/.config/xplr/preview.lua new file mode 100644 index 0000000..a19b34b --- /dev/null +++ b/.config/xplr/preview.lua @@ -0,0 +1,128 @@ +-- Implementation of file preview with support for syntax highlighting, +-- directory and archive contents, and images, +-- falling back to showing stats of unsupported files. +-- Requires bat for syntax highlighting (https://github.com/sharkdp/bat), +-- viu for image preview (https://github.com/atanunq/viu), +-- and ouch for archive preview (https://github.com/ouch-org/ouch) + +---@diagnostic disable +local xplr = xplr +---@diagnostic enable + +local M = {} + +local function mimetype(n) + return xplr.util.shell_execute("file", { "--brief", "--mime-type", n.absolute_path }).stdout:sub(1, -2) +end + +local function filetype(n) + local type = "other" + if n.is_file then + local mime = mimetype(n) + if (mime:match("text") or mime:match("json") or mime:match("csv") or mime:match("empty")) then + type = "text" + elseif (mime:match("zip") or mime:match("tar")) then + type = "archive" + elseif (mime:match("image")) then + type = "image" + end + elseif n.is_dir then + type = "directory" + end + return type +end + +local function stats(n) + return xplr.util.to_yaml(xplr.util.node(n.absolute_path)) +end + +local function endswith(s, suffix) + return s:sub(- #suffix) == suffix +end + +local function render_text(n, ctx) + local result = xplr.util.shell_execute("bat", + { "--color=always", "--style=plain", "--line-range=:" .. ctx.layout_size.height - 2, n.absolute_path }) + local out = (result.returncode == 0 and result.stdout) or stats(n) + -- Replace tabs with 4 spaces (for some reason tabs don't seem to render properly) + return out:gsub("\t", " ") +end + +local function render_image(n, ctx) + local result = xplr.util.shell_execute("viu", + { "--blocks", "--static", "--width", ctx.layout_size.width, n.absolute_path }) + return (result.returncode == 0 and result.stdout) or stats(n) +end + +local function render_directory(n, ctx) + local result = xplr.util.shell_execute("sh", + { "-c", "tree -aC --noreport " .. + xplr.util.shell_escape(n.absolute_path) .. "| head --lines=" .. ctx.layout_size.height - 1 .. "| tail +2" }) + return (result.returncode == 0 and result.stdout) or stats(n) +end + +local function render_archive(n, ctx) + -- To keep from lagging out xplr, + -- we only extract archives that are 10 MiB or less in size + -- (mibibytes, not megabytes, since that's what ls -h shows). + if n.size > 10485760 then + return stats(n) + end + local result = xplr.util.shell_execute("sh", + { "-c", "ouch list " .. + xplr.util.shell_escape(n.absolute_path) .. "| head --lines=" .. ctx.layout_size.height - 1 .. "| tail +2" }) + local out = (result.returncode == 0 and result.stdout) or stats(n) + -- Since ouch doesn't support forcing coloration in non-interactive terminals (a strange omission TBH), + -- we need to add the colors ourselves. + -- The following is a bit brittle, since it will break if a file for some reason ends in /, but eh. + local body = "" + for line in string.gmatch(out, "[^\n]+") do + -- Remove extra / from end of directories that head adds for whatever reason + if endswith(line, "//") then + line = line:sub(1, -2) + end + -- Directories end with a / and should be highlighted blue + if endswith(line, "/") then + local style = { fg = "Blue", bg = nil, add_modifiers = { "Bold" }, sub_modifiers = {} } + body = body .. xplr.util.paint(line, style) .. "\n" + else + body = body .. line .. "\n" + end + end + return body +end + +xplr.fn.custom.preview_pane = {} +xplr.fn.custom.preview_pane.render = function(ctx) + local title = nil + local body = "" + local n = ctx.app.focused_node + -- Follow symlinks + if n then + -- Symlinks to symlinks are a thing, so we must support that + while n.canonical do + n = n.canonical + end + end + + if n then + title = { format = n.absolute_path, style = xplr.util.lscolor(n.absolute_path) } + local type = filetype(n) + if type == "text" then + body = render_text(n, ctx) + elseif type == "image" then + body = render_image(n, ctx) + elseif type == "directory" then + body = render_directory(n, ctx) + elseif type == "archive" then + body = render_archive(n, ctx) + else + body = stats(n) + end + end + + return { CustomParagraph = { ui = { title = title }, body = body } } +end + +M.preview_pane = { Dynamic = "custom.preview_pane.render" } +return M