diff --git a/config/fish/config.fish b/config/fish/config.fish index eafc85a..36c37ed 100644 --- a/config/fish/config.fish +++ b/config/fish/config.fish @@ -11,9 +11,9 @@ set -gx GOOGLE_DEFAULT_CLIENT_ID "no" set -gx GOOGLE_DEFAULT_CLIENT_SECRET "no" # Core settings -set -gx EDITOR "vim" -set -gx VISUAL "vim" -set -gx MANPAGER "vim +Man!" +set -gx EDITOR "vi" +set -gx VISUAL "vi" +set -gx MANPAGER "vi +Man!" set -gx BROWSER "firefox" set -gx COLORTERM "truecolor" @@ -40,7 +40,7 @@ set -gx FZF_DEFAULT_OPTS " --color=fg:#ffffff,header:#f38ba8,info:#cba6ac,pointer:#f5e0dc --color=marker:#f5e0dc,fg+:#cdd6f4,prompt:#cba6ac,hl+:#f38ba8" -set -gx FZF_DEFAULT_COMMAND "fdfind --exclude={.git,.cache,.xmake,.zig-cache,build,tmp,node_modules,elpa} --type f -H" +set -gx FZF_DEFAULT_COMMAND "fd --exclude={.git,.cache,.xmake,.zig-cache,build,tmp,node_modules,elpa} --type f -H" # ============================================================================== # PATH CONFIGURATION @@ -82,6 +82,7 @@ alias bat 'bat --theme="ansi" --paging=never' alias :q 'exit' alias files 'thunar .' alias fetch 'pfetch' +alias vi 'vis' # Custom shortcuts alias reload 'source ~/.config/fish/config.fish' diff --git a/config/vis/build.lua b/config/vis/build.lua new file mode 100644 index 0000000..969529c --- /dev/null +++ b/config/vis/build.lua @@ -0,0 +1,129 @@ +-- ~/.config/vis/build.lua +-- Runs the nearest build.sh, shows the output, and can jump to the first +-- Odin error. Loaded from visrc.lua. + +local M = {} + +-- args: list of flags passed through to build.sh, e.g. { 'run' } +function M.run(args) + -- find the nearest build.sh, searching upward from vis's working dir + local p = io.popen('pwd') + local dir = p and p:read('*l') + if p then p:close() end + while dir and dir ~= '' do + local f = io.open(dir .. '/build.sh', 'r') + if f then + f:close() + break + end + dir = dir:match('^(.*)/[^/]*$') + end + if not dir or dir == '' then + vis:info('No build.sh found in this directory or any parent') + return + end + + -- save the current buffer so the build sees your latest changes + local win = vis.win + if win and win.file and win.file.modified and win.file.path then + vis:command('w') + end + + -- shell-quote each flag and the directory + local quoted = {} + for _, a in ipairs(args) do + table.insert(quoted, "'" .. a:gsub("'", "'\\''") .. "'") + end + local argstr = table.concat(quoted, ' ') + local qdir = "'" .. dir:gsub("'", "'\\''") .. "'" + local display = ('./build.sh ' .. table.concat(args, ' ')):gsub('%s+$', '') + local qdisplay = "'" .. display:gsub("'", "'\\''") .. "'" + + local out_file = os.tmpname() + local status_file = os.tmpname() + local answer_file = os.tmpname() + + local script = table.concat({ + 'saved=$(stty -g)', + 'stty sane', + 'cd ' .. qdir .. ' || exit 1', + 'printf "\\n\\033[1m$ %s\\033[0m (in %s)\\n\\n" ' .. qdisplay .. ' ' .. qdir, + '{ if [ -x ./build.sh ]; then ./build.sh ' .. argstr + .. '; else bash ./build.sh ' .. argstr .. '; fi; echo $? > \'' + .. status_file .. "'; } 2>&1 | tee '" .. out_file .. "'", + "st=$(cat '" .. status_file .. "')", + 'if [ "$st" = 0 ]; then', + ' printf "\\n\\033[32m[build ok]\\033[0m enter: back to vis "', + 'else', + ' printf "\\n\\033[31m[build failed: exit %s]\\033[0m ' + .. 'enter: back to vis | e + enter: jump to first error " "$st"', + 'fi', + 'read -r ans', + "printf '%s' \"$ans\" > '" .. answer_file .. "'", + 'stty "$saved"', + }, '\n') + + -- leave the alternate screen so the build output lands in your normal + -- terminal scrollback, run it, then come back to vis + local tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[?1049l') tty:close() end + + os.execute('{\n' .. script .. '\n} /dev/tty 2>&1') + + tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[?1049h') tty:close() end + vis:redraw() + + -- read back exit status and the key you answered with + local f = io.open(status_file, 'r') + local status = f and f:read('*l') + if f then f:close() end + f = io.open(answer_file, 'r') + local answer = f and f:read('*l') + if f then f:close() end + + -- first Odin error: `file.odin(12:5)` (default) or `file.odin:12:5` (unix) + local path, line, col + f = io.open(out_file, 'r') + if f then + for l in f:lines() do + path, line, col = l:match('^%s*(.-%.odin)%((%d+):(%d+)%)') + if not path then + path, line, col = l:match('^%s*(.-%.odin):(%d+):(%d+)') + end + if path then break end + end + f:close() + end + if path and path:sub(1, 1) ~= '/' then path = dir .. '/' .. path end + + os.remove(out_file) + os.remove(status_file) + os.remove(answer_file) + + if status == '0' then + vis:info('build ok: ' .. display) + return + end + if not path then + vis:info('build failed: exit ' .. (status or '?')) + return + end + if answer ~= 'e' then + vis:info(string.format('build failed: first error at %s:%s', path, line)) + return + end + + -- jump to the error: open the file unless it's already the current one + local current = vis.win and vis.win.file and vis.win.file.path + if current ~= path then + if vis.win.file.modified then + vis:info('Buffer has unsaved changes — :w first (or use :e! manually)') + return + end + vis:command(string.format("e '%s'", path)) + end + vis.win.selection:to(tonumber(line), tonumber(col)) +end + +return M diff --git a/config/vis/fzf.lua b/config/vis/fzf.lua new file mode 100644 index 0000000..7349cb8 --- /dev/null +++ b/config/vis/fzf.lua @@ -0,0 +1,230 @@ +-- ~/.config/vis/fzf.lua +-- Pickers: fuzzy file finder, live ripgrep, terminal file manager. +-- Loaded from visrc.lua. Each function is self-contained on purpose. + +local M = {} + +-- height of the drop-down fzf panel at the top ('100%' = full screen) +M.height = '50%' + +-- --------------------------------------------------------------------------- +-- files: fuzzy-find a file, or create one from the query +-- enter open the highlighted file (or create the query if nothing matches) +-- ctrl-n new file named after the query, e.g. src/util/new.odin +-- --------------------------------------------------------------------------- +function M.files() + -- file list: fd, fdfind (Debian/Ubuntu), or plain find + local list = "find . -type f -not -path '*/.git/*' | sed 's|^\\./||'" + for _, name in ipairs({ 'fd', 'fdfind' }) do + local ok = os.execute('command -v ' .. name .. ' >/dev/null 2>&1') + if ok == true or ok == 0 then + list = name .. ' --type f --hidden --exclude .git' + break + end + end + + -- preview: bat, batcat (Debian/Ubuntu), or head + local preview = 'head -n 500 {}' + for _, name in ipairs({ 'bat', 'batcat' }) do + local ok = os.execute('command -v ' .. name .. ' >/dev/null 2>&1') + if ok == true or ok == 0 then + preview = name .. ' --color=always --style=numbers --line-range=:500 {}' + break + end + end + + local cmd = list .. ' | fzf' + .. ' --height=' .. M.height .. ' --layout=reverse --border' + .. " --prompt 'files> '" + .. ' --print-query --expect=ctrl-n' -- line 1: query, line 2: key + .. " --header 'enter: open · ctrl-n: new file from query'" + .. " --preview '" .. preview .. "'" + .. " --preview-window 'right:60%:border-left'" + .. " --bind 'ctrl-/:toggle-preview'" + .. " --bind 'shift-up:preview-up,shift-down:preview-down'" + + -- fzf's --height mode draws from the cursor down: start at the top-left + local tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[H') tty:close() end + + local handle = io.popen(cmd) + if not handle then + vis:info('fzf: failed to start') + return + end + local out = {} + for line in handle:lines() do table.insert(out, line) end + local _, _, code = handle:close() + + -- back onto the alternate screen (so quitting vis restores the + -- terminal), then repaint vis + tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[?1049h') tty:close() end + vis:redraw() + + if code == 130 then return end -- Esc / Ctrl-C + + local query, key, choice = out[1], out[2], out[3] + local is_new = key == 'ctrl-n' or not choice or choice == '' + local path = is_new and query or choice + if not path or path == '' then return end + + -- open in the current window, unless it's already the current file + local win = vis.win + local current = win and win.file and win.file.path + local same = current ~= nil + and (current == path or current:sub(-#path - 1) == '/' .. path) + if not same then + if win and win.file and win.file.modified then + vis:info('Buffer has unsaved changes — :w first (or use :e! manually)') + return + end + vis:command(string.format("e '%s'", path)) + end + + if is_new then + vis:info('New file: ' .. path .. ' (written to disk on :w)') + end +end + +-- --------------------------------------------------------------------------- +-- grep: live ripgrep search across the project, jump to the match +-- --------------------------------------------------------------------------- +function M.grep() + local ok = os.execute('command -v rg >/dev/null 2>&1') + if not (ok == true or ok == 0) then + vis:info('ripgrep (rg) not found on PATH') + return + end + + -- preview: bat/batcat with the match highlighted, or cat -n + -- {1} = path, {2} = line number (fields split on ':') + local preview = 'cat -n {1}' + for _, name in ipairs({ 'bat', 'batcat' }) do + local found = os.execute('command -v ' .. name .. ' >/dev/null 2>&1') + if found == true or found == 0 then + preview = name .. ' --color=always --style=numbers --highlight-line {2} {1}' + break + end + end + + -- don't run rg on an empty query (it would match every line) + local reload = '[ -n {q} ] && rg --column --line-number --no-heading' + .. ' --color=always --smart-case --hidden --glob "!.git" -- {q} || true' + + -- empty stdin: results only appear once you start typing + local cmd = ': | fzf' + .. ' --height=' .. M.height .. ' --layout=reverse --border' + .. " --prompt 'rg> '" + .. ' --ansi --disabled' -- let rg do the matching, not fzf + .. ' --delimiter :' + .. " --bind 'change:reload:" .. reload .. "'" + .. " --preview '" .. preview .. "'" + .. " --preview-window 'right:60%:border-left:+{2}/2'" -- centre match + .. " --bind 'ctrl-/:toggle-preview'" + .. " --bind 'shift-up:preview-up,shift-down:preview-down'" + + -- fzf's --height mode draws from the cursor down: start at the top-left + local tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[H') tty:close() end + + local handle = io.popen(cmd) + if not handle then + vis:info('fzf: failed to start') + return + end + local choice = handle:read('*l') + handle:close() + + -- back onto the alternate screen, then repaint vis + tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[?1049h') tty:close() end + vis:redraw() + + if not choice or choice == '' then return end + + choice = choice:gsub('\27%[[%d;]*m', '') -- strip any colour codes + local path, line, col = choice:match('^(.-):(%d+):(%d+):') + if not path then return end + + -- open in the current window, unless it's already the current file + local win = vis.win + local current = win and win.file and win.file.path + local same = current ~= nil + and (current == path or current:sub(-#path - 1) == '/' .. path) + if not same then + if win and win.file and win.file.modified then + vis:info('Buffer has unsaved changes — :w first (or use :e! manually)') + return + end + vis:command(string.format("e '%s'", path)) + end + + vis.win.selection:to(tonumber(line), tonumber(col)) +end + +-- --------------------------------------------------------------------------- +-- fm: browse/create/rename/delete in a terminal file manager, then open the +-- file you pick. Uses the first one found: yazi, lf, nnn, ranger +-- --------------------------------------------------------------------------- +function M.fm() + local tmp = os.tmpname() + local managers = { + { 'yazi', "yazi --chooser-file='%s'" }, + { 'lf', "lf -selection-path '%s'" }, + { 'nnn', "nnn -p '%s'" }, + { 'ranger', "ranger --choosefile='%s'" }, + } + + local cmd + for _, m in ipairs(managers) do + local ok = os.execute('command -v ' .. m[1] .. ' >/dev/null 2>&1') + if ok == true or ok == 0 then + cmd = string.format(m[2], tmp) + break + end + end + if not cmd then + os.remove(tmp) + vis:info('No file manager found (install yazi, lf, nnn or ranger)') + return + end + + os.execute(cmd .. ' /dev/tty 2>&1') + + -- back onto the alternate screen, then repaint vis + local tty = io.open('/dev/tty', 'w') + if tty then tty:write('\27[?1049h') tty:close() end + vis:redraw() + + local f = io.open(tmp, 'r') + local path = f and f:read('*l') + if f then f:close() end + os.remove(tmp) + if not path or path == '' then return end + + -- open in the current window, unless it's already the current file + local win = vis.win + local current = win and win.file and win.file.path + if current ~= path then + if win and win.file and win.file.modified then + vis:info('Buffer has unsaved changes — :w first (or use :e! manually)') + return + end + vis:command(string.format("e '%s'", path)) + end +end + +-- --------------------------------------------------------------------------- +-- create missing parent directories on save, so a new file from ctrl-n like +-- src/util/new.odin can be written even if src/util/ doesn't exist yet +-- --------------------------------------------------------------------------- +vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file, path) -- luacheck: no unused args + local dir = path and path:match('^(.*)/[^/]+$') + if dir and dir ~= '' then + os.execute("mkdir -p '" .. dir:gsub("'", "'\\''") .. "'") + end + return true +end) + +return M diff --git a/config/vis/lexers/odin.lua b/config/vis/lexers/odin.lua new file mode 100644 index 0000000..0bb5a30 --- /dev/null +++ b/config/vis/lexers/odin.lua @@ -0,0 +1,100 @@ +-- Copyright 2026 Artur Ugnivenko. See LICENSE. +-- Odin LPeg lexer. + +-- References: +-- https://odin-lang.org/spec/grammar/ +-- https://pkg.odin-lang.org/base/builtin/ + +local lexer = lexer +local P, S = lpeg.P, lpeg.S + +local lex = lexer.new(...) + +-- Keywords. +lex:add_rule('keyword', lex:tag(lexer.KEYWORD, lex:word_match(lexer.KEYWORD))) + +-- Types. +lex:add_rule('type', lex:tag(lexer.TYPE, lex:word_match(lexer.TYPE))) + +-- Functions. +local builtin_func = -lpeg.B('.') * + lex:tag(lexer.FUNCTION_BUILTIN, lex:word_match(lexer.FUNCTION_BUILTIN)) +local func = lex:tag(lexer.FUNCTION, lexer.word) +lex:add_rule('function', (builtin_func + func) * #P('(')) + +-- Constants. +lex:add_rule('constant', lex:tag(lexer.CONSTANT_BUILTIN, lex:word_match(lexer.CONSTANT_BUILTIN))) + +-- Variables. +lex:add_rule('variable', lex:word_match(lexer.VARIABLE_BUILTIN)) + +-- Identifiers. +lex:add_rule('identifier', lex:tag(lexer.IDENTIFIER, lexer.word)) + +-- Strings. +local sq_str = lexer.range("'") +local dq_str = lexer.range('"') +local raw_str = lexer.range('`') +lex:add_rule('string', lex:tag(lexer.STRING, P('L')^-1 * (sq_str + dq_str + raw_str))) + +-- Comments. +local comment = lexer.to_eol(P('//') + '#!', true) +local block_comment = lexer.range('/*', '*/', false, false, true) +local file_tag = lexer.to_eol('#+') +lex:add_rule('comment', lex:tag(lexer.COMMENT, comment + block_comment + file_tag)) + +-- Directives. +lex:add_rule('directive', lex:tag(lexer.PREPROCESSOR, '#' * S(' \t')^0 * lexer.word)) + +-- Attributes. +lex:add_rule('attribute', lex:tag(lexer.PREPROCESSOR, '@' * lexer.word^-1)) + +-- Numbers. +lex:add_rule('number', lex:tag(lexer.NUMBER, lexer.number * S('ijk')^-1)) + +-- Operators. +lex:add_rule('operator', lex:tag(lexer.OPERATOR, '..' + S('+-/*%<>!=^&|?~:;,.()[]{}'))) + +-- Fold points. +lex:add_fold_point(lexer.OPERATOR, '(', ')') +lex:add_fold_point(lexer.OPERATOR, '[', ']') +lex:add_fold_point(lexer.OPERATOR, '{', '}') +lex:add_fold_point(lexer.COMMENT, '/*', '*/') + +-- Word lists. +lex:set_word_list(lexer.KEYWORD, { + 'asm', 'auto_cast', 'bit_field', 'bit_set', 'break', 'case', 'cast', 'continue', 'defer', + 'distinct', 'do', 'dynamic', 'else', 'fallthrough', 'for', 'foreign', 'if', 'import', 'in', 'map', + 'matrix', 'not_in', 'of_break', 'or_continue', 'or_else', 'or_return', 'package', 'proc', + 'return', 'switch', 'transmute', 'typeid', 'using', 'when', 'where', 'enum', 'struct', 'union' +}) + +lex:set_word_list(lexer.TYPE, { + 'any', 'b8', 'b16', 'b32', 'b64', 'bool', 'byte', 'complex32', 'complex64', 'complex128', + 'cstring', 'cstring16', 'f16', 'f16le', 'f16be', 'f32', 'f32le', 'f32be', 'f64', 'f64le', 'f64be', + 'i8', 'i16', 'i16le', 'i16be', 'i32', 'i32le', 'i32be', 'i64', 'i64le', 'i64be', 'int', + 'quaternion64', 'quaternion128', 'quaternion256', 'rawptr', 'rune', 'string', 'string16', + 'typeid', 'u8', 'u16', 'u16le', 'u16be', 'u32', 'u32le', 'u32be', 'u64', 'u64le', 'u64be', 'uint', + 'uintptr' +}) + +lex:set_word_list(lexer.FUNCTION_BUILTIN, { + 'abs', 'align_of', 'cap', 'clamp', 'complex', 'compress_values', 'conj', 'expand_values', 'imag', + 'jmag', 'kmag', 'len', 'max', 'min', 'offset_of', 'offset_of_by_string', 'offset_of_member', + 'offset_of_selector', 'quaternion', 'raw_data', 'real', 'size_of', 'soa_unzip', 'soa_zip', + 'swizzle', 'type_info_of', 'type_of', 'typeid_of' +}) + +lex:set_word_list(lexer.CONSTANT_BUILTIN, { + 'false', 'true', 'nil', 'ODIN_ARCH', 'ODIN_BUILD_MODE', 'ODIN_COMPILE_TIMESTAMP', 'ODIN_DEBUG', + 'ODIN_DEFAULT_TO_NIL_ALLOCATOR', 'ODIN_DEFAULT_TO_PANIC_ALLOCATOR', 'ODIN_DISABLE_ASSERT', + 'ODIN_ENDIAN', 'ODIN_ERROR_POS_STYLE', 'ODIN_NO_CRT', 'ODIN_NO_ENTRY_POINT', 'ODIN_NO_RTTI', + 'ODIN_OS', 'ODIN_PLATFORM_SUBTARGET', 'ODIN_ROOT', 'ODIN_VENDOR', 'ODIN_VERSION', + 'ODIN_WINDOWS_SUBSYSTEM' +}) + +lex:set_word_list(lexer.VARIABLE_BUILTIN, { + 'context', 'runtime' +}) + +return lex diff --git a/config/vis/themes/custom.lua b/config/vis/themes/custom.lua new file mode 100644 index 0000000..a6f191d --- /dev/null +++ b/config/vis/themes/custom.lua @@ -0,0 +1,59 @@ +-- vis-minimal-jellybeans-soft +-- Dark neutral background, warm off-white, and muted, low-brightness accents + +local bg_dark = '#131313' -- Dark off-black background instead of harsh pure black +local black1 = '#303030' +local black2 = '#585858' + +local offwhite0 = '#b9b9b9' -- Softened off-white base (reduces glare) +local offwhite1 = '#b0b0b0' +local offwhite2 = '#888888' + +local clear0 = '#00000000' + +-- Darkened, lower-contrast Jellybeans accents +local jelly_yellow_muted = '#d9b36a' -- Subdued warm yellow (Methods / Functions) +local jelly_blue_muted = '#75a0bc' -- Muted ice blue (Types / Classes) + +local lexers = vis.lexers + +-- Default Softened Base +lexers.STYLE_DEFAULT = 'back:'..clear0..',fore:'..offwhite0 +lexers.STYLE_NOTHING = 'back:'..bg_dark +lexers.STYLE_COMMENT = 'fore:'..black2 +lexers.STYLE_ERROR = 'fore:'..offwhite0 +lexers.STYLE_WHITESPACE = '' +lexers.STYLE_EMBEDDED = 'back:'..black1 + +-- The ONLY Colored Highlights (Deepened / Softened) +lexers.STYLE_FUNCTION = 'fore:'..jelly_yellow_muted +lexers.STYLE_TYPE = 'fore:'..jelly_blue_muted +lexers.STYLE_CLASS = 'fore:'..jelly_blue_muted + +-- Neutral / Off-White Text +lexers.STYLE_VARIABLE = 'fore:'..offwhite0 +lexers.STYLE_IDENTIFIER = 'fore:'..offwhite0 +lexers.STYLE_KEYWORD = 'fore:'..offwhite2 +lexers.STYLE_CONSTANT = 'fore:'..offwhite0 +lexers.STYLE_DEFINITION = 'fore:'..offwhite0 +lexers.STYLE_LABEL = 'fore:'..offwhite0 +lexers.STYLE_NUMBER = 'fore:'..offwhite1 +lexers.STYLE_OPERATOR = 'fore:'..offwhite0 +lexers.STYLE_REGEX = 'fore:'..offwhite1 +lexers.STYLE_STRING = 'fore:'..offwhite1 +lexers.STYLE_PREPROCESSOR= 'fore:'..offwhite0 +lexers.STYLE_TAG = 'fore:'..offwhite0 + +-- Editor Interface UI +lexers.STYLE_LINENUMBER = 'fore:'..black2 +lexers.STYLE_LINENUMBER_CURSOR = 'fore:'..offwhite1 +lexers.STYLE_CURSOR = 'back:'..offwhite2 +lexers.STYLE_CURSOR_PRIMARY = lexers.STYLE_CURSOR..',fore:'..bg_dark +lexers.STYLE_CURSOR_LINE = 'underlined' +lexers.STYLE_COLOR_COLUMN = 'back:'..black1 +lexers.STYLE_SELECTION = 'back:'..black1 +lexers.STYLE_STATUS = 'reverse' +lexers.STYLE_STATUS_FOCUSED = 'back:'..black1..',fore:'..offwhite1 +lexers.STYLE_SEPARATOR = lexers.STYLE_DEFAULT +lexers.STYLE_INFO = 'fore:default,back:default' +lexers.STYLE_EOF = '' diff --git a/config/vis/visrc.lua b/config/vis/visrc.lua new file mode 100644 index 0000000..71d6b5f --- /dev/null +++ b/config/vis/visrc.lua @@ -0,0 +1,51 @@ +-- load the standard vis module (provides the Lua API) +require('vis') + +-- ~/.config/vis/fzf.lua and ~/.config/vis/build.lua +local fzf = require('fzf') +local build = require('build') + +-- --------------------------------------------------------------------------- +-- Odin syntax highlighting (lexer lives in ~/.config/vis/lexers/odin.lua) +-- --------------------------------------------------------------------------- +if vis.ftdetect then + if vis.ftdetect.extensions then -- newer vis (git master) + vis.ftdetect.extensions.odin = 'odin' + end + if vis.ftdetect.filetypes then -- vis 0.9 and earlier + vis.ftdetect.filetypes.odin = { ext = { '%.odin$' } } + end +end + +-- --------------------------------------------------------------------------- +-- Global options, key mappings and commands +-- --------------------------------------------------------------------------- +vis.events.subscribe(vis.events.INIT, function() + vis:command('set escdelay 15') + vis:command('set autoindent on') + vis:command('set theme custom') + + -- pickers + vis:map(vis.modes.NORMAL, '', fzf.files, 'Fuzzy find / create a file') + vis:map(vis.modes.NORMAL, '', fzf.grep, 'Live grep the project with ripgrep') + vis:command_register('files', function() fzf.files() return true end, 'Fuzzy find / create a file') + vis:command_register('grep', function() fzf.grep() return true end, 'Live grep the project with ripgrep') + vis:command_register('fm', function() fzf.fm() return true end, 'Pick a file with a terminal file manager') + + vis:map(vis.modes.NORMAL, '', function() build.run({}) end, 'Run ./build.sh') + vis:command_register('build', function(argv) + local args = {} + for i = 1, #argv do table.insert(args, argv[i]) end + build.run(args) + return true + end, 'Run ./build.sh with optional flags, e.g. :build run') +end) + +-- --------------------------------------------------------------------------- +-- Per-window options +-- --------------------------------------------------------------------------- +vis.events.subscribe(vis.events.WIN_OPEN, function(win) -- luacheck: no unused args + vis:command('set tabwidth 4') + vis:command('set expandtab on') + vis:command('set number on') +end) diff --git a/config/yazi/theme.toml b/config/yazi/theme.toml new file mode 100644 index 0000000..b63ebb9 --- /dev/null +++ b/config/yazi/theme.toml @@ -0,0 +1,33 @@ +# ~/.config/yazi/theme.toml +# Minimal status bar: same colours as the default, as text only. +# Anything not set here falls back to yazi's built-in theme. + +[mode] +# mode label (NOR / SEL / UNS) and position counter +normal_main = { fg = "blue", bold = true } +select_main = { fg = "red", bold = true } +unset_main = { fg = "red", bold = true } + +# file size and Top/Bot/% segments +normal_alt = { fg = "blue" } +select_alt = { fg = "red" } +unset_alt = { fg = "red" } + +[status] +overall = {} + +# no powerline arrows between segments +sep_left = { open = "", close = "" } +sep_right = { open = "", close = "" } + +# permissions (unchanged from default) +perm_sep = { fg = "darkgray" } +perm_type = { fg = "green" } +perm_read = { fg = "yellow" } +perm_write = { fg = "red" } +perm_exec = { fg = "cyan" } + +# task progress bar, without the black track behind it +progress_label = { bold = true } +progress_normal = { fg = "green" } +progress_error = { fg = "red" } diff --git a/install.sh b/install.sh index 905e764..e2d15b4 100755 --- a/install.sh +++ b/install.sh @@ -87,8 +87,9 @@ if [ "$DO_LINKS" = true ]; then link_file "$DOTFILES_DIR/config/niri/config.kdl" "$HOME/.config/niri/config.kdl" link_file "$DOTFILES_DIR/config/niri/dms/binds.kdl" "$HOME/.config/niri/dms/binds.kdl" link_file "$DOTFILES_DIR/config/fish/config.fish" "$HOME/.config/fish/config.fish" - link_file "$DOTFILES_DIR/config/vim" "$HOME/.vim" link_file "$DOTFILES_DIR/config/kanata" "$HOME/.config/kanata" + link_file "$DOTFILES_DIR/config/vis" "$HOME/.config/vis" + link_file "$DOTFILES_DIR/config/yazi" "$HOME/.config/yazi" link_file "$DOTFILES_DIR/scripts/bin" "$HOME/.local/bin" echo "" @@ -151,10 +152,11 @@ if [ "$DO_INSTALL" = true ]; then # network & download wget curl ca-certificates gnupg rsync # core utilities & CLI tools - git vim fd jq fzf ripgrep tree direnv make bat - ark unzip p7zip tar gzip bzip2 xz kanata gitu + git vis yazi fd jq fzf ripgrep tree direnv make + bat ark unzip p7zip tar gzip bzip2 xz kanata # build & dev tools alacritty base-devel valgrind tree-sitter-cli go nodejs + # cli text editing ) MISSING_PACKAGES=()