Skip to content

Instantly share code, notes, and snippets.

@wendtl
Created January 29, 2020 20:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wendtl/1be711b3fbec5a293c6cf557c1dd315f to your computer and use it in GitHub Desktop.
Save wendtl/1be711b3fbec5a293c6cf557c1dd315f to your computer and use it in GitHub Desktop.
" TODO: global search and replace
" TODO: easier key sequence for surround actions (switch from vim-surround to vim-sandwich?)
" Helpful Hints:
" If you're getting errors while starting vim/nvim after applying this config, run :CheckHealth to see diagnostic information
" =i{ reindents the current code block (replace = with < or > to change indent level)
" :Vexplore opens built in file browser (look into replacing nerdtee with this)
" Type <C-f> while in '/' search to open search history
" While in '/' search, type cgn to replace the current highlighted result, type . to repeat on subsequent occurrences
" Use :tab split to effectively 'full-screen' a split
" To insert any unicode char: press <C-v>u then type the unicode number
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Logans Vimrc:
" based loosely on https://github.com/amix/vimrc
"
" Sections: TODO: update sections
" -> General Configuration And Preferences
" -> Text Tab Fold And Indent Related
" -> FileType Specific Configuration
" -> VimPlug Setup And Plugin Configuration
" -> Plugin Configuration And Mappings
" -> Compatibility And Modernization
" -> Vim User Interface Configuration
" -> Colors And Fonts
" -> Window, Buffers And Movement
" -> Status Line Configuration
" -> Spell Checking
" -> Miscellaneous Configuration
" -> Helper Functions
"-------------- SECTION BEGIN --------------------------------
" General Configuration And Preferences:
"-------------------------------------------------------------
" Double tap Esc to disable search highlighting
nnoremap <silent> <Esc><Esc> :nohlsearch<cr>
set tabstop=4
autocmd VimEnter * set autoindent
" Remap VIM 0 to first non-blank character (and scroll to the left)
noremap 0 ^32zh
noremap ^ 0
" Move a line of text using ALT+[jk] or Command+[jk] on mac
nmap <M-j> mz:m+<cr>`z
nmap <M-k> mz:m-2<cr>`z
vmap <M-j> :m'>+<cr>`<my`>mzgv`yo`z
vmap <M-k> :m'<-2<cr>`>my`<mzgv`yo`z
if has("mac") || has("macunix")
nmap <D-j> <M-j>
nmap <D-k> <M-k>
vmap <D-j> <M-j>
vmap <D-k> <M-k>
endif
if has("autocmd")
autocmd BufWritePre *.txt,*.js,*.py,*.wiki,*.sh,*.coffee :call CleanExtraSpaces()
endif
" Visual mode pressing * or # searches for the current selection
vnoremap <silent> * :<C-u>call VisualSelection('', '')<CR>/<C-R>=@/<CR><CR>
vnoremap <silent> # :<C-u>call VisualSelection('', '')<CR>?<C-R>=@/<CR><CR>
" Prefer space as the leader key
let mapleader = "\<space>"
let g:mapleader = "\<space>"
" Always set working directory to the current directory
autocmd BufEnter * lcd %:p:h
" Fast saving
nmap <leader>w :wa<cr>
nmap <leader>q :Bclose<cr>
" Open a shell
noremap Q !!$SHELL<cr>
" Close buffer (without closing window)
"nnoremap <expr><leader>w len(getbufinfo("")[0].windows) > 1 ?
" \ ":close<CR>" :
" \ (bufnr("") == getbufinfo({"buflisted": 1})[-1].bufnr ? ":bp" : ":bn")."<bar>bd #<CR>"
" :W sudo saves the file (useful for handling the permission-denied error)
command! W w !sudo tee % > /dev/null
" Commenting blocks of code.
autocmd FileType c,cpp,java,scala,js let b:comment_leader = '// '
autocmd FileType sh,ruby,python let b:comment_leader = '# '
autocmd FileType conf,fstab let b:comment_leader = '# '
autocmd FileType tex let b:comment_leader = '% '
autocmd FileType mail let b:comment_leader = '> '
autocmd FileType vim let b:comment_leader = '" '
"noremap <silent> ,cc :<C-B>silent <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:nohlsearch<CR>
"noremap <silent> ,cu :<C-B>silent <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:nohlsearch<CR>
" Toggle whitespace
"vnoremap <silent> <leader>ws <Esc>:set list!<CR>gv
" because I always invoke command history accidentally
nnoremap q: :q<CR>
"nnoremap ;q :q<CR>
nnoremap q; :q<CR>
inoremap jk <esc>
inoremap kj <esc>
"let g:netrw_home="~/.vim"
" For local replace
"nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>
" For global replace
"nnoremap gR gD:%s/<C-R>///g<left><left>
" Global rename (refactor)
"nnoremap gr :set hidden<CR> :argadd %<CR> :argdo silent! %s/old_variable_name/new_variable_name/ge
" Windows habits die hard
nnoremap <C-a> ggVG
vnoremap <C-c> ygv
vnoremap <C-x> x
"nnoremap <silent> <C-v> :set paste<CR>P:set nopaste<CR>
vnoremap <silent> <C-v> :<C-u>set paste<CR>gv"_x"*P:set nopaste<CR>
inoremap <silent> <C-v> <Esc>:set paste<CR>p:set nopaste<CR>a
inoremap <silent> <C-b> <C-v>
inoremap <C-BS> <C-w>
nnoremap vv <C-v>
" Make Ctrl-Backspace delete previous word (May have issues in gVim)
inoremap <C-H> <C-w>
" Paste at end of line
nnoremap <A-p> $p
" When in visual mode, delete/paste without yanking the selection (use 'x' for that)
vnoremap p "_dP
vnoremap d "dd
" Use Ctrl+Alt+J / Ctrl+Alt+K in normal, insert, visual mode to move lines
" not using for now since it interferes with my byobu keybindings
"nnoremap <silent> <Leader>j :m .+1<CR>==
"nnoremap <silent> <Leader>k :m .-2<CR>==
"Fold all lines that do not match search expression
nnoremap <Leader>z :setlocal foldexpr=(getline(v:lnum)=~@/)?0:(getline(v:lnum-1)=~@/)\\|\\|(getline(v:lnum+1)=~@/)?1:2 foldmethod=expr foldlevel=0 foldcolumn=2<CR>
"-------------- SECTION BEGIN --------------------------------
" Text Tab Fold And Indent Related:
"-------------------------------------------------------------
set autoindent " Indent when moving to the next line when writing code
set smartindent " Smart indent
set foldmethod=syntax
set foldlevelstart=99 "start file with all folds opened
set foldnestmax=1 " Single level of nested folding
let javaScript_fold=1 "activate folding by JS syntax
" TODO: re-evaluate this block
set timeout timeoutlen=1000
set ttimeout ttimeoutlen=100 " Reduce delay when switching between modes.
augroup NoInsertKeycodes
autocmd!
autocmd InsertEnter * set ttimeoutlen=0
autocmd InsertLeave * set ttimeoutlen=100
augroup END
"Allow for <A-x> alt key bindings to work
"let c='a'
"while c <= 'z'
" exec "set <A-".c.">=\e".c
" exec "imap \e".c." <A-".c.">"
" let c = nr2char(1+char2nr(c))
"endw
" generate ctags
nnoremap <leader>ct :!ctags -Rf .git/tags<cr><cr>
" CTRL-L refreshes the screen by default
" (this keystroke works the same way in many other text programs, too.
" try it in your shell to clear the screen)
"
"let c='0'
"while c <= '9'
" exec "set <A-".c.">=\e".c
" exec "imap \e".c." <A-".c.">"
" let c = nr2char(1+char2nr(c))
"endw
" CTRL-L refreshes the screen by default. (double escape does the same)
" (this keystroke works the same way in many other text programs, too. try it in your shell to clear the screen)
" This mapping also un-highlights text matching the current search pattern
noremap <silent> <C-L> :nohlsearch <bar> redraw<CR>
inoremap <silent> <C-L> <C-O>:nohlsearch <bar> redraw<CR>
" Cycle between displaying absolute line numbers, relative numbers, or no line numbers
" CTRL-N by default moves the cursor down by one line.
" Personally, I never use it that way as there are already four other ways to do that //TODO: remap this
if exists('+relativenumber')
nnoremap <expr> <C-N> CycleLNum()
xnoremap <expr> <C-N> CycleLNum()
onoremap <expr> <C-N> CycleLNum()
" this function cycles between normal, relative, and no line numbering
function! CycleLNum()
if &l:rnu
setlocal nonu nornu
elseif &l:nu
setlocal nu rnu
else
setlocal nu
endif
" sometimes (op-pending mode) the redraw doesn't happen automatically - so I'll force it to happen
redraw
" return nothing; this is important to op-pending mode
return ""
endfunc
endif
" TODO: do I want this one?
"inoremap <Esc> <Esc>`^
set shortmess+=c " don't give |ins-kompletion-menu| messages.
set signcolumn=yes " show the signcolumn (column on the left, used by git-gutter to show changes, etc.)
set foldcolumn=0 " Like signcolumn but for folds
set cursorline " highlight the line the cursor is currently on
set backspace=indent,eol,start " Backspace for dummies
set linespace=0 " No extra spaces between rows
set number " Line numbers on
set relativenumber " Show relative line numbers
set winminheight=0 " Windows can be 0 line high
set wildmenu " Show list instead of just completing
set wildmode=list:longest:full " Command <Tab> completion, list matches, the longest common part, then all
set nowrap " Don't wrap lines
"set whichwrap=b,s,h,l,<,>,[,] " Backspace and cursor keys wrap too
"set whichwrap+=<,>,h,l TODO: which of these `whichwrap` lines to keep?
"set wrapmargin=120
"set whichwrap=b,s,<,>
set scrolljump=5 " Lines to scroll when cursor leaves screen
set scrolloff=3 " Minimum lines to keep above and below cursor
"-------------- SECTION BEGIN --------------------------------
" FileType Specific Configuration:
"-------------------------------------------------------------
" Instead of reverting the cursor to the last position in the buffer, we
" set it to the first line when editing a git commit message
autocmd FileType gitcommit au! BufEnter COMMIT_EDITMSG call setpos('.', [0, 1, 1, 0])
" To disable views add the following to your .vimrc.before.local file:
" let g:spf13_no_view = 1
if !exists('g:spf13_no_views')
" Add exclusions to mkview and loadview
" eg: *.*, svn-commit.tmp
let g:skipview_files = [
\ '\[example pattern\]'
\ ]
endif
if has('cmdline_info')
set ruler
set rulerformat=%30(%=\:b%n%y%m%r%w\ %l,%c%V\ %P%) " A ruler on steroids
set noshowcmd " Show partial commands in status line and Selected characters/lines in visual mode
endif
" inoremap <Esc> <Esc>l " Explore this later
"set foldmethod=indent
"set nofoldenable " Don't automatically fold when a file is opened
autocmd BufWritePre * %s/\s\+$//e " Automatically deletes all tralling whitespace on save.
" Ctrl-p: Open current window in new tab
nnoremap <C-p> :sbp<bar>wincmd p<bar>wincmd T<CR>k
" Markdown Formatting: {
autocmd FileType md set tw=80
set autoindent " indent at the same level of the previous line
set nojoinspaces " prevents inserting two spaces after punctuation on a join (j)
set splitright " puts new vsplit windows to the right of the current
set splitbelow " puts new split windows to the bottom of the current
set matchpairs+=<:> " match, to be used with %
set pastetoggle=<f12> " pastetoggle (sane indentation on pastes)
set comments=sl:/*,mb:*,elx:*/ " auto format comment blocks
" Markdown Formatting: }
"-------------- SECTION BEGIN --------------------------------
" VimPlug Setup And Plugin Configuration: {
"-------------------------------------------------------------
" Automatically install vim-plug (the plugin manager) if it isn't already installed
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
" Load all of my plugins with VimPlug (always use single quotes for VimPlug)
call plug#begin('~/.vim/vim-plug')
" Plugins I can't live without
Plug 'junegunn/seoul256.vim' " A color scheme I like
Plug 'itchyny/lightline.vim' " A color scheme I like
Plug 'google/vim-searchindex' " Shows search indices ie. [3/10]
Plug 'junegunn/fzf', {'dir': '~/.vim/fzf', 'do': './install --all'} " Fuzzy finder
Plug 'junegunn/fzf.vim' " Fuzzy finder
Plug 'neoclide/coc.nvim', {'do': 'yarn install --frozen-lockfile'} " Post install, run :CocInstall coc-tsserver coc-eslint coc-json coc-prettier coc-css coc-diagnostic (IMPORTANT: yarn MUST be installed!)
Plug 'inkarkat/argtextobj.vim' " `argument` text object - very useful
Plug 'justinmk/vim-sneak' " alternative navigation method
Plug 'tpope/vim-fugitive' " Git support
Plug 'tpope/vim-sleuth' " auto-adjust shiftwidth and expandtab based on current file
Plug 'sheerun/vim-polyglot' " Syntax highlighting
Plug 'morhetz/gruvbox' " Gruvbox color scheme
Plug 'scrooloose/nerdtree' " File finder
Plug 'wellle/targets.vim'
Plug 'bitc/vim-bad-whitespace'
" Other plugins
"Plug 'ludovicchabant/vim-gutentags' " generate tags automatically
Plug 'tmsvg/pear-tree'
Plug 'norcalli/nvim-colorizer.lua'
Plug 'vimwiki/vimwiki'
Plug 'voldikss/vim-floaterm'
"Plug 'wendtl/TaskList.vim'
Plug 'michaeljsmith/vim-indent-object'
Plug 'mhinz/vim-signify'
Plug 'junegunn/goyo.vim', { 'for': 'txt,md' } " Distraction-free writing
Plug 'reedes/vim-pencil', { 'for': 'txt,md' } " Vim Tools for writing
Plug 'iamcco/markdown-preview.vim', { 'for': 'txt,md' } " Markdown preview - :MarkdownPreview to launch
Plug 'prettier/vim-prettier', { 'do': 'yarn install' } " post install (yarn install | npm install)
Plug 'wincent/ferret' " multi-file find and replace
Plug 'flazz/vim-colorschemes'
Plug 'majutsushi/tagbar'
call plug#end() " List of plugins ends here. Use :PlugInstall to install plugins once Vim has started.
" Plugins that I want to look into but am not currently using
"Plug 'machakann/vim-sandwich' " TODO: try this plugin - conflicts with vim-sneak
"Plug 'tpope/vim-surround' " adds 'surround' motion
"Plug 'jiangmiao/auto-pairs'
"Plug 'kana/vim-textobj-line' " `Line` text object
"Plug 'soywod/kronos.vim'
"Plug 'liuchengxu/vista.vim'
"Plug 'pangloss/vim-javascript' " JavaScript syntax highlighting (maybe redundant because of coc.nvim)
"Plug 'junegunn/limelight.vim' " Highlights the block of text at the cursor
"Plug 'junegunn/vim-github-dashboard'
"Plug 'junegunn/vim-easy-align'
"Plug 'Shougo/vimproc.vim', '{do': 'make' }
"Plug 'wincent/ferret' " multi-file find and replace
"Plug 'gregsexton/MatchTag' " Highlight matching HTML tags - maybe broken
"Plug 'lukhio/vim-mapping-conflicts' " broken currently
"Plug 'w0rp/ale'
"Plug 'airblade/vim-gitgutter'
"Plug 'Grimy/vim-rainbow'
"Plug 'gabrielelana/vim-markdown'
"Plug 'vim-airline/vim-airline'
"Plug 'vim-airline/vim-airline-themes'
"Plug 'Konfekt/FastFold'
"Plug 'iamcco/markdown-support-for-mkdp'
"Plug 'dahu/SearchParty'
"Plug 'zxqfl/tabnine-vim' " Language agnostic autocompletion
"Plug 'romainl/vim-cool'
"Plug 'kenng/vim-bettersearch'
"Plug 'haya14busa/incsearch.vim'
"Plug 'pgdouyon/vim-evanesco' " Search improvements. Highlights search under cursor as different color & disables highlighting when navigating away from search
"}
"-------------- SECTION BEGIN --------------------------------
" Plugin Configuration And Mappings: {
"-------------------------------------------------------------
set noshowmode " removes mode in bottom line since that is taken care of by lightline.vim
"FZF Settings: {
" Use ripgrep instead of ag:
command! -bang -nargs=* Rg
\ call fzf#vim#grep(
\ 'rg --column --line-number --no-heading --color=always '.shellescape(<q-args>), 1,
\ <bang>0 ? fzf#vim#with_preview('right:50%', '?')
\ : fzf#vim#with_preview('right:50%', '?'),
\ <bang>0)
function! s:find_git_root()
return system('git rev-parse --show-toplevel 2> /dev/null')[:-2]
endfunction
command! ProjectFiles execute 'Files' s:find_git_root()
nmap <leader>lp :ProjectFiles<CR>
nmap <leader>f :Files .<CR>
nmap <leader>p :GFiles<CR>
nmap <leader>gs :GFiles?<CR>
nmap <leader>b :Buffers<CR>
nmap R :Rg<CR>
nmap <leader>s :Rg .<CR>
nmap <leader>l :Lines<CR>
nmap <leader>T :Tags<CR>
nmap <leader>t :BTags<CR>
nmap <leader>' :Marks<CR>
nmap <leader>h :History<CR>
nmap <leader>; :History:<CR>
nmap <leader>/ :History/<CR>
"nmap ________ :Colors<CR>
"nmap <leader>L :BLines<CR>
"nmap ________ :Windows<CR>
"nmap ________ :Locate<CR>
"nmap ________ :Snippets<CR>
"nmap ________ :Commits<CR>
"nmap ________ :BCommits<CR>
"nmap ________ :Commands<CR>
"nmap ________ :Maps<CR>
"nmap ________ :Helptags<CR>
"nmap ________ :Filetypes<CR>
let g:fzf_buffers_jump = 1 " Jump to the existing windows if possible
let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%C(bold)%cr"' " Customize options used by 'git log'
let g:fzf_tags_command = 'ctags -R' " Command to generate tags file
" Better search history
command! QHist call fzf#vim#search_history({'right': '40'})
nnoremap <silent> q/ :QHist<CR>
noremap <C-f> :FZF<CR>
nmap <leader><tab> <plug>(fzf-maps-n)
xmap <leader><tab> <plug>(fzf-maps-x)
omap <leader><tab> <plug>(fzf-maps-o)
"FZF Settings: }
"" Heavily inspired by: https://github.com/junegunn/dotfiles/blob/master/vimrc
"function! s:statusline_expr()
" let mod = "%{&modified ? '[+] ' : !&modifiable ? '[x] ' : ''}"
" let ro = "%{&readonly ? '[RO] ' : ''}"
" let ft = "%{len(&filetype) ? '['.&filetype.'] ' : ''}"
" let fug = "%{exists('g:loaded_fugitive') ? fugitive#statusline() : ''}"
" let sep = ' %= '
" let pos = ' %-12(%l : %c%V%) '
" let pct = ' %P'
"
" return '[%n] %f %<'.mod.ro.ft.fug.sep.pos.'%*'.pct
"endfunction
"let &statusline = s:statusline_expr()
"
set colorcolumn=0
set complete-=i
set completeopt=menuone,preview
"set cryptmethod=blowfish2
set matchpairs+=<:> " Use % to jump between pairs
set modelines=2
set noshiftround
set nospell " Disable spell check
set regexpengine=0 " automatically choose the Regex engine
set showmode " Show on last line if in any mode other than Normal mode
set spelllang=en_us
"nnoremap <Leader>r :%s///g<Left><Left>
"" Press * to search for the term under the cursor or a visual selection and
"" then press a key below to replace all instances of it in the current file.
"nnoremap <Leader>r :%s///g<Left><Left>
"nnoremap <Leader>rc :%s///gc<Left><Left><Left>
"
"" The same as above but instead of acting on the whole file it will be
"" restricted to the previously visually selected range. You can do that by
"" pressing *, visually selecting the range you want it to apply to and then
"" press a key below to replace all instances of it in the current selection.
"xnoremap <Leader>r :s///g<Left><Left>
"xnoremap <Leader>rc :s///gc<Left><Left><Left>
"
" TODO: figure out how to populate substitute command with a keybind
" nnoremap <leader>r :%s/asdf/sadf/g
"" Type a replacement term and press . to repeat the replacement again. Useful
"" for replacing a few instances of the term (comparable to multiple cursors).
"nnoremap <silent> s* :let @/='\<'.expand('<cword>').'\>'<CR>cgn
"xnoremap <silent> s* "sy:let @/=@s<CR>cgn
" Floaterm: Floating Terminal
noremap <silent> <F12> :FloatermToggle<CR>i
noremap! <silent> <F12> <Esc>:FloatermToggle<CR>i
tnoremap <silent> <F12> <C-\><C-n>:FloatermToggle<CR>
augroup javascript_folding
au!
au FileType javascript setlocal foldmethod=syntax
augroup END
let g:javascript_plugin_jsdoc = 1
let g:javascript_plugin_flow = 0
let g:gutentags_ctags_exclude = ["*.min.js", "*.min.css", "build", "vendor", ".git", "node_modules", "*.vim/bundle/*"]
let g:gutentag_trace = 1
"set tags=~/.vim/tags
set autochdir
" Coc Configuration: syntax highlighting & autocomplete {
autocmd CursorHold * silent call CocActionAsync('highlight')
" Use tab for trigger completion with characters ahead and navigate. Use command ':verbose imap <tab>' to make sure tab is not mapped by other plugin.
inoremap <silent><expr> <TAB> pumvisible() ? "\<C-n>" : <SID>check_back_space() ? "\<TAB>" : coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
" Use <c-space> to trigger completion.
inoremap <silent><expr> <c-space> coc#refresh()
" Make <CR> confirm completion
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
" coc.nvim autocomplete menu
inoremap <silent><expr> <c-j> coc#refresh()
autocmd! CompleteDone * if pumvisible() == 0 | pclose | endif
" set tab to jump through snippet placeholder
inoremap <silent><expr> <TAB>
\ pumvisible() ? coc#_select_confirm() :
\ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ coc#refresh()
let g:coc_snippet_next = '<tab>'
let g:coc_snippet_prev = '<S-tab>'
let g:coc_force_debug = 1
" run :echo coc#util#job_command() to restart the coc.nvim service
" Use <cr> to confirm completion, `<C-g>u` means break undo chain at current position.
" Coc only does snippet and additional edit on confirm. //TODO: figure out to
" use below mapping or above mapping
inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
" Use `[c` and `]c` to navigate diagnostics
nmap <silent> [c <Plug>(coc-diagnostic-prev)
nmap <silent> ]c <Plug>(coc-diagnostic-next)
" Remap keys for gotos
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
autocmd CursorHold * silent call CocActionAsync('highlight')
" Highlight symbol under cursor on CursorHold
" Remap for rename current word
"nmap <leader>rn <Plug>(coc-rename)
"vmap <leader>rf <Plug>(coc-refactor)
" Remap for format selected region
"vmap <leader>f <Plug>(coc-format-selected)
"nmap <leader>f <Plug>(coc-format-selected)
augroup mygroup
autocmd!
" Setup formatexpr specified filetype(s).
autocmd FileType typescript,json setl formatexpr=CocActionAsync('formatSelected')
" Update signature help on jump placeholder
autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
augroup end
" Remap for do codeAction of selected region, ex: `<leader>aap` for current paragraph
vmap <leader>a <Plug>(coc-codeaction-selected)
nmap <leader>a <Plug>(coc-codeaction-selected)
" Remap for do codeAction of current line
nmap <leader>ac <Plug>(coc-codeaction)
" auto-fix problem of current line
nmap <leader>- <Plug>(coc-fix-current)
" Create mappings for function text object, requires document symbols feature of languageserver.
xmap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap if <Plug>(coc-funcobj-i)
omap af <Plug>(coc-funcobj-a)
" Use <C-d> for select selections ranges, needs server support, like: coc-tsserver, coc-python TODO: review. Overlaps with default <C-d> binding
"nmap <silent> <C-d> <Plug>(coc-range-select)
"xmap <silent> <C-d> <Plug>(coc-range-select)
command! -nargs=0 Format :call CocAction('format') " Use `:Format` to format current buffer
command! -nargs=? Fold :call CocAction('fold', <f-args>) " Use `:Fold` to fold current buffer
autocmd FileType json syntax match Comment +\/\/.\+$+ " Syntax highlighting for .json files (with comment syntax highlighting)
" """" CocList: (coc.nvim) """"
" Show all diagnostics
nnoremap <silent> <leader>a :<C-u>CocList diagnostics<cr>
" Manage extensions
nnoremap <silent> <leader>cx :<C-u>CocList extensions<cr>
" Show commands
nnoremap <silent> <leader>c :<C-u>CocList commands<cr>
" Find symbol of current document
nnoremap <silent> <leader>co :<C-u>CocList outline<cr>
" Search workspace symbols
"nnoremap <silent> <leader>s :<C-u>CocList -I symbols<cr>
" Do default action for next item.
nnoremap <silent> <leader>j :<C-u>CocNext<CR>
" Do default action for previous item.
nnoremap <silent> <leader>k :<C-u>CocPrev<CR>
" Resume latest coc list
"nnoremap <silent> <leader>p :<C-u>CocListResume<CR>
" END Coc Config: }
" Quickfix list with FZF
" CTRL+Q (combined with CTRL+A) to put search results into the quickfix.
" CTRL+Y to copy the highlighted file path to the clipboard.
function! s:build_quickfix_list(lines)
call setqflist(map(copy(a:lines), '{ "filename": v:val }'))
copen
cc
endfunction
let g:fzf_action = {
\ 'ctrl-q': function('s:build_quickfix_list'),
\ 'ctrl-t': 'tab split',
\ 'ctrl-x': 'split',
\ 'ctrl-v': 'vsplit',
\ 'ctrl-y': {lines -> setreg('*', join(lines, "\n"))}}
" Customize fzf colors to match your color scheme
let g:fzf_colors =
\ { 'fg': ['fg', 'Normal'],
\ 'bg': ['bg', 'Normal'],
\ 'hl': ['fg', 'Comment'],
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
\ 'hl+': ['fg', 'Statement'],
\ 'info': ['fg', 'PreProc'],
\ 'border': ['fg', 'Ignore'],
\ 'prompt': ['fg', 'Conditional'],
\ 'pointer': ['fg', 'Exception'],
\ 'marker': ['fg', 'Keyword'],
\ 'spinner': ['fg', 'Label'],
\ 'header': ['fg', 'Comment'] }
" Enable per-command history.
" CTRL-N and CTRL-P will be automatically bound to next-history and
" previous-history instead of down and up. If you don't like the change,
" explicitly bind the keys to down and up in your $FZF_DEFAULT_OPTS.
let g:fzf_history_dir = '~/.local/share/fzf-history'
"NERDTree Settings: {
let NERDTreeQuitOnOpen = 1
let NERDTreeShowHidden=1
let NERDTreeAutoDeleteBuffer = 1
let NERDTreeMinimalUI = 1
let NERDTreeDirArrows = 1
" Open/close NerdTree
nnoremap <leader>n :NERDTreeToggle %<CR>
" Open nerd tree at the current file or close nerd tree if pressed again.
nnoremap <expr> <leader>e g:NERDTree.IsOpen() ? "\:NERDTreeClose<CR>" : bufexists(expand('%')) ? "\:NERDTreeFind<CR>" : "\:NERDTree<CR>"
"NERDTree Settings: }
" TODO: what is this supposed to do
"autocmd bufenter * if (winnr(“$”) == 1 && exists(“b:NERDTreeType”) && b:NERDTreeType == “primary”) | q | endif
" TODO: Git Conflict Resolution with 'tpope/vim-fugitive' plugin (not yet tested)
"nnoremap <leader>gd :Gvdiff<CR>
"noremap gdh :diffget //2<CR>
"nnoremap gdl :diffget //3<CR>
" Use K for show documentation in preview window
nnoremap <silent> K :call <SID>show_documentation()<CR>
function! s:show_documentation()
if &filetype == 'vim'
execute 'vert h '.expand('<cword>')
else
call CocAction('doHover')
endif
endfunction
let g:sneak#label = 1
let vim_markdown_preview_hotkey="<C-m>"
let vim_markdown_preview_browser="chrome"
augroup pencill
autocmd!
autocmd FileType markdown,mkd,md call pencil#init({'wrap': 'soft', 'autoformat': 1})
autocmd FileType text call pencil#init()
augroup END
" Lightline: Configures the statusline by using lightline.vim
let g:lightline = {
\ 'colorscheme': 'seoul256',
\ 'active': {
\ 'left': [ [ 'mode', 'paste' ],
\ [ 'readonly', 'filename', 'modified', 'method' ] ]
\ },
\ 'component_function': {
\ 'method': 'NearestMethodOrFunction'
\ },
\ }
"}
"-------------- SECTION BEGIN --------------------------------
" Compatibility And Modernization: {
"-------------------------------------------------------------
set ignorecase " Case insenstive search
set smartcase " Case sensitive when only when uppercase letters in search string
set hlsearch " Highlight search results
set hidden " Allow buffer switching without saving
set updatetime=300 " You will have a bad experience for diagnostic messages with the default value of 4000. Used by coc.nvim.
set formatoptions=qwlrnj1 " see :help fo-table
set nostartofline
set nowb " Turn backup off, since most stuff is in SVN, git, etc. anyway...
set noswapfile "TODO: configure explicit directory for swap files?
" Return to last edit position when opening files (i like this one a lot)
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
if has('nvim')
set inccommand=nosplit " incremental updates while doing search commands
endif
if !has('nvim')
set ttyfast " Unnecessary in newer versions of VIM
set nocompatible " Disable compatibility mode. Makes VIM work better with newer machines (this may need to be on the first line of vimrc, not needed for NeoVim)
endif
" :help [[
nnoremap [[ ?{<CR>w99[{
nnoremap ][ /}<CR>b99]}
nnoremap ]] j0[[%/{<CR>
nnoremap [] k$][%?}<CR>
" Setup persistent undo behavior (can undo even after exiting and reopening vim)
if has('persistent_undo')
set undofile " So is persistent undo ...
set undolevels=1000 " Maximum number of changes that can be undone
set undoreload=10000 " Maximum number of lines to save for undo on a buffer reload
endif
" Make the directories used in the next block
if !isdirectory($HOME . "/.vim/backup")
call mkdir($HOME . "/.vim/backup", "p", 0700)
call mkdir($HOME . "/.vim/swp", "p", 0700)
call mkdir($HOME . "/.vim/undo", "p", 0700)
call mkdir($HOME . "/.vim/view", "p", 0700)
endif
" Set undofile/backupfile directory (so it doesn't get put in the working directory)
set backup
set backupdir=~/.vim/backup/,~/.backup/,/tmp//
set directory=~/.vim/swp/,~/.swp/,/tmp//
set undodir=~/.vim/undo/,~/.undo/,/tmp//
set viewdir=~/.vim/view
setlocal suffixesadd+=.js,.java,.xlf " Set file extensions for 'gt'/'gf' (go to file) command
set viewoptions=folds,options,cursor,unix,slash " Better Unix / Windows compatibility
set virtualedit=onemore " Allow for cursor beyond last character
" Set extra options when running in GUI mode
if has("gui_running")
set guioptions-=T
set guioptions-=e
set t_Co=256 " Enable 256-bit colors
set guitablabel=%M\ %t
endif
"Use Unix as the standard file type
set ffs=unix,dos,mac
if has("multi_byte")
if &termencoding == ""
let &termencoding = &encoding
endif
set encoding=utf-8
setglobal fileencoding=utf-8
"setglobal bomb
set fileencodings=ucs-bom,utf-8,latin1
endif
scriptencoding utf-8
if has('clipboard')
if has('unnamedplus') " When possible use '+' register for copy-paste
set clipboard=unnamed,unnamedplus
else " On mac and Windows, use '*' register for copy-paste
set clipboard=unnamed
endif
endif
" Enable filetype plugins
filetype plugin on
filetype indent on
" Split commands:
" <C-w>r swap position of top/bottom or left/right splits
" <C-w>t break current split into new tab
" <C-w>o close every window in the current tab except the current one (effectively a 'fullscreen' binding)
" Auto-resize splits when Vim gets resized.
autocmd VimResized * wincmd =
" Always split windows vertically and to the right
set splitbelow
set splitright
set diffopt+=vertical " split vertically when in diff mode
silent! set splitvertical
" always open in a vertical split (default is horizontal) (might break things plugin-related)
autocmd FileType help,txt wincmd L
" should be deprecated by the above autocmd
if v:errmsg != ''
"cabbrev split vert split
cabbrev hsplit split
"cabbrev help vert help
"cabbrev h vert help
noremap <C-w>] :vert botright wincmd ]<CR> conflicts with 'vim-searchant' for unknown reason
noremap <C-w><C-]> :vert botright wincmd ]<CR>
else
cabbrev hsplit hor split
endif
" Copy selected text to 'clipboard registry' (Makes Ctrl+c work like a normal Windows user would expect) (buggy)
"vnoremap <C-c> "+yy
" Remove the delay when exiting visual mode
vnoremap <ESC> <C-c>
" File Finding (use by typing :find)
"set path=$PWD/**
"set path=.,,, " Directory of the current file (.) * the working directory (,,)
let &path .= "," . system("git rev-parse --show-toplevel | tr -d '\\n'")
" TODO: Figure out how this block should work
" set wildcharm=<C-z>
" nnoremap ,e :e **/*<C-z><S-Tab>
" nnoremap ,f :find **/*<C-z><S-Tab>
" Autocomplete : press Ctrl+n or Ctrl-p
" Sets how many lines of history VIM has to remember
set history=500
" enable mouse scrolling (may not work on some terminals)
set mouse=a
set mousehide
" Better indenting (makes repeating indentation easier)
vnoremap < <gv
vnoremap > >gv
" Visual line navigation (helpful for wrapped lines)
"nnoremap j gj
"nnoremap k gk
" Auto Reload Files When Changed From Outside: {
set autoread " Set to auto re-read when the file is changed from the outside
" Trigger `autoread` when files changes on disk (https://unix.stackexchange.com/questions/149209/refresh-changed-content-of-file-opened-in-vim/383044#383044) (https://vi.stackexchange.com/questions/13692/prevent-focusgained-autocmd-running-in-command-line-editing-mode)
autocmd FocusGained,BufEnter,CursorHold,CursorHoldI * if mode() != 'c' | checktime | endif
" Notification after file change (https://vi.stackexchange.com/questions/13091/autocmd-event-for-autoread)
autocmd FileChangedShellPost * echohl WarningMsg | echo "File changed on disk. Buffer reloaded." | echohl None
"}
" Tag Jumping: (ctrl+] , g+ctrl+], ctrl+t)
command! MakeTags !ctags -R .
"}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" File Browsing (:edit a folder to open) v or h to open in split window. t to open in tab.
let g:netrw_banner=0
let g:netrw_browse_split=4
let g:netrw_altv=1
let g:netrw_liststyle=3
let g:netrw_winsize=25
let g:netrw_list_hide=netrw_gitignore#Hide()
let g:netrw_list_hide.=',\(^\|\s\s\)\zs\.\S\+'
" Search in all currently opened buffers with :Vim <pattern>
function! ClearQuickfixList()
call setqflist([])
endfunction
function! Vimgrepall(pattern)
call ClearQuickfixList()
exe 'bufdo vimgrepadd ' . a:pattern . ' %'
cnext
endfunction
command! -nargs=1 Vim call Vimgrepall(<f-args>)
"-------------- SECTION BEGIN --------------------------------
" Vim User Interface Configuration:
"-------------------------------------------------------------
" Avoid garbled characters in Chinese language windows OS
let $LANG='en'
set langmenu=en
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
" Ignore compiled files
set wildignore=*.o,*~,*.pyc
if has("win16") || has("win32")
set wildignore+=.git\*,.hg\*,.svn\*
else
set wildignore+=*/.git/*,*/.hg/*,*/.svn/*,*/.DS_Store
endif
set so=7 "Set 7 lines to the cursor - when moving vertically using j/k
set ruler "Always show current position
set cmdheight=2 "Height of the command bar
set incsearch "Makes search act like search in modern browsers (moves to words as you type)
set lazyredraw "Don't redraw while executing macros (good performance config)
set magic "For regular expressions turn magic on
"set showmatch "Show matching brackets when text indicator is over them
"set mat=2 "How many tenths of a second to blink when matching brackets
set list "highlight whitespace
" Center search results in the middle of the screen
"nnoremap <silent> n nzz :SearchIndex<CR>
"nnoremap <silent> N Nzz :SearchIndex<CR>
"nnoremap * *zz
"nnoremap # #zz
nnoremap g* g*zz
nnoremap g# g#zz
nnoremap zl 8zl
nnoremap zh 8zh
" No annoying sound on errors
set noerrorbells
set novisualbell
set t_vb=
set tm=500
" Properly disable sound on errors on MacVim
if has("gui_macvim")
autocmd GUIEnter * set vb t_vb=
endif
"-------------- SECTION BEGIN --------------------------------
" Colors And Fonts:
"-------------------------------------------------------------
set termguicolors " Enables 24-bit colors
try
" Attempt to set colorscheme (requires 24-bit colors)
colorscheme seoul256
set ctermbg=dark
set t_ut= " For some reason, might fix background color rendering on certain systems (or NeoVim)
catch
endtry
set guifont=Consolas:h12:cANSI:qDRAFT
set background=dark
" Enable syntax highlighting ('syntax on' also works but according to the docs this overrides custom colors)
if !exists("g:syntax_on")
syntax enable
endif
"-------------- SECTION BEGIN --------------------------------
" Windows Buffers And Movement:
"-------------------------------------------------------------
" my preferred way to move between windows (aka splits) and tabs
nnoremap gh <C-W>h
nnoremap gl <C-W>l
nnoremap gk <C-W>k
nnoremap gj <C-W>j
nnoremap gn :tabnext<CR>
nnoremap gp :tabprev<CR>
" Useful mappings for managing tabs
"map <leader>tn :tabnew<cr>
"map <leader>to :tabonly<cr>
"map <leader>tc :tabclose<cr>
"map <leader>tm :tabmove
" Open current tab as fullscreen
"map <leader>tf :tabnew %
" Opens a new tab with the current buffer's path. Super useful for opening other files in the current directory
"nnoremap <leader>te :tabedit <c-r>=expand("%:p:h")<cr>/
" Show the tasklist (includes TODOs and FIXMEs)
"nnoremap <leader>tl :TaskList<CR>
" Close the current buffer
"map <leader>c :Bclose<cr>:tabclose<cr>gT
"nnoremap <leader>c :Bclose<cr>
"
" Close all the buffers
" map <leader>ba :bufdo bd<cr>
" map <leader>l :bnext<cr>
" map <leader>h :bprevious<cr>
" toggle between this and the last accessed tab
let g:lasttab = 1
"nmap <tab> :exe "tabn ".g:lasttab<CR>
au TabLeave * let g:lasttab = tabpagenr()
" Switch CWD to the directory of the open buffer
"map <leader>cd :cd %:p:h<cr>:pwd<cr>
" Specify the behavior when switching between buffers
try
set switchbuf=useopen,usetab,newtab
set stal=2
catch
endtry
" close the current buffer
"nnoremap <leader>bq :bp <bar> bd! #<cr>
" use tab/shift-tab to switch between buffers TODO: maybe do this for tabs instead of buffers
"nnoremap <Tab> :tabnext<cr>
"nnoremap <S-Tab> :tabprevious<cr>
"TODO: Incorporate these into current mappings --
":sb 1 "Open buffer #1 in a split
":sb {bufname} "Open buffer bufname in a split
":sbn "Open next buffer in a split
":sbp "Open previous buffer in a split
":sba "Open all buffers in split windows
" Remember you can use splits to open one file in multiple places
" <C-X><C-L> attempts to finish an entire line of text
" <C-X><C-V> autocompletes vim keywords
" <C-X><C-F> shows a list of file names
" <C-N> shows keywords from your files
" <C-X>s attempts to suggest spelling alternatives
" pressing o in visual mode jumps to the other side of the selection
" 1<C-V> to reselect last visual mode selection
" retain code folds between sessions
"autocmd BufWinLeave *.* mkview
"autocmd BufWinEnter *.* silent loadview
"autocmd BufWinLeave *.* mkviewautocmd BufWinEnter *.* silent loadview
" maps <Esc> to exit the built-in terminal (:term)
tnoremap <Esc> <C-\><C-n>:q!<CR>
"-------------- SECTION BEGIN --------------------------------
" Status Line Configuration:
"-------------------------------------------------------------
"function! NearestMethodOrFunction() abort
" return get(b:, 'vista_nearest_method_or_function', '')
"endfunction
"autocmd VimEnter * call NearestMethodOrFunction()
if has('statusline')
set laststatus=2
" Broken down into easily includeable segments
"set statusline=%<%f\ " Filename
"set statusline+=%w%h%m%r " Options
"if !exists('g:override_spf13_bundles')
" set statusline+=%{fugitive#statusline()} " Git hotness
"endif
"set statusline+=\ [%{&ff}/%Y] " Filetype
"set statusline+=\ [%{getcwd()}] " Current dir
"set statusline+=%=%-14.(%l,%c%V%)\ %p%% " Right aligned file nav info
"set statusline+=%{coc#status()}
"set statusline+=%{NearestMethodOrFunction()}
endif
"-------------- SECTION BEGIN --------------------------------
" Spell Checking:
"-------------------------------------------------------------
" Pressing ,ss will toggle and untoggle spell checking
"map <leader>ss :setlocal spell!<cr>
" Shortcuts using <leader>
"map <leader>sn ]s
"map <leader>sp [s
"map <leader>sa zg
"map <leader>s? z=
"-------------- SECTION BEGIN --------------------------------
" Miscellaneous Configuration:
"-------------------------------------------------------------
" Remove the Windows ^M - when the encodings gets messed up
noremap <Leader>m mmHmt:%s/<C-V><cr>//ge<cr>'tzt'm
" Quickly open a buffer for scribble
" map <leader>q :e ~/buffer<cr>
" Quickly open a markdown buffer for scribble
map <leader>x :e ~/buffer.md<cr>
" Toggle paste mode on and off
"map <leader>pp :setlocal paste!<cr>
"-------------- SECTION BEGIN --------------------------------
" Helper Functions:
"-------------------------------------------------------------
" Don't close window, when deleting a buffer
command! Bclose call <SID>BufcloseCloseIt()
function! <SID>BufcloseCloseIt()
let l:currentBufNum = bufnr("%")
let l:alternateBufNum = bufnr("#")
if buflisted(l:alternateBufNum)
buffer #
else
bnext
endif
if bufnr("%") == l:currentBufNum
new
endif
if buflisted(l:currentBufNum)
execute("bdelete! ".l:currentBufNum)
endif
endfunction
function! CmdLine(str)
call feedkeys(":" . a:str)
endfunction
function! VisualSelection(direction, extra_filter) range
let l:saved_reg = @"
execute "normal! vgvy"
let l:pattern = escape(@", "\\/.*'$^~[]")
let l:pattern = substitute(l:pattern, "\n$", "", "")
if a:direction == 'gv'
call CmdLine("Ack '" . l:pattern . "' " )
elseif a:direction == 'replace'
call CmdLine("%s" . '/'. l:pattern . '/')
endif
let @/ = l:pattern
let @" = l:saved_reg
endfunction
" TODO: figure out where this block should go
set list
set listchars=tab:▸\ ,eol:¬
highlight NonText guifg=#4a4a59
highlight SpecialKey guifg=#4a4a59
" if has('gui_running')
" set listchars=tab:▶\ ,trail:·,extends:\#,nbsp:.
" else
" set listchars=tab:>.,trail:.,extends:\#,nbsp:.
" endif
" set iskeyword-=. " '.' is an end of word designator
" set iskeyword-=# " '#' is an end of word designator
" set iskeyword-=- " '-' is an end of word designator
" Bubble single lines
nmap <C-Up> :m .-2<CR>
nmap <C-Down> :m .+1<CR>
" Bubble multiple lines
vnoremap <silent> <C-Up> @='"zxk"zP`[V`]'<CR>
vnoremap <silent> <C-Down> @='"zx"zp`[V`]'<CR>
" Open ranger in vim. (buggy)
" function! RangerExplorer()
" 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 <leader>g :call RangerExplorer()<CR>
" Delete trailing white space on save, useful for some filetypes
fun! CleanExtraSpaces()
let save_cursor = getpos(".")
let old_query = getreg('/')
silent! %s/\s\+$//e
call setpos('.', save_cursor)
call setreg('/', old_query)
endfun
" Toggle quickfix window.
function! QuickFix_toggle()
for i in range(1, winnr('$'))
let bnum = winbufnr(i)
if getbufvar(bnum, '&buftype') == 'quickfix'
cclose
return
endif
endfor
copen
endfunction
nnoremap <silent> qf :call QuickFix_toggle()<CR>
" Add all TODO items to the quickfix list relative to where you opened Vim.
function! s:todo() abort
let entries = []
for cmd in ['git grep -niI -e TODO -e FIXME -e XXX 2> /dev/null',
\ 'grep -rniI -e TODO -e FIXME -e XXX * 2> /dev/null']
let lines = split(system(cmd), '\n')
if v:shell_error != 0 | continue | endif
for line in lines
let [fname, lno, text] = matchlist(line, '^\([^:]*\):\([^:]*\):\(.*\)')[1:3]
call add(entries, { 'filename': fname, 'lnum': lno, 'text': text })
endfor
break
endfor
if !empty(entries)
call setqflist(entries)
copen
endif
endfunction
command! Todo call s:todo()
" Profile Vim by running this command once to start it and again to stop it.
function! s:profile(bang)
if a:bang
profile pause
noautocmd qall
else
profile start /tmp/profile.log
profile func *
profile file *
endif
endfunction
command! -bang Profile call s:profile(<bang>0)
" Random assorted miscellaneous commands
command! Wsession mksession! ~/.vim/session.vim | echom "Wrote ~/.vim/session.vim"
command! Rsession source ~/.vim/session.vim | echom "Restored ~/.vim/session.vim"
command! Csva :%CSVArrange
command! Nom e ++ff=dos
command! Mod :setlocal modifiable
command! Nomod :setlocal nomodifiable
command! Notes vert topleft sp | vertical resize 50 | setlocal nonumber | edit ~/notes.txt | norm <C-w><C-p>
command! Logview vert topleft sp | vertical resize 37 | setlocal nuw=7 | setlocal norelativenumber | setlocal scrollbind | exe ':norm 0<C-w><C-p>' | setlocal scrollbind | exe ':norm 029zl'
command! Curcolor :echom "hi<" . synIDattr(synID(line("."),col("."),1),"name") . '> trans<' . synIDattr(synID(line("."),col("."),0),"name") ."> lo<" . synIDattr(synIDtrans(synID(line("."),col("."),1)),"name") . ">"
command! Vimrc :e ~/.vimrc "shortcut to open vimrc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment