Files
dotfiles/vis/.config/vis/visrc.lua

381 lines
10 KiB
Lua

require('vis')
require('fast-jump')
local plug = (function()
if not pcall(require, 'plugins/vis-plug') then
os.execute('git clone --quiet https://github.com/erf/vis-plug ' ..
(os.getenv('XDG_CONFIG_HOME') or os.getenv('HOME') .. '/.config')
.. '/vis/plugins/vis-plug')
end
return require('plugins/vis-plug')
end)()
plug = require('plugins/vis-plug')
local plugins = {
{ 'https://gitlab.com/muhq/vis-lspc', alias = 'lspc' },
{ 'lutobler/vis-commentary' },
{ 'https://repo.or.cz/vis-surround.git' },
{ 'peaceant/vis-fzf-mru', file = 'fzf-mru', alias = 'fzfmru' },
{ 'https://gitlab.com/muhq/vis-build' },
{ 'erf/vis-cursors' },
}
plug.init(plugins, true)
vis.ftdetect.filetypes.go_ext = vis.ftdetect.filetypes.go
vis.ftdetect.filetypes.go = nil
plug.plugins.lspc.ls_map.go_ext = plug.plugins.lspc.ls_map.go
vis.ftdetect.filetypes.templ = {
ext = { "%.templ$" },
}
plug.plugins.lspc.message_level = 2
plug.plugins.lspc.ls_map.templ = {
name = 'templ-lsp',
cmd = 'templ lsp',
}
plug.plugins.fzfmru.fzfmru_history = 60
local function open_file(file, cmd)
vis:command((cmd or 'o') .. ' ' .. file)
end
local function nil_or_tonumber(s)
return s and tonumber(s)
end
local function open_file_pos(line, open_cmd)
local iter = line:gmatch('[^:]+')
local file = iter()
local ln = iter()
local col = nil_or_tonumber(iter()) or 1
local i = ln and ln:find(' ')
if i then
ln = ln:sub(0, i)
col = 1
end
local line_num = nil_or_tonumber(ln)
if open_cmd ~= 'e' or vis.win.file ~= file then
open_file(file, open_cmd)
end
if line_num ~= nil then
vis.win.selection:to(line_num, col)
end
end
local function open_file_current_line(open_cmd, keys)
local line = vis.win.file.lines[vis.win.selection.line]
vis:info(line)
if keys then
vis:feedkeys(keys)
end
open_file_pos(line, open_cmd)
end
local function escape_and_quoted(s)
return "'" .. s:gsub("'", [['"'"']]) .. "'"
end
local function cmd_action(cmd, action)
local code, out, err = vis:pipe(cmd, true)
if code == 0 then
action(out)
elseif err ~= nil then
vis:info(err)
elseif code ~= 0 then
vis:info('Program exit code ' .. code)
end
end
local function fzf_sh(arg, query)
action = function(out)
if (out:find('\n') or #out) == #out then
open_file_pos(out, vis.win.file.modified and 'o' or 'e')
else
vis:message(out)
end
end
local home = os.getenv('HOME')
local path = vis.win.file.path or ''
local dir = path:match('^.*/') or ''
if not query and vis.register ~= '"' then
query = string.gsub(vis.registers[vis.register][1], '%z', '')
end
local cmd = home ..
'/.config/vis/fzf.sh ' ..
escape_and_quoted(arg) .. ' ' .. escape_and_quoted(dir) .. ' ' .. escape_and_quoted(query or '')
cmd_action(cmd, action)
end
vis:command_register('fzf-files', function(argv, force, win, selection, range)
fzf_sh(argv[1] or 'auto-files', argv[2])
end)
local function search(cmd, action)
if action == nil then
action = function(out)
if (out:find('\n') or #s) == #s then
open_file_pos(out, 'e')
else
vis:message(out)
end
end
end
if cmd:match('^fzf ') and vis.register ~= '"' then
local reg = string.gsub(vis.registers[vis.register][1], '%z', '')
if reg ~= '' then
cmd = cmd .. ' --query=' .. escape_and_quoted(reg)
end
end
cmd_action(cmd, action)
end
local file_slots = {}
local function set_file_slot(num)
local file = vis.win.file.path
if file ~= nil then
file_slots[num] = file
vis:info('File slot [' .. num .. '] updated')
else
vis:info('Window has no file')
end
end
local function open_file_slot(num, open_cmd)
local file = file_slots[num]
if file == nil then
vis:info('File slot [' .. num .. '] empty')
elseif file == vis.win.file.path then
vis:info('File slot [' .. num .. '] is the same file, no file change')
else
vis:info('File slot [' .. num .. '] open')
open_file(file, open_cmd)
end
end
local function fzf_reload(cmd)
local prompt = escape_and_quoted('1. ' .. cmd:match('^%w*') .. '> ')
if not cmd:match('{q}') then
cmd = cmd .. ' {q}'
end
return 'fzf --ansi --bind "start:reload:' .. cmd .. '" --bind "change:reload:' .. cmd .. ' || true"' ..
' --prompt ' .. prompt ..
' --bind "alt-enter:unbind(change,alt-enter)+change-prompt(2. fzf> )+enable-search+clear-query"'
end
local function add_global_mark()
local file = vis.win.file.path
if file ~= nil then
local code, out, err = vis:pipe('vis-menu -p "global mark comment:"', true)
if code == 0 then
local prefix = file .. ':' .. vis.win.selection.line .. ':' .. vis.win.selection.col .. ': '
local line = vis.win.file.lines[vis.win.selection.line]
out = out:gsub('\n$', '')
if out ~= '' then
prefix = prefix .. '(' .. out .. '): '
end
out = io.open(os.getenv('HOME') .. '/.config/vis/global-marks.txt', 'a')
out:write(prefix .. line .. '\n')
out:close()
elseif err ~= nil then
vis:info(err)
elseif code ~= 0 then
vis:info('Program exit code ' .. code)
end
else
vis:info('Save file first')
end
end
local lfs = require('lfs')
local theme_modification = 0
local last_theme = 'default'
function set_current_theme()
local path = os.getenv('HOME') .. '/.config/xsettingsd/xsettingsd.conf'
local m = lfs.attributes(path, 'modification')
if m == theme_modification then
return
end
theme_modification = m
local f = io.open(path)
if f then
local s = f:read('*all')
f:close()
local theme = s:match('light') and 'light' or 'dark'
if theme == last_theme then
return
end
last_theme = theme
if theme == 'light' then
vis:command('set theme lupan-light')
else
vis:command('set theme lupan-dark')
end
end
end
local ripgrep = 'rg --column --line-number --color=always --smart-case'
local function close_prev_win()
vis:feedkeys('<vis-window-prev>')
if vis.win == win then
vis:info('Last window')
elseif not vis.win:close() then
if vis.win.file.modified then
vis:info('No write since last change')
else
vis:command('q')
end
end
end
local function close_next_win()
vis:feedkeys('<vis-window-next>')
if vis.win == win then
vis:info('Last window')
elseif not vis.win:close() then
if vis.win.file.modified then
vis:info('No write since last change')
else
vis:command('q')
end
end
end
vis.events.subscribe(vis.events.INIT, function()
vis:command('set autoindent')
vis:command_register('search', function(argv, force, win, selection, range)
search(argv[1])
end)
vis:map(vis.modes.NORMAL, '<M-k>', '<vis-window-prev>')
vis:map(vis.modes.NORMAL, '<M-j>', '<vis-window-next>')
vis:map(vis.modes.NORMAL, ' K', close_prev_win)
vis:map(vis.modes.NORMAL, ' J', close_next_win)
vis:map(vis.modes.NORMAL, ' [', ':lspc-prev-diagnostic<Enter>')
vis:map(vis.modes.NORMAL, ' ]', ':lspc-next-diagnostic<Enter>')
vis:map(vis.modes.NORMAL, ' =', ':lspc-format<Enter>')
for num = 1, 9 do
vis:map(vis.modes.NORMAL, ' r' .. num, function() set_file_slot(num) end, 'set file slot ' .. num)
vis:map(vis.modes.NORMAL, ' ' .. num, function() open_file_slot(num, 'e') end, 'open file slot ' .. num)
vis:map(vis.modes.NORMAL, ' h' .. num, function() open_file_slot(num, 'o') end, 'open file slot ' .. num)
vis:map(vis.modes.NORMAL, ' v' .. num, function() open_file_slot(num, 'vsplit') end,
'open file slot ' .. num)
end
vis:map(vis.modes.NORMAL, ' s', ':fzf-files auto-search<Enter>', 'fzf: search')
vis:map(vis.modes.NORMAL, ' f', ':fzf-files auto-files<Enter>', 'fzf: files')
vis:map(vis.modes.NORMAL, ' /', function()
search(fzf_reload(ripgrep .. ' --with-filename {q} ' .. escape_and_quoted(vis.win.file.path)))
end, 'fzf: rg current file')
vis:map(vis.modes.NORMAL, ' .', function()
local shell = os.getenv('SHELL')
vis:command('!' .. shell)
end, 'run shell')
vis:map(vis.modes.NORMAL, ' ds', function()
local shell = os.getenv('SHELL')
local path = vis.win.file.path
if path then
local dir = path:match('^.*/')
local arg = escape_and_quoted(dir)
vis:command('!cd ' .. arg .. ' && ' .. shell)
else
vis:command('!' .. shell)
end
end, 'run shell in file directory')
vis:map(vis.modes.NORMAL, ' gl', function()
vis:command('!lazygit')
end, 'lazygit')
vis:map(vis.modes.NORMAL, ' gj', function()
vis:command('!lazyjj')
end, 'lazyjj')
vis:map(vis.modes.NORMAL, ' ', function()
vis:command('fzfmru')
end, 'fzf recent')
vis:map(vis.modes.NORMAL, ' w', function()
open_file_current_line('e')
end, 'open file from current line in current window (with optional line and col)')
vis:map(vis.modes.NORMAL, ' o', function()
open_file_current_line('o')
end, 'open file from current line in new window (with optional line and col)')
vis:map(vis.modes.NORMAL, ' k', function()
open_file_current_line('e', '<vis-window-prev>')
end, 'open file from current line in above window (with optional line and col)')
vis:map(vis.modes.NORMAL, ' j', function()
open_file_current_line('e', '<vis-window-next>')
end, 'open file from current line in below window (with optional line and col)')
vis:map(vis.modes.NORMAL, ' c', function()
search('zoxide query -l | fzf', function(path)
vis:command('cd ' .. path)
end)
end, 'fzf change directory')
vis:map(vis.modes.NORMAL, ' l', ':!lf<Enter>', 'lf file manager')
vis:map(vis.modes.NORMAL, ' L', function()
local path = vis.win.file.path
if path then
vis:command('!lf ' .. escape_and_quoted(path:match('^.*/')))
else
vis:command('!lf')
end
end, 'lf file manager in current file directory')
vis:map(vis.modes.NORMAL, ' ma', add_global_mark, 'global marks: add')
vis:map(vis.modes.NORMAL, ' mj', function()
search('cat ~/.config/vis/global-marks.txt | fzf --tac')
end, 'global marks: jump')
vis:map(vis.modes.NORMAL, ' me', function()
vis:command('o ~/.config/vis/global-marks.txt')
end, 'global marks: edit')
vis:map(vis.modes.NORMAL, ' td', function()
vis:command('set theme lupan-dark')
end, 'change to dark theme')
vis:map(vis.modes.NORMAL, ' tl', function()
vis:command('set theme lupan-light')
end, 'change to light theme')
vis:map(vis.modes.NORMAL, '<C-l>', function()
vis:feedkeys('<vis-selections-remove-column-except>')
set_current_theme()
end, 'Remove all but the count selection column and update theme if needed')
set_current_theme()
end)
vis.events.subscribe(vis.events.WIN_OPEN, function(win)
vis:command('set relativenumber')
end)
vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file, path)
if path:find('[.]go$') then
-- formatting is async, so when reformated you should write file again
vis:command('lspc-format')
end
return true
end)