return { -- Libraries {{{1 -- telescope.nvim depends on it. { 'nvim-lua/plenary.nvim', }, -- Text editing {{{1 -- IME {{{2 -- SKK (Simple Kana to Kanji conversion program) for Vim. { 'vim-skk/eskk.vim', config = function() local my_env = require('vimrc.my_env') vim.g['eskk#dictionary'] = { path = my_env.skk_dir .. '/jisyo', sorted = false, encoding = 'utf-8', } vim.g['eskk#large_dictionary'] = { path = my_env.skk_dir .. '/jisyo.L', sorted = true, encoding = 'euc-jp', } vim.g['eskk#backup_dictionary'] = vim.g['eskk#dictionary'].path .. '.bak' -- NOTE: -- Boolean values are not accepted because eskk#utils#set_default() checks types. vim.g['eskk#enable_completion'] = 0 vim.g['eskk#egg_like_newline'] = 1 -- Change default markers because they are EAW (East Asian Width) characters. vim.g['eskk#marker_henkan'] = '[!]' vim.g['eskk#marker_okuri'] = '-' vim.g['eskk#marker_henkan_select'] = '[#]' vim.g['eskk#marker_jisyo_touroku'] = '[?]' vim.cmd([=[ function! My_eskk_initialize_pre() for [orgtable, mode] in [['rom_to_hira', 'hira'], ['rom_to_kata', 'kata']] let t = eskk#table#new(orgtable . '*', orgtable) call t.add_map('z ', ' ') call t.add_map('0.', '0.') call t.add_map('1.', '1.') call t.add_map('2.', '2.') call t.add_map('3.', '3.') call t.add_map('4.', '4.') call t.add_map('5.', '5.') call t.add_map('6.', '6.') call t.add_map('7.', '7.') call t.add_map('8.', '8.') call t.add_map('9.', '9.') call t.add_map(':', ':') call t.add_map('z:', ':') " Workaround: 'zl' does not work as 'l' key leaves from SKK mode. call t.add_map('zL', '→') call eskk#register_mode_table(mode, t) endfor endfunction autocmd Vimrc User eskk-initialize-pre call My_eskk_initialize_pre() function! My_eskk_initialize_post() " I don't use hankata mode for now. EskkUnmap -type=mode:hira:toggle-hankata EskkUnmap -type=mode:kata:toggle-hankata " I don't use abbrev mode for now. EskkUnmap -type=mode:hira:to-abbrev EskkUnmap -type=mode:kata:to-abbrev " I don't use ascii mode for now. EskkUnmap -type=mode:hira:to-ascii EskkUnmap -type=mode:kata:to-ascii " Instead, l key disable SKK input. EskkMap -type=disable l " I type for new line. EskkMap -type=kakutei map! jk (eskk:disable) " Custom highlight for henkan markers. syntax match skkMarker '\[[!#?]\]' hi link skkMarker Special endfunction autocmd Vimrc User eskk-initialize-post call My_eskk_initialize_post() ]=]) end, }, -- Operators {{{2 -- Support for user-defined operators. { 'kana/vim-operator-user', }, -- Extract expression and make assingment statement. { 'tek/vim-operator-assign', }, -- Replace text without updating registers. { 'kana/vim-operator-replace', lazy = true, keys = { {'', '(operator-replace)', mode = {'n', 'o', 'x'}}, }, }, -- Super surround. { 'machakann/vim-sandwich', config = function() vim.fn['operator#sandwich#set']('add', 'all', 'highlight', 2) vim.fn['operator#sandwich#set']('delete', 'all', 'highlight', 0) vim.fn['operator#sandwich#set']('replace', 'all', 'highlight', 2) do local rs = vim.fn['sandwich#get_recipes']() rs[#rs+1] = { buns = {'「', '」'}, input = {'j[', 'j]'}, } rs[#rs+1] = { buns = {'『', '』'}, input = {'j{', 'j}'}, } rs[#rs+1] = { buns = {'【', '】'}, input = {'j(', 'j)'}, } vim.g['sandwich#recipes'] = rs end end, }, -- Non-operators {{{2 -- Comment out. { 'numToStr/Comment.nvim', config = function() require('Comment').setup { toggler = { line = 'm//', block = 'm??', }, opleader = { line = 'm/', block = 'm?', }, extra = { above = 'm/O', below = 'm/o', eol = 'm/A', }, } end, }, -- Align text. { 'junegunn/vim-easy-align', lazy = true, cmd = {'EasyAlign'}, keys = { {'=', '(EasyAlign)', mode = {'n', 'x'}}, }, }, -- Text objects {{{1 -- Support for user-defined text objects. { 'kana/vim-textobj-user', priority = 100, }, -- Text object for blockwise. { 'osyo-manga/vim-textobj-blockwise', }, -- Text object for comment. { 'thinca/vim-textobj-comment', }, -- Text object for indent. { 'kana/vim-textobj-indent', }, -- Text object for line. { 'kana/vim-textobj-line', }, -- Text object for parameter. { 'sgur/vim-textobj-parameter', }, -- Text object for space. { 'saihoooooooo/vim-textobj-space', lazy = true, keys = { {'a', '(textobj-space-a)', mode = {'o', 'x'}}, {'i', '(textobj-space-i)', mode = {'o', 'x'}}, }, init = function() vim.g.textobj_space_no_default_key_mappings = true end, }, -- Text object for syntax. { 'kana/vim-textobj-syntax', }, -- Text object for URL. { 'mattn/vim-textobj-url', }, -- Text object for words in words. { 'h1mesuke/textobj-wiw', lazy = true, keys = { {'', '(textobj-wiw-n)', mode = {'n', 'o', 'x'}}, {'g', '(textobj-wiw-p)', mode = {'n', 'o', 'x'}}, {'', '(textobj-wiw-N)', mode = {'n', 'o', 'x'}}, {'g', '(textobj-wiw-P)', mode = {'n', 'o', 'x'}}, {'a', '(textobj-wiw-a)', mode = {'o', 'x'}}, {'i', '(textobj-wiw-i)', mode = {'o', 'x'}}, }, init = function() vim.g.textobj_wiw_no_default_key_mappings = true end, }, -- Search {{{1 -- Extend * and #. { 'haya14busa/vim-asterisk', lazy = true, keys = { {'*', '(asterisk-z*)', mode = {'n', 'x'}}, {'g*', '(asterisk-gz*)', mode = {'n', 'x'}}, }, }, -- NOTE: it is a fork version of jremmen/vim-ripgrep -- Integration with ripgrep, fast alternative of grep command. { 'nsfisis/vim-ripgrep', lazy = true, cmd = {'Rg', 'RG'}, config = function() -- Workaround: do not open quickfix window. -- exe g:rg_window_location 'copen' vim.g.rg_window_location = 'silent! echo' vim.g.rg_jump_to_first = true vim.api.nvim_create_user_command( 'RG', 'Rg ', { bang = true, bar = true, nargs = '*', complete = 'file', } ) end, }, -- Files {{{1 -- Switch to related files. { 'kana/vim-altr', config = function() -- C/C++ vim.fn['altr#define']('%.c', '%.cpp', '%.cc', '%.h', '%.hh', '%.hpp') -- Vim vim.fn['altr#define']('autoload/%.vim', 'doc/%.txt', 'plugin/%.vim') -- Go to File Alternative vim.keymap.set('n', 'gfa', '(altr-forward)') end, }, -- Full-featured filer. { 'lambdalisue/fern.vim', lazy = true, cmd = {'Fern'}, config = function() local vimrc = require('vimrc') vimrc.autocmd('FileType', { pattern = {'fern'}, callback = function() if vim.fn.hasmapto('(fern-action-open:tabedit)', 'n') == 1 then vim.keymap.del('n', 't', { buffer = true }) end end, }) end, }, -- Fern plugin: hijack Netrw. { 'lambdalisue/fern-hijack.vim', }, -- Appearance {{{1 -- Show highlight. { 'cocopon/colorswatch.vim', lazy = true, cmd = {'ColorSwatchGenerate'}, }, -- Makes folding text cool. { 'LeafCage/foldCC.vim', config = function() vim.o.foldtext = 'FoldCCtext()' vim.g.foldCCtext_head = 'repeat(">", v:foldlevel) . " "' end, }, -- Show indentation guide. { 'lukas-reineke/indent-blankline.nvim', main = 'ibl', config = function() require('ibl').setup { scope = { enabled = false, }, } end, }, -- Highlight matched parentheses. { 'itchyny/vim-parenmatch', }, -- Tree-sitter integration. { 'nvim-treesitter/nvim-treesitter', build = ':TSUpdateSync', config = function() require('nvim-treesitter.configs').setup { ensure_installed = 'all', sync_install = false, highlight = { enable = true, additional_vim_regex_highlighting = false, }, --[[ incremental_selection = { enable = true, keymaps = { init_selection = 'TODO', node_incremental = 'TODO', scope_incremental = 'TODO', node_decremental = 'TODO', }, }, --]] indent = { enable = true, }, } end, }, -- Tree-sitter debugging. { 'nvim-treesitter/playground', }, -- Highlight specified words. { 't9md/vim-quickhl', config = function() -- TODO: CUI vim.g.quickhl_manual_colors = { 'guifg=#101020 guibg=#8080c0 gui=bold', 'guifg=#101020 guibg=#80c080 gui=bold', 'guifg=#101020 guibg=#c08080 gui=bold', 'guifg=#101020 guibg=#80c0c0 gui=bold', 'guifg=#101020 guibg=#c0c080 gui=bold', 'guifg=#101020 guibg=#a0a0ff gui=bold', 'guifg=#101020 guibg=#a0ffa0 gui=bold', 'guifg=#101020 guibg=#ffa0a0 gui=bold', 'guifg=#101020 guibg=#a0ffff gui=bold', 'guifg=#101020 guibg=#ffffa0 gui=bold', } vim.keymap.set('n', '"', '(quickhl-manual-this)') vim.keymap.set('x', '"', '(quickhl-manual-this)') vim.keymap.set('n', '', ':nohlsearch QuickhlManualReset', { silent=true }) end, }, -- Filetypes {{{1 -- C/C++ { 'rhysd/vim-clang-format', config = function() local vimrc = require('vimrc') vim.g['clang_format#auto_format'] = true vimrc.autocmd('FileType', { pattern = {'javascript', 'typescript'}, command = 'ClangFormatAutoDisable', }) end, }, -- HTML/CSS { 'mattn/emmet-vim', lazy = true, cmd = {'EmmetInstall'}, init = function() local vimrc = require('vimrc') vim.g.user_emmet_install_global = false vimrc.autocmd('FileType', { pattern = {'html', 'css'}, command = 'EmmetInstall', }) end, }, -- Rust { 'rust-lang/rust.vim', config = function() vim.g.rustfmt_autosave = true end, }, -- QoL {{{1 -- Capture the output of a command. { 'tyru/capture.vim', lazy = true, cmd = {'Capture'}, }, -- Write git commit message. { 'rhysd/committia.vim', config = function() vim.g.committia_hooks = { edit_open = function(_info) vim.wo.spell = true end, } end, }, -- Neovim clone of EasyMotion { 'phaazon/hop.nvim', branch = 'v2', -- Hop.nvim's README recommends this. lazy = true, keys = { {'f', '(hop-f)', mode = {'n', 'o', 'x'}}, {'F', '(hop-F)', mode = {'n', 'o', 'x'}}, {'t', '(hop-t)', mode = {'o', 'x'}}, {'T', '(hop-T)', mode = {'o', 'x'}}, -- Note: Don't use the following key sequences! They are used by 'vim-sandwich'. -- * sa -- * sd -- * sr {'ss', '(hop-s2)', mode = {'n', 'o', 'x'}}, {'sn', '(hop-n)', mode = {'n', 'o', 'x'}}, {'sN', '(hop-N)', mode = {'n', 'o', 'x'}}, {'sj', '(hop-j)', mode = {'n', 'o', 'x'}}, {'sk', '(hop-k)', mode = {'n', 'o', 'x'}}, }, config = function() require('hop').setup { keys = 'asdfghweryuiocvbnmjkl;', } -- Emulate `g:EasyMotion_startofline = 0` in hop.nvim. local function hop_jk(opts) local hop = require('hop') local jump_target = require('hop.jump_target') local column = vim.fn.col('.') local match if column == 1 then match = function(_) return 0, 1, false end else local pat = vim.regex('\\%' .. column .. 'c') match = function(s) return pat:match_str(s) end end setmetatable(opts, { __index = hop.opts }) hop.hint_with( jump_target.jump_targets_by_scanning_lines({ oneshot = true, match = match, }), opts ) end local hop = require('hop') local HintDirection = require('hop.hint').HintDirection local AFTER_CURSOR = HintDirection.AFTER_CURSOR local BEFORE_CURSOR = HintDirection.BEFORE_CURSOR vim.keymap.set('', '(hop-f)', function() hop.hint_char1({ direction = AFTER_CURSOR, current_line_only = true }) end, { silent = true }) vim.keymap.set('', '(hop-F)', function() hop.hint_char1({ direction = BEFORE_CURSOR, current_line_only = true }) end, { silent = true }) vim.keymap.set('', '(hop-t)', function() hop.hint_char1({ direction = AFTER_CURSOR, current_line_only = true, hint_offset = -1 }) end, { silent = true }) vim.keymap.set('', '(hop-T)', function() hop.hint_char1({ direction = BEFORE_CURSOR, current_line_only = true, hint_offset = 1 }) end, { silent = true }) vim.keymap.set('', '(hop-s2)', function() hop.hint_char2() end, { silent = true }) vim.keymap.set('', '(hop-n)', function() hop.hint_patterns({ direction = AFTER_CURSOR }, vim.fn.getreg('/')) end, { silent = true }) vim.keymap.set('', '(hop-N)', function() hop.hint_patterns({ direction = BEFORE_CURSOR }, vim.fn.getreg('/')) end, { silent = true }) vim.keymap.set('', '(hop-j)', function() hop_jk({ direction = AFTER_CURSOR }) end, { silent = true }) vim.keymap.set('', '(hop-k)', function() hop_jk({ direction = BEFORE_CURSOR }) end, { silent = true }) end, }, -- Extend J. { 'osyo-manga/vim-jplus', config = function() vim.g['jplus#input_config'] = { __DEFAULT__ = { delimiter_format = ' %d ' }, __EMPTY__ = { delimiter_format = '' }, [' '] = { delimiter_format = ' ' }, [','] = { delimiter_format = '%d ' }, [':'] = { delimiter_format = '%d ' }, [';'] = { delimiter_format = '%d ' }, l = { delimiter_format = '' }, L = { delimiter_format = '' }, } vim.keymap.set('n', 'J', '(jplus-getchar)') vim.keymap.set('x', 'J', '(jplus-getchar)') vim.keymap.set('n', 'gJ', '(jplus-input)') vim.keymap.set('x', 'gJ', '(jplus-input)') end, }, -- Improve behaviors of I, A and gI in Blockwise-Visual mode. { 'kana/vim-niceblock', config = function() vim.keymap.set('x', 'I', '(niceblock-I)') vim.keymap.set('x', 'gI', '(niceblock-gI)') vim.keymap.set('x', 'A', '(niceblock-A)') end, }, -- Edit QuickFix freely. { 'itchyny/vim-qfedit', }, -- Edit QuickFix and reflect to original buffers. { 'thinca/vim-qfreplace', lazy = true, cmd = {'Qfreplace'}, config = function() vim.keymap.set('n', 'br', ':Qfreplace SmartOpen', { silent=true }) end, }, -- Run anything. { 'thinca/vim-quickrun', config = function() vim.g.quickrun_config = { cpp = { cmdopt = '--std=c++17 -Wall -Wextra', }, d = { exec = 'dub run', }, haskell = { exec = {'stack build', 'stack exec %{matchstr(globpath(".,..,../..,../../..", "*.cabal"), "\\w\\+\\ze\\.cabal")}'}, }, python = { command = 'python3', }, } vim.keymap.set('n', 'BB', '(quickrun)') vim.keymap.set('x', 'BB', '(quickrun)') end, }, -- Extend dot-repeat. { 'tpope/vim-repeat', config = function() vim.keymap.set('n', 'U', '(RepeatRedo)') -- Autoload vim-repeat immediately in order to make (RepeatRedo) available. -- repeat#setreg() does nothing here. vim.fn['repeat#setreg']('', '') end, }, -- Introduce user-defined mode. { 'kana/vim-submode', config = function() -- Global settings {{{2 vim.g.submode_always_show_submode = true vim.g.submode_keyseqs_to_leave = {'', ''} vim.g.submode_keep_leaving_key = true -- yankround {{{2 vim.fn['submode#enter_with']('YankRound', 'nv', 'rs', 'gp', '(yankround-p)') vim.fn['submode#enter_with']('YankRound', 'nv', 'rs', 'gP', '(yankround-P)') vim.fn['submode#map']('YankRound', 'nv', 'rs', 'p', '(yankround-prev)') vim.fn['submode#map']('YankRound', 'nv', 'rs', 'P', '(yankround-next)') -- swap {{{2 vim.fn['submode#enter_with']('Swap', 'n', 'rs', 'g>', '(swap-next)') vim.fn['submode#map']('Swap', 'n', 'rs', '<', '(swap-prev)') vim.fn['submode#enter_with']('Swap', 'n', 'rs', 'g<', '(swap-prev)') vim.fn['submode#map']('Swap', 'n', 'rs', '>', '(swap-next)') -- Resizing a window (height) {{{2 vim.fn['submode#enter_with']('WinResizeH', 'n', 's', 'trh') vim.fn['submode#enter_with']('WinResizeH', 'n', 's', 'trh') vim.fn['submode#map']('WinResizeH', 'n', 's', '+', '+') vim.fn['submode#map']('WinResizeH', 'n', 's', '-', '-') -- Resizing a window (width) {{{2 vim.fn['submode#enter_with']('WinResizeW', 'n', 's', 'trw') vim.fn['submode#enter_with']('WinResizeW', 'n', 's', 'trw') vim.fn['submode#map']('WinResizeW', 'n', 's', '+', '>') vim.fn['submode#map']('WinResizeW', 'n', 's', '-', '') -- Super undo/redo {{{2 vim.fn['submode#enter_with']('Undo/Redo', 'n', 's', 'gu', 'g-') vim.fn['submode#map']('Undo/Redo', 'n', 's', 'u', 'g-') vim.fn['submode#enter_with']('Undo/Redo', 'n', 's', 'gU', 'g+') vim.fn['submode#map']('Undo/Redo', 'n', 's', 'U', 'g+') -- }}} end, }, -- Swap arguments. { 'machakann/vim-swap', init = function() vim.g.swap_no_default_key_mappings = true end, }, -- Fuzzy finder. { 'nvim-telescope/telescope.nvim', }, -- Adjust window size. { 'rhysd/vim-window-adjuster', config = function() vim.keymap.set('n', 'tRw', 'AdjustScreenWidth') vim.keymap.set('n', 'tRh', 'AdjustScreenHeight') vim.keymap.set('n', 'tRr', ':AdjustScreenWidth AdjustScreenHeight', { silent=true }) end, }, -- Remember yank history and paste them. { 'LeafCage/yankround.vim', config = function() local my_env = require('vimrc.my_env') vim.g.yankround_dir = my_env.yankround_dir vim.g.yankround_use_region_hl = true end, }, -- LSP {{{1 -- Collection of common LSP configurations. { 'neovim/nvim-lspconfig', config = function() local lspconfig = require('lspconfig') -- TODO -- Enable denols xor tsserver. local is_deno_repo if vim.fn.executable('deno') == 1 then local get_deno_root_dir = lspconfig.util.root_pattern("deno.json", "deno.jsonc") is_deno_repo = get_deno_root_dir(vim.api.nvim_buf_get_name(0)) ~= nil else is_deno_repo = false end if vim.fn.executable('typescript-language-server') == 1 then if not is_deno_repo then lspconfig.tsserver.setup({}) end end if vim.fn.executable('deno') == 1 then if is_deno_repo then lspconfig.denols.setup({}) end end if vim.fn.executable('gopls') == 1 then lspconfig.gopls.setup({}) end vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup('UserLspConfig', {}), callback = function(e) vim.bo[e.buf].omnifunc = 'v:lua.vim.lsp.omnifunc' local opts = { buffer = e.buf } vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) vim.keymap.set('n', 'f', function() vim.lsp.buf.format({ async = true }) end, opts) end, }) end, }, -- *Magic* {{{1 -- Integration with GitHub Copilot (https://docs.github.com/en/copilot) { 'github/copilot.vim', }, -- }}} }