" #plugins {{{
if empty(glob('~/.vim/autoload/plug.vim'))
  silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
    \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
call plug#begin('~/.vim/bundle')
"css3-syntax
Plug 'hail2u/vim-css3-syntax'
"scss-syntax
Plug 'cakebaker/scss-syntax.vim'
"tagbar
Plug 'majutsushi/tagbar'
"vim-surround
Plug 'tpope/vim-surround'
"undotree
Plug 'mbbill/undotree'
" Ctrlp
Plug 'ctrlpvim/ctrlp.vim'
"
" Obsession
Plug 'tpope/vim-obsession'
" vim-css-color
" Plug 'ap/vim-css-color'
" vim-javascript
Plug 'pangloss/vim-javascript'
" ultisnips
" https://github.com/sirver/UltiSnips
Plug 'SirVer/ultisnips'
" and some snippets
" https://github.com/honza/vim-snippets
" Plug 'honza/vim-snippets'
" ALE
" https://github.com/w0rp/ale
Plug 'w0rp/ale'
" MatchTag
" https://github.com/gregsexton/MatchTag
" DISABLED DUE TO KNOWN ISSUE - https://github.com/gregsexton/MatchTag/issues/40
" Plug 'gregsexton/MatchTag'
" phpcomplete.vim
" https://github.com/shawncplus/phpcomplete.vim
Plug 'shawncplus/phpcomplete.vim'
" https://github.com/dsawardekar/wordpress.vim
" For up to date Wordpress Files see:
"   https://github.com/joseluis/wordpress.vim-generator
"Plug 'dsawardekar/wordpress.vim'
" disabled - doesn't support universal ctags?
" vim-vue
" https://github.com/posva/vim-vue
Plug 'posva/vim-vue'
" vim-commentary
" https://github.com/tpope/vim-commentary
Plug 'tpope/vim-commentary'
" vim-repeat
" https://github.com/tpope/vim-repeat
Plug 'tpope/vim-repeat'
" https://github.com/mattn/emmet-vim
Plug 'mattn/emmet-vim'
" vimwiki
" https://github.com/vimwiki/vimwiki
Plug 'vimwiki/vimwiki'
" gitgutter
" https://github.com/airblade/vim-gitgutter/blob/master/README.mkd
Plug 'airblade/vim-gitgutter'
" vim-gutentags
" https://github.com/ludovicchabant/vim-gutentags
Plug 'ludovicchabant/vim-gutentags'
" vim-qlist
" https://github.com/romainl/vim-qlist/
" Plug 'romainl/vim-qlist'
" fugitive-vim
" https://github.com/tpope/vim-fugitive/blob/master/README.markdown
Plug 'tpope/vim-fugitive'
" vim-dispatch
" https://github.com/tpope/vim-dispatch
Plug 'tpope/vim-dispatch'
" colorV
" https://github.com/gu-fan/colorv.vim
Plug 'gu-fan/colorv.vim'
" vim switch
"https://github.com/AndrewRadev/switch.vim
Plug 'AndrewRadev/switch.vim'
" gitv
" https://github.com/gregsexton/gitv
Plug 'gregsexton/gitv'
" wakarime
" https://wakatime.com/vim
Plug 'wakatime/vim-wakatime'
" vim-easy-align
" https://github.com/junegunn/vim-easy-align
Plug 'junegunn/vim-easy-align'
" vim-instant-markdown
" https://github.com/suan/vim-instant-markdown
" Plug 'suan/vim-instant-markdown'
" asyncomplete.vim
" https://github.com/prabirshrestha/asyncomplete.vim
" Plug 'prabirshrestha/asyncomplete.vim'
" Plug 'yami-beta/asyncomplete-omni.vim'
" Plug 'prabirshrestha/asyncomplete-ultisnips.vim'
" Plug 'prabirshrestha/asyncomplete-file.vim'
" Plug 'prabirshrestha/asyncomplete-buffer.vim'
" Plug 'prabirshrestha/asyncomplete-tags.vim'
" Plug 'prabirshrestha/asyncomplete-lsp.vim'
" Plug 'Shougo/neco-vim'
" Plug 'prabirshrestha/asyncomplete-necovim.vim'
" vim-lsp
" https://github.com/prabirshrestha/vim-lsp
Plug 'prabirshrestha/async.vim'
Plug 'prabirshrestha/vim-lsp'
" inline_edit.vim
" https://github.com/AndrewRadev/inline_edit.vim
Plug 'AndrewRadev/inline_edit.vim'
" Activity Watch
" https://github.com/ActivityWatch/aw-watcher-vim
Plug 'ActivityWatch/aw-watcher-vim'
call plug#end()
runtime macros/matchit.vim
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #plugin settings {{{
" inline_edit.vim{{{
let g:inline_edit_patterns = [{
    \ 'main_filetype':     '*html',
    \ 'sub_filetype':      'scss',
    \ 'indent_adjustment': 1,
    \ 'start':             ''
  \ }]
