371 lines
10 KiB
Lua
371 lines
10 KiB
Lua
require('vis')
|
|
require('fast-jump')
|
|
|
|
local lspc = require('plugins/vis-lspc')
|
|
require('plugins/vis-commentary')
|
|
require('plugins/vis-surround')
|
|
local fzfmru = require('plugins/vis-fzf-mru/fzf-mru')
|
|
require('plugins/vis-build')
|
|
require('plugins/vis-cursors')
|
|
require('plugins/vis-colorizer')
|
|
local qf = require('plugins/vis-quickfix')
|
|
local pairs = require('plugins/vis-pairs')
|
|
|
|
require('plugins/vis-pin-files')
|
|
|
|
pairs.autopairs = false
|
|
|
|
vis.ftdetect.filetypes.go_ext = vis.ftdetect.filetypes.go
|
|
vis.ftdetect.filetypes.go = nil
|
|
lspc.ls_map.go_ext = lspc.ls_map.go
|
|
|
|
vis.ftdetect.filetypes.templ = {
|
|
ext = { "%.templ$" },
|
|
}
|
|
|
|
vis.ftdetect.filetypes.odin = {
|
|
ext = { "%.odin$" },
|
|
}
|
|
|
|
lspc.message_level = 2
|
|
|
|
lspc.ls_map.templ = {
|
|
name = 'templ-lsp',
|
|
cmd = 'templ lsp',
|
|
}
|
|
|
|
lspc.ls_map.odin = {
|
|
name = 'ols',
|
|
cmd = 'ols',
|
|
}
|
|
|
|
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 #out) == #out 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 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 function set_current_theme()
|
|
local path = os.getenv('HOME') .. '/.lightmode'
|
|
local theme = 'lupan-dark'
|
|
local f = io.open(path)
|
|
if f then
|
|
f:close()
|
|
theme = 'lupan-light'
|
|
end
|
|
vis:command('set theme ' .. theme)
|
|
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
|
|
|
|
local function ensure_last_line_empty()
|
|
local size = vis.win.file.size
|
|
if size > 0 then
|
|
if vis.win.file:content(size - 1, size) ~= '\n' then
|
|
vis.win.file:insert(size, '\n')
|
|
end
|
|
local lines = vis.win.file.lines
|
|
if string.find(lines[#lines], '%S') then
|
|
lines[#lines + 1] = ''
|
|
end
|
|
end
|
|
end
|
|
|
|
local function add_note()
|
|
local path = vis.win.file.path
|
|
local line = path and path .. ':' .. vis.win.selection.line .. ':' .. vis.win.selection.col .. ': ' .. vis.win.file.lines[vis.win.selection.line]
|
|
vis:command('o ~/notes/notes.md')
|
|
ensure_last_line_empty()
|
|
local lines = vis.win.file.lines
|
|
lines[#lines + 1] = '## '
|
|
local pos = vis.win.file.size - 1
|
|
lines[#lines + 1] = '* time: ' .. os.date('%Y-%m-%d %X')
|
|
if line then
|
|
lines[#lines + 1] = '* line: ' .. line
|
|
end
|
|
vis.win.selection.pos = pos
|
|
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, '<M-n>', '<vis-prompt-show>open<Enter>')
|
|
vis:map(vis.modes.NORMAL, ' K', close_prev_win)
|
|
vis:map(vis.modes.NORMAL, ' J', close_next_win)
|
|
vis:map(vis.modes.NORMAL, ' k', qf.action.cp)
|
|
vis:map(vis.modes.NORMAL, ' j', qf.action.cn)
|
|
|
|
vis:map(vis.modes.NORMAL, ' [', '<vis-prompt-show>lspc-prev-diagnostic<Enter>')
|
|
vis:map(vis.modes.NORMAL, ' ]', '<vis-prompt-show>lspc-next-diagnostic<Enter>')
|
|
vis:map(vis.modes.NORMAL, ' =', '<vis-prompt-show>lspc-format<Enter>')
|
|
|
|
vis:map(vis.modes.NORMAL, ' s', '<vis-prompt-show>fzf-files auto-search<Enter>', 'fzf: search')
|
|
vis:map(vis.modes.NORMAL, ' f', '<vis-prompt-show>fzf-files auto-files<Enter>', 'fzf: files')
|
|
vis:map(vis.modes.NORMAL, ' S', '<vis-prompt-show>fzf-files search<Enter>', 'fzf: search with rg')
|
|
vis:map(vis.modes.NORMAL, ' F', '<vis-prompt-show>fzf-files files<Enter>', 'fzf: files with fd')
|
|
|
|
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, ' d', function()
|
|
local shell = os.getenv('SHELL')
|
|
vis:command('!' .. shell)
|
|
end, 'run shell')
|
|
|
|
vis:map(vis.modes.NORMAL, ' D', 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, ' zk', 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, ' zj', 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('( fd -t d "" ~/src ~/dotfiles -H -E "\\.git" -E node_modules ; zoxide query -l ) | fzf --scheme path', function(path)
|
|
vis:command('cd ' .. path)
|
|
end)
|
|
end, 'fzf change directory')
|
|
|
|
vis:map(vis.modes.NORMAL, ' l', '<vis-prompt-show>!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, ' m', add_global_mark, 'global marks: add')
|
|
|
|
vis:map(vis.modes.NORMAL, ' M', function()
|
|
search('cat ~/.config/vis/global-marks.txt | fzf --tac')
|
|
end, 'global marks: jump')
|
|
|
|
vis:map(vis.modes.NORMAL, ' zm', function()
|
|
vis:command('o ~/.config/vis/global-marks.txt')
|
|
end, 'global marks: edit')
|
|
|
|
vis:map(vis.modes.NORMAL, ' n', add_note)
|
|
|
|
vis:map(vis.modes.NORMAL, ' N', function()
|
|
search(fzf_reload(ripgrep .. ' --with-filename {q} ~/notes'))
|
|
end, 'search notes')
|
|
|
|
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)
|