First commit

This commit is contained in:
James Dugan 2025-02-04 21:06:01 -07:00
commit 847c9e64c0
51 changed files with 4058 additions and 0 deletions

6
.config/bat/config Normal file
View file

@ -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"

20
.config/bat/setup.sh Executable file
View file

@ -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

63
.config/hilbish/carapace.lua Executable file
View file

@ -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

View file

@ -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

20
.config/hilbish/hinter.lua Executable file
View file

@ -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

9
.config/hilbish/homebrew.lua Executable file
View file

@ -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")

77
.config/hilbish/init.lua Executable file
View file

@ -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)

64
.config/hilbish/starship.lua Executable file
View file

@ -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

192
.config/hilbish/syntax.lua Executable file
View file

@ -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

20
.config/hilbish/utils.lua Executable file
View file

@ -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

388
.config/hilbish/vendor/json.lua vendored Executable file
View file

@ -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

View file

@ -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
}

View file

@ -0,0 +1,8 @@
map global normal <F2> :toggle-whitespace<ret>
map global normal <F4> :buffer-switcher<ret>
map global normal <F5> :xplr<ret>
map global normal <F6> :lazygit<ret>
map global user 'p' '<a-!>pbpaste<ret>' -docstring 'Paste from clipboard'
map global user 'P' '!pbpaste<ret>' -docstring 'Paste from clipboard'
map global user 'y' '<a-|>pbcopy<ret>' -docstring 'Yank to clipboard'

View file

@ -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
}

View file

@ -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 <space> ':focus-toggle<ret>' -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
}

View file

@ -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
}

View file

@ -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}"
$
@

View file

@ -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
}

View file

@ -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
}

View file

@ -0,0 +1,3 @@
hook global BufSetOption tree_sitter_lang=sh %{
set-option buffer tree_sitter_lang bash
}

View file

@ -0,0 +1,5 @@
hook global WinSetOption filetype=yaml %{
set-option global tabstop 2
set-option global indentwidth 2
softtab
}

47
.config/kak/kakrc Normal file
View file

@ -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

175
.config/kak/starship.toml Normal file
View file

@ -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

View file

@ -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 '"' (?<!\\)(\\\\)*" fill string
add-highlighter shared/capnp/code/ regex '(?i)\b0b[01]+l?\b' 0:value
add-highlighter shared/capnp/code/ regex '(?i)\b0x[\da-f]+l?\b' 0:value
add-highlighter shared/capnp/code/ regex '(?i)\b0o?[0-7]+l?\b' 0:value
add-highlighter shared/capnp/code/ regex '(?i)\b([1-9]\d*|0)l?\b' 0:value
add-highlighter shared/capnp/code/ regex '\b\d+[eE][+-]?\d+\b' 0:value
add-highlighter shared/capnp/code/ regex '(\b\d+)?\.\d+\b' 0:value
add-highlighter shared/capnp/code/ regex '\b\d+\.' 0:value
evaluate-commands %sh{
builtin_types="Void Bool Text Data List union group Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float32 Float64"
declarations="struct union enum interface const annotation"
keywords="using extends import"
values="true false inf"
join() { sep=$2; eval set -- $1; IFS="$sep"; echo "$*"; }
printf %s\\n "declare-option str-list capnp_static_words $(join "${builtin_types}" ' ') $(join "${declarations}" ' ') $(join "${keywords}" ' ') $(join "${values}" ' ')"
printf %s\\n "add-highlighter shared/capnp/code/ regex '\b($(join "${builtin_types}" '|'))\b' 0:type"
printf %s\\n "add-highlighter shared/capnp/code/ regex '\b($(join "${declarations}" '|'))\b' 0:keyword"
printf %s\\n "add-highlighter shared/capnp/code/ regex '\b($(join "${keywords}" '|'))\b' 0:keyword"
printf %s\\n "add-highlighter shared/capnp/code/ regex '\b($(join "${values}" '|'))\b' 0:value"
}
# Commands
# ‾‾‾‾‾‾‾‾
define-command -hidden capnp-trim-indent %{
# remove trailing white spaces
try %{ execute-keys -draft -itersel x s \h+$ <ret> 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 <a-h> <a-k> ^\h+[\]}]$ <ret> m <a-S> 1<a-&> >
>
>
define-command -hidden capnp-indent-on-new-line %<
evaluate-commands -draft -itersel %<
# preserve previous line indent
try %{ execute-keys -draft <semicolon> K <a-&> }
# filter previous line
try %{ execute-keys -draft k : capnp-trim-indent <ret> }
# indent after lines ending with opener token
try %< execute-keys -draft k x <a-k> [[{]\h*$ <ret> j <a-gt> >
# deindent closer token(s) when after cursor
try %< execute-keys -draft x <a-k> ^\h*[}\]] <ret> gh / [}\]] <ret> m <a-S> 1<a-&> >
>
>
@

