" == Naming convention. == {{{1
" Command name
"  - CamelCase
" Global function name
"  - CamelCase
" Local function name
"  - s:split_by_underbar
" Group name for autocmd
"  - split-by-dash
"    In vimrc, start with "vimrc"
"     - vimrc-{unique-name}
"    In vim plugin, start with "plugin"
"     - plugin-{plugin-name}
"     - plugin-{plugin-name}-{unique-name}
"    In other custom files, start with "custom"
"     - custom-{unique-name}

" == Initial process. == {{{1
" Startup time.
if !v:vim_did_enter && has('reltime')
  let g:startuptime = reltime()
  augroup vimrc-startuptime
    autocmd! VimEnter * ++once
    \                   let g:startuptime = reltime(g:startuptime)
    \                 | redraw
    \                 | echomsg 'startuptime: ' .. reltimestr(g:startuptime)
  augroup END
endif

if v:vim_did_enter
  command! -nargs=+ -bar Set setglobal <args>
else
  command! -nargs=+ -bar Set set <args>
endif

" == Encoding settings. == {{{1
" Use utf-8.
if &encoding !=? 'utf-8'
  let &termencoding = &encoding
  Set encoding=utf-8
endif

" Must after set of 'encoding'.
scriptencoding utf-8

if has('guess_encode')
  Set fileencodings=ucs-bom,utf-8,iso-2022-jp,guess,euc-jp,cp932,latin1
else
  Set fileencodings=ucs-bom,utf-8,iso-2022-jp,euc-jp,cp932,latin1
endif
Set fileformats=unix,dos

Set guioptions+=M

" runtimepath.
if $VIM_USERDIR ==# ''
  let $VIM_USERDIR =
  \ substitute(
  \   get(
  \     filter(
  \       map(['~/vimfiles', '~/.vim'], 'expand(v:val)'),
  \       'isdirectory(v:val)'
  \     ),
  \   0, ''),
  \ '\\\+', '/', 'g')
endif

if !v:vim_did_enter
  Set runtimepath&
  if !isdirectory(expand('~/vimfiles'))
    " Even Windows uses "$HOME/.vim".
    let &runtimepath = substitute(&runtimepath,
    \ escape($HOME, '\') .. '/vimfiles', escape($HOME, '\') .. '/.vim', 'g')
  endif
endif

" Interface dll  {{{2
if isdirectory($ASDF_DIR)
  let s:ext = has('mac') ? 'dylib' : 'so'
  let s:tool_versions = {}
  eval '~/.tool-versions'->expand()->readfile()
  \   ->map({ _, v -> split(v, '\s\+')->filter({ _, v -> v isnot# 'system' }) })
  \   ->map({ _, v -> extend(s:tool_versions, {v[0]: v[1 :]}) })

  " if_perl
  if exists('+perldll')
    let s:perl_ver = s:tool_versions->get('perl')->get(0)
    if s:perl_ver isnot# ''
      let &perldll =
      \   printf('%s/installs/perl/%s/lib/%s/x86_64-linux/CORE/libperl.%s',
      \     $ASDF_DIR, s:perl_ver, s:perl_ver, s:ext)
    endif
    unlet s:perl_ver
  endif

  " if_ruby
  if exists('+rubydll')
    let s:ruby_ver = s:tool_versions->get('ruby')->get(0)
    if s:ruby_ver isnot# ''
      let &rubydll =
      \   printf('%s/installs/ruby/%s/lib/libruby.%s',
      \     $ASDF_DIR, s:ruby_ver, s:ext)
    endif
    unlet s:ruby_ver
  endif

  " if_python
  let s:python_ver = s:tool_versions->get('python')
  if exists('+pythondll')
    let s:py_v2 = s:python_ver->copy()->filter({ _, v -> v =~# '^2' })->get(0)
    if s:py_v2 isnot# ''
      let &pythondll =
      \   printf('%s/installs/python/%s/lib/libpython%s.%s',
      \     $ASDF_DIR, s:py_v2, matchstr(s:py_v2, '^\d\+\.\d\+'), s:ext)
    endif
    unlet s:py_v2
  endif
  if exists('+pythonthreedll')
    let s:py_v3 = s:python_ver->copy()->filter({ _, v -> v =~# '^3' })->get(0)
    if s:py_v3 isnot# ''
      let &pythonthreedll =
      \   printf('%s/installs/python/%s/lib/libpython%s.%s',
      \     $ASDF_DIR, s:py_v3, matchstr(s:py_v3, '^\d\+\.\d\+'), s:ext)
    endif
    unlet s:py_v3
  endif
  unlet s:python_ver

  unlet s:ext s:tool_versions
endif
" }}}2

" Plugin Manager
let g:vimproc#download_windows_dll = 1
source <sfile>:h/dein.vim

" localrc.vim
let s:vim_config_dir = expand('~/.config/vim')
if dein#is_sourced('localrc')
  call localrc#load('local.pre.vim', s:vim_config_dir, 1)
  if !v:vim_did_enter
    call localrc#load('.init.vimrc', getcwd())
  endif
endif

" singleton.vim
if dein#is_sourced('singleton')
  call singleton#enable()
endif

" vital.vim
if dein#is_sourced('vital')
  " let g:vital_debug = 1
  let g:V = vital#vital#new().load(
  \  ['Prelude'],
  \  'Vim.Buffer',
  \  ['Vim.Compat', 'Compat'],
  \  ['Math'],
  \  ['DateTime'],
  \  ['System.Filepath', 'Path'],
  \  ['Process', 'P'],
  \  ['Data.List'],
  \  ['Data.String'],
  \  ['Data.Dict', 'Dict'],
  \  'Random',
  \  ['Vim.Message', 'Message'],
  \  ['Web.JSON', 'J'],
  \  ['Web.XML', 'X'],
  \  ['Web.HTTP'])
endif


" == Utilities for vimrc. == {{{1
let s:is_win = has('win32')

function s:SID() abort
  return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfunction

function s:SIDP() abort
  return '<SNR>' .. s:SID() .. '_'
endfunction

function s:check_flag(flag) abort
  for scope in [w:, b:, g:]
    let f = get(scope, a:flag, v:null)
    if f isnot v:null
      return f
    endif
  endfor
  return 0
endfunction

function s:toggle_flag(scope, name) abort
  let a:scope[a:name] = !get(a:scope, a:name, 0)
endfunction

function s:get_range(type, mode) abort
  if a:mode ==# 'o'
    let vm = {
    \ 'line' : 'V',
    \ 'char' : 'v',
    \ 'block' : "\<C-v>" }[a:type]
    let [sm, em] = ['[', ']']
    let save_sel = &selection
    set selection=inclusive
  elseif a:mode ==# 'v'
    let [vm, sm, em] = [a:type, '<', '>']
  else
    return ''
  end

  let save_reg = @"
  execute 'silent normal! `' .. sm .. vm .. '`' .. em .. 'y'
  let selected = @"
  let @" = save_reg
  if exists('save_sel')
    let &selection = save_sel
  endif
  return selected
endfunction

function s:clamp(value, min, max) abort
  return a:value < a:min ? a:min :
  \      a:max < a:value ? a:max :
  \                        a:value
endfunction


" == Appearance settings. == {{{1
syntax enable

augroup vimrc-highlight
  autocmd!
  autocmd ColorScheme * call s:highlight_additional()
augroup END

function s:highlight_additional() abort
  highlight CursorIM guibg=Red guifg=NONE
  let env = has('gui_running') ? 'gui' : 'cterm'
  for hl in ['TabLine', 'TabLineSel']
    let id = synIDtrans(hlID(hl))
    let bg = synIDattr(id, 'bg', env)
    let bg = bg =~# '^#\?\w\+$' ? env .. 'bg=' .. bg : ''
    let attrs = filter(['bold', 'italic', 'reverse', 'inverse',
    \                   'standout', 'underline', 'undercurl'],
    \                  'synIDattr(id, v:val, env)')
    let attr = empty(attrs) ? '' : env .. '=' .. join(attrs, ',')
    execute 'highlight' hl .. 'Number' env .. 'fg=Red' bg attr
    execute 'highlight' hl .. 'TabNumber' env .. 'fg=DarkCyan' bg attr
  endfor
endfunction

" colorscheme.
if !exists('g:colors_name')
  Set background=dark
  let g:gruvbox_contrast_dark = 'hard'
  try
    if !s:is_win || has('gui_running')
      " ['candycode', 'wuye', 'freya', 'leo']
      colorscheme gruvbox
    else  "CUI win32
      " ['oceandeep']
      colorscheme default
    endif
  catch
    colorscheme habamax
  endtry
endif


" Show (partial) command in the last line of the screen.
Set showcmd
" Show invisible characters.
Set list listchars=tab:^\ ,trail:_,extends:>,precedes:<
" Set list listchars=tab:^\ ,trail:␣,extends:>,precedes:<
Set nolinebreak showbreak=>
" Display the last line as much as possible in a window.
Set display=lastline

if has('directx') && &encoding ==# 'utf-8'
  Set renderoptions=type:directx
endif

Set matchpairs& matchpairs+=<:>

Set laststatus=2 statusline=%!MakeStatusLine()
Set showtabline=2 tabline=%!MakeTabLine()

" Don't show :intro when startup.
Set shortmess& shortmess+=I

if has('kaoriya') && s:is_win && has('gui_running')
  Set ambiwidth=auto
else
  Set ambiwidth=double
endif

Set helplang=ja,en

" Get character code on cursor with 'fileencoding'.
function GetCharacterCode() abort
  let str = matchstr(getline('.'), '.', col('.') - 1)
  let str = iconv(str, &encoding, &fileencoding)
  let out = '0x'
  if str ==# ''
    return out .. '00'
  endif
  for i in range(strlen(str))
    let out ..= printf('%02X', char2nr(str[i]))
  endfor
  return out
endfunction

" Return the current file size in human readable format.
function GetFileSize() abort
  if &encoding ==# &fileencoding || &fileencoding ==# ''
    let size = line2byte(line('$') + 1) - 1
  else
    let size = getfsize(expand('%'))
  endif

  if size < 0
    let size = 0
  endif
  for unit in ['B', 'KB', 'MB']
    if size < 1024
      return size .. unit
    endif
    let size = size / 1024
  endfor
  return size .. 'GB'
endfunction

function GetSyntaxInfo() abort
  let line = synstack(line('.'), col('.'))->map(
  \  'printf("%s (%s)", synIDattr(v:val, "name"), synIDattr(synIDtrans(v:val), "name"))'
  \ )->join(',')
endfunction

function STLBufnr() abort
  return s:check_flag('statusline_bufnr')
  \   ? printf('[%d] ', bufnr('%')) : ''
endfunction

function STLHighLight() abort
  return s:check_flag('statusline_highlight')
  \   ? printf('[%s]', GetSyntaxInfo()) : ''
endfunction

function STLCharacterCode() abort
  return s:check_flag('statusline_char')
  \   ? printf('[%s]', GetCharacterCode()) : ''
endfunction

function STLFileSize() abort
  return s:check_flag('statusline_filesize')
  \   ? printf('[%s]', GetFileSize()) : ''
endfunction

function GetBufname(...) abort
  let bufnr = get(a:000, 0, '')
  let tail = get(a:000, 1, 0)
  let bufname = bufname(bufnr)
  let buftype = getbufvar(bufnr, '&buftype')
  if bufname ==# ''
    if buftype ==# ''
      return '[No Name]'
    elseif buftype ==# 'quickfix'
      return '[Quickfix List]'
    elseif buftype ==# 'nofile' || buftype ==# 'acwrite'
      return '[Scratch]'
    endif
  endif
  if tail && bufname =~# '^[[:alnum:].+-]\+://'
    let head = matchstr(bufname, '^[[:alnum:].+-]\+://[^/]\+')
    let file = matchstr(bufname, '[^/]\+$')
    let short_path = head .. '/../' .. file
    return strwidth(bufname) < strwidth(short_path) ? bufnr : short_path
  endif
  if buftype ==# 'nofile' || buftype ==# 'acwrite'
    return bufname
  endif
  if tail
    return fnamemodify(bufname, ':t')
  endif
  if exists('b:lcd') && b:lcd !=# ''
    let fullpath = fnamemodify(bufname, ':p')
    let bufname = matchstr(fullpath, '^\V\(' .. escape(b:lcd, '\')
    \ .. '\v)?[/\\]?\zs.*')
    if exists('g:actual_curbuf')
      let actual_lcd = getbufvar(g:actual_curbuf - 0, 'lcd', '')
      if actual_lcd !=# '' && actual_lcd !=# b:lcd
        let bufname = '*' .. bufname
      endif
    endif
  endif
  return bufname
endfunction

function StatusLineExtra() abort
  let extra = ''
  for scope in ['w:', 'b:', 't:', 'g:']
    if exists(scope .. 'statusline_extra')
      let e = {scope .. 'statusline_extra'}
      if e[0] ==# '='
        let r = eval(e[1 :])
        let e = type(r) == v:t_string ? r : string(r)
      endif
      let extra ..= e
    endif
  endfor
  return extra
endfunction

function MakeStatusLine(...) abort
  let multi = a:0 && a:1
  let line = ''
  let line ..= '%{STLBufnr()}'  " Buffer number.
  let line ..= '%<'       " Truncate point.
  " Buffer name.
  let line ..= '%{GetBufname()}'
  if multi
    let line ..= '%@'
  else
    let line ..= ' '
  endif
  " Character encoding
  let line ..= '[%{(&fenc!=#"" ? &fenc : &enc) .. (&bomb ? "(BOM)" : "")}:'
  " File format (+ &binary and &endofline)
  if exists('+fixendofline')
    let line ..= '%{&ff .. (&bin?":bin":"") .. (&eol?"":":noeol")}]'
  else
    let line ..= '%{&ff .. (&bin?"(BIN" .. (&eol?"":"-noeol") .. ")":"")}]'
  endif
  let line ..= '%y'       " Filetype.
  let line ..= '%m'       " Modified flag.
  let line ..= '%r'       " Readonly flag.
  let line ..= '%{get(b:, "swapfile_exists", 0) ? "[swp]" : ""}'
  let line ..= '%h'       " Help buffer hlag.
  let line ..= '%w'       " Preview window flag.
  " The state of SKK.
  let line ..= '%{get(b:, "skk_on", 0) ? SkkGetModeStr() : ""}'
  if exists('*eskk#statusline')
    let line ..= '%{eskk#statusline()}'
  endif
  if exists('*Skkeleton_statusline')
    let line ..= '%{Skkeleton_statusline()}'
  endif
  if exists('*SyntasticStatuslineFlag')
    let line ..= '%{SyntasticStatuslineFlag()}'
  endif
  let line ..= '%{STLHighLight()}'
  let line ..= '%{StatusLineExtra()}'
  " let line ..= StatusLineExtra()
  let line ..= '%='       " Separation point.
  let line ..= '%{STLFileSize()}' " Rough file size.
  let line ..= '%{STLCharacterCode()}' " Character code under the cursor.
  let line ..= $LANG =~# '^ja' ? ' %l/%L行 %3v桁'
  \                            : ' %l/%LL %2vC'   " Line and column.
  let line ..= ' %3p%%'         " Percentage through file in lines.

  return line
endfunction

function s:buf_label(bufnr, i, is_cur) abort
  let label = GetBufname(a:bufnr, 1)
  if getbufvar(a:bufnr, '&modified')
    let label ..= '+'
  endif
  let curmark = a:is_cur ? '>' : ' '
  return printf(' %s%d) %s', curmark, a:i, label)
endfunction

function s:tabpage_label(n, ...) abort
  let is_sidebar = a:0 && a:1
  let n = a:n
  let bufnrs = tabpagebuflist(n)
  let curwinnr = tabpagewinnr(n)
  let curbufnr = bufnrs[curwinnr - 1]  " first window, first appears

  let hi = n == tabpagenr() ? 'TabLineSel' : 'TabLine'

  let label = printf('%%#%sTabNumber#%d:%%#%s# ', hi, n, hi)
  let label ..= '%<'
  let title = gettabvar(n, 'title')
  if is_sidebar && get(g:, 'tabsidebar_show_all_window', 0)
    let cwd = getcwd(curwinnr, n)
    let label ..= title !=# '' ? title : fnamemodify(cwd, ':t') .. '/'
    let labels = map(copy(bufnrs), { i, v ->
    \   s:buf_label(v, i + 1, curwinnr == i + 1)
    \ })
    let label ..= "\n" .. join(labels, "\n")
  elseif title !=# ''
    let label ..= title
  else
    let text = GetBufname(curbufnr, 1)
    let mod_bufs = filter(copy(bufnrs), 'getbufvar(v:val, "&modified")')
    let mod = len(mod_bufs) ? '+' : ''

    let label ..= text .. mod
    let no = len(bufnrs)
    if 2 <= no
      let label ..= ' %#' .. hi .. 'Number#' .. no
      let label ..= '%#' .. hi .. '#'
    endif
  endif

  return label
endfunction

function MakeTabLine() abort
  let sep = ' | '
  let has_tabsidebar = has('tabsidebar') &&
  \   (&g:showtabsidebar == 2 ||
  \    &g:showtabsidebar == 1 && 2 <= tabpagenr('$'))

  if has_tabsidebar
    let tabs = '%{GetBufname()}'
  else
    let titles = map(range(1, tabpagenr('$')), 's:tabpage_label(v:val)')
    let titles = map(titles, function('printf', ['%%%dT%s%%T%%#TabLineFill#']))
    let tabs = join(titles, sep) .. sep .. '%#TabLineFill#%T'
  endif
  let info = '%#TabLine#'
  if exists('t:tabline_extra')
    let info ..= t:tabline_extra .. sep
  endif
  if dein#is_sourced('current-func-info')
    let info ..= cfi#format('%s()' .. sep, '')
  endif
  if exists('*Uptime') && has_tabsidebar
    let info ..= Uptime(2) .. sep
  endif
  if dein#is_sourced('reanimate')
    let last_point = reanimate#last_point()
    if last_point =~# '^session/'
      let info ..= matchstr(last_point, '/\zs.*') .. sep
    endif
  endif
  if dein#is_sourced('gina')
    let branch = gina#component#repo#branch()
    if branch !=# ''
      let info ..= branch .. sep
    endif
  endif
  let cwd = fnamemodify(getcwd(), ':~')
  " TODO: vcs#root() occurs an error by unknown reason, and can not catch it
  let vcs_root = exists('*vcs#root') ? vcs#root(cwd) : ''
  if vcs_root !=# ''
    let vcs_root = fnamemodify(vcs_root, ':~')
    if len(vcs_root) < len(cwd)
      let cwd = substitute(vcs_root, '\([/\\][^/\\]\)[^/\\]*', '\1', 'g')
      \         .. cwd[len(vcs_root) :]
    endif
  endif
  let info ..= cwd .. ' '
  return tabs .. '%=' .. info
endfunction

if has('tabsidebar')
  function s:update_showtabsidebar() abort
    let &g:showtabsidebar = 80 * 2 + &g:tabsidebarcolumns <= &columns
  endfunction
  call s:update_showtabsidebar()
  Set tabsidebarcolumns=32
  Set tabsidebarwrap
  let g:tabsidebar_show_all_window = 1
  let g:tabsidebar_vertsplit = 1
  let &g:tabsidebar =
  \   '%!' .. get(function('s:tabpage_label'), 'name') ..
  \   '(g:actual_curtabpage, 1)'
  augroup tabsidebar-highlight
    autocmd!
    autocmd ColorScheme * highlight! link TabSideBar TabLine
    autocmd ColorScheme * highlight! link TabSideBarSel TabLineSel
    autocmd ColorScheme * highlight! link TabSideBarFill TabLineFill
  augroup END
  augroup tabsidebar-size
    autocmd!
    autocmd VimResized * call s:update_showtabsidebar()
  augroup END
  doautocmd tabsidebar-highlight ColorScheme
endif


" == Behavior settings. == {{{1
" Enable FileType
if v:vim_did_enter
  " To reapply 'ftdetect/*.vim'.
  filetype off
endif
filetype plugin indent on

" Search.
Set ignorecase smartcase incsearch hlsearch
if has('migemo')
  " 'migemo' option changes the behavior of "g?".
  " NOTE: 'migemo' option is local to buffer.
  Set nomigemo migemodict=$VIM_USERDIR/dict/migemo/migemo-dict
endif
if executable('rg')
  if executable('jq')
    let &grepprg = 'rg --json $* \| jq -r ''select(.type=="match")\|.data as $data\|$data.submatches[]\|"\($data.path.text):\($data.line_number):\(.start+1):\(.end+1):\($data.lines.text//""\|sub("\n$";""))"'''
    Set grepformat=%f:%l:%c:%k:%m
  else
    Set grepprg=rg\ --no-heading\ --column\ --color\ never
  endif
elseif executable('jvgrep')
  Set grepprg=jvgrep\ -RC
elseif executable('ag')
  Set grepprg=ag\ --nogroup\ --column\ --nocolor
  Set grepformat=%f:%l:%c:%m,%l:%c:%m
elseif executable('ack')
  Set grepprg=ack\ --nogroup\ --column\ --nocolor
else
  Set grepprg=internal
endif

" Tab and indent.
Set shiftround softtabstop=-1 shiftwidth=0 tabstop=2
Set autoindent copyindent preserveindent
Set breakindent
Set expandtab
Set cinoptions& cinoptions+=b1,l1,g0,N-s,(1s,m1
Set cinkeys& cinkeys+=0=break

" Auto reload when changed by external.
Set autoread
" Enable backspace.
Set backspace=indent,eol,start
" Allow move between line end and next line head.
Set whichwrap=b,s,<,>,[,]

if exists('+fixendofline')
  Set nofixendofline
endif

" Format settings for multi byte character.
Set formatoptions& formatoptions+=mM
Set formatoptions-=r formatoptions-=o formatoptions+=j formatoptions+=n
" The following needs autofmt plugin.
let g:plugin_format_disable = 1
Set formatexpr=autofmt#japanese#formatexpr()
" Minimal number of screen lines to keep above and below the cursor.
Set scrolloff=3
Set nostartofline
Set sidescroll=1 sidescrolloff=1
Set modeline

" Open a window.
Set splitbelow splitright
Set switchbuf& switchbuf+=useopen

" Completion.
Set complete& complete+=k
Set completeopt& completeopt+=menuone completeopt-=preview
Set infercase
" Command-line completion.
Set wildmenu wildmode=list:longest,full wildignorecase

" Foldings.
Set foldlevelstart=99

" History number for search and command mode.
Set history=1000

" Toggle Command-line mode and cmdwin with <C-c>
let &g:cedit = "\<C-c>"

Set timeoutlen=5000
Set ttimeout ttimeoutlen=50

Set nrformats& nrformats-=octal
if has('patch-8.2.0860')
  Set nrformats+=unsigned
endif

" spelling
Set spelllang& spelllang+=cjk
Set spelloptions& spelloptions+=camel
Set spellfile=~/.local/share/vim/spell/en.utf-8.add
call mkdir(expand('~/.local/share/vim/spell'), 'p')

" encryption
if has('crypt-blowfish2')
  Set cryptmethod=blowfish2
endif

" backup.
Set backup
Set backupdir=~/.cache/vim/backup//
" Paths of swap file and backup file.
if $TMP !=# ''
  execute 'Set backupdir+=' .. escape(expand($TMP), ' \')
elseif has('unix')
  Set backupdir+=/tmp
endif
Set directory=~/.cache/vim/swap//
if has('persistent_undo')
  Set undodir=~/.cache/vim/undo
  augroup vimrc-undofile
    autocmd!
    autocmd BufReadPre ~/* setlocal undofile
    if s:is_win
      autocmd BufReadPre D:/* setlocal undofile
    endif
  augroup END
endif
Set backupcopy=yes
Set viewdir=~/.cache/vim/view

call mkdir(expand('~/.cache/vim/backup'), 'p')
call mkdir(expand('~/.cache/vim/swap'), 'p')
call mkdir(expand('~/.cache/vim/undo'), 'p')

" Swap
Set swapfile
augroup vimrc-swapfile
  autocmd!
  autocmd SwapExists * call s:on_SwapExists()
augroup END

function s:on_SwapExists() abort
  if !filereadable(expand('<afile>'))
    let v:swapchoice = 'd'
    return
  endif
  let v:swapchoice = get(b:, 'swapfile_choice', 'o')
  unlet! b:swapfile_choice
  if v:swapchoice !=# 'd'
    let b:swapfile_exists = 1
  endif
endfunction

command! SwapfileRecovery call s:swapfile_recovery()
command! SwapfileDelete call s:swapfile_delete()

function s:swapfile_recovery() abort
  if get(b:, 'swapfile_exists', 0)
    let b:swapfile_choice = 'r'
    unlet b:swapfile_exists
    edit
  endif
endfunction

function s:swapfile_delete() abort
  if get(b:, 'swapfile_exists', 0)
    let b:swapfile_choice = 'd'
    unlet b:swapfile_exists
    edit
  endif
endfunction

if has('viminfo')
  " TELLME: The history is not saved in specified number.
  Set viminfo='500,<500,s50,h,rA:,rB:
end

" Free move in Visual mode blockwise.
Set virtualedit& virtualedit+=block

" Don't search tags file in current directory. And search upward.
Set tags& tags-=tags tags+=./tags;
Set tagcase=match


" autocmd
if has('multi_statusline')
  augroup vimrc-multi-statusline
    autocmd! BufEnter
    \ * if 80 < len(GetBufname())
    \ |   setlocal statusline=%!MakeStatusLine(1) statuslineheight=2
    \ | else
    \ |   setlocal statusline< statuslineheight<
    \ | endif
  augroup END
endif

augroup vimrc-auto-cursorline
  autocmd!
  autocmd CursorMoved,CursorMovedI * call s:auto_cursorline('CursorMoved')
  autocmd CursorHold,CursorHoldI * call s:auto_cursorline('CursorHold')
  autocmd WinEnter * call s:auto_cursorline('WinEnter')
  autocmd WinLeave * call s:auto_cursorline('WinLeave')

  let s:cursorline_lock = 0
  function s:auto_cursorline(event) abort
    if &l:buftype isnot# '' || get(b:, 'cursorline_disable', 0)
      return
    endif
    if a:event ==# 'WinEnter'
      setlocal cursorline
      let s:cursorline_lock = 2
    elseif a:event ==# 'WinLeave'
      setlocal nocursorline
    elseif a:event ==# 'CursorMoved'
      if s:cursorline_lock
        if 1 < s:cursorline_lock
          let s:cursorline_lock = 1
        else
          setlocal nocursorline
          let s:cursorline_lock = 0
        endif
      endif
    elseif a:event ==# 'CursorHold'
      setlocal cursorline
      let s:cursorline_lock = 1
    endif
  endfunction
augroup END

augroup vimrc-lcd
  autocmd!
  autocmd BufReadPre,BufFilePre * unlet! b:lcd
  autocmd BufReadPost,BufFilePost,FileType * call s:lcd()

  function s:lcd() abort
    if &l:buftype !=# '' && &l:buftype !=# 'help'
      if exists('b:lcd_original')
        lcd `=b:lcd_original`
      endif
      " unlet! b:lcd b:lcd_original
      return
    endif

    if exists('b:lcd') && (b:lcd ==# '' || getcwd() ==# b:lcd)
      return
    endif

    let path = s:lcd_path()
    if isdirectory(path)
      let b:lcd_original = getcwd()
      lcd `=path`
      let b:lcd = getcwd()
      let b:lcd_count = get(b:, 'lcd_count', 0) + 1
    endif
  endfunction

  let g:lcd = [
  \   ['tags'],
  \   [
  \     'Gemfile',
  \     'package.json',
  \     'Cargo.toml',
  \   ],
  \   [
  \     '.svn/',
  \     '.git/',
  \     '.git',
  \     '.bzr/',
  \     '.hg/',
  \     'doc/:vim,help,vimspec',
  \   ],
  \   ['README.*', 'README'],
  \   ['src/', 'include/'],
  \ ]

  function s:lcd_path() abort
    let path = ''
    let simple = expand('%:p:h:gs?\\\+?/?')

    if &l:buftype ==# 'help'
      return simple
    endif

    for lib_pat in [
    \   '^.*/vendor/bundle/\%(ruby/[^/]\+/\)\?\%(bundler/\)\?gems/[^/]\+/',
    \   '^.*/node_modules/[^/]\+/',
    \ ]
      let lib_base = matchstr(simple, lib_pat)
      if lib_base !=# ''
        return lib_base
      endif
    endfor

    for targets in g:lcd
      let dir = expand('%:p:h')
      let pdir = ''
      while dir isnot# pdir
        for target in targets
          let [name; opts] = split(target, ':')
          if !empty(opts) && index(split(opts[0], ','), &l:filetype) < 0
            continue
          endif
          let t = dir .. '/' .. name
          if name =~# '/$' ? isdirectory(t) : len(glob(t))
            return dir
          endif
        endfor
        let pdir = dir
        let dir = fnamemodify(dir, ':h')
      endwhile
    endfor

    return simple
  endfunction
augroup END

augroup vimrc-auto-mkdir
  autocmd!
  autocmd BufWritePre * call s:auto_mkdir(expand('<afile>:p:h'), v:cmdbang)
  function s:auto_mkdir(dir, force) abort
    if &l:buftype !=# '' || bufname('%') =~# '^[^:]\+://'
      return
    endif
    let mes = '"%s" does not exist. Create? [y/N]'
    if !isdirectory(a:dir) && (a:force ||
    \    input(printf(mes, a:dir)) =~? '^y\%[es]$')
      call mkdir(a:dir, 'p')
    endif
  endfunction
augroup END

if executable('chmod')
  augroup vimrc-autoexecutable
    autocmd!
    autocmd BufWritePost * call s:add_permission_x()
  augroup END

  function s:add_permission_x() abort
    let file = expand('%:p')
    if getline(1) =~# '^#!' && !executable(file)
      silent! call system('chmod a+x ' .. shellescape(file))
    endif
  endfunction
endif

augroup vimrc-fileencoding
  autocmd!
  autocmd BufReadPost * if &modifiable && !&modified &&
  \                         !search('[^\x00-\x7F]', 'cnw')
  \                   |   setlocal fileencoding=
  \                   | endif
augroup END

if !v:vim_did_enter && &binary  " launched with -b option
  augroup vimrc-xxd
    autocmd!
    autocmd BufReadPost * if &l:binary | setlocal filetype=xxd | endif
  augroup END
endif

augroup vimrc-misc
  autocmd!

  " Set 'dictionary'.
  autocmd FileType
  \ * if filereadable(expand('$VIM_USERDIR/dict/' .. &l:filetype .. '.dict'))
  \ |   let &l:dict = '$VIM_USERDIR/dict/' .. &l:filetype .. '.dict'
  \ | endif

  autocmd FileType
  \ * if &l:buftype !=# 'help' && &l:kp ==# '' && mapcheck('K', 'n') ==# ''
  \ |   silent! execute 'nnoremap <buffer> <unique> K <C-w>}'
  \ | endif

  " Auto open/close Quickfix/location window.
  autocmd QuickFixCmdPost [^l]* leftabove cwindow | redraw!
  autocmd QuickFixCmdPost l* silent! lwindow | redraw!

  " Update filetype.
  autocmd BufWritePost
  \ * if &l:filetype ==# '' || exists('b:ftdetect')
  \ |   unlet! b:ftdetect
  \ |   filetype detect
  \ | endif

  " Check timestamp more for 'autoread'.
  autocmd WinEnter,FocusGained * checktime %

  autocmd BufReadPost bzr_log.* let &l:fileencoding = &termencoding
  " Edit something to avoid the confirmation when aborting.
  autocmd BufReadPost bzr_log.* if empty(getline(1))
  \                           |   1 delete _ | silent write
  \                           | endif

  autocmd InsertEnter * if &l:foldmethod ==# 'expr'
  \                   |   let b:foldinfo = [&l:foldmethod, &l:foldexpr]
  \                   |   setlocal foldmethod=manual foldexpr=0
  \                   | endif
  autocmd InsertLeave * if exists('b:foldinfo')
  \                   |   let [&l:foldmethod, &l:foldexpr] = b:foldinfo
  \                   | endif

  autocmd InsertLeave * if &paste | set nopaste | endif
  autocmd InsertLeave * if &diff | diffupdate | endif

  autocmd VimResized * wincmd =
augroup END



" == Key mappings & command definition. == {{{1
" It is likely to be changed by $VIM/vimrc.
if !v:vim_did_enter
  mapclear
  mapclear!
endif

function s:meta_map(key, rhs, ...) abort
  let mode = a:0 ? a:1 : 'n'
  let modifier = has('mac') ? 'D' : 'M'
  execute printf('%snoremap <%s-%s> %s', mode, modifier, a:key, a:rhs)
endfunction

" -- Key mappings.  {{{2

" Physical moving.
noremap j gj
noremap k gk
noremap gj j
noremap gk k
nnoremap <expr> 0  &l:wrap ? 'g0' : '0'
nnoremap <expr> g0 &l:wrap ? '0'  : 'g0'
nnoremap <expr> ^  &l:wrap ? 'g^' : '^'
nnoremap <expr> g^ &l:wrap ? '^'  : 'g^'
nnoremap <expr> $  &l:wrap ? 'g$' : '$'
nnoremap <expr> g$ &l:wrap ? '$'  : 'g$'
" Yank to the end of line. (It is same as C and D)
nnoremap Y y$
" Current line at center of window and open the folding.
noremap n nzzzv
noremap N Nzzzv
" Very magic by default.
nnoremap / /\v
nnoremap ? ?\v
cnoremap <expr> s/ getcmdline() =~# '^\A*$' ? 's/\v' : 's/'
cnoremap <expr> g/ getcmdline() =~# '^\A*$' ? 'g/\v' : 'g/'
cnoremap <expr> v/ getcmdline() =~# '^\A*$' ? 'v/\v' : 'v/'
cnoremap s// s//
cnoremap g// g//
cnoremap v// v//

nnoremap gA A<C-g>U<Left>

nnoremap <Esc> <Nop>

" Control search highlight.
if dein#is_sourced('asterisk')
  noremap <Plug>(vimrc-searchafter) zz
  noremap * <Plug>(asterisk-z*)<Plug>(vimrc-searchafter)
  noremap # <Plug>(asterisk-z#)<Plug>(vimrc-searchafter)
  noremap g* <Plug>(asterisk-gz*)<Plug>(vimrc-searchafter)
  noremap g# <Plug>(asterisk-gz#)<Plug>(vimrc-searchafter)
  let g:asterisk#keeppos = 1
endif
nnoremap <Esc><Esc> <Cmd>nohlsearch<CR>

" Search the word nearest to the cursor in new window.
nnoremap <C-w>*  <C-w>s*
nnoremap <C-w>#  <C-w>s#

nnoremap <C-w>V <C-w>vgF

" repeat :substitute with same flag
noremap <silent> & :&&<CR>

" Search selected area.
vnoremap <silent> z/ <Esc>/\v%V
vnoremap <silent> z? <Esc>?\v%V

" Repeat on Visual-mode.
vnoremap <silent> . :normal .<CR>
vnoremap <silent> @q :normal @q<CR>

" Switch the tab page.
nnoremap <C-n> gt
nnoremap <C-p> gT
for s:n in range(1, 9)
  call s:meta_map(s:n, s:n .. 'gt')
endfor
unlet! s:n

" Scroll + Move
nnoremap <C-j> <C-e>gj
nnoremap <C-k> <C-y>gk

nnoremap <expr> [c &diff ? '[c' : '<Cmd>cprevious<CR>'
nnoremap <expr> ]c &diff ? ']c' : '<Cmd>cnext<CR>'
nnoremap [l <Cmd>lprevious<CR>
nnoremap ]l <Cmd>lnext<CR>

" Swap ; and :
noremap ; :
noremap : ;

function s:good_feeling_prefix() abort
  return printf(":\<C-u>%s", 78 * 2 <= winwidth(0) ? 'vertical ' : '')
endfunction
nnoremap <expr> <C-h> <SID>good_feeling_prefix() .. 'h '
nnoremap <expr> <Space>tm <SID>good_feeling_prefix() .. 'terminal<CR>'

" Show :messages quickly.
nnoremap <expr> <lt> v:count ? '<Cmd>' .. v:count .. 'messages<CR>' : '<lt>'

nnoremap <silent> <expr> ]p <SID>paste_with_indent()
function s:paste_with_indent() abort
  if getregtype(v:register) isnot# 'V'
    call setreg(v:register, getreg(v:register) . "\n")
  endif
  return "]p:undojoin\<CR>=`]"
endfunction

" Don't move at escaping from insert mode.
" inoremap <silent> <Esc> <Esc>:keepjumps normal! `^<CR>

" Quick completion.
inoremap <C-]> <C-x><C-]>

" Create an undo point before <C-u> and <C-w>.
" XXX: <C-u> doesn't work on <C-x><C-u>
inoremap <expr> <C-u> (pumvisible() ? '<C-y>' : '') .. '<C-g>u<C-u>'
inoremap <C-w> <C-g>u<C-w>

" inoremap <expr> <CR> pumvisible() ? '<C-y><CR>' : '<CR>'

inoremap <C-l> <C-o><C-l>

" To uppercase/lowercase the word immediately before.
inoremap <C-g><C-u> <Esc>gUvbgi
inoremap <C-g><C-l> <Esc>guvbgi

" Make inputting a character by code easily.
inoremap <Plug>(vimrc-input-char-by-code)
\ <C-r>=nr2char(eval(input('char? ', '0x')))<CR>
inoremap <C-v>x <Plug>(vimrc-input-char-by-code)
inoremap <C-v>u <Plug>(vimrc-input-char-by-code)
inoremap <C-v>U <Plug>(vimrc-input-char-by-code)

" Select the last changed.
nnoremap <expr> gc '`[' .. getregtype()[0] .. '`]'
onoremap gc <Cmd>normal gc<CR>
onoremap gv <Cmd>normal gv<CR>

onoremap q /["',.{}()[\]<>]<CR>

" Do not select whitespace of outer of quotes.  :help v_iquote
onoremap a" 2i"
onoremap a' 2i'
onoremap a` 2i`

" Prevent a typing error.
nmap <C-@> <Esc>
imap <C-@> <Esc>
cmap <C-@> <C-c>

nnoremap <Left>  <C-w>h
nnoremap <Down>  <C-w>j
nnoremap <Up>    <C-w>k
nnoremap <Right> <C-w>l
nnoremap <S-Left>  <C-w>H
nnoremap <S-Down>  <C-w>J
nnoremap <S-Up>    <C-w>K
nnoremap <S-Right> <C-w>L
call s:meta_map('h', '<C-w>h')
call s:meta_map('j', '<C-w>j')
call s:meta_map('k', '<C-w>k')
call s:meta_map('l', '<C-w>l')
call s:meta_map('H', '<C-w>H')
call s:meta_map('J', '<C-w>J')
call s:meta_map('K', '<C-w>K')
call s:meta_map('L', '<C-w>L')

nnoremap c "_c
nnoremap C "_C

" Don't use commands.
noremap ZZ <Nop>
noremap ZQ <Nop>
noremap <C-z> <Nop>
noremap <F1> <Nop>

nnoremap =ae <Cmd>KeepCursor normal! gg=G<CR>


" Mappings for command-line mode.
cnoremap <C-a> <C-b>
cnoremap <C-f> <Right>
cnoremap <C-b> <Left>

" Move the cursor not complete list.
cnoremap <Left> <Space><BS><Left>
cnoremap <Right> <Space><BS><Right>

cnoremap <C-p> <Up>
cnoremap <C-n> <Down>
cnoremap <Up> <C-p>
cnoremap <Down> <C-n>

nnoremap <Space> <Nop>
" Quick save and quit.
nnoremap <Space>w <Cmd>update<CR>
nnoremap <Space>W <Cmd>update!<CR>
nnoremap <Space>q <Cmd>quit<CR>
nnoremap <Space>Q <Cmd>quit!<CR>

" Change encodings and formats.
nnoremap <Space>e <Nop>
nnoremap <Space>es <Cmd>setlocal fenc=cp932<CR>
nnoremap <Space>ee <Cmd>setlocal fenc=euc-jp<CR>
nnoremap <Space>eu <Cmd>setlocal fenc=utf-8<CR>
nnoremap <Space>ej <Cmd>setlocal fenc=iso-2022-jp<CR>
nnoremap <Space>ed <Cmd>setlocal ff=dos<CR>
nnoremap <Space>ex <Cmd>setlocal ff=unix<CR>

" Change statusline.
nnoremap <Space>s <Nop>
for [s:key, s:var] in [['n', 'bufnr'], ['c', 'char'],
\                      ['s', 'filesize'], ['h', 'highlight']]
  for [s:prefix, s:scope] in [['', 'g'], ['b', 'b'], ['w', 'w']]
    execute printf('nnoremap <Space>s%s%s '
    \            .. '<Cmd>call <SID>toggle_flag(%s:, "statusline_%s")<CR>'
    \            .. '<Cmd>redrawstatus!<CR>',
    \              s:prefix, s:key, s:scope, s:var)
  endfor
endfor
unlet! s:key s:var s:prefix s:scope

" Quick toggle options.
nnoremap <Space>o <Nop>
nnoremap <Space>oe <Cmd>setlocal expandtab! expandtab?<CR>
nnoremap <Space>of
\ <Cmd>let &l:foldcolumn=1-&l:foldcolumn<CR>:setlocal foldcolumn?<CR>
nnoremap <Space>on <Cmd>setlocal number! number?<CR>
nnoremap <Space>ol <Cmd>setlocal list! list?<CR>
nnoremap <Space>ow <Cmd>setlocal wrap! wrap?<CR>
nnoremap <Space>os <Cmd>setlocal spell! spell?<CR>
nnoremap <Space>op <Cmd>set paste! paste?<CR>

" Tabpage operation.
nnoremap <Space>t <Nop>
nnoremap <Space>tn <Cmd>tabnew<CR>
nnoremap <silent> <Space>tc :<C-u><C-r>=v:count?v:count:''<CR>tabclose<CR>

" q as prefix
nnoremap <script> <expr> q reg_recording() is# '' ? '<SID>(q)' : 'q'

nnoremap <silent> <SID>(q) q
nnoremap <SID>(q)<Space> <Cmd>quit<CR>
nnoremap <silent> <SID>(q)@
\ <Cmd>call <SID>make_macro_recursive(nr2char(getchar()))<CR>

function s:make_macro_recursive(reg) abort
  if a:reg !~# '^[a-z]$'
    return
  endif
  let contents = getreg(a:reg)
  if contents !~# '@' .. a:reg .. '$'
    let contents ..= '@' .. a:reg
    call setreg(a:reg, contents)
  endif
endfunction

if exists(':tmap')
  call s:meta_map('h', '<C-w>h', 't')
  call s:meta_map('j', '<C-w>j', 't')
  call s:meta_map('k', '<C-w>k', 't')
  call s:meta_map('l', '<C-w>l', 't')
  call s:meta_map('H', '<C-w>H', 't')
  call s:meta_map('J', '<C-w>J', 't')
  call s:meta_map('K', '<C-w>K', 't')
  call s:meta_map('L', '<C-w>L', 't')
endif

nnoremap <Space>.
\  <Cmd>if expand('%:p:h:gs?\\?/?') ==# resolve($VIM_USERDIR)
\ <Bar>   source %
\ <Bar> else
\ <Bar>   tabnew $VIM_USERDIR/vimrc
\ <Bar> endif<CR>

function s:grep_same_ext(pat) abort
  let exts = get({
  \   'c': ['c', 'h'],
  \   'cpp': ['cpp', 'h', 'hpp', 'cc', 'cxx'],
  \ }, &l:filetype, [expand('%:e')])
  let files = join(map(exts, '"**/*." .. v:val'), ' ')
  silent! execute 'vimgrep /' .. a:pat .. '/j ' .. files
endfunction
nnoremap <Space>grep <Cmd>call <SID>grep_same_ext('\C' .. @/)<CR>
nnoremap <Space>Grep <Cmd>call <SID>grep_same_ext('\c' .. @/)<CR>
nnoremap <Space><C-g> <Cmd>vimgrep /<C-r>//gj %<CR>

noremap! <expr> <C-r>/  <SID>strip_magic()
function s:strip_magic() abort
  let search_pat = getreg('/')
  return getcmdtype() =~# '[/?]'
  \ ? search_pat
  \ : substitute(search_pat, '\(^\\V\|\\[<>]\)', '', 'g')
endfunction

command! -nargs=+ G call vimrc#grep(<f-args>)

" <Space><C-n>, <Space><C-p>: Move window position {{{
nnoremap <Space><C-n> <Cmd>call <SID>swap_window(v:count1)<CR>
nnoremap <Space><C-p> <Cmd>call <SID>swap_window(-v:count1)<CR>

function s:swap_window(n) abort
  let curbuf = bufnr('%')
  let target = vimrc#modulo(winnr() + a:n - 1, winnr('$')) + 1

  " 'hide' is necessary to keep the undo history.
  execute 'hide' winbufnr(target) .. 'buffer'
  execute target .. 'wincmd w'
  execute curbuf .. 'buffer'
endfunction
" }}}

nnoremap <Leader><CR> <Cmd>%s/\r$//ge<CR><C-o>

" Shortcut enc and ff.
cnoreabbrev ++u ++enc=utf8
cnoreabbrev ++c ++enc=cp932
cnoreabbrev ++s ++enc=cp932
cnoreabbrev ++e ++enc=euc-jp
cnoreabbrev ++j ++enc=iso-2022-jp
cnoreabbrev ++x ++ff=unix
cnoreabbrev ++d ++ff=dos
cnoreabbrev ++m ++ff=mac


" Show the diff between the current buffer and the last saved file. {{{
" TODO: Become plugin.
function s:diff_original() abort
  if exists('b:diff_current')
    execute bufwinnr(b:diff_current) 'wincmd w'
  endif
  if exists('b:diff_original')
    diffoff
    execute b:diff_original 'bwipeout'
    unlet b:diff_original
    return
  endif

  let bufnr = bufnr('%')
  let ft = &l:filetype
  let fenc = &l:fileencoding

  if &modified
    let source = '#' .. bufnr
    let file = '[last save]'
  else
    echo 'There is not the diff.'
    return
  endif

  vertical new

  let b:diff_current = bufnr
  let bufnr = bufnr('%')
  setlocal buftype=nofile
  let &l:filetype = ft
  let &l:fileencoding = fenc
  file `=file .. fnamemodify(bufname(b:diff_current), ':.')`

  silent! execute 'read' source

  0 delete _
  diffthis
  wincmd p
  diffthis
  let b:diff_original = bufnr
endfunction
nnoremap <Space>diff <Cmd>call <SID>diff_original()<CR>
" }}}

" -- Commands.  {{{2
command! -nargs=1 -bang -bar -complete=file Rename
\        call vimrc#move(<q-args>, <q-bang>, expand('%:h'))
command! -nargs=1 -bang -bar -complete=file Move
\        call vimrc#move(<q-args>, <q-bang>, getcwd())

command! -nargs=? -bang -bar -complete=file Delete
\ call vimrc#delete_with_confirm(<q-args>, <bang>0)

" unique lines without sort.
command! -bar -nargs=* -range=% Unique
\        <line1>,<line2>call vimrc#unique_lines(<q-args>)

" FIXME: :diffoff make 'foldmethod' to "manual" (not restored).
command! -bar Diff if &diff | diffoff! | else
\                           | execute 'windo diffthis' | endif

if executable('ctags')
  " Execute ctags command. And echo for error.
  command! -nargs=? -complete=file -bar CtagsR call vimrc#ctags([<f-args>])
  nnoremap <Space>tr <Cmd>CtagsR<CR>
endif

command! -bar Tasks execute 'vimgrep /\C\v<(TODO|FIXME|XXX)>/ **/*.'
\                           .. expand('%:e')

" Show 'runtimepath'.
command! -bar RTP echo substitute(&runtimepath, ',', "\n", 'g')

" :HighlightWith {filetype} ['a 'b]  FIXME: Doesn't work in some case.
command! -nargs=+ -range=% HighlightWith
\                          <line1>,<line2>call vimrc#highlight_with(<q-args>)

" :KeepCursor {excmd}
command -nargs=+ KeepCursor call vimrc#keep_cursor(<q-args>)


" Grep({text}, {pat} [, invert])
function Grep(text, pat, ...) abort
  let op = a:0 && a:1 ? '!~#' : '=~#'
  return join(filter(split(a:text, "\n"), 'v:val' .. op .. 'a:pat'), "\n")
endfunction

command! -nargs=+ Vars PP filter(copy(g:), 'v:key =~# "^<args>"')

" experimental
command! -nargs=+ -bang -bar -complete=file Opener
\    if <q-args> =~# '`=.*`\s*$'
\  |   execute vimrc#opener(<q-args>,
\                           eval(matchstr(<q-args>, '`=\zs.*\ze`\s*$')))
\  | elseif <q-args> =~# '`.*`\s*$'
\  |   execute vimrc#opener(<q-args>)
\  | else
\  |   execute vimrc#opener(<q-args>)
\  | endif


" -- Functions.  {{{2
function GeneratePassword(len, ...) abort
  let char_types = {
  \   'upper': repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 2),
  \   'lower': repeat('abcdefghijklmnopqrstuvwxyz', 2),
  \   'num': repeat('0123456789', 2),
  \   'marks': '!"#$%&''()*+,-./:;<=>?@[\]^_`{|}~',
  \   'space': ' ',
  \ }
  let char_types.all = join(values(char_types), '')
  let char_types.alpha = char_types.upper .. char_types.lower
  let char_types.alnum = char_types.alpha .. char_types.num

  let use_types = a:0 ? a:1 : 'alpha'
  let types = split(use_types, ',')

  let chars = ''
  for type in types
    let chars ..= get(char_types, type, '')
  endfor

  let list = split(chars, '.\zs')
  return join(map(range(a:len), 'g:V.Random.sample(list)'), '')
endfunction


" == Setting according to environments. == {{{1
" cygwin (UTF-8)  {{{2
if has('win32unix')
  Set termencoding=
endif

" Use a mouse in terminal.  {{{2
Set mouse=a

" MS Windows  {{{2
if s:is_win
  " Vim starts on $VIM or $VIMRUNTIME,
  " but I want to start on $HOME.
  if getcwd() ==? $VIM || getcwd() ==? $VIMRUNTIME
    cd ~
  endif
endif

" GUI  {{{2
if has('gui_running')
  " My default gui settings.
  function s:init_guioptions() abort
    " GUI option to use by default.
    winpos 0 0
    " Disable Toolbar and menu, and use non-GUI tab pages line.
    Set guioptions-=T guioptions-=m guioptions-=e
    " Hide any scrollbar.
    Set guioptions-=l guioptions-=r guioptions-=L guioptions-=R
    if has('kaoriya') && s:is_win
      " Remove caption (title) bar. Support Windows only.
      Set guioptions+=C
    endif

    if s:is_win
      Set guifont=Migu_1M:h11:cSHIFTJIS,MS_Gothic:h9:cDEFAULT
    elseif has('x11')
      Set guifont=
    elseif has('unix')
      Set guifont=M+2M+IPAG\ 9
    endif
  endfunction
  command! -nargs=0 -bar InitGuioptions call s:init_guioptions()

  function s:start_vim_plugin_test(dir) abort
    call vimproc#system_bg(printf('gvim --cmd "cd %s"', a:dir))
  endfunction

  " Does not use IM by default.
  Set iminsert=0 imsearch=0
  Set winaltkeys=no
else
  " CUI  {{{2
  if has('unix')
    " Use meta keys in console.
    function s:use_meta_keys() abort
      for i in map(
      \   range(char2nr('a'), char2nr('z'))
      \ + range(char2nr('A'), char2nr('Z'))
      \ + range(char2nr('0'), char2nr('9'))
      \ , 'nr2char(v:val)')
        execute printf("set <M-%s>=\e%s", i, i)
      endfor
    endfunction

    call s:use_meta_keys()
    map <NUL> <C-Space>
    map! <NUL> <C-Space>

    " Change the shape of the cursor depending on the mode.
    if !v:vim_did_enter
      let &t_ti ..= "\e[1 q"
      let &t_SI ..= "\e[5 q"
      let &t_SR ..= "\e[3 q"
      let &t_EI ..= "\e[1 q"
      let &t_te ..= "\e[0 q"
    endif

    " Tmux will send xterm-style keys when its xterm-keys option is on
    if &term =~? '^screen'
      execute "set <xUp>=\e[1;*A"
      execute "set <xDown>=\e[1;*B"
      execute "set <xRight>=\e[1;*C"
      execute "set <xLeft>=\e[1;*D"
    endif

    " Change the shape of the cursor at Command-line mode.
    augroup vimrc-cursor-shape
      autocmd!
      autocmd CmdlineEnter * silent! execute "!echo -n '\e[5 q'"
      autocmd CmdlineLeave * silent! execute "!echo -n '\e[1 q'"
    augroup END

    " let &t_ti ..= "\e[?2004h"
    " let &t_te ..= "\e[?2004l"
    " function s:XTermPaste(on) abort
    "   let &paste = a:on
    "   return ''
    " endfunction
    " inoremap <expr> <Esc>[200~ <SID>XTermPaste(1)
    " inoremap <expr> <Esc>[201~ <SID>XTermPaste(0)

    Set termguicolors
    let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
    let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
  endif

  " For GNU Screen or tmux.  {{{2
  if $WINDOW !=# '' || $TMUX !=# ''
    let s:window = 1
    " Use a mouse in screen.
    if has('mouse')
      Set ttymouse=xterm2
    endif
    function s:set_window_name(name) abort
      if get(g:, 'before_window_name', '') is# a:name
        return
      endif
      let esc = "\<Esc>"
      let escaped_name = escape(a:name, '%#!')
      let cmd = printf('!echo -n "%sk%s%s\\"', esc, escaped_name, esc)
      silent! execute cmd
      let g:before_window_name = a:name
      " redraw!
    endfunction
    command! -nargs=? WindowName call s:set_window_name(<q-args>)
    function s:auto_window_name() abort
      let varname = 'window_name'
      for scope in ['w:', 'b:', 't:', 'g:']
        if exists(scope .. varname)
          call s:set_window_name(eval(scope .. varname))
          return
        endif
      endfor
      if bufname('%') !~# '^\[A-Za-z0-9\]*:/'
        call s:set_window_name('v:' .. expand('%:t'))
      endif
    endfunction
    augroup vimrc-screen
      autocmd!
      autocmd VimEnter * ++once call s:set_window_name(0 < argc() ?
      \ 'v:' .. fnamemodify(argv(0), ':t') : 'vim')
      autocmd BufEnter,WinEnter,BufFilePost * call s:auto_window_name()
      autocmd VimLeave * call s:set_window_name(len($SHELL) ?
      \ fnamemodify($SHELL, ':t') : 'shell')
    augroup END

    if $TMUX !=# ''
      function s:start_vim_plugin_test(dir) abort
        let cmd = printf(
        \   'tmux new-window "zsh -i -c \"cd %s; DISPLAY= vim\""', a:dir)
        call system(cmd)
      endfunction
    endif
  endif
endif

" :terminal  {{{2
function s:on_terminal_win_open() abort
  augroup vimrc-terminal-window
    autocmd! * <buffer>
    autocmd WinEnter <buffer> call s:on_terminal_win_enter()
    autocmd WinLeave <buffer> call s:on_terminal_win_leave()
  augroup END
endfunction
function s:on_terminal_win_enter() abort
  if get(b:, 'term_normal', 0)
    call feedkeys("\<C-\>\<C-n>", 'nt')
    unlet b:term_normal
  endif
endfunction
function s:on_terminal_win_leave() abort
  if term_getstatus('%') is# 'running,normal'
    let b:term_normal = 1
    normal! i
  endif
endfunction
augroup vimrc-terminal
  autocmd!
  autocmd TerminalWinOpen * call s:on_terminal_win_open()
augroup END

" :CheckInterface  {{{2
command! CheckInterface call vimrc#check_interface()



" == Filetype settings. == {{{1
" Java
let g:java_highlight_functions = 'style'
let g:java_highlight_all = 1
let g:java_allow_cpp_keywords = 1

" PHP
let g:PHP_vintage_case_default_indent = 1

" Ruby
let g:ruby_minlines = 500

" Python
let g:python_highlight_all = 1

" Scheme
let g:is_gauche = 1
" gauref
let g:gauref_file = expand('$VIM_USERDIR/ftplugin/scheme/gauche-refj.txt')

" bash
let g:is_bash = 1

" XML
let g:xml_syntax_folding = 1

" Vim
let g:vimsyntax_noerror = 1
let g:vim_indent_cont = 0

" lisp
let g:lisp_rainbow = 1

" sh
let g:sh_noisk = 1

" Clojure
let g:vimclojure#HighlightBuiltins = 1
let g:vimclojure#ParenRainbow = 1
let g:vimclojure#SetupKeyMap = 0

" bzr
let g:bzr_highlight_diff = 1

" doxygen
let g:doxygen_end_punctuation = '[.。]'

" rst (riv)
let g:riv_global_leader = '<LocalLeader>t'



" == Plugin settings. == {{{1
let s:plugin_info = expand('~/.local/share/vim/info')
function s:plugin_info_dir(plugin_name) abort
  let dir = s:plugin_info .. '/' .. a:plugin_name
  if !isdirectory(dir)
    call mkdir(dir, 'p')
  endif
  return dir .. '/'
endfunction

let s:temp_file_pat = join([
\   '/svn-commit\%(\.\d\+\)\?\.tmp$',
\   '.git/COMMIT_EDITMSG$',
\   '/bzr_log\..\{6}$',
\ ], '\|')
if $TMP !=# ''
  let s:temp_file_pat ..=
  \  '\|^' .. substitute(expand($TMP), '\', '[/\\\\]', 'g')
elseif has('unix')
  let s:temp_file_pat ..= '\|^/tmp/\|^/var/tmp/'
endif

" netrw.vim  {{{2
let g:netrw_home = s:plugin_info_dir('netrw')

" vimfiler.vim  {{{2
if dein#is_sourced('vimfiler')
  let g:vimfiler_as_default_explorer = 1
  let g:vimfiler_safe_mode_by_default = 0
  let g:vimfiler_data_directory = s:plugin_info_dir('vimfiler')
  let g:vimfiler_split_rule = 'botright'
  nnoremap <Leader>sf <Cmd>VimFilerSplit<CR>
  nnoremap <Leader>sF <Cmd>VimFilerBufferDir -split<CR>
endif

" deoplete.nvim  {{{2
if dein#is_sourced('deoplete')
  Set pyxversion=3
  let g:deoplete#enable_at_startup = 1
  let g:deoplete#enable_camel_case = 1

  call g:V.set_default('g:deoplete#keyword_patterns', {})
  let g:deoplete#keyword_patterns.javascript = '\v\k+'

  call g:V.set_default('g:deoplete#omni_patterns', {})
  let g:deoplete#omni_patterns.cs = '[^.]\.\%(\u\{2,}\)\?'
  let g:deoplete#omni_patterns.csharp = '[^.]\.\%(\u\{2,}\)\?'
  let g:deoplete#omni_patterns.typescript = '[^.]\.\%(\u\{2,}\)\?'

  inoremap <expr> <C-f> deoplete#manual_complete('file')
  inoremap <expr> <C-y> pumvisible() ? deoplete#close_popup()  : '<C-y>'
  inoremap <expr> <C-e> pumvisible() ? deoplete#cancel_popup() : '<C-e>'
endif

" ddc.vim  {{{2
if dein#is_sourced('ddc')
  let g:ddc_sources = ['neosnippet', 'around', 'buffer', 'file']
  if executable('look')
    let g:ddc_sources += ['look']
  endif
  call ddc#custom#patch_global(#{
  \   sources: g:ddc_sources,
  \   sourceOptions: #{
  \     _: #{
  \       matchers: ['matcher_fuzzy'],
  \       sorters: ['sorter_fuzzy'],
  \       converters: ['converter_fuzzy', 'converter_remove_overlap'],
  \       ignoreCase: v:true,
  \     },
  \     around: #{mark: 'around'},
  \     buffer: #{mark: 'buffer'},
  \     file: #{mark: 'file', forceCompletionPattern: '/\S*'},
  \     look: #{mark: 'look', maxCandidates: 5},
  \     vim-lsp: #{mark: 'lsp', forceCompletionPattern: '(?:\.|:|->)\w*'},
  \     neosnippet: #{mark: 'snip'},
  \     skkeleton: #{
  \       mark: 'skkeleton',
  \       matchers: ['skkeleton'],
  \       sorters: [],
  \     },
  \   },
  \   sourceParams: #{
  \     buffer: #{fromAltBuf: v:true, forceCollect: v:true},
  \   },
  \ })
  if dein#is_sourced('pum')
    call ddc#custom#patch_global('completionMenu', 'pum.vim')
    inoremap <expr> <C-n> pum#visible() ?
    \   '<Cmd>call pum#map#insert_relative(+1)<CR>' : '<C-n>'
    inoremap <expr> <C-p> pum#visible() ?
    \   '<Cmd>call pum#map#insert_relative(-1)<CR>' : '<C-p>'
    inoremap <expr> <C-y> pum#visible() ?
    \   '<Cmd>call pum#map#confirm()<CR>' : '<C-y>'
    inoremap <expr> <C-e> pum#visible() ?
    \   '<Cmd>call pum#map#cancel()<CR>' : '<C-e>'

    if dein#is_sourced('denops-popup-preview')
      call popup_preview#enable()
    endif
  endif
  call ddc#enable()
  augroup vimrc-plugin-ddc
    autocmd!
    autocmd User plugin-quickmemo-opened call ddc#custom#patch_buffer(#{
    \   specialBufferCompletion: v:true,
    \ })
    autocmd FileType unite call ddc#custom#patch_buffer(#{
    \   specialBufferCompletion: v:false,
    \ })
  augroup END
endif

" context_filetype.vim
if !exists('g:context_filetype#same_filetypes')
  let g:context_filetype#same_filetypes = {}
endif
let g:context_filetype#same_filetypes.vimspec = 'vim'

" neosnippet.vim
if dein#is_sourced('neosnippet')
  let g:neosnippet#snippets_directory = $VIM_USERDIR .. '/snippets'
  function TabWrapper() abort
    if neosnippet#expandable() || neosnippet#jumpable()
      " return "\<Plug>(neosnippet_jump_or_expand)"
      return "\<Plug>(neosnippet_expand_or_jump)"
    elseif pumvisible()
      return "\<C-y>"
    elseif (!exists('b:smart_expandtab') || b:smart_expandtab) &&
    \   !&l:expandtab && !search('^\s*\%#', 'nc')
      return repeat(' ', &l:tabstop - (virtcol('.') - 1) % &l:tabstop)
    endif
    return "\<Tab>"
  endfunction
  inoremap <silent> <expr> <Tab> TabWrapper()

  " Start editing with any key in the select mode.
  " This overwrites :vmap.
  augroup vimrc-plugin-snippets
    autocmd!
    autocmd VimEnter,BufEnter * call s:snippets_remap()
    autocmd InsertLeave * NeoSnippetClearMarkers
  augroup END
  function s:snippets_remap() abort
    smapclear
    smapclear <buffer>
    snoremap <silent> <Tab> <C-\><C-n>a<Plug>(neosnippet_jump_or_expand)
    snoremap <C-h> _<C-h>
  endfunction