let g:inline_edit_autowrite = 1
let g:inline_edit_proxy_type = 'tempfile'
let g:inline_edit_new_buffer_command ='tabedit'
let g:inline_edit_modify_statusline = 0
nnoremap ie :InlineEdit
"}}}
" vim-lsp{{{
let g:lsp_signs_enabled = 1
let g:lsp_signs_error = {'text': '>>'}
let g:lsp_signs_warning = {'text': '>'}
let g:lsp_signs_information = {'text': '--'}
let g:lsp_signs_hint = {'text': '--'}
let g:lsp_diagnostics_echo_cursor = 1
let g:lsp_diagnostics_echo_delay = 0
nnoremap \l :LspDocumentDiagnostics
nnoremap \h :LspHover
nnoremap \d :LspDefinition
nnoremap \r :LspReferences
nnoremap \n :LspRename
nnoremap \s :LspDocumentSymbol
nnoremap \w :LspWorkspaceSymbol
nnoremap \ff :LspDocumentFormat
nnoremap \fr :LspDocumentRangeFormat
augroup User lsp_setup 
  autocmd!
  if executable('vls')
    autocmd User lsp_setup call lsp#register_server({
          \ 'name': 'vue',
          \ 'cmd': {server_info->['vls']},
          \ 'whitelist': ['vue'],
          \ })
  endif
  if executable('pyls')
    autocmd User lsp_setup call lsp#register_server({
          \ 'name': 'pyls',
          \ 'cmd': {server_info->['pyls']},
          \ 'whitelist': ['python'],
          \ })
  endif
  if executable('typescript-language-server')
    au User lsp_setup call lsp#register_server({
      \ 'name': 'typescript-language-server',
      \ 'cmd': { server_info->[&shell, &shellcmdflag, 'typescript-language-server --stdio']},
      \ 'root_uri': { server_info->lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_directory(lsp#utils#get_buffer_path(), '.git/..'))},
      \ 'whitelist': ['typescript', 'javascript', 'javascript.jsx']
      \ })
  endif
augroup END
"}}}
" ALE {{{
nnoremap ne :lnext
nnoremap pe :lprev
let g:ale_sign_error = '>>'
let g:ale_sign_warning = '>'
let g:ale_sign_column_always = 1
let g:ale_open_list = 0
" let g:ale_linters = {'scss': ['stylelint'], 'javascript': ['eslint'], 'php':['php'], 'html':['htmlhint'], 'python': [], 'vue': []}
let g:ale_linters = {'scss': ['stylelint'], 'javascript': [], 'php':['php'], 'html':['htmlhint'], 'python': [], 'vue': []}
" let g:ale_linters_explicit = 1
let g:ale_html_htmlhint_options = '-c ~/.htmlhintrc --format=unix'
let g:ale_fixers = {'javascript': ['eslint']}
"}}}
" vim-easy-align {{{
xmap ga (EasyAlign)
nmap ga (EasyAlign)
"}}}
" switch.vim{{{
let g:switch_mapping = '-'
let g:switch_custom_definitions = [
  \ ['0', '1'],
  \ ['ease-in', 'ease-out'],
  \ ['auto', 'none'],
  \ ['left', 'right'],
  \ ['top', 'bottom'],
  \ ['relative', 'absolute', 'fixed']
\ ]
"}}}
" gitgutter{{{
nmap ]h GitGutterNextHunk
nmap [h GitGutterPrevHunk
omap ih GitGutterTextObjectInnerPending
omap ah GitGutterTextObjectOuterPending
xmap ih GitGutterTextObjectInnerVisual
xmap ah GitGutterTextObjectOuterVisual
"}}}
" Use the silver searcher ag command instead of grep{{{
if executable('ag')
  " Use ag over grep
  set grepprg=ag\ --nogroup\ --nocolor\ --ignore\ node_modules
  " Use ag in CtrlP for listing files. Lightning fast and respects .gitignore
  let g:ctrlp_user_command = 'ag %s -l --nocolor -g ""'
  " ag is fast enough that CtrlP doesn't need to cache
  let g:ctrlp_use_caching = 0
endif
"vim-wiki
let g:vimwiki_list = [{'path': '~/vimwiki/', 'path_html': '~/vimwiki_html/'}]
" emmet
let g:user_emmet_leader_key=',,'
let g:user_emmet_settings = {
\  'indentation': '  ',
\  'html': {
\    'indentation': '    ',
\  }
\}
"}}}
" vue-vim{{{
" disable preprocessor checking for vue files - increases speed
let g:vue_disable_pre_processors=0
" set custom syntax highlighting
augroup fixhighlighting
  autocmd!
  autocmd BufNewFile,BufRead *.vue syntax sync fromstart
augroup END
"}}}
" ultisnips{{{
nnoremap ul :call ListUltisnips()
inoremap jkul :call ListUltisnips()
let g:UltiSnipsSnippetsDir='~/.vim/UltiSnips'
" Trigger configuration. Do not use  if you use https://github.com/Valloric/YouCompleteMe.
let g:UltiSnipsExpandTrigger=''
let g:UltiSnipsJumpForwardTrigger=''
let g:UltiSnipsJumpBackwardTrigger=''
let g:UltiSnipsEditSplit='horizontal'
function! ListUltisnips() abort
  let l:snips = UltiSnips#SnippetsInCurrentScope(1)
  let l:keylist = sort(keys(l:snips))
  echo ' --------------------------------------------------'
  for l:key in l:keylist
    echo printf(" %-10s\t%s", l:key, l:snips[l:key])
  endfor
  echo '---------------------------------------------------'
endfunction
function! CompleteSnippets(findstart, base)
  if a:findstart
    let l:line = getline('.')
    let l:start = col('.') - 1
    while l:start > 0 && l:line[l:start - 1] =~ '\a'
      let l:start -= 1
    endwhile
    return l:start
  else
    let l:res = []
    let l:snips = UltiSnips#SnippetsInCurrentScope(1)
    let l:keylist = sort(keys(l:snips))
    for l:key in l:keylist
      if l:key =~ '^' . a:base
        let l:item = {'word': l:key, 'menu': l:snips[l:key]}
        call add(l:res, l:item)
      endif
    endfor
    return l:res
  endif
endfunction
set completefunc=CompleteSnippets
"}}}
" Netrw{{{
let g:netrw_liststyle=3
let g:netrw_list_hide='^\..*'
let g:netrw_preview = 0
"}}}
" undotree{{{
nnoremap ut :UndotreeToggle
"}}}
" TagBar{{{
nnoremap tb :TagbarOpen fj
nnoremap ] :tag /[.#@]=expand('')
let g:tagbar_autoclose = 1
" let g:tagbar_autopreview = 1
" let g:tagbar_previewwin_pos = ''
let g:tagbar_type_css = {
\  'ctagstype' : 'css',
\  'kinds' : [
\    'c:classes',
\    'i:ids',
\    't:tags',
\    'm:medias'
\  ]
\}
let g:tagbar_type_scss = {
\  'ctagstype' : 'scss',
\  'kinds' : [
\    'v:variables',
\    'c:classes',
\    'i:ids',
\    't:tags',
\    'd:medias',
\    'm:mixins',
\    'f:functions'
\  ]
\}
let g:tagbar_type_vue = {
\ 'ctagstype' : 'vue',
\ 'kinds' : [
\ 'o:objects',
\ 'f:functions',
\ 'a:array',
\ 's:string',
\ 'b:boolean',
\ 'n:number',
\ 'v:variable'
\ ]
\ }
"}}}
" gutentags{{{
let g:gutentags_ctags_tagfile = '.tags'
let g:gutentags_ctags_exclude = ['package.json', 'Session.vim', 'package-lock.json', 'TODO.txt']
"}}}
" colorV{{{
let g:colorv_no_global_map = 1
let g:colorv_win_pos = 'top'
let g:colorv_preview_area = 0
nnoremap cv :ColorV
nnoremap ce :ColorVEdit
nnoremap cc :call ToggleColorPreview()
nnoremap ci :ColorVInsert
nnoremap cp :ColorVPicker
function! ToggleColorPreview() abort
  if !exists('w:colorv_is_previewing')
    let w:colorv_is_previewing = 0
  endif
  if w:colorv_is_previewing == 0
    execute 'ColorVPreview'
    let w:colorv_is_previewing = 1
  else
    execute 'ColorVClear'
    let w:colorv_is_previewing = 0
  endif
endfunction
"}}}
" vim-instant-markdown{{{
" this doesn't work - issue is open in guthub
let g:instant_markdown_open_to_the_world = 1
"}}}
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #functions {{{
function! SetColor(name, fg, bg, fg_l, bg_l, style) abort"{{{
  if &background ==? 'dark'
    if a:fg ==? 'normal'
      let l:guifg = ' guifg=' . g:d_normal_fg
      let l:ctermfg = 'ctermfg=black'
      " let l:termfg = 'termfg=black'
    elseif a:fg ==? 'none'
      let l:guifg = ' guifg=' . g:d_normal_bg
      let l:ctermfg = ' ctermfg=white'
      " let l:termfg = ' termfg=white'
    elseif a:fg ==? ''
      let l:guifg = ''
      let l:ctermfg = ''
      " let l:termfg = ''
    else
      let l:guifg = ' guifg=' . a:fg
      let l:ctermfg = ' ctermfg=black'
      " let l:termfg = ' termfg=black'
    endif
    if a:bg ==? 'none'
      let l:guibg = ' guibg=NONE'
      let l:ctermbg = ' ctermbg=none'
      " let l:termbg = ' termbg=none'
    elseif a:bg ==? ''
      let l:guibg = ''
      let l:ctermbg = ''
      " let l:termbg = ''
    else
      let l:guibg = ' guibg=' . a:bg
      let l:ctermbg = ' ctermbg=black'
    endif
  else " light background
    if a:fg_l ==? 'normal'
      let l:guifg = ' guifg=' . g:l_normal_fg
      let l:ctermfg = ' ctermfg=black'
      " let l:termfg = ' termfg=black'
    elseif a:fg_l ==? 'none'
      let l:guifg = ' guifg=' . g:l_normal_bg
      let l:ctermfg = ' ctermfg=white'
      " let l:termfg = ' termfg=white'
    elseif a:fg_l ==? ''
      let l:guifg = ''
      let l:ctermfg = ''
      let l:termfg = ''
    else
      let l:guifg = ' guifg=' . a:fg_l
      let l:ctermfg = ' ctermfg=black'
      " let l:termfg = ' termfg=black'
    endif
    if a:bg_l ==? 'none'
      let l:guibg = ' guibg=NONE'
      let l:ctermbg = ' ctermbg=none'
      " let l:termbg = ' termbg=none'
    elseif a:bg_l ==? ''
      let l:guibg = ''
      let l:ctermbg = ''
      " let l:termbg = ''
    else
      let l:guibg = ' guibg=' . a:bg_l
      let l:ctermbg = ' ctermbg=white'
      " let l:termbg = ' termbg=white'
    endif
  endif
  if a:style ==? ''
    let l:style = ' term=none cterm=none gui=NONE'
  else
    let l:style = ' term=' . a:style . ' cterm=' . a:style . ' gui=' . a:style
  endif
  let l:histring = 'hi! ' . a:name . l:guifg . l:guibg . l:style
  let l:histring .= l:ctermfg . l:ctermbg
  " let l:histring .= l:termfg . l:termbg
  execute 'hi clear ' . a:name
  execute l:histring
endfunction"}}}
function! GetStatusFrag(condition, colorname, conditionprefix, text) abort "{{{
" TODO better name
  let l:frag='%#' . a:colorname . '#'
  let l:frag.=a:conditionprefix
  let l:frag.='%{(' . a:condition . ")?'" . a:text . "':''}"
  return l:frag
endfunction"}}}
function! MyFoldText() "{{{
  if !exists('g:foldtext_column')
    let g:foldtext_column = 80 " column to right align foldtext with
  endif
  if !exists('b:foldtext_column')
    let b:foldtext_column = g:foldtext_column " column to right align foldtext with
  endif
  if !exists('g:foldtext_maxcolumn')
    let g:foldtext_maxcolumn = 120
  endif
  let l:linecount = v:foldend - v:foldstart
  " don't display foldmarker braces
  let l:line = substitute(getline(v:foldstart), '\{\{\{', '', '')
  " don't display vim comment quotation marks
  let l:line = substitute(l:line, "\^\"\\s\\?", '', '')
  let l:postfix = l:linecount . ' ' . substitute(v:folddashes, '-', '•', 'g')
  while strchars(l:postfix) < 7
    let l:postfix = ' ' . l:postfix
  endwhile
  let l:postfix = '  ↓ ' . l:postfix
  let l:len_line = len(l:line)
  let l:len_postfix = strchars(l:postfix)
  if l:len_line + l:len_postfix <= b:foldtext_column
    let l:padding = '                                                                                                                                                                        '[l:len_line + l:len_postfix + 0:b:foldtext_column - 1]
    let l:foldtext = l:line . l:padding . l:postfix
  else
    let l:sniptext = ' ⋯'
    let l:foldtext = l:line[:b:foldtext_column - 1 - strchars(l:sniptext) - l:len_postfix] . l:sniptext . l:postfix
  endif
  return l:foldtext
endfunction"}}}
function! IndentFoldTextColumn(amount) abort "{{{
  if !exists('g:foldtext_column')
    " column to right align foldtext with
    let g:foldtext_column = 80
  endif
  if !exists('b:foldtext_column')
    " column to right align foldtext with
    let b:foldtext_column = g:foldtext_column
  endif
  if a:amount == 0
    let b:foldtext_column = g:foldtext_column
    return
  endif
  let l:newcolumn = b:foldtext_column + a:amount
  if l:newcolumn < 20
    let l:newcolumn = 20
  elseif l:newcolumn > g:foldtext_maxcolumn
    let l:newcolumn = g:foldtext_maxcolumn
  endif
  let b:foldtext_column = l:newcolumn
endfunction
nnoremap z, :call IndentFoldTextColumn(-5 * (v:count == 0 ? 1 : v:count))
nnoremap z. :call IndentFoldTextColumn(5 * (v:count == 0 ? 1 : v:count))
nnoremap z= :call IndentFoldTextColumn(0)
"}}}
function! SyntaxItem() abort "{{{
" get name of syntax item
  return synIDattr(synID(line('.'),col('.'),1),'name') . ' -> ' . synIDattr(synIDtrans(synID(line('.'),col('.'),1)), 'name' )
endfunction
nnoremap pp :echom SyntaxItem()
"}}}
function! s:Get_env() abort "{{{
" devdocs DD
" https://gist.github.com/romainl/8d3b73428b4366f75a19be2dad2f0987#file-devdocs-vim
    if has('win64') || has('win32') || has('win16')
        return 'WINDOWS'
    else
        return toupper(substitute(system('uname'), '\n', '', ''))
    endif
endfunction
" What command to use on what system
let s:cmds = {'DARWIN': 'open', 'LINUX': 'qutebrowser', 'WINDOWS': 'start'}
" Build the URL stub
let s:stub = s:cmds[Get_env()] . " 'http://devdocs.io/?q="
command! -nargs=* DD silent! call system(len(split(, ' ')) == 0 ?
            \ s:stub . &ft . ' ' . expand('') . "'" : len(split(, ' ')) == 1 ?
            \ s:stub . &ft . ' ' .  . "'" : s:stub .  . "'")
"}}}
if !exists('*RangerExplorer') "{{{
" use ranger as file manager
  function RangerExplorer() abort
    exec 'silent !ranger --choosefile=/tmp/vim_ranger_current_file ' . expand('%:p:h')
    if filereadable('/tmp/vim_ranger_current_file')
      exec 'edit ' . system('cat /tmp/vim_ranger_current_file')
      call system('rm /tmp/vim_ranger_current_file')
    endif
    redraw!
  endfun
map ra :call RangerExplorer()
endif
"}}}
function! SetColorColumn() abort"{{{
  if &buftype == ''
    setlocal colorcolumn=80,120
  endif
endfunction
"}}}
function! GetLinterStatus(key) abort "{{{
  let l:statuscount = 0
  if exists('b:ale_linted')
    let l:linter = ale#statusline#Count(bufnr(''))
  else
    let l:linter = GetDiagnosticCountsFromSigns(bufnr(''))
  endif
  if has_key(l:linter, a:key)
    let l:statuscount = l:linter[a:key]
  endif
  return l:statuscount
endfunction
"}}}
function! s:RunShellCommand(cmdline) abort"{{{
" Shell command
" http://vim.wikia.com/wiki/VimTip1599
  let l:expanded_cmdline = a:cmdline 
  for l:part in split(a:cmdline, ' ')
     if l:part[0] =~ '\v[%#<]'
        let l:expanded_part = fnameescape(expand(l:part))
        let l:expanded_cmdline = substitute(l:expanded_cmdline, l:part, l:expanded_part, '')
     endif
  endfor
  if g:shell_scratch_buffer_nr > -1
    let l:win_nr = bufwinnr(g:shell_scratch_buffer_nr)
    if l:win_nr < 0
      execute 'bdelete' g:shell_scratch_buffer_nr
      top new
      let g:shell_scratch_buffer_nr = bufnr('%')
    else
      execute l:win_nr. ' wincmd w'
      setlocal modifiable
      %delete _
    endif
  else
    top new
    let g:shell_scratch_buffer_nr = bufnr('%')
  endif
  setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
  nnoremap  q :bdelete 
  augroup ResetShellBufferNr
    autocmd! * 
    autocmd BufUnload  let g:shell_scratch_buffer_nr = -1
  augroup END
  " call setline(1, 'You entered:    ' . a:cmdline)
  " call setline(2, 'Expanded Form:  ' .l:expanded_cmdline)
  " call setline(3,substitute(getline(2),'.','=','g'))
  execute '$read !'. l:expanded_cmdline
  1
  setlocal nomodifiable
  if !exists('b:shell_line_count')
    let b:shell_line_count = line('$')
    if b:shell_line_count > 25
      let b:shell_line_count = 20
    endif
    execute 'resize' b:shell_line_count + 1
  endif
  wincmd p
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand()
let g:shell_scratch_buffer_nr = -1
"}}}
function! GetDiagnosticCountsFromSigns(buffer) abort "{{{
    let l:error = 0
    let l:warn = 0
    let l:info = 0
    let l:hint = 0
    redir => l:result
    silent exec 'sign place buffer=' . a:buffer
    redir end
    let l:lines = split(l:result, '\n')
    for l:line in l:lines
        if l:line =~? 'Error'
            let l:error += 1
        endif
        if l:line =~? 'Warning'
            let l:warn += 1
        endif
        if l:line =~? 'Info'
            let l:info += 1
        endif
        if l:line =~? 'Hint'
            let l:hint += 1
        endif
    endfor
    return {'error': l:error, 'warning': l:warn, 'info': l:info, 'hint': l:hint}
endfunction
"}}}
function! SaveAndExecute(ex_command) abort "{{{
" https://stackoverflow.com/a/40195855
" ex_command: command to run to execute file
    " SOURCE [reusable window]: https://github.com/fatih/vim-go/blob/master/autoload/go/ui.vim
    " save and reload current file
    silent execute 'update | edit'
    " get file path of current file
    let s:current_buffer_file_path = expand('%')
    let s:output_buffer_name = 'Output'
    let s:output_buffer_filetype = 'output'
    " reuse existing buffer window if it exists otherwise create a new one
    if !exists('c:buf_nr') || !bufexists(s:buf_nr) || bufwinnr(s:buf_nr) == -1
        silent execute 'top new ' . s:output_buffer_name
        let s:buf_nr = bufnr('%')
    elseif bufwinnr(s:buf_nr) != bufwinnr('%')
        silent execute bufwinnr(s:buf_nr) . 'wincmd w'
    endif
    silent execute 'setlocal filetype=' . s:output_buffer_filetype
    setlocal bufhidden=delete
    setlocal buftype=nofile
    setlocal noswapfile
    setlocal nobuflisted
    setlocal winfixheight
    setlocal cursorline " make it easy to distinguish
    setlocal nonumber
    setlocal norelativenumber
    setlocal showbreak=""
    nnoremap   q :bdelete!'.zz
    " clear the buffer
    setlocal noreadonly
    " setlocal modifiable
    %delete _
    " add the console output
    silent execute '.!'. a:ex_command . ' ' . shellescape(s:current_buffer_file_path, 1)
    " resize window to content length
    " Note: This is annoying because if you print a lot of lines then your code buffer is forced to a height of one line every time you run this function.
    "       However without this line the buffer starts off as a default size and if you resize the buffer then it keeps that custom size after repeated runs of this function.
    "       But if you close the output buffer then it returns to using the default size when its recreated
    "execute 'resize' . line('$')
    " make the buffer non modifiable
    setlocal readonly
    " setlocal nomodifiable
endfunction
"}}}
function! JsIncludeExpr(file)
  " substitute(substitute(v:fname,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','')
  echom v:fname
  return substitute(substitute(a:file,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','')
endfunction
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #settings {{{
scriptencoding utf-8
set ttyfast
if &term ==? 'xterm-256color'
  set termguicolors
endif
syntax on
set background=light
set fillchars=stl:\ ,stlnc:\ ,vert:\|
colorscheme monotonous2
set guioptions-=mTrLb
set guioptions+=c
set updatetime=100
set timeoutlen=500
set backupdir=~/.vimtmp
set directory=~/.vimtmp
set tags+=./.tags,.tags;/home/ray/
" persisitent undo file
set undodir=/home/ray/.vim/undodir
set undofile
set clipboard=unnamedplus
set viewoptions-=options
set ignorecase
set smartcase
set wildmenu
set wildmode=longest:full,full
set wildignore+=/node_modules/,dist/
set hidden
set number relativenumber
set hlsearch
" set previewheight=24
" set splitbelow
set completeopt=longest,menuone
set completeopt-=preview
set nospell
set spelllang=en_gb
set dictionary+=/usr/share/dict/brit-a-z.txt,/usr/share/dict/britcaps.txt
set thesaurus+=/usr/share/dict/mthesaur.txt
" function! GetGitRoot() abort
"   let gitroot=system("git rev-parse --show-toplevel")
"   if gitroot=~?"^fatal"
"     let gitstring = system("echo ${PWD/#$HOME/'~'}") . "/"
"     let gitstring .= expand("%t")
"   else
"     let gitstring = system("echo ${PWD/#$HOME/'~'}") . "/"
"     let gitstring .= expand("%t")
"     let gitstring .= " [ " . system("git branch | grep '*' | cut -d ' ' -f2")
"     let gitstring .= " ] ( " .  system('basename "' . gitroot . '"') . " )"
"   endif
"   return gitstring
" endfunction
" let &titlestring="%{GetGitRoot()}"
" set title
set tabstop=8
set softtabstop=2
set shiftwidth=2
set shiftround
set expandtab
set autoindent
set textwidth=180
set formatoptions=cq
set wrapmargin=0
set foldcolumn=1
set signcolumn=yes
set colorcolumn=80,120
set iskeyword+=-
set scrolloff=10
set showcmd
set incsearch
set laststatus=2
set shortmess=aoOT
set cmdheight=3
set foldmethod=manual
set showmode
set autoindent
set breakindent
set showbreak=\ \ ↳\ 
set mouse=a
set listchars=eol:¬,tab:>-,trail:~,extends:>,precedes:<,space:·
set foldtext=MyFoldText()
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #mappings {{{
let g:mapleader = ' '
" miscallaneous {{{
nnoremap  : :setlocal norelativenumber:
nnoremap  rc :so $MYVIMRC
nnoremap  nn :set invrelativenumber
nnoremap  nh (&hls && v:hlsearch ? ':nohls' : ':set hls')."\n"
nnoremap  sl :set invlist
nnoremap aa A
nnoremap a2 A
nnoremap ab AB
nnoremap co :!clear;
" Focus on current fold, close the rest
nnoremap  zz zMzvzt
" replace current word with last yanked/deleted text
nnoremap  rr "_diwP
" replace current word with last yanked text
nnoremap  ry diw"0P
" quick grep of visual selection
vnoremap gr y:grep! -R " .
" open quickfix window of TODOs
nnoremap td :grep! -R '// *TODO' .:botright cwindow:echo len(getqflist()) 'TODOs'
" devdocs mapping
nnoremap dd :DD
" write and delete current buffer
nnoremap bx :w\|bd
"}}}
" git mappings {{{
nnoremap gs :Gstatus
nnoremap gd :Gdiff
nnoremap gD :!clear; echo 'git diff'; git diff
nnoremap ga :!clear; git add %; git status
nnoremap gA :!clear; git add .; git status
nnoremap gc :Gcommit
nnoremap gg :!clear; git add %; git commit -m ''
nnoremap gp :!clear; echo 'git push'; git push
" nnoremap gp :terminal echo ':git push' & git push
" nnoremap gp :Gpush
" nnoremap gp :pedit | read ! echo 'git push'; git push
nnoremap gl :Glog
"}}}
" netrw {{{
nnoremap ex :Ex
nnoremap ee :e .
nnoremap eq :Rex
"}}}
" better window/tab/buffer navigation/management {{{
nnoremap j :resize -5
nnoremap k :resize +5
nnoremap l :vertical resize +5
nnoremap h :vertical resize -5
"}}}
"location list and quickfix mappings {{{
nnoremap lo :botright lwindow
nnoremap       :lprevzv
nnoremap     :lnextzv
nnoremap lc :lclose
nnoremap lh :lhistory
nnoremap lp :lolder
nnoremap ln :lnewer
nnoremap qo :botright cwindow
nnoremap     :cprevzv
nnoremap    :cnextzv
nnoremap qc :cclose
nnoremap qh :chistory
nnoremap qp :colder
nnoremap qn :cnewer
"}}}
" insert mode mappings {{{
inoremap jkrg     :reg
inoremap :w   :w
inoremap [:w   :w
inoremap {:w   :w
"}}}
" brace/quotes completion {{{
inoremap {{       {}
inoremap {    {}O
inoremap {;       {};O
inoremap {,       {},O
inoremap {{{      {{}}
inoremap ((       ()
inoremap (    ()O
inoremap (;       ();
inoremap (,       (),
inoremap [[       []
inoremap [    []O
inoremap ""       ""
inoremap """      ""
inoremap ";       "";
inoremap ''       ''
inoremap '''      ''
inoremap ';       '';
"}}}
"}}}
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #abbreviations {{{
iabbrev adn and
iabbrev waht what
iabbrev tehn then
iabbrev functin function
iabbrev positin position
" css
iabbrev pabs; position: absolute;
iabbrev pfix; position: fixed;
iabbrev prel; position: relative;
iabbrev fdr; flex-direction: row;
iabbrev fdc; flex-direction: column;
iabbrev jcc; justify-content: center;
iabbrev aic; align-items: center;
iabbrev t0; top: 0;
iabbrev b0; bottom: 0;
iabbrev l0; left: 0;
iabbrev r0; right: 0;
iabbrev ct'' content-type: '';
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #autocommands {{{
" persistent folds {{{
augroup AutoSaveFolds
  autocmd!
  " autocmd BufWinLeave ?* mkview
  autocmd BufWrite ?* mkview
  " autocmd BufWinEnter ?* silent loadview
  autocmd BufRead ?* silent loadview
augroup END
"}}}
" fix higlight problems such as vertical-align etc {{{
augroup VimCSS3Syntax
  autocmd!
  autocmd FileType css setlocal iskeyword+=-
augroup END
"}}}
" Show trailing whitepace and spaces before a tab: {{{
augroup whitespaceerrors
  autocmd!
  autocmd Syntax * syn match ExtraWhitespace /\s\+$\| \+\ze\t/ containedin=ALL 
augroup END 
"}}}
" automatically reload if color scheme file written {{{
" augroup coloreload
"   autocmd!
" 	autocmd BufWritePost customred256.vim so $MYVIMRC
" augroup end
"
"}}}
" line numbering {{{
augroup linenumbering
  autocmd!
  autocmd InsertEnter * :set norelativenumber
  autocmd InsertLeave * :set number relativenumber
  autocmd WinEnter * :set number relativenumber
  autocmd WinLeave * set norelativenumber
  autocmd CmdlineLeave * :set number relativenumber
  " see 'mapping nnoremap :' for setting norelative number.
augroup END
"}}}
" colorcolumns {{{
augroup colorcolumns
  autocmd!
  autocmd WinEnter * call SetColorColumn()
  autocmd WinLeave * setlocal colorcolumn=0
augroup END
"}}}
" Automatically reload .vimrc if chanaged {{{
augroup myvimrc
  autocmd!
  autocmd BufWritePost .vimrc,_vimrc,vimrc,.gvimrc,_gvimrc,gvimrc so $MYVIMRC | if has('gui_running') | so $MYGVIMRC | endif
augroup END
"}}}
" Open qfix after grepping {{{
augroup qfixopen
  autocmd!
  autocmd QuickFixCmdPost *grep* botright cwindow
augroup END
"}}}
" }}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #statusline {{{
set statusline=%!GetStatus(1)
function! GetStatus(isactive) abort "{{{
  " let l:linter = ale#statusline#Count(bufnr(''))
  let l:divider = '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >'
  let l:separator = '%#StatusLineSeparator# '
  let l:normal = '%#StatusLineNormal#'
  let l:active = '%#StatusLineActive#'
  let l:statusline = ''
  "buffer number
  if a:isactive
    let l:statusline .= '%#StatusLineBufferNrActive#'
  else
    let l:statusline .= '%#StatusLineBufferNr#'
  endif
  let l:statusline .= ' %n %* '
  " file percentage {{{
  let l:statusline .= '%#FoldColumn# ' 
  if a:isactive
    let l:statusline .= '%#StatusLinePercentActive#'
    let l:statusline .= '%P %#StatusLineDirActive#of %#StatusLineFileActive#%L %* '
  else
    let l:statusline .= '%#StatusLinePercent#'
    let l:statusline .= '%P %#StatusLineDir#of %#StatusLinePercent#%L %* '
  endif"}}}
  " non-empty buftype (help, quickfix, etc) {{{
  if a:isactive 
    let l:statusline .= l:active . "%{&buftype == '' ? '' : ' '}%q%h%w%#StatusLineActiveNoText#"
  else
    let l:statusline .= l:normal . "%{&buftype == '' ? '' : ' '}%q%h%w%#StatusLineNormalNoText#"
  endif
  let l:statusline .= "%{&buftype == '' ? '' : '                                                                                                                                                                                                                                                '}%s"
"}}}
  " right/left divider {{{
  let l:statusline.=l:separator 
  " modified version 
  let l:color = 'StatusLineDivMod' . (a:isactive?'Active':'')
  let l:statusline .= GetStatusFrag("&modified && mode() != 'i'", l:color, '%<', l:divider)
   
  " unmodified version
  let l:color = 'StatusLineDiv' . (a:isactive?'Active':'')
  let l:statusline .= GetStatusFrag("!&modified && mode() != 'i'", l:color, '%<', l:divider)
   
  " input mode version
  if a:isactive
    let l:statusline .= GetStatusFrag("mode() == 'i'", 'StatusLineDivInput', '%<', l:divider)
  endif
  let l:statusline.= l:separator . '%*%='
  let l:statusline .= ' '
 "}}}
  " file info{{{
   if a:isactive == 1 
     " let l:statusline.=l:active
     let l:statusline.='%#StatusLineFileActive#'
     " let l:statusline.=" %{strlen(&ft)?&ft:'none'} "
     " let l:statusline.=l:separator . l:active
     let l:statusline.=' %{strlen(&fenc)?&fenc:&enc} '
     " let l:statusline.=l:separator . l:active
     let l:statusline.=' %{&fileformat} '
     let l:statusline.=l:separator . l:active
     " let l:statusline.=' %{&spelllang} '
     " let l:statusline.=l:separator
   endif
"}}}
  " path/filename.extension {{{
  if a:isactive 
    let l:statusline.='%#StatusLineDirActive# '
    let l:statusline.="%{expand('%:p:h:t')}/"
    let l:statusline.='%#StatusLineFileActive#'
    let l:statusline.="%{expand('%:t:r')}"
    let l:statusline.='%#StatusLineDotActive#'
    let l:statusline.="%{strlen(expand('%:e'))?'.':''}"
    let l:statusline.='%#StatusLineExtActive#'
    let l:statusline.="%{strlen(expand('%:e'))?expand('%:e'):expand('%:e')} "
    let l:statusline .= '%#InterfaceSignWarning# %R '
  else
    let l:statusline.='%#StatusLineDir# '
    let l:statusline.="%{fnamemodify(expand('%:p:h'),':~')}/"
    let l:statusline.='%#StatusLineFile#'
    let l:statusline.="%{expand('%:t:r')}"
    let l:statusline.='%#StatusLineDot#'
    let l:statusline.="%{strlen(expand('%:e'))?'.':''}"
    let l:statusline.='%#StatusLineExt#'
    let l:statusline.="%{strlen(expand('%:e'))?expand('%:e'):expand('%:e')} "
    let l:statusline .= '%#LinterWarningInactive# %R '
  endif
  let l:statusline.='%*'
  "}}}
  " linter status {{{
  if a:isactive 
    " errors
    let l:statusline .= "%#LinterDashActive#%{(GetLinterStatus('error') == 0?'-':'')}"
    let l:statusline .= "%#LinterError#%{(GetLinterStatus('error') == 0?'':GetLinterStatus('error'))}"
    " style errors
    let l:statusline .= '%#LinterDash#|'
    let l:statusline .= "%#LinterDashActive#%{(GetLinterStatus('style_error') == 0?'-':'')}"
    let l:statusline .= "%#LinterErrorStyle#%{(GetLinterStatus('style_error') == 0?'':GetLinterStatus('style_error'))} "
    " warnings
    let l:statusline .= "%#LinterDashActive#%{(GetLinterStatus('warning') == 0?'-':'')}"
    let l:statusline .= "%#LinterWarning#%{(GetLinterStatus('warning') == 0?'':GetLinterStatus('warning'))}"
    " style warnings
    let l:statusline .= '%#LinterDash#|'
    let l:statusline .= "%#LinterDashActive#%{(GetLinterStatus('style_warning') == 0?'-':'')}"
    let l:statusline .= "%#LinterWarningStyle#%{(GetLinterStatus('style_warning') == 0?'':GetLinterStatus('style_warning'))} "
    " info
    let l:statusline .= "%#LinterDashActive#%{(GetLinterStatus('info') == 0?'-':'')}"
    let l:statusline .= "%#LinterInfo#%{(GetLinterStatus('info') == 0?'':GetLinterStatus('info'))}"
  else
    " errors
    let l:statusline .= "%#LinterDash#%{(GetLinterStatus('error') == 0?'-':'')}"
    let l:statusline .= "%#LinterErrorInactive#%{(GetLinterStatus('error') == 0?'':GetLinterStatus('error'))}"
    " style errors
    let l:statusline .= '%#LinterDash#|'
    let l:statusline .= "%{(GetLinterStatus('style_error') == 0?'-':'')}"
    let l:statusline .= "%#LinterErrorStyleInactive#%{(GetLinterStatus('style_error') == 0?'':GetLinterStatus('style_error'))} "
    " warnings
    let l:statusline .= "%#LinterDash#%{(GetLinterStatus('warning') == 0?'-':'')}"
    let l:statusline .= "%#LinterWarningInactive#%{(GetLinterStatus('warning') == 0?'':GetLinterStatus('warning'))}"
    " style warnings
    let l:statusline .= '%#LinterDash#|'
    let l:statusline .= "%{(GetLinterStatus('style_warning') == 0?'-':'')}"
    let l:statusline .= "%#LinterWarningStyleInactive#%{(GetLinterStatus('style_warning') == 0?'':GetLinterStatus('style_warning'))} "
    " info
    let l:statusline .= "%#LinterDash#%{GetLinterStatus('info') == 0 ? '-' : GetLinterStatus('info')}"
  endif
"}}}
  return l:statusline
endfunction 
"}}}
function! DoInsertEnter() "{{{
  set cursorline
  call SetColor('LineNr', '#262626', '', '#cccccc', '', '')
  call SetColor('CursorLineNr', '#bcbcbc', '', '#999999', '', 'bold')
endfunction
"}}}
function! DoInsertLeave() "{{{
  set nocursorline
  call SetColor('LineNr', '#3a3a3a', '', '#999999', '', '')
  call SetColor('CursorLineNr', '#767676', '', '#777777', '', 'bold')
endfunction
"}}}
augroup status "{{{
  autocmd!
  autocmd WinNew,WinEnter * setlocal statusline=%!GetStatus(1)
  autocmd WinLeave * setlocal statusline=%!GetStatus(0)
  " autocmd WinNew * setlocal statusline=%!GetStatus(1)
  " autocmd InsertChange * setlocal statusline=%!GetStatus(1)
augroup END
"}}}
augroup statuscursorlines "{{{
  au!
  au InsertEnter * call DoInsertEnter()
  au InsertLeave * call DoInsertLeave()
augroup END
"}}}
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #tabline {{{
if exists('+showtabline')
  " Rename tabs to show tab number.
  " based on:
  " http://stackoverflow.com/questions/5927952/whats-implementation-of-vims-default-tabline-function
  function! MyTabLine() "{{{
    let l:customtabline = ''
    let l:currenttabnum = tabpagenr()
    let l:lasttabnumber = tabpagenr('$')
    let l:tabnumber = 1
    while l:tabnumber <= l:lasttabnumber
      let l:buflist = tabpagebuflist(l:tabnumber)
      let l:winnr = tabpagewinnr(l:tabnumber)
      if l:lasttabnumber > 1
        let l:customtabline .= '%' . l:tabnumber . 'T'
        let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%1*' : '%2*')
        let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%#TabNumSel#' : '%#TabNum#')
        let l:customtabline .= ' ' . l:tabnumber
        let l:customtabline .= '%#TabSeparator#:'
        let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%#TabLineItemSel#' : '%#TabLineItem#')
      endif
      let l:bufnr = l:buflist[l:winnr - 1]
      let l:file = bufname(l:bufnr)
      let l:buftype = getbufvar(l:bufnr, '&buftype')
      if l:buftype ==# 'help'
        let l:file = 'help:' . fnamemodify(l:file, ':t:r')
      elseif l:buftype ==# 'quickfix'
        let l:file = 'quickfix'
      elseif l:buftype ==# 'nofile'
        if l:file =~# '\/.'
          let l:file = substitute(l:file, '.*\/\ze.', '', '')
        endif
      else
        let l:file = fnamemodify(l:file, ':p:t')
      endif
      if l:file ==# ''
        let l:file = "''"
      endif
      let l:customtabline .= l:file . ' %#TabLineNoise# '
      let l:tabnumber = l:tabnumber + 1
    endwhile
    let l:customtabline .= '%T%#TabLineFill#%='
    let l:customtabline .= '%#TabLineItemSel# %{fugitive#statusline()}%#TabSeparator# '
    let l:customtabline .= '%#TabLineNoise# '
    let l:customtabline .= '%#TabLineNoise# '
    " let l:customtabline .= '%#TabSeparator# "%#TabLineItemSel#%{v:register}%#TabSeparator#" '
    " let l:customtabline .= '%#TabLineNoise# '
    let l:customtabline .= "%#TabLineItemSel# %{ObsessionStatus(fnamemodify(v:this_session,':t'),'---')} %*"
    return l:customtabline
  endfunction
"}}}
  set showtabline=2
  set tabline=%!MyTabLine()
endif " exists("+showtabline")
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" #pymode {{{
let g:pymode = 1
let g:pymode_syntax = 1
let g:pymode_syntax_all = 1
let g:pymode_syntax_print_as_function = 1
let g:pymode_syntax_highlight_async_await = 1
let g:pymode_syntax_highlight_equal_operator = 1
let g:pymode_syntax_highlight_stars_operator = 1
let g:pymode_syntax_highlight_self = 1
let g:pymode_syntax_indent_errors = 0
let g:pymode_syntax_space_errors = 0
let g:pymode_syntax_string_formatting = 1
let g:pymode_syntax_string_format = 1
let g:pymode_syntax_string_templates = 1
let g:pymode_syntax_doctests = 1
let g:pymode_syntax_docstrings = 1
let g:pymode_syntax_builtin_objs = 1
let g:pymode_syntax_builtin_types = 1
let g:pymode_syntax_builtin_funcs = 1
let g:pymode_syntax_highlight_exceptions = 1
let g:pymode_syntax_slow_sync = 1
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" vim: foldmethod=marker