View file

@ -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 '"' (?<!\\)(\\\\)*" fill string
add-highlighter shared/kdl/comment region -recurse /\* /\* \*/ fill comment
add-highlighter shared/kdl/line_comment region // $ fill comment
# Slashdash (/-) comments are annoying to highlight properly without a proper parser due to the fact that they can comment
# out any kdl construct..
# The below is, at best, an approximation, and there are almost certainly edge cases missed.
add-highlighter shared/kdl/slashdash_child region -recurse \{ /-[^\n]+\{ \} fill comment
add-highlighter shared/kdl/slashdash_string region '/-\s+"' (?<!\\)(\\\\)*" fill comment
add-highlighter shared/kdl/slashdash_raw_string region -match-capture '/-\s+r"(#*)' '"(#*)' fill comment
add-highlighter shared/kdl/slashdash_builtin_value region /-\s+(true|false|null) \s fill comment
add-highlighter shared/kdl/slashdash_binary region /-\s+0b[01_]+ \s fill comment
add-highlighter shared/kdl/slashdash_octal region /-\s+0o[0-7_]+ \s fill comment
add-highlighter shared/kdl/slashdash_hex region /-\s+0x[a-fA-F0-9_]+ \s fill comment
add-highlighter shared/kdl/slashdash_decimal region /-\s+[0-9-+][0-9_]* \s fill comment
add-highlighter shared/kdl/slashdash_float region /-\s+[0-9-+][0-9_]*\.[0-9_]+ \s fill comment
add-highlighter shared/kdl/slashdash_float_exp region /-\s+[0-9-+][0-9_]*(\.[0-9_]+)?[eE][-+]?[0-9_]+ \s fill comment
add-highlighter shared/kdl/slashdash_prop_string region '/-\s+[\u000021-\u00FFFF]+="' (?<!\\)(\\\\)*" fill comment
add-highlighter shared/kdl/slashdash_prop_raw_string region -match-capture '/-\s+[\u000021-\u00FFFF]+=r"(#*)' '"(#*)' fill comment
add-highlighter shared/kdl/slashdash_prop_other region /-\s+[\u000021-\u00FFFF]+= \s fill comment
add-highlighter shared/kdl/slashdash_node region /-\s+[\u000021-\u00FFFF]+ $ fill comment
add-highlighter shared/kdl/code/node regex \b([\u000021-\u00FFFF]*)\b 0:variable # Everything not covered below is a node
add-highlighter shared/kdl/code/property regex \b([\u000021-\u00FFFF]+)(=) 0:operator 1:attribute
add-highlighter shared/kdl/code/builtin_value regex \b(true|false|null)\b 0:value
add-highlighter shared/kdl/code/binary regex \b(0b[01_]+)\b 0:value
add-highlighter shared/kdl/code/octal regex \b(0o[0-7_]+)\b 0:value
add-highlighter shared/kdl/code/hex regex \b(0x[a-fA-F0-9_]+)\b 0:value
add-highlighter shared/kdl/code/decimal regex \b([0-9-+][0-9_]*)\b 0:value
add-highlighter shared/kdl/code/float regex \b([0-9-+][0-9_]*\.[0-9_]+)\b 0:value
add-highlighter shared/kdl/code/float_exp regex \b([0-9-+][0-9_]*(\.[0-9_]+)?[eE][-+]?[0-9_]+)\b 0:value
# Commands
# ‾‾‾‾‾‾‾‾
define-command -hidden kdl-trim-indent %{
# remove trailing white spaces
try %{ execute-keys -draft -itersel x s \h+$ <ret> 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 <a-h> <a-k> ^\h+[\]}]$ <ret> m <a-S> 1<a-&> >
>
>
define-command -hidden kdl-indent-on-new-line %<
evaluate-commands -draft -itersel %<
# preserve previous line indent
try %{ execute-keys -draft <semicolon> K <a-&> }
# filter previous line
try %{ execute-keys -draft k : kdl-trim-indent <ret> }
# indent after lines ending with opener token
try %< execute-keys -draft k x <a-k> [[{]\h*$ <ret> j <a-gt> >
# deindent closer token(s) when after cursor
try %< execute-keys -draft x <a-k> ^\h*[}\]] <ret> gh / [}\]] <ret> m <a-S> 1<a-&> >
>
>
@

