From f04388f562ba3d06b532664b3d527da89d955147 Mon Sep 17 00:00:00 2001 From: Hung Date: Mon, 12 Jun 2023 23:58:03 -0700 Subject: [PATCH] many neovim changes and vimplugins nightly overlay --- native_configs/neovim/init.lua | 1714 ++++++++++++++----------- nix-conf/home-manager/base/neovim.nix | 3 +- nix-conf/home-manager/flake.lock | 74 +- nix-conf/home-manager/flake.nix | 2 + nix-conf/home-manager/overlays.nix | 5 + 5 files changed, 989 insertions(+), 809 deletions(-) diff --git a/native_configs/neovim/init.lua b/native_configs/neovim/init.lua index 27616b9..5fcd059 100644 --- a/native_configs/neovim/init.lua +++ b/native_configs/neovim/init.lua @@ -4,17 +4,14 @@ -- - df to format document -- - Harpoon marks: Navigate through main files within each project -- --- REQUIREMENTS: --- - zk @ https://github.com/mickael-menu/zk --- - prettierd @ npm install -g @fsouza/prettierd -- Auto-installs vim-plug vim.cmd([[ let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim' let plug_path = data_dir . '/autoload/plug.vim' if empty(glob(plug_path)) - execute '!curl -fLo '.plug_path.' --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' - execute 'so '.plug_path + execute '!curl -fLo '.plug_path.' --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' + execute 'so '.plug_path endif ]]) @@ -25,19 +22,19 @@ local Plug = vim.fn['plug#'] local installed_plugins = {} -- NOTE: nvim_list_runtime_paths will expand wildcard paths for us. for _, path in ipairs(vim.api.nvim_list_runtime_paths()) do - local last_folder_start = path:find("/[^/]*$") - if last_folder_start then - local plugin_name = path:sub(last_folder_start + 1) - installed_plugins[plugin_name] = true - end + local last_folder_start = path:find("/[^/]*$") + if last_folder_start then + local plugin_name = path:sub(last_folder_start + 1) + installed_plugins[plugin_name] = true + end end -- Do Plug if plugin not yet linked in `rtp`. This takes care of Nix-compatibility local function WPlug(plugin_path, ...) - local plugin_name = string.lower(plugin_path:match("/([^/]+)$")) - if not installed_plugins[plugin_name] then - Plug(plugin_path, ...) - end + local plugin_name = string.lower(plugin_path:match("/([^/]+)$")) + if not installed_plugins[plugin_name] then + Plug(plugin_path, ...) + end end vim.call('plug#begin') @@ -55,12 +52,12 @@ WPlug('nvim-telescope/telescope.nvim', { branch = '0.1.x' }) -- file browser -- ----- -- What to do: -- - Run `make` at anytime before Nix is done on this repository --- - Might mean that we fetch this repository, run make, and copy to destination folder +-- - Might mean that we fetch this repository, run make, and copy to destination folder -- - Make sure that if we run `make` at first WPlug run, that `make` is idempotent -- OR --- Make sure that WPlug does not run `make` and use the output it needs +-- Make sure that WPlug does not run `make` and use the output it needs WPlug('nvim-telescope/telescope-fzf-native.nvim', - { ['do'] = 'make >> /tmp/log 2>&1' }) + { ['do'] = 'make >> /tmp/log 2>&1' }) WPlug('nvim-telescope/telescope-file-browser.nvim') -- cmp: auto-complete/suggestions @@ -70,6 +67,7 @@ WPlug('hrsh7th/cmp-path') WPlug('hrsh7th/cmp-buffer') -- Recommends words within the buffer WPlug('hrsh7th/cmp-cmdline') WPlug('hrsh7th/nvim-cmp') +WPlug('hrsh7th/cmp-nvim-lsp-signature-help') WPlug('onsails/lspkind-nvim') WPlug('yioneko/nvim-yati', { tag = '*' }) -- copium: fix Python indent auto-correct from smart-indent WPlug('nathanalderson/yang.vim') @@ -91,19 +89,21 @@ WPlug('folke/trouble.nvim') -- File-grouped workspace diagnostics WPlug('tpope/vim-dispatch') -- Allows quick build/compile/test vim commands WPlug('clojure-vim/vim-jack-in') -- Clojure: ":Boot", ":Clj", ":Lein" WPlug('radenling/vim-dispatch-neovim') -- Add support for neovim's terminal emulator --- WPlug('Olical/conjure') -- REPL on the source for Clojure (and other LISPs) +-- WPlug('Olical/conjure') -- REPL on the source for Clojure (and other LISPs) WPlug('gennaro-tedesco/nvim-jqx') -- JSON formatter (use :Jqx*) WPlug('kylechui/nvim-surround') -- surrounds with tags/parenthesis WPlug('simrat39/rust-tools.nvim') -- config rust-analyzer and nvim integration -- UI & colorscheme -WPlug('simrat39/inlay-hints.nvim') -- type-hints with pseudo-virtual texts -WPlug('gruvbox-community/gruvbox') -- theme provider -WPlug('nvim-lualine/lualine.nvim') -- fancy status line -WPlug('lukas-reineke/indent-blankline.nvim') -- identation lines on blank lines -WPlug('kyazdani42/nvim-web-devicons') -- icons for folder and filetypes -WPlug('m-demare/hlargs.nvim') -- highlights arguments; great for func prog -WPlug('folke/todo-comments.nvim') -- Highlights TODO +WPlug('simrat39/inlay-hints.nvim') -- type-hints with pseudo-virtual texts +WPlug('gruvbox-community/gruvbox') -- theme provider +WPlug('nvim-lualine/lualine.nvim') -- fancy status line +WPlug('lukas-reineke/indent-blankline.nvim') -- identation lines on blank lines +WPlug('kyazdani42/nvim-web-devicons') -- icons for folder and filetypes +WPlug('m-demare/hlargs.nvim') -- highlights arguments; great for func prog +WPlug('folke/todo-comments.nvim') -- Highlights TODO +WPlug('NvChad/nvim-colorizer.lua') -- color highlighter with tailwind support +WPlug('roobert/tailwindcss-colorizer-cmp.nvim') -- color highlighter with tailwind support -- other utilities WPlug('nvim-treesitter/nvim-treesitter-context') -- Top one-liner context of func/class scope @@ -121,29 +121,37 @@ WPlug('~/local_repos/ts-ql') -- workspace code intelligence --------- vim.call('plug#end') +local PLUGIN_URI = 'gh:pegasust:dotfiles' +local PLUGIN_LEVEL = 'debug' +local log = require('plenary.log').new({ plugin = PLUGIN_URI, level = PLUGIN_LEVEL, use_console = false }) + vim.cmd([[ if len(filter(values(g:plugs), '!isdirectory(v:val.dir)')) - PlugInstall --sync | autocmd VimEnter * so $MYVIMRC + PlugInstall --sync | autocmd VimEnter * so $MYVIMRC endif ]]) -- special terminals, place them at 4..=7 for ergonomics +-- NOTE: this requires a flawless startup, otherwise, it's going to throw errors +-- since we're basically simulating keystrokes +-- TODO: The correct behavior is to register terminal keystroke with an assigned +-- buffer vim.api.nvim_create_autocmd({ "VimEnter" }, { - callback = function() - local function named_term(term_idx, term_name) - require('harpoon.term').gotoTerminal(term_idx) - vim.cmd([[:exe ":file ]] .. term_name .. [[" | :bfirst]]) - end - - -- term:ctl at 4 - named_term(4, "term:ctl") - -- term:dev at 5 - named_term(5, "term:dev") - -- term:repl at 7 - named_term(7, "term:repl") - -- term:repl at 6 - named_term(6, "term:repl2") + callback = function() + local function named_term(term_idx, term_name) + require('harpoon.term').gotoTerminal(term_idx) + vim.cmd([[:exe ":file ]] .. term_name .. [[" | :bfirst]]) end + + -- term:ctl at 4 + named_term(4, "term:ctl") + -- term:dev at 5 + named_term(5, "term:dev") + -- term:repl at 7 + named_term(7, "term:repl") + -- term:repl at 6 + named_term(6, "term:repl2") + end }) vim.g.gruvbox_contrast_dark = "soft"; @@ -168,22 +176,22 @@ vim.opt.colorcolumn = "80"; vim.opt.background = "dark"; vim.api.nvim_create_user_command('Dark', function(opts) - -- opts: {name, args: str, fargs: Splited, range, ...} - ---@type string - local contrast = (opts.args and string.len(opts.args) > 0) and opts.args or vim.g.gruvbox_contrast_dark; - vim.g.gruvbox_contrast_dark = contrast; - vim.opt.background = "dark"; - end, - { nargs = "?", }) + -- opts: {name, args: str, fargs: Splited, range, ...} + ---@type string + local contrast = (opts.args and string.len(opts.args) > 0) and opts.args or vim.g.gruvbox_contrast_dark; + vim.g.gruvbox_contrast_dark = contrast; + vim.opt.background = "dark"; + end, + { nargs = "?", }) vim.api.nvim_create_user_command('Light', function(opts) - -- opts: {name, args: str, fargs: Splited, range, ...} - ---@type string - local contrast = (opts.args and string.len(opts.args) > 0) and opts.args or vim.g.gruvbox_contrast_light; - vim.g.gruvbox_contrast_light = contrast; - vim.opt.background = "light"; - end, - { nargs = "?", }) + -- opts: {name, args: str, fargs: Splited, range, ...} + ---@type string + local contrast = (opts.args and string.len(opts.args) > 0) and opts.args or vim.g.gruvbox_contrast_light; + vim.g.gruvbox_contrast_light = contrast; + vim.opt.background = "light"; + end, + { nargs = "?", }) vim.opt.lazyredraw = true vim.opt.termguicolors = true @@ -193,7 +201,10 @@ vim.opt.swapfile = false vim.opt.backup = false vim.opt.undodir = vim.fn.stdpath('state') .. '/.vim/undodir' vim.opt.undofile = true -vim.opt.completeopt = 'menuone,noselect' +-- show menu even if there's 1 selection, and default to no selection +-- Note that we're not setitng `noinsert`, which allows us to "foresee" what the +-- completion would give us. This is faithful to VSCode +vim.opt.completeopt = { "menu", "menuone", "noselect", "noinsert" } -- vim.opt.clipboard = "unnamedplus" @@ -237,8 +248,8 @@ require('todo-comments').setup() -- plugin keymaps local function remap(mode, key_cmd, binded_fn, opts) - opts = opts or { remap = true } - return vim.keymap.set(mode, key_cmd, binded_fn, opts) + opts = opts or { remap = true } + return vim.keymap.set(mode, key_cmd, binded_fn, opts) end -- Comment.nvim @@ -249,76 +260,76 @@ vim.opt.listchars:append "space:⋅" vim.opt.listchars:append "eol:↴" require("indent_blankline").setup { - show_end_of_line = true, - space_char_blankline = " ", + show_end_of_line = true, + space_char_blankline = " ", } -- User command that transform into 2-spaces by translating to tabstop vim.api.nvim_create_user_command( - 'HalfSpaces', - function(opts) - vim.api.nvim_command("set ts=2 sts=2 noet") - vim.api.nvim_command("retab!") - vim.api.nvim_command("set ts=1 sts=1 et") - vim.api.nvim_command("retab") - vim.api.nvim_command("GuessIndent") - end, - { nargs = 0 } + 'HalfSpaces', + function(opts) + vim.api.nvim_command("set ts=2 sts=2 noet") + vim.api.nvim_command("retab!") + vim.api.nvim_command("set ts=1 sts=1 et") + vim.api.nvim_command("retab") + vim.api.nvim_command("GuessIndent") + end, + { nargs = 0 } ) vim.api.nvim_create_user_command( - 'DoubleSpaces', - function(opts) - -- cannot really do 1-space tab. The minimum is 2-space to begin - -- doubling - vim.api.nvim_command("set ts=2 sts=2 noet") - vim.api.nvim_command("retab!") - vim.api.nvim_command("set ts=4 sts=4 et") - vim.api.nvim_command("retab") - vim.api.nvim_command("GuessIndent") - end, - { nargs = 0 } + 'DoubleSpaces', + function(opts) + -- cannot really do 1-space tab. The minimum is 2-space to begin + -- doubling + vim.api.nvim_command("set ts=2 sts=2 noet") + vim.api.nvim_command("retab!") + vim.api.nvim_command("set ts=4 sts=4 et") + vim.api.nvim_command("retab") + vim.api.nvim_command("GuessIndent") + end, + { nargs = 0 } ) -- telescope local fb_actions = require "telescope".extensions.file_browser.actions require('telescope').setup { - defaults = { - mappings = { - i = { - [''] = false, - [''] = false, - }, - }, + defaults = { + mappings = { + i = { + [''] = false, + [''] = false, + }, }, - extensions = { - fzf = { - fuzzy = true, -- allow fuzzy matches - override_generic_sorter = true, - override_file_sorter = true, - case_mode = 'smart_case' - }, - file_browser = { - theme = require('telescope.themes').get_ivy().theme, - hiject_netrw = true, -- disables netrw and use file-browser instead - mappings = { - ["i"] = {}, -- disable any shortcut in insert mode for now - ["n"] = { - ["c"] = fb_actions.create, - ["r"] = fb_actions.rename, - ["m"] = fb_actions.move, - ["y"] = fb_actions.copy, - ["d"] = fb_actions.remove, - ["o"] = fb_actions.open, - ["g"] = fb_actions.goto_parent_dir, - ["e"] = fb_actions.goto_home_dir, - ["w"] = fb_actions.goto_cwd, - ["t"] = fb_actions.change_cwd, - ["f"] = fb_actions.toggle_browser, - ["h"] = fb_actions.toggle_hidden, - ["s"] = fb_actions.toggle_all, - } - } + }, + extensions = { + fzf = { + fuzzy = true, -- allow fuzzy matches + override_generic_sorter = true, + override_file_sorter = true, + case_mode = 'smart_case' + }, + file_browser = { + theme = require('telescope.themes').get_ivy().theme, + hiject_netrw = true, -- disables netrw and use file-browser instead + mappings = { + ["i"] = {}, -- disable any shortcut in insert mode for now + ["n"] = { + ["c"] = fb_actions.create, + ["r"] = fb_actions.rename, + ["m"] = fb_actions.move, + ["y"] = fb_actions.copy, + ["d"] = fb_actions.remove, + ["o"] = fb_actions.open, + ["g"] = fb_actions.goto_parent_dir, + ["e"] = fb_actions.goto_home_dir, + ["w"] = fb_actions.goto_cwd, + ["t"] = fb_actions.change_cwd, + ["f"] = fb_actions.toggle_browser, + ["h"] = fb_actions.toggle_hidden, + ["s"] = fb_actions.toggle_all, } + } } + } } -- Telescope key remap stuffs @@ -327,62 +338,62 @@ pcall(require('telescope').load_extension, 'file_browser') remap('n', '', 'Telescope', { desc = 'Open Telescope general search' }) remap('n', 'fm', function() - require("telescope").extensions.file_browser.file_browser({}) + require("telescope").extensions.file_browser.file_browser({}) end, { desc = '[F]ile [M]utation' }) remap('n', 'ff', function() - require('telescope.builtin').find_files({ - hidden = false, - no_ignore = false, - follow = false, - }) + require('telescope.builtin').find_files({ + hidden = false, + no_ignore = false, + follow = false, + }) end, { desc = '[F]ind [F]ile' }) remap('n', 'fa', function() - require('telescope.builtin').find_files({ - hidden = true, - no_ignore = true, - follow = true, - }) + require('telescope.builtin').find_files({ + hidden = true, + no_ignore = true, + follow = true, + }) end, { desc = '[F]ind [A]ll files' }) remap('n', 'fg', function() - require('telescope.builtin').live_grep() + require('telescope.builtin').live_grep() end, { desc = '[F]ind by [G]rep' }) remap('n', 'fug', function() - -- This relies on many factors: We use `rg` and that `-g '**/*'` effectively - -- drops ignore rules like the default `.gitignore` rule. - require('telescope.builtin').live_grep({ glob_pattern = '**/*' }) + -- This relies on many factors: We use `rg` and that `-g '**/*'` effectively + -- drops ignore rules like the default `.gitignore` rule. + require('telescope.builtin').live_grep({ glob_pattern = '**/*' }) end, { desc = '[F]ind by [u]nrestricted [G]rep' }) remap('n', 'fb', function() - require('telescope.builtin').buffers() + require('telescope.builtin').buffers() end, { desc = '[F]ind existing [B]uffers' }) remap('n', 'fh', function() - require('telescope.builtin').help_tags() + require('telescope.builtin').help_tags() end, { desc = '[F]ind [H]elp' }) remap('n', 'fd', function() - require('telescope.builtin').diagnostics() + require('telescope.builtin').diagnostics() end, { desc = '[F]ind [D]iagnostics' }) -- ZK remap stuffs remap('n', 'zf', function() - -- vim.cmd([[:ZkNotes]]) - require('zk').edit({}, { multi_select = false }) + -- vim.cmd([[:ZkNotes]]) + require('zk').edit({}, { multi_select = false }) end, { desc = '[Z]ettelkasten [F]iles' }) remap('n', 'zg', function() - vim.cmd(":ZkGrep") + vim.cmd(":ZkGrep") end, { desc = '[Z]ettelkasten [G]rep' }) -- tab management {{{ -- Jump to specific tab with [number] for i = 1, 9 do - vim.api.nvim_set_keymap('n', '' .. i, ':tabn ' .. i .. '', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', '' .. i, ':tabn ' .. i .. '', { noremap = true, silent = true }) end -- Show tab number in tab display @@ -390,81 +401,81 @@ vim.o.showtabline = 1 vim.o.tabline = '%!v:lua.my_tabline()' function _G.my_tabline() - local s = '' - for i = 1, vim.fn.tabpagenr('$') do - if i == vim.fn.tabpagenr() then - s = s .. '%' .. i .. 'T%#TabLineSel#' - else - s = s .. '%' .. i .. 'T%#TabLine#' - end - local tab = vim.fn.gettabinfo(i)[1] - local tabbuf = tab.variables.buffers - local bufname = "" - if tabbuf then - bufname = tabbuf[tab.curwin].name - end - -- Canonicalize tab/buf name - s = s .. ' ' .. i .. ' ' .. vim.fn.fnamemodify(bufname, ':t') - if i ~= vim.fn.tabpagenr('$') then - s = s .. '%#TabLine#|%#TabLine#' - end + local s = '' + for i = 1, vim.fn.tabpagenr('$') do + if i == vim.fn.tabpagenr() then + s = s .. '%' .. i .. 'T%#TabLineSel#' + else + s = s .. '%' .. i .. 'T%#TabLine#' end - return s .. '%T%#TabLineFill#%=' + local tab = vim.fn.gettabinfo(i)[1] + local tabbuf = tab.variables.buffers + local bufname = "" + if tabbuf then + bufname = tabbuf[tab.curwin].name + end + -- Canonicalize tab/buf name + s = s .. ' ' .. i .. ' ' .. vim.fn.fnamemodify(bufname, ':t') + if i ~= vim.fn.tabpagenr('$') then + s = s .. '%#TabLine#|%#TabLine#' + end + end + return s .. '%T%#TabLineFill#%=' end -- Close all tabs except the first one vim.api.nvim_set_keymap('n', 'x', ':tabdo if tabpagenr() > 1 | tabclose | endif', - { noremap = true, silent = true }) + { noremap = true, silent = true }) -- }}} -- treesitter require 'treesitter-context' require('nvim-treesitter.configs').setup { - yati = { - enable = true, - default_lazy = true, - default_fallback = "auto", - disable = { "nix" } + yati = { + enable = true, + default_lazy = true, + default_fallback = "auto", + disable = { "nix" } + }, + indent = { enable = false }, + highlight = { + enable = true, + enable_vim_regex_highlighting = true, + }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = '', + node_incremental = '', + node_decremental = '', + scope_incremental = '' }, - indent = { enable = false }, - highlight = { - enable = true, - enable_vim_regex_highlighting = true, - }, - incremental_selection = { - enable = true, - keymaps = { - init_selection = '', - node_incremental = '', - node_decremental = '', - pscope_incremental = '' - }, - }, - textobjects = { - select = { - enable = true, - lookahead = true, - keymaps = { - ['af'] = '@function.outer', - ['if'] = '@function.inner', - ['ac'] = '@class.outer', - ['ic'] = '@class.inner', - }, - }, - }, - playground = { - enable = true, - disable = {} - }, - -- automatically close and modify HTML and TSX tags - autotag = { - enable = true, + }, + textobjects = { + select = { + enable = true, + lookahead = true, + keymaps = { + ['af'] = '@function.outer', + ['if'] = '@function.inner', + ['ac'] = '@class.outer', + ['ic'] = '@class.inner', + }, }, + }, + playground = { + enable = true, + disable = {} + }, + -- automatically close and modify HTML and TSX tags + autotag = { + enable = true, + }, } require('nvim-autopairs').setup { - check_ts = true, + check_ts = true, } local parser_config = require('nvim-treesitter.parsers').get_parser_configs() @@ -473,29 +484,29 @@ parser_config.astro.filetype_to_parsername = { "javascript", "typescript.tsx", " require('guess-indent').setup { - auto_cmd = true, - filetype_exclude = { -- A list of filetypes for which the auto command gets disabled - "netrw", - "tutor", - }, + auto_cmd = true, + filetype_exclude = { -- A list of filetypes for which the auto command gets disabled + "netrw", + "tutor", + }, - -- buftype_exclude = { -- A list of buffer types for which the auto command gets disabled - -- "help", - -- "nofile", - -- "terminal", - -- -- "prompt", - -- }, + -- buftype_exclude = { -- A list of buffer types for which the auto command gets disabled + -- "help", + -- "nofile", + -- "terminal", + -- -- "prompt", + -- }, } -- harpoon: O(1) buffer/terminal switching remap('n', 'm', function() require('harpoon.mark').add_file() end, { desc = "[H]arpoon [M]ark" }) local function harpoon_nav(key, nav_file_index, lead_keybind) - lead_keybind = lead_keybind or 'h' - assert(type(key) == "string", "expect key to be string(keybind)") - assert(type(nav_file_index) == "number" and nav_file_index >= 1, "expect 1-indexed number for file index") - return remap('n', lead_keybind .. key, - function() require('harpoon.ui').nav_file(nav_file_index) end, - { desc = "[H]arpoon navigate " .. tostring(nav_file_index) }) + lead_keybind = lead_keybind or 'h' + assert(type(key) == "string", "expect key to be string(keybind)") + assert(type(nav_file_index) == "number" and nav_file_index >= 1, "expect 1-indexed number for file index") + return remap('n', lead_keybind .. key, + function() require('harpoon.ui').nav_file(nav_file_index) end, + { desc = "[H]arpoon navigate " .. tostring(nav_file_index) }) end -- remap letters to index. Inspired by alternating number of Dvorak programmer @@ -506,12 +517,12 @@ harpoon_nav('d', 3) harpoon_nav('k', 4) remap('n', 'hh', function() require('harpoon.ui').toggle_quick_menu() end) for i = 1, 10 do - -- harpoon: navigate files by numbers - harpoon_nav(tostring(i % 10), i) - -- harpoon: navigate terms by numbers - remap('n', 't' .. tostring(i % 10), function() - require('harpoon.term').gotoTerminal(i) - end) + -- harpoon: navigate files by numbers + harpoon_nav(tostring(i % 10), i) + -- harpoon: navigate terms by numbers + remap('n', 't' .. tostring(i % 10), function() + require('harpoon.term').gotoTerminal(i) + end) end -- neogit: easy-to-see git status. Provides only productivity on staging/unstage @@ -521,518 +532,620 @@ remap('n', 'gs', function() require('neogit').open({}) end, { desc = "[G -- LSP settings -- This function gets run when an LSP connects to a particular buffer. require("inlay-hints").setup { - only_current_line = false, - eol = { - right_align = false, - } -} -local on_attach = function(client, bufnr) - local nmap = function(keys, func, desc) - if desc then - desc = 'LSP: ' .. desc - end + -- renderer to use + -- possible options are dynamic, eol, virtline and custom + -- renderer = "inlay-hints/render/dynamic", + renderer = "inlay-hints/render/dynamic", - vim.keymap.set('n', keys, func, { noremap = true, buffer = bufnr, desc = desc }) + hints = { + parameter = { + show = true, + highlight = "whitespace", + }, + type = { + show = true, + highlight = "Whitespace", + }, + }, + + -- Only show inlay hints for the current line + only_current_line = false, + + eol = { + -- whether to align to the extreme right or not + right_align = false, + + -- padding from the right if right_align is true + right_align_padding = 7, + + parameter = { + separator = ", ", + format = function(hints) + return string.format(" <- (%s)", hints) + end, + }, + + type = { + separator = ", ", + format = function(hints) + return string.format(" => %s", hints) + end, + }, + }, +} + + +local on_attach = function(client, bufnr) + local nmap = function(keys, func, desc) + if desc then + desc = 'LSP: ' .. desc end - nmap('rn', vim.lsp.buf.rename, '[R]e[n]ame') - nmap('ca', vim.lsp.buf.code_action, '[C]ode [A]ction') - -- NOTE: I have no clue what this does again - vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') - nmap('df', function() vim.lsp.buf.format({ async = true }) end, '[D]ocument [F]ormat') + vim.keymap.set('n', keys, func, { noremap = true, buffer = bufnr, desc = desc }) + end - -- symbols and gotos - nmap('gd', vim.lsp.buf.definition, '[G]oto [D]efinition') - nmap('gi', vim.lsp.buf.implementation, '[G]oto [I]mplementation') - nmap('gr', require('telescope.builtin').lsp_references) - nmap('ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') - nmap('ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') + nmap('rn', vim.lsp.buf.rename, '[R]e[n]ame') + nmap('ca', vim.lsp.buf.code_action, '[C]ode [A]ction') + -- NOTE: I have no clue what this does again + vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') + nmap('df', function() vim.lsp.buf.format({ async = true }) end, '[D]ocument [F]ormat') - -- documentations & helps - -- NOTE: When you press K, it shows in-line Documentation - -- This is to stay faithful with vim's default keybind for help. - -- See `:help K` for even more info on Vim's original keybindings for help - nmap('K', vim.lsp.buf.hover, 'Hover Documentation') - nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') + -- symbols and gotos + nmap('gd', vim.lsp.buf.definition, '[G]oto [D]efinition') + nmap('gi', vim.lsp.buf.implementation, '[G]oto [I]mplementation') + nmap('gr', require('telescope.builtin').lsp_references) + nmap('ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') + nmap('ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') - -- Less likely LSP functionality to be used - nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - nmap('gtd', vim.lsp.buf.type_definition, '[G]oto [T]ype [D]efinition') - nmap('D', vim.lsp.buf.type_definition, 'Type [D]efinition') - -- - -- Very rarely used - nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') - nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') - nmap('wl', function() - print(vim.inspect(vim.lsp.buf.list_workspace_folders())) - end, '[W]orkspace [L]ist Folders') + -- documentations & helps + -- NOTE: When you press K, it shows in-line Documentation + -- This is to stay faithful with vim's default keybind for help. + -- See `:help K` for even more info on Vim's original keybindings for help + nmap('K', vim.lsp.buf.hover, 'Hover Documentation') + -- nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') - -- enable inlay hints if available - require('inlay-hints').on_attach(client, bufnr) + -- Less likely LSP functionality to be used + nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') + nmap('gtd', vim.lsp.buf.type_definition, '[G]oto [T]ype [D]efinition') + nmap('D', vim.lsp.buf.type_definition, 'Type [D]efinition') + -- + -- Very rarely used + nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') + nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') + nmap('wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, '[W]orkspace [L]ist Folders') + + -- enable inlay hints if available + require('inlay-hints').on_attach(client, bufnr) end -- nvim-cmp + local cmp = require 'cmp' local luasnip = require 'luasnip' local lspkind = require('lspkind') -local source_mapping = { - buffer = '[Buffer]', - nvim_lsp = '[LSP]', - nvim_lua = '[Lua]', - -- cmp_tabnine = '[T9]', - path = '[Path]', -} + +lspkind.init { + symbol_map = { + Copilot = "", + }, +} cmp.event:on( - "confirm_done", - require('nvim-autopairs.completion.cmp').on_confirm_done() + "confirm_done", + require('nvim-autopairs.completion.cmp').on_confirm_done() ) -cmp.setup { - snippet = { - expand = function(args) - luasnip.lsp_expand(args.body) - end, +---@type cmp.ConfigSchema +local cmp_config = { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert { + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.complete(), + [''] = cmp.mapping.confirm { + behavior = cmp.ConfirmBehavior.Replace, + select = true, }, - mapping = cmp.mapping.preset.insert { - [''] = cmp.mapping.scroll_docs(-4), - [''] = cmp.mapping.scroll_docs(4), - [''] = cmp.mapping.complete(), - [''] = cmp.mapping.confirm { - behavior = cmp.ConfirmBehavior.Replace, - select = true, - }, - [''] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_next_item() - elseif luasnip.expand_or_jumpable() then - luasnip.expand_or_jump() - else - fallback() + -- NOTE: rebind tab and shift-tab since it may break whenever we + -- need to peform manual indentation + [''] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item({ behavior = cmp.SelectBehavior.Select }) + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + else + fallback() + end + end, { 'i', 's' }), + [''] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item({ behavior = cmp.SelectBehavior.Select }) + elseif luasnip.jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { 'i', 's' }), + + }, + performance = { + debounce = 60, + throttle = 30, + }, + formatting = { + fields = { 'abbr', 'kind', 'menu' }, + -- vim_items: complete-items (`:h complete-items`) + -- word, abbr, menu, info, kind, icase, equal, dup, empty, user_data + format = function(entry, vim_item) + local kind_fn = lspkind.cmp_format { + with_text = true, + menu = { + buffer = "[buf]", + nvim_lsp = "[LSP]", + nvim_lua = "[api]", + path = "[path]", + luasnip = "[snip]", + gh_issues = "[issues]", + tn = "[TabNine]", + eruby = "[erb]", + nvim_lsp_signature_help = "[sig]", + } + } + vim_item = kind_fn(entry, vim_item) + return require('tailwindcss-colorizer-cmp').formatter(entry, vim_item) + end, + }, + sources = cmp.config.sources( --[[@as cmp.SourceConfig[]] { + { name = 'nvim_lsp', }, + { name = 'nvim_lsp_signature_help' }, + -- NOTE: Path is triggered by `.` and `/`, so when it comes up, it's + -- usually desirable. + { name = 'path' }, + { name = 'luasnip' }, + { + name = 'buffer', + option = { + -- default is only in the current buffer. This grabs recommendations + -- from all visible buffers + get_bufnrs = function() + -- Must always have current buffer + local bufs = { [0] = true } + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + local byte_size = vim.api.nvim_buf_get_offset(buf, vim.api.nvim_buf_line_count(buf)) + if byte_size <= 1024 * 1024 then -- 1 MiB max + bufs[buf] = true end - end, { 'i', 's' }), - [''] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_prev_item() - elseif luasnip.jumpable(-1) then - luasnip.jump(-1) - else - fallback() - end - end, { 'i', 's' }), - }, - formatting = { - format = function(entry, vim_item) - vim_item.kind = lspkind.symbolic(vim_item.kind, { mode = 'symbol' }) - vim_item.menu = source_mapping[entry.source_name] - -- if entry.source.name == "cmp_tabnine" then - -- local detail = (entry.completion_item.data or {}).detail - -- vim_item.kind = "" - -- if detail and detail:find('.*%%.*') then - -- vim_item.kind = vim_item.kind .. ' ' .. detail - -- end - -- - -- if (entry.completion_item.data or {}).multiline then - -- vim_item.kind = vim_item.kind .. ' ' .. '[ML]' - -- end - -- end - local maxwidth = 80 - vim_item.abbr = string.sub(vim_item.abbr, 1, maxwidth) - return vim_item + end + return vim.tbl_keys(bufs) end, + }, }, - sources = cmp.config.sources { - { name = 'nvim_lsp' }, - { name = 'luasnip' }, - { - name = 'buffer', - option = { - -- default is only in the current buffer. This grabs recommendations - -- from all visible buffers - get_bufnrs = function() - local bufs = {} - for _, win in ipairs(vim.api.nvim_list_wins()) do - local buf = vim.api.nvim_win_get_buf(win) - local byte_size = vim.api.nvim_buf_get_offset(buf, vim.api.nvim_buf_line_count(buf)) - if byte_size <= 1024 * 1024 then -- 1 MiB max - bufs[buf] = true - end - end - return vim.tbl_keys(bufs) - end, - } - }, - { name = 'path' }, - -- { name = "conjure" }, - -- { name = 'cmp_tabnine' }, - }, - sorting = { - comparators = { - -- Optimize searches by recommending things that are closer to the current cursor - function(...) require('cmp-buffer'):compare_locality(...) end, - } + -- NOTE: I don't like cmdline that much. Most of the time, it recommends more harm than good + -- { name = 'cmp_tabnine' }, + -- { name = "conjure" }, + }), + experimental = { ghost_text = { hl_group = "Comment" }, }, + sorting = { + comparators = { + ---@param lhs_entry cmp.Entry + ---@param rhs_entry cmp.Entry + function(lhs_entry, rhs_entry) + return nil + end, + cmp.config.compare.exact, + cmp.config.compare.recently_used, + cmp.config.compare.offset, + cmp.config.compare.score, + cmp.config.compare.kind, + cmp.config.compare.locality, + cmp.config.compare.sort_text, + cmp.config.compare.scope, }, + }, } + + +cmp.setup(vim.tbl_deep_extend("force", require('cmp.config.default')(), cmp_config)) + +-- `/` cmdline search. +cmp.setup.cmdline('/', { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = 'buffer' } + } +}) +-- `:` cmdline vim command. +cmp.setup.cmdline(':', { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = 'path' } + }, { + { + name = 'cmdline', + option = { + ignore_cmds = { 'Man', '!' } + } + } + }) +}) + -- nvim-cmp supports additional completion capabilities local capabilities = require('cmp_nvim_lsp').default_capabilities() -- local tabnine = require('cmp_tabnine.config') -- tabnine.setup({ --- max_lines = 1000, --- max_num_results = 20, --- sort = true, --- run_on_every_keystroke = true, --- snippet_placeholder = '..', --- ignored_file_types = {}, --- show_prediction_strength = true, +-- max_lines = 1000, +-- max_num_results = 20, +-- sort = true, +-- run_on_every_keystroke = true, +-- snippet_placeholder = '..', +-- ignored_file_types = {}, +-- show_prediction_strength = true, -- }) -- default language servers local servers = { - 'clangd', 'rust_analyzer', 'pyright', 'tsserver', 'lua_ls', 'cmake', 'tailwindcss', 'prismals', - 'rnix', 'eslint', 'terraformls', 'tflint', 'svelte', 'astro', 'clojure_lsp', "bashls", 'yamlls', "ansiblels", - "jsonls", "denols", "gopls", "nickel_ls", 'pylsp', + 'clangd', 'rust_analyzer', 'pyright', 'tsserver', 'lua_ls', 'cmake', 'tailwindcss', 'prismals', + 'rnix', 'eslint', 'terraformls', 'tflint', 'svelte', 'astro', 'clojure_lsp', "bashls", 'yamlls', "ansiblels", + "jsonls", "denols", "gopls", "nickel_ls", 'pylsp', } require("mason").setup({ - ui = { - icons = { - package_installed = "✓", - package_pending = "➜", - package_uninstalled = "✗" - }, - check_outdated_packages_on_open = true, + ui = { + icons = { + package_installed = "✓", + package_pending = "➜", + package_uninstalled = "✗" }, - -- NOTE: The default settings is "prepend" https://github.com/williamboman/mason.nvim#default-configuration - -- Which means Mason's installed path is prioritized against our local install - -- see: https://git.pegasust.com/pegasust/aoc/commit/b45dc32c74d84c9f787ebce7a174c9aa1d411fc2 - -- This introduces some pitfalls, so we'll take the approach of trusting user's local installation - PATH = "append", + check_outdated_packages_on_open = true, + }, + -- NOTE: The default settings is "prepend" https://github.com/williamboman/mason.nvim#default-configuration + -- Which means Mason's installed path is prioritized against our local install + -- see: https://git.pegasust.com/pegasust/aoc/commit/b45dc32c74d84c9f787ebce7a174c9aa1d411fc2 + -- This introduces some pitfalls, so we'll take the approach of trusting user's local installation + PATH = "append", }) require('mason-lspconfig').setup({ - -- ensure_installed = servers, - automatic_installation = false + -- ensure_installed = servers, + ensure_installed = { "pylsp", "pyright", "tailwindcss", "svelte", "astro", "lua_ls" }, + automatic_installation = false, }) local inlay_hint_tsjs = { - includeInlayEnumMemberValueHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayFunctionParameterTypeHints = true, - includeInlayParameterNameHints = 'all', -- "none" | "literals" | "all" - inlcudeInlayParameterNameHintsWhenArgumentMatchesName = false, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayVariableTypeHints = true, + includeInlayEnumMemberValueHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayFunctionParameterTypeHints = true, + includeInlayParameterNameHints = 'all', -- "none" | "literals" | "all" + inlcudeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayVariableTypeHints = true, }; require('mason-lspconfig').setup_handlers({ - -- default handler - function(server_name) - require('lspconfig')[server_name].setup { - on_attach = on_attach, - capabilities = capabilities, - } - end, - ["lua_ls"] = function() - require('lspconfig').lua_ls.setup { - on_attach = on_attach, - capabilities = capabilities, - settings = { - Lua = { - runtime = { - version = "LuaJIT", - path = vim.split(package.path, ";"), - }, - diagnostics = { - globals = { "vim" } - }, - workspace = { - library = vim.api.nvim_get_runtime_file('', true) - }, - telemetry = { enable = false }, - hint = { - enable = true, - }, - format = { - enable = true, - defaultConfig = { - indent_style = "space", - indent_size = 4, - } - } - } + -- default handler + function(server_name) + require('lspconfig')[server_name].setup { + on_attach = on_attach, + capabilities = capabilities, + } + end, + ["lua_ls"] = function() + require('lspconfig').lua_ls.setup { + on_attach = on_attach, + capabilities = capabilities, + settings = { + Lua = { + runtime = { + version = "LuaJIT", + path = vim.split(package.path, ";"), + }, + diagnostics = { + globals = { "vim" } + }, + workspace = { + library = vim.api.nvim_get_runtime_file('', true), + -- Don't prompt me to select + checkThirdParty = false, + }, + telemetry = { enable = false }, + hint = { + enable = true, + }, + format = { + enable = true, + defaultConfig = { + indent_style = "space", + indent_size = 4, } + } } - end, - ["pyright"] = function() - require('lspconfig').pyright.setup { - on_attach = on_attach, - capabilities = capabilities, - settings = { - pyright = { - disableLanguageServices = false, - disableOrganizeImports = false, - }, - python = { - analysis = { - autoImportCompletions = true, - autoSearchPaths = true, - diagnosticMode = "openFilesOnly", - -- diagnosticSeverityOverrides = - extraPaths = {}, - logLevel = "Information", - stubPath = "typings", - typeCheckingMode = "basic", - typeshedPaths = {}, - useLibraryCodeForTypes = false, - pythonPath = "python", - venvPath = "", - }, - linting = { - mypyEnabled = true, - } - }, - }, + } + } + end, + ["pyright"] = function() + require('lspconfig').pyright.setup { + on_attach = on_attach, + capabilities = capabilities, + settings = { + pyright = { + disableLanguageServices = false, + disableOrganizeImports = false, + }, + python = { + analysis = { + autoImportCompletions = true, + autoSearchPaths = true, + diagnosticMode = "openFilesOnly", + -- diagnosticSeverityOverrides = + extraPaths = {}, + logLevel = "Information", + stubPath = "typings", + typeCheckingMode = "basic", + typeshedPaths = {}, + useLibraryCodeForTypes = false, + pythonPath = "python", + venvPath = "", + }, + linting = { + mypyEnabled = true, + } + }, + }, + } + end, + ["tsserver"] = function() + require('lspconfig').tsserver.setup { + on_attach = on_attach, + capabilities = capabilities, + -- TODO: Have to figure out an alternative config for monorepo to prevent + -- Deno from injecting TS projects. + -- Monorepo support: spawn one instance of lsp within the git + -- repos. + -- root_dir = require('lspconfig.util').root_pattern('.git'), + root_dir = require('lspconfig.util').root_pattern('package.json'), + settings = { + javascript = inlay_hint_tsjs, + typescript = inlay_hint_tsjs, + } + } + end, + ["denols"] = function() + require('lspconfig').denols.setup { + on_attach = on_attach, + capabilities = capabilities, + root_dir = require('lspconfig.util').root_pattern("deno.json", "deno.jsonc"), + } + end, + ["yamlls"] = function() + require('lspconfig').yamlls.setup { + on_attach = on_attach, + capabilities = capabilities, + settings = { + yaml = { + keyOrdering = false, } - end, - ["tsserver"] = function() - require('lspconfig').tsserver.setup { - on_attach = on_attach, - capabilities = capabilities, - -- TODO: Have to figure out an alternative config for monorepo to prevent - -- Deno from injecting TS projects. - -- Monorepo support: spawn one instance of lsp within the git - -- repos. - -- root_dir = require('lspconfig.util').root_pattern('.git'), - root_dir = require('lspconfig.util').root_pattern('package.json'), - settings = { - javascript = inlay_hint_tsjs, - typescript = inlay_hint_tsjs, - } - } - end, - ["denols"] = function() - require('lspconfig').denols.setup { - on_attach = on_attach, - capabilities = capabilities, - root_dir = require('lspconfig.util').root_pattern("deno.json", "deno.jsonc"), - } - end, - ["yamlls"] = function() - require('lspconfig').yamlls.setup { - on_attach = on_attach, - capabilities = capabilities, - settings = { - yaml = { - keyOrdering = false, - } - }, - } - end, + }, + } + end, }) require("rust-tools").setup { - tools = { - -- rust-tools options + tools = { + -- rust-tools options - -- how to execute terminal commands - -- options right now: termopen / quickfix - executor = require("rust-tools/executors").termopen, - -- callback to execute once rust-analyzer is done initializing the workspace - -- The callback receives one parameter indicating the `health` of the server: "ok" | "warning" | "error" - on_initialized = function() - require('inlay-hints').set_all() - end, - -- automatically call RustReloadWorkspace when writing to a Cargo.toml file. - reload_workspace_from_cargo_toml = true, - -- These apply to the default RustSetInlayHints command - inlay_hints = { - -- automatically set inlay hints (type hints) - -- default: true - auto = false, - -- Only show inlay hints for the current line - only_current_line = true, - -- whether to show parameter hints with the inlay hints or not - -- default: true - show_parameter_hints = true, - -- prefix for parameter hints - -- default: "<-" - parameter_hints_prefix = "<- ", - -- prefix for all the other hints (type, chaining) - -- default: "=>" - other_hints_prefix = "=> ", - -- whether to align to the length of the longest line in the file - max_len_align = false, - -- padding from the left if max_len_align is true - max_len_align_padding = 1, - -- whether to align to the extreme right or not - right_align = false, - -- padding from the right if right_align is true - right_align_padding = 7, - -- The color of the hints use `:highlight` for a pick-and-choose menu - highlight = "NonText", - }, - -- options same as lsp hover / vim.lsp.util.open_floating_preview() - hover_actions = { - -- the border that is used for the hover window - -- see vim.api.nvim_open_win() - border = { - { "╭", "FloatBorder" }, - { "─", "FloatBorder" }, - { "╮", "FloatBorder" }, - { "│", "FloatBorder" }, - { "╯", "FloatBorder" }, - { "─", "FloatBorder" }, - { "╰", "FloatBorder" }, - { "│", "FloatBorder" }, - }, - -- whether the hover action window gets automatically focused - -- default: false - auto_focus = false, - }, - -- settings for showing the crate graph based on graphviz and the dot - -- command - crate_graph = { - -- Backend used for displaying the graph - -- see: https://graphviz.org/docs/outputs/ - -- default: x11 - backend = "x11", - -- where to store the output, nil for no output stored (relative - -- path from pwd) - -- default: nil - output = nil, - -- true for all crates.io and external crates, false only the local - -- crates - -- default: true - full = true, - -- List of backends found on: https://graphviz.org/docs/outputs/ - -- Is used for input validation and autocompletion - -- Last updated: 2021-08-26 - enabled_graphviz_backends = { - "bmp", - "cgimage", - "canon", - "dot", - "gv", - "xdot", - "xdot1.2", - "xdot1.4", - "eps", - "exr", - "fig", - "gd", - "gd2", - "gif", - "gtk", - "ico", - "cmap", - "ismap", - "imap", - "cmapx", - "imap_np", - "cmapx_np", - "jpg", - "jpeg", - "jpe", - "jp2", - "json", - "json0", - "dot_json", - "xdot_json", - "pdf", - "pic", - "pct", - "pict", - "plain", - "plain-ext", - "png", - "pov", - "ps", - "ps2", - "psd", - "sgi", - "svg", - "svgz", - "tga", - "tiff", - "tif", - "tk", - "vml", - "vmlz", - "wbmp", - "webp", - "xlib", - "x11", - }, - }, + -- how to execute terminal commands + -- options right now: termopen / quickfix + executor = require("rust-tools/executors").termopen, + -- callback to execute once rust-analyzer is done initializing the workspace + -- The callback receives one parameter indicating the `health` of the server: "ok" | "warning" | "error" + on_initialized = function() + require('inlay-hints').set_all() + end, + -- automatically call RustReloadWorkspace when writing to a Cargo.toml file. + reload_workspace_from_cargo_toml = true, + -- These apply to the default RustSetInlayHints command + inlay_hints = { + -- automatically set inlay hints (type hints) + -- default: true + auto = false, + -- Only show inlay hints for the current line + only_current_line = true, + -- whether to show parameter hints with the inlay hints or not + -- default: true + show_parameter_hints = true, + -- prefix for parameter hints + -- default: "<-" + parameter_hints_prefix = "<- ", + -- prefix for all the other hints (type, chaining) + -- default: "=>" + other_hints_prefix = "=> ", + -- whether to align to the length of the longest line in the file + max_len_align = false, + -- padding from the left if max_len_align is true + max_len_align_padding = 1, + -- whether to align to the extreme right or not + right_align = false, + -- padding from the right if right_align is true + right_align_padding = 7, + -- The color of the hints use `:highlight` for a pick-and-choose menu + highlight = "NonText", }, - - -- all the opts to send to nvim-lspconfig - -- these override the defaults set by rust-tools.nvim - -- see https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#rust_analyzer - server = { - -- standalone file support - -- setting it to false may improve startup time - standalone = true, - on_attach = function(client, bufnr) - local nmap = function(keys, func, desc) - if desc then - desc = 'LSP: ' .. desc - end - - vim.keymap.set('n', keys, func, { noremap = true, buffer = bufnr, desc = desc }) - end - on_attach(client, bufnr) - nmap('K', require 'rust-tools'.hover_actions.hover_actions, 'Hover Documentation') - end, - capabilities = capabilities, - cmd = { "rust-analyzer" }, - settings = { - ["rust-analyzer"] = { - -- enable clippy on save - checkOnSave = { - command = "clippy", - extraArgs = { "--all", "--", "-W", "clippy::all" }, - }, - rustfmt = { - extraArgs = { "+nightly" }, - }, - cargo = { - loadOutDirsFromCheck = true, - }, - procMacro = { - enable = true, - }, - }, - }, - }, -- rust-analyzer options - - -- debugging stuff - dap = { - adapter = { - type = "executable", - command = "lldb-vscode", - name = "rt_lldb", - }, + -- options same as lsp hover / vim.lsp.util.open_floating_preview() + hover_actions = { + -- the border that is used for the hover window + -- see vim.api.nvim_open_win() + border = { + { "╭", "FloatBorder" }, + { "─", "FloatBorder" }, + { "╮", "FloatBorder" }, + { "│", "FloatBorder" }, + { "╯", "FloatBorder" }, + { "─", "FloatBorder" }, + { "╰", "FloatBorder" }, + { "│", "FloatBorder" }, + }, + -- whether the hover action window gets automatically focused + -- default: false + auto_focus = false, }, + -- settings for showing the crate graph based on graphviz and the dot + -- command + crate_graph = { + -- Backend used for displaying the graph + -- see: https://graphviz.org/docs/outputs/ + -- default: x11 + backend = "x11", + -- where to store the output, nil for no output stored (relative + -- path from pwd) + -- default: nil + output = nil, + -- true for all crates.io and external crates, false only the local + -- crates + -- default: true + full = true, + -- List of backends found on: https://graphviz.org/docs/outputs/ + -- Is used for input validation and autocompletion + -- Last updated: 2021-08-26 + enabled_graphviz_backends = { + "bmp", + "cgimage", + "canon", + "dot", + "gv", + "xdot", + "xdot1.2", + "xdot1.4", + "eps", + "exr", + "fig", + "gd", + "gd2", + "gif", + "gtk", + "ico", + "cmap", + "ismap", + "imap", + "cmapx", + "imap_np", + "cmapx_np", + "jpg", + "jpeg", + "jpe", + "jp2", + "json", + "json0", + "dot_json", + "xdot_json", + "pdf", + "pic", + "pct", + "pict", + "plain", + "plain-ext", + "png", + "pov", + "ps", + "ps2", + "psd", + "sgi", + "svg", + "svgz", + "tga", + "tiff", + "tif", + "tk", + "vml", + "vmlz", + "wbmp", + "webp", + "xlib", + "x11", + }, + }, + }, + + -- all the opts to send to nvim-lspconfig + -- these override the defaults set by rust-tools.nvim + -- see https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#rust_analyzer + server = { + -- standalone file support + -- setting it to false may improve startup time + standalone = true, + on_attach = function(client, bufnr) + local nmap = function(keys, func, desc) + if desc then + desc = 'LSP: ' .. desc + end + + vim.keymap.set('n', keys, func, { noremap = true, buffer = bufnr, desc = desc }) + end + on_attach(client, bufnr) + nmap('K', require 'rust-tools'.hover_actions.hover_actions, 'Hover Documentation') + end, + capabilities = capabilities, + cmd = { "rust-analyzer" }, + settings = { + ["rust-analyzer"] = { + -- enable clippy on save + checkOnSave = { + command = "clippy", + extraArgs = { "--all", "--", "-W", "clippy::all" }, + }, + rustfmt = { + extraArgs = { "+nightly" }, + }, + cargo = { + loadOutDirsFromCheck = true, + }, + procMacro = { + enable = true, + }, + }, + }, + }, -- rust-analyzer options + + -- debugging stuff + dap = { + adapter = { + type = "executable", + command = "lldb-vscode", + name = "rt_lldb", + }, + }, } require('zk').setup({ - picker = "telescope", - lsp = { - config = { - cmd = { "zk", "lsp" }, - name = "zk", - on_attach = on_attach, - }, - auto_attach = { - enable = true, - filetypes = { "markdown" } - }, + picker = "telescope", + lsp = { + config = { + cmd = { "zk", "lsp" }, + name = "zk", + on_attach = on_attach, }, + auto_attach = { + enable = true, + filetypes = { "markdown" } + }, + }, }) -- Custom ZkOrphans that determines unlinked notes -- `:ZkOrphans {tags = {"work"}}` require('zk.commands').add("ZkOrphans", function(options) - options = vim.tbl_extend("force", { orphan = true }, options or {}) - -- zk.edit opens notes picker - require('zk').edit(options, { title = "Zk Orphans (unlinked notes)" }) + options = vim.tbl_extend("force", { orphan = true }, options or {}) + -- zk.edit opens notes picker + require('zk').edit(options, { title = "Zk Orphans (unlinked notes)" }) end) -- -- ZkGrep: opens file picker @@ -1041,116 +1154,177 @@ end) -- Params: -- match_ctor: string | {match= :string,...} | "" | nil require('zk.commands').add("ZkGrep", function(match_ctor) - -- handle polymorphic `match_ctor` - local grep_str = match_ctor - local match - if match_ctor == nil or match_ctor == '' then - vim.fn.inputsave() - grep_str = vim.fn.input('Grep string: >') - vim.fn.inputrestore() - match = { match = grep_str } - elseif type(match_ctor) == 'string' then - match = { match = grep_str } - end - require('zk').edit(match, { title = "Grep: '" .. grep_str .. "'", mutli_select = false }) + -- handle polymorphic `match_ctor` + local grep_str = match_ctor + local match + if match_ctor == nil or match_ctor == '' then + vim.fn.inputsave() + grep_str = vim.fn.input('Grep string: >') + vim.fn.inputrestore() + match = { match = grep_str } + elseif type(match_ctor) == 'string' then + match = { match = grep_str } + end + require('zk').edit(match, { title = "Grep: '" .. grep_str .. "'", mutli_select = false }) end) -- Gitsigns require('gitsigns').setup { - signs = { - add = { text = '+' }, - change = { text = '~' }, - delete = { text = '_' }, - topdelete = { text = '‾' }, - changedelete = { text = '~' }, - } + signs = { + add = { text = '+' }, + change = { text = '~' }, + delete = { text = '_' }, + topdelete = { text = '‾' }, + changedelete = { text = '~' }, + } } require('lualine').setup { - options = { - icons_enabled = true, - }, - sections = { - lualine_a = { 'mode' }, - lualine_b = { 'branch', 'diff', 'diagnostics' }, - lualine_c = { - { - 'filename', - file_status = true, - newfile_status = false, - path = 1, - symbols = { - modified = '[+]', - readonly = '[-]', - unnamed = '[Unnamed]', - newfile = '[New]', - }, - }, + options = { + icons_enabled = true, + }, + sections = { + lualine_a = { 'mode' }, + lualine_b = { 'branch', 'diff', 'diagnostics' }, + lualine_c = { + { + 'filename', + file_status = true, + newfile_status = false, + path = 1, + symbols = { + modified = '[+]', + readonly = '[-]', + unnamed = '[Unnamed]', + newfile = '[New]', }, - lualine_x = { 'encoding', 'fileformat', 'filetype', }, - lualine_y = { 'progress' }, - lualine_z = { 'location' }, + }, }, - inactive_sections = { - lualine_a = {}, - lualine_b = {}, - lualine_c = { { 'filename', path = 1, file_status = true, }, }, - lualine_x = { 'location' }, - lualine_y = {}, - lualine_z = {}, - } + lualine_x = { 'encoding', 'fileformat', 'filetype', }, + lualine_y = { 'progress' }, + lualine_z = { 'location' }, + }, + inactive_sections = { + lualine_a = {}, + lualine_b = {}, + lualine_c = { { 'filename', path = 1, file_status = true, }, }, + lualine_x = { 'location' }, + lualine_y = {}, + lualine_z = {}, + } } require('nvim-surround').setup {} -require('tsql').setup() require('fidget').setup({ - text = { - spinner = "moon", -- animation shown when tasks are ongoing - done = "✔", -- character shown when all tasks are complete - commenced = "Started", -- message shown when task starts - completed = "Completed", -- message shown when task completes - }, - align = { - bottom = true, -- align fidgets along bottom edge of buffer - right = true, -- align fidgets along right edge of buffer - }, - timer = { - spinner_rate = 125, -- frame rate of spinner animation, in ms - fidget_decay = 2000, -- how long to keep around empty fidget, in ms - task_decay = 1000, -- how long to keep around completed task, in ms - }, - window = { - relative = "editor", -- where to anchor, either "win" or "editor" - blend = 100, -- &winblend for the window - zindex = nil, -- the zindex value for the window - border = "none", -- style of border for the fidget window - }, - fmt = { - leftpad = true, -- right-justify text in fidget box - stack_upwards = true, -- list of tasks grows upwards - max_width = 0, -- maximum width of the fidget box - fidget = -- function to format fidget title - function(fidget_name, spinner) - return string.format("%s %s", spinner, fidget_name) - end, - task = -- function to format each task line - function(task_name, message, percentage) - return string.format( - "%s%s [%s]", - message, - percentage and string.format(" (%s%%)", percentage) or "", - task_name - ) - end, - }, - sources = { - -- Sources to configure - ['*'] = { -- Name of source - ignore = false, -- Ignore notifications from this source - }, - }, - debug = { - logging = false, -- whether to enable logging, for debugging - strict = false, -- whether to interpret LSP strictly + text = { + spinner = "moon", -- animation shown when tasks are ongoing + done = "✔", -- character shown when all tasks are complete + commenced = "Started", -- message shown when task starts + completed = "Completed", -- message shown when task completes + }, + align = { + bottom = true, -- align fidgets along bottom edge of buffer + right = true, -- align fidgets along right edge of buffer + }, + timer = { + spinner_rate = 125, -- frame rate of spinner animation, in ms + fidget_decay = 2000, -- how long to keep around empty fidget, in ms + task_decay = 1000, -- how long to keep around completed task, in ms + }, + window = { + relative = "editor", -- where to anchor, either "win" or "editor" + blend = 100, -- &winblend for the window + zindex = nil, -- the zindex value for the window + border = "none", -- style of border for the fidget window + }, + fmt = { + leftpad = true, -- right-justify text in fidget box + stack_upwards = true, -- list of tasks grows upwards + max_width = 0, -- maximum width of the fidget box + fidget = -- function to format fidget title + function(fidget_name, spinner) + return string.format("%s %s", spinner, fidget_name) + end, + task = -- function to format each task line + function(task_name, message, percentage) + return string.format( + "%s%s [%s]", + message, + percentage and string.format(" (%s%%)", percentage) or "", + task_name + ) + end, + }, + sources = { + -- Sources to configure + ['*'] = { -- Name of source + ignore = false, -- Ignore notifications from this source }, + }, + debug = { + logging = false, -- whether to enable logging, for debugging + strict = false, -- whether to interpret LSP strictly + }, }) + +-- Messaages as buf because it's so limiting to work with builtin view menu from neovim +vim.api.nvim_create_user_command('ShowLogs', function(opts) + local plugin_name = opts.fargs[1] or PLUGIN_URI + local min_level = opts.fargs[2] or PLUGIN_LEVEL + local logfile = string.format("%s/%s.log", vim.api.nvim_call_function("stdpath", { "cache" }), plugin_name) + + -- Ensure that the logfile exists + local file = io.open(logfile, 'r') + if not file then + print(string.format("No logfile found for plugin '%s'", vim.inspect(plugin_name))) + print("min_level: " .. vim.inspect(min_level)) + return + end + file:close() + + vim.cmd('vnew ' .. logfile) + + -- Load messages from the log file + local file_messages = vim.fn.readfile(logfile) + local levels = { trace = 1, debug = 2, info = 3, warn = 4, error = 5, fatal = 6 } + local min_index = levels[min_level] or 3 + local filtered_messages = {} + for _, message in ipairs(file_messages) do + local level = message:match("^%[([a-z]+)") + if levels[level] and levels[level] >= min_index then + table.insert(filtered_messages, message) + end + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, filtered_messages) + vim.cmd('setlocal ft=log') + vim.cmd('setlocal nomodifiable') +end, { nargs = "*", }) + +require("colorizer").setup { + filetypes = { "*" }, + user_default_options = { + RGB = true, -- #RGB hex codes + RRGGBB = true, -- #RRGGBB hex codes + names = true, -- "Name" codes like Blue or blue + RRGGBBAA = true, -- #RRGGBBAA hex codes + AARRGGBB = true, -- 0xAARRGGBB hex codes + rgb_fn = true, -- CSS rgb() and rgba() functions + hsl_fn = true, -- CSS hsl() and hsla() functions + css = true, -- Enable all CSS features: rgb_fn, hsl_fn, names, RGB, RRGGBB + css_fn = true, -- Enable all CSS *functions*: rgb_fn, hsl_fn + -- Available modes for `mode`: foreground, background, virtualtext + mode = "background", -- Set the display mode. + -- Available methods are false / true / "normal" / "lsp" / "both" + -- True is same as normal + tailwind = true, -- Enable tailwind colors + -- parsers can contain values used in |user_default_options| + sass = { enable = true, parsers = { "css" }, }, -- Enable sass colors + virtualtext = "■", + -- update color values even if buffer is not focused + -- example use: cmp_menu, cmp_docs + always_update = false + }, + -- all the sub-options of filetypes apply to buftypes + buftypes = {}, +} diff --git a/nix-conf/home-manager/base/neovim.nix b/nix-conf/home-manager/base/neovim.nix index ecc36ab..a040407 100644 --- a/nix-conf/home-manager/base/neovim.nix +++ b/nix-conf/home-manager/base/neovim.nix @@ -1,5 +1,4 @@ -# TODO: vim-plug and Mason supports laziness. Probably worth it to explore incremental dependencies based on the project -# TODO: just install these things, then symlink to mason's bin directory +# TODO: vim-plug and Mason supports laziness. Probably worth it to explore incremental dependencies based on the project TODO: just install these things, then symlink to mason's bin directory # # One thing to consider, though, /nix/store of `nix-shell` or `nix-develop` # might be different from `home-manager`'s (~/.nix_profile/bin/jq) diff --git a/nix-conf/home-manager/flake.lock b/nix-conf/home-manager/flake.lock index 13cf0fe..51f864f 100644 --- a/nix-conf/home-manager/flake.lock +++ b/nix-conf/home-manager/flake.lock @@ -58,11 +58,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1684981077, - "narHash": "sha256-68X9cFm0RTZm8u0rXPbeBzOVUH5OoUGAfeHHVoxGd9o=", + "lastModified": 1686186025, + "narHash": "sha256-SuQjKsO1G87qM5j8VNtq6kIw4ILYE03Y8yL/FoKwR+4=", "owner": "ipetkov", "repo": "crane", - "rev": "35110cccf28823320f4fd697fcafcb5038683982", + "rev": "057d95721ee67d421391dda7031977d247ddec28", "type": "github" }, "original": { @@ -570,11 +570,11 @@ "systems": "systems_2" }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -818,11 +818,11 @@ ] }, "locked": { - "lastModified": 1686562199, - "narHash": "sha256-FG6kCtVjCh0dHnV4AsVfhfSyPhjnSVXucwqCdTpMASE=", + "lastModified": 1686638670, + "narHash": "sha256-+/5lqVzqeOguJlX/57LU2e3tChw5L/jpAOzyNsiveVg=", "owner": "nix-community", "repo": "home-manager", - "rev": "b0cdae4e9baa188d69ba84aa1b7406b7bebe37f6", + "rev": "c8dafb187b7b010bf279a7bf0842eaadf3e387a8", "type": "github" }, "original": { @@ -953,11 +953,11 @@ "topiary": "topiary" }, "locked": { - "lastModified": 1686315162, - "narHash": "sha256-KZZRTXSpxJDDGVbEdyTR/4Mu2COSMtrim+5iL7qwDTw=", + "lastModified": 1686564419, + "narHash": "sha256-DJGvo1wDBRQSjAHAiNb8dD/77/CHwpeBzBYasIb51Hk=", "owner": "tweag", "repo": "nickel", - "rev": "9fed1326c9306d7c339884584702ce570764beaf", + "rev": "25c509e0b19f5b38b61a28765f62ce5c20e3e476", "type": "github" }, "original": { @@ -1037,11 +1037,11 @@ ] }, "locked": { - "lastModified": 1685764721, - "narHash": "sha256-CIy1iwQTEKfZRrid4gBLA+r/LPGA9IUFo0lKJVyECGI=", + "lastModified": 1686574167, + "narHash": "sha256-hxE8z+S9E4Qw03D2VQRaJUmj9zep3FvhKz316JUZuPA=", "owner": "mic92", "repo": "nix-index-database", - "rev": "669ca1f2e2bc401abab6b837ae9c51503edc9b49", + "rev": "7e83b70f31f4483c07e6939166cb667ecb8d05d5", "type": "github" }, "original": { @@ -1150,16 +1150,16 @@ }, "nixpkgs-stable_2": { "locked": { - "lastModified": 1678872516, - "narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=", + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.11", + "ref": "nixos-23.05", "repo": "nixpkgs", "type": "github" } @@ -1245,11 +1245,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1685655444, - "narHash": "sha256-6EujQNAeaUkWvpEZZcVF8qSfQrNVWFNNGbUJxv/A5a8=", + "lastModified": 1686412476, + "narHash": "sha256-inl9SVk6o5h75XKC79qrDCAobTD1Jxh6kVYTZKHzewA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e635192892f5abbc2289eaac3a73cdb249abaefd", + "rev": "21951114383770f96ae528d0ae68824557768e81", "type": "github" }, "original": { @@ -1513,11 +1513,11 @@ "nixpkgs-stable": "nixpkgs-stable_2" }, "locked": { - "lastModified": 1685361114, - "narHash": "sha256-4RjrlSb+OO+e1nzTExKW58o3WRwVGpXwj97iCta8aj4=", + "lastModified": 1686213770, + "narHash": "sha256-Re6xXLEqQ/HRnThryumyGzEf3Uv0Pl4cuG50MrDofP8=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "ca2fdbf3edda2a38140184da6381d49f8206eaf4", + "rev": "182af51202998af5b64ddecaa7ff9be06425399b", "type": "github" }, "original": { @@ -1599,11 +1599,11 @@ ] }, "locked": { - "lastModified": 1683080331, - "narHash": "sha256-nGDvJ1DAxZIwdn6ww8IFwzoHb2rqBP4wv/65Wt5vflk=", + "lastModified": 1685759304, + "narHash": "sha256-I3YBH6MS3G5kGzNuc1G0f9uYfTcNY9NYoRc3QsykLk4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "d59c3fa0cba8336e115b376c2d9e91053aa59e56", + "rev": "c535b4f3327910c96dcf21851bbdd074d0760290", "type": "github" }, "original": { @@ -1624,11 +1624,11 @@ ] }, "locked": { - "lastModified": 1685759304, - "narHash": "sha256-I3YBH6MS3G5kGzNuc1G0f9uYfTcNY9NYoRc3QsykLk4=", + "lastModified": 1686364106, + "narHash": "sha256-h4gCQg+jizmAbdg6UPlhxQVk4A7Ar/zoLa0wx3wBya0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "c535b4f3327910c96dcf21851bbdd074d0760290", + "rev": "ba011dd1c5028dbb880bc3b0f427e0ff689e6203", "type": "github" }, "original": { @@ -1768,11 +1768,11 @@ "nixpkgs": "nixpkgs_13" }, "locked": { - "lastModified": 1686537156, - "narHash": "sha256-mJD80brS6h6P4jzwdKID0S9RvfyiruxgJbXvPPIDqF0=", + "lastModified": 1686623191, + "narHash": "sha256-x2gQcKtSgfbZlcTaVvdMPbrXMRjUEYIV88yzsFww6D4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "e75da5cfc7da874401decaa88f4ccb3b4d64d20d", + "rev": "e279547de84413ca1a65cec3f0f879709c8c65eb", "type": "github" }, "original": { @@ -1973,11 +1973,11 @@ "rust-overlay": "rust-overlay_4" }, "locked": { - "lastModified": 1685522994, - "narHash": "sha256-OJQ16KpYT3jGyP0WSI+jZQMU55/cnbzdYZKVBfx9wNk=", + "lastModified": 1686167925, + "narHash": "sha256-2OU00zeoIS2jFBdXKak1Y2txC6IXEP0LsIUKSvr0qbc=", "owner": "tweag", "repo": "topiary", - "rev": "b2399161f60c1eb3404e487b4471ff76455d7a94", + "rev": "61d076c216422af7f865e2ade3bbdb4729e767ef", "type": "github" }, "original": { diff --git a/nix-conf/home-manager/flake.nix b/nix-conf/home-manager/flake.nix index b4da2d7..0b20873 100644 --- a/nix-conf/home-manager/flake.nix +++ b/nix-conf/home-manager/flake.nix @@ -15,6 +15,7 @@ description = "simple home-manager config"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs-latest.url = "github:nixos/nixpkgs"; home-manager = { url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; @@ -52,6 +53,7 @@ , neovim-nightly-overlay , nickel , nix-boost + , nixpkgs-latest , ... }: let diff --git a/nix-conf/home-manager/overlays.nix b/nix-conf/home-manager/overlays.nix index c711e6a..3501dbe 100644 --- a/nix-conf/home-manager/overlays.nix +++ b/nix-conf/home-manager/overlays.nix @@ -5,6 +5,7 @@ flake_input@{ kpcli-py , system , nickel , nix-boost +, nixpkgs-latest , ... }: let @@ -63,6 +64,10 @@ let inherit (flake_input.nickel.packages.${system}) lsp-nls nickel nickelWasm; }); + + vimPlugins = (final: prev: { + inherit (nixpkgs-latest) vimPlugins; + }); in [ nix-boost.overlays.default