vim.cmd.packadd('packer.nvim') local packer = require('packer') -- Plugins {{{1 packer.startup(function(use) -- Plugin management {{{2 use { 'wbthomason/packer.nvim', opt = true, } -- Libraries {{{2 -- telescope.nvim depends on it. use { 'nvim-lua/plenary.nvim', } -- Text editing {{{2 -- IME {{{3 -- SKK (Simple Kana to Kanji conversion program) for Vim. use { '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 {{{3 -- Support for user-defined operators. use { 'kana/vim-operator-user', } -- Extract expression and make assingment statement. use { 'tek/vim-operator-assign', } -- Replace text without updating registers. use { 'kana/vim-operator-replace', opt = true, keys = { {'n', '(operator-replace)'}, {'o', '(operator-replace)'}, {'x', '(operator-replace)'}, }, setup = function() vim.keymap.set('n', '', '(operator-replace)') vim.keymap.set('o', '', '(operator-replace)') vim.keymap.set('x', '', '(operator-replace)') end, } -- Super surround. use { '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 {{{3 -- Comment out. use { 'numToStr/Comment.nvim', opt = true, keys = { {'n', 'm//'}, {'n', 'm??'}, {'n', 'm/'}, {'x', 'm/'}, {'n', 'm?'}, {'x', 'm?'}, {'n', 'm/O'}, {'n', 'm/o'}, {'n', 'm/A'}, }, 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. use { 'junegunn/vim-easy-align', opt = true, cmd = {'EasyAlign'}, keys = { {'n', '(EasyAlign)'}, {'x', '(EasyAlign)'}, }, setup = function() vim.keymap.set('n', '=', '(EasyAlign)') vim.keymap.set('x', '=', '(EasyAlign)') end, } -- Text objects {{{2 -- Support for user-defined text objects. use { 'kana/vim-textobj-user', } -- Text object for blockwise. use { 'osyo-manga/vim-textobj-blockwise', } -- Text object for comment. use { 'thinca/vim-textobj-comment', } -- Text object for indent. use { 'kana/vim-textobj-indent', } -- Text object for line. use { 'kana/vim-textobj-line', } -- Text object for parameter. use { 'sgur/vim-textobj-parameter', } -- Text object for space. use { 'saihoooooooo/vim-textobj-space', opt = true, keys = { {'o', 'a'}, {'x', 'a'}, {'o', 'i'}, {'x', 'i'}, }, setup = function() vim.g.textobj_space_no_default_key_mappings = true end, config = function() vim.keymap.set('o', 'a', '(textobj-space-a)') vim.keymap.set('x', 'a', '(textobj-space-a)') vim.keymap.set('o', 'i', '(textobj-space-i)') vim.keymap.set('x', 'i', '(textobj-space-i)') end, } -- Text object for syntax. use { 'kana/vim-textobj-syntax', } -- Text object for URL. use { 'mattn/vim-textobj-url', } -- Text object for words in words. use { 'h1mesuke/textobj-wiw', opt = true, keys = { {'n', ''}, {'o', ''}, {'x', ''}, {'n', 'g'}, {'o', 'g'}, {'x', 'g'}, {'n', ''}, {'o', ''}, {'x', ''}, {'n', 'g'}, {'o', 'g'}, {'x', 'g'}, {'o', 'a'}, {'x', 'a'}, {'o', 'i'}, {'x', 'i'}, }, setup = function() vim.g.textobj_wiw_no_default_key_mappings = true end, config = function() vim.keymap.set('n', '', '(textobj-wiw-n)') vim.keymap.set('o', '', '(textobj-wiw-n)') vim.keymap.set('x', '', '(textobj-wiw-n)') vim.keymap.set('n', 'g', '(textobj-wiw-p)') vim.keymap.set('o', 'g', '(textobj-wiw-p)') vim.keymap.set('x', 'g', '(textobj-wiw-p)') vim.keymap.set('n', '', '(textobj-wiw-N)') vim.keymap.set('o', '', '(textobj-wiw-N)') vim.keymap.set('x', '', '(textobj-wiw-N)') vim.keymap.set('n', 'g', '(textobj-wiw-P)') vim.keymap.set('o', 'g', '(textobj-wiw-P)') vim.keymap.set('x', 'g', '(textobj-wiw-P)') vim.keymap.set('o', 'a', '(textobj-wiw-a)') vim.keymap.set('x', 'a', '(textobj-wiw-a)') vim.keymap.set('o', 'i', '(textobj-wiw-i)') vim.keymap.set('x', 'i', '(textobj-wiw-i)') end, } -- Search {{{2 -- Extend * and #. use { 'haya14busa/vim-asterisk', opt = true, keys = { {'n', '(asterisk-z*)'}, {'x', '(asterisk-z*)'}, {'n', '(asterisk-gz*)'}, {'x', '(asterisk-gz*)'}, }, setup = function() vim.keymap.set({'n', 'x'}, '*', '(asterisk-z*)') vim.keymap.set({'n', 'x'}, 'g*', '(asterisk-gz*)') end, } -- NOTE: it is a fork version of jremmen/vim-ripgrep -- Integration with ripgrep, fast alternative of grep command. use { 'nsfisis/vim-ripgrep', opt = 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 {{{2 -- Switch to related files. use { '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. use { 'lambdalisue/fern.vim', opt = 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. use { 'lambdalisue/fern-hijack.vim', } -- Appearance {{{2 -- Show highlight. use { 'cocopon/colorswatch.vim', opt = true, cmd = {'ColorSwatchGenerate'}, } -- Makes folding text cool. use { 'LeafCage/foldCC.vim', config = function() vim.o.foldtext = 'FoldCCtext()' vim.g.foldCCtext_head = 'repeat(">", v:foldlevel) . " "' end, } -- Show indentation guide. use { 'lukas-reineke/indent-blankline.nvim', config = function() require("indent_blankline").setup { char_blankline = ' ', show_first_indent_level = false, } end, } -- Highlight matched parentheses. use { 'itchyny/vim-parenmatch', } -- Tree-sitter integration. use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate', 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 = false, }, yati = { enable = true, }, } end, } -- Tree-sitter debugging. use { 'nvim-treesitter/playground', } -- Highlight specified words. use { '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, } -- Yet another tree-sitter indentation. -- TODO: uninstall it once the official nvim-treesitter provides sane indentation. use { 'yioneko/nvim-yati', } -- Filetypes {{{2 -- Faster replacement for bundled filetype.vim use { 'nathom/filetype.nvim', config = function() require('filetype').setup({ overrides = { extensions = { saty = 'satysfi', satyg = 'satysfi', satyh = 'satysfi', }, }, }) end, } -- C/C++ use { '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 use { 'mattn/emmet-vim', opt = true, cmd = {'EmmetInstall'}, setup = function() local vimrc = require('vimrc') vim.g.user_emmet_install_global = false vimrc.autocmd('FileType', { pattern = {'html', 'css'}, command = 'EmmetInstall', }) end, } -- Rust use { 'rust-lang/rust.vim', config = function() vim.g.rustfmt_autosave = true end, } -- QoL {{{2 -- Capture the output of a command. use { 'tyru/capture.vim', opt = true, cmd = {'Capture'}, } -- Write git commit message. use { 'rhysd/committia.vim', config = function() vim.g.committia_hooks = { edit_open = function(_info) vim.wo.spell = true end, } end, } -- Neovim clone of EasyMotion use { 'phaazon/hop.nvim', branch = 'v2', -- Hop.nvim's README recommends this. opt = true, keys = { {'n', '(hop-f)'}, {'o', '(hop-f)'}, {'x', '(hop-f)'}, {'n', '(hop-F)'}, {'o', '(hop-F)'}, {'x', '(hop-F)'}, {'o', '(hop-t)'}, {'x', '(hop-t)'}, {'o', '(hop-T)'}, {'x', '(hop-T)'}, {'n', '(hop-s2)'}, {'o', '(hop-s2)'}, {'x', '(hop-s2)'}, {'n', '(hop-n)'}, {'o', '(hop-n)'}, {'x', '(hop-n)'}, {'n', '(hop-N)'}, {'o', '(hop-N)'}, {'x', '(hop-N)'}, {'n', '(hop-j)'}, {'o', '(hop-j)'}, {'x', '(hop-j)'}, {'n', '(hop-k)'}, {'o', '(hop-k)'}, {'x', '(hop-k)'}, }, 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, setup = function() vim.keymap.set('n', 'f', '(hop-f)') vim.keymap.set('o', 'f', '(hop-f)') vim.keymap.set('x', 'f', '(hop-f)') vim.keymap.set('n', 'F', '(hop-F)') vim.keymap.set('o', 'F', '(hop-F)') vim.keymap.set('x', 'F', '(hop-F)') vim.keymap.set('o', 't', '(hop-t)') vim.keymap.set('x', 't', '(hop-t)') vim.keymap.set('o', 'T', '(hop-T)') vim.keymap.set('x', 'T', '(hop-T)') -- Note: Don't use the following key sequences! They are used by 'vim-sandwich'. -- * sa -- * sd -- * sr vim.keymap.set('n', 'ss', '(hop-s2)') vim.keymap.set('o', 'ss', '(hop-s2)') vim.keymap.set('x', 'ss', '(hop-s2)') vim.keymap.set('n', 'sn', '(hop-n)') vim.keymap.set('o', 'sn', '(hop-n)') vim.keymap.set('x', 'sn', '(hop-n)') vim.keymap.set('n', 'sN', '(hop-N)') vim.keymap.set('o', 'sN', '(hop-N)') vim.keymap.set('x', 'sN', '(hop-N)') vim.keymap.set('n', 'sj', '(hop-j)') vim.keymap.set('o', 'sj', '(hop-j)') vim.keymap.set('x', 'sj', '(hop-j)') vim.keymap.set('n', 'sk', '(hop-k)') vim.keymap.set('o', 'sk', '(hop-k)') vim.keymap.set('x', 'sk', '(hop-k)') end, } -- Integration with EditorConfig (https://editorconfig.org) use { 'editorconfig/editorconfig-vim', } -- Extend J. use { '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. use { '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. use { 'itchyny/vim-qfedit', } -- Edit QuickFix and reflect to original buffers. use { 'thinca/vim-qfreplace', opt = true, cmd = {'Qfreplace'}, config = function() vim.keymap.set('n', 'br', ':Qfreplace SmartOpen', { silent=true }) end, } -- Run anything. use { '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. use { '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. use { 'kana/vim-submode', config = function() -- Global settings {{{3 vim.g.submode_always_show_submode = true vim.g.submode_keyseqs_to_leave = {'', ''} vim.g.submode_keep_leaving_key = true -- yankround {{{3 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 {{{3 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)') -- TODO if packer_plugins['vim-swap'] and not packer_plugins['vim-swap'].loaded then vim.cmd.packadd('vim-swap') end -- Resizing a window (height) {{{3 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) {{{3 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 {{{3 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. use { 'machakann/vim-swap', opt = true, setup = function() vim.g.swap_no_default_key_mappings = true end, } -- Fuzzy finder. use { 'nvim-telescope/telescope.nvim', } -- Adjust window size. use { '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. use { '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, } -- }}} end) -- }}} return { compile = packer.compile, sync = packer.sync, }