From 2d2009413f8be624a7cca95cf702e32d9315cbef Mon Sep 17 00:00:00 2001 From: Robert Günzler Date: Fri, 14 Oct 2022 20:57:03 +0200 Subject: vim: move custom modules under internal/ --- .vim/lua/_globals.lua | 16 +++ .vim/lua/align/init.lua | 103 -------------- .vim/lua/debugger.lua | 164 --------------------- .vim/lua/exrc.lua | 49 ------- .vim/lua/globals.lua | 16 --- .vim/lua/hardmode.lua | 10 -- .vim/lua/internal/align.lua | 103 ++++++++++++++ .vim/lua/internal/dap.lua | 162 +++++++++++++++++++++ .vim/lua/internal/exrc.lua | 49 +++++++ .vim/lua/internal/hardmode.lua | 10 ++ .vim/lua/internal/job.lua | 140 ++++++++++++++++++ .vim/lua/internal/lsp.lua | 299 +++++++++++++++++++++++++++++++++++++++ .vim/lua/internal/misc.lua | 210 +++++++++++++++++++++++++++ .vim/lua/internal/snips.lua | 124 ++++++++++++++++ .vim/lua/internal/spell.lua | 9 ++ .vim/lua/internal/statusline.lua | 255 +++++++++++++++++++++++++++++++++ .vim/lua/job.lua | 140 ------------------ .vim/lua/lsp.lua | 299 --------------------------------------- .vim/lua/misc.lua | 178 ----------------------- .vim/lua/plugins.lua | 23 +-- .vim/lua/snips.lua | 124 ---------------- .vim/lua/spell.lua | 10 -- .vim/lua/statusline.lua | 253 --------------------------------- 23 files changed, 1390 insertions(+), 1356 deletions(-) create mode 100644 .vim/lua/_globals.lua delete mode 100644 .vim/lua/align/init.lua delete mode 100644 .vim/lua/debugger.lua delete mode 100644 .vim/lua/exrc.lua delete mode 100644 .vim/lua/globals.lua delete mode 100644 .vim/lua/hardmode.lua create mode 100644 .vim/lua/internal/align.lua create mode 100644 .vim/lua/internal/dap.lua create mode 100644 .vim/lua/internal/exrc.lua create mode 100644 .vim/lua/internal/hardmode.lua create mode 100644 .vim/lua/internal/job.lua create mode 100644 .vim/lua/internal/lsp.lua create mode 100644 .vim/lua/internal/misc.lua create mode 100644 .vim/lua/internal/snips.lua create mode 100644 .vim/lua/internal/spell.lua create mode 100644 .vim/lua/internal/statusline.lua delete mode 100644 .vim/lua/job.lua delete mode 100644 .vim/lua/lsp.lua delete mode 100644 .vim/lua/misc.lua delete mode 100644 .vim/lua/snips.lua delete mode 100644 .vim/lua/spell.lua delete mode 100644 .vim/lua/statusline.lua (limited to '.vim/lua') diff --git a/.vim/lua/_globals.lua b/.vim/lua/_globals.lua new file mode 100644 index 0000000..6aef29b --- /dev/null +++ b/.vim/lua/_globals.lua @@ -0,0 +1,16 @@ +---@diagnostic disable: undefined-global + +_G.augroup = function(tbl) + for name, autocmds in pairs(tbl) do + local group = vim.api.nvim_create_augroup(name, { clear = true }) + for _, au in ipairs(autocmds) do + vim.api.nvim_create_autocmd(au[1], { + pattern = au[2], + command = au[3], + group = group, + }) + end + end +end + +_G.floating_win_border = 'solid' diff --git a/.vim/lua/align/init.lua b/.vim/lua/align/init.lua deleted file mode 100644 index 5dcf7c0..0000000 --- a/.vim/lua/align/init.lua +++ /dev/null @@ -1,103 +0,0 @@ --- based on the ideas from: --- https://github.com/RRethy/nvim-align - -local M = {} - -function M.align_lines(pat, line1, line2, preview_ns, preview_bufnr) - local re = vim.regex(pat) - local bufnr = vim.api.nvim_get_current_buf() - local lines = vim.api.nvim_buf_get_lines(bufnr, line1 - 1, line2, false) - local newlines = {} - local preview_buf_line = 0 - - -- find the longest match - local max = -1 - for _, line in pairs(lines) do - local s = re:match_str(line) - if s and max < s then max = s end - end - - -- exit if nothing was found - if max == -1 then return error('nothing found') end - - for i, line in pairs(lines) do - local s = re:match_str(line) - if s then - local rep = max - s - local changeset = { - string.sub(line, 1, s), - string.rep(' ', rep), - string.sub(line, s+1), - } - local newline = table.concat(changeset) - - -- append to changse if not inside the preview callback - if not preview_ns then - newlines[#newlines+1] = newline - end - - if preview_ns ~= nil then - -- set extmarks inside the live buffer - vim.api.nvim_buf_set_extmark(bufnr, preview_ns, line1+i - 2, 0, - { - hl_mode = 'combine', - virt_text_pos = 'overlay', - virt_text = { - {changeset[1]}, - {changeset[2], 'Substitute'}, - {changeset[3]}, - }, - }) - - -- modify preview buffer - if preview_bufnr ~= nil then - local prefix = string.format('|%d| ', line1 + i - 1) - vim.api.nvim_buf_set_lines(preview_bufnr, preview_buf_line, preview_buf_line, false, { prefix .. newline }) - vim.api.nvim_buf_add_highlight(preview_bufnr, preview_ns, 'Substitute', preview_buf_line, #prefix + s, #prefix + s + #changeset[2]) - preview_buf_line = preview_buf_line + 1 - end - end - end - end - - -- only change buffer when not previewing - if not preview_ns then - -- exit if nothing was changed - if #newlines == 0 then return error('nothing changed') end - vim.api.nvim_buf_set_lines(bufnr, line1 - 1, line2, 0, newlines) - return 0 - end - - if preview_ns ~= nil then - -- open preview buffer only if there is more than a single line of change - return (#preview_buf_line > 1) and 2 or 1 - end -end - -function M.align(pat) - local top, bot = vim.fn.getpos("'<"), vim.fn.getpos("'>") - M.align_lines(pat, top[2]-1, bot[2]) - vim.fn.setpos("'<", top) - vim.fn.setpos("'>", bot) -end - -local function aligncmd(opts, preview_ns, preview_bufnr) - return M.align_lines(opts.fargs[1], opts.line1, opts.line2, preview_ns, preview_bufnr) -end - -local default_opts = { - bindings = true -} - -function M.setup(opts) - opts = vim.tbl_extend('keep', opts or {}, default_opts) - - vim.api.nvim_create_user_command('SimpleAlign', aligncmd, - {nargs = 1, range = '%', preview = aligncmd}) - - if opts.bindings then - vim.keymap.set('v', '', ':SimpleAlign ') - end -end - -return M diff --git a/.vim/lua/debugger.lua b/.vim/lua/debugger.lua deleted file mode 100644 index 1f03434..0000000 --- a/.vim/lua/debugger.lua +++ /dev/null @@ -1,164 +0,0 @@ --- vim: fdm=marker - -require('telescope').load_extension('dap') - -local dap = require('dap') -dap.defaults.fallback.terminal_win_cmd = 'belowright 10new' -dap.defaults.fallback.terminal_win_cmd = 'belowright 10new' - --- open repl when session starts -dap.listeners.after['event_initialized']['me'] = function() - dap.repl.toggle() -end - --- signs -vim.fn.sign_define({{name='DapBreakpoint', text='🞱', texthl='DapBreakpoint', linehl='DapBreakpointLn'}}) -vim.fn.sign_define({{name='DapStopped', text='→', texthl='DapStopped', linehl='DapStoppedLn'}}) - --- keymaps -vim.keymap.set('n', 'dd', dap.toggle_breakpoint, {desc='toggle breakpoint'}) -- convenience -vim.keymap.set('n', 'db', dap.toggle_breakpoint, {desc='toggle breakpoint'}) -vim.keymap.set('n', 'dc', dap.continue, {desc='continue'}) -vim.keymap.set('n', 'do', dap.step_over, {desc='step over'}) -vim.keymap.set('n', 'di', dap.step_into, {desc='step into'}) -vim.keymap.set('n', 'dO', dap.step_out, {desc='step out'}) -vim.keymap.set('n', 'dR', dap.repl.toggle, {desc='toggle REPL'}) -vim.keymap.set('n', 'dL', dap.run_last, {desc='run last'}) -vim.keymap.set('n', 'dt', dap.terminate, {desc='terminate'}) - -local widgets = require('dap.ui.widgets') -vim.keymap.set('n', 'dh', widgets.hover, {desc='hover'}) -vim.keymap.set('n', 'dB', require('telescope').extensions.dap.list_breakpoints, {desc='list breakpoints'}) - --- Common -local bin_from_var_or_pick = function() - local ok, retval = pcall(vim.api.nvim_buf_get_var, 0, 'dap_bin') - if ok then return retval end - local bin = nil - vim.ui.input({prompt = 'DAP Binary: '}, function(choice) bin = choice end) - return bin -end - --- Go {{{ -dap.adapters.go_dlv_local = function(callback, config) -- {{{ - local stdout = vim.loop.new_pipe() - local handle - local pid_or_err - local port = 38697 - local opts = { - stdio = {nil, stdout}, - args = {'dap', '-l', '127.0.0.1:' .. port}, - detached = true, - } - handle, pid_or_err = vim.loop.spawn("dlv", opts, function(exit) - stdout:close() - handle:close() - if exit ~= 0 then vim.notify('dlv exited with exit code ' .. exit) end - end) - assert(handle, 'Error running dlv: ' .. tostring(pid_or_err)) - stdout:read_start(function(err, chunk) - assert(not err, err) - if chunk then vim.schedule(function() require('dap.repl').append(chunk) end) end - end) - vim.defer_fn(function() callback({type = 'server', host = '127.0.0.1', port = port}) end, 100) -end -- }}} - -dap.adapters.go_dlv_remote = { - type = 'server', - host = '127.0.0.1', - port = 38697, -} - -dap.configurations.go = { - { - name = 'Debug (local)', - type = 'go_dlv_local', - request = 'launch', - program = '${file}', - }, - { - name = 'Debug (remote)', - type = 'go_dlv_remote', - request = 'launch', - mode = 'exec', - program = bin_from_var_or_pick, - }, -} --- end of Go }}} - --- C/C++/Rust {{{ --- dap.adapters.cppdbg = { --- id = 'cppdbg', --- type = 'executable', --- command = vim.env.HOME .. '/.local/share/nvim/dap/ms-vscode.cpptools/extension/debugAdapters/bin/OpenDebugAD7', --- } -dap.adapters.lldb = { - type = 'executable', - command = vim.trim(vim.fn.system('command -v lldb-vscode')), - name = 'lldb', -} - --- dap.configurations.c = { --- { --- name = 'Launch binary', --- type = 'cppdbg', --- request = 'launch', --- program = function() --- local file = vim.g.dapbin --- if file then return file end --- -- TODO: assuming meson --- file = vim.trim(vim.fn.system( --- [[jq -r '..|select(.type?=="executable")|.filename|.[0]' ]] .. --- vim.lsp.buf.list_workspace_folders()[1] .. --- [[/build/meson-info/intro-targets.json]] --- )) --- local fd = vim.loop.fs_open(file, "r", 438) --- if file and fd then --- vim.loop.fs_close(fd) --- return file --- end --- vim.ui.input('binary: ', function(result) file = result end) --- return file --- end, --- cwd = '${workspaceFolder}', --- stopOnEntry = true, --- }, --- { --- name = 'Attach to gdbserver', --- type = 'cppdbg', --- request = 'launch', --- MIMode = 'gdb', --- miDebuggerServerAddress = 'localhost:1234', --- miDebuggerPath = '/usr/bin/gdb', --- cwd = '${workspaceFolder}', --- program = function() --- local file = vim.g.dapbin --- if file then return file end --- vim.ui.input('binary: ', function(result) file = result end) --- return file --- end, --- }, --- } - -dap.configurations.c = { - { - name = 'Launch', - type = 'lldb', - request = 'launch', - program = bin_from_var_or_pick, - args = {}, - cwd = '${workspaceFolder}', - stopOnEntry = false, - }, - { - name = 'Attach', - type = 'lldb', - request = 'attach', - pid = require('dap.utils').pick_process, - args = {}, - }, -} -dap.configurations.cpp = dap.configurations.c -dap.configurations.rust = dap.configurations.c - --- end of C/C++/Rust }}} diff --git a/.vim/lua/exrc.lua b/.vim/lua/exrc.lua deleted file mode 100644 index 6b7742b..0000000 --- a/.vim/lua/exrc.lua +++ /dev/null @@ -1,49 +0,0 @@ -local root_pattern = require('lspconfig.util').root_pattern - -local M = { - config = { - filenames = {'.nvimrc'} - } -} - -M.setup = function (opt) - vim.validate { - filenames = { opt.filenames, 'table', true }, - } - - M.config = vim.tbl_extend('force', M.config, opt) - - local group = vim.api.nvim_create_augroup('ExrcLoad', { clear = true }) - vim.api.nvim_create_autocmd('VimEnter', { - callback = M.load, - group = group, - }) -end - -local load = function (root, filename) - local fpath = root .. '/' .. filename - if root and vim.loop.fs_stat(fpath) then - vim.cmd('luafile ' .. fpath) - vim.notify('[exrc] loaded') - else - error(string.format('[exrc] %s not found', fpath)) - end -end - -M.load = function () - local root = vim.fn.getcwd() - for _, fname in ipairs(M.config.filenames) do - local ok = false - ok, _ = pcall(load, root, fname) - if ok then return true end - - -- try harder by searching up the dir tree - root = root_pattern(fname)(root) - ok, _ = pcall(load, root, fname) - if ok then return true end - end - - return false -end - -return M diff --git a/.vim/lua/globals.lua b/.vim/lua/globals.lua deleted file mode 100644 index 6aef29b..0000000 --- a/.vim/lua/globals.lua +++ /dev/null @@ -1,16 +0,0 @@ ----@diagnostic disable: undefined-global - -_G.augroup = function(tbl) - for name, autocmds in pairs(tbl) do - local group = vim.api.nvim_create_augroup(name, { clear = true }) - for _, au in ipairs(autocmds) do - vim.api.nvim_create_autocmd(au[1], { - pattern = au[2], - command = au[3], - group = group, - }) - end - end -end - -_G.floating_win_border = 'solid' diff --git a/.vim/lua/hardmode.lua b/.vim/lua/hardmode.lua deleted file mode 100644 index cc71baf..0000000 --- a/.vim/lua/hardmode.lua +++ /dev/null @@ -1,10 +0,0 @@ --- hard mode means we're not using the arrow keys! - -local bail = function() - vim.cmd [[silent! echohl ErrorMsg | echo "HARD MODE: hjkl operation only" | echohl None]] -end - -vim.keymap.set({'n', 'v', 'i'}, '', bail) -vim.keymap.set({'n', 'v', 'i'}, '', bail) -vim.keymap.set({'n', 'v', 'i'}, '', bail) -vim.keymap.set({'n', 'v', 'i'}, '', bail) diff --git a/.vim/lua/internal/align.lua b/.vim/lua/internal/align.lua new file mode 100644 index 0000000..5dcf7c0 --- /dev/null +++ b/.vim/lua/internal/align.lua @@ -0,0 +1,103 @@ +-- based on the ideas from: +-- https://github.com/RRethy/nvim-align + +local M = {} + +function M.align_lines(pat, line1, line2, preview_ns, preview_bufnr) + local re = vim.regex(pat) + local bufnr = vim.api.nvim_get_current_buf() + local lines = vim.api.nvim_buf_get_lines(bufnr, line1 - 1, line2, false) + local newlines = {} + local preview_buf_line = 0 + + -- find the longest match + local max = -1 + for _, line in pairs(lines) do + local s = re:match_str(line) + if s and max < s then max = s end + end + + -- exit if nothing was found + if max == -1 then return error('nothing found') end + + for i, line in pairs(lines) do + local s = re:match_str(line) + if s then + local rep = max - s + local changeset = { + string.sub(line, 1, s), + string.rep(' ', rep), + string.sub(line, s+1), + } + local newline = table.concat(changeset) + + -- append to changse if not inside the preview callback + if not preview_ns then + newlines[#newlines+1] = newline + end + + if preview_ns ~= nil then + -- set extmarks inside the live buffer + vim.api.nvim_buf_set_extmark(bufnr, preview_ns, line1+i - 2, 0, + { + hl_mode = 'combine', + virt_text_pos = 'overlay', + virt_text = { + {changeset[1]}, + {changeset[2], 'Substitute'}, + {changeset[3]}, + }, + }) + + -- modify preview buffer + if preview_bufnr ~= nil then + local prefix = string.format('|%d| ', line1 + i - 1) + vim.api.nvim_buf_set_lines(preview_bufnr, preview_buf_line, preview_buf_line, false, { prefix .. newline }) + vim.api.nvim_buf_add_highlight(preview_bufnr, preview_ns, 'Substitute', preview_buf_line, #prefix + s, #prefix + s + #changeset[2]) + preview_buf_line = preview_buf_line + 1 + end + end + end + end + + -- only change buffer when not previewing + if not preview_ns then + -- exit if nothing was changed + if #newlines == 0 then return error('nothing changed') end + vim.api.nvim_buf_set_lines(bufnr, line1 - 1, line2, 0, newlines) + return 0 + end + + if preview_ns ~= nil then + -- open preview buffer only if there is more than a single line of change + return (#preview_buf_line > 1) and 2 or 1 + end +end + +function M.align(pat) + local top, bot = vim.fn.getpos("'<"), vim.fn.getpos("'>") + M.align_lines(pat, top[2]-1, bot[2]) + vim.fn.setpos("'<", top) + vim.fn.setpos("'>", bot) +end + +local function aligncmd(opts, preview_ns, preview_bufnr) + return M.align_lines(opts.fargs[1], opts.line1, opts.line2, preview_ns, preview_bufnr) +end + +local default_opts = { + bindings = true +} + +function M.setup(opts) + opts = vim.tbl_extend('keep', opts or {}, default_opts) + + vim.api.nvim_create_user_command('SimpleAlign', aligncmd, + {nargs = 1, range = '%', preview = aligncmd}) + + if opts.bindings then + vim.keymap.set('v', '', ':SimpleAlign ') + end +end + +return M diff --git a/.vim/lua/internal/dap.lua b/.vim/lua/internal/dap.lua new file mode 100644 index 0000000..aa419ea --- /dev/null +++ b/.vim/lua/internal/dap.lua @@ -0,0 +1,162 @@ +-- vim: fdm=marker + +local dap = require('dap') +dap.defaults.fallback.terminal_win_cmd = 'belowright 10new' +dap.defaults.fallback.terminal_win_cmd = 'belowright 10new' + +-- open repl when session starts +dap.listeners.after['event_initialized']['me'] = function() + dap.repl.toggle() +end + +-- signs +vim.fn.sign_define({{name='DapBreakpoint', text='🞱', texthl='DapBreakpoint', linehl='DapBreakpointLn'}}) +vim.fn.sign_define({{name='DapStopped', text='→', texthl='DapStopped', linehl='DapStoppedLn'}}) + +-- keymaps +vim.keymap.set('n', 'dd', dap.toggle_breakpoint, {desc='toggle breakpoint'}) -- convenience +vim.keymap.set('n', 'db', dap.toggle_breakpoint, {desc='toggle breakpoint'}) +vim.keymap.set('n', 'dc', dap.continue, {desc='continue'}) +vim.keymap.set('n', 'do', dap.step_over, {desc='step over'}) +vim.keymap.set('n', 'di', dap.step_into, {desc='step into'}) +vim.keymap.set('n', 'dO', dap.step_out, {desc='step out'}) +vim.keymap.set('n', 'dR', dap.repl.toggle, {desc='toggle REPL'}) +vim.keymap.set('n', 'dL', dap.run_last, {desc='run last'}) +vim.keymap.set('n', 'dt', dap.terminate, {desc='terminate'}) + +local widgets = require('dap.ui.widgets') +vim.keymap.set('n', 'dh', widgets.hover, {desc='hover'}) +vim.keymap.set('n', 'dB', require('telescope').extensions.dap.list_breakpoints, {desc='list breakpoints'}) + +-- Common +local bin_from_var_or_pick = function() + local ok, retval = pcall(vim.api.nvim_buf_get_var, 0, 'dap_bin') + if ok then return retval end + local bin = nil + vim.ui.input({prompt = 'DAP Binary: '}, function(choice) bin = choice end) + return bin +end + +-- Go {{{ +dap.adapters.go_dlv_local = function(callback, config) -- {{{ + local stdout = vim.loop.new_pipe() + local handle + local pid_or_err + local port = 38697 + local opts = { + stdio = {nil, stdout}, + args = {'dap', '-l', '127.0.0.1:' .. port}, + detached = true, + } + handle, pid_or_err = vim.loop.spawn("dlv", opts, function(exit) + stdout:close() + handle:close() + if exit ~= 0 then vim.notify('dlv exited with exit code ' .. exit) end + end) + assert(handle, 'Error running dlv: ' .. tostring(pid_or_err)) + stdout:read_start(function(err, chunk) + assert(not err, err) + if chunk then vim.schedule(function() require('dap.repl').append(chunk) end) end + end) + vim.defer_fn(function() callback({type = 'server', host = '127.0.0.1', port = port}) end, 100) +end -- }}} + +dap.adapters.go_dlv_remote = { + type = 'server', + host = '127.0.0.1', + port = 38697, +} + +dap.configurations.go = { + { + name = 'Debug (local)', + type = 'go_dlv_local', + request = 'launch', + program = '${file}', + }, + { + name = 'Debug (remote)', + type = 'go_dlv_remote', + request = 'launch', + mode = 'exec', + program = bin_from_var_or_pick, + }, +} +-- end of Go }}} + +-- C/C++/Rust {{{ +-- dap.adapters.cppdbg = { +-- id = 'cppdbg', +-- type = 'executable', +-- command = vim.env.HOME .. '/.local/share/nvim/dap/ms-vscode.cpptools/extension/debugAdapters/bin/OpenDebugAD7', +-- } +dap.adapters.lldb = { + type = 'executable', + command = vim.trim(vim.fn.system('command -v lldb-vscode')), + name = 'lldb', +} + +-- dap.configurations.c = { +-- { +-- name = 'Launch binary', +-- type = 'cppdbg', +-- request = 'launch', +-- program = function() +-- local file = vim.g.dapbin +-- if file then return file end +-- -- TODO: assuming meson +-- file = vim.trim(vim.fn.system( +-- [[jq -r '..|select(.type?=="executable")|.filename|.[0]' ]] .. +-- vim.lsp.buf.list_workspace_folders()[1] .. +-- [[/build/meson-info/intro-targets.json]] +-- )) +-- local fd = vim.loop.fs_open(file, "r", 438) +-- if file and fd then +-- vim.loop.fs_close(fd) +-- return file +-- end +-- vim.ui.input('binary: ', function(result) file = result end) +-- return file +-- end, +-- cwd = '${workspaceFolder}', +-- stopOnEntry = true, +-- }, +-- { +-- name = 'Attach to gdbserver', +-- type = 'cppdbg', +-- request = 'launch', +-- MIMode = 'gdb', +-- miDebuggerServerAddress = 'localhost:1234', +-- miDebuggerPath = '/usr/bin/gdb', +-- cwd = '${workspaceFolder}', +-- program = function() +-- local file = vim.g.dapbin +-- if file then return file end +-- vim.ui.input('binary: ', function(result) file = result end) +-- return file +-- end, +-- }, +-- } + +dap.configurations.c = { + { + name = 'Launch', + type = 'lldb', + request = 'launch', + program = bin_from_var_or_pick, + args = {}, + cwd = '${workspaceFolder}', + stopOnEntry = false, + }, + { + name = 'Attach', + type = 'lldb', + request = 'attach', + pid = require('dap.utils').pick_process, + args = {}, + }, +} +dap.configurations.cpp = dap.configurations.c +dap.configurations.rust = dap.configurations.c + +-- end of C/C++/Rust }}} diff --git a/.vim/lua/internal/exrc.lua b/.vim/lua/internal/exrc.lua new file mode 100644 index 0000000..6b7742b --- /dev/null +++ b/.vim/lua/internal/exrc.lua @@ -0,0 +1,49 @@ +local root_pattern = require('lspconfig.util').root_pattern + +local M = { + config = { + filenames = {'.nvimrc'} + } +} + +M.setup = function (opt) + vim.validate { + filenames = { opt.filenames, 'table', true }, + } + + M.config = vim.tbl_extend('force', M.config, opt) + + local group = vim.api.nvim_create_augroup('ExrcLoad', { clear = true }) + vim.api.nvim_create_autocmd('VimEnter', { + callback = M.load, + group = group, + }) +end + +local load = function (root, filename) + local fpath = root .. '/' .. filename + if root and vim.loop.fs_stat(fpath) then + vim.cmd('luafile ' .. fpath) + vim.notify('[exrc] loaded') + else + error(string.format('[exrc] %s not found', fpath)) + end +end + +M.load = function () + local root = vim.fn.getcwd() + for _, fname in ipairs(M.config.filenames) do + local ok = false + ok, _ = pcall(load, root, fname) + if ok then return true end + + -- try harder by searching up the dir tree + root = root_pattern(fname)(root) + ok, _ = pcall(load, root, fname) + if ok then return true end + end + + return false +end + +return M diff --git a/.vim/lua/internal/hardmode.lua b/.vim/lua/internal/hardmode.lua new file mode 100644 index 0000000..cc71baf --- /dev/null +++ b/.vim/lua/internal/hardmode.lua @@ -0,0 +1,10 @@ +-- hard mode means we're not using the arrow keys! + +local bail = function() + vim.cmd [[silent! echohl ErrorMsg | echo "HARD MODE: hjkl operation only" | echohl None]] +end + +vim.keymap.set({'n', 'v', 'i'}, '', bail) +vim.keymap.set({'n', 'v', 'i'}, '', bail) +vim.keymap.set({'n', 'v', 'i'}, '', bail) +vim.keymap.set({'n', 'v', 'i'}, '', bail) diff --git a/.vim/lua/internal/job.lua b/.vim/lua/internal/job.lua new file mode 100644 index 0000000..f9f7bf3 --- /dev/null +++ b/.vim/lua/internal/job.lua @@ -0,0 +1,140 @@ +local Job = require ('plenary.job') +local spinner_ok, spinner = pcall(require, 'spinner.core') + +local M = { + current_jobs = {} +} + +local strip_ansi = function(line) + return line:gsub(string.char(27) .. '[[0-9;]*m', '') +end + +--create a new job and register +--@return ~/.local/share/nvim/site/pack/packer/start/plenary.nvim/lua/plenary/job.lua +function M.jobstart(opts) + opts = opts or {} + + -- default options + -- opts.enable_recording = true + opts.enable_spinner = (opts.enable_spinner or true) and spinner_ok + opts.populate_quickfix = opts.populate_quickfix or true + + local title + if opts.format_title then + title = opts.format_title(opts.command, opts.args) + opts.format_title = nil + else + title = opts.command + end + + opts.on_start = vim.schedule_wrap(function(j) + table.insert(M.current_jobs, j.pid, j) + + if opts.populate_quickfix then + -- clear quickfix + vim.fn.setqflist({}, 'r') + end + + if opts.enable_spinner then + spinner.on_attach(j.pid, title, vim.fn.bufnr()) + spinner.on_progress('begin', j.pid, j.pid) + end + end) + + opts.on_exit = vim.schedule_wrap(function(j, _) + table.remove(M.current_jobs, j.pid) + + if opts.populate_quickfix then + vim.cmd([[doautocmd QuickFixCmdPost]]) + -- vim.fn.setqflist({}, 'r', { + -- lines = {}, + -- id = j.pid, + -- }) + end + + if opts.enable_spinner then + spinner.on_progress('end', j.pid, j.pid) + spinner.on_exit(nil, nil, j.pid) + end + end) + + opts.on_stdout = vim.schedule_wrap(function(error, data, j) + if error then + vim.notify('error: ' .. error) + return + end -- handle error? + + if opts.populate_quickfix and data then + vim.fn.setqflist({}, 'a', { + title = title, + lines = {strip_ansi(data)}, + efm = '%m', + id = j.pid, + }) + end + end) + + opts.on_stderr = vim.schedule_wrap(function(error, data, j) + if error then + vim.notify('error: ' .. error) + return + end -- handle error? + + if opts.populate_quickfix and data then + vim.fn.setqflist({}, 'a', { + title = title, + lines = {strip_ansi(data)}, + efm = '%m', + id = j.pid, + }) + vim.cmd([[doautocmd QuickFixCmdPost]]) + end + end) + + -- run vim.fn.expand() on all args + for i=1, #opts.args do + opts.args[i] = vim.fn.expandcmd(opts.args[i]) + end + + local j = Job:new(opts) + j:start() + + return j +end + +function M.make(extra_args) + local makeprg = vim.fn.expandcmd(vim.opt.makeprg:get()) + -- split makeprg into command + args + local args = vim.split(makeprg, ' ') + local command = args[1] + table.remove(args, 1) + + local cwd = vim.fn.expand('%:p:h') + + if not (string.match(makeprg, 'make') == nil) then + -- detect makefile + cwd = require('lspconfig.util').root_pattern('Makefile')(cwd) + end + + table.foreach(extra_args or {}, function(_, v) table.insert(args, v) end) + + return M.jobstart { + command = command, + args = args, + cwd = cwd, + } +end + +function M.sh(command_string) + return M.jobstart { + command = vim.env.SHELL, + args = {'-c', command_string}, + + -- strip 'sh -c' from the title (used by progress reporting etc.) + format_title = function(_, args) + return require('plenary.collections.py_list')(args):slice(2,#args):join(' ') + end + } +end + +return M diff --git a/.vim/lua/internal/lsp.lua b/.vim/lua/internal/lsp.lua new file mode 100644 index 0000000..669c2c7 --- /dev/null +++ b/.vim/lua/internal/lsp.lua @@ -0,0 +1,299 @@ +local lsp = require('lspconfig') +local lspstatus = require('lsp-status') + +local my_attach = function(client, bufnr) + if vim.opt.diff:get() then + vim.notify('not running LSP client in diff mode', vim.log.levels.WARN) + vim.lsp.stop_client() + return + end + + local group = vim.api.nvim_create_augroup('LspOnAttach', {}) + vim.api.nvim_create_autocmd('CursorHold', { + buffer = bufnr, + group = group, + callback = function() + if not _G.diagnostic_hidden then + vim.diagnostic.open_float(nil, { + focusable = false, + close_events = {'BufLeave', 'CursorMoved', 'InsertEnter', 'FocusLost'}, + border = _G.floating_win_border, + source = 'always', + prefix = ' ', + scope = 'cursor', + }) + end + end, + }) + + lspstatus.on_attach(client) + if client.supports_method('textDocument/documentSymbol') then + require('nvim-navic').attach(client, bufnr) + -- require('aerial').on_attach(client, bufnr) + -- vim.keymap.set('n', 'g0', vim.lsp.buf.document_symbol, {buffer = bufnr}) + end + if client.supports_method('workspace/symbol') then + vim.keymap.set('n', 'gW' , vim.lsp.buf.workspace_symbol, {buffer = bufnr, desc = 'goto symbol'}) + vim.keymap.set('n', ';s' , require('telescope.builtin').lsp_workspace_symbols, {desc='lsp workspace symbols'}) + end + if client.supports_method('textDocument/definition') then + vim.keymap.set('n', '' , vim.lsp.buf.definition, {buffer = bufnr, desc = 'goto definition'}) + vim.keymap.set('n', 'gd' , vim.lsp.buf.definition, {buffer = bufnr, desc = 'goto definition'}) + vim.keymap.set('n', 'gR' , vim.lsp.buf.references, {buffer = bufnr, desc = 'goto references'}) + vim.keymap.set('n', ';R' , require('telescope.builtin').lsp_references, {desc='lsp references'}) + end + if client.supports_method('textDocument/hover') then + vim.keymap.set('n', 'K' , vim.lsp.buf.hover, {buffer = bufnr, desc = 'hover'}) + end + if client.supports_method('textDocument/rename') then + vim.keymap.set('n', 'grr' , vim.lsp.buf.rename, {buffer = bufnr, desc = 'rename'}) + end + if client.supports_method('signatureHelp') then + vim.keymap.set('n', '' , vim.lsp.buf.signature_help, {buffer = bufnr, desc = 'signature help'}) + end + if client.supports_method('textDocument/formatting') then + vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr()') + vim.keymap.set('n', 'f' , vim.lsp.buf.format, {buffer = bufnr, desc = 'format'}) + vim.api.nvim_create_autocmd('BufWritePre', { + buffer = bufnr, + group = group, + callback = function() require('internal.lsp').format(vim.fn.expand(':p')) end, + }) + end + if client.supports_method('textDocument/typeDefinition') then + vim.keymap.set('n', 'gT' , vim.lsp.buf.type_definition, {buffer = bufnr, desc = 'goto typedef'}) + end + if client.supports_method('textDocument/declaration') then + vim.keymap.set('n', 'gD' , vim.lsp.buf.declaration, {buffer = bufnr, desc = 'goto declaration'}) + end + if client.supports_method('textDocument/implementation') then + vim.keymap.set('n', 'gI' , vim.lsp.buf.implementation, {buffer = bufnr, desc = 'goto implementation'}) + end + if client.supports_method('textDocument/codeAction') then + vim.keymap.set('n', 'ga', vim.lsp.buf.code_action, {buffer = bufnr, desc = 'code action'}) + end + + if client.supports_method('textDocument/documentHighlight') then + vim.keymap.set('n', '8', vim.lsp.buf.document_highlight, {buffer = bufnr, desc = 'document highlight'}) + -- vim.keymap.set('n', '', vim.lsp.buf.clear_references, {buffer = bufnr, desc = 'clear references'}) + vim.api.nvim_create_autocmd('CursorMoved', { + callback = vim.lsp.buf.clear_references, + buffer = bufnr, + }) + end +end + +local my_exit = function(_, _, _) +end + +local capabilities = function() + local caps = vim.lsp.protocol.make_client_capabilities() + -- enable lsp-based snippets + caps.textDocument.completion.completionItem.snippetSupport = true + caps.textDocument.completion.completionItem.resolveSupport = { + properties = { + 'documentation', + 'detail', + 'additionalTextEdits', + } + } + -- add window/workDoneProgress capability + caps = vim.tbl_extend('keep', caps or {}, lspstatus.capabilities) + return caps +end + +local servers = { + ccls = { disabled = true, + root_dir = lsp.util.root_pattern('.ccls','meson.build','.git'), + init_options = { + compilationDatabaseDirectory = "build", + index = { threads = 0 }, + completion = { + filterAndSort = false, + }, + clang = { excludeArgs = { '-frounding-math' } }, + }, + }, + clangd = { + root_dir = lsp.util.root_pattern('.ccls','meson.build','.git'), + }, + elixirls = { + cmd = { 'elixir-ls' }, + settings = { + elixirLS = { + dialyzerEnabled = false, + } + } + }, + gopls = { + settings = { + gopls = { + analyses = { + -- composites = false, + fieldalignment = true, + nilness = true, + shadow = false, + unusedparams = true, + unusedwrite = true, + }, + gofumpt = true, + -- hoverKind = 'Structured', + } + } + }, + sumneko_lua = { + cmd = { 'lua-language-server' }, + settings = { + Lua = { + runtime = { + version = 'LuaJIT', + path = vim.split(package.path, ';'), + }, + diagnostics = { + globals = { + '_G', + 'assert', + 'error', + 'os', + 'package', + 'pairs', 'ipairs', + 'pcall', + 'require', + 'string', + 'table', + 'type', + 'vim', + }, + neededFileStatus = { + ['code-style-check'] = 'Any', + } + }, + format = { + enable = true, + defaultConfig = { + indent_style = 'space', + indent_size = '2', + } + }, + workspace = { + -- library = vim.api.nvim_get_runtime_file("", true), + library = { + [vim.env.VIMRUNTIME .. '/lua'] = true, + [vim.env.VIMRUNTIME .. '/lua/vim/lsp'] = true, + [vim.fn.stdpath('config') .. '/lua'] = true, + } + }, + telemetry = { + enable = false, + }, + }, + }, + }, + rust_analyzer = { + cmd = { 'env', 'CARGO_TARGET_DIR=/tmp', 'RUST_SRC_PATH=/usr/src/rustlib/library', 'rust-analyzer' }, + settings = { + ['rust-analyzer'] = { + checkOnSave = { + command = 'clippy' + } + } + }, + }, + tsserver = { disabled = true, + cmd = { + 'toolbox', 'run', '--', + 'sh', '-c', + '. /etc/profile.d/nvm.sh && typescript-language-server --stdio' + }, + }, + zls = { disabled = true, + }, + zk = { disabled = true, + root_dir = lsp.util.root_pattern('.zk'), + }, +} + +local setup = function() + -- configure floating win handlers + vim.lsp.handlers['textDocument/hover'] = vim.lsp.with( + vim.lsp.handlers.hover, { border = _G.floating_win_border }) + vim.lsp.handlers['textDocument/signature_help'] = vim.lsp.with( + vim.lsp.handlers.signature_help, { border = _G.floating_win_border }) + + local caps = capabilities() + for server, opts in pairs(servers) do + if not opts.disabled then + opts = vim.tbl_extend('error', opts, { + on_attach = my_attach, + on_exit = my_exit, + capabilities = caps, + }) + -- lsp-status custom handlers + local ok, lspstatus_ext = pcall(lspstatus.extensions[server]) + if ok then + opts = vim.tbl_extend('error', opts, { + handlers = lspstatus_ext.setup(), + }) + end + lsp[server].setup(opts) + end + end +end + +local format = function(afile) + if vim.g.nofmt then return end + if not string.match(afile, '^/home/robert/devel/upstream') then + vim.lsp.buf.format() + if string.match(afile, '.go$') then + vim.lsp.buf.code_action({ only = {'source.organizeImports'} }) + end + -- vim.notify('%#MoreMsg#󰃢%#Italic# fmt') + vim.notify('%#MoreMsg#󰃢%#Italic# fmt') + end +end + +local symbols = { + -- 󰆼 󱆃 + Array = '󰨾 ', + Boolean = '󰦍 ', + Class = '󰙀 ', + Color = '󰉦 ', + Constant = ' ', + Constructor = '󱇿 ', + Enum = ' ', + EnumMember = ' ', + Event = '󱐋 ', + -- Field = '󰽜 ', + Field = '󰆈 ', + File = '󰈔 ', + Folder = '󰝰 ', + Function = ' ', + Interface = '󱦜 ', + Key = '󰌋 ', + Keyword = '󰓽 ', + Method = '󰒓 ', + Module = '󰏖 ', + Namespace = '󰆧 ', + Null = '󰎣 ', + Object = '󰘦 ', + Operator = '󱓉 ', + Property = '󰐱 ', + Package = '󰏗 ', + Reference = '󰌹 ', + Snippet = '󰯁 ', + Struct = '󰙅 ', + Text = '󰉿 ', + TypeParameter = '󰌨 ', + Unit = '󰠱 ', + Value = '󰎠 ', + Variable = '󱄑 ', +} + +return { + my_attach = my_attach, + my_exit = my_exit, + capabilities = capabilities, + setup = setup, + format = format, + symbols = symbols, +} diff --git a/.vim/lua/internal/misc.lua b/.vim/lua/internal/misc.lua new file mode 100644 index 0000000..5a2ae21 --- /dev/null +++ b/.vim/lua/internal/misc.lua @@ -0,0 +1,210 @@ +-- misc stuff implemented in lua + +local M = {} + +function M.do_under_cursor(obj, cb) + return cb(vim.fn.expand(vim.fn.expand(obj))) +end + +function M.word_under_cursor(cb) + return M.do_under_cursor('', cb) +end + +function M.expr_under_cursor(cb) + return M.do_under_cursor('', cb) +end + +function M.file_under_cursor(cb) + return M.do_under_cursor('', cb) +end + +function M.open_under_cursor(cmd, detect_cmd) + return M.file_under_cursor(function(txt) + txt = vim.trim(txt) + if not cmd and detect_cmd then + if vim.regex([[^http.*$]]):match_str(txt) then + cmd = 'url-launcher' + end + if vim.regex([[^(\.\./|[\w\d_/\-])*(\.[\w\d]+)?$]]):match_str(txt) then + cmd = ':edit' + end + vim.notify("open_under_cursor: detected command " .. txt .. " => " .. (cmd or "")) + end + if not cmd then + vim.fn.inputsave() + vim.ui.input('open with: ', function(result) cmd = result end) + vim.fn.inputrestore() + if not cmd then return end + end + -- detect vim command + if cmd:sub(1, 1) == ":" then + vim.cmd(cmd:sub(2) .. ' ' .. txt) + else + vim.loop.spawn(cmd, {args = {txt}}) + end + end) +end + +local function get_visual_selection() + local top = vim.fn.getpos("'<") + top = { ln = top[2], col = top[3] } + local bot = vim.fn.getpos("'>") + bot = { ln = bot[2], col = bot[3] } + local lines = vim.api.nvim_buf_get_lines(0, (top.ln - 1), bot.ln, false) + if vim.opt.selection:get() == 'inclusive' then + lines[#lines] = lines[#lines]:sub(1, bot.col) + else + lines[#lines] = lines[#lines]:sub(1, (bot.col -1)) + end + lines[1] = lines[1]:sub(top.col) + return top, bot, lines +end + +function M.sort_lines(_, preview_ns, preview_bufnr) + local bufnr = vim.api.nvim_get_current_buf() + + local top, bot, lines = get_visual_selection() + for i=1, #lines do + lines[i] = vim.fn.join(vim.fn.sort(vim.fn.split(lines[i], " "))) + end + + if not preview_ns then + vim.api.nvim_buf_set_lines(bufnr, top.ln-1, bot.ln, false, lines) + vim.notify('no preview') + return 0 + end + + -- inccommand preview + if preview_ns ~= nil then + for i, line in ipairs(lines) do + vim.api.nvim_buf_set_extmark(bufnr, preview_ns, top.ln+i - 2, 0, { + hl_mode = 'combine', + virt_text_pos = 'overlay', + virt_text = {{line, 'Substitute'}}, + }) + + if preview_bufnr ~= nil then + local prefix = string.format('|%d| ', top.ln + i - 1) + vim.api.nvim_buf_set_lines(preview_bufnr, i-1, -1, false, { prefix .. line }) + vim.api.nvim_buf_add_highlight(preview_bufnr, preview_ns, 'Substitute', i, #prefix, #prefix+#line) + end + end + return (#lines > 1 and 2 or 1) + end +end + +local telescope_builtin = require('telescope.builtin') +local telescope_actions = require('telescope.actions') +local telescope_action_state = require('telescope.actions.state') + +local get_searchdirs = function(dirs) + -- skip asking if we're looking at known filetypes + local ft = vim.api.nvim_buf_get_option(0, 'filetype') + if not dirs and (ft == 'dirbuf' or ft == 'alpha') then + dirs = '%:p:h' + end + if not dirs then + vim.ui.input('Search directories: ', function(result) dirs = result end) + end + -- default to something reasonable + if not dirs then dirs = '%:p:h' end + return vim.split(vim.fn.expand(dirs), ',') +end + +function M.live_grep(dirs, opts, on_choice) + opts = opts or {} + local search_dirs = get_searchdirs(dirs) + opts.search_dirs = search_dirs + opts.prompt_title = 'Grep: '.. table.concat(search_dirs) + if on_choice then + opts.attach_mappings = function(prompt_bufnr) + telescope_actions.select_default:replace(function() + local selection = telescope_action_state.get_selected_entry() + if selection == nil then return end + telescope_actions.close(prompt_bufnr) + on_choice(selection.path) + end) + return true + end + end + telescope_builtin.live_grep(opts) +end + +function M.find_files(dirs, opts, on_choice) + if dirs == 'plugins' then dirs = vim.fn.stdpath('data') .. '/site/pack/' end + + opts = opts or {} + local search_dirs = dirs + if type(dirs) == 'string' then search_dirs = get_searchdirs(dirs) end + opts.search_dirs = search_dirs + opts.prompt_title = 'Find: '.. table.concat(search_dirs) + if on_choice then + opts.attach_mappings = function(prompt_bufnr) + telescope_actions.select_default:replace(function() + local selection = telescope_action_state.get_selected_entry() + if not selection then + vim.notify('Nothing selected', vim.log.levels.WARN) + return + end + telescope_actions.close(prompt_bufnr) + on_choice(selection.path) + end) + return true + end + end + telescope_builtin.find_files(opts) +end + + +function M.fold_block() -- {{{ + local Comment = require('Comment.api') + local m = vim.api.nvim_buf_get_mark + local inital_cusor_pos = vim.api.nvim_win_get_cursor(0) + local spos, epos = m(0, '<'), m(0, '>') + + -- do start of selection + vim.api.nvim_win_set_cursor(0, spos) + Comment.insert_linewise_eol() + vim.api.nvim_feedkeys('\\', 'ni', true) + local sln = vim.api.nvim_get_current_line() + vim.api.nvim_set_current_line(sln .. '{{{') + + -- do end of selection + vim.api.nvim_win_set_cursor(0, epos) + Comment.insert_linewise_eol() + vim.api.nvim_feedkeys('\\', 'ni', true) + local eln = vim.api.nvim_get_current_line() + vim.api.nvim_set_current_line(eln .. '}}}') + + -- restore initial cursor postition + vim.api.nvim_win_set_cursor(0, inital_cusor_pos) +end -- }}} + +function M.link_preview() + local link = vim.fn.expand('') + if not link then return end + + local buf = vim.api.nvim_get_current_buf() + local ln = (vim.api.nvim_win_get_cursor(0)[1]) - 1 + + local j = require('job').jobstart({ + format_title = function() return "link-preview" end, + command = vim.env.SHELL, + args = {'-c', [[ curl -sSfL ]] .. link .. [[ | grep -iPo '(?<=property="og:title" content=")([^\"]+)(?=")' ]]}, + populate_quickfix = false, + enable_recording = true, + }) + + j:after_success(vim.schedule_wrap(function(j, code, _) + local results = j:result() + if not code == 0 or #results == 0 then return end + + local ns = vim.api.nvim_create_namespace('') + vim.api.nvim_buf_set_extmark(buf, ns, ln, 0, { + virt_text = {{results[1], 'Error'}}, + virt_text_pos = 'eol' + }) + end)) +end + +return M diff --git a/.vim/lua/internal/snips.lua b/.vim/lua/internal/snips.lua new file mode 100644 index 0000000..318c9f7 --- /dev/null +++ b/.vim/lua/internal/snips.lua @@ -0,0 +1,124 @@ + +local ls = require('luasnip') +local types = require('luasnip.util.types') + +vim.api.nvim_set_hl(0, 'LuasnipIndicator', { + fg = vim.g.terminal_color_15, + bg = vim.g.terminal_color_1, + italic = true, + nocombine = true, +}) + +-- autowrap: wraps the function in top and bot if there is any content +local autowrap = function(top, bot, inner) + local autoinsert = function(args, _, _, wrap_with) + local nodes = {} + if vim.trim(table.concat(args[1] or {})) ~= "" then + table.insert(nodes, wrap_with) + end + return ls.sn(nil, nodes) + end + + local argnodes = {} + local maxpos = -1 + for _, e in ipairs(inner) do + if e.pos ~= nil then + table.insert(argnodes, e.pos) + if e.pos > maxpos then + maxpos = e.pos + end + end + end + + local nodes = {} + table.insert(nodes, ls.d(maxpos+1, autoinsert, argnodes, {user_args = {top}})) + for _, e in ipairs(inner) do table.insert(nodes, e) end + table.insert(nodes, ls.d(maxpos+2, autoinsert, argnodes, {user_args = {bot}})) + return nodes +end + +-- comment: wraps the content in &commentstring (or a blockcomment) +local comment = function(wrapped, blockcomment) + -- commentstring helper + local get_cstring = function() + local cs = require('Comment.ft').calculate { + ctype = blockcomment and 2 or 1, + range = require('Comment.utils').get_region() + } + local tbl = vim.split(cs or '', '%s', {plain = true, trimempty = true}) + return (#tbl == 0) and {'', ''} + or ((#tbl == 1) and {tbl[1] .. ' ', ''} + or {tbl[1], tbl[2]}) + end + + if type(wrapped) ~= "table" then + wrapped = {wrapped} + end + + local nodes = {} + table.insert(nodes, ls.f(function() return get_cstring()[1] end)) + for _, n in ipairs(wrapped) do table.insert(nodes, n) end + table.insert(nodes, ls.f(function() return get_cstring()[2] end)) + return nodes +end + +-- exec: inserts the output of command +local exec = function(command) + return ls.f(function(_, _, ...) + local results, code = require('plenary.job'):new({ + command = vim.env.SHELL, + args = {'-c', ...}, + enable_recording = true, + }):sync() + if not code == 0 or #results == 0 then + error(string.format('exec "%s" failed', ...)) + end + return results + end, {}, {user_args = {command}}) +end + +ls.setup { + ext_opts = { + [types.snippet] = { + active = { virt_text = {{ '<-- luasnip', 'LuasnipIndicator' }}, virt_text_pos = 'right_align' } + }, + [types.insertNode] = { + unvisited = { hl_group = 'LuasnipIndicator' } + }, + [types.choiceNode] = { + active = { + virt_text = {{'<-- choice node', 'LuasnipIndicator'}}, + } + } + }, + + snip_env = vim.tbl_extend('keep', ls.session.config.snip_env, { + autowrap = autowrap, + exec = exec, + comment = comment, + + user_email = { + exec([[git config --get user.name]]), + ls.t(' <'), + ls.c(1, { + exec([[git config --get user.email]]), + ls.t([[robert.gunzler@postman.com]]), + ls.t([[robert@gnzler.io]]), + }), + ls.t('>'), + }, + }) +} + +-- snipmate snippets +require('luasnip.loaders.from_snipmate').lazy_load {paths = './after/snippets'} +-- lua snippets +require("luasnip.loaders.from_lua").lazy_load {paths = './snippets'} + +vim.api.nvim_create_user_command('LuaSnipUnlinkAll', + function() + while #package.loaded.luasnip.session.current_nodes > 0 do + package.loaded.luasnip.unlink_current() + end + end, + { desc = 'unlink all active snippets' }) diff --git a/.vim/lua/internal/spell.lua b/.vim/lua/internal/spell.lua new file mode 100644 index 0000000..57cbad2 --- /dev/null +++ b/.vim/lua/internal/spell.lua @@ -0,0 +1,9 @@ + +vim.opt_local.spell = true +vim.opt.spellfile = vim.fn['spellfile#WritableSpellDir']() .. '/spellfile.utf-8.add' +vim.opt.spellcapcheck = '' +vim.opt.spelloptions = {'camel'} +vim.opt.spellsuggest = 'double' + +vim.keymap.set('n', '', require('telescope.builtin').spell_suggest) +vim.keymap.set('n', '', [[u[s1z=`]au]]) diff --git a/.vim/lua/internal/statusline.lua b/.vim/lua/internal/statusline.lua new file mode 100644 index 0000000..97f5031 --- /dev/null +++ b/.vim/lua/internal/statusline.lua @@ -0,0 +1,255 @@ +function _G.statusline() + local bufnr = vim.fn.bufnr() or 0 + local hi = statusline_color(vim.fn.mode()) + + local sl = hi + -- sl = sl .. statusline_append([[ ⢷]], 'StatusLineIcon', hi) + + sl = sl .. statusline_append(statusline_lightbulb(), + 'StatusLineLightbulb', hi) + + sl = sl .. statusline_append(statusline_ts(), + 'StatusLineTreesitter', hi) + + sl = sl .. statusline_append(statusline_lsp_diagnostics(bufnr, hi), + 'StatusLineDiagnostics', hi) + + sl = sl .. statusline_append(statusline_lspstatus(), + 'StatusLineLsp', hi) + + sl = sl .. statusline_append(statusline_dap(), + 'StatusLineDap', hi) + + sl = sl .. [[ %= ]] -- spacer + + sl = sl .. statusline_append(statusline_notify(hi), + 'StatusLineNotify', hi) + + sl = sl .. statusline_append(statusline_spinner(bufnr), + 'StatusLineJobs', hi) + + sl = sl .. statusline_append([[ %l:%v --%p%%-- %y]], hi, hi) + + return sl +end + +function _G.statusline_color(mode) + local hi = '%*' + if mode == 'i' then + -- hi = '%#StatusLineInsert#' + elseif mode == 'c' then + -- hi = '%#StatusLineCommand#' + elseif mode == 'v' or mode == 'V' or mode == '' then + hi = '%#StatusLineVisual#' + elseif mode == 'R' or mode == 'Rv' then + hi = '%#StatusLineReplace#' + end + -- return '%{g:actual_curwin==win_getid()?'.. hi ..':%#StatusLineNC#}' + return hi +end +-- does item highlighting and conditionnal spacing +function _G.statusline_append(element, hi, default_hi, opts) + if not element or element == '' then return '' end + opts = opts or { append_space = true } + + if hi ~= nil then hi = '%#' .. hi .. '#' end + if not (default_hi == '%*') then hi = default_hi end + local el = hi .. element .. default_hi + if opts.append_space then el = el .. ' ' end + return el +end +function _G.statusline_combine_hi(outer_name, inner_name) + local outer = vim.api.nvim_get_hl_by_id(vim.api.nvim_get_hl_id_by_name(outer_name), true) + local inner = vim.api.nvim_get_hl_by_id(vim.api.nvim_get_hl_id_by_name(inner_name), true) + local hi = 'auto' .. outer_name .. inner_name + if pcall(vim.api.nvim_get_hl_by_name, hi, true) then return hi end + local gui + gui = inner.bold and 'bold' + gui = inner.italic and 'italic' + gui = inner.underline and 'underline' + vim.api.nvim_set_hl(0, hi, {bg = outer.background, fg = inner.foreground, gui = gui}) + return hi +end + +function _G.statusline_lsp_diagnostics(bufnr, default_hi) + local error_num = vim.diagnostic.get(bufnr, {severity=vim.diagnostic.severity.ERROR}) + local warn_num = vim.diagnostic.get(bufnr, {severity=vim.diagnostic.severity.WARN}) + + local s = '' + if #error_num > 0 then + local errs = vim.fn.sign_getdefined('DiagnosticSignError')[1].text .. #error_num + s = s .. statusline_append(errs, statusline_combine_hi('StatusLineDiagnostics', 'DiagnosticError'), default_hi) + end + if #warn_num > 0 then + local warns = vim.fn.sign_getdefined('DiagnosticSignWarn')[1].text .. #warn_num + s = s .. statusline_append(warns, statusline_combine_hi('StatusLineDiagnostics', 'DiagnosticWarn'), default_hi) + end + return vim.trim(s) +end +function _G.statusline_ts() + local navic = package.loaded['nvim-navic'] + if not navic then return '' end + local data = navic.get_data() + if not data then return '' end + local s = {} + for i = 1, #data do + table.insert(s, string.format('%%#CmpItemKind%s#%s%%* %%#StatusLine#%s%%*', data[i].type, data[i].icon, data[i].name)) + end + return table.concat(s, ' > ') +end +function _G.statusline_lspstatus() + local lst = package.loaded['lsp-status'] + if not lst then return '' end + return vim.trim(lst.status()) +end +function _G.statusline_lightbulb() + local lb = package.loaded['nvim-lightbulb'] + if not lb then return '' end + return lb.get_status_text() +end +function _G.statusline_spinner(bufnr) + local sp = package.loaded.spinner + if not sp then return '' end + return sp.status(bufnr) +end +function _G.statusline_dap() + local dap = package.loaded.dap + if not dap then return '' end + local s = dap.status() + if s == '' then return s end + return '[DAP: ' .. s .. ']' +end + +-- notifications cache +_G.statusline_notifications = {} +_G.statusline_notifications_archive = {} + +function _G.statusline_notify(default_hi) + if #_G.statusline_notifications == 0 then return '' end + local n = _G.statusline_notifications[1] + local timeout = (n.options and n.options.timeout) or 2000 + -- pop message after and move to archive + vim.defer_fn(function() + local n = table.remove(_G.statusline_notifications, 1) + table.insert(_G.statusline_notifications_archive, n) + -- make sure archive is never longer than 20 notifications + if #_G.statusline_notifications_archive > 20 then + table.remove(_G.statusline_notifications_archive, 1) + end + end, timeout) + + local s = '' + if n.hi then + s = s .. statusline_append(n.lvl_string .. ' ', statusline_combine_hi('StatusLineNotify', n.hi), default_hi, { append_space = false }) + end + s = s .. statusline_append(n.message, 'StatusLineNotify', default_hi) + return vim.trim(s) +end + +-- out vim.notify implementation +local notify = function(m, l, o) + local lvl_string = l + local hi = nil + if l and type(l) == 'number' then + if l == vim.log.levels.TRACE then + hi = 'deEmph' + elseif l == vim.log.levels.DEBUG then + hi = 'DiagnosticHint' + elseif l == vim.log.levels.INFO then + hi = 'DiagnosticInfo' + elseif l == vim.log.levels.WARN then + hi = 'DiagnosticWarn' + elseif l == vim.log.levels.ERROR then + hi = 'DiagnosticError' + end + -- get level string + lvl_string = vim.lsp.log_levels[l] + end + local display = m + if lvl_string then display = lvl_string .. ' ' .. display end + table.insert(_G.statusline_notifications, { + message = m, + level = l, + options = o, + lvl_string = lvl_string, + hi = hi, + display = display, + }) + + if _G.statusline_enable_notifysend then + local args = {} + if lvl_string then + if lvl_string == 'ERROR' then + table.insert(args, '--category=error') + end + if lvl_string == 'WARN' then + table.insert(args, '--category=warning') + end + end + table.insert(args, 'nvim') + table.insert(args, display) + require('internal.job').jobstart { command = 'notify-send', args = args } + end +end + +-- overwrite vim.notify +vim.notify = function( m, l, o) + if vim.in_fast_event() then + vim.schedule(function() + notify(m, l, o) + end) + else + return notify(m, l, o) + end +end + +vim.keymap.set('n', 'n', function() + local pickers = require('telescope.pickers') + local finders = require('telescope.finders') + local conf = require('telescope.config').values + local actions = require('telescope.actions') + -- local action_state = require('telescope.actions.state') + -- local previewers = require('telescope.previewers') + + local opts = {} + pickers.new(opts, { + prompt_title = "Notifications", + finder = finders.new_dynamic { + fn = function() + return _G.statusline_notifications_archive + end, + entry_maker = function(n) + return { + value = n, + display = n.display, + ordinal = n.message, + } + end, + }, + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + -- noop + -- local sel = action_state.get_selected_entry() + -- vim.notify(sel.value.message, sel.value.level, sel.value.options) + end) + return true + end, + -- previewer = previewers.new_buffer_previewer { + -- define_preview = function(self, entry) + -- vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, {entry.value.display}) + -- end, + -- }, + }):find() +end, {desc='notifications'}) + +-- vim.opt.statusline = '%!luaeval("statusline()")' +vim.opt.statusline = '%{%v:lua.statusline()%}' + +-- WINBAR -- +vim.opt.winbar = [[%h%w%q%f %-m %-r %= %#WinBarCwd#%{%getcwd()%}%*]] -- keep it simple +-- function _G.winbar() +-- return [[%<%F %-m %-r]] +-- end +-- vim.opt.winbar = '%{%v:lua.winbar()%}' diff --git a/.vim/lua/job.lua b/.vim/lua/job.lua deleted file mode 100644 index f9f7bf3..0000000 --- a/.vim/lua/job.lua +++ /dev/null @@ -1,140 +0,0 @@ -local Job = require ('plenary.job') -local spinner_ok, spinner = pcall(require, 'spinner.core') - -local M = { - current_jobs = {} -} - -local strip_ansi = function(line) - return line:gsub(string.char(27) .. '[[0-9;]*m', '') -end - ---create a new job and register ---@return ~/.local/share/nvim/site/pack/packer/start/plenary.nvim/lua/plenary/job.lua -function M.jobstart(opts) - opts = opts or {} - - -- default options - -- opts.enable_recording = true - opts.enable_spinner = (opts.enable_spinner or true) and spinner_ok - opts.populate_quickfix = opts.populate_quickfix or true - - local title - if opts.format_title then - title = opts.format_title(opts.command, opts.args) - opts.format_title = nil - else - title = opts.command - end - - opts.on_start = vim.schedule_wrap(function(j) - table.insert(M.current_jobs, j.pid, j) - - if opts.populate_quickfix then - -- clear quickfix - vim.fn.setqflist({}, 'r') - end - - if opts.enable_spinner then - spinner.on_attach(j.pid, title, vim.fn.bufnr()) - spinner.on_progress('begin', j.pid, j.pid) - end - end) - - opts.on_exit = vim.schedule_wrap(function(j, _) - table.remove(M.current_jobs, j.pid) - - if opts.populate_quickfix then - vim.cmd([[doautocmd QuickFixCmdPost]]) - -- vim.fn.setqflist({}, 'r', { - -- lines = {}, - -- id = j.pid, - -- }) - end - - if opts.enable_spinner then - spinner.on_progress('end', j.pid, j.pid) - spinner.on_exit(nil, nil, j.pid) - end - end) - - opts.on_stdout = vim.schedule_wrap(function(error, data, j) - if error then - vim.notify('error: ' .. error) - return - end -- handle error? - - if opts.populate_quickfix and data then - vim.fn.setqflist({}, 'a', { - title = title, - lines = {strip_ansi(data)}, - efm = '%m', - id = j.pid, - }) - end - end) - - opts.on_stderr = vim.schedule_wrap(function(error, data, j) - if error then - vim.notify('error: ' .. error) - return - end -- handle error? - - if opts.populate_quickfix and data then - vim.fn.setqflist({}, 'a', { - title = title, - lines = {strip_ansi(data)}, - efm = '%m', - id = j.pid, - }) - vim.cmd([[doautocmd QuickFixCmdPost]]) - end - end) - - -- run vim.fn.expand() on all args - for i=1, #opts.args do - opts.args[i] = vim.fn.expandcmd(opts.args[i]) - end - - local j = Job:new(opts) - j:start() - - return j -end - -function M.make(extra_args) - local makeprg = vim.fn.expandcmd(vim.opt.makeprg:get()) - -- split makeprg into command + args - local args = vim.split(makeprg, ' ') - local command = args[1] - table.remove(args, 1) - - local cwd = vim.fn.expand('%:p:h') - - if not (string.match(makeprg, 'make') == nil) then - -- detect makefile - cwd = require('lspconfig.util').root_pattern('Makefile')(cwd) - end - - table.foreach(extra_args or {}, function(_, v) table.insert(args, v) end) - - return M.jobstart { - command = command, - args = args, - cwd = cwd, - } -end - -function M.sh(command_string) - return M.jobstart { - command = vim.env.SHELL, - args = {'-c', command_string}, - - -- strip 'sh -c' from the title (used by progress reporting etc.) - format_title = function(_, args) - return require('plenary.collections.py_list')(args):slice(2,#args):join(' ') - end - } -end - -return M diff --git a/.vim/lua/lsp.lua b/.vim/lua/lsp.lua deleted file mode 100644 index 8d16987..0000000 --- a/.vim/lua/lsp.lua +++ /dev/null @@ -1,299 +0,0 @@ -local lsp = require('lspconfig') -local lspstatus = require('lsp-status') - -local my_attach = function(client, bufnr) - if vim.opt.diff:get() then - vim.notify('not running LSP client in diff mode', vim.log.levels.WARN) - vim.lsp.stop_client() - return - end - - local group = vim.api.nvim_create_augroup('LspOnAttach', {}) - vim.api.nvim_create_autocmd('CursorHold', { - buffer = bufnr, - group = group, - callback = function() - if not _G.diagnostic_hidden then - vim.diagnostic.open_float(nil, { - focusable = false, - close_events = {'BufLeave', 'CursorMoved', 'InsertEnter', 'FocusLost'}, - border = _G.floating_win_border, - source = 'always', - prefix = ' ', - scope = 'cursor', - }) - end - end, - }) - - lspstatus.on_attach(client) - if client.supports_method('textDocument/symbols') then - require('nvim-navic').attach(client, bufnr) - require('aerial').on_attach(client, bufnr) - end - - if client.supports_method('textDocument/definition') then - vim.keymap.set('n', '' , vim.lsp.buf.definition, {buffer = bufnr, desc = 'goto definition'}) - vim.keymap.set('n', 'gd' , vim.lsp.buf.definition, {buffer = bufnr, desc = 'goto definition'}) - vim.keymap.set('n', 'gR' , vim.lsp.buf.references, {buffer = bufnr, desc = 'goto references'}) - end - if client.supports_method('textDocument/hover') then - vim.keymap.set('n', 'K' , vim.lsp.buf.hover, {buffer = bufnr, desc = 'hover'}) - end - if client.supports_method('textDocument/rename') then - vim.keymap.set('n', 'grr' , vim.lsp.buf.rename, {buffer = bufnr, desc = 'rename'}) - end - if client.supports_method('signatureHelp') then - vim.keymap.set('n', '' , vim.lsp.buf.signature_help, {buffer = bufnr, desc = 'signature help'}) - end - if client.supports_method('textDocument/formatting') then - vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr()') - vim.keymap.set('n', 'f' , vim.lsp.buf.format, {buffer = bufnr, desc = 'format'}) - vim.api.nvim_create_autocmd('BufWritePre', { - buffer = bufnr, - group = group, - callback = function() require('lsp').format(vim.fn.expand(':p')) end, - }) - end - if client.supports_method('textDocument/typeDefinition') then - vim.keymap.set('n', 'gT' , vim.lsp.buf.type_definition, {buffer = bufnr, desc = 'goto typedef'}) - end - if client.supports_method('textDocument/declaration') then - vim.keymap.set('n', 'gD' , vim.lsp.buf.declaration, {buffer = bufnr, desc = 'goto declaration'}) - end - if client.supports_method('textDocument/implementation') then - vim.keymap.set('n', 'gI' , vim.lsp.buf.implementation, {buffer = bufnr, desc = 'goto implementation'}) - end - if client.supports_method('workspace/symbol') then - vim.keymap.set('n', 'gW' , vim.lsp.buf.workspace_symbol, {buffer = bufnr, desc = 'goto symbol'}) - end - -- if client.resolved_capabilities.document_symbol then - -- vim.keymap.set('n', 'g0', vim.lsp.buf.document_symbol, {buffer = bufnr}) - -- end - if client.supports_method('textDocument/codeAction') then - vim.keymap.set('n', 'ga', vim.lsp.buf.code_action, {buffer = bufnr, desc = 'code action'}) - end - - if client.supports_method('textDocument/documentHighlight') then - vim.keymap.set('n', '8', vim.lsp.buf.document_highlight, {buffer = bufnr, desc = 'document highlight'}) - -- vim.keymap.set('n', '', vim.lsp.buf.clear_references, {buffer = bufnr, desc = 'clear references'}) - vim.api.nvim_create_autocmd('CursorMoved', { - callback = vim.lsp.buf.clear_references, - buffer = bufnr, - }) - end -end - -local my_exit = function(_, _, _) -end - -local capabilities = function() - local caps = vim.lsp.protocol.make_client_capabilities() - -- enable lsp-based snippets - caps.textDocument.completion.completionItem.snippetSupport = true - caps.textDocument.completion.completionItem.resolveSupport = { - properties = { - 'documentation', - 'detail', - 'additionalTextEdits', - } - } - -- add window/workDoneProgress capability - caps = vim.tbl_extend('keep', caps or {}, lspstatus.capabilities) - return caps -end - -local servers = { - ccls = { disabled = true, - root_dir = lsp.util.root_pattern('.ccls','meson.build','.git'), - init_options = { - compilationDatabaseDirectory = "build", - index = { threads = 0 }, - completion = { - filterAndSort = false, - }, - clang = { excludeArgs = { '-frounding-math' } }, - }, - }, - clangd = { - root_dir = lsp.util.root_pattern('.ccls','meson.build','.git'), - }, - elixirls = { - cmd = { 'elixir-ls' }, - settings = { - elixirLS = { - dialyzerEnabled = false, - } - } - }, - gopls = { - settings = { - gopls = { - analyses = { - -- composites = false, - fieldalignment = true, - nilness = true, - shadow = false, - unusedparams = true, - unusedwrite = true, - }, - gofumpt = true, - -- hoverKind = 'Structured', - } - } - }, - sumneko_lua = { - cmd = { 'lua-language-server' }, - settings = { - Lua = { - runtime = { - version = 'LuaJIT', - path = vim.split(package.path, ';'), - }, - diagnostics = { - globals = { - '_G', - 'assert', - 'error', - 'os', - 'package', - 'pairs', 'ipairs', - 'pcall', - 'require', - 'string', - 'table', - 'type', - 'vim', - }, - neededFileStatus = { - ['code-style-check'] = 'Any', - } - }, - format = { - enable = true, - defaultConfig = { - indent_style = 'space', - indent_size = '2', - } - }, - workspace = { - -- library = vim.api.nvim_get_runtime_file("", true), - library = { - [vim.env.VIMRUNTIME .. '/lua'] = true, - [vim.env.VIMRUNTIME .. '/lua/vim/lsp'] = true, - } - }, - telemetry = { - enable = false, - }, - }, - }, - }, - rust_analyzer = { - cmd = { 'env', 'CARGO_TARGET_DIR=/tmp', 'RUST_SRC_PATH=/usr/src/rustlib/library', 'rust-analyzer' }, - settings = { - ['rust-analyzer'] = { - checkOnSave = { - command = 'clippy' - } - } - }, - }, - tsserver = { disabled = true, - cmd = { - 'toolbox', 'run', '--', - 'sh', '-c', - '. /etc/profile.d/nvm.sh && typescript-language-server --stdio' - }, - }, - zls = { disabled = true, - }, - zk = { disabled = true, - root_dir = lsp.util.root_pattern('.zk'), - }, -} - -local setup = function() - -- configure floating win handlers - vim.lsp.handlers['textDocument/hover'] = vim.lsp.with( - vim.lsp.handlers.hover, { border = _G.floating_win_border }) - vim.lsp.handlers['textDocument/signature_help'] = vim.lsp.with( - vim.lsp.handlers.signature_help, { border = _G.floating_win_border }) - - local caps = capabilities() - for server, opts in pairs(servers) do - if not opts.disabled then - opts = vim.tbl_extend('error', opts, { - on_attach = my_attach, - on_exit = my_exit, - capabilities = caps, - }) - -- lsp-status custom handlers - local ok, lspstatus_ext = pcall(lspstatus.extensions[server]) - if ok then - opts = vim.tbl_extend('error', opts, { - handlers = lspstatus_ext.setup(), - }) - end - lsp[server].setup(opts) - end - end -end - -local format = function(afile) - if vim.g.nofmt then return end - if not string.match(afile, '^/home/robert/devel/upstream') then - vim.lsp.buf.format() - if string.match(afile, '.go$') then - vim.lsp.buf.code_action({ only = {'source.organizeImports'} }) - end - -- vim.notify('%#MoreMsg#󰃢%#Italic# fmt') - vim.notify('%#MoreMsg#󰃢%#Italic# fmt') - end -end - -local symbols = { - -- 󰆼 󱆃 - Array = '󰨾 ', - Boolean = '󰦍 ', - Class = '󰙀 ', - Color = '󰉦 ', - Constant = ' ', - Constructor = '󱇿 ', - Enum = ' ', - EnumMember = ' ', - Event = '󱐋 ', - -- Field = '󰽜 ', - Field = '󰆈 ', - File = '󰈔 ', - Folder = '󰝰 ', - Function = ' ', - Interface = '󱦜 ', - Key = '󰌋 ', - Keyword = '󰓽 ', - Method = '󰒓 ', - Module = '󰏖 ', - Namespace = '󰆧 ', - Null = '󰎣 ', - Object = '󰘦 ', - Operator = '󱓉 ', - Property = '󰐱 ', - Package = '󰏗 ', - Reference = '󰌹 ', - Snippet = '󰯁 ', - Struct = '󰙅 ', - Text = '󰉿 ', - TypeParameter = '󰌨 ', - Unit = '󰠱 ', - Value = '󰎠 ', - Variable = '󱄑 ', -} - -return { - my_attach = my_attach, - my_exit = my_exit, - capabilities = capabilities, - setup = setup, - format = format, - symbols = symbols, -} diff --git a/.vim/lua/misc.lua b/.vim/lua/misc.lua deleted file mode 100644 index 6c642f4..0000000 --- a/.vim/lua/misc.lua +++ /dev/null @@ -1,178 +0,0 @@ --- misc stuff implemented in lua - -local M = {} - -function M.do_under_cursor(obj, cb) - return cb(vim.fn.expand(vim.fn.expand(obj))) -end - -function M.word_under_cursor(cb) - return M.do_under_cursor('', cb) -end - -function M.expr_under_cursor(cb) - return M.do_under_cursor('', cb) -end - -function M.file_under_cursor(cb) - return M.do_under_cursor('', cb) -end - -function M.open_under_cursor(cmd, detect_cmd) - return M.file_under_cursor(function(txt) - txt = vim.trim(txt) - if not cmd and detect_cmd then - if vim.regex([[^http.*$]]):match_str(txt) then - cmd = 'url-launcher' - end - if vim.regex([[^(\.\./|[\w\d_/\-])*(\.[\w\d]+)?$]]):match_str(txt) then - cmd = ':edit' - end - vim.notify("open_under_cursor: detected command " .. txt .. " => " .. (cmd or "")) - end - if not cmd then - vim.fn.inputsave() - vim.ui.input('open with: ', function(result) cmd = result end) - vim.fn.inputrestore() - if not cmd then return end - end - -- detect vim command - if cmd:sub(1, 1) == ":" then - vim.cmd(cmd:sub(2) .. ' ' .. txt) - else - vim.loop.spawn(cmd, {args = {txt}}) - end - end) -end - -local function get_visual_selection() - local top = vim.fn.getpos("'<") - top = { ln = top[2], col = top[3] } - local bot = vim.fn.getpos("'>") - bot = { ln = bot[2], col = bot[3] } - local lines = vim.api.nvim_buf_get_lines(0, (top.ln - 1), bot.ln, false) - if vim.opt.selection:get() == 'inclusive' then - lines[#lines] = lines[#lines]:sub(1, bot.col) - else - lines[#lines] = lines[#lines]:sub(1, (bot.col -1)) - end - lines[1] = lines[1]:sub(top.col) - return top, bot, lines -end - -function M.sort_lines(_, preview_ns, preview_bufnr) - local bufnr = vim.api.nvim_get_current_buf() - - local top, bot, lines = get_visual_selection() - for i=1, #lines do - lines[i] = vim.fn.join(vim.fn.sort(vim.fn.split(lines[i], " "))) - end - - if not preview_ns then - vim.api.nvim_buf_set_lines(bufnr, top.ln-1, bot.ln, false, lines) - vim.notify('no preview') - return 0 - end - - -- inccommand preview - if preview_ns ~= nil then - for i, line in ipairs(lines) do - vim.api.nvim_buf_set_extmark(bufnr, preview_ns, top.ln+i - 2, 0, { - hl_mode = 'combine', - virt_text_pos = 'overlay', - virt_text = {{line, 'Substitute'}}, - }) - - if preview_bufnr ~= nil then - local prefix = string.format('|%d| ', top.ln + i - 1) - vim.api.nvim_buf_set_lines(preview_bufnr, i-1, -1, false, { prefix .. line }) - vim.api.nvim_buf_add_highlight(preview_bufnr, preview_ns, 'Substitute', i, #prefix, #prefix+#line) - end - end - return (#lines > 1 and 2 or 1) - end -end - -local function get_searchdirs(dirs) - -- skip asking if we're looking at known filetypes - local ft = vim.api.nvim_buf_get_option(0, 'filetype') - if not dirs and (ft == 'dirbuf' or ft == 'alpha') then - dirs = '%:p:h' - end - if not dirs then - vim.ui.input('Search directories: ', function(result) dirs = result end) - end - -- default to something reasonable - if not dirs then dirs = '%:p:h' end - return vim.split(vim.fn.expand(dirs), ',') -end - -function M.live_grep(dirs, opts) - opts = opts or {} - local search_dirs = get_searchdirs(dirs) - opts.search_dirs = search_dirs - opts.prompt_title = 'Grep: '.. vim.inspect(search_dirs) - return require('telescope.builtin').live_grep(opts) -end - -function M.find_files(dirs, opts) - opts = opts or {} - local search_dirs = get_searchdirs(dirs) - opts.search_dirs = search_dirs - opts.prompt_title = 'Files: '.. vim.inspect(search_dirs) - return require('telescope.builtin').find_files(opts) -end - - -function M.fold_block() -- {{{ - local Comment = require('Comment.api') - local m = vim.api.nvim_buf_get_mark - local inital_cusor_pos = vim.api.nvim_win_get_cursor(0) - local spos, epos = m(0, '<'), m(0, '>') - - -- do start of selection - vim.api.nvim_win_set_cursor(0, spos) - Comment.insert_linewise_eol() - vim.api.nvim_feedkeys('\\', 'ni', true) - local sln = vim.api.nvim_get_current_line() - vim.api.nvim_set_current_line(sln .. '{{{') - - -- do end of selection - vim.api.nvim_win_set_cursor(0, epos) - Comment.insert_linewise_eol() - vim.api.nvim_feedkeys('\\', 'ni', true) - local eln = vim.api.nvim_get_current_line() - vim.api.nvim_set_current_line(eln .. '}}}') - - -- restore initial cursor postition - vim.api.nvim_win_set_cursor(0, inital_cusor_pos) -end -- }}} - -function M.link_preview() - local link = vim.fn.expand('') - if not link then return end - - local buf = vim.api.nvim_get_current_buf() - local ln = (vim.api.nvim_win_get_cursor(0)[1]) - 1 - - local j = require('job').jobstart({ - format_title = function() return "link-preview" end, - command = vim.env.SHELL, - args = {'-c', [[ curl -sSfL ]] .. link .. [[ | grep -iPo '(?<=property="og:title" content=")([^\"]+)(?=")' ]]}, - populate_quickfix = false, - enable_recording = true, - }) - - j:after_success(vim.schedule_wrap(function(j, code, _) - local results = j:result() - if not code == 0 or #results == 0 then return end - - local ns = vim.api.nvim_create_namespace('') - vim.api.nvim_buf_set_extmark(buf, ns, ln, 0, { - virt_text = {{results[1], 'Error'}}, - virt_text_pos = 'eol' - }) - end)) -end - -return M diff --git a/.vim/lua/plugins.lua b/.vim/lua/plugins.lua index de7a984..e8630f2 100644 --- a/.vim/lua/plugins.lua +++ b/.vim/lua/plugins.lua @@ -349,7 +349,8 @@ require('packer').startup({function() 'stevearc/aerial.nvim', }, config = function() - require('lsp').setup() + require('telescope').load_extension('lsp_handlers') + require('internal.lsp').setup() end} -- }}} use {'nvim-lua/lsp-status.nvim', -- {{{ @@ -382,7 +383,7 @@ require('packer').startup({function() 'Constant', 'Variable', }, - icons = require('lsp').symbols, + icons = require('internal.lsp').symbols, close_automatic_events = {'switch_buffer'}, open_automatic = function(bufnr) return vim.api.nvim_buf_line_count(bufnr) > 80 @@ -399,7 +400,7 @@ require('packer').startup({function() config = function() local navic = require('nvim-navic') navic.setup { - icons = require('lsp').symbols, + icons = require('internal.lsp').symbols, } end} -- }}} @@ -445,14 +446,15 @@ require('packer').startup({function() -- nls.builtins.formatting.rustfmt, -- nls.builtins.formatting.stylua, }, - on_attach = require('lsp').my_attach, + on_attach = require('internal.lsp').my_attach, } end} -- }}} use {'mfussenegger/nvim-dap', module = {'dap'}, -- {{{ requires = {'nvim-telescope/telescope-dap.nvim'}, config = function() - require('debugger') + require('telescope').load_extension('dap') + require('internal.dap') end} -- }}} use {'hrsh7th/nvim-cmp', -- {{{ @@ -616,7 +618,7 @@ require('packer').startup({function() path = '░ path', buffer = '░ buf', } - item.kind = package.loaded.lsp.symbols[item.kind] or '' + item.kind = require('internal.lsp').symbols[item.kind] or '' item.menu = menus[entry.source.name] return item end, @@ -651,7 +653,7 @@ require('packer').startup({function() use {'L3MON4D3/LuaSnip', -- {{{ config = function() - require('snips') + require('internal.snips') end} -- }}} use {'nvim-telescope/telescope.nvim', --- {{{ @@ -898,7 +900,7 @@ require('packer').startup({function() use {'mickael-menu/zk-nvim', module = {'zk', 'telescope._extensions.zk'}, -- {{{ config = function() - local lsp = require('lsp') + local lsp = require('internal.lsp') require('zk').setup { picker = 'telescope', lsp = { @@ -1154,8 +1156,8 @@ require('packer').startup({function() {type = 'padding', val = 1}, {type = 'group', val = { -- buttons {{{ button('e', '󰈔 new', [[ene startinsert]]), - button('r', '󰈸 live grep', [[lua require('misc').live_grep()]]), - button('f', '󰝰 find files', [[lua require('misc').find_files()]]), + button('r', '󰈸 live grep', [[lua require('internal.misc').live_grep()]]), + button('f', '󰝰 find files', [[lua require('internal.misc').find_files()]]), button('m', '󰥔 mru', [[lua require('telescope.builtin').oldfiles()]]), -- button('o', '󰃶 orgmode', [[lua require('packer').loader('orgmode.nvim'); require('orgmode').action('agenda.prompt')]]), button('T', '󰃶 todos', [[lua require('telescope._extensions.todo-comments').exports.todo {cwd=vim.env.ZK_NOTEBOOK_DIR}]]), @@ -1269,3 +1271,4 @@ config = { if vim.fn.empty(vim.fn.glob(compilepath)) > 0 then require('packer').sync() end + diff --git a/.vim/lua/snips.lua b/.vim/lua/snips.lua deleted file mode 100644 index 318c9f7..0000000 --- a/.vim/lua/snips.lua +++ /dev/null @@ -1,124 +0,0 @@ - -local ls = require('luasnip') -local types = require('luasnip.util.types') - -vim.api.nvim_set_hl(0, 'LuasnipIndicator', { - fg = vim.g.terminal_color_15, - bg = vim.g.terminal_color_1, - italic = true, - nocombine = true, -}) - --- autowrap: wraps the function in top and bot if there is any content -local autowrap = function(top, bot, inner) - local autoinsert = function(args, _, _, wrap_with) - local nodes = {} - if vim.trim(table.concat(args[1] or {})) ~= "" then - table.insert(nodes, wrap_with) - end - return ls.sn(nil, nodes) - end - - local argnodes = {} - local maxpos = -1 - for _, e in ipairs(inner) do - if e.pos ~= nil then - table.insert(argnodes, e.pos) - if e.pos > maxpos then - maxpos = e.pos - end - end - end - - local nodes = {} - table.insert(nodes, ls.d(maxpos+1, autoinsert, argnodes, {user_args = {top}})) - for _, e in ipairs(inner) do table.insert(nodes, e) end - table.insert(nodes, ls.d(maxpos+2, autoinsert, argnodes, {user_args = {bot}})) - return nodes -end - --- comment: wraps the content in &commentstring (or a blockcomment) -local comment = function(wrapped, blockcomment) - -- commentstring helper - local get_cstring = function() - local cs = require('Comment.ft').calculate { - ctype = blockcomment and 2 or 1, - range = require('Comment.utils').get_region() - } - local tbl = vim.split(cs or '', '%s', {plain = true, trimempty = true}) - return (#tbl == 0) and {'', ''} - or ((#tbl == 1) and {tbl[1] .. ' ', ''} - or {tbl[1], tbl[2]}) - end - - if type(wrapped) ~= "table" then - wrapped = {wrapped} - end - - local nodes = {} - table.insert(nodes, ls.f(function() return get_cstring()[1] end)) - for _, n in ipairs(wrapped) do table.insert(nodes, n) end - table.insert(nodes, ls.f(function() return get_cstring()[2] end)) - return nodes -end - --- exec: inserts the output of command -local exec = function(command) - return ls.f(function(_, _, ...) - local results, code = require('plenary.job'):new({ - command = vim.env.SHELL, - args = {'-c', ...}, - enable_recording = true, - }):sync() - if not code == 0 or #results == 0 then - error(string.format('exec "%s" failed', ...)) - end - return results - end, {}, {user_args = {command}}) -end - -ls.setup { - ext_opts = { - [types.snippet] = { - active = { virt_text = {{ '<-- luasnip', 'LuasnipIndicator' }}, virt_text_pos = 'right_align' } - }, - [types.insertNode] = { - unvisited = { hl_group = 'LuasnipIndicator' } - }, - [types.choiceNode] = { - active = { - virt_text = {{'<-- choice node', 'LuasnipIndicator'}}, - } - } - }, - - snip_env = vim.tbl_extend('keep', ls.session.config.snip_env, { - autowrap = autowrap, - exec = exec, - comment = comment, - - user_email = { - exec([[git config --get user.name]]), - ls.t(' <'), - ls.c(1, { - exec([[git config --get user.email]]), - ls.t([[robert.gunzler@postman.com]]), - ls.t([[robert@gnzler.io]]), - }), - ls.t('>'), - }, - }) -} - --- snipmate snippets -require('luasnip.loaders.from_snipmate').lazy_load {paths = './after/snippets'} --- lua snippets -require("luasnip.loaders.from_lua").lazy_load {paths = './snippets'} - -vim.api.nvim_create_user_command('LuaSnipUnlinkAll', - function() - while #package.loaded.luasnip.session.current_nodes > 0 do - package.loaded.luasnip.unlink_current() - end - end, - { desc = 'unlink all active snippets' }) diff --git a/.vim/lua/spell.lua b/.vim/lua/spell.lua deleted file mode 100644 index e5cfca1..0000000 --- a/.vim/lua/spell.lua +++ /dev/null @@ -1,10 +0,0 @@ - -vim.opt_local.spell = true -vim.opt.spelllang = {'en_gb', 'de_de'} -vim.opt.spellfile = vim.fn['spellfile#WritableSpellDir']() .. '/spellfile.utf-8.add' -vim.opt.spellcapcheck = '' -vim.opt.spelloptions = {'camel'} -vim.opt.spellsuggest = 'double' - -vim.keymap.set('n', '', require('telescope.builtin').spell_suggest) -vim.keymap.set('n', '', [[u[s1z=`]au]]) diff --git a/.vim/lua/statusline.lua b/.vim/lua/statusline.lua deleted file mode 100644 index c0c185d..0000000 --- a/.vim/lua/statusline.lua +++ /dev/null @@ -1,253 +0,0 @@ - -local spinner_ok, spinner = pcall(require, 'spinner') -if spinner_ok then - spinner.setup { - spinner = {'⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'}, - interval = 120, -- spinner frame rate in ms - } -end - -function _G.statusline() - local bufnr = vim.fn.bufnr() or 0 - local hi = statusline_color(vim.fn.mode()) - - local sl = hi - -- sl = sl .. statusline_append([[ ⢷]], 'StatusLineIcon', hi) - - sl = sl .. statusline_append(statusline_ts(), - 'StatusLineTreesitter', hi) - - sl = sl .. statusline_append(statusline_lsp_diagnostics(bufnr, hi), - 'StatusLineDiagnostics', hi) - - sl = sl .. statusline_append(vim.trim(require('lsp-status').status()), - 'StatusLineLsp', hi) - - sl = sl .. statusline_append(statusline_dap(), - 'StatusLineDap', hi) - - sl = sl .. [[ %= ]] -- spacer - - sl = sl .. statusline_append(statusline_notify(hi), - 'StatusLineNotify', hi) - - if spinner_ok then - sl = sl .. statusline_append(spinner.status(bufnr), - 'StatusLineJobs', hi) - end - - sl = sl .. statusline_append(require('nvim-lightbulb').get_status_text(), - 'StatusLineLightbulb', hi) - - sl = sl .. statusline_append([[ %l:%v --%p%%-- %y]], hi, hi) - - return sl -end - -function _G.statusline_color(mode) - local hi = '%*' - if mode == 'i' then - -- hi = '%#StatusLineInsert#' - elseif mode == 'c' then - -- hi = '%#StatusLineCommand#' - elseif mode == 'v' or mode == 'V' or mode == '' then - hi = '%#StatusLineVisual#' - elseif mode == 'R' or mode == 'Rv' then - hi = '%#StatusLineReplace#' - end - -- return '%{g:actual_curwin==win_getid()?'.. hi ..':%#StatusLineNC#}' - return hi -end - --- statusline_append --- does item highlighting and conditionnal spacing -function _G.statusline_append(element, hi, default_hi, opts) - if not element or element == '' then return '' end - opts = opts or { append_space = true } - - if hi ~= nil then hi = '%#' .. hi .. '#' end - if not (default_hi == '%*') then hi = default_hi end - local el = hi .. element .. default_hi - if opts.append_space then el = el .. ' ' end - return el -end - -function _G.statusline_lsp_diagnostics(bufnr, default_hi) - local error_num = vim.diagnostic.get(bufnr, {severity=vim.diagnostic.severity.ERROR}) - local warn_num = vim.diagnostic.get(bufnr, {severity=vim.diagnostic.severity.WARN}) - - local s = '' - if #error_num > 0 then - local errs = vim.fn.sign_getdefined('DiagnosticSignError')[1].text .. #error_num - s = s .. statusline_append(errs, statusline_combine_hi('StatusLineDiagnostics', 'DiagnosticError'), default_hi) - end - if #warn_num > 0 then - local warns = vim.fn.sign_getdefined('DiagnosticSignWarn')[1].text .. #warn_num - s = s .. statusline_append(warns, statusline_combine_hi('StatusLineDiagnostics', 'DiagnosticWarn'), default_hi) - end - return vim.trim(s) -end - -function _G.statusline_combine_hi(outer_name, inner_name) - local outer = vim.api.nvim_get_hl_by_id(vim.api.nvim_get_hl_id_by_name(outer_name), true) - local inner = vim.api.nvim_get_hl_by_id(vim.api.nvim_get_hl_id_by_name(inner_name), true) - local hi = 'auto' .. outer_name .. inner_name - if pcall(vim.api.nvim_get_hl_by_name, hi, true) then return hi end - local gui - gui = inner.bold and 'bold' - gui = inner.italic and 'italic' - gui = inner.underline and 'underline' - vim.api.nvim_set_hl(0, hi, {bg = outer.background, fg = inner.foreground, gui = gui}) - return hi -end -function _G.statusline_ts() - local data = require('nvim-navic').get_data() - if not data then return '' end - local s = {} - for i = 1, #data do - table.insert(s, string.format('%%#CmpItemKind%s#%s%%* %%#StatusLine#%s%%*', data[i].type, data[i].icon, data[i].name)) - end - return table.concat(s, ' > ') -end -function _G.statusline_dap() - local dap_ok, dap = pcall(require, 'dap') - if not dap_ok then return '' end - - local s = dap.status() - if s == '' then return s end - return '[DAP: ' .. s .. ']' -end - --- notifications cache -_G.statusline_notifications = {} -_G.statusline_notifications_archive = {} - -function _G.statusline_notify(default_hi) - if #_G.statusline_notifications == 0 then return '' end - local n = _G.statusline_notifications[1] - local timeout = (n.options and n.options.timeout) or 2000 - -- pop message after and move to archive - vim.defer_fn(function() - local n = table.remove(_G.statusline_notifications, 1) - table.insert(_G.statusline_notifications_archive, n) - -- make sure archive is never longer than 20 notifications - if #_G.statusline_notifications_archive > 20 then - table.remove(_G.statusline_notifications_archive, 1) - end - end, timeout) - - local s = '' - if n.hi then - s = s .. statusline_append(n.lvl_string .. ' ', statusline_combine_hi('StatusLineNotify', n.hi), default_hi, { append_space = false }) - end - s = s .. statusline_append(n.message, 'StatusLineNotify', default_hi) - return vim.trim(s) -end - --- out vim.notify implementation -local notify = function(m, l, o) - local lvl_string = l - local hi = nil - if l and type(l) == 'number' then - if l == vim.log.levels.TRACE then - hi = 'deEmph' - elseif l == vim.log.levels.DEBUG then - hi = 'DiagnosticHint' - elseif l == vim.log.levels.INFO then - hi = 'DiagnosticInfo' - elseif l == vim.log.levels.WARN then - hi = 'DiagnosticWarn' - elseif l == vim.log.levels.ERROR then - hi = 'DiagnosticError' - end - -- get level string - lvl_string = vim.lsp.log_levels[l] - end - local display = m - if lvl_string then display = lvl_string .. ' ' .. display end - table.insert(_G.statusline_notifications, { - message = m, - level = l, - options = o, - lvl_string = lvl_string, - hi = hi, - display = display, - }) - - if _G.statusline_enable_notifysend then - local args = {} - if lvl_string then - if lvl_string == 'ERROR' then - table.insert(args, '--category=error') - end - if lvl_string == 'WARN' then - table.insert(args, '--category=warning') - end - end - table.insert(args, 'nvim') - table.insert(args, display) - require('job').jobstart { command = 'notify-send', args = args } - end -end - --- overwrite vim.notify -vim.notify = function( m, l, o) - if vim.in_fast_event() then - vim.schedule(function() - notify(m, l, o) - end) - else - return notify(m, l, o) - end -end - -vim.keymap.set('n', 'n', function() - local pickers = require('telescope.pickers') - local finders = require('telescope.finders') - local conf = require('telescope.config').values - local actions = require('telescope.actions') - -- local action_state = require('telescope.actions.state') - -- local previewers = require('telescope.previewers') - - local opts = {} - pickers.new(opts, { - prompt_title = "Notifications", - finder = finders.new_dynamic { - fn = function() - return _G.statusline_notifications_archive - end, - entry_maker = function(n) - return { - value = n, - display = n.display, - ordinal = n.message, - } - end, - }, - sorter = conf.generic_sorter(opts), - attach_mappings = function(prompt_bufnr, _) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - -- noop - -- local sel = action_state.get_selected_entry() - -- vim.notify(sel.value.message, sel.value.level, sel.value.options) - end) - return true - end, - -- previewer = previewers.new_buffer_previewer { - -- define_preview = function(self, entry) - -- vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, {entry.value.display}) - -- end, - -- }, - }):find() -end, {desc='notifications'}) - --- vim.opt.statusline = '%!luaeval("statusline()")' -vim.opt.statusline = '%{%v:lua.statusline()%}' - --- WINBAR -- -vim.opt.winbar = [[%h%w%q%f %-m %-r %= %#WinBarCwd#%{%getcwd()%}%*]] -- keep it simple --- function _G.winbar() --- return [[%<%F %-m %-r]] --- end --- vim.opt.winbar = '%{%v:lua.winbar()%}' -- cgit 1.4.1