neovim

Personal neovim configuration files
git clone git://gtms.dev/neovim.git
Log | Files | Refs

commit a0e3834e38db78fcda5660c17646cf745858047d
parent 75063ba761053a85bae70ec8e4843be4bc4dc9b9
Author: Tomas Nemec <nemi@skaut.cz>
Date:   Mon,  6 Dec 2021 11:47:24 +0100

update

Diffstat:
Mftplugin/mail.lua | 1+
Minit.lua | 39+++++++++++++--------------------------
Dlua/tms/diagnostic.lua | 19-------------------
Mlua/tms/ft/dart/lsp.lua | 2+-
Mlua/tms/lsp/init.lua | 19+++++--------------
Mlua/tms/p/luasnip.lua | 7++++++-
Mlua/tms/p/telescope.lua | 71+++++++++++++++++++----------------------------------------------------
Mlua/tms/plugins.lua | 46++++++++++++++++++++++++++++++++++++----------
Dlua/tms/ts/range.lua | 108-------------------------------------------------------------------------------
Mlua/tms/u/git.lua | 1+
Dlua/tms/u/ui.lua | 24------------------------
Dlua/tms/ws/file_pairs.lua | 59-----------------------------------------------------------
Mlua/tms/ws/init.lua | 26++------------------------
Mlua/tms/ws/medoro.lua | 28+++++++++++++++++-----------
Aplugin/bufremove.lua | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aplugin/diagnostic.lua | 13+++++++++++++
Aplugin/file_pairs.lua | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mplugin/terminal.lua | 14++++----------
Aplugin/ws.lua | 12++++++++++++
19 files changed, 347 insertions(+), 359 deletions(-)

diff --git a/ftplugin/mail.lua b/ftplugin/mail.lua @@ -1,2 +1,3 @@ vim.opt.spell = true vim.opt.spelllang = {'cs', 'csa', 'en'} +vim.keymap.nnoremap {'<leader>pa', require('tms.p.telescope').mail_address, buffer = true} diff --git a/init.lua b/init.lua @@ -1,18 +1,16 @@ local install_path = vim.fn.stdpath('data') .. '/site/pack/packer/opt/packer.nvim' - if vim.fn.empty(vim.fn.glob(install_path)) > 0 then vim.api.nvim_command('!git clone --depth=1 https://github.com/wbthomason/packer.nvim ' .. install_path) end -function _G.dump(...) +function _G.D(...) local objects = vim.tbl_map(vim.inspect, {...}) print(unpack(objects)) end -- Meta setup -require('impatient') -vim.cmd [[runtime plugin/astronauta.vim]] -vim.g.mapleader = ',' +require('impatient') -- faster `require` +require('astronauta.keymap') -- vim.keymap require('colorbuddy').colorscheme('my-default') -- disable netrw @@ -66,15 +64,8 @@ vim.opt.scrolloff = 5 vim.opt.sidescrolloff = 5 vim.opt.signcolumn = 'yes:1' --- Load plugins -require('tms.plugins') -if vim.fn.empty(vim.fn.glob(vim.fn.stdpath('config') .. '/lua/packer_compiled.lua')) > 0 then - vim.cmd [[PackerCompile]] -else - require('packer_compiled') -end - -- MAPPINGS +vim.g.mapleader = ',' local nmap = vim.keymap.nmap local nnoremap = vim.keymap.nnoremap local tnoremap = vim.keymap.tnoremap @@ -99,7 +90,7 @@ nnoremap {'<leader>W', '<cmd>wall<cr>'} nnoremap {'<leader>e', '<cmd>edit<cr>'} nnoremap {'<leader>E', ':e %:h/'} nnoremap {'<leader>q', '<cmd>quit<cr>'} -nnoremap {'<leader>Q', '<cmd>qall<cr>'} +nnoremap {'<leader>Q', '<cmd>quit!<cr>'} nnoremap {'<leader>M', '<cmd>messages<cr>'} nnoremap {'<leader>so', '<cmd>source<cr>'} nnoremap {'<leader>o', '<cmd>BufOnly<cr>'} @@ -177,20 +168,16 @@ au.addListeners({ ['user-cursorline'] = {[[WinEnter * setlocal cursorline]], [[WinLeave * setlocal nocursorline]]}, ['user-yank-high'] = {[[TextYankPost * silent! lua require'vim.highlight'.on_yank()]]}, ['user-colorscheme'] = {[[ColorScheme * lua require('tms.u.reload').colors()]]}, - -- ['java-lsp'] = { - -- [[FileType java lua require('jdtls').start_or_attach({cmd = {'java-lsp.sh'}})]], - -- }, - -- ['quickfix'] = {[[QuickFixCmdPost [^l]* nested cwindow]], [[QuickFixCmdPost l* nested lwindow]]}, }) +-- commands vim.cmd('command! Reload lua require("tms.u.reload").nvim()') --- vim.api.nvim_exec([[ --- augroup Packer --- autocmd! --- autocmd BufWritePost lua/tms/plugins.lua PackerCompile --- augroup end --- ]], false) +-- Load plugins vim.cmd [[ packadd cfilter ]] -require('tms.diagnostic').setup() -require('tms.ws').setup() +require('tms.plugins') +if vim.fn.empty(vim.fn.glob(vim.fn.stdpath('config') .. '/lua/packer_compiled.lua')) > 0 then + vim.cmd [[PackerCompile]] +else + require('packer_compiled') +end diff --git a/lua/tms/diagnostic.lua b/lua/tms/diagnostic.lua @@ -1,19 +0,0 @@ -local M = {} - -M.setup = function() - vim.diagnostic.config({virtual_text = false, underline = false, float = {border = 'single'}, severity_sort = true}) - - vim.keymap.nnoremap {'gs', function() vim.diagnostic.open_float(0, {scope = 'line'}) end, silent = true} - vim.keymap.nnoremap {'gS', function() vim.diagnostic.open_float(0, {scope = 'cursor'}) end, silent = true} - vim.keymap.nnoremap {'gll', function() vim.diagnostic.setloclist() end, silent = true} - vim.keymap.nnoremap {'glq', function() vim.diagnostic.setqflist() end, silent = true} - - local goto_next = function() vim.diagnostic.goto_next({float = false}) end - local goto_prev = function() vim.diagnostic.goto_prev({float = false}) end - vim.keymap.nnoremap {'>d', goto_next, silent = true} - vim.keymap.nnoremap {'>(', goto_next, silent = true} - vim.keymap.nnoremap {'<d', goto_prev, silent = true} - vim.keymap.nnoremap {'<(', goto_prev, silent = true} -end - -return M diff --git a/lua/tms/ft/dart/lsp.lua b/lua/tms/ft/dart/lsp.lua @@ -18,7 +18,7 @@ M.extract = function() local cur_buf_name = api.nvim_buf_get_name(cur_buf) local range = vim.lsp.util.make_range_params() local params = {command = 'refactor.perform', arguments = {'EXTRACT_METHOD', cur_buf_name, range}, title = ''} - dump(lsp.get_active_clients()[1].request('codeAction/resolve', 'EXTRACT_METHOD', function(err, resolved_action) + D(lsp.get_active_clients()[1].request('codeAction/resolve', 'EXTRACT_METHOD', function(err, resolved_action) if err then vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR) return diff --git a/lua/tms/lsp/init.lua b/lua/tms/lsp/init.lua @@ -11,22 +11,16 @@ local keybind = function(bufnr) vim.keymap.nnoremap {'<c-p>', vim.lsp.buf.signature_help, silent = true, buffer = bufnr} vim.keymap.inoremap {'<c-p>', vim.lsp.buf.signature_help, silent = true, buffer = bufnr} vim.keymap.nnoremap {'gr', vim.lsp.buf.references, silent = true, buffer = bufnr} - vim.keymap.nnoremap {'ga', t.lsp_code_actions, silent = true, buffer = bufnr} - vim.keymap.vnoremap { - 'ga', - ':Telescope lsp_range_code_actions theme=dropdown previewer=false<cr>', - silent = true, - buffer = bufnr, - } + vim.keymap.nnoremap {'ga', vim.lsp.buf.code_action, silent = true, buffer = bufnr} vim.keymap.nnoremap {'gn', vim.lsp.buf.rename, silent = true, buffer = bufnr} - vim.keymap.nnoremap {'gm', t.lsp_document_symbols, silent = true, buffer = bufnr} -- formatting vim.keymap.nnoremap {'Q', vim.lsp.buf.formatting, silent = true, buffer = bufnr} vim.keymap.vnoremap {'Q', vim.lsp.buf.range_formatting, silent = true, buffer = bufnr} - -- workspace + -- symbols + vim.keymap.nnoremap {'gm', t.lsp_document_symbols, silent = true, buffer = bufnr} vim.keymap.nnoremap {'gww', t.b.lsp_dynamic_workspace_symbols, silent = true, buffer = bufnr} vim.keymap.nnoremap {'gwW', vim.lsp.buf.workspace_symbol, silent = true, buffer = bufnr} - vim.keymap.nnoremap {'gwl', function() dump(vim.lsp.buf.list_workspace_folders()) end, silent = true, buffer = bufnr} + vim.keymap.nnoremap {'gwl', function() D(vim.lsp.buf.list_workspace_folders()) end, silent = true, buffer = bufnr} end local attach_callbacks = {} @@ -84,10 +78,7 @@ M.setup = function() end) -- Manual install - local manual_servers = { - 'gdscript', - 'dartls' - } + local manual_servers = {'gdscript', 'dartls'} for _, name in ipairs(manual_servers) do add_server(name) end end diff --git a/lua/tms/p/luasnip.lua b/lua/tms/p/luasnip.lua @@ -57,7 +57,12 @@ local snippets = function(luasnip) t(': '), }), }, - html = {s('ni', fmt('*ngIf="{1}"', {i(1)}))}, + html = { + s('if', fmt('*ngIf="{1}"', {i(1)})), + s('ni', fmt('[{1}]="{2}"', {i(1), i(2)})), + s('no', fmt('({1})="{2}"', {i(1), i(2)})), + s('nb', fmt('[({1})]="{2}"', {i(1), i(2)})), + }, lua = { s('f', fmt('function() {1} end', {i(1)})), s('r', fmt('require(\'{1}\')', {i(1)})), diff --git a/lua/tms/p/telescope.lua b/lua/tms/p/telescope.lua @@ -3,6 +3,7 @@ local themes = require('telescope.themes') local builtin = require('telescope.builtin') local actions = require('telescope.actions') local action_set = require('telescope.actions.set') +local action_generate = require('telescope.actions.generate') local action_state = require('telescope.actions.state') local pickers = require('telescope.pickers') local make_entry = require('telescope.make_entry') @@ -41,7 +42,23 @@ local layouts = { function M.setup() telescope.setup { - defaults = {mappings = {i = {['<esc>'] = actions.close, ['<c-r>'] = 'delete_buffer'}}}, + defaults = { + -- + mappings = { + -- + i = { + -- + ['<esc>'] = actions.close, + ['<c-r>'] = 'delete_buffer', + ['<c-?>'] = action_generate.which_key({ + name_width = 20, -- typically leads to smaller floats + max_height = 0.5, -- increase potential maximum height + seperator = ' > ', -- change sep between mode, keybind, and name + close_with_action = false, -- do not close float on action + }), + }, + }, + }, extensions = {fzy_native = {override_generic_sorter = false, override_file_sorter = true}}, } end @@ -70,53 +87,10 @@ end M.spell_suggest = function() builtin.spell_suggest(layouts.dd) end -M.grep_files = function(cwd, files, select_fn, opts) - local opts = opts or {} - local vimgrep_arguments = opts.vimgrep_arguments or conf.vimgrep_arguments - opts.cwd = cwd or opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd() - - local search_files = {} - if type(files) == 'string' then - table.insert(search_files, vim.fn.expand(files)) - elseif type(files) == 'table' then - for i, path in ipairs(files) do files[i] = vim.fn.expand(path) end - search_files = files - end - - local live_grepper = finders.new_job(function(prompt) - if not prompt or prompt == '' then return nil end - return vim.tbl_flatten {vimgrep_arguments, escape_chars(prompt), search_files} - end, opts.entry_maker or make_entry.gen_from_vimgrep(opts), opts.max_results, opts.cwd) - - pickers.new(opts, { - prompt_title = 'Grep files', - finder = live_grepper, - previewer = conf.grep_previewer(opts), - sorter = conf.generic_sorter(opts), - attach_mappings = function(_) - action_set.select:replace(select_fn) - return true - end, - }):find() -end - --- TODO(tms) 29.04.2021 -M.grep_file = function(filepath, opts) - local finder = finders.new_job({conf.vimgrep_arguments}, function(line) return line end, opts.max_results, '') - - pickers.new(opts, { - prompt_title = 'rg ', - finder = finder, - previewer = conf.grep_previewer({}), - sorter = conf.generic_sorter({}), - }):find() -end - M.mail_address = function() - local search = vim.fn.input('Address > ') pickers.new { results_title = 'Adresses', - finder = finders.new_oneshot_job({'goobook', 'query', search}), + finder = finders.new_oneshot_job({'goobook', 'query', '.*'}), sorter = sorters.get_fuzzy_file(), attach_mappings = function(_) action_set.select:replace(function(prompt_bufnr, _) @@ -131,13 +105,6 @@ M.mail_address = function() }:find() end --- TODO: not working --- If git project run Git_files otherwise run find_files -M.project_files = function() - local opts = {} - local ok = pcall(builtin.git_files, opts) - if not ok then builtin.find_files(opts) end -end M.lines = function() builtin.current_buffer_fuzzy_find(layouts.dd_large_noprev) end M.reloader = function() builtin.reloader(layouts.dd_noprev) end M.buffers = function() builtin.buffers(layouts.dd_large) end diff --git a/lua/tms/plugins.lua b/lua/tms/plugins.lua @@ -38,7 +38,23 @@ return packer.startup({ config = function() require('Comment').setup({ ignore = '^$', - pre_hook = function(_) return require('ts_context_commentstring.internal').calculate_commentstring() end, + pre_hook = function(ctx) + -- Only calculate commentstring for tsx filetypes + local U = require('Comment.utils') + -- Detemine whether to use linewise or blockwise commentstring + local type = ctx.ctype == U.ctype.line and '__default' or '__multiline' + -- Determine the location where to calculate commentstring from + local location = nil + if ctx.ctype == U.ctype.block then + location = require('ts_context_commentstring.utils').get_cursor_location() + elseif ctx.cmotion == U.cmotion.v or ctx.cmotion == U.cmotion.V then + location = require('ts_context_commentstring.utils').get_visual_start_location() + end + return require('ts_context_commentstring.internal').calculate_commentstring({ + key = type, + location = location, + }) + end, }) end, } @@ -87,14 +103,6 @@ return packer.startup({ vim.keymap.nmap {'#', '#:Beacon<cr>'} end, } - use { - disable = true, - 'VonHeikemen/fine-cmdline.nvim', - requires = {'MunifTanjim/nui.nvim'}, - config = function() - vim.api.nvim_set_keymap('n', ':', '<cmd>lua require("fine-cmdline").open()<CR>', {noremap = true}) - end, - } -- Nice thing... not sure if i like this use { -- highlight parens 'Yggdroot/hiPairs', setup = function() @@ -306,7 +314,25 @@ return packer.startup({ } -- ui - use 'MunifTanjim/nui.nvim' + use { + 'stevearc/dressing.nvim', + config = function() + -- + require('dressing').setup({ + + select = { + -- Priority list of preferred vim.select implementations + backend = {'telescope', 'fzf', 'builtin', 'nui'}, + + -- Options for telescope selector + telescope = { + -- can be 'dropdown', 'cursor', or 'ivy' + theme = 'dropdown', + }, + }, + }) + end, + } use { 'rcarriga/nvim-notify', config = function() diff --git a/lua/tms/ts/range.lua b/lua/tms/ts/range.lua @@ -1,108 +0,0 @@ -local function get_selection_range() - local _, start_row, start_col, _ = unpack(vim.fn.getpos("'<")) - local _, end_row, _, _ = unpack(vim.fn.getpos("'>")) - local end_col = vim.fn.col("'>") - - -- end_col :: TS is 0 based, and '> on line selections is char_count + 1 - -- I think - 2 is correct on - -- - -- end_row : end_row is exclusive in TS, so we don't minus - return start_row, start_col, end_row, end_col -end - ----@class Region ---- The following fields act similar to a cursor ----@field start_row number: The 1-based row ----@field start_col number: The 0-based col ----@field end_row number: The 1-based row ----@field end_col number: The 0-based col ----@field bufnr number: the buffer that the region is from -local Region = {} -Region.__index = Region - ---- Get a Region from the current selection ----@return Region -function Region:from_current_selection() - local start_row, start_col, end_row, end_col = get_selection_range() - - return setmetatable({ - bufnr = vim.fn.bufnr(), - from_vim = true, - start_row = start_row, - start_col = start_col, - end_row = end_row, - end_col = end_col, - }, self) -end - ---- Get a region from a Treesitter Node ----@return Region -function Region:from_node(node, bufnr) - bufnr = bufnr or vim.fn.bufnr() - local start_line, start_col, end_line, end_col = node:range() - - -- todo: is col correct? - return setmetatable({ - bufnr = vim.fn.bufnr(bufnr), - start_row = start_line + 1, - start_col = start_col, - end_row = end_line + 1, - end_col = end_col, - }, self) -end - -function Region:from_lsp_range(lsp_range, bufnr) - bufnr = bufnr or vim.fn.bufnr() - - -- todo: is col correct? - return setmetatable({ - bufnr = vim.fn.bufnr(bufnr), - start_row = lsp_range.start.line + 1, - start_col = lsp_range.start.character, - end_row = lsp_range["end"].line + 1, - end_col = lsp_range["end"].character, - }, self) -end - ---- Convert a region to a vim region -function Region:to_vim() - return self.start_row, self.start_col, self.end_row, self.end_col -end - ---- Convert a region to a tree sitter region -function Region:to_ts() - return self.start_row - 1, self.start_col, self.end_row - 1, self.end_col -end - -function Region:get_text(bufnr) - local text = vim.api.nvim_buf_get_lines( - bufnr or 0, - self.start_row - 1, - self.end_row, - false - ) - return text -end - ---- Convert a region to an LSP Range -function Region:to_lsp_range() - return { - ["start"] = { - line = self.start_row - 1, - character = self.start_col, - }, - ["end"] = { - line = self.end_row - 1, - character = self.end_col, - }, - } -end - -function Region:to_lsp_text_edit(text) - return { - range = self:to_lsp_range(), - newText = text, - } -end - -return Region diff --git a/lua/tms/u/git.lua b/lua/tms/u/git.lua @@ -1,6 +1,7 @@ local M = {} M.is_git = function(path) + ---@diagnostic disable-next-line: unused-local local id = vim.fn.jobstart('git -C "' .. path .. '" rev-parse', {on_exit = function(_, code, type) end}) local status = vim.fn.jobwait({id})[1] if status == 0 then diff --git a/lua/tms/u/ui.lua b/lua/tms/u/ui.lua @@ -1,24 +0,0 @@ --- local api = vim.api --- local Popup = require('nui.popup') -local M = {} - -M.input = function(headline, callback) - local Input = require('nui.input') - local event = require('nui.utils.autocmd').event - - local input = Input({ - border = {style = 'rounded', text = {top = headline, top_align = 'left'}}, - relative = 'editor', - position = '50%', - size = {width = '80', height = '1'}, - }, {on_submit = callback, prompt = ''}) - - input:mount() - input:map('i', '<esc>', function() - input.input_props.on_close() - vim.cmd [[stopinsert]] - end, {noremap = true}) - input:on(event.BufLeave, input.input_props.on_close, {once = true}) -end - -return M diff --git a/lua/tms/ws/file_pairs.lua b/lua/tms/ws/file_pairs.lua @@ -1,59 +0,0 @@ -local M = {} - -local ft_letter = {html = 't', scss = 's', dart = 'd', css = 'c'} - -local letter_set = {} - -local set_mark = function(letter, path, buffer) - path = path or vim.fn.expand('%') - if buffer == nil then buffer = true end - vim.keymap.nnoremap {'<leader>m' .. letter, '<cmd>edit ' .. path .. '<cr>', ['buffer'] = buffer} - vim.keymap.nnoremap {'<leader>mv' .. letter, '<cmd>vsplit ' .. path .. '<cr>', ['buffer'] = buffer} - vim.keymap.nnoremap {'<leader>mx' .. letter, '<cmd>split ' .. path .. '<cr>', ['buffer'] = buffer} -end - -local unset_marks = function() - local leader = vim.g.mapleader - for _, map in ipairs(vim.api.nvim_buf_get_keymap(0, 'n')) do - for _, letter in pairs(ft_letter) do - if map.lhs == leader .. 'm' .. letter then - vim.api.nvim_buf_del_keymap(0, 'n', '<leader>m' .. letter) - end - if map.lhs == leader .. 'mv' .. letter then vim.api.nvim_buf_del_keymap(0, 'n', '<leader>mv' .. letter) end - if map.lhs == leader .. 'mx' .. letter then vim.api.nvim_buf_del_keymap(0, 'n', '<leader>mx' .. letter) end - end - end -end - -M.config = function() - -- TODO(tms) 19.11.21: - unset_marks() - local filename = vim.fn.expand('%:t:r') - local dir = vim.fn.expand('%:h') - local files = {} - local on_event = function(_, data, event) - if event == 'stderr' then print(data) end - if event == 'stdout' then - if #data > 1 then - for _, file in ipairs(data) do - local _, _, ext = file:match('(.-)([^\\/]-%.?([^%.\\/]*))$') - files[ext] = file - end - end - end - if event == 'exit' then - for ext, file in pairs(files) do - local letter = ft_letter[ext] - if letter then - set_mark(letter, file, true) - table.insert(letter_set, letter) - end - end - files = {} - end - end - - vim.fn.jobstart(string.format('fd -t f "^%s\\." "%s"', filename, dir), {on_stdout = on_event, on_exit = on_event}) -end - -return M diff --git a/lua/tms/ws/init.lua b/lua/tms/ws/init.lua @@ -1,30 +1,8 @@ -local au = require('tms.c.autocmd') - local M = {} -local ws = {} -ws.mail = { - filetypes = {'mail'}, - config = function() vim.keymap.nnoremap{'<leader>pa', [[<cmd>lua require("tms.p.telescope").mail_address()<cr>]]} end, -} - -ws.file_pairs = {buffer = '*', config = function() require('tms.ws.file_pairs').config() end} - -ws.medoro = { +M.medoro = { path = '*/medoro/**', - config = function() vim.keymap.nnoremap{'<leader>pl', '<cmd>lua require("tms.ws.medoro").lang()<cr>'} end, + config = function() vim.keymap.nnoremap {'<leader>pl', '<cmd>lua require("tms.ws.medoro").lang()<cr>', buffer = true} end, } -M.setup = function() - for name, setup in pairs(ws) do - if setup.buffer then au.addListener('user-project-buffer-' .. name, {'BufEnter ' .. setup.buffer}, setup.config) end - if setup.path then au.addListener('user-project-path-' .. name, {'VimEnter ' .. setup.path}, setup.config) end - if setup.filetypes then - for _, filetype in ipairs(setup.filetypes) do - au.addListener('user-project-ft-' .. name, {'FileType ' .. filetype}, setup.config) - end - end - end -end - return M diff --git a/lua/tms/ws/medoro.lua b/lua/tms/ws/medoro.lua @@ -1,19 +1,25 @@ -local actions_state = require('telescope.actions.state') -local actions = require('telescope.actions') - local M = {} M.lang = function() local cwd = '/home/tms/dev/medoro/dpgw/dpgw/src/main/resources/org/medoro/dpgw/core/lang/' local files = {'lang.properties', 'lang_cs.properties'} - require('tms.p.telescope').grep_files(cwd, files, function(prompt_bufnr, _) - local entry = actions_state.get_selected_entry() - local lang = entry.text:match('(%S+)=.*') - print(entry.text, lang) - actions.close(prompt_bufnr) - vim.fn.setreg('+', lang) - vim.fn.setreg('*', lang) - end) + require('telescope.builtin').live_grep({ + cwd = cwd, + search_dirs = files, + disable_coordinates = true, + attach_mappings = function(prompt_bufnr) + local actions = require('telescope.actions') + actions.select_default:replace(function(_, _) + local entry = require('telescope.actions.state').get_selected_entry() + local lang = entry.text:match('(%S+)=.*') + print(entry.text, lang) + actions.close(prompt_bufnr) + vim.fn.setreg('+', lang) + vim.fn.setreg('*', lang) + end) + return true + end, + }) end return M diff --git a/plugin/bufremove.lua b/plugin/bufremove.lua @@ -0,0 +1,160 @@ +-- MIT License Copyright (c) 2021 Evgeni Chasnovski +---@brief [[ +--- Lua module for minimal buffer removing (unshow, delete, wipeout), which +--- saves window layout (opposite to builtin Neovim's commands). This is mostly +--- a Lua implementation of +--- [bclose.vim](https://vim.fandom.com/wiki/Deleting_a_buffer_without_closing_the_window). +--- Other alternatives: +--- - [vim-bbye](https://github.com/moll/vim-bbye) +--- - [vim-sayonara](https://github.com/mhinz/vim-sayonara) +--- +--- # Notes +--- 1. Which buffer to show in window(s) after its current buffer is removed is +--- decided by the algorithm: +--- - If alternate buffer (see |CTRL-^|) is listed (see |buflisted()|), use it. +--- - If previous listed buffer (see |bprevious|) is different, use it. +--- - Otherwise create a scratch one with `nvim_create_buf(true, true)` and use +--- it. +--- +---@brief ]] +---@tag Bufremove bufremove +-- Module and its helper +local BufRemove = {} +local H = {} + +-- Module functionality +--- Delete buffer `buf_id` with |:bdelete| after unshowing it. +--- +---@param buf_id number: Buffer identifier (see |bufnr()|) to use. Default: 0 for current. +---@param force boolean: Whether to ignore unsaved changes (using `!` version of command). Default: `false`. +---@return boolean: Whether operation was successful. +function BufRemove.delete(buf_id, force) return H.unshow_and_cmd(buf_id, force, 'bdelete') end + +--- Wipeout buffer `buf_id` with |:bwipeout| after unshowing it. +--- +---@param buf_id number: Buffer identifier (see |bufnr()|) to use. Default: 0 for current. +---@param force boolean: Whether to ignore unsaved changes (using `!` version of command). Default: `false`. +---@return boolean: Whether operation was successful. +function BufRemove.wipeout(buf_id, force) return H.unshow_and_cmd(buf_id, force, 'bwipeout') end + +--- Stop showing buffer `buf_id` in all windows +--- +---@param buf_id number: Buffer identifier (see |bufnr()|) to use. Default: 0 for current. +---@return boolean: Whether operation was successful. +function BufRemove.unshow(buf_id) + + buf_id = H.normalize_buf_id(buf_id) + + if not H.is_valid_id(buf_id, 'buffer') then return false end + + vim.tbl_map(BufRemove.unshow_in_window, vim.fn.win_findbuf(buf_id)) + + return true +end + +--- Stop showing current buffer of window `win_id` +---@param win_id number: Window identifier (see |win_getid()|) to use. Default: 0 for current. +---@return boolean: Whether operation was successful. +function BufRemove.unshow_in_window(win_id) + + win_id = (win_id == nil) and 0 or win_id + + if not H.is_valid_id(win_id, 'window') then return false end + + local cur_buf = vim.api.nvim_win_get_buf(win_id) + + -- Temporary use window `win_id` as current to have Vim's functions working + vim.api.nvim_win_call(win_id, function() + -- Try using alternate buffer + local alt_buf = vim.fn.bufnr('#') + if alt_buf ~= cur_buf and vim.fn.buflisted(alt_buf) == 1 then + vim.api.nvim_win_set_buf(win_id, alt_buf) + return + end + + -- Try using previous buffer + vim.cmd([[bprevious]]) + if cur_buf ~= vim.api.nvim_win_get_buf(win_id) then return end + + -- Create new listed scratch buffer + local new_buf = vim.api.nvim_create_buf(true, true) + vim.api.nvim_win_set_buf(win_id, new_buf) + end) + + return true +end + +-- Removing implementation +function H.unshow_and_cmd(buf_id, force, cmd) + buf_id = H.normalize_buf_id(buf_id) + force = (force == nil) and false or force + + if not H.is_valid_id(buf_id, 'buffer') then return false end + + local fun_name = ({['bdelete'] = 'delete', ['bwipeout'] = 'wipeout'})[cmd] + if not H.can_remove(buf_id, force, fun_name) then return false end + + -- Unshow buffer from all windows + BufRemove.unshow(buf_id) + + -- Execute command + local command = string.format('%s%s %d', cmd, force and '!' or '', buf_id) + ---- Use `pcall` here to take care of case where `unshow()` was enough. + ---- This can happen with 'bufhidden' option values: + ---- - If `delete` then `unshow()` already `bdelete`d buffer. Without `pcall` + ---- it gives E516 for `Bufremove.delete()` (`wipeout` works). + ---- - If `wipe` then `unshow()` already `bwipeout`ed buffer. Without `pcall` + ---- it gives E517 for module's `wipeout()` (still E516 for `delete()`). + local ok, result = pcall(vim.cmd, command) + if not (ok or result:find('E516') or result:find('E517')) then + vim.notify('(bufremove) ' .. result) + return false + end + + return true +end + +-- Utilities +function H.is_valid_id(x, type) + local is_valid = false + if type == 'buffer' then + is_valid = vim.api.nvim_buf_is_valid(x) + elseif type == 'window' then + is_valid = vim.api.nvim_win_is_valid(x) + end + + if not is_valid then H.notify(string.format('%s is not a valid %s id.', tostring(x), type)) end + return is_valid +end + +---- Check if buffer can be removed with `Bufremove.fun_name` function +function H.can_remove(buf_id, force, fun_name) + if force then return true end + + if vim.api.nvim_buf_get_option(buf_id, 'modified') then + H.notify(string.format('Buffer %d has unsaved changes. Use `Bufremove.%s(%d, true)` to force.', buf_id, fun_name, + buf_id)) + return false + end + return true +end + +---- Compute 'true' buffer id (strictly positive integer). Treat `nil` and 0 as +---- current buffer. +function H.normalize_buf_id(buf_id) + if buf_id == nil or buf_id == 0 then return vim.api.nvim_get_current_buf() end + return buf_id +end + +function H.notify(msg) vim.notify(string.format('(bufremove) %s', msg)) end + +_G.BufRemove = BufRemove + +vim.cmd [[command! -nargs=? BufDelete lua BufRemove.delete(<args>)]] +vim.cmd [[command! -nargs=? BufWipeout lua BufRemove.wipeout(<args>)]] +vim.cmd [[command! -nargs=? BufUnshow lua BufRemove.unshow(<args>)]] +vim.cmd [[command! -nargs=? BufWinUnshow lua BufRemove.unshow_in_window(<args>)]] +vim.keymap.nnoremap {'<leader>bd', _G.BufRemove.delete} +vim.keymap.nnoremap {'<leader>bw', _G.BufRemove.wipeout} +vim.keymap.nnoremap {'<leader>bu', _G.BufRemove.unshow} +vim.keymap.nnoremap {'<leader>bU', _G.BufRemove.unshow_in_window} diff --git a/plugin/diagnostic.lua b/plugin/diagnostic.lua @@ -0,0 +1,13 @@ +vim.diagnostic.config({virtual_text = false, underline = false, float = {border = 'single'}, severity_sort = true}) + +vim.keymap.nnoremap {'gs', function() vim.diagnostic.open_float(0, {scope = 'line'}) end, silent = true} +vim.keymap.nnoremap {'gS', function() vim.diagnostic.open_float(0, {scope = 'cursor'}) end, silent = true} +vim.keymap.nnoremap {'gll', function() vim.diagnostic.setloclist() end, silent = true} +vim.keymap.nnoremap {'glq', function() vim.diagnostic.setqflist() end, silent = true} + +local goto_next = function() vim.diagnostic.goto_next({float = false}) end +local goto_prev = function() vim.diagnostic.goto_prev({float = false}) end +vim.keymap.nnoremap {'>d', goto_next, silent = true} +vim.keymap.nnoremap {'>(', goto_next, silent = true} +vim.keymap.nnoremap {'<d', goto_prev, silent = true} +vim.keymap.nnoremap {'<(', goto_prev, silent = true} diff --git a/plugin/file_pairs.lua b/plugin/file_pairs.lua @@ -0,0 +1,57 @@ +local au = require('tms.c.autocmd') + +local ft_letter = {html = 't', scss = 's', dart = 'd', css = 'c'} + +local letter_set = {} + +local set_mark = function(letter, path, buffer) + path = path or vim.fn.expand('%') + if buffer == nil then buffer = true end + vim.keymap.nnoremap {'<leader>m' .. letter, '<cmd>edit ' .. path .. '<cr>', ['buffer'] = buffer} + vim.keymap.nnoremap {'<leader>mv' .. letter, '<cmd>vsplit ' .. path .. '<cr>', ['buffer'] = buffer} + vim.keymap.nnoremap {'<leader>mx' .. letter, '<cmd>split ' .. path .. '<cr>', ['buffer'] = buffer} +end + +local unset_marks = function() + local leader = vim.g.mapleader + for _, map in ipairs(vim.api.nvim_buf_get_keymap(0, 'n')) do + for _, letter in pairs(ft_letter) do + if map.lhs == leader .. 'm' .. letter then vim.api.nvim_buf_del_keymap(0, 'n', '<leader>m' .. letter) end + if map.lhs == leader .. 'mv' .. letter then vim.api.nvim_buf_del_keymap(0, 'n', '<leader>mv' .. letter) end + if map.lhs == leader .. 'mx' .. letter then vim.api.nvim_buf_del_keymap(0, 'n', '<leader>mx' .. letter) end + end + end +end + +local configure = function() + -- TODO(tms) 19.11.21: + unset_marks() + local filename = vim.fn.expand('%:t:r') + local dir = vim.fn.expand('%:h') + local files = {} + local on_event = function(_, data, event) + if event == 'stderr' then print(data) end + if event == 'stdout' then + if #data > 1 then + for _, file in ipairs(data) do + local _, _, ext = file:match('(.-)([^\\/]-%.?([^%.\\/]*))$') + files[ext] = file + end + end + end + if event == 'exit' then + for ext, file in pairs(files) do + local letter = ft_letter[ext] + if letter then + set_mark(letter, file, true) + table.insert(letter_set, letter) + end + end + files = {} + end + end + + vim.fn.jobstart(string.format('fd -t f "^%s\\." "%s"', filename, dir), {on_stdout = on_event, on_exit = on_event}) +end + +au.addListener('user-file-pairs', {'BufEnter *'}, configure) diff --git a/plugin/terminal.lua b/plugin/terminal.lua @@ -1,9 +1,6 @@ -local ok, terminal = pcall(require, 'tms.p.terminal') -if not ok then - return -end +local terminal = require('tms.p.terminal') +local au = require('tms.c.autocmd') -local ui = require('tms.u.ui') local keymap = vim.keymap local nnoremap = keymap.nnoremap local tnoremap = keymap.tnoremap @@ -14,10 +11,8 @@ nnoremap {'<leader>tj', ':TerminalRun<space>'} nnoremap { '<leader>tk', function() - ok = terminal.rerun() - if not ok then - ui.input('[CMD]', function(cmd) terminal.run(cmd) end) - end + local ok = terminal.rerun() + if not ok then vim.api.nvim_feedkeys(':TerminalRun ', 'n', nil) end end, } nnoremap {'<leader>th', function() terminal.exit() end} @@ -26,7 +21,6 @@ tnoremap {'<leader>tl', function() terminal.interactive() end} tnoremap {'<leader>to', function() terminal.toggle() end} tnoremap {'<leader>th', function() terminal.exit() end} -local au = require('tms.c.autocmd') au.addListeners({ ['user-terminal'] = { [[BufEnter terminal let g:SexyScroller_ScrollTime=0|let g:SexyScroller_CursorTime=0]], diff --git a/plugin/ws.lua b/plugin/ws.lua @@ -0,0 +1,12 @@ +local au = require('tms.c.autocmd') +local ws = require('tms.ws') + +for name, setup in pairs(ws) do + if setup.path then au.addListener('user-project-path-' .. name, {'VimEnter ' .. setup.path}, setup.config) end + -- if setup.buffer then au.addListener('user-project-buffer-' .. name, {'BufEnter ' .. setup.buffer}, setup.config) end + -- if setup.filetypes then + -- for _, filetype in ipairs(setup.filetypes) do + -- au.addListener('user-project-ft-' .. name, {'FileType ' .. filetype}, setup.config) + -- end + -- end +end