endif

" unite.vim  {{{2
if dein#is_sourced('unite')
  let g:unite_data_directory = s:plugin_info_dir('unite')
  let g:unite_source_history_yank_enable = 1
  let s:pat = '\v' .. join([
  \   '\~$',
  \   '\.%(o|exe|dll|bak|DS_Store|zwc|pyc|sw[po]|class|meta)$',
  \   '%(^|[/\\])%(\.|\.hg|\.git|\.bzr|\.svn|tags%(-.*)?)%($|[/\\])$',
  \   '\.bundle/', 'vendor/',
  \ ], '|')
  let g:unite_source_alias_aliases = {
  \   'proj_mru': {
  \     'source': 'file_mru',
  \   }
  \ }
  call unite#custom#source('file', 'ignore_pattern',
  \                        '/\.\%(svn\|/\)\?$\|/tags\%(-..\)\?$\|\.meta$')
  call unite#custom#source('file', 'ignore_globs', [])
  call unite#custom#source('file_rec', 'ignore_pattern', s:pat)
  call unite#custom#source('file_rec/async', 'ignore_pattern', s:pat)
  call unite#custom#source('file_rec/git', 'ignore_pattern', s:pat)
  call unite#custom#source('proj_mru', 'matchers',
  \                        ['matcher_project_files', 'matcher_default'])
  call unite#custom#source('proj_mru', 'converters',
  \                        ['converter_relative_word'])
  let s:unite_default_options = {
  \   'update_time': 50,
  \   'start_insert': 1,
  \ }
  call unite#custom#profile('default', 'context', s:unite_default_options)
  let g:unite_source_rec_max_cache_files = 100000

  call unite#filters#sorter_default#use(['sorter_selecta'])

  nnoremap <Leader>z <Cmd>Unite -buffer-name=file
  \ window:all:no-current proj_mru file buffer<CR>
  nnoremap <Leader>a <Nop>
  nnoremap <Leader>ab <Cmd>Unite -buffer-name=file buffer<CR>
  nnoremap <Leader>af <Cmd>Unite -buffer-name=file file file/new<CR>
  nnoremap <Leader>aF     <Cmd>UniteWithBufferDir -buffer-name=file file<CR>
  nnoremap <Leader>a<C-f> <Cmd>UniteWithBufferDir -buffer-name=file file<CR>
  nnoremap <Leader>am <Cmd>Unite -buffer-name=file file_mru<CR>

  let s:cmds = [
  \   ['fd', '--hidden', '--no-ignore', '--type', 'file', '--color', 'never', '.'],
  \   ['files'],
  \ ]
  let s:rec_cmd = get(filter(s:cmds, 'executable(v:val[0])'), 0, [])
  if !empty(s:rec_cmd)
    let g:unite_source_rec_async_command = s:rec_cmd
    nnoremap <Leader>ar <Cmd>Unite -buffer-name=file file_rec/async<CR>
    nnoremap <silent> <Leader>aR :<C-u>Unite -buffer-name=file file_rec/async:<C-r>=expand('%:p:h:gs?[ :]?\\\0?')<CR><CR>
  else
    nnoremap <Leader>ar <Cmd>Unite -buffer-name=file file_rec<CR>
    nnoremap <silent> <Leader>aR :<C-u>Unite -buffer-name=file file_rec:<C-r>=expand('%:p:h:gs?[ :]?\\\0?')<CR><CR>
  endif

  nnoremap <Leader>a<Tab> <Cmd>Unite -vertical tab<CR>
  nnoremap <Leader>ah <Cmd>Unite help<CR>
  nnoremap <Leader>al <Cmd>Unite line<CR>
  nnoremap <Leader>ao <Cmd>Unite -buffer-name=outline -vertical -no-start-insert -create outline<CR>
  nnoremap <Leader>aw <Cmd>Unite window:all<CR>
  nnoremap <Leader>ap <Cmd>Unite tab<CR>
  nnoremap <Leader>aP <Cmd>Unite process<CR>
  nnoremap <Leader>at <Cmd>Unite tag<CR>
  nnoremap <Leader>aT <Cmd>Unite tag/file<CR>
  nnoremap <Leader>a<C-t> <Cmd>Unite tag/file<CR>
  nnoremap <Leader>a: <Cmd>Unite history/command<CR>
  nnoremap <Leader>a; <Cmd>Unite history/command<CR>
  nnoremap <Leader>a/ <Cmd>Unite history/search<CR>
  nnoremap <Leader>aq <Cmd>Unite qf<CR>
  nnoremap <Leader>ag <Cmd>Unite -no-quit grep:**<CR>
  " nnoremap <Leader>as <Cmd>Unite session<CR>

  nnoremap <Leader>a<Leader> <Nop>
  nnoremap <Leader>a<Leader>r <Nop>
  nnoremap <Leader>a<Leader>rc <Cmd>Unite rails/controller<CR>
  nnoremap <Leader>a<Leader>rm <Cmd>Unite rails/model<CR>
  nnoremap <Leader>a<Leader>rv <Cmd>Unite rails/view<CR>

  nnoremap <silent> <C-]>      :<C-u>Unite -immediately -no-start-insert tag:<C-r>=expand('<cword>')<CR><CR>
  vnoremap <silent> <C-]>      :<C-u>Unite -immediately -no-start-insert -input=<C-r>=escape(<SID>get_range(visualmode(), 'v'), '\ ')<CR> tag<CR>
  nnoremap <silent> <C-w><C-]> :<C-u>Unite -immediately -no-start-insert -default-action=split tag:<C-r>=expand('<cword>')<CR><CR>
  vnoremap <silent> <C-w><C-]> :<C-u>Unite -immediately -no-start-insert -input=<C-r>=escape(<SID>get_range(visualmode(), 'v'), '\ ')<CR> -default-action=split tag<CR>

  call g:V.Dict.clear(unite#custom#get_profile('file', 'substitute_patterns'))

  call unite#custom#substitute('file', '\$\w\+', '\=eval(submatch(0))', 200)

  call unite#custom#substitute('file', '[^~.:]\zs/', '*/*', 20)

  call unite#custom#substitute('file', '^@@', '\=getcwd()."/*"', 2)
  call unite#custom#substitute('file', '^@', '\=expand("#:h:.")."/"', 1)
  call unite#custom#substitute('file', '^!', '\=vcs#root()."/*"', 1)
  call unite#custom#substitute('file', '^\\', '~/*')
  call unite#custom#substitute('file', '^;v', '$VIM_USERDIR/*')
  call unite#custom#substitute('file', '\C^;b', '$DEIN_BASE/repos/github.com/*/*')
  call unite#custom#substitute('file', '\C^;B', '$DEIN_BASE/.cache/vimrc/.dein/*')
  if $DROPBOX_HOME !=# ''
    call unite#custom#substitute('file', '^;d', '$DROPBOX_HOME/work/vim-plugins/*')
    call unite#custom#substitute('file', '^;l', '$DROPBOX_HOME/work/vim-plugins/labs/*')
  endif
  call unite#custom#substitute('file', '^;i', s:plugin_info .. '/*')
  call unite#custom#substitute('file', '^;s', '$VIM_USERDIR/pack/personal/start/default/after/syntax/*')
  call unite#custom#substitute('file', '^;f', '$VIM_USERDIR/pack/personal/start/default/after/ftplugin/*')
  if s:is_win
    call unite#custom#substitute('file', '^;p', 'C:/Program Files/*')
  endif

  call unite#custom#substitute('file', '\*\*\+', '*', -1)
  call unite#custom#substitute('file', '^\~', escape($HOME, '\'), -2)
  call unite#custom#substitute('file', '\\ \@!', '/', -30)
  call unite#custom#substitute('file', ';', ' ', -31)

  call unite#custom#profile('file', 'context', {'ignorecase': 1, 'smartcase': 0})

  function s:unite_status_highlight() abort
    highlight link uniteStatusNormal StatusLine
    highlight link uniteStatusHead StatusLine
    highlight link uniteStatusSourceNames StatusLine
    highlight link uniteStatusSourceCandidates StatusLine
    highlight link uniteStatusMessage StatusLine
    highlight link uniteStatusLineNR StatusLine
  endfunction
  augroup vimrc-plugin-unite-highlight
    autocmd!
    autocmd VimEnter,ColorScheme * call s:unite_status_highlight()
  augroup END

  " custom_actions for unite. {{{3
  " echo action {{{4
  let s:unite_action = {
  \   'description': 'Echo the candidates for debug.',
  \   'is_selectable': 1,
  \ }

  function s:unite_action.func(candidates) abort
    PP a:candidates
  endfunction

  call unite#custom_action('common', 'echo', s:unite_action)
  unlet! s:unite_action

  " tabvsplit action {{{4
  let s:unite_action = {
  \   'description': 'Open files to new tabpage with :vsplit.',
  \   'is_selectable': 1,
  \ }

  function s:unite_action.func(candidates) abort
    tabnew `=a:candidates[0].action__path`
    for c in a:candidates[1 :]
      vsplit `=c.action__path`
    endfor
  endfunction

  call unite#custom_action('openable', 'tabvsplit', s:unite_action)
  unlet! s:unite_action

  " source action for file {{{4
  let s:unite_action = {
  \   'description': ':source files',
  \   'is_selectable': 1,
  \ }

  function s:unite_action.func(candidates) abort
    for c in a:candidates
      source `=c.action__path`
    endfor
  endfunction

  call unite#custom_action('file', 'source', s:unite_action)
  unlet! s:unite_action

  command! UniteBeautifulAttack Unite -auto-preview colorscheme

  " file delete action {{{4
  let s:unite_action = {
  \   'description': 'delete selected files',
  \   'is_selectable': 1,
  \ }

  function s:unite_action.func(candidates) abort
    call map(filter(copy(a:candidates), 'filewritable(v:val.action__path)'),
    \        'delete(v:val.action__path)')
  endfunction

  call unite#custom_action('file', 'delete', s:unite_action)
  unlet! s:unite_action

  " unite-grep.vim  {{{2
  if executable('ack')
    " let g:unite_source_grep_command = 'ack'
    " let g:unite_source_grep_default_opts = '-a'
  endif

  " unite-tag.vim  {{{2
  let g:unite_source_tag_max_fname_length = sort([
  \   30,
  \   &columns - 50,
  \   100,
  \ ], 'n')[1]

  " unite-menu.vim  {{{2
  let g:unite_source_menu_menus = {}

  " unite-outline.vim  {{{2
  call unite#custom_max_candidates('outline', 0)
  let g:unite_source_outline_info = {
  \   'lua': {
  \     'heading': '^\%(local\|function\)\>',
  \   },
  \   'clojure': {
  \     'heading': '^(defn\>',
  \   },
  \   'coffee': {
  \     'heading': '^class\>\|\w\+\s*[:=]\s*\%((.\{-})\s*\)\?[-=]>'
  \   },
  \   'vimspec': {
  \     'heading': '^\c\s*\%(Describe\|Context\|Before\|After\|It\)\>',
  \     'heading_groups': {
  \       'describe': ['describe', 'context'],
  \       'hook': ['before', 'after'],
  \       'example': ['it'],
  \     },
  \     'highlight_rules': [
  \       {
  \         'name': 'summary',
  \         'pattern': '/.*/',
  \         'highlight': 'Constant',
  \       },
  \       {
  \         'name': 'commnd',
  \         'pattern': '/\<\%(Describe\|Context\|Before\|After\|It\)\>/',
  \         'highlight': 'Statement',
  \       },
  \     ],
  \   },
  \ }
  function g:unite_source_outline_info.coffee.create_heading(
  \ which, heading_line, matched_line, context)
    return {
    \   'word': a:heading_line,
    \   'level': (len(matchstr(a:heading_line, '^\s*')) / shiftwidth()) + 1,
    \   'type': a:matched_line =~# '^class' ? 'class' : 'function',
    \ }
  endfunction
  function g:unite_source_outline_info.vimspec.create_heading(
  \ which, heading_line, matched_line, context)
    return {
    \   'word': a:heading_line,
    \   'level': len(matchstr(a:matched_line, '^\s*')) / &l:shiftwidth + 1,
    \   'type': tolower(matchstr(a:heading_line, '^\w\+')),
    \ }
  endfunction
endif

" unite-locate.vim  {{{2
if s:is_win && executable('es')
  let g:unite_locate_command = 'es -i -r -n %d %s'
endif

" ddu.vim  {{{2
if dein#is_sourced('ddu')
  call ddu#custom#patch_global(#{
  \   ui: 'ff',
  \   kindOptions: #{
  \     file: #{
  \       defaultAction: 'open',
  \     },
  \   },
  \   sourceOptions: #{
  \     _: #{
  \       matchers: ['matcher_fzf'],
  \     },
  \   },
  \   filterParams: #{
  \     matcher_fzf: #{
  \       highlightMatched: 'Search',
  \     },
  \   },
  \   uiParams: #{
  \     ff: #{
  \       startFilter: v:true,
  \     },
  \   },
  \ })

  command! -bar -nargs=* -complete=dir DduFilerec
  \   call ddu#start(#{
  \     name: 'file',
  \     sources: [
  \       #{name: 'file_external', params: {}},
  \     ],
  \     sourceParams: #{
  \       file_external: #{
  \         cmd: vimrc#ddu#file_external_cmd(<q-args> ?? getcwd()),
  \         path: len(<q-args>) ? fnamemodify(<q-args>, ':p') : getcwd(),
  \       },
  \     },
  \   })
  command! -bar -nargs=* -complete=dir DduMru
  \   call ddu#start(#{
  \     name: 'file',
  \     sources: [#{name: 'mr'}],
  \   })

  augroup plugin-ddu-ui-ff
    autocmd!
    autocmd FileType ddu-ff call vimrc#ddu#setup_ui_ff_buffer()
    autocmd FileType ddu-ff-filter call vimrc#ddu#setup_ui_ff_filter_buffer()
  augroup END

  " Overwrite unite.vim's mappings
  nnoremap <Leader>ar <Cmd>DduFilerec<CR>
  nnoremap <Leader>am <Cmd>DduMru<CR>
