diff options
| author | Robert Günzler <r@gnzler.io> | 2024-11-25 13:30:37 +0100 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2024-11-25 13:58:25 +0100 |
| commit | 23de12baba9fbfc4ca24581b37c374aa5345cc25 (patch) | |
| tree | e4b3c421bad572eb85a1089eaad44dc3059ab6e6 /.vim/lua/internal | |
| parent | 18e3848110da0a59843058927ea04b496f5db2a5 (diff) | |
update nvim config
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to '')
37 files changed, 1378 insertions, 1735 deletions
diff --git a/.vim/lua/internal/commit-preview.lua b/.vim/lua/internal/commit-preview.lua deleted file mode 100644 index 512b3fb..0000000 --- a/.vim/lua/internal/commit-preview.lua +++ /dev/null @@ -1,67 +0,0 @@ -local M = {} - -function M.under_cursor() - require('internal.cursor').word(require('internal.commit-preview').commit_preview) -end - -function M.commit_preview(commit, on_attach) - if not commit then return end - - local result = require('internal.job') - .jobstart({ - command = 'git', - args = { 'show', '--stat', '--patch', commit }, - format_title = function(_, _) - return 'git-show' - end, - populate_quickfix = false, - }) - :wait() - :result() - - -- create buffer - local bufnr = vim.api.nvim_create_buf(false, true) - assert(bufnr, 'Failed to create buffer') - vim.api.nvim_buf_set_name(bufnr, commit) - vim.api.nvim_set_option_value('filetype', 'commitpreview', { buf = bufnr }) - - -- add lines - vim.api.nvim_set_option_value('modifiable', true, { buf = bufnr }) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, result) - vim.api.nvim_set_option_value('modifiable', false, { buf = bufnr }) - - -- create window - local winpos = 'belowright' - local winheight = #result <= 25 and #result or 25 - vim.cmd(string.format('%s %dsplit', winpos, winheight)) -- open split - local winid = vim.api.nvim_get_current_win() - vim.api.nvim_win_set_buf(winid, bufnr) - vim.cmd('wincmd p') - - vim.keymap.set('n', 'gd', M.under_cursor, { buffer = bufnr }) - vim.keymap.set('n', 'q', function() vim.api.nvim_win_close(winid, true) end, { buffer = bufnr }) - - if on_attach then on_attach(bufnr, winid) end - -- close on CursorMoved (anywhere but git-show-buf) - -- local old_cursor = vim.api.nvim_win_get_cursor(beforewin) - -- local group = vim.api.nvim_create_augroup('gitcommit_win_' .. winid, {}) - -- vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { - -- group = group, - -- callback = function() - -- local cursor = vim.api.nvim_win_get_cursor(0) - -- if - -- (old_cursor[1] ~= cursor[1] or old_cursor[2] ~= cursor[2]) - -- and vim.api.nvim_get_current_win() ~= winid - -- then - -- close() - -- return - -- end - -- old_cursor = cursor - -- end, - -- }) - - -- focus - vim.api.nvim_set_current_win(winid) -end - -return M diff --git a/.vim/lua/internal/completion.lua b/.vim/lua/internal/completion.lua new file mode 100644 index 0000000..552a45e --- /dev/null +++ b/.vim/lua/internal/completion.lua @@ -0,0 +1,154 @@ +vim.opt.completeopt = { 'menu', 'menuone', 'noselect' } +vim.opt.shortmess:append('c') +vim.opt.pumheight = 20 -- max height of completion window + +-- re-link the highlight group for the 3rd field in the completion popup +-- which is populated with the completion source +vim.schedule(function() + local hl = vim.api.nvim_set_hl + + hl(0, 'CmpItemMenu', { link = 'Comment', force = true }) + + hl(0, 'CmpItemAbbrMatch', { bold = true, force = true }) + hl(0, 'CmpItemAbbrMatchFuzzy', { link = 'CmpItemAbbrMatch', force = true }) + + hl(0, 'CmpItemKindVariable', { link = 'Normal', force = true }) + hl(0, 'CmpItemKindInterface', { link = 'CmpItemKindVariable', force = true }) + hl(0, 'CmpItemKindText', { link = 'CmpItemKindVariable', force = true }) + + hl(0, 'CmpItemKindFunction', { link = 'Function', force = true }) + hl(0, 'CmpItemKindMethod', { link = 'CmpItemKindFunction', force = true }) + + hl(0, 'CmpItemKindKeyword', { link = 'Keyword', force = true }) + hl(0, 'CmpItemKindProperty', { link = 'CmpItemKindKeyword', force = true }) + hl(0, 'CmpItemKindUnit', { link = 'CmpItemKindKeyword', force = true }) +end) + +local cmp = require('cmp') + +cmp.setup({ + sources = { + { name = 'nvim_lsp', keyword_length = 1, group_index = 1 }, + { name = 'nvim_lsp_signature_help', keyword_length = 1, group_index = 1 }, + { name = 'luasnip', keyword_length = 2, group_index = 1 }, + -- { name = 'spell' }, + { name = 'async_path', group_index = 2 }, + { name = 'buffer', keyword_length = 3, group_index = 2 }, + }, + + mapping = { + ['<c-n>'] = cmp.mapping( + cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), + { 'i', 'c' } + ), + ['<c-p>'] = cmp.mapping( + cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), + { 'i', 'c' } + ), + ['<tab>'] = cmp.mapping( + cmp.mapping.confirm({ + behavior = cmp.ConfirmBehavior.Insert, + select = true, + }), + { 'i', 'c' } + ), + }, + + -- enable snippet expansion + snippet = { + expand = function(args) + vim.snippet.expand(args.body) + end, + }, + + experimental = { + ghost_text = false, + native_menu = false, + }, + + window = { + completion = { + scrollbar = true, + -- align 'abbr' with cursor, necessary due to 'kind' appearing first + col_offset = -3, + }, + }, + + formatting = { + fields = { 'kind', 'abbr', 'menu' }, + expandable_indicator = true, + format = function(entry, item) + item.dup = 0 -- dedup items from the same source, first one wins + item.menu = '░ ' .. entry.source.name + return require('lspkind').cmp_format({ + mode = 'symbol', + symbol_map = { + -- + 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 = ' ', + }, + })(entry, item) + end, + }, +}) + +cmp.setup.cmdline({ ':', '/', '?', '@' }, { + sources = { + { name = 'cmdline', group_index = 1 }, + { name = 'cmdline_history', group_index = 1 }, + { name = 'nvim_lsp_document_symbol', keyword_length = 1, group_index = 1 }, + { name = 'async_path', group_index = 1 }, + { name = 'buffer', group_index = 1 }, + }, + + matching = { + disallow_symbol_nonprefix_matching = false, + }, + + view = { + entries = { selection_order = 'near_cursor' }, + }, + + formatting = { + fields = { 'abbr', 'menu' }, + }, +}) + +cmp.setup.cmdline({ '/', '?' }, { + sources = { + { name = 'nvim_lsp_document_symbol', keyword_length = 1, group_index = 1 }, + { name = 'path', max_item_count = 12, group_index = 1 }, + { name = 'buffer', group_index = 2 }, + }, +}) diff --git a/.vim/lua/internal/cursor.lua b/.vim/lua/internal/cursor.lua deleted file mode 100644 index ad8d8b2..0000000 --- a/.vim/lua/internal/cursor.lua +++ /dev/null @@ -1,11 +0,0 @@ -local M = {} - -function impl(obj, cb) return cb(vim.fn.expand(vim.fn.expand(obj))) end - -function M.word(cb) return impl('<cword>', cb) end - -function M.expr(cb) return impl('<cexpr>', cb) end - -function M.file(cb) return impl('<cfile>', cb) end - -return M diff --git a/.vim/lua/internal/dap.lua b/.vim/lua/internal/dap.lua deleted file mode 100644 index 4b1d776..0000000 --- a/.vim/lua/internal/dap.lua +++ /dev/null @@ -1,173 +0,0 @@ --- vim: fdm=marker - -local dap = require('dap') -dap.defaults.fallback.terminal_win_cmd = 'belowright 10new' -dap.defaults.fallback.focus_terminal = false - --- open repl when session starts -dap.listeners.after['event_initialized']['me'] = function() - -- dap.repl.toggle() -end - --- try loading dap-launch.json --- require('dap.ext.vscode').load_launchjs(vim.fn.getcwd() .. '/dap-launch.json') - --- 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', '<leader>dd', dap.toggle_breakpoint, { desc = 'toggle breakpoint' }) -- convenience -vim.keymap.set('n', '<leader>db', dap.toggle_breakpoint, { desc = 'toggle breakpoint' }) -vim.keymap.set('n', '<leader>dc', dap.continue, { desc = 'continue' }) -vim.keymap.set('n', '<leader>ds', dap.step_over, { desc = 'step over' }) -vim.keymap.set('n', '<leader>di', dap.step_into, { desc = 'step into' }) -vim.keymap.set('n', '<leader>do', dap.step_out, { desc = 'step out' }) -vim.keymap.set('n', '<leader>dR', dap.repl.toggle, { desc = 'toggle REPL' }) -vim.keymap.set('n', '<leader>dL', dap.run_last, { desc = 'run last' }) -vim.keymap.set('n', '<leader>dq', dap.terminate, { desc = 'terminate' }) - -local widgets = require('dap.ui.widgets') -vim.keymap.set('n', '<leader>dh', widgets.hover, { desc = 'hover' }) -vim.keymap.set( - 'n', - '<leader>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_get_var, 'dap_bin') -- global let g:dap_bin - if ok then - local workspace_folders = vim.lsp.buf.list_workspace_folders() - if #workspace_folders >= 1 then - retval = retval:gsub(':workspace', workspace_folders[1]) - end - return retval - end - -- NOTE: try to resolve binaries from build system - local bin = nil - vim.ui.input({ prompt = 'DAP: binary to launch: ' }, function(choice) - bin = choice - end) - if not bin == nil then - return bin - end - return false -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.lldb = { - type = 'executable', - command = '/usr/bin/lldb-vscode', - name = 'lldb', -} - -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 - --- enable rust types -dap.configurations.rust = vim.tbl_extend('force', dap.configurations.c, { - initCommands = function() - local rustc_sysroot = vim.fn.trim(vim.fn.system('rustc --print sysroot')) - - local script_import = 'command script import "' - .. rustc_sysroot - .. '/lib/rustlib/etc/lldb_lookup.py"' - local commands_file = rustc_sysroot .. '/lib/rustlib/etc/lldb_commands' - - local commands = {} - local file = io.open(commands_file, 'r') - if file then - for line in file:lines() do - table.insert(commands, line) - end - file:close() - end - table.insert(commands, 1, script_import) - - return commands - end, -}) --- end of C/C++/Rust }}} - -local dapui = require('dapui') -dapui.setup {} -vim.keymap.set('n', '<leader>du', dapui.toggle, { desc = 'toggle ui' }) diff --git a/.vim/lua/internal/find.lua b/.vim/lua/internal/find.lua deleted file mode 100644 index 32bdea5..0000000 --- a/.vim/lua/internal/find.lua +++ /dev/null @@ -1,106 +0,0 @@ -local M = {} - -local get_searchdirs = function(dirs) - dirs = dirs or {} - if type(dirs) == 'table' and #dirs > 0 then - return dirs - elseif type(dirs) == 'string' and (dirs == ':workspace') then - dirs = vim.lsp.buf.list_workspace_folders() - elseif type(dirs) == 'string' and not (dirs == '') then - dirs = vim.split(dirs, ',') - end - -- skip asking if we're looking at known filetypes - local ft = vim.api.nvim_buf_get_option(0, 'filetype') - if #dirs == 0 and (ft == 'dirbuf' or ft == 'NvimTree' or ft == 'alpha') then - dirs = { '%:p:h' } - end - -- ask user - if #dirs == 0 then - vim.ui.input({ prompt = 'Search directories: ', default = '%:p:h' }, function(result) - dirs = { result } - end) - end - -- default to something reasonable - if #dirs == 0 then - dirs = { '%:p:h' } - end - -- finally return - return dirs -end - -function onchoice(opts, cb) - if not cb then - return - end - opts.attach_mappings = function(prompt_bufnr) - require('telescope.actions').select_default:replace(function() - local selection = require('telescope.actions.state').get_selected_entry() - if selection == nil then - return - end - require('telescope.actions').close(prompt_bufnr) - on_choice(selection.path) - end) - return true - end -end - -function search_shim(fn, search_dirs, opts, cb) - opts = opts or {} - opts.search_dirs = get_searchdirs(search_dirs) - opts.prompt_title = vim.fn.expand(table.concat(opts.search_dirs, ',')) - onchoice(opts, cb) - fn(opts) -end - -function M.live_grep(search_dirs, opts, cb) - search_shim(require('telescope.builtin').live_grep, search_dirs, opts, cb) -end - -function M.find_files(search_dirs, opts, cb) - -- convenience aliases - if type(search_dirs) == 'string' and search_dirs == 'data' then - search_dirs = vim.fn.stdpath('data') - end - search_shim(require('telescope.builtin').find_files, search_dirs, opts, cb) -end - -function M.setup(opts) - vim.keymap.set('n', ';f', function() - vim.notify('use gsf', vim.log.levels.ERROR) - end, { desc = 'find files' }) - vim.keymap.set('n', ';g', function() - vim.notify('use gsg', vim.log.levels.ERROR) - end, { desc = 'live grep' }) - - vim.keymap.set('n', 'gsg', function() - M.live_grep(':workspace') - end, { desc = 'live grep in workspace' }) - vim.keymap.set('n', 'gsG', M.live_grep, { desc = 'live grep ask' }) - vim.keymap.set('n', 'gs-', function() - M.live_grep('%:p:h') - end, { desc = 'live grep in parent' }) - - vim.keymap.set('n', 'gsf', function() - M.find_files(':workspace') - end, { desc = 'find files in workspace' }) - vim.keymap.set('n', 'gsF', M.find_files, { desc = 'find files ask' }) - - vim.api.nvim_create_user_command('Grep', function(o) - M.live_grep(table.concat(o.fargs)) - end, { - desc = 'live grep (rg)', - nargs = '*', - complete = 'dir', - }) - - vim.api.nvim_create_user_command('Find', function(o) - M.find_files(table.concat(o.fargs)) - end, { - desc = 'find files (fd)', - nargs = '*', - complete = 'dir', - }) -end - -return M diff --git a/.vim/lua/internal/hardmode.lua b/.vim/lua/internal/hardmode.lua deleted file mode 100644 index 2774ead..0000000 --- a/.vim/lua/internal/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' }, '<up>', bail) -vim.keymap.set({ 'n', 'v', 'i' }, '<down>', bail) -vim.keymap.set({ 'n', 'v', 'i' }, '<left>', bail) -vim.keymap.set({ 'n', 'v', 'i' }, '<right>', bail) diff --git a/.vim/lua/internal/job.lua b/.vim/lua/internal/job.lua deleted file mode 100644 index 2e97f16..0000000 --- a/.vim/lua/internal/job.lua +++ /dev/null @@ -1,181 +0,0 @@ -local M = { - current_jobs = {}, -} - -local strip_ansi = function(line) - line, _ = line:gsub(string.char(27) .. '[[0-9;]*m', '') - return line -end -local setqf = function(opts, pid, data) - if data == nil then - return - end - vim.fn.setqflist({}, 'a', { - title = opts.format_title, - lines = { strip_ansi(data) }, - efm = '%m', - context = { - cmd = { opts.command, unpack(opts.args) }, - pid = pid, - source = 'jobstart', - }, - }) - vim.cmd.doautocmd('QuickFixCmdPost') -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 {} - - opts = vim.tbl_extend('keep', opts or {}, { - enable_spinner = vim.g.job_enable_spinner, - populate_quickfix = vim.g.job_populate_quickfix, - attach = vim.g.job_attach, - }) - - -- vim.notify_once(vim.inspect(opts), vim.log.levels.DEBUG) - - if opts.attach then - return vim.schedule_wrap(function() - vim.cmd.terminal({ args = { opts.command, unpack(opts.args) } }) - end)() - end - - local spinner = {} - if opts.enable_spinner then - local ok = false - ok, spinner = pcall(require, 'spinner.core') - if not ok then - opts.enable_spinner = false - end - end - - if opts.format_title == nil then - opts.format_title = table.concat({ opts.command, unpack(opts.args) }, ' ') - elseif type(opts.format_title) == 'function' then - opts.format_title = opts.format_title(opts.command, opts.args) - elseif type(opts.format_title) == 'string' then - -- noop - else - error(string.format('Invalid field "format_title" of type %s', type(opts.format_title))) - end - - opts.on_start = vim.schedule_wrap(function(j) - M.current_jobs[j.pid] = j - - if opts.populate_quickfix then - vim.fn.setqflist({}, 'r') -- clear quickfix - end - if opts.enable_spinner then - spinner.on_attach(j.pid, opts.format_title, vim.fn.bufnr()) - spinner.on_progress('begin', j.pid, j.pid) - end - end) - - opts.on_exit = vim.schedule_wrap(function(j, code) - M.current_jobs[j.pid] = nil - - if not (code == 0) then - vim.notify(string.format('[%d] exit %d', j.pid, code), vim.log.levels.ERROR) - end - if opts.enable_spinner then - spinner.on_progress('end', j.pid, j.pid) - spinner.on_exit(nil, nil, j.pid) - end - if opts.populate_quickfix then - vim.cmd.doautocmd('QuickFixCmdPost') - end - end) - - opts.on_stdout = vim.schedule_wrap(function(err, data, j) - if err ~= nil then - vim.notify(string.format('[%d] error: %s', j.pid, err), vim.log.levels.ERROR) - end -- handle error? - - if opts.populate_quickfix and opts.populate_quickfix ~= 'onerror' then - setqf(opts, j.pid, data) - end - end) - - opts.on_stderr = vim.schedule_wrap(function(err, data, j) - if err ~= nil then - vim.notify(string.format('[%d] error: %s', j.pid, err), vim.log.levels.ERROR) - end -- handle error? - - if opts.populate_quickfix then - setqf(opts, j.pid, data) - 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 = require('plenary.job'):new(opts) - j:start() - - return j -end - -function M.sh(command, opts) - return M.jobstart(vim.tbl_extend('keep', opts or {}, { - command = vim.env.SHELL, - args = { '-c', command }, - -- strip 'sh -c' from the title (used by progress reporting etc.) - format_title = function(_, args) - return table.concat({ unpack(args, 2, #args) }, ' ') - end, - })) -end - -function M.make(opts) - opts = opts or {} - - local makeprg = vim.fn.expandcmd(vim.opt.makeprg:get()) - local cwd = vim.fn.expand('%:p:h') - - if not (string.match(makeprg, 'make') == nil) then - -- detect makefile - opts.cwd = require('lspconfig.util').root_pattern('Makefile')(cwd) - end - - return M.sh(makeprg, opts) -end - -function M.list() - require('telescope._extensions').manager['jobs']['jobs']() -end - -function M.setup(opts) - opts = vim.tbl_extend('keep', opts, { telescope = true, mappings = true }) - - -- defaults - vim.g.job_enable_spinner = true - vim.g.job_populate_quickfix = 'onerror' - vim.g.job_attach = false - - if opts.telescope then - require('telescope').load_extension('jobs') - vim.api.nvim_create_user_command('Jobs', M.list, { desc = 'list jobs managed by internal.job' }) - if opts.mappings then - vim.keymap.set('n', '<leader>jl', M.list, { desc = 'list jobs managed by internal.job' }) - end - end - - vim.api.nvim_create_user_command('Make', function(a) - require('internal.job').make(a.fargs) - end, { nargs = '*', desc = 'run make target or &makeprg with internal.job' }) - - vim.api.nvim_create_user_command('Sh', function(a) - require('internal.job').sh(table.concat(a.fargs, ' ')) - end, { nargs = '*', desc = 'run shell command with internal.job' }) - - if opts.mappings then - vim.keymap.set('n', '<leader>jm', M.make, { desc = 'run &makeprg with internal.job' }) - vim.keymap.set('n', '<leader>js', ':Sh ', { desc = 'run shell commands with internal.job' }) - end -end - -return M diff --git a/.vim/lua/internal/lsp.lua b/.vim/lua/internal/lsp.lua deleted file mode 100644 index b0aa7dc..0000000 --- a/.vim/lua/internal/lsp.lua +++ /dev/null @@ -1,319 +0,0 @@ --- TODO vim.api.nvim_create_autocmd('LspAttach', { --- callback = function(args) --- local client = vim.lsp.get_client_by_id(args.data.client_id) --- local bufnr = args.buf --- end, --- }) - -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(client) - return - end - - local group = vim.api.nvim_create_augroup('LspOnAttach', {}) - vim.api.nvim_create_autocmd('CursorHold', { - buffer = bufnr, - group = group, - callback = function() - if _G.diagnostic_hidden then - return - end - -- evalutate if there's already a floating preview buffer - local existing = vim.F.npcall(vim.api.nvim_buf_get_var, bufnr, 'lsp_floating_preview') - if not existing or not vim.api.nvim_win_is_valid(existing) then - vim.diagnostic.open_float() - end - end, - }) - - require('lsp-status').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', - '<C-]>', - 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', - '<c-h>', - vim.lsp.buf.signature_help, - { buffer = bufnr, desc = 'signature help' } - ) - end - if client.supports_method('textDocument/formatting') then - -- if client.server_capabilities.documentFormattingProvider then - vim.api.nvim_set_option_value('formatexpr', 'v:lua.vim.lsp.formatexpr()', { buf = bufnr }) - vim.keymap.set('n', '<leader>f', vim.lsp.buf.format, { buffer = bufnr, desc = 'format' }) - vim.api.nvim_create_autocmd('BufWritePre', { - buffer = bufnr, - callback = function() - vim.cmd.mkview({ bang = true }) - require('internal.lsp').format(vim.fn.expand('<afile>:p')) - end, - group = vim.api.nvim_create_augroup('LspAutoFormat', {}), - }) - 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' }) - vim.keymap.set('n', 'ga', vim.cmd.CodeActionMenu, { buffer = bufnr, desc = 'code action' }) - end - if client.supports_method('textDocument/documentHighlight') then - vim.keymap.set( - 'n', - '<leader>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 = vim.tbl_extend('keep', caps or {}, require('cmp_nvim_lsp').default_capabilities()) - - -- add window/workDoneProgress capability - caps = vim.tbl_extend('keep', caps or {}, require('lsp-status').capabilities) - return caps -end - -local servers = { - clangd = { - cmd = { - 'clangd', - '--clang-tidy', - '--header-insertion=iwyu', - '--import-insertions', - '--header-insertion-decorators', - } - }, - 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', - }, - }, - }, - lua_ls = { - -- cmd = { 'lua-language-server' }, - cmd = { 'luals' }, -- custom firejail-wrapped - settings = { - Lua = { - runtime = { - version = 'LuaJIT', - path = vim.split(package.path, ';'), - }, - diagnostics = { - globals = { - '_G', - 'assert', - 'error', - 'os', - 'package', - 'pairs', - 'ipairs', - 'pcall', - 'require', - 'string', - 'table', - 'type', - 'unpack', - 'vim', - 'xpcall', - }, - 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 = { 'cargo', 'clippy' }, - }, - }, - }, - }, - tsserver = {}, - pylsp = {}, - zls = {}, -} - -local setup = function() - -- configure floating win handlers - vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { - focus = false, - zindex = 100, - 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(require('lsp-status').extensions[server]) - if ok then - opts = vim.tbl_extend('error', opts, { - handlers = lspstatus_ext.setup(), - }) - end - require('lspconfig')[server].setup(opts) - end - end -end - -local format = function(afile) - if vim.g.nofmt then - return - end - - local errhandler = function(err) - vim.notify('internal.lsp.format: ' .. err, vim.log.levels.ERROR) - return err - end - - -- save folds - pcall(vim.cmd.mkview, { bang = true }) - - -- run lsp format - xpcall(vim.lsp.buf.format, errhandler) - - -- run organize imports for go - if string.match(afile, '.go$') then - xpcall( - vim.lsp.buf.code_action, - errhandler, - { context = { only = { 'source.organizeImports' } }, apply = true } - ) - end - - -- restore folds - pcall(vim.cmd.silent, { 'loadview', bank = true }) - - -- vim.notify('%#MoreMsg#%#Italic# fmt', vim.log.levels.INFO) - vim.notify('internal.lsp.format: ', vim.log.levels.INFO) -end - -return { - my_attach = my_attach, - my_exit = my_exit, - capabilities = capabilities, - setup = setup, - format = format, -} diff --git a/.vim/lua/internal/lsp_symbols.lua b/.vim/lua/internal/lsp_symbols.lua deleted file mode 100644 index 97a1b0e..0000000 --- a/.vim/lua/internal/lsp_symbols.lua +++ /dev/null @@ -1,36 +0,0 @@ -return { - -- - 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 = ' ', -} diff --git a/.vim/lua/internal/misc.lua b/.vim/lua/internal/misc.lua deleted file mode 100644 index a92b7aa..0000000 --- a/.vim/lua/internal/misc.lua +++ /dev/null @@ -1,223 +0,0 @@ --- misc stuff implemented in lua - -local M = {} - -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 get_searchdirs = function(dirs) - if type(dirs) == 'table' and #dirs > 0 then - return dirs - elseif type(dirs) == 'string' and not (dirs == '') then - dirs = vim.split(dirs, ',') - end - -- skip asking if we're looking at known filetypes - local ft = vim.api.nvim_buf_get_option(0, 'filetype') - if #dirs == 0 and (ft == 'dirbuf' or ft == 'alpha') then - dirs = { '%:p:h' } - end - -- ask user - if #dirs == 0 then - vim.ui.input({ prompt = 'Search directories: ' }, function(result) - dirs = { result } - end) - end - -- default to something reasonable - if #dirs == 0 then - dirs = { '%:p:h' } - end - -- finally return - for i = 1, #dirs do - dirs[i] = vim.fn.expand(dirs[i]) - end - return dirs -end - -local function onchoice(opts, cb) - if not cb then - return - end - opts.attach_mappings = function(prompt_bufnr) - require('telescope.actions').select_default:replace(function() - local selection = require('telescope.actions.state').get_selected_entry() - if selection == nil then - return - end - require('telescope.actions').close(prompt_bufnr) - cb(selection.path) - end) - return true - end -end - -function M.live_grep(dirs, opts, cb) - opts = opts or {} - local search_dirs = get_searchdirs(dirs) - opts.search_dirs = search_dirs - opts.prompt_title = 'Grep: ' .. vim.inspect(search_dirs) - onchoice(opts, cb) - require('telescope.builtin').live_grep(opts) -end - -function M.find_files(dirs, opts, cb) - -- convenience aliases - 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: ' .. vim.inspect(search_dirs) - onchoice(opts, cb) - 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('\\<esc>', '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('\\<esc>', '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('<cfile>') - 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 - - 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, - }) - :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 - -function M.setup(opts) - opts = opts or {} - - if opts.sortline then - vim.api.nvim_create_user_command( - 'SortLine', - M.sort_lines, - { desc = 'sort line', range = '%', preview = M.sort_lines } - ) - end - if opts.grep then - vim.api.nvim_create_user_command('Grep', function(o) - M.live_grep(table.concat(o.fargs)) - end, { - desc = 'live grep (rg)', - nargs = '*', - complete = 'dir', - }) - end - if opts.find then - vim.api.nvim_create_user_command('Find', function(o) - M.find_files(table.concat(o.fargs)) - end, { - desc = 'find files (fd)', - nargs = '*', - complete = 'dir', - }) - end -end - -return M diff --git a/.vim/lua/internal/notify.lua b/.vim/lua/internal/notify.lua deleted file mode 100644 index 5445f4f..0000000 --- a/.vim/lua/internal/notify.lua +++ /dev/null @@ -1,105 +0,0 @@ --- notifications cache -_G.statusline_notifications = {} -_G.statusline_notifications_archive = {} - --- 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', '<leader>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' }) diff --git a/.vim/lua/internal/plugins/aerial.lua b/.vim/lua/internal/plugins/aerial.lua new file mode 100644 index 0000000..a5fb4b3 --- /dev/null +++ b/.vim/lua/internal/plugins/aerial.lua @@ -0,0 +1,13 @@ +return { + { + 'stevearc/aerial.nvim', + opts = {}, + dependencies = { + 'nvim-treesitter/nvim-treesitter', + 'echasnovski/mini.icons', + }, + keys = { + { '<leader>b', '<cmd>AerialToggle<cr>' }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/colorizer.lua b/.vim/lua/internal/plugins/colorizer.lua new file mode 100644 index 0000000..cf55336 --- /dev/null +++ b/.vim/lua/internal/plugins/colorizer.lua @@ -0,0 +1,16 @@ +return { + { + 'NvChad/nvim-colorizer.lua', + -- 'norcalli/nvim-colorizer.lua', + -- events = { 'VeryLazy' }, + lazy = false, + opts = { + name = true, + RRGGBB = true, + RRGGBBAA = false, + rgb_fn = true, + hsl_fn = true, + mode = 'background', + }, + }, +} diff --git a/.vim/lua/internal/plugins/colorschemes.lua b/.vim/lua/internal/plugins/colorschemes.lua new file mode 100644 index 0000000..9371229 --- /dev/null +++ b/.vim/lua/internal/plugins/colorschemes.lua @@ -0,0 +1,11 @@ +return { + { + enabled = false, + 'xero/evangelion.nvim', + lazy = false, + priority = 1000, + config = function() + vim.cmd('colorscheme evangelion') + end, + }, +} diff --git a/.vim/lua/internal/plugins/completion.lua b/.vim/lua/internal/plugins/completion.lua new file mode 100644 index 0000000..db96085 --- /dev/null +++ b/.vim/lua/internal/plugins/completion.lua @@ -0,0 +1,60 @@ +return { + { + -- 'hrsh7th/nvim-cmp', + 'iguanacucumber/magazine.nvim', -- perf improvements + name = 'nvim-cmp', + + lazy = false, + -- event = {'InsertEnter', 'CmdlineEnter' }, + priority = 100, + dependencies = { + 'hrsh7th/cmp-buffer', + 'hrsh7th/cmp-nvim-lsp', + 'https://codeberg.org/FelipeLema/cmp-async-path', + -- 'hrsh7th/cmp-nvim-lua', + 'hrsh7th/cmp-nvim-lsp-signature-help', -- used to provide function signature completion + 'hrsh7th/cmp-cmdline', + 'dmitmel/cmp-cmdline-history', + 'hrsh7th/cmp-nvim-lsp-document-symbol', -- used by cmdline completion + -- 'f3fora/cmp-spell', + + { 'L3MON4D3/LuaSnip', run = 'make install_jsregexp' }, + 'saadparwaiz1/cmp_luasnip', + + 'onsails/lspkind.nvim', + }, + config = function() + require('internal.snippets') + require('internal.completion') + end, + }, + + -- { -- TODO: try when it doesnt require nightly rust, i dont want binary blobs + -- + -- 'saghen/blink.cmp', + -- lazy = false, + -- -- use a release tag to download pre-built binaries + -- -- version = 'v0.*', + -- -- OR build from source, requires nightly: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust + -- build = 'cargo build --release', + -- + -- opts = { + -- highlight = { + -- -- sets the fallback highlight groups to nvim-cmp's highlight groups + -- -- useful for when your theme doesn't support blink.cmp + -- -- will be removed in a future release, assuming themes add support + -- use_nvim_cmp_as_default = true, + -- }, + -- + -- -- set to 'mono' for 'Nerd Font Mono' or 'normal' for 'Nerd Font' + -- -- adjusts spacing to ensure icons are aligned + -- nerd_font_variant = 'normal', + -- + -- -- experimental auto-brackets support + -- -- accept = { auto_brackets = { enabled = true } } + -- + -- -- experimental signature help support + -- -- trigger = { signature_help = { enabled = true } } + -- }, + -- }, +} diff --git a/.vim/lua/internal/plugins/csv.lua b/.vim/lua/internal/plugins/csv.lua new file mode 100644 index 0000000..bc4cb2c --- /dev/null +++ b/.vim/lua/internal/plugins/csv.lua @@ -0,0 +1,20 @@ +return { + { + 'emmanueltouzery/decisive.nvim', + lazy = true, + ft = { 'csv' }, + main = 'decisive', + keys = { + { + '<leader>a', + function() + require('decisive').align_csv({}) + require('decisive').show_sticky_header() + end, + desc = 'decisive: Align CSV', + }, + { '[,', ":lua require('decisive').align_csv_prev_col()<cr>", desc = 'decisive: Prev column' }, + { '],', ":lua require('decisive').align_csv_next_col()<cr>", desc = 'decisive: Next column' }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/gentoo.lua b/.vim/lua/internal/plugins/gentoo.lua new file mode 100644 index 0000000..142374c --- /dev/null +++ b/.vim/lua/internal/plugins/gentoo.lua @@ -0,0 +1,15 @@ +return { + { + 'gentoo/gentoo-syntax', + lazy = false, + config = function() + vim.api.nvim_create_autocmd('LspAttach', { + callback = function(args) + if vim.bo.filetype == 'ebuild' then + vim.lsp.stop_client(vim.lsp.get_clients({ bufnr = args.bufnr })) + end + end, + }) + end, + }, +} diff --git a/.vim/lua/internal/plugins/git.lua b/.vim/lua/internal/plugins/git.lua new file mode 100644 index 0000000..d907161 --- /dev/null +++ b/.vim/lua/internal/plugins/git.lua @@ -0,0 +1,108 @@ +return { + { + 'lewis6991/gitsigns.nvim', + lazy = false, + opts = { + signs = { + change = { text = '▋' }, + add = { text = '▋' }, + }, + }, + keys = { + { + ']c', + function() + if vim.wo.diff then + vim.cmd.normal({ ']c', bang = true }) + else + require('gitsigns').nav_hunk('next') + end + end, + desc = 'Gitsigns: next hunk', + }, + { + '[c', + function() + if vim.wo.diff then + vim.cmd.normal({ '[c', bang = true }) + else + require('gitsigns').nav_hunk('prev') + end + end, + desc = 'Gitsigns: prev hunk', + }, + { '<leader>gb', '<cmd>Gitsigns blame<cr>', desc = 'Gitsigns: blame' }, + { '<leader>gs', '<cmd>Gitsigns<cr>', desc = 'Gitsigns: select action' }, + { + ';c', + function() + require('gitsigns').setqflist('all', { open = false }) + require('telescope.builtin').quickfix({ prompt_title = 'Git changesets' }) + end, + desc = 'Telescope: list hunks via gitsigns', + }, + }, + }, + + { + 'linrongbin16/gitlinker.nvim', + cmd = { 'GitLink' }, + dependencies = { 'nvim-lua/plenary.nvim' }, + opts = { + message = true, + }, + keys = { + { + '<leader>gl', + vim.cmd.GitLink, + desc = 'gitlinker: clipboard', + }, + }, + }, + + { + 'moyiz/git-dev.nvim', + lazy = true, + cmd = { 'GitDevOpen', 'GitDevCleanAll' }, + opts = { + read_only = false, + }, + }, + + { + 'isakbm/gitgraph.nvim', + dependencies = { 'sindrets/diffview.nvim' }, + opts = { + symbols = { + merge_commit = 'M', + commit = '∙', + }, + format = { + timestamp = '%d-%m-%Y %H:%M:%S %z', + fields = { 'hash', 'timestamp', 'author', 'branch_name', 'tag' }, + }, + }, + init = vim.schedule_wrap(function() + vim.api.nvim_set_hl(0, 'GitGraphBranch1', { fg = 'NvimLightGray1' }) + vim.api.nvim_set_hl(0, 'GitGraphBranch2', { fg = 'NvimLightMagenta' }) + vim.api.nvim_set_hl(0, 'GitGraphBranch3', { fg = 'NvimLightRed' }) + vim.api.nvim_set_hl(0, 'GitGraphBranch4', { fg = 'NvimDarkCyan' }) + vim.api.nvim_set_hl(0, 'GitGraphBranch5', { fg = 'NvimDarkYellow' }) + vim.api.nvim_set_hl(0, 'GitGraphHash', { fg = 'NvimLightMagenta' }) + vim.api.nvim_set_hl(0, 'GitGraphAuthor', { fg = 'NvimLightGray4', italic = true }) + vim.api.nvim_set_hl(0, 'GitGraphTimestamp', { fg = 'NvimLightCyan' }) + vim.api.nvim_set_hl(0, 'GitGraphBranchName', { fg = 'NvimLightYellow' }) + vim.api.nvim_set_hl(0, 'GitGraphBranchTag', { fg = 'NvimLightYellow' }) + vim.api.nvim_set_hl(0, 'GitGraphBranchMsg', { link = 'Normal' }) + end), + keys = { + { + 'g-', + function() + require('gitgraph').draw({}, { all = true, max_count = 5000 }) + end, + desc = 'git graph', + }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/icons.lua b/.vim/lua/internal/plugins/icons.lua new file mode 100644 index 0000000..3d503dc --- /dev/null +++ b/.vim/lua/internal/plugins/icons.lua @@ -0,0 +1,12 @@ +return { + { + 'echasnovski/mini.icons', + version = false, + events = { 'VeryLazy' }, + config = function(_, opts) + require('mini.icons').setup(opts) + ---@diagnostic disable-next-line: undefined-global + MiniIcons.mock_nvim_web_devicons() + end, + }, +} diff --git a/.vim/lua/internal/plugins/indent.lua b/.vim/lua/internal/plugins/indent.lua new file mode 100644 index 0000000..a27a328 --- /dev/null +++ b/.vim/lua/internal/plugins/indent.lua @@ -0,0 +1,28 @@ +return { + -- show indents using virtual text + { + 'lukas-reineke/indent-blankline.nvim', + lazy = false, + main = 'ibl', + opts = { + indent = { + char = '▏', + }, + scope = { + enabled = true, + show_start = false, + show_end = false, + }, + }, + }, + -- detect indent from the buffer contents + { + 'NMAC427/guess-indent.nvim', + lazy = false, + opts = { + auto_cmd = true, + filetype_exclude = { 'netrw', 'tutor', 'dirbuf', 'nvimtree', 'oil' }, + buftype_exclude = { 'help', 'nofile', 'terminal', 'prompt' }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/lsp.lua b/.vim/lua/internal/plugins/lsp.lua new file mode 100644 index 0000000..d138c6c --- /dev/null +++ b/.vim/lua/internal/plugins/lsp.lua @@ -0,0 +1,276 @@ +return { + { + 'neovim/nvim-lspconfig', + lazy = false, + dependencies = { + { 'j-hui/fidget.nvim', opts = {} }, + 'stevearc/conform.nvim', + }, + config = function() + local capabilities = nil + if pcall(require, 'cmp_nvim_lsp') then + capabilities = require('cmp_nvim_lsp').default_capabilities() + end + + local lspconfig = require('lspconfig') + + local servers = { + clangd = { + cmd = { + 'clangd', + '--clang-tidy', + '--header-insertion=iwyu', + '--import-insertions', + '--header-insertion-decorators', + }, + }, + elixirls = { + cmd = { 'elixir-ls' }, + settings = { + elixirLS = { + dialyzerEnabled = false, + }, + }, + }, + gopls = { + settings = { + gopls = { + hints = { + assignVariableTypes = true, + compositeLiteralFields = true, + compositeLiteralTypes = true, + constantValues = true, + functionTypeParameters = true, + parameterNames = true, + rangeVariableTypes = true, + }, + analyses = { + -- composites = false, + nilness = true, + shadow = false, + unusedparams = true, + unusedwrite = true, + }, + gofumpt = true, + -- hoverKind = 'Structured', + }, + }, + }, + lua_ls = { + cmd = { 'luals' }, -- custom firejail-wrapped + -- 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', + 'unpack', + 'vim', + 'xpcall', + }, + neededFileStatus = { + ['code-style-check'] = 'Any', + }, + }, + format = { + enable = true, + defaultConfig = { + indent_style = 'space', + indent_size = '2', + }, + }, + workspace = { + library = { + [vim.env.VIMRUNTIME .. '/lua'] = true, + [vim.env.VIMRUNTIME .. '/lua/vim/lsp'] = true, + [vim.fn.stdpath('config') .. '/lua'] = true, + }, + }, + telemetry = { + enable = false, + }, + }, + }, + }, + rust_analyzer = { + settings = { + ['rust-analyzer'] = { + checkOnSave = { + command = { 'cargo', 'clippy' }, + }, + }, + }, + }, + ts_ls = { + init_options = { + tsserver = { + path = '/usr/lib/node_modules/typescript/lib', + }, + }, + }, + pylsp = {}, + zls = { + cmd = { + 'zls', + '--enable-debug-log', + '--enable-message-tracing', + }, + }, + bashls = {}, + cssls = {}, + jsonls = {}, + html = {}, + superhtml = {}, + kotlin_language_server = { + -- cmd = vim.lsp.rpc.connect('127.0.0.1', 20100), + cmd = { + 'distrobox', + 'enter', + '-n', + 'android-dev', + '--', + '/usr/local/kotlin-langserver/bin/kotlin-language-server', + }, + init_options = { + formatting = { + formatter = 'none', -- disable because we use ktlint via gradle + }, + }, + }, + } + + for name, opts in pairs(servers) do + opts = vim.tbl_deep_extend('force', { + capabilities = capabilities, + }, opts) + lspconfig[name].setup(opts) + end + + vim.api.nvim_create_autocmd('LspAttach', { + callback = function() + -- local client = + -- assert(vim.lsp.get_client_by_id(args.data.client_id), 'must have valid client') + + vim.opt_local.omnifunc = 'v:lua.vim.lsp.omnifunc' + + vim.keymap.set('n', 'gd', vim.lsp.buf.definition, { buffer = true }) + vim.keymap.set('n', 'gR', vim.lsp.buf.references, { buffer = true }) + vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, { buffer = true }) + vim.keymap.set('n', 'gT', vim.lsp.buf.type_definition, { buffer = true }) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, { buffer = true }) + vim.keymap.set('n', 'grr', vim.lsp.buf.rename, { buffer = true }) + vim.keymap.set('n', 'ga', vim.lsp.buf.code_action, { buffer = true }) + end, + }) + end, + }, + + { + 'folke/lazydev.nvim', + ft = 'lua', + -- could add a completion source to cmp? + }, + + -- formatting + { + 'stevearc/conform.nvim', + lazy = false, + opts = { + formatters_by_ft = { + lua = { 'stylua' }, + go = { 'goimports', 'gofmt' }, + python = { 'ruff_format' }, + }, + }, + config = function(_, opts) + require('conform').setup(opts) + + vim.api.nvim_create_autocmd('BufWritePre', { + callback = function(args) + if vim.g.nofmt then + return + end + require('conform').format({ + bufnr = args.buf, + lsp_fallback = true, + quiet = true, + }) + end, + }) + end, + }, + + -- linting + { + 'nvimtools/none-ls.nvim', + dependencies = { 'nvim-lua/plenary.nvim' }, + event = { 'VeryLazy' }, + config = function() + local nls = require('null-ls') + nls.setup({ + sources = { + -- https://github.com/nvimtools/none-ls.nvim/blob/main/doc/BUILTINS.md + -- nls.builtins.code_actions.gitsigns, + nls.builtins.code_actions.impl, + + -- nls.builtins.completion.spell, + + -- nls.builtins.diagnostics.checkmake, + -- nls.builtins.diagnostics.cmake_lint, + -- nls.builtins.diagnostics.cppcheck, + -- nls.builtins.diagnostics.gccdiag, + nls.builtins.diagnostics.golangci_lint, + nls.builtins.diagnostics.hadolint, + -- nls.builtins.diagnostics.pylint, + -- nls.builtins.diagnostics.selene, + -- nls.builtins.diagnostics.semgrep, + nls.builtins.diagnostics.sqlfluff, + -- nls.builtins.diagnostics.stylelint, + -- nls.builtins.diagnostics.textidote, + nls.builtins.diagnostics.vale, + }, + }) + end, + }, + + -- diagnostics + { + 'rachartier/tiny-inline-diagnostic.nvim', + event = 'VeryLazy', + opts = { + signs = { + left = ' ', + right = '', + diag = '', + arrow = '◂ ', + up_arrow = '▴ ', + }, + options = { + throttle = 0, + show_source = true, + }, + }, + config = function(_, opts) + vim.diagnostic.config({ virtual_text = false }) + require('tiny-inline-diagnostic').setup(opts) + if vim.opt.background:get() == 'light' then + require('tiny-inline-diagnostic').change({}, { mixing_color = '#aaaaaa' }) + end + end, + }, +} diff --git a/.vim/lua/internal/plugins/mediawiki.lua b/.vim/lua/internal/plugins/mediawiki.lua new file mode 100644 index 0000000..f557627 --- /dev/null +++ b/.vim/lua/internal/plugins/mediawiki.lua @@ -0,0 +1,6 @@ +return { + { + 'chikamichi/mediawiki.vim', + ft = { 'mediawiki' }, + }, +} diff --git a/.vim/lua/internal/plugins/mini.lua b/.vim/lua/internal/plugins/mini.lua new file mode 100644 index 0000000..1886766 --- /dev/null +++ b/.vim/lua/internal/plugins/mini.lua @@ -0,0 +1,35 @@ +return { + { + 'echasnovski/mini.align', + version = false, + opts = {}, + keys = { + { mode = 'n', 'ga' }, + { mode = 'n', 'gA' }, + { mode = 'v', 'ga' }, + { mode = 'v', 'gA' }, + { + mode = 'v', + '<cr>', + function() + vim.cmd([[silent! echohl ErrorMsg | echo "use ga/gA" | echohl None]]) + end, + }, + }, + }, + { + 'echasnovski/mini.surround', + lazy = false, + version = false, + opts = { + mappings = { + delete = 'ds', + replace = 'cs', + }, + }, + keys = { + { mode = 'n', 'cs' }, + { mode = 'n', 'ds' }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/oil.lua b/.vim/lua/internal/plugins/oil.lua new file mode 100644 index 0000000..401fe8b --- /dev/null +++ b/.vim/lua/internal/plugins/oil.lua @@ -0,0 +1,21 @@ +return { + { + 'stevearc/oil.nvim', + lazy = false, + opts = { + keymaps = { + ['gt'] = { + function() + local cwd = require('oil').get_current_dir() + vim.cmd('silent !footclient --no-wait -D ' .. cwd) + end, + nowait = true, + desc = 'Open current directory with foot', + }, + }, + }, + keys = { + { mode = 'n', '-', '<cmd>Oil<cr>', desc = 'oil: open parent directory' }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/telescope.lua b/.vim/lua/internal/plugins/telescope.lua new file mode 100644 index 0000000..6339a2c --- /dev/null +++ b/.vim/lua/internal/plugins/telescope.lua @@ -0,0 +1,137 @@ +return { + { + 'nvim-telescope/telescope.nvim', + lazy = false, + dependencies = { + { 'nvim-lua/plenary.nvim' }, + { + 'nvim-telescope/telescope-fzf-native.nvim', + build = 'cmake -S. -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release && cmake --build build --config Release', + }, + { 'nvim-telescope/telescope-ui-select.nvim' }, + }, + config = function(spec, _) + require('telescope').setup({ + defaults = require('telescope.themes').get_ivy({ + prompt = false, + borderchars = { + preview = { '─', '│', '─', '│', '┌', '┐', '┘', '└' }, + }, + }), + + extensions = { + wrap_results = true, + + fzf = {}, + + ['ui-select'] = { + require('telescope.themes').get_ivy({ + prompt = false, + -- sharp edges please + borderchars = { + preview = { '─', '│', '─', '│', '┌', '┐', '┘', '└' }, + }, + layout_config = { height = 9 }, + }), + }, + }, + }) + + pcall(require('telescope').load_extension, 'fzf') + pcall(require('telescope').load_extension, 'ui-select') + + -- user commands + vim.api.nvim_create_user_command( + 'F', + 'Telescope find_files search_dirs=<args>', + { desc = 'Telescope find_files', nargs = '?' } + ) + vim.api.nvim_create_user_command( + 'G', + 'Telescope live_grep search_dirs=<args>', + { desc = 'Telescope live_grep', nargs = '?' } + ) + + -- keymaps + local builtin = require('telescope.builtin') + for _, o in ipairs(spec.keys) do + if not o[2] then + local mod = vim.split(o.desc, ': ')[2] + vim.keymap.set(o.mode, o[1], builtin[mod], { desc = o.desc }) + end + end + + -- highlights + vim.schedule(function() + vim.api.nvim_set_hl(0, 'TelescopeBorder', { fg = 'NvimDarkGrey4', force = true }) + vim.api.nvim_set_hl(0, 'TelescopeTitle', { fg = 'NvimLightMagenta', force = true }) + vim.api.nvim_set_hl(0, 'NormalFloat', { link = 'TelescopeNormal', force = true }) + end) + end, + keys = { + { mode = 'n', ';/', desc = 'telescope: current_buffer_fuzzy_find' }, + { mode = 'n', ';b', desc = 'telescope: buffers' }, + { mode = 'n', ';f', desc = 'telescope: find_files' }, + { mode = 'n', ';g', desc = 'telescope: live_grep' }, + { mode = 'n', ';d', desc = 'telescope: diagnostics' }, + { + mode = 'n', + ';v', + function() + require('telescope.builtin').find_files({ + prompt_title = 'vimrc', + search_dirs = { + vim.fn.stdpath('config'), + }, + }) + end, + desc = 'telescope: vim_config', + }, + { + mode = 'n', + ';;t', + '<cmd>Telescope<cr>', + desc = 'telescope: select (interactive)', + }, + { + mode = 'n', + ';;f', + function() + local dir + if vim.opt.filetype:get() == 'oil' then + dir = require('oil').get_current_dir() + else + dir = vim.fn.expand('%:p') + end + _G.feedkeys(':Telescope find_files search_dirs=' .. dir) + end, + desc = 'telescope: find_files (interactive)', + }, + { + mode = 'n', + ';;g', + function() + local dir + if vim.opt.filetype:get() == 'oil' then + dir = require('oil').get_current_dir() + else + dir = vim.fn.expand('%:p') + end + _G.feedkeys(':Telescope live_grep search_dirs=' .. dir) + end, + desc = 'telescope: live_grep (interactive)', + }, + }, + }, + + { + 'prochri/telescope-all-recent.nvim', + lazy = false, + dependencies = { + 'nvim-telescope/telescope.nvim', + 'kkharji/sqlite.lua', + }, + after = { 'nvim-telescope/telescope-ui-select.nvim' }, + opts = {}, + }, +} diff --git a/.vim/lua/internal/plugins/todo.lua b/.vim/lua/internal/plugins/todo.lua new file mode 100644 index 0000000..e7ae0a7 --- /dev/null +++ b/.vim/lua/internal/plugins/todo.lua @@ -0,0 +1,46 @@ +return { + { + 'folke/todo-comments.nvim', + dependencies = { 'nvim-lua/plenary.nvim' }, + lazy = false, + cmd = { 'TodoTelescope' }, + opts = { + merge_keywords = true, + keywords = { + FIX = { icon = '' }, + TODO = { icon = '' }, + HACK = { icon = '' }, + WARN = { icon = '' }, + PERF = { icon = '' }, + NOTE = { icon = '' }, + TEST = { icon = '' }, + }, + highlight = { + keyword = 'bg', + pattern = [[<(KEYWORDS)(|\(.+\))(:|)]], + }, + search = { + pattern = [[\b(KEYWORDS)(|\(.+\))(:|)]], + }, + }, + keys = { + { mode = 'n', ';t', '<cmd>TodoTelescope<cr>', desc = 'telescope: todos' }, + { + mode = 'n', + ']t', + function() + require('todo-comments').jump_next() + end, + desc = 'todo: next', + }, + { + mode = 'n', + '[t', + function() + require('todo-comments').jump_prev() + end, + desc = 'todo: prev', + }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/treesitter.lua b/.vim/lua/internal/plugins/treesitter.lua new file mode 100644 index 0000000..b8b1d56 --- /dev/null +++ b/.vim/lua/internal/plugins/treesitter.lua @@ -0,0 +1,124 @@ +return { + { + 'nvim-treesitter/nvim-treesitter', + dependencies = { + -- TODO: https://github.com/nvim-treesitter/nvim-treesitter-context + { 'nvim-treesitter/nvim-treesitter-refactor', lazy = false }, + { 'nvim-treesitter/nvim-treesitter-textobjects', lazy = false }, + { 'nvim-treesitter/playground', cmd = { 'TSPlayground' } }, + }, + lazy = false, + build = ':TSUpdate', + config = function(_, opts) + -- TODO: overwrite parser configs, insert gotmpl + + require('nvim-treesitter.configs').setup(opts) + + -- use bash parser for gentoo ebuilds + vim.treesitter.language.register('bash', 'ebuild') + + -- register mediawiki parser + -- local parser_configs = require('nvim-treesitter.parsers').get_parser_configs() + -- parser_configs.mediawiki = { + -- install_info = { + -- url = 'github.com/Ordoviz/tree-sitter-mediawiki', + -- files = { 'src/parser.c' }, + -- branch = 'main', + -- generate_requires_npm = false, + -- requires_generate_from_grammar = false, + -- }, + -- filetype = 'mediawiki', + -- } + end, + opts = { + ensure_installed = { + 'bash', + 'bibtex', + 'c', + 'c_sharp', + 'cmake', + 'comment', + 'cpp', + 'css', + 'dockerfile', + 'go', + 'gomod', + 'gotmpl', + 'gowork', + 'hare', + 'hcl', + 'html', + 'java', + 'javascript', + 'json', + 'jsonc', + 'kotlin', + 'latex', + 'ledger', + 'lua', + 'make', + 'markdown', + 'markdown_inline', + 'ninja', + 'norg', + 'python', + 'query', + 'regex', + 'rust', + 'scss', + 'sql', + 'toml', + 'typescript', + 'vim', + 'vimdoc', + 'yaml', + 'zig', + + -- external parsers + -- 'mediawiki', -- TODO: missing queries + }, + highlight = { + enable = true, + additional_vim_regex_highlighting = { 'markdown' }, + }, + indent = { + enable = true, + }, + refactor = { + navigation = { + enable = true, + keymaps = { + goto_definition = 'gd', + }, + }, + smart_rename = { + enable = true, + keymaps = { + smart_rename = 'grr', + }, + }, + }, + textobjects = { + select = { + enable = true, + keymaps = { + ['ib'] = '@block.inner', + ['ab'] = '@block.outer', + -- ['ic'] = '@conditional.inner', + -- ['ac'] = '@conditional.outer', + ['if'] = '@function.inner', + ['af'] = '@function.outer', + ['il'] = '@loop.inner', + ['al'] = '@loop.outer', + ['is'] = '@scopename.inner', + ['as'] = '@scopename.outer', + ['ic'] = '@comment.outer', + }, + selection_mode = { + ['@comment.outer'] = 'V', + }, + }, + }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/whichkey.lua b/.vim/lua/internal/plugins/whichkey.lua new file mode 100644 index 0000000..3c9e802 --- /dev/null +++ b/.vim/lua/internal/plugins/whichkey.lua @@ -0,0 +1,9 @@ +return { + { + 'folke/which-key.nvim', + event = 'VeryLazy', + opts = { + icons = { separator = '→ ', group = '🞱 ' }, + }, + }, +} diff --git a/.vim/lua/internal/plugins/writing.lua b/.vim/lua/internal/plugins/writing.lua new file mode 100644 index 0000000..4792697 --- /dev/null +++ b/.vim/lua/internal/plugins/writing.lua @@ -0,0 +1,123 @@ +return { + { + 'folke/zen-mode.nvim', + cmd = { 'ZenMode' }, + opts = { + window = { + -- width = 0.9, + -- height = 0.9, + options = { + cursorline = true, + }, + }, + plugins = { + options = { + number = false, + ruler = false, + showcmd = false, + }, + gitsigns = { enabled = false }, + twilight = { enabled = true }, + }, + on_open = function() + vim.diagnostic.enable(false) + end, + on_close = function() + vim.diagnostic.enable(true) + end, + }, + -- init = function() + -- vim.api.nvim_create_autocmd({ 'BufWinEnter', 'BufWinLeave' }, { + -- pattern = { '*.md' }, + -- command = [[ZenMode]], + -- }) + -- end, + dependencies = { + { + 'folke/twilight.nvim', + opts = { + context = 24, + dimming = { + alpha = 0.5, + color = { 'Normal', '#ffffff' }, + }, + }, + }, + }, + }, + { + 'tadmccorkle/markdown.nvim', + ft = { 'markdown' }, + opts = { + mappings = false, + }, + config = function(_, opts) + require('markdown').setup(opts) + + local set = vim.keymap.set + set('n', '[[', [[<Plug>(markdown_go_prev_heading)]], { desc = 'md: previous heading' }) + set('n', ']]', [[<Plug>(markdown_go_next_heading)]], { desc = 'md: next heading' }) + set('n', '<s-tab>', [[:MDTaskToggle<cr>]], { desc = 'md: toggle task' }) + set('x', '<c-l>', [[<esc>gv<Plug>(markdown_add_link_visual)]], { desc = 'md: make link' }) + local toggle_emph = function(key) + return [[<esc>gv<cmd>lua require('markdown.inline').toggle_emphasis_visual(']] + .. key + .. [[')<cr>]] + end + set('x', '<c-b>', toggle_emph('b'), { desc = 'md: make bold' }) + set('x', '<c-i>', toggle_emph('i'), { desc = 'md: make italic' }) + set('x', '<c-s>', toggle_emph('s'), { desc = 'md: make strikethrough' }) + set('x', '<c-c>', toggle_emph('c'), { desc = 'md: make code' }) + end, + }, + { + 'MeanderingProgrammer/markdown.nvim', + name = 'render-markdown', -- needed if used together with markdown.nvim above + main = 'render-markdown', + dependencies = { + 'nvim-treesitter/nvim-treesitter', + 'echasnovski/mini.icons', + }, + ft = { 'markdown' }, + opts = { + heading = { + -- icons = { '❶ ', '❷ ', '❸ ', '❹ ', '❺ ', '❻ ' }, + icons = { + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + }, + signs = { 'ⅰ', 'ⅱ', 'ⅲ', 'ⅳ', 'ⅴ', 'ⅵ' }, + }, + bullet = { + icons = { '∙', '∘', '⋅', '⋄' }, + }, + checkbox = { + checked = { icon = ' ' }, + unchecked = { icon = ' ' }, + custom = { + todo = { raw = '[-]', rendered = ' ', highlight = 'RenderMarkdownTodo' }, + }, + }, + }, + init = vim.schedule_wrap(function() + vim.api.nvim_set_hl(0, 'RenderMarkdownH1Bg', { bg = 'NvimDarkBlue' }) + vim.api.nvim_set_hl(0, 'RenderMarkdownH1Fg', { fg = 'NvimLightBlue' }) + + vim.api.nvim_set_hl(0, 'RenderMarkdownH2Bg', { bg = 'NvimDarkMagenta' }) + vim.api.nvim_set_hl(0, 'RenderMarkdownH2Fg', { fg = 'NvimLightMagenta' }) + + vim.api.nvim_set_hl(0, 'RenderMarkdownH3Bg', { bg = 'NvimDarkYellow' }) + vim.api.nvim_set_hl(0, 'RenderMarkdownH3Fg', { fg = 'NvimLightYellow' }) + + vim.api.nvim_set_hl(0, 'RenderMarkdownH4Bg', { bg = 'NvimDarkCyan' }) + vim.api.nvim_set_hl(0, 'RenderMarkdownH4Fg', { fg = 'NvimLightCyan' }) + + vim.api.nvim_set_hl(0, 'RenderMarkdownH6Bg', { bg = 'NvimDarkRed' }) + vim.api.nvim_set_hl(0, 'RenderMarkdownH6Fg', { fg = 'NvimLightRed' }) + end), + }, +} diff --git a/.vim/lua/internal/plugins/zk.lua b/.vim/lua/internal/plugins/zk.lua new file mode 100644 index 0000000..76cbcb3 --- /dev/null +++ b/.vim/lua/internal/plugins/zk.lua @@ -0,0 +1,35 @@ +return { + { + lazy = false, + 'zk-org/zk-nvim', + main = 'zk', + opts = { + picker = 'telescope', + }, + keys = { + -- these will work everywhere + { ';zc', ':ZkNew ' }, + { ';zz', '<cmd>ZkNotes {sort={"modified"}}<cr>' }, + { ';zl', '<cmd>ZkLinks<cr>' }, + { ';zb', '<cmd>ZkBacklinks<cr>' }, + { ';zt', '<cmd>ZkTags<cr>' }, + -- { ';zj', '<cmd>ZkNotes { dir = "500_journals" }<cr>' }, + }, + init = function() + if not vim.env.ZK_NOTEBOOK_DIR then + return + end + vim.api.nvim_create_autocmd({ 'BufEnter' }, { + pattern = vim.env.ZK_NOTEBOOK_DIR .. '/*', + callback = function() + local o = { remap = true, silent = false, buffer = true } + -- these will only work in a zettel + vim.keymap.set('n', '-', ':call feedkeys(";zz")<cr>', o) + vim.keymap.set('n', '<cr>', '<cmd>lua vim.lsp.buf.definition()<cr>', o) + end, + group = vim.api.nvim_create_augroup('zk-binds', { clear = true }), + once = true, + }) + end, + }, +} diff --git a/.vim/lua/internal/snippets.lua b/.vim/lua/internal/snippets.lua new file mode 100644 index 0000000..be00884 --- /dev/null +++ b/.vim/lua/internal/snippets.lua @@ -0,0 +1,129 @@ +local ls = require('luasnip') +local types = require('luasnip.util.types') + +-- attach to builtin snippet hooks + +vim.snippet.expand = ls.lsp_expand + +---@diagnostic disable-next-line: duplicate-set-field +vim.snippet.active = function(filter) + filter = filter or {} + filter.direction = filter.direction or 1 + + if filter.direction == 1 then + return ls.expand_or_jumpable() + else + return ls.jumpable(filter.direction) + end +end + +---@diagnostic disable-next-line: duplicate-set-field +vim.snippet.jump = function(direction) + if direction == 1 then + if ls.expandable() then + return ls.expand_or_jump() + else + return ls.jumpable(1) and ls.jump(1) + end + else + return ls.jumpable(-1) and ls.jump(-1) + end +end + +vim.snippet.stop = ls.unlink_current + +local snip_env = { + -- snippet helpers + nl = function() + return ls.t({ '', '' }) + end, + exec = function(command) + return ls.f(function(_, _, ...) + local job = require('plenary.job'):new({ + command = vim.env.SHELL, + args = { '-c', ... }, + enable_recording = true, + }) + local res, exitcode = job:sync() + if not exitcode == 0 or #res == 0 then + error(string.format('exec "%s" failed', ...)) + end + return res + end, {}, { user_args = { command } }) + end, + -- condition helpers + cond = { + ts = function(capture) + return function() + return vim.tbl_contains(vim.treesitter.get_captures_at_cursor(), capture) + end + end, + }, +} + +ls.config.set_config({ + enable_autosnippets = true, + history = true, + updateevents = 'TextChanged,TextChangedI', + override_builtin = true, + snip_env = vim.tbl_deep_extend('error', ls.session.config.snip_env, snip_env), + ext_opts = { + [types.choiceNode] = { + active = { + virt_text = { { '◂ ', 'NonText' } }, + }, + }, + [types.insertNode] = { + active = { + virt_text = { { '◂ ', 'NonText' } }, + }, + }, + }, +}) + +require('luasnip.loaders.from_lua').lazy_load({ paths = './snippets' }) + +vim.keymap.set({ 'i', 's' }, '<c-j>', function() + return vim.snippet.active({ direction = 1 }) and vim.snippet.jump(1) +end, { silent = true, desc = 'snippet: jump next' }) + +vim.keymap.set({ 'i', 's' }, '<c-k>', function() + return vim.snippet.active({ direction = -1 }) and vim.snippet.jump(-1) +end, { silent = true, desc = 'snippet: jump prev' }) + +vim.keymap.set({ 'i', 's' }, '<c-n>', function() + if ls.choice_active() then + ls.change_choice(1) + end +end, { silent = true, desc = 'snippet: next choice' }) + +vim.keymap.set({ 'i', 's' }, '<c-p>', function() + if ls.choice_active() then + ls.change_choice(-1) + end +end, { silent = true, desc = 'snippet: prev choice' }) + +vim.api.nvim_create_user_command('EditSnippets', require('luasnip.loaders').edit_snippet_files, {}) + +-- vim.api.nvim_create_autocmd('User', { +-- pattern = 'LuasnipChoiceNodeEnter', +-- callback = function() +-- vim.schedule(function() +-- assert(ls.session.active_choice_nodes[vim.api.nvim_get_current_buf()], 'No active choiceNode') +-- vim.ui.select( +-- ls.get_current_choices(), +-- -- TODO: patch luasnip.extras.select_choice to fix missing prompt +-- { prompt = 'LuaSnip: choice node', kind = 'luasnip' }, +-- function(_, idx) +-- if not idx then +-- return +-- end +-- -- feed+immediately execute i to enter INSERT after vim.ui.input closes. +-- vim.api.nvim_feedkeys('i', 'x', false) +-- ls.set_choice(idx) +-- ls.unlink_current() +-- end +-- ) +-- end) +-- end, +-- }) diff --git a/.vim/lua/internal/snips.lua b/.vim/lua/internal/snips.lua deleted file mode 100644 index bb9fdef..0000000 --- a/.vim/lua/internal/snips.lua +++ /dev/null @@ -1,159 +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 - -local file_contents = function(path, vargs) - return ls.d(1, function(_, _, _, ...) - local lines = {} - for line in io.lines(path) do - table.insert(lines, line) - end - return ls.sn(nil, require('luasnip.extras.fmt').fmt(table.concat(lines, '\n'), ...)) - end, {}, { user_args = { vargs } }) -end - -ls.setup({ - history = true, - update_events = 'TextChanged,TextChangedI', - delete_check_events = 'TextChanged', - - ext_opts = { - [types.snippet] = { - active = { - virt_text = { { '<-- snippet', '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, { - f = ls.f, - i = ls.i, - s = ls.s, - t = ls.t, - c = ls.c, - sn = ls.sn, - fmt = require('luasnip.extras.fmt').fmt, - autowrap = autowrap, - exec = exec, - comment = comment, - file_contents = file_contents, - 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/sortline.lua b/.vim/lua/internal/sortline.lua deleted file mode 100644 index 69f7f64..0000000 --- a/.vim/lua/internal/sortline.lua +++ /dev/null @@ -1,78 +0,0 @@ -local M = {} - -local function get_visual_selection(intact) - intact = intact or false - 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 not intact then - 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) - end - return top, bot, lines -end - -local function sortline(line, a, o, separator) - separator = separator or ' ' - local result, _ = string.gsub(line, string.sub(line, a, o), - table.concat(vim.fn.sort(vim.fn.split(string.sub(line, a, o), separator)), separator), 1) - return result -end - -function M.sort_lines(_, preview_ns, preview_bufnr) - local bufnr = vim.api.nvim_get_current_buf() - - local top, bot, lines = get_visual_selection(true) - vim.pretty_print(top, bot, lines) - for i = 1, #lines do - local a = 0; if i == 1 then a = top.col end - local o = -1; if i == #lines then o = bot.col end - lines[i] = sortline(lines[i], a, o, ' ') - end - - if not preview_ns then - vim.api.nvim_buf_set_lines(bufnr, top.ln - 1, bot.ln, false, lines) - 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 - -function M.setup(opts) - vim.api.nvim_create_user_command( - 'SortLine', - M.sort_lines, - { desc = 'sort line', range = '%', preview = M.sort_lines } - ) -end - -return M diff --git a/.vim/lua/internal/spell.lua b/.vim/lua/internal/spell.lua deleted file mode 100644 index 3c37dad..0000000 --- a/.vim/lua/internal/spell.lua +++ /dev/null @@ -1,8 +0,0 @@ -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', '<C-l>', require('telescope.builtin').spell_suggest) -vim.keymap.set('n', '<C-l>', [[<c-g>u<esc>[s1z=`]a<c-g>u]]) diff --git a/.vim/lua/internal/statusline.lua b/.vim/lua/internal/statusline.lua deleted file mode 100644 index 8ed5cae..0000000 --- a/.vim/lua/internal/statusline.lua +++ /dev/null @@ -1,206 +0,0 @@ -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 .. [[%-h%-w%-q%-f %-m %-r]] - - sl = sl .. statusline_append(statusline_grapple(bufnr), 'StatusLineGrapple', hi) - - -- sl = sl .. statusline_append(statusline_ts(), 'StatusLineTreesitter', hi) - - sl = sl .. [[ %= ]] -- spacer - - 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 .. [[%-l:%-v --%p%%-- %-Y]] - - 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(0, { name = outer_name, create = false }) - local inner = vim.api.nvim_get_hl(0, { name = inner_name, create = false }) - local name = ('auto' .. outer_name .. inner_name) - vim.api.nvim_get_hl(0, - { name = name, create = true }) - local hi = inner - hi.bg = inner.fg - hi.fg = outer.bg - vim.api.nvim_set_hl(0, name, hi) - return name -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('StatusLine', '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('StatusLine', '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_grapple(bufnr) - local g = package.loaded.grapple - if not g then return '' end - return g.statusline() - -- if not g or not g.exists({ buffer = bufnr }) then - -- return '' - -- end - -- return '➥ ' .. g.key({ buffer = bufnr }) -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_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 - -function _G.statusline_notify(default_hi) - if not _G.statusline_notifications or #_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 <timeout> 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(vim.inspect(n.message), 'StatusLineNotify', default_hi) - return vim.trim(s) -end - -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/internal/syncbg.lua b/.vim/lua/internal/syncbg.lua deleted file mode 100644 index 418e17e..0000000 --- a/.vim/lua/internal/syncbg.lua +++ /dev/null @@ -1,46 +0,0 @@ -local M = {} - -M.init = function() - -- get tty - local tty_handle = io.popen('tty') - if tty_handle == nil then return end - local tty = tty_handle:read('*a') - tty_handle:close() - if tty:find("not a tty") then error('not a tty') end - - M.tty = tty -end - -M.update = function() - if M.tty == nil then return end - - if not M.normal then - -- get colorscheme Normal highlight - local normal = vim.api.nvim_get_hl(0, { name = 'Normal', create = false }) - if (normal.bg == nil) then return end - -- cache old value for use with VimResume - M.normal = normal - end - - -- emit CSI to change terminal background to Normal.bg - os.execute('printf "\\033]11;' .. string.format('#%06x', M.normal.bg) .. '\\007" > ' .. M.tty) - - -- set colorscheme Normal.bg to NONE, making it transparent - vim.cmd [[hi Normal ctermbg=NONE guibg=NONE]] -end - -M.reset = function() - if M.tty == nil then return end - - os.execute('printf "\\033]111\\007" > ' .. M.tty) -end - -M.setup = function(opts) - opts = opts or {} - - M.init() - vim.api.nvim_create_autocmd({ 'ColorScheme', 'UIEnter', 'VimResume' }, { callback = M.update }) - vim.api.nvim_create_autocmd({ 'UILeave' }, { callback = M.reset }) -end - -return M diff --git a/.vim/lua/internal/zk.lua b/.vim/lua/internal/zk.lua deleted file mode 100644 index 5e17786..0000000 --- a/.vim/lua/internal/zk.lua +++ /dev/null @@ -1,7 +0,0 @@ --- vim.keymap.set('n', '<leader>zn', function() require('zk').new() end, {buffer=true}) --- vim.keymap.set('n', '<leader>zi', function() require('zk').index() end, {buffer=true}) --- vim.cmd [[ command! -nargs=* ZettelkastenNew lua require('zk').new(nil, <f-args>) ]] - -vim.keymap.set('n', 'gt', function() - require('telescope._extensions.todo-comments').exports.todo({ cwd = vim.env.ZK_NOTEBOOK_DIR }) -end, { desc = 'show zk todos', buffer = true }) |