View file

@ -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
}
}

View file

@ -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 %{(?<!\\)(?:\\\\)*\K"} %{(?<!\\)(?:\\\\)*"} group
add-highlighter shared/ssh/single_string region %{(?<!\\)(?:\\\\)*\K'} %{'} fill string
add-highlighter shared/ssh/comment region (?<!\\)(?:\\\\)*(?:^|\h)\K# '$' fill comment
add-highlighter shared/ssh/double_string/fill fill string
evaluate-commands %sh{
keywords="AddKeysToAgent AddressFamily AskPassGUI BatchMode BindAddress CanonicalDomains CanonicalizeFallbackLocal CanonicalizeHostname
CanonicalizeMaxDots CanonicalizePermittedCNAMEs ChallengeResponseAuthentication CheckHostIP Cipher Ciphers ClearAllForwardings
Compression CompressionLevel ConnectionAttempts ConnectTimeout ControlMaster ControlPath ControlPersist DynamicForward
EnableSSHKeysign EscapeChar ExitOnForwardFailure FingerprintHash ForwardAgent ForwardX11 ForwardX11Timeout ForwardX11Trusted
GatewayPorts GlobalKnownHostsFile GSSAPIAuthentication GSSAPIClientIdentity GSSAPIDelegateCredentials GSSAPIKeyExchange
GSSAPIRenewalForcesRekey GSSAPIServerIdentity GSSAPITrustDns HashKnownHosts Host HostbasedAuthentication HostbasedKeyTypes
HostKeyAlgorithms HostKeyAlias HostName IdentitiesOnly IdentityFile IgnoreUnknown IPQoS KbdInteractiveAuthentication
KbdInteractiveDevices KexAlgorithms KeychainIntegration LocalCommand LocalForward LogLevel MACs Match NoHostAuthenticationForLocalhost
NumberOfPasswordPrompts PasswordAuthentication PermitLocalCommand PKCS11Provider Port PreferredAuthentications Protocol ProxyCommand
ProxyJump ProxyUseFdpass PubkeyAuthentication RekeyLimit RemoteForward RequestTTY RevokedHostKeys RhostsRSAAuthentication
RSAAuthentication SendEnv ServerAliveCountMax ServerAliveInterval SmartcardDevice StreamLocalBindMask StreamLocalBindUnlink
StrictHostKeyChecking TCPKeepAlive Tunnel TunnelDevice UpdateHostKeys UseKeychain UsePrivilegedPort User UserKnownHostsFile
VerifyHostKeyDNS VisualHostKey XAuthLocation"
join() { sep=$2; eval set -- $1; IFS="$sep"; echo "$*"; }
printf %s\\n "declare-option str-list ssh_static_words $(join "${keywords}" ' ') $(join "${builtins}" ' ')"
printf %s\\n "add-highlighter shared/ssh/code/ regex (?<!-)\b($(join "${keywords}" '|'))\b(?!-) 0:keyword"
}
add-highlighter shared/ssh/code/ regex ^host\s+ 0:keyword
# Commands
# ‾‾‾‾‾‾‾‾
define-command -hidden ssh-insert-on-new-line %{ evaluate-commands -itersel -draft %{
execute-keys <semicolon>
try %{
evaluate-commands -draft -save-regs '/"' %{
# Ensure previous line is a comment
execute-keys -draft kxs^\h*#+\h*<ret>
# 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.*$ <ret> 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*$ <ret> 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 <a-k> ^\h*#+\h*\n\h*#+\h*$ <ret> <a-d>
} 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*$<ret> y
execute-keys -draft P
execute-keys -draft i<space>
}
}
}
}
# trim trailing whitespace on the previous line
try %{ execute-keys -draft k x s\h+$<ret> d }
}
} }
define-command -hidden ssh-indent-on-new-line %<
evaluate-commands -draft -itersel %<
# preserve previous line indent
try %{ execute-keys -draft <semicolon> K <a-&> }
# cleanup trailing whitespaces from previous line
try %{ execute-keys -draft k x s \h+$ <ret> d }
>
>
@

View file

@ -0,0 +1,7 @@
# https://github.com/jesseduffield/lazygit
define-command lazygit %{
popup lazygit
}
alias global lg lazygit

View file

@ -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}
}

View file

@ -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 "<c-f> <c-b> <c-d> <c-u> <pageup> <pagedown> ( ) m M <a-semicolon> n <a-n> N <a-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 </dev/null &
}
} -hidden
hook global FocusIn .* beacon
hook global WinCreate .* %{
lua %opt{beacon_keys_normal} %opt{beacon_keys_goto} %{
for key in string.gmatch(arg[1], "[^%s]+") do
kak.map("window", "normal", key, key .. ":beacon<ret>")
end
for key in string.gmatch(arg[2], "[^%s]+") do
kak.map("window", "goto", key, key .. ":beacon<ret>")
end
}
hook window RawKey '<mouse:press:left:.*>' beacon
}

View file

@ -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><a-k>\A\h+\z<ret><a-;>;%opt{indentwidth}@"
}}
hook buffer InsertDelete ' ' %{ try %{
execute-keys -draft 'h<a-h><a-k>\A\h+\z<ret>i<space><esc><lt>'
}}
}
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 " "
}
}

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
)

View file

@ -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)

View file

@ -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<string, _.wezterm.Palette>
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

View file

@ -0,0 +1,27 @@
---@meta
local gui = {}
---@return table<string, _.wezterm.KeyBinding[]>
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<string, _.wezterm.ScreenInformation>, main: _.wezterm.ScreenInformation, origin_x: number, origin_y: number, virtual_height: number, virtual_width: number }
function gui.screens() end
return gui

View file

@ -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<string, any>
GLOBAL = {},
---@type _.wezterm.KeyAssignment
action = {},
---@type string
config_dir = '',
---@type string
config_file = '',
---@type string
executable_dir = '',
---@type string
home_dir = '',
---@type table<string, string>
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<string, string>
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<string, _.wezterm.Palette>
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

View file

@ -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<string, string>, 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

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -0,0 +1,6 @@
local config = require('config')
require("events.format_tab_title")
require("events.update_status")
return config

54
.config/xplr/init.lua Normal file
View file

@ -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"
]===],
},
},
}

34
.config/xplr/plugins.lua Normal file
View file

@ -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
})

128
.config/xplr/preview.lua Normal file
View file

@ -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