endif

" neomru.vim  {{{2
let g:neomru#file_mru_path = s:plugin_info_dir('neomru') .. 'file'
let g:neomru#directory_mru_path = s:plugin_info_dir('neomru') .. 'directory'
let g:neomru#file_mru_limit = 10000
let g:neomru#file_mru_ignore_pattern = s:temp_file_pat

" mr.vim  {{{2
def s:mru_predicate(filename: string): bool
  return filename !~ '\.git/COMMIT_EDITMSG$' &&
  \   getbufvar(filename, '&buftype', '') == ''
enddef
let g:mr#mru#predicates = [function('s:mru_predicate')]

" alignta.vim  {{{2
vnoremap <C-h> <Cmd>Alignta<CR>
let g:alignta_default_arguments = '\S\+'

" OmniSharp.vim  {{{2
let g:OmniSharp_timeout = 10
let g:OmniSharp_quickFixLength = 1000
let g:Omnisharp_start_server = 0
let g:OmniSharp_server_type = 'roslyn'
let g:OmniSharp_autoselect_existing_sln = 0
command! -nargs=1 -complete=customlist,s:omnisharp_api OmniSharpAPI
\     PP json_decode(pyeval(printf('getResponse("/%s")', <q-args>)))
function s:omnisharp_api(lead, line, pos) abort
  let cand = [
  \   'gotodefinition',
  \   'findsymbols',
  \   'updatebuffer',
  \   'changebuffer',
  \   'codecheck',
  \   'filesChanged',
  \   'formatAfterKeystroke',
  \   'formatRange',
  \   'codeformat',
  \   'highlight',
  \   'autocomplete',
  \   'findimplementations',
  \   'findusages',
  \   'gotofile',
  \   'gotoregion',
  \   'navigateup',
  \   'navigatedown',
  \   'typelookup',
  \   'getcodeactions',
  \   'runcodeaction',
  \   'rename',
  \   'signatureHelp',
  \   'currentfilemembersastree',
  \   'currentfilemembersasflat',
  \   'gettestcontext',
  \   'metadata',
  \   'packagesource',
  \   'packagesearch',
  \   'packageversion',
  \   'projects',
  \   'project',
  \   'fixusings',
  \   'checkalivestatus',
  \   'checkreadystatus',
  \   'stopserver',
  \   'v2/getcodeactions',
  \   'v2/runcodeaction',
  \ ]
  return filter(cand, 'v:val =~# a:lead')
endfunction

" calendar.vim  {{{2
let g:calendar_navi_label = '前月,今月,次月'
let g:calendar_mruler =
\ '睦月,如月,弥生,卯月,皐月,水無月,文月,葉月,長月,神無月,霜月,師走'
let g:calendar_wruler = '日 月 火 水 木 金 土'
nnoremap cal <Plug>CalendarV
nnoremap caL <Plug>CalendarH

" itchyny-calendar.vim  {{{2
let g:calendar_google_calendar = 1
let g:calendar_cache_directory = s:plugin_info_dir('itchyny-calendar')


" gist.vim  {{{2
let g:gist_detect_filetype = 1


" skk.vim  {{{2
let g:skk_large_jisyo = '$VIM_USERDIR/dict/skk/SKK-JISYO.utf-8.L'
let g:skk_auto_save_jisyo = 1
let g:skk_keep_state = 1
let g:skk_egg_like_newline = 1
let g:skk_show_annotation = 1
let g:skk_use_face = 1
highlight default skk_henkan ctermbg=1 ctermfg=15 guibg=#0000FF guifg=#FFFFFF
" Following options are patched by id:krogue.
let g:skk_sticky_key = ';'
let g:skk_kakutei_key = '.'
let g:skk_use_color_cursor = 1
let g:skk_control_j_key = '<C-g><C-j>'

" eskk.vim  {{{2
let g:plugin_skk_disable = 1
" let g:eskk_disable = 1
let g:eskk#large_dictionary = {
\   'path':  '$VIM_USERDIR/dict/skk/SKK-JISYO.utf-8.L',
\   'sorted': 1,
\   'encoding': 'utf-8',
\}

let g:eskk#egg_like_newline = 1
let g:eskk#egg_like_newline_completion = 1
let g:eskk#map_normal_keys = 0
let g:eskk#show_annotation = 1
let g:eskk#rom_input_style = 'msime'
let g:eskk#keep_state = 0
" let g:eskk#keep_state = 1
" let g:eskk#keep_state_beyond_buffer = 1
if s:is_win && !has('gui_running')
  let g:eskk#enable_completion = 0
endif
let g:eskk#directory = s:plugin_info_dir('eskk')
let g:eskk#log_cmdline_level = 2
let g:eskk#log_file_level = 4

inoremap <C-k> <Plug>(eskk:toggle)
cnoremap <C-k> <Plug>(eskk:toggle)

if dein#is_sourced('eskk')
  augroup vimrc-plugin-eskk
    autocmd!
    autocmd CursorHold * silent EskkUpdateDictionary
    autocmd User eskk-initialize-pre call s:init_eskk()
    autocmd User eskk-enable-pre call s:eskk_enable_pre()
    autocmd User eskk-disable-pre call s:eskk_disable_pre()
  augroup END
endif

function s:init_eskk() abort
  let t = eskk#table#new('rom_to_hira*', 'rom_to_hira')
  call t.add_map('va', 'ゔぁ')
  call t.add_map('vi', 'ゔぃ')
  call t.add_map('vu', 'ゔ')
  call t.add_map('ve', 'ゔぇ')
  call t.add_map('vo', 'ゔぉ')
  call t.add_map('z ', ' ')
  call t.add_map('h-', '-')
  call t.add_map('h!', '!')
  call t.add_map('h/', '/')
  call t.add_map('h ', ' ')
  call t.add_map('h:', ':')
  call t.add_map('h;', ';')
  call t.add_map('h[', '[')
  call t.add_map('h]', ']')
  call t.add_map('h(', '(')
  call t.add_map('h)', ')')
  call eskk#register_mode_table('hira', t)
endfunction

function s:eskk_enable_pre() abort
  if exists('*deoplete#disable')
    call deoplete#disable()
  endif

  " For mintty
  if has('unix')
    silent !echo -ne '\e]12;\#FFA500\a'
  endif
endfunction

function s:eskk_disable_pre() abort
  if exists('*deoplete#enable')
    call deoplete#enable()
  endif

  " For mintty
  if has('unix')
    silent !echo -ne '\e]12;\#00FF00\a'
  endif
endfunction


" skkeleton  {{{2
if dein#is_sourced('skkeleton')
  inoremap <C-j> <Plug>(skkeleton-toggle)
  cnoremap <C-j> <Plug>(skkeleton-toggle)
  " let g:skkeleton#debug = v:true

  let s:skkeleton_modes = #{
  \   hira: 'あ',
  \   kata: 'ア',
  \   hankata: 'ァア',
  \   zenkaku: 'a',
  \ }
  function Skkeleton_statusline() abort
    if !skkeleton#is_enabled()
      return ''
    endif
    let mode = skkeleton#mode()
    return '[' .. get(s:skkeleton_modes, mode, mode) .. ']'
  endfunction

  function s:skkeleton_init() abort
    call skkeleton#config(#{
    \   globalJisyo: expand('$VIM_USERDIR/dict/skk/SKK-JISYO.utf-8.L'),
    \   globalJisyoEncoding: 'utf-8',
    \   eggLikeNewline: v:true,
    \   registerConvertResult: v:true,
    \   immediatelyCancel: v:false,
    \ })
    call skkeleton#register_kanatable('rom', {
    \   'z ': [' ', ''],
    \ })
    call skkeleton#register_keymap('henkan', "\<C-h>", 'henkanBackward')
    call skkeleton#register_keymap('input', ';', 'henkanPoint')
  endfunction

  let s:skkeleton_cursor_colors = {
  \   '': '#00FF00',
  \   'hira': '#FFA500',
  \   'kata': '#8B3E2F',
  \   'hankata': '#BEBEBE',
  \   'zenkaku': '#FFD700',
  \ }
  if has('gui_running')
    function s:skkeleton_update_cursor() abort
      let color = get(s:skkeleton_cursor_colors, skkeleton#mode(), '')
      if color isnot# ''
        execute printf('highlight lCursor guifg=bg guibg=%s', color)
      endif
    endfunction
  elseif has('unix')
    function s:skkeleton_update_cursor() abort
      let color = get(s:skkeleton_cursor_colors, skkeleton#mode(), '')
      if color isnot# ''
        execute printf('silent !echo -ne ''\e]12;\%s\a''', color)
      endif
    endfunction
  endif

  function s:skkeleton_enable_pre_ddc() abort
    let b:_ddc_save_config_for_skkeleton = ddc#custom#get_buffer()
    call ddc#custom#patch_buffer(#{
    \   sources: ['skkeleton'],
    \   completionMenu: 'native',
    \ })
    if exists('*pum#close')
      call pum#close()
    endif
  endfunction

  function s:skkeleton_disable_pre_ddc() abort
    if exists('b:_ddc_save_config_for_skkeleton')
      call ddc#custom#set_buffer(b:_ddc_save_config_for_skkeleton)
      unlet b:_ddc_save_config_for_skkeleton
    endif
  endfunction

  augroup vimrc-plugin-skkeleton
    autocmd!
    autocmd User skkeleton-initialize-pre call s:skkeleton_init()
    if dein#is_sourced('ddc')
      autocmd User skkeleton-enable-pre call s:skkeleton_enable_pre_ddc()
      autocmd User skkeleton-disable-pre call s:skkeleton_disable_pre_ddc()
    endif
    autocmd User skkeleton-mode-changed redrawstatus
    if exists('*s:skkeleton_update_cursor')
      autocmd User skkeleton-mode-changed call s:skkeleton_update_cursor()
    endif
  augroup END
endif

" caw.vim  {{{2
nnoremap <Leader>c <Plug>(caw:prefix)
vnoremap <Leader>c <Plug>(caw:prefix)
nnoremap <Plug>(caw:prefix)<Space> <Plug>(caw:hatpos:toggle)
vnoremap <Plug>(caw:prefix)<Space> <Plug>(caw:hatpos:toggle)
nnoremap <Plug>(caw:prefix)w <Plug>(caw:wrap:toggle)
vnoremap <Plug>(caw:prefix)w <Plug>(caw:wrap:toggle)
nnoremap <Plug>(caw:prefix)c <Plug>(caw:hatpos:toggle:operator)

" open-browser.vim  {{{2
nnoremap m<CR> <Plug>(openbrowser-smart-search)
vnoremap m<CR> <Plug>(openbrowser-smart-search)
if !has('gui_running') && executable('lemonade')
  let g:openbrowser_browser_commands = [
  \   {
  \     'name': 'lemonade',
  \     'args': ['{browser}', 'open', '{uri}'],
  \   },
  \ ]
endif

" restart.vim  {{{2
let g:restart_sessionoptions =
\     'blank,curdir,folds,help,localoptions,tabpages,unix'
nnoremap <Leader><Leader>res <Cmd>Restart<CR>

" nextfile.vim  {{{2
let g:nf_ignore_ext = ['meta']
let g:nf_map_next = ''
let g:nf_map_previous = ''
let g:nf_include_dotfiles = 1
let g:nf_loop_files = 1
let g:nf_loop_hook_fn = 'NextFileLoop'
function NextFileLoop(file) abort
  return g:V.input_safe('nextfile: loop?[Y/n]: ', 'y') =~? '^y\%[es]$'
endfunction
if dein#is_sourced('submode')
  call submode#enter_with('nextfile', 'n', '', '<Leader>j', '<Plug>(nextfile-next)')
  call submode#enter_with('nextfile', 'n', '', '<Leader>k', '<Plug>(nextfile-previous)')
  call submode#map('nextfile', 'n', '', 'j', '<Plug>(nextfile-next)')
  call submode#map('nextfile', 'n', '', 'k', '<Plug>(nextfile-previous)')
endif

" submode.vim  {{{2
if dein#is_sourced('submode')
  " let g:submode_timeout = 0
  " TELLME: The above setting do not work.
  " Use the following instead of above.
  let g:submode_timeoutlen = 1000000
  let g:submode_keep_leaving_key = 1

  call submode#enter_with('undo/redo', 'n', '', 'g-', 'g-')
  call submode#enter_with('undo/redo', 'n', '', 'g+', 'g+')
  call submode#map('undo/redo', 'n', '', '-', 'g-')
  call submode#map('undo/redo', 'n', '', '+', 'g+')

  call submode#enter_with('change-list', 'n', '', 'g;', 'g;')
  call submode#enter_with('change-list', 'n', '', 'g,', 'g,')
  call submode#map('change-list', 'n', '', ';', 'g;')
  call submode#map('change-list', 'n', '', ',', 'g,')

  call submode#enter_with('changetab', 'n', '', 'gt', 'gt')
  call submode#enter_with('changetab', 'n', '', 'gT', 'gT')
  call submode#map('changetab', 'n', '', 't', 'gt')
  call submode#map('changetab', 'n', '', 'T', 'gT')

  function s:movetab(nr) abort
    let pos = vimrc#modulo(tabpagenr() - 1 + a:nr, tabpagenr('$'))
    let pos += tabpagenr() <= pos ? 1 : 0
    execute 'tabmove' pos
  endfunction
  let s:movetab = '<Cmd>call ' .. s:SIDP() .. 'movetab(%d)<CR>'
  call submode#enter_with('movetab', 'n', '', '<Space>gt', printf(s:movetab, 1))
  call submode#enter_with('movetab', 'n', '', '<Space>gT', printf(s:movetab, -1))
  call submode#map('movetab', 'n', '', 't', printf(s:movetab, 1))
  call submode#map('movetab', 'n', '', 'T', printf(s:movetab, -1))
  unlet s:movetab

  call submode#enter_with('winsize', 'n', '', '<C-w>>', '<C-w>>')
  call submode#enter_with('winsize', 'n', '', '<C-w><', '<C-w><')
  call submode#enter_with('winsize', 'n', '', '<C-w>+', '<C-w>+')
  call submode#enter_with('winsize', 'n', '', '<C-w>-', '<C-w>-')
  call submode#map('winsize', 'n', '', '>', '<C-w>>')
  call submode#map('winsize', 'n', '', '<', '<C-w><')
  call submode#map('winsize', 'n', '', '+', '<C-w>+')
  call submode#map('winsize', 'n', '', '-', '<C-w>-')
  call submode#map('winsize', 'n', '', '=', '<C-w>=')

  call submode#enter_with('diff', 'n', '', '<Space>D')
  call submode#map('diff', 'n', '', 'j', ']c') " next diff
  call submode#map('diff', 'n', '', 'k', '[c') " prev diff
  call submode#map('diff', 'n', '', 'h', 'do') " get diff
  call submode#map('diff', 'n', '', 'l', 'dp') " put diff
  call submode#map('diff', 'n', '', 'u', 'do]c') " get diff and next diff
  call submode#map('diff', 'n', '', 'i', 'dp]c') " put diff and next diff
endif

" fakeclip.vim  {{{2
nmap "+Y "+y$
nmap "*Y "*y$
nmap "&Y "&y$

" altr.vim  {{{2
if dein#is_sourced('altr')
  call altr#reset()
  call altr#define('%.c', '%.cpp', '%.cc', '%.cxx',
  \                '%.h', '%.hpp', '%.hh', '%.hxx', '%.h++')
  call altr#define('%.coffee', '%.js')
  call altr#define(
  \   'autoload/vital/__*__/%.vim',
  \   'doc/vital/%.txt',
  \   'test/%.vimspec',
  \   'test/%.vim')
  call altr#define('vimrc', 'dein.vim')

  " Rails
  call altr#define(
  \   'app/models/%.rb',
  \   'spec/models/%_spec.rb',
  \   'spec/factories/%s.rb')
  call altr#define(
  \   'app/controllers/%_controller.rb',
  \   'spec/controllers/%_controller_spec.rb',
  \   'app/views/%/*.*',
  \   'spec/requests/%_spec.rb')
  call altr#define('app/%/%.rb', 'spec/%/%_spec.rb')
  call altr#define('lib/%.rb', 'spec/lib/%_spec.rb')
  call altr#define('lib/tasks/%.rake', 'spec/rake/%_spec.rb')

  " nodejs
  call altr#define(
  \   'bin/%.js',
  \   'lib/%.js',
  \   'scripts/%.js',
  \   'test/%.js',
  \ )

  " TypeScript
  call altr#define(
  \   'src/%.ts',
  \   'test/%.test.ts',
  \ )

  " Go
  call altr#define('%.go', '%_test.go')

  nnoremap <C-Space> <Plug>(altr-forward)
  nnoremap <C-S-Space> <Plug>(altr-back)
  nnoremap <C-w><C-Space> <C-w>s<Plug>(altr-forward)
  nnoremap <C-w><C-S-Space> <C-w>s<Plug>(altr-back)
endif

" smartword.vim  {{{2
if dein#is_sourced('smartword')
  nnoremap w  <Plug>(smartword-w)
  nnoremap b  <Plug>(smartword-b)
  nnoremap e  <Plug>(smartword-e)
  nnoremap ge <Plug>(smartword-ge)
  vnoremap w  <Plug>(smartword-w)
  vnoremap b  <Plug>(smartword-b)
  vnoremap e  <Plug>(smartword-e)
  vnoremap ge <Plug>(smartword-ge)
  onoremap <Leader>w <Plug>(smartword-w)
  onoremap <Leader>b <Plug>(smartword-b)
  onoremap <Leader>e <Plug>(smartword-e)
  onoremap <Leader>ge <Plug>(smartword-ge)
endif

" textobj-user.vim  {{{2
if dein#is_sourced('textobj-user')
  "   textobj-function  {{{3
  let g:textobj_function_no_default_key_mappings = 1
  onoremap iF <Plug>(textobj-function-i)
  onoremap aF <Plug>(textobj-function-a)
  vnoremap iF <Plug>(textobj-function-i)
  vnoremap aF <Plug>(textobj-function-a)
  call textobj#user#plugin('camelcase', {
  \   '-': {
  \   '*pattern*': '\C\a[a-z0-9]\+',
  \   'select': ["a\<C-w>", "i\<C-w>"],
  \   },
  \ })

  "   textobj-multitextobj  {{{3
  let g:textobj_multitextobj_textobjects_group_a = {
  \   'A': [
  \     ['a(', 'a[', 'a{', 'a<', 'a"', "a'", '`a']
  \   ],
  \ }
  let g:textobj_multitextobj_textobjects_group_i = {
  \   'A': [
  \     ['i(', 'i[', 'i{', 'i<', 'i"', "i'", '`i']
  \   ],
  \ }
  onoremap ab <Plug>(textobj-multitextobj-A-a)
  onoremap ib <Plug>(textobj-multitextobj-A-i)
  vnoremap ab <Plug>(textobj-multitextobj-A-a)
  vnoremap ib <Plug>(textobj-multitextobj-A-i)
endif

"   textobj-fold
onoremap iz <Plug>(textobj-fold-i)
onoremap az <Plug>(textobj-fold-a)
vnoremap iz <Plug>(textobj-fold-i)
vnoremap az <Plug>(textobj-fold-a)

" operator-user.vim  {{{2
if dein#is_sourced('operator-user')
  "   operator-replace  {{{3
  noremap mp <Plug>(operator-replace)
  vnoremap p <Plug>(operator-replace)

  "   operator-camelize  {{{3
  nnoremap <Leader>oc <Plug>(operator-camelize)iw
  vnoremap <Leader>oc <Plug>(operator-camelize)
  nnoremap <Leader>oC <Plug>(operator-decamelize)iw
  vnoremap <Leader>oC <Plug>(operator-decamelize)

  "   operator-sequence  {{{3
  noremap <expr> <Leader>oU
  \       operator#sequence#map('<Plug>(operator-decamelize)', 'gU') .. 'iw'
  noremap <expr> <Leader>ou
  \       operator#sequence#map('<Plug>(operator-camelize)', ['b~']) .. 'iw'
  noremap <expr> moU
  \       operator#sequence#map('<Plug>(operator-decamelize)', 'gU')

  "   operator-suddendeath  {{{3
  noremap X <Plug>(operator-suddendeath)

  "   operator-insert  {{{3
  noremap mi <Plug>(operator-insert-i)
  noremap ma <Plug>(operator-insert-a)
endif

" gf-user.vim  {{{2
if dein#is_sourced('gf-user')
  "   gf-file  {{{3
  " On MS Windows, 'isfname' contains ':', so "foo.c:30" can not open by gF
  function GfFile() abort
    let path = expand('<cfile>')
    let line = 0
    if path =~# ':\d\+:\?$'
      let line = matchstr(path, '\d\+:\?$')
      let path = matchstr(path, '.*\ze:\d\+:\?$')
    endif
    let path = findfile(path, getcwd() .. ';')
    if !filereadable(path)
      return 0
    endif
    return {
    \   'path': path,
    \   'line': line,
    \   'col': 0,
    \ }
  endfunction
  call gf#user#extend('GfFile', 0)
endif

" ProjectEuler.vim  {{{2
let g:projecteuler_dir = s:plugin_info_dir('projecteuler')
let g:projecteuler_user = 'thinca'
let g:projecteuler_problem_lang = 'ja'

" onlinejadge.vim  {{{2
let g:onlinejudge_account = {'aoj': {'user': 'thinca'}}

" quickhl.vim  {{{2
noremap mh <Plug>(quickhl-manual-this)
noremap mH <Plug>(quickhl-manual-reset)

" yankround.vim  {{{2
if dein#is_sourced('yankround')
  let g:yankround_dir = s:plugin_info_dir('yankround')
  let g:yankround_max_history = 100
  let g:yankround_use_region_hl = 1
  nnoremap <expr> p yankround#is_active() ?
  \             '<Plug>(my-yankround-start)' : '<Plug>(yankround-p)'
  nnoremap P <Plug>(yankround-P)
  nnoremap gp <Plug>(yankround-gp)
  nnoremap gP <Plug>(yankround-gP)
  if dein#is_sourced('submode')
    call submode#enter_with('yankround', 'n', '',
    \               '<Plug>(my-yankround-start)', '<Plug>(yankround-prev)')
    call submode#map('yankround', 'n', '', 'p', '<Plug>(yankround-prev)')
    call submode#map('yankround', 'n', '', 'n', '<Plug>(yankround-next)')
  endif
  nnoremap <Leader>a<C-p> <Cmd>Unite yankround<CR>
endif

" reanimate.vim  {{{2
if dein#is_sourced('reanimate')
  let g:reanimate_default_save_name = ''
  let g:reanimate_default_category = 'session'
  let g:reanimate_save_dir = s:plugin_info_dir('reanimate')
  let g:reanimate_enable_force_load = 1
  let g:reanimate_event_disables = {
  \   '_': {
  \     'reanimate_viminfo': 1,
  \     'reanimate_confirm': 1,
  \     'reanimate_window': 1,
  \     'reanimate_session': 0,
  \     'reanimate_quickfix': 0,
  \     'session_clean': 0,
  \     'gui': 1,
  \   },
  \   'window/default': {
  \     'reanimate_session': 1,
  \     'reanimate_quickfix': 1,
  \     'session_clean': 1,
  \     'reanimate_window': 0,
  \     'gui': 0,
  \   },
  \ }
  let g:reanimate_sessionoptions =
  \     'blank,curdir,folds,help,localoptions,tabpages,unix'
  augroup vimrc-plugin-reanimate
    autocmd!
    if has('gui_running')
      autocmd GUIEnter * ++nested silent! ReanimateLoad window/default
      autocmd VimLeavePre * ReanimateSave window/default
    endif
    autocmd CursorHold,VimLeavePre * ReanimateSaveCursorHold
  augroup END

  let s:event = {'name': 'session_clean'}
  function s:event.load_pre(context) abort
    tabnew
    hide tabonly
    let point = a:context.point
    if point =~# '^session/'
      let g:window_name = 'vim[' .. matchstr(point, '/\zs.*') .. ']'
    endif
  endfunction

  function s:event.save_pre(context) abort
    arglocal
    silent! argdelete *
  endfunction

  function s:event.save_post(context) abort
    argglobal
  endfunction

  call reanimate#hook(s:event)
  unlet s:event

  let s:event = {'name': 'gui'}
  " This must run before reanimate_window
  " Because this canges guifont
  function s:event.load_pre(context) abort
    let file = a:context.path .. '/gui.vim'
    if filereadable(file) && has('gui_running')
      source `=file`
    endif
  endfunction

  function s:event.save(context) abort
    let file = a:context.path .. '/gui.vim'
    if !filereadable(file) || filewritable(file)
      if has('gui')
        let options = [
        \ 'set guioptions=' .. &guioptions,
        \ 'set guifont=' .. escape(&guifont, '\ '),
        \ ]
        call writefile(options, file)
      endif
    endif
  endfunction

  call reanimate#hook(s:event)
  unlet s:event

  nnoremap <Leader>as
  \        <Cmd>Unite reanimate:session -default-action=reanimate_switch<CR>
endif

" hitspop.vim  {{{2
let g:hitspop_line = 'winbot'
let g:hitspop_timeout = 500

" colorv.vim  {{{2
let g:colorv_no_global_map = 1
let g:colorv_cache_file = s:plugin_info_dir('colorv') .. 'cache'
let g:colorv_cache_fav = s:plugin_info_dir('colorv') .. 'fav'

" clever-f.vim  {{{2
let g:clever_f_across_no_line = 1
let g:clever_f_timeout_ms = 2000
let g:clever_f_use_migemo = 1

" operator-surround.vim  {{{2
if dein#is_sourced('operator-surround')
  nnoremap ys <Plug>(operator-surround-append)
  nnoremap ds <Plug>(operator-surround-delete)a
  nnoremap cs <Plug>(operator-surround-replace)a
  nnoremap msa <Plug>(operator-surround-append)
  nnoremap msd <Plug>(operator-surround-delete)
  nnoremap msr <Plug>(operator-surround-replace)
  " let g:operator#surround#ignore_space = 0
endif

" committia.vim  {{{2
let g:committia_hooks = {}
function g:committia_hooks.edit_open(info) abort
  setlocal spell

  inoremap <buffer> <C-e> <Plug>(committia-scroll-diff-down-half)
  inoremap <buffer> <C-y> <Plug>(committia-scroll-diff-up-half)

  if getline(1) ==# ''
    startinsert
  endif
endfunction

" lexima.vim  {{{2
function s:setup_lexima() abort
  let g:lexima_no_default_rules = 1
  let g:lexima_enable_basic_rules = 0
  call lexima#set_default_rules()
  call lexima#add_rule({
  \   'char': '<CR>', 'at': '(\%([^()]\|([^)]*)\)*{\%#$',
  \   'except': '\C\v^(\s*)\S.*%#\n%(%(\s*|\1\s.+)\n)*\1}\);',
  \   'input': '<CR>', 'input_after': '<CR>});',
  \   'filetype': ['javascript', 'typescript'],
  \ })
  call lexima#add_rule({
  \   'char': '<CR>', 'at': '{\%#}',
  \   'input': '<CR><Bslash>   ', 'input_after': '<CR><Bslash> ',
  \   'filetype': ['vim', 'vimspec'],
  \ })
  call lexima#add_rule({
  \   'char': '<CR>', 'at': '{\%#$',
  \   'input': '<CR><Bslash>   ', 'input_after': '<CR><Bslash> }',
  \   'filetype': ['vim', 'vimspec'],
  \ })
  call lexima#add_rule({
  \   'char': '<CR>', 'at': '[\%#$',
  \   'input': '<CR><Bslash>   ', 'input_after': '<CR><Bslash> ]',
  \   'filetype': ['vim', 'vimspec'],
  \ })
  call lexima#add_rule({
  \   'char': '<CR>', 'at': '\C\v^\s*%(Describe|Context|Before|After|It)>.*%#$',
  \   'except': '\C\v^(\s*)\S.*%#\n%(%(\s*|\1\s.+)\n)*\1End',
  \   'input': '<CR>', 'input_after': '<CR>End',
  \   'filetype': 'vimspec',
  \ })
  call lexima#add_rule({
  \   'char': 'd', 'at': 'end\%#$',
  \   'input': '<CR>end',
  \   'filetype': 'ruby',
  \ })
  call lexima#add_rule({
  \   'char': '<CR>', 'at': 'do\%#$',
  \   'input': '<CR>', 'input_after': '<CR>end',
  \   'filetype': 'elixir',
  \ })
  if dein#is_sourced('neocomplete')
    call lexima#insmode#map_hook('before', '<CR>', "\<C-r>=neocomplete#close_popup()\<CR>")
  endif
  " Also use <CR> rule via o
  nmap o A<CR>
endfunction
if dein#is_available('lexima')
  call dein#set_hook('lexima', 'hook_post_source', function('s:setup_lexima'))
endif

" sideways.vim  {{{2
nnoremap <Leader>< <Plug>SidewaysLeft
nnoremap <Leader>> <Plug>SidewaysRight

" previm.vim  {{{2
let g:previm_enable_realtime = 1

" operator-insert.vim  {{{2
if dein#is_sourced('operator-insert')
  nnoremap <Leader>I <Plug>(operator-insert-i)
  nnoremap <Leader>A <Plug>(operator-insert-a)
endif

" rogue.vim  {{{2
let g:rogue#directory = s:plugin_info_dir('rogue')

" ambicmd.vim  {{{2
if dein#is_sourced('ambicmd')
  cnoremap <expr> <Space> '<C-]>' .. ambicmd#expand('<Space>')
  cnoremap <expr> <CR>    '<C-]>' .. ambicmd#expand('<CR>')
  cnoremap <expr> <C-f>   ambicmd#expand('<Right>')
  cnoremap <expr> !       ambicmd#expand('!')
  augroup vimrc-plugin-ambicmd
    autocmd! CmdwinEnter * call s:init_cmdwin()
  augroup END
endif

function s:init_cmdwin() abort
  inoremap <buffer> <expr> <Space> '<C-]>' .. ambicmd#expand('<Space>')
  inoremap <buffer> <expr> <CR>    '<C-]>' .. ambicmd#expand('<CR>')
  inoremap <buffer> <expr> <C-f>   ambicmd#expand('<Right>')
  inoremap <buffer> <expr> !       ambicmd#expand('!')
  inoremap <buffer> <expr> <C-h> col('.') == 1 ? '<Esc><C-w>c' : '<C-h>'
  inoremap <buffer> <expr> <C-r><C-w> '<C-c><C-r><C-w>' .. &g:cedit
  nnoremap <buffer> <Esc> <C-w>c
  nnoremap <buffer> <Esc><Esc> <C-w>c
  nnoremap <buffer> <nowait> q <C-w>c
  startinsert!
endfunction

" singleton.vim  {{{2
let g:singleton#opener = 'Opener'

" github.vim  {{{2
let g:github#debug = 1
let g:github#info_directory = s:plugin_info_dir('github')
let g:github#debug_file = s:plugin_info_dir('github') .. 'log/debug-%Y-%m-%d.log'

" poslist.vim  {{{2
if dein#is_sourced('poslist')
  let g:poslist_histsize = 1000
  noremap <C-o> <Plug>(poslist-prev-pos)
  noremap <C-i> <Plug>(poslist-next-pos)
  noremap <Leader><C-o> <Plug>(poslist-prev-line)
  noremap <Leader><C-i> <Plug>(poslist-next-line)
  noremap <Space><C-o> <Plug>(poslist-prev-buf)
  noremap <Space><C-i> <Plug>(poslist-next-buf)
endif

" quickrun.vim  {{{2
if dein#is_sourced('quickrun')
  function s:init_quickrun() abort
    for [key, c] in items({
    \   '<Leader>x': '>message',
    \   '<Leader>p': '-runner shell',
    \   '<Leader>"': '>variable:@"',
    \   '<Leader>w': '',
    \   '<Leader>W': '-append 1',
    \   '<Leader>ex': '-hook/eval/enable 1 >message',
    \   '<Leader>ep': '-hook/eval/enable 1 -runner shell',
    \   '<Leader>e"': '-hook/eval/enable 1 >variable:@"',
    \   '<Leader>ew': '-hook/eval/enable 1',
    \   '<Leader>eW': '-hook/eval/enable 1 -append 1',
    \ })
      execute 'nnoremap <silent>' key ':QuickRun' c '-mode n<CR>'
      execute 'vnoremap <silent>' key ':QuickRun' c '-mode v<CR>'
    endfor
    nnoremap <Leader>r <Plug>(quickrun-op)

    let g:quickrun_config = {
    \   '_': {
    \     'debug': 'ss',
    \     'input': '=%{b:input}', 'cmdopt': '%{b:cmdopt}', 'args': '%{b:args}',
    \     'runner': 'job',
    \   },
    \   'c/tcc': {'command': 'tcc', 'exec': '%c -run %o %s %a',
    \             'hook/eval/template': 'int main(int argc, char *argv[]){%s;}'},
    \   'cpp/gcc': {'cmdopt': '-std=c++0x'},
    \   'cpp/C': {'cmdopt': '-lstd=c++0x'},
    \   'clojure': {
    \     'command': 'clojure-1.4',
    \     'hook/eval/template': '(prn (do %s))'
    \   },
    \   'msil': {
    \     'command': 'ilasm',
    \   },
    \   'mysql': {
    \     'type': 'sql/mysql',
    \   },
    \   'powershell': {
    \     'type': 'ps1',
    \   },
    \   'lhaskell': {'command': 'runghc', 'tempfile': '%{tempname()}.lhs'},
    \   'nilscript': {'exec': 'ng.exe %s %a'},
    \   'ruby': {'hook/ruby_bundle/enable': 1},
    \   'ruby/rspec': {
    \     'command': 'rspec',
    \     'hook/ruby_bundle/enable': 1,
    \   },
    \   'xmodmap': {},
    \   'mxml': {'exec': ['amxmlc %s', 'adl %s:r-app.xml'],
    \            'output_encode': '&termencoding'},
    \   'vimgolf': {
    \     'command': 'vi',
    \     'exec': [
    \       '(cat > /tmp/out)',
    \       '(TERM=dumb %c -u NONE -i NONE -n -C -s %s /tmp/out >/dev/null 2>\&1)',
    \       '(cat /tmp/out)',
    \     ],
    \     'hook/sweep/files': '/tmp/out',
    \   },
    \   'vimspec': {
    \     'command': 'themis',
    \     'hook/output_encode/encoding': '&termencoding',
    \     'hook/output_encode/fileformat': 'unix',
    \   },
    \ }

    let g:quickrun_config['csharp'] = {'type': 'cs'}

    let s:watchdogs_config = {
    \   'vim/watchdogs_checker': {
    \     'type': 'watchdogs_checker/vint',
    \   },
    \   'watchdogs_checker/_': {
    \     'outputter': 'loclist',
    \     'runner': 'job',
    \   },
    \   'watchdogs_checker/vint': {
    \     'command': 'vint',
    \     'exec': '%c %o %s',
    \   },
    \   'watchdogs_checker/rubocop': {
    \     'command': 'rubocop',
    \     'exec': '%c --format emacs %s',
    \     'outputter/quickfix/errorformat': '%f:%l:%c: %t: %m',
    \   },
    \   'watchdogs_checker/omnisharp': {
    \     'exec': 'call setloclist(0, OmniSharp#CodeCheck()) | lwindow',
    \     'runner': 'vimscript',
    \   },
    \   'watchdogs_checker/eslint': {
    \     'command': './node_modules/.bin/eslint',
    \     'exec': '%c --format unix %o %s',
    \     'outputter/loclist/errorformat': '%f:%l:%c: %m,%-G%.%#',
    \   },
    \ }

    let g:quickrun_config['csharp/watchdogs_checker'] = {
    \   'type': 'watchdogs_checker/omnisharp'
    \ }
    let g:quickrun_config['javascript/watchdogs_checker'] = {
    \   'type': 'watchdogs_checker/eslint'
    \ }
    " let s:watchdogs_config['ruby/watchdogs_checker'] =
    " \   {'type': 'watchdogs_checker/rubocop'}

    call extend(g:quickrun_config, s:watchdogs_config)

    if executable('C')
      let g:quickrun_config.c   = {'type': 'c/C'}
      let g:quickrun_config.cpp = {'type': 'cpp/C'}
    endif
    " if executable('tcc')
    "   let g:quickrun_config.c = {'type': 'c/tcc'}
    " endif
    let ruby_bundle_hook = {'kind': 'hook', 'name': 'ruby_bundle'}
    function ruby_bundle_hook.on_normalized(session, context) abort
      if getcwd() !=# $HOME && isdirectory('.bundle')
        let a:session.config.exec =
        \   map(copy(a:session.config.exec), 's:bundle_exec(v:val)')
      endif
    endfunction
    function s:bundle_exec(cmd) abort
      return substitute(a:cmd, '\ze%c', 'bundle exec ', '')
    endfunction
    call quickrun#module#register(ruby_bundle_hook, 1)

    let rust_cargo_hook = {'kind': 'hook', 'name': 'rust_cargo'}
    function rust_cargo_hook.on_normalized(session, context) abort
      if a:session.config.type ==# 'rust' &&
      \   findfile('Cargo.toml', '.;') !=# ''
        let a:session.config.exec = ['cargo run --quiet']
      endif
    endfunction
    call quickrun#module#register(rust_cargo_hook, 1)

    noremap <Leader>or <Plug>(quickrun-op)
  endfunction
  call s:init_quickrun()

  augroup vimrc-plugin-quickrun
    autocmd!
    autocmd BufReadPost,BufNewFile [Rr]akefile{,.rb}
    \ let b:quickrun_config = {'exec': 'rake -f %s'}
  augroup END

  function s:complete_open_scratch(a, c, p) abort
    return sort(filter(keys(extend(copy(g:quickrun#default_config),
    \           g:quickrun_config)), 'v:val !~# "[*_/]" && v:val =~# "^".a:a'))
  endfunction
  function s:open_scratch() abort
    let ft = input('type?', '', 'customlist,' .. s:SIDP()
    \ .. 'complete_open_scratch')
    if ft ==# ''
      return
    endif
    if 78 * 2 < winwidth(0)
      vnew
    else
      new
    endif
    lcd ~
    let &l:filetype = ft
    call template#load('Scratch.' .. ft)
  endfunction
  nnoremap <Leader><Leader>s <Cmd>call <SID>open_scratch()<CR>
endif

" ref.vim  {{{2
let g:ref_open = 'vsplit'
let g:ref_use_vimproc = 0
let g:ref_cache_dir = s:plugin_info_dir('ref')
let g:ref_clojure_cmd = 'clojure-1.4'
let g:ref_clojure_precode = '(use ''[clojure.repl :only (doc find-doc)])'
let g:ref_phpmanual_path = $HOME .. '/local/share/doc/php'
if executable('perlfind')
  let g:ref_perldoc_cmd = 'perlfind'
endif
if executable('refe2')
  let g:ref_refe_cmd = 'refe2'
endif
let g:ref_source_webdict_sites = {
\   'alc': {'url': 'https://eow.alc.co.jp/search?q=%s'},
\   'wikipedia': {'url': 'https://ja.wikipedia.org/wiki/%s', 'line': 19},
\   'wiktionary': {
\     'url': 'https://ja.wiktionary.org/wiki/%s',
\     'keyword_encoding': 'utf-8',
\     'cache': 1,
\   },
\   'weblio' : {'url' : 'https://ejje.weblio.jp/content/%s'},
\ }
function g:ref_source_webdict_sites.alc.filter(output) abort
  return substitute(a:output, '^.\{-}\n\ze・該当件数', '', '')
endfunction
function g:ref_source_webdict_sites.wikipedia.filter(output) abort
  return join(split(a:output, "\n")[18 :], "\n")
endfunction
function g:ref_source_webdict_sites.weblio.filter(output) abort
  let lines = split(a:output, "\n")
  call map(lines, 'substitute(v:val, "\\v(発音記号|音声を聞く|ダウンロード再生)", "", "g")')
  return join(lines[60 : ], "\n")
endfunction
let g:ref_source_webdict_sites.default = 'alc'
let g:ref_source_webdict_use_cache = 1
if executable('w3m')
  let g:ref_source_webdict_cmd = 'w3m -dump -O utf-8 %s'
  let g:ref_source_webdict_encoding = 'utf-8'
endif
let s:lynx_cmd = 'C:\Program Files\Lynx for Win32\lynx.exe'
if !exists('g:ref_source_webdict_cmd') &&
\  s:is_win &&
\  executable(s:lynx_cmd)
  let g:ref_source_webdict_cmd = [s:lynx_cmd, '-dump', '-nonumbers', '%s']
  let g:ref_phpmanual_cmd = g:ref_source_webdict_cmd
endif
nnoremap <Space>K <Cmd>call ref#jump('normal', 'webdict', {'noenter': 1})<CR>
vnoremap <silent> <Space>K
\ :<C-u>call ref#jump('visual', 'webdict', {'noenter': 1})<CR>
nnoremap <Space><C-k> :<C-u>Ref webdict alc<Space>
nnoremap <Space><C-h> :<C-u>Ref <C-r>=ref#detect()<CR><Space>
if !exists('g:ref_detect_filetype')
  let g:ref_detect_filetype = {}
endif
function! g:ref_detect_filetype._(ft) abort
  return &keywordprg ==# ':help' ? '' : 'man'
endfunction

" scall.vim  {{{2
let g:scall_function_name = 'S'

" breadcrumbs.vim  {{{2
augroup vimrc-breadcrumbs-auto
  autocmd!
  autocmd BufReadPost *_spec.rb BreadcrumbsOn
  autocmd FileType json,yaml BreadcrumbsOn
augroup END

" template.vim  {{{2
augroup vimrc-plugin-template
  autocmd!
  autocmd FileType * if exists('*template#load')
  \                |   call template#load('/filetype/' .. &l:filetype)
  \                | endif
  autocmd User plugin-template-loaded call s:template_loaded()
  autocmd BufEnter $VIM_USERDIR/template/* setlocal makeprg=
augroup END
function s:template_loaded() abort
  silent keeppatterns %substitute/<%=\(.\{-}\)%>/\=eval(submatch(1))/ge
  if exists('b:template_loaded')
    unlet b:template_loaded
    return
  endif
  let b:template_loaded = 1
  while search('^:TemplateLoad!', 'cw')
    let cmd = getline('.')
    . delete _
    execute cmd
  endwhile
  1
  if search('<+CURSOR+>')
    normal! "_da>
  endif
endfunction

" prettyprint.vim  {{{2
let g:prettyprint_string = ['split']

" wtrans.vim  {{{2
let g:wtrans#source_filters = [
\   'wtrans#filter#remove_help_marks',
\   'wtrans#filter#remove_commentstring',
\   'wtrans#filter#split_a_word',
\   'wtrans#filter#shrink_whitespace',
\ ]
noremap <Space>tt <Plug>(operator-wtrans-echomsg)
noremap <Space>ts <Plug>(operator-wtrans-replace)

" threes.vim  {{{2
let g:threes#data_directory = s:plugin_info_dir('threes')
let g:threes#start_with_higher_tile = 1

" vcs.vim  {{{2
function s:convert_pattern(pat) abort
  let chars = split(a:pat, '\zs')
  let len = len(chars)
  let pat = ''
  let i = 0
  while i < len
    let ch = chars[i]
    if ch ==# '\'
      let nch = chars[i + 1]
      if nch =~# '[vVmM<>%]'
        let i += 1
      elseif nch ==# 'z'
        let i += 2
      elseif nch ==# '%'
        let i += 2
        let pat ..= chars[i]
      else
        let pat ..= ch
      endif
    else
      let pat ..= ch
    endif
    let i += 1
  endwhile
  return escape(pat, ' ')
endfunction

if dein#is_sourced('vcs')
  let g:vcs#debug = 1
  let g:vcs#buffer#opener = 'new'
  nnoremap <Leader>va  <Cmd>Vcs add<CR>
  nnoremap <Leader>vb  <Cmd>Vcs blame<CR>
  nnoremap <Leader>vc  <Cmd>Vcs commit<CR>
  nnoremap <Leader>vd  <Cmd>Vcs diff<CR>
  nnoremap <Leader>vD  <Cmd>Vcs delete<CR>
  nnoremap <Leader>vs  <Cmd>Vcs status<CR>
  nnoremap <Leader>vl  <Cmd>Vcs log<CR>
  nnoremap <Leader>vzl <Cmd>Vcs log %<CR>
  nnoremap <Leader>vzc <Cmd>Vcs commit %<CR>
  nnoremap <Leader>vzd <Cmd>Vcs diff %<CR>
  nnoremap <silent> <Leader>vg
  \        :<C-u>Vcs grep '<C-r>=<SID>convert_pattern(@/)<CR>'<CR>

elseif dein#is_sourced('gina')  " gina.vim {{{2
  call gina#custom#command#option('commit', '--group', 'commit')
  call gina#custom#command#option('commit', '--opener', 'new')
  call gina#custom#command#option('diff', '--opener', 'split')
  call gina#custom#command#option('status', '--group', 'status')
  call gina#custom#command#option('status', '--opener', 'new')

  nnoremap <silent> <Leader>va  <Cmd>Gina add %:p<CR>
  nnoremap <silent> <Leader>vb  <Cmd>Gina blame<CR>
  nnoremap <silent> <Leader>vc  <Cmd>Gina commit<CR>
  nnoremap <silent> <Leader>vd  <Cmd>Gina diff<CR>
  nnoremap <silent> <Leader>vD  <Cmd>Gina rm %:p<CR>
  nnoremap <silent> <Leader>vs  <Cmd>Gina status<CR>
  nnoremap <silent> <Leader>vl  <Cmd>Gina log<CR>
  nnoremap <silent> <Leader>vzl <Cmd>Gina log :%:p<CR>
  nnoremap <silent> <Leader>vzc <Cmd>Gina commit :%:p<CR>
  nnoremap <silent> <Leader>vzd <Cmd>Gina diff :%:p<CR>
  nnoremap <silent> <Leader>vg
  \        :<C-u>Gina qrep! '<C-r>=<SID>convert_pattern(@/)<CR>' -- <C-r>=getcwd()<CR><CR>
endif


" gita.vim  {{{2
let g:gita#command#diff#default_options = {
\   'opener': 'vsplit',
\ }

" EasyMotion.vim  {{{2
let g:EasyMotion_do_mapping = 0
let g:EasyMotion_keys = ';HKLYUIONM,WERTXCVBASDGJF'
let g:EasyMotion_use_migemo = 1
let g:EasyMotion_smartcase = 1
let g:EasyMotion_skipfoldedline = 0
let g:EasyMotion_use_upper = 1
noremap <Leader>f <Plug>(easymotion-overwin-f2)

" edgemotion.vim  {{{2
noremap [d <Plug>(edgemotion-k)
noremap ]d <Plug>(edgemotion-j)

" matchit.vim  {{{2
let g:matchup_matchparen_status_offscreen = 0

" open-googletranslate.vim  {{{2
if executable('electron-open')
  let g:opengoogletranslate#openbrowsercmd = 'electron-open'
endif

" ctrlp.vim  {{{2
let g:ctrlp_map = ''

" lsp.vim  {{{2
" To troubleshoot
" let s:lsp_log_dir = s:plugin_info_dir('lsp') .. 'log/'
" call mkdir(s:lsp_log_dir, 'p')
" let g:lsp_log_file = s:lsp_log_dir .. strftime('%Y-%m-%d.log')
" let g:lsp_log_verbose = 1

let g:lsp_diagnostics_float_cursor = 1

let g:lsp_settings = {
\   'efm-langserver': {
\     'disabled': 0,
\   },
\ }

function s:lsp_format() abort
  silent LspDocumentFormatSync
  silent LspCodeActionSync source.organizeImports
endfunction

function s:on_lsp_buffer_enabled() abort
  if &l:buftype isnot# '' || win_gettype() isnot# ''
    return
  endif
  setlocal omnifunc=lsp#complete
  setlocal signcolumn=yes
  nnoremap <buffer> gd <Plug>(lsp-definition)
  nnoremap <buffer> <C-w>d <Cmd>rightbelow LspDefinition<CR>
  nnoremap <buffer> <C-w><C-d> <Cmd>rightbelow LspDefinition<CR>
  nnoremap <buffer> <f2> <Plug>(lsp-rename)
  nnoremap <buffer> [q <Plug>(lsp-previous-diagnostic)
  nnoremap <buffer> ]q <Plug>(lsp-next-diagnostic)
  nnoremap <buffer> mt <Plug>(lsp-hover)
  nnoremap <buffer> mz <Plug>(lsp-code-action)

  if &filetype is# 'go'
    augroup vimrc-plugin-lsp-ft-go
      autocmd! * <buffer>
      autocmd BufWritePre <buffer> call s:lsp_format()
    augroup END
  endif

  if dein#is_sourced('ddc')
    let sources = get(ddc#custom#get_global(), 'sources', v:null)
    if sources isnot v:null
      call ddc#custom#patch_buffer('sources', ['vim-lsp'] + sources)
    endif
  endif
endfunction

augroup vimrc-plugin-lsp
  autocmd!
  autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
augroup END

" emphasiscursor.vim  {{{2
nnoremap <Space><Space> <Nop>
nnoremap <Space><Space><Space> <Cmd>EmphasisCursor<CR>

" plasticboy/vim-markdown  {{{2
let g:vim_markdown_no_default_key_mappings = 1
let g:vim_markdown_new_list_item_indent = 0

" pocke/iro.vim  {{{2
if dein#is_sourced('iro')
  let s:iro_ft = g:iro#enabled_filetypes
  let s:iro_ft.yaml = 0
endif

" default plugins  {{{2
let g:loaded_matchparen = 1



" == Misc. == {{{1
" Assist b:undo_ftplugin
function SetUndoFtplugin(com) abort
  let command = 'execute ' .. string(a:com)
  if exists('b:undo_ftplugin')
    if 0 <= stridx(b:undo_ftplugin, command)
      return
    endif
    let command ..= ' | ' .. b:undo_ftplugin
  endif
  let b:undo_ftplugin = command
endfunction
command! -nargs=1 -bang -complete=command SetUndoFtplugin
\ call SetUndoFtplugin(<q-args>)

" syntax test
function CurrentSyntax() abort
  let syntax = synstack(line('.'), col('.'))
  return empty(syntax) ? '' : synIDattr(syntax[-1], 'name')
endfunction
nnoremap <Plug>(vimrc-show-current-syntax)
\ <Cmd>echo join(map(synstack(line('.'), col('.')),
\ 'synIDattr(v:val, "name")
\ .. "(" .. synIDattr(synIDtrans(v:val), "name") .. ")"'), ',')<CR>
nnoremap <C-CR> <Plug>(vimrc-show-current-syntax)
nnoremap mx <Plug>(vimrc-show-current-syntax)
inoremap <C-CR> <C-o><Plug>(vimrc-show-current-syntax)


command! -nargs=1 -complete=command -bang Time
\         call vimrc#time(<q-args>, <bang>0)

command! -range=% Tsv2csv
\   if getline(<line1>) =~# '\t'
\ |   silent! keeppatterns <line1>,<line2> substitute/\t/","/g
\ |   silent! keeppatterns <line1>,<line2> substitute/^\|$/"/g
\ | endif


if dein#is_sourced('localrc')
  " Load a setting for machine local.
  call localrc#load('local.vim', s:vim_config_dir, 1)

  if !v:vim_did_enter
    call localrc#load('.init.after.vimrc', getcwd())
  endif
endif

Set secure