" Set Vim's internal encodding. " Note: This option must be set before 'scriptencoding' is set. set encoding=utf-8 " Set this file's encoding. scriptencoding utf-8 " Global settings {{{1 " Global variables. {{{2 let g:MY_ENV = {} if has('unix') let g:MY_ENV.os = 'unix' elseif has('mac') let g:MY_ENV.os = 'mac' elseif has('wsl') let g:MY_ENV.os = 'wsl' elseif has('win32') || has('win64') let g:MY_ENV.os = 'windows' else let g:MY_ENV.os = 'unknown' endif if empty($XDG_CONFIG_HOME) let g:MY_ENV.config_home = $HOME . '/.config' else let g:MY_ENV.config_home = $XDG_CONFIG_HOME endif if empty($XDG_CACHE_HOME) let g:MY_ENV.cache_home = $HOME . '/.cache' else let g:MY_ENV.cache_home = $XDG_CONFIG_HOME endif if has('nvim') let g:MY_ENV.config_dir = g:MY_ENV.config_home . '/nvim' else let g:MY_ENV.config_dir = g:MY_ENV.config_home . '/vim' endif if has('nvim') let g:MY_ENV.cache_dir = g:MY_ENV.cache_home . '/nvim' else let g:MY_ENV.cache_dir = g:MY_ENV.cache_home . '/vim' endif let g:MY_ENV.my_dir = g:MY_ENV.config_dir . '/my' let g:MY_ENV.plug_dir = g:MY_ENV.config_dir . '/plugged' let g:MY_ENV.undo_dir = g:MY_ENV.cache_dir . '/undo' let g:MY_ENV.backup_dir = g:MY_ENV.cache_dir . '/backup' let g:MY_ENV.swap_dir = g:MY_ENV.cache_dir . '/swap' let g:MY_ENV.yankround_dir = g:MY_ENV.cache_dir . '/yankround' let g:MY_ENV.skk_dir = g:MY_ENV.config_home . '/skk' for [s:k, s:v] in items(g:MY_ENV) if s:k =~# '_dir$' && !isdirectory(s:v) call mkdir(s:v, 'p') endif endfor unlet s:k s:v " The autogroup used in .vimrc {{{2 augroup Vimrc autocmd! augroup END " Note: |:autocmd| does not accept |-bar|. command! -nargs=* \ Autocmd \ autocmd Vimrc " Language {{{2 " Disable L10N. language messages C language time C " Options {{{1 " * Use |:set|, not |:setglobal|. " |:setglobal| does not set local options, so options are not set in " the starting buffer you specified as commandline arguments like " "$ vim ~/.vimrc". " Moving around, searching and patterns {{{2 set nowrapscan set incsearch set ignorecase set smartcase " Displaying text {{{2 set scrolloff=7 set wrap set linebreak set breakindent set breakindentopt+=sbr " Use let statement to avoid trailing space. let &showbreak = '> ' set sidescrolloff=20 set display=lastline " Use let statement to avoid trailing space. let &fillchars = 'stl: ,stlnc: ,vert: ,fold: ,diff: ' set cmdheight=2 set list let &listchars="eol:\u00ac,tab:\u25b8 ,extends:\u00bb,precedes:\u00ab" set conceallevel=2 set concealcursor=cnv " Syntax, highlighting and spelling {{{2 set background=dark set synmaxcol=500 set hlsearch " Execute nohlsearch to avoid highlighting last searched pattern when reloading " .vimrc. nohlsearch if exists('+termguicolors') let &t_8f="\[38;2;%lu;%lu;%lum" let &t_8b="\[48;2;%lu;%lu;%lum" set termguicolors endif set t_Co=256 set nocursorline set colorcolumn=+1 " Multiple windows {{{2 set laststatus=2 set equalalways set eadirection=both set winminheight=0 set hidden set switchbuf=usetab " Multiple tabpages {{{2 set showtabline=2 " Terminal {{{2 set notitle " Using the mouse {{{2 set mouse= " Messages and info {{{2 set shortmess+=a \ shortmess+=s \ shortmess+=I \ shortmess+=c set showcmd set noshowmode set report=999 set confirm set belloff=all " Selecting text {{{2 set clipboard=unnamed " Editing text {{{2 set undofile let &undodir = g:MY_ENV.undo_dir set textwidth=0 set backspace=indent,eol,start set complete+=t set completeopt-=preview set pumheight=10 set noshowmatch set matchpairs+=<:> set nojoinspaces set nrformats-=octal \ nrformats+=unsigned " Tabs and indenting {{{2 " Note: you should also set them for each file types. " These following settings are global, used for unknown file types. set tabstop=4 set shiftwidth=4 set smarttab set softtabstop=4 set expandtab set autoindent set smartindent set copyindent set preserveindent " Folding {{{2 set foldlevelstart=0 set foldopen+=insert set foldmethod=marker " Diff mode {{{2 set diffopt+=vertical \ diffopt+=foldcolumn:3 " Mapping {{{2 set maxmapdepth=10 set notimeout set ttimeout set ttimeoutlen=100 " Reading and writing files {{{2 set nofixendofline " Note: if 'fileformat' is empty, the first item of 'fileformats' is used. set fileformats=unix,dos,mac " Note: these settings make one backup. If you want more backups, see " |'backupext'|. set backup let &backupdir = g:MY_ENV.backup_dir set autowrite set autoread " The swap file {{{2 " Note: 'dictionary' is swap files' directory. " '//' is converted to swap file's path. " If you are editing 'a/b.vim', Vim makes '{g:MY_ENV.cache_dir}/swap/a/b.vim'. let &directory = g:MY_ENV.swap_dir . '//' " Command line editing {{{2 set history=2000 set wildignore+=*.o,*.obj,*.lib set wildignorecase set wildmenu " Executing external commands {{{2 set shell=zsh set keywordprg= " Encoding {{{2 " Note: if 'fileencoding' is empty, 'encoding' is used. set fileencodings=utf-8,cp932,euc-jp set termencoding=utf-8 " Misc. {{{2 set maxfuncdepth=50 set sessionoptions+=localoptions \ sessionoptions+=resize \ sessionoptions+=winpos let &viminfo .= ',n' . g:MY_ENV.cache_dir . '/viminfo' " Installed plugins {{{1 " === BEGIN === {{{2 execute 'set runtimepath+=' . g:MY_ENV.config_dir call plug#begin(g:MY_ENV.plug_dir) " Text editing {{{2 " IME {{{3 " SKK (Simple Kana to Kanji conversion program) for Vim. Plug 'vim-skk/eskk.vim' " Operators {{{3 " Support for user-defined operators. Plug 'kana/vim-operator-user' " Extract expression and make assingment statement. Plug 'tek/vim-operator-assign' " Replace text without updating registers. Plug 'kana/vim-operator-replace' " Reverse text. Plug 'tyru/operator-reverse.vim' " Search in a specific region. Plug 'osyo-manga/vim-operator-search' " Shiffle text. Plug 'pekepeke/vim-operator-shuffle' " Sort text characterwise and linewise. Plug 'emonkak/vim-operator-sort' " Super surround. Plug 'machakann/vim-sandwich' " Non-operators {{{3 " Comment out. Plug 'tyru/caw.vim' " Align text. Plug 'junegunn/vim-easy-align', { 'on': '(EasyAlign)' } " Text objects {{{2 " Support for user-defined text objects. Plug 'kana/vim-textobj-user' " Text object for blockwise. Plug 'osyo-manga/vim-textobj-blockwise' " Text object for comment. Plug 'thinca/vim-textobj-comment' " Text object for continuous line. Plug 'rhysd/vim-textobj-continuous-line' " Text object for entire file. Plug 'kana/vim-textobj-entire' " Text object for function. Plug 'kana/vim-textobj-function' " Text object for indent. Plug 'kana/vim-textobj-indent' " Text object for last inserted text. Plug 'rhysd/vim-textobj-lastinserted' " Text object for last pasted text. Plug 'gilligan/textobj-lastpaste' " Text object for last searched pattern. Plug 'kana/vim-textobj-lastpat' " Text object for line. Plug 'kana/vim-textobj-line' " Text object for parameter. Plug 'sgur/vim-textobj-parameter' " Text object for space. Plug 'saihoooooooo/vim-textobj-space' " Text object for syntax. Plug 'kana/vim-textobj-syntax' " Text object for URL. Plug 'mattn/vim-textobj-url' " Text object for words in words. Plug 'h1mesuke/textobj-wiw' " Search {{{2 " Extend * and #. Plug 'haya14busa/vim-asterisk' " Extend incremental search. Plug 'haya14busa/incsearch.vim' " NOTE: it is a fork version of jremmen/vim-ripgrep " Integration with ripgrep, fast alternative of grep command. Plug 'nsfisis/vim-ripgrep', { 'on': 'Rg' } " Files {{{2 " Switch to related files. Plug 'kana/vim-altr' " Fast Fuzzy Finder. Plug 'ctrlpvim/ctrlp.vim', { 'on': '(ctrlp)' } " CtrlP's matcher by builtin `matchfuzzy()`. Plug 'mattn/ctrlp-matchfuzzy', { 'on': '(ctrlp)' } " Filer for minimalists. Plug 'justinmk/vim-dirvish' " Appearance {{{2 " Show highlight. Plug 'cocopon/colorswatch.vim', { 'on': 'ColorSwatchGenerate' } " NOTE: it is a fork of godlygeek/csapprox " Make gui-only color schemes 256colors-compatible. Plug 'nsfisis/csapprox' " Makes folding text cool. Plug 'LeafCage/foldCC.vim' " Show indent. Plug 'Yggdroot/indentLine' " Cool status line. Plug 'itchyny/lightline.vim' " Highlight matched parentheses. Plug 'itchyny/vim-parenmatch' " Highlight specified words. Plug 't9md/vim-quickhl', { 'on': [ 'QuickhlManualReset', '(quickhl-manual-this)'] } " Filetypes {{{2 " Syntax {{{3 " HCL Plug 'b4b4r07/vim-hcl' " JavaScript Plug 'pangloss/vim-javascript', { 'for': 'javascript' } " JSON5 Plug 'GutenYe/json5.vim' " MoonScript Plug 'leafo/moonscript-vim' " Nginx conf Plug 'chr4/nginx.vim' " Rust Plug 'rust-lang/rust.vim', { 'for': 'rust' } " TOML Plug 'cespare/vim-toml', { 'for': 'toml' } " TypeScript Plug 'leafgarland/typescript-vim', { 'for': 'typescript' } " Tools {{{3 " C/C++: clang-format Plug 'rhysd/vim-clang-format', { 'for': ['c', 'cpp'] } " Python: autopep8 Plug 'tell-k/vim-autopep8', { 'for': 'python' } " QoL {{{2 " If a directory is missing, make it automatically. Plug 'mopp/autodirmake.vim' " Capture the output of a command. Plug 'tyru/capture.vim' " Write git commit message. Plug 'rhysd/committia.vim' " Motion on speed. Plug 'easymotion/vim-easymotion', { 'on': [ \ '(easymotion-Fl)', \ '(easymotion-N)', \ '(easymotion-Tl)', \ '(easymotion-bd-w)', \ '(easymotion-fl)', \ '(easymotion-j)', \ '(easymotion-k)', \ '(easymotion-n)', \ '(easymotion-s2)', \ '(easymotion-tl)', \ ] } " Integration with EditorConfig (https://editorconfig.org) Plug 'editorconfig/editorconfig-vim' " Extend J. Plug 'osyo-manga/vim-jplus' " Improve behaviors of I, A and gI in Blockwise-Visual mode. Plug 'kana/vim-niceblock' " Edit QuickFix and reflect to original buffers. Plug 'thinca/vim-qfreplace' " Run anything. Plug 'thinca/vim-quickrun' " Extend dot-repeat. Plug 'tpope/vim-repeat' " Split one line format and Join multiline format. Plug 'AndrewRadev/splitjoin.vim' " Introduce user-defined mode. Plug 'kana/vim-submode' " Swap arguments. Plug 'machakann/vim-swap' " Adjust window size. Plug 'rhysd/vim-window-adjuster' " Remember yank history and paste them. Plug 'LeafCage/yankround.vim' " === END === {{{2 Plug g:MY_ENV.my_dir call plug#end() " Autocommands {{{1 " Auto-resize windows when Vim is resized. Autocmd VimResized * wincmd = " Calculate 'numberwidth' to fit file size. " Note: extra 2 is the room of left and right spaces. Autocmd BufEnter,WinEnter,BufWinEnter * \ let &l:numberwidth = len(line('$')) + 2 " Jump to the last cursor position when you open a file. Autocmd BufRead * \ if 0 < line("'\"") && line("'\"") <= line('$') && \ &filetype !~# 'commit' && &filetype !~# 'rebase' | \ execute "normal g`\"" | \ endif " Syntax highlight for .vimrc {{{2 Autocmd Filetype vim \ if expand('%') =~? 'vimrc' || expand('%') =~? 'init.vim' | \ call s:highlight_vimrc() | \ endif function! s:highlight_vimrc() abort " Autocmd syn keyword vimrcAutocmd Autocmd skipwhite nextgroup=vimAutoEventList " Plugin manager command syn keyword vimrcPluginManager Plug hi def link vimrcAutocmd vimAutocmd hi def link vimrcPluginManager vimCommand endfunction Autocmd ColorScheme ocean call s:extra_highlight() function! s:extra_highlight() abort if &background != 'dark' return endif hi! link YankRoundRegion DiffChange hi! link OperatorSandwichBuns DiffChange hi! link OperatorSandwichStuff DiffChange hi! link OperatorSandwichDelete DiffChange hi! link OperatorSandwichAdd OperatorSandwichBuns hi EasyMotionShade guifg=#4d4d4d guibg=NONE gui=NONE cterm=NONE hi EasyMotionTarget guifg=#ff7100 guibg=NONE gui=underline cterm=underline hi! link EasyMotionMoveHL IncSearch endfunction " Mappings {{{1 " Note: |:noremap| defines mappings in |Normal|, |Visual|, |Operator-Pending| " and |Select| mode. Because I don't use |Select| mode, I use |:noremap| as " substitute of |:nnoremap|, |:xnoremap| and |:onoremap| for simplicity. " Fix the search direction. {{{2 noremap gn v:searchforward ? 'gn' : 'gN' noremap gN v:searchforward ? 'gN' : 'gn' noremap n v:searchforward ? 'n' : 'N' noremap N v:searchforward ? 'N' : 'n' nnoremap & :%&& xnoremap & :%&& " Registers and macros. {{{2 " Access an resister in the same way in Insert and Commandline mode. nnoremap " xnoremap " " Paste clipboard content with 'paste' enabled function! s:paste_clipboard_content_with_paste_opt() abort let old_paste = &paste set paste set pastetoggle=(pastetoggle) if old_paste return "\+" else " 'paste' was off when the function was called. Then, 'paste' will be " disabled via 'pastetoggle'. return "\+\(pastetoggle)" endif endfunction " Automatically enable 'paste' and disable it after pasting clipboard's " content. inoremap + paste_clipboard_content_with_paste_opt() let @j = 'j.' let @k = 'k.' let @n = 'n.' nnoremap @N N. " Repeat the last executed macro as many times as possible. " a => all " Note: "let @a = '@@'" does not work well. nnoremap @a 9999@@ " Execute the last executed macro again. nnoremap ` @@ " Emacs like key mappings in Insert and CommandLine mode. {{{2 function! s:go_to_beginning_of_line() abort if col('.') == match(getline('.'), '\S') + 1 return repeat("\U\", col('.') - 1) else return (col('.') < match(getline('.'), '\S')) ? \ repeat("\U\", match(getline('.'), '\S') - col('.') + 1) : \ repeat("\U\", col('.') - 1 - match(getline('.'), '\S')) endif endfunction inoremap " Go elsewhere without deviding the undo history. inoremap go_to_beginning_of_line() inoremap repeat('U', col('$') - col('.')) inoremap U inoremap U " Delete something deviding the undo history. inoremap u inoremap u cnoremap cnoremap cnoremap cnoremap cnoremap cnoremap cnoremap cnoremap inoremap cnoremap inoremap function! s:my_gA() let line = getline('.') if match(line, ';;$') != -1 " For OCaml. return "A\U\\U\" elseif match(line, '[,;)]$') != -1 return "A\U\" else return 'A' endif endfunction nnoremap gA my_gA() " QuickFix or location list. {{{2 nnoremap bb :cc nnoremap bn :=v:count1cnext nnoremap bp :=v:count1cprevious nnoremap bf :cfirst nnoremap bl :clast nnoremap bS :colder nnoremap bs :cnewer " Operators {{{2 " Throw deleted text into the black hole register ("_). nnoremap c "_c xnoremap c "_c nnoremap C "_C xnoremap C "_C noremap g= = noremap ml gu noremap mu gU noremap gu noremap gU xnoremap u xnoremap U xnoremap x "_x nnoremap Y y$ " In Blockwise-Visual mode, select text linewise. " In default, select text characterwise, neither blockwise nor linewise. xnoremap Y mode() ==# 'V' ? 'y' : 'Vy' " Swap the keys entering Replace mode and Visual-Replace mode. nnoremap R gR nnoremap gR R nnoremap r gr nnoremap gr r nnoremap U " Motions {{{2 noremap H ^ noremap L $ noremap M % noremap gw b noremap gW B noremap k gk noremap j gj noremap gk k noremap gj j nnoremap gff gF " Tabpages and windows. {{{2 function! s:move_current_window_to_tabpage() abort if winnr('$') == 1 " Leave the current window and open it in a new tabpage. " Because :wincmd T fails when the current tabpage has only one window. tab split else " Close the current window and re-open it in a new tabpage. wincmd T endif endfunction function! s:bdelete_bang_with_confirm() abort if s:getchar_with_prompt('Delete? (y/n) ') ==? 'y' bdelete! else echo 'Canceled' endif endfunction function! s:choose_window_interactively() abort const indicators = [ \ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', \ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', \ ] " List normal windows up to 20. let wins = [] for winnr in range(1, winnr('$')) if winnr !=# winnr() && win_gettype(winnr) ==# '' call add(wins, win_getid(winnr)) endif endfor if len(indicators) < len(wins) unlet wins[len(indicators):] endif if len(wins) ==# 0 return endif if len(wins) ==# 1 if wins[0] ==# win_getid() call win_gotoid(wins[1]) else call win_gotoid(wins[0]) endif return endif " Show popups. let popups = [] for i in range(len(wins)) let winid = wins[i] let indicator = indicators[i] let [winy, winx, winh, winw] = s:win_getrect(winid) if has('nvim') let buf_id = nvim_create_buf(v:false, v:true) call nvim_buf_set_lines(buf_id, 0, -1, v:true, ['', ' ' . indicator . ' ', '']) let popup = nvim_open_win( \ buf_id, \ v:false, \ { \ 'relative': 'win', \ 'win': winid, \ 'row': (winh - 5) / 2, \ 'col': (winw - 9) / 2, \ 'width': 5, \ 'height': 3, \ 'focusable': v:false, \ 'style': 'minimal', \ 'border': 'double', \ 'noautocmd': v:true, \ }) else let popup = popup_create(indicator, #{ \ line: winy + (winh - 5) / 2, \ col: winx + (winw - 9) / 2, \ drag: v:false, \ resize: v:false, \ padding: [1, 3, 1, 3], \ border: [], \ }) endif call add(popups, #{ \ winid: popup, \ indicator: indicator, \ target_winid: winid, \ }) endfor " Prompt let result = s:getchar_with_prompt('Select window: ') " Jump let jump_target = -1 for popup in popups if result ==? popup.indicator let jump_target = popup.target_winid endif endfor if jump_target !=# -1 call win_gotoid(jump_target) endif " Close popups for popup in popups if has('nvim') call nvim_win_close(popup.winid, v:true) else call popup_close(popup.winid) endif endfor endfunction nnoremap tt :tabnew nnoremap tT :call move_current_window_to_tabpage() nnoremap tn :=(tabpagenr() + v:count1 - 1) % tabpagenr('$') + 1tabnext nnoremap tp :=(tabpagenr('$') * 10 + tabpagenr() - v:count1 - 1) % tabpagenr('$') + 1tabnext nnoremap tN :tabmove + nnoremap tP :tabmove - nnoremap tsh :leftabove vsplit nnoremap tsj :rightbelow split nnoremap tsk :leftabove split nnoremap tsl :rightbelow vsplit nnoremap tsH :topleft vsplit nnoremap tsJ :botright split nnoremap tsK :topleft split nnoremap tsL :botright vsplit nnoremap twh :leftabove vnew nnoremap twj :rightbelow new nnoremap twk :leftabove new nnoremap twl :rightbelow vnew nnoremap twH :topleft vnew nnoremap twJ :botright new nnoremap twK :topleft new nnoremap twL :botright vnew nnoremap th h nnoremap tj j nnoremap tk k nnoremap tl l nnoremap tH H nnoremap tJ J nnoremap tK K nnoremap tL L nnoremap tx x " r => manual resize. " R => automatic resize. nnoremap tRH _ nnoremap tRW nnoremap tRR _ nnoremap t= = nnoremap tq :bdelete nnoremap tQ :call bdelete_bang_with_confirm() nnoremap tc c nnoremap to o nnoremap tO :tabonly if has('popupwin') || has('nvim') nnoremap tg :call choose_window_interactively() endif function! s:smart_open(command) abort if winwidth(winnr()) < 150 let modifiers = 'topleft' else let modifiers = 'vertical botright' endif try execute modifiers a:command catch echohl Error echo v:exception echohl None return endtry if &filetype ==# 'help' if &l:textwidth > 0 execute 'vertical resize' &l:textwidth endif " Help tags are often right-justfied, moving the cursor to BoL. normal! 0 endif endfunction command! -nargs=+ -complete=command \ SmartOpen \ call s:smart_open() " Increment/decrement numbers {{{2 " nnoremap + " nnoremap - " xnoremap + " xnoremap - " xnoremap g+ g " xnoremap g- g " Disable unuseful or dangerous mappings. {{{2 " Disable Select mode. nnoremap gh nnoremap gH nnoremap g " Disable Ex mode. nnoremap Q nnoremap gQ nnoremap ZZ nnoremap ZQ " Help {{{2 " Search help. nnoremap :SmartOpen help " For writing Vim script. {{{2 if !v:vim_did_enter " Define this function only when Vim is starting up. |v:vim_did_enter| function! SourceThisFile() abort let filename = expand('%') if &filetype ==# 'vim' || expand('%:e') ==# 'vim' || filename =~# '\.g\?vimrc' if &filetype !=# 'vim' setfiletype vim endif update unlet! g:loaded_{expand('%<')} source % else echo filename ' is not a Vim Script.' endif endfunction endif nnoremap XV :tabedit $MYVIMRC nnoremap XX :call SourceThisFile() " See |numbered-function|. nnoremap XF :function {=v:count} nnoremap XM :messages nnoremap XP :call popup_clear(1) " Misc. {{{2 onoremap gv :normal! gv " Swap : and ;. nnoremap ; : nnoremap : ; xnoremap ; : xnoremap : ; nnoremap @; @: xnoremap @; @: cnoremap ; : inoremap ; : " Since may be mapped to something else somewhere, it should be :map, not " :noremap. imap jk cmap jk nnoremap :nohlsearch nnoremap (my-insert-blank-lines-after) \ :call insert_blank_line(0) nnoremap (my-insert-blank-lines-before) \ :call insert_blank_line(1) nmap go (my-insert-blank-lines-after) nmap gO (my-insert-blank-lines-before) function! s:insert_blank_line(offset) abort for i in range(v:count1) call append(line('.') - a:offset, '') endfor endfunction nnoremap w :write " Abbreviations {{{1 inoreabbrev retrun return inoreabbrev reutrn return inoreabbrev tihs this " Commands {{{1 " Set 'makeprg' to `ninja` if `build.ninja` exists in the current working " directory. Then, execute :make command. command! -bang -bar -nargs=* \ Make \ if filereadable('build.ninja') | \ let &makeprg = 'ninja' | \ endif | \ make " Reverse a selected range in line-wise. " Note: directly calling `g/^/m` will overwrite the current search pattern with " '^' and highlight it, which is not expected. " :h :keeppatterns command! -bar -range=% \ Reverse \ keeppatterns ,g/^/m-1 function! s:dummy_man_command(mods, args) abort " Delete the dummy command. delcommand Man " Load man.vim which defines |:Man|. runtime ftplugin/man.vim " Pass the given arguments to it. execute printf("%s Man %s", a:mods, a:args) endfunction " To shorten Vim startup, lazily load ftplugin/man.vim. command! -complete=shellcmd -nargs=+ \ Man \ call s:dummy_man_command(, ) " ftplugin {{{1 " This command do the followings: " * Execute |:setlocal| for each options. " * Set information to restore the original setting to b:|undo_ftplugin|. " This command is used in ftplugin/*.vim. " Note: specify only single option. command! -nargs=+ \ FtpluginSetLocal \ call s:ftplugin_setlocal() function! s:ftplugin_setlocal(qargs) abort execute 'setlocal' a:qargs let option_name = substitute(a:qargs, '\L.*', '', '') if option_name ==# 'shiftwidth' && exists(':IndentLinesReset') ==# 2 IndentLinesReset endif if exists('b:undo_ftplugin') let b:undo_ftplugin .= '|setlocal ' . option_name . '<' else let b:undo_ftplugin = 'setlocal ' . option_name . '<' endif endfunction " Color scheme {{{1 " A command which changes color scheme with fall back. command! -bang -nargs=? \ ColorScheme \ call s:colorscheme(0, ) function! s:colorscheme(bang, name) abort try if get(g:, 'colors_name') isnot# a:name || a:bang execute 'colorscheme' a:name endif catch " Loading colorscheme failed. " The color scheme, "desert", is one of the built-in ones. Probably, it " will be loaded without any errors. colorscheme desert endtry endfunction ColorScheme! ocean " Plugins configuration {{{1 " Disable standard plugins. {{{2 let g:loaded_2html_plugin = 1 let g:loaded_getscriptPlugin = 1 let g:loaded_gzip = 1 let g:loaded_logiPat = 1 let g:loaded_matchparen = 1 let g:loaded_netrwPlugin = 1 let g:loaded_rrhelper = 1 let g:loaded_spellfile_plugin = 1 let g:loaded_tarPlugin = 1 let g:loaded_vimballPlugin = 1 let g:loaded_zipPlugin = 1 " altr {{{2 " For vim call altr#define('autoload/%.vim', 'doc/%.txt', 'plugin/%.vim') " For C and C++ call altr#define('%.c', '%.cpp', '%.cc', '%.h', '%.hh', '%.hpp') " Go to File Alternative nmap gfa (altr-forward) " asterisk {{{2 function! s:asterisk(ret, keeppos) let g:asterisk#keeppos = a:keeppos return a:ret endfunction " Do not keep the relative cursor position. nmap * asterisk('(asterisk-z*)', 0) omap * asterisk('(asterisk-z*)', 0) xmap * asterisk('(asterisk-z*)', 0) nmap g* asterisk('(asterisk-gz*)', 0) omap g* asterisk('(asterisk-gz*)', 0) xmap g* asterisk('(asterisk-gz*)', 0) " Keep the relative cursor position (use offset like /s+1). " Note: I fix the search direction in typing 'n' and 'N', so there is no " difference between '*' and '#'. nmap # asterisk('(asterisk-z*)', 1) omap # asterisk('(asterisk-z*)', 1) xmap # asterisk('(asterisk-z*)', 1) nmap g# asterisk('(asterisk-gz*)', 1) omap g# asterisk('(asterisk-gz*)', 1) xmap g# asterisk('(asterisk-gz*)', 1) " autodirmake {{{2 let g:autodirmake#msg_highlight = 'Question' " autopep8 {{{2 let g:autopep8_on_save = 1 let g:autopep8_disable_show_diff = 1 command! \ Autopep8Disable \ let g:autopep8_on_save = 0 " caw {{{2 let g:caw_no_default_keymappings = 1 nmap m// (caw:hatpos:toggle) xmap m// (caw:hatpos:toggle) nmap m/w (caw:wrap:comment) xmap m/w (caw:wrap:comment) nmap m/W (caw:wrap:uncomment) xmap m/W (caw:wrap:uncomment) nmap m/b (caw:box:comment) xmap m/b (caw:box:comment) " clang-format {{{2 let g:clang_format#auto_format = 1 Autocmd FileType javascript ClangFormatAutoDisable Autocmd FileType typescript ClangFormatAutoDisable " ctrlp {{{2 let g:ctrlp_map = 'f' let g:ctrlp_match_func = {'match': 'ctrlp_matchfuzzy#matcher'} " dirvish {{{2 " Prevent dirvish from mapping hyphen key to "(dirvish_up)". " nmap (nomap-dirvish_up) (dirvish_up) " easyalign {{{2 nmap = (EasyAlign) xmap = (EasyAlign) " easymotion {{{2 let g:EasyMotion_keys = 'asdfghweryuiocvbnmjkl;' let g:EasyMotion_space_jump_first = 1 let g:EasyMotion_do_shade = 0 let g:EasyMotion_do_mappings = 0 let g:EasyMotion_smartcase = 1 let g:EasyMotion_verbose = 0 let g:EasyMotion_startofline = 0 nmap f (easymotion-fl) omap f (easymotion-fl) xmap f (easymotion-fl) nmap F (easymotion-Fl) omap F (easymotion-Fl) xmap F (easymotion-Fl) omap t (easymotion-tl) xmap t (easymotion-tl) omap T (easymotion-Tl) xmap T (easymotion-Tl) " Note: Don't use the following key sequences! It is used 'vim-sandwich'. " * sa " * sd " * sr nmap ss (easymotion-s2) omap ss (easymotion-s2) xmap ss (easymotion-s2) nmap sw (easymotion-bd-w) omap sw (easymotion-bd-w) xmap sw (easymotion-bd-w) nmap sn (easymotion-n) omap sn (easymotion-n) xmap sn (easymotion-n) nmap sN (easymotion-N) omap sN (easymotion-N) xmap sN (easymotion-N) nmap sj (easymotion-j) omap sj (easymotion-j) xmap sj (easymotion-j) nmap sk (easymotion-k) omap sk (easymotion-k) xmap sk (easymotion-k) " eskk {{{2 let g:eskk#dictionary = { \ 'path': g:MY_ENV.skk_dir . '/jisyo', \ 'sorted': 0, \ 'encoding': 'utf-8', \ } let g:eskk#large_dictionary = { \ 'path': g:MY_ENV.skk_dir . '/jisyo.L', \ 'sorted': 1, \ 'encoding': 'euc-jp', \ } let g:eskk#backup_dictionary = g:eskk#dictionary.path . ".bak" let g:eskk#kakutei_when_unique_candidate = v:true let g:eskk#enable_completion = v:false " let g:eskk#no_default_mappings = v:true function! s:eskk_initialize_pre() abort let t = eskk#table#new('rom_to_hira*', 'rom_to_hira') 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 eskk#register_mode_table('hira', t) endfunction Autocmd User eskk-initialize-pre call s:eskk_initialize_pre() function! s:eskk_initialize_post() abort " 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 EskkMap -type=disable l endfunction Autocmd User eskk-initialize-post call s:eskk_initialize_post() " foldcc {{{2 set foldtext=FoldCCtext() let g:foldCCtext_head = 'repeat(">", v:foldlevel) . " "' " incsearch {{{2 " let g:incsearch#magic = '\v' nmap / (incsearch-forward) omap / (incsearch-forward) xmap / (incsearch-forward) nmap ? (incsearch-backward) omap ? (incsearch-backward) xmap ? (incsearch-backward) nmap g/ (incsearch-stay) omap g/ (incsearch-stay) xmap g/ (incsearch-stay) " indentline {{{2 let g:indentLine_conceallevel = 1 let g:indentLine_fileTypeExclude = ['help'] " jplus {{{2 let g:jplus#input_config = { \ '__DEFAULT__': {'delimiter_format': ' %d '}, \ '__EMPTY__': {'delimiter_format': ''}, \ ' ': {'delimiter_format': ' '}, \ ',': {'delimiter_format': '%d '}, \ ';': {'delimiter_format': '%d '}, \ 'l': {'delimiter_format': ''}, \ 'L': {'delimiter_format': ''}, \ "\": {'delimiter_format': '%d'}, \ } nmap J (jplus-getchar) xmap J (jplus-getchar) nmap gJ (jplus-input) xmap gJ (jplus-input) " lightline {{{2 let g:lightline = { \ 'colorscheme': 'jellybeans', \ 'active': { \ 'left': [['mode', 'paste'], ['readonly', 'filename', 'modified']], \ 'right': [['linenum'], ['fileencoding', 'fileformat', 'filetype']] \ }, \ 'inactive': { \ 'left': [['readonly', 'filename', 'modified']], \ 'right': [['linenum'], ['fileencoding', 'fileformat', 'filetype']] \ }, \ 'component_function': { \ 'mode': 'Lightline_mode', \ 'linenum': 'Lightline_linenum', \ 'fileformat': 'Lightline_fileformat', \ }, \ 'mode_map': { \ 'n' : 'N', \ 'i' : 'I', \ 'R' : 'R', \ 'v' : 'V', \ 'V' : 'V-L', \ "\": 'V-B', \ 'c' : 'C', \ 's' : 'S', \ 'S' : 'S-L', \ "\": 'S-B', \ 't': 'T', \ }, \ 'tabline': { \ 'left': [['tabs']], \ 'right': [], \ }, \ 'tab': { \ 'active': ['tabnum', 'filename', 'modified'], \ 'inactive': ['tabnum', 'filename', 'modified'], \ }, \ } function! Lightline_mode() " Calling `eskk#statusline()` makes Vim autoload eskk. If you call it " without checking `g:loaded_autoload_eskk`, eskk is loaded on an early " stage of the initialization (probably the first rendering of status line), " which slows down Vim startup. Loading eskk can be delayed by checking both " of `g:loaded_eskk` and `g:loaded_autoload_eskk`. if exists('g:loaded_eskk') && exists('g:loaded_autoload_eskk') let skk = eskk#statusline(' (%s)', '') else let skk = '' endif return lightline#mode() . skk endfunction function! Lightline_linenum() return line('.') . '/' . line('$') endfunction function! Lightline_fileformat() if &fileformat ==# 'unix' return 'LF' elseif &fileformat ==# 'dos' return 'CRLF' elseif &fileformat ==# 'mac' return 'CR' else return '-' endif endfunction " vim-lsp {{{2 " TODO " niceblock {{{2 xmap I (niceblock-I) xmap gI (niceblock-gI) xmap A (niceblock-A) " operator-replace {{{2 nmap (operator-replace) omap (operator-replace) xmap (operator-replace) " operator-search {{{2 " Note: m/ is the prefix of comment out. nmap m? (operator-search) omap m? (operator-search) xmap m? (operator-search) " prettyprint {{{2 let g:prettyprint_indent = 2 let g:prettyprint_string = ['split'] let g:prettyprint_show_expression = 1 " qfreplace {{{2 nnoremap br :Qfreplace SmartOpen " quickhl {{{2 " TODO: CUI let 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', \ ] nmap " (quickhl-manual-this) xmap " (quickhl-manual-this) nnoremap :nohlsearch QuickhlManualReset " quickrun {{{2 let g:quickrun_no_default_key_mappings = 1 if !exists('g:quickrun_config') let g:quickrun_config = {} endif let g:quickrun_config.cpp = { \ 'cmdopt': '--std=c++17 -Wall -Wextra', \ } let g:quickrun_config.d = { \ 'exec': 'dub run', \ } let g:quickrun_config.haskell = { \ 'exec': ['stack build', 'stack exec %{matchstr(globpath(".,..,../..,../../..", "*.cabal"), "\\w\\+\\ze\\.cabal")}'], \ } let g:quickrun_config.python = { \ 'command': 'python3', \ } nmap BB (quickrun) xmap BB (quickrun) " nnoremap BB make " repeat {{{2 nmap U (RepeatRedo) " Autoload vim-repeat immediately in order to make (RepeatRedo) available. " repeat#setreg() does nothing here. call repeat#setreg('', '') " Make them repeatable with vim-repeat. nnoremap (my-insert-blank-lines-after) \ :call insert_blank_line(0) \ silent! call repeat#set("\Plug>(my-insert-blank-lines-after)") nnoremap (my-insert-blank-lines-before) \ :call insert_blank_line(1) \ silent! call repeat#set("\Plug>(my-insert-blank-lines-before)") " ripgrep {{{2 " Workaround: do not open quickfix window. " exe g:rg_window_location 'copen' let g:rg_window_location = 'silent! echo' let g:rg_jump_to_first = 1 command! -bang -nargs=* -complete=file -bar \ RG \ Rg " rust {{{2 let g:rustfmt_autosave = 1 " sandwich {{{2 " splitjoin {{{2 " Note: Don't use J{any sign}, 'Jl' and 'JL'. They will conflict with 'vim-jplus'. let g:splitjoin_split_mapping = '' let g:splitjoin_join_mapping = '' nnoremap JS :SplitjoinSplit nnoremap JJ :SplitjoinJoin " submode {{{2 " Global settings {{{3 let g:submode_always_show_submode = 1 let g:submode_keyseqs_to_leave = ['', ''] let g:submode_keep_leaving_key = 1 " yankround {{{3 call submode#enter_with('YankRound', 'nv', 'rs', 'gp', '(yankround-p)') call submode#enter_with('YankRound', 'nv', 'rs', 'gP', '(yankround-P)') call submode#map('YankRound', 'nv', 'rs', 'p', '(yankround-prev)') call submode#map('YankRound', 'nv', 'rs', 'P', '(yankround-next)') " swap {{{3 call submode#enter_with('Swap', 'n', 'r', 'g>', '(swap-next)') call submode#map('Swap', 'n', 'r', '<', '(swap-prev)') call submode#enter_with('Swap', 'n', 'r', 'g<', '(swap-prev)') call submode#map('Swap', 'n', 'r', '>', '(swap-next)') " Resizing a window (height) {{{3 call submode#enter_with('WinResizeH', 'n', '', 'trh') call submode#enter_with('WinResizeH', 'n', '', 'trh') call submode#map('WinResizeH', 'n', '', '+', '+') call submode#map('WinResizeH', 'n', '', '-', '-') " Resizing a window (width) {{{3 call submode#enter_with('WinResizeW', 'n', '', 'trw') call submode#enter_with('WinResizeW', 'n', '', 'trw') call submode#map('WinResizeW', 'n', '', '+', '>') call submode#map('WinResizeW', 'n', '', '-', '') " Super undo/redo {{{3 call submode#enter_with('Undo/Redo', 'n', '', 'gu', 'g-') call submode#map('Undo/Redo', 'n', '', 'u', 'g-') call submode#enter_with('Undo/Redo', 'n', '', 'gU', 'g+') call submode#map('Undo/Redo', 'n', '', 'U', 'g+') " swap {{{2 let g:swap_no_default_key_mappings = 1 " textobj-continuousline {{{2 let g:textobj_continuous_line_no_default_key_mappings = 1 omap aL (textobj-continuous-cpp-a) xmap aL (textobj-continuous-cpp-a) omap iL (textobj-continuous-cpp-i) xmap iL (textobj-continuous-cpp-i) Autocmd FileType vim omap aL (textobj-continuous-vim-a) Autocmd FileType vim xmap aL (textobj-continuous-vim-a) Autocmd FileType vim omap iL (textobj-continuous-vim-i) Autocmd FileType vim xmap iL (textobj-continuous-vim-i) " textobj-lastpaste {{{2 let g:textobj_lastpaste_no_default_key_mappings = 1 omap iP (textobj-lastpaste-i) xmap iP (textobj-lastpaste-i) omap aP (textobj-lastpaste-a) xmap aP (textobj-lastpaste-a) " textobj-space {{{2 let g:textobj_space_no_default_key_mappings = 1 omap a (textobj-space-a) xmap a (textobj-space-a) omap i (textobj-space-i) xmap i (textobj-space-i) " textobj-wiw {{{2 let g:textobj_wiw_no_default_key_mappings = 1 nmap (textobj-wiw-n) omap (textobj-wiw-n) xmap (textobj-wiw-n) nmap g (textobj-wiw-p) omap g (textobj-wiw-p) xmap g (textobj-wiw-p) nmap (textobj-wiw-N) omap (textobj-wiw-N) xmap (textobj-wiw-N) nmap g (textobj-wiw-P) omap g (textobj-wiw-P) xmap g (textobj-wiw-P) omap a (textobj-wiw-a) xmap a (textobj-wiw-a) omap i (textobj-wiw-i) xmap i (textobj-wiw-i) " window-adjuster {{{2 nnoremap tRw :AdjustScreenWidth nnoremap tRh :AdjustScreenHeight nnoremap tRr :AdjustScreenWidth AdjustScreenHeight " yankround {{{2 let g:yankround_dir = g:MY_ENV.cache_dir . '/yankround' let g:yankround_use_region_hl = 1 " Utilities {{{1 "" Wrapper of |getchar()|. function! s:getchar() let ch = getchar() while ch == "\" let ch = getchar() endwhile return type(ch) == v:t_number ? nr2char(ch) : ch endfunction "" Wrapper of |:echo| and |:echohl|. function! s:echo(message, ...) abort let highlight = get(a:000, 0, 'None') redraw execute 'echohl' highlight echo a:message echohl None endfunction "" Wrapper of |getchar()|. function! s:getchar_with_prompt(prompt) abort call s:echo(a:prompt) return s:getchar() endfunction "" Wrapper of |input()|. "" Only when it is used in a mapping, |inputsave()| and |inputstore()| are "" required. function! s:input(...) abort call inputsave() let result = call('input', a:000) call inputrestore() return result endfunction "" Wrapper of |win_screenpos()|, |winheight()| and |winwidth()|. "" Returns quadruple consisting of y, x, width and height. function! s:win_getrect(...) abort let win = get(a:000, 0, 0) let [y, x] = win_screenpos(win) let h = winheight(win) let w = winwidth(win) return [y, x, h, w] endfunction " Modelines {{{1 " vim: expandtab:softtabstop=4:shiftwidth=4:textwidth=80:colorcolumn=+1: " vim: foldenable:foldmethod=marker:foldlevel=0: