diff --git a/gitconfig b/gitconfig index 84df200..e93502e 100644 --- a/gitconfig +++ b/gitconfig @@ -64,7 +64,7 @@ email = rob@netflux.io name = Rob Watson [core] - editor = vim + editor = nvim quotePath = false commitGraph = true pager = delta diff --git a/nvimrc b/nvimrc new file mode 100644 index 0000000..7b76dc3 --- /dev/null +++ b/nvimrc @@ -0,0 +1,611 @@ +" TODO: remove +set runtimepath^=~/.vim runtimepath+=~/.vim/after +let &packpath = &runtimepath + +set background=dark +syntax on +filetype plugin indent on + +let mapleader=',' + +" netrw +let g:netrw_banner = 0 +let g:netrw_liststyle = 1 +let g:netrw_list_hide = '^\.' +let g:netrw_winsize=25 +map n :Lexplore + +" fix helptags for opt/ plugins +" https://vi.stackexchange.com/questions/17210/generating-help-tags-for-packages-that-are-loaded-by-vim-8s-package-management +command! -nargs=0 -bar Helptags + \ for p in glob('~/.vim/pack/git-plugins/opt/*', 1, 1) + \| exe 'packadd ' . fnamemodify(p, ':t') + \| endfor + \| helptags ALL + +set shiftwidth=2 +set shiftround +set tabstop=2 +set expandtab +set smarttab +set splitbelow +set splitright +set encoding=utf-8 +set hidden +set nowrap +set smartindent +set copyindent +set autoindent +set hlsearch +set showmatch +set wildmenu +set wildmode=list:full,full +set number +set relativenumber +set ruler +set backspace=indent,eol,start +set ignorecase +set smartcase +set incsearch +set history=1000 +set undolevels=1000 +set title +set novisualbell +set noerrorbells +set nobackup +set noswapfile +set mouse=a +set mousemodel=popup_setpos +" https://github.com/tpope/vim-sensible/issues/78: +set lazyredraw +set timeoutlen=1000 +set scrolloff=15 +set dictionary=/usr/share/dict/words +" See :help thesaurus +set thesaurus=$HOME/Documents/thesaurus/thesaurus_pkg/thesaurus.txt +set shortmess+=I +set updatetime=250 +set pastetoggle= +set pumheight=200 +" Required for nvim-compe: +set completeopt=menuone,noselect +set complete-=i +set nrformats-=octal +set ttimeout +set ttimeoutlen=100 +set formatoptions+=j +set autoread +" https://github.com/tpope/vim-sensible/issues/142: +set synmaxcol=500 + +" Enable 24-bit colours. +" https://github.com/alacritty/alacritty/issues/109#issuecomment-440353106 +if exists('+termguicolors') + let &t_8f="\[38;2;%lu;%lu;%lum" + let &t_8b="\[48;2;%lu;%lu;%lum" + set termguicolors +endif + +" Colour scheme: +packadd! nord-vim " https://github.com/arcticicestudio/nord-vim.git +colorscheme nord + +augroup vimrc + autocmd! + " Automatically load/save views on files. + " https://vi.stackexchange.com/posts/13874/revisions + autocmd BufWinLeave,BufLeave,BufWritePost,BufHidden,QuitPre ?* nested silent! mkview! + autocmd BufWinEnter ?* silent! loadview + " set cursor line highlight in insert mode. + autocmd InsertEnter * set cul + autocmd InsertLeavePre * set nocul + " use tabs in .gitconfig + autocmd BufEnter .gitconfig setlocal shiftwidth=2 tabstop=2 noexpandtab + " Quickfix window is always full-width. + " https://github.com/fatih/vim-go/issues/1757#issuecomment-565130503 + autocmd FileType qf if (getwininfo(win_getid())[0].loclist != 1) | wincmd J | endif + " Remove trailing whitespace pre-save: + autocmd FileType go,ruby,markdown,rust,python,markdown,lua autocmd BufWritePre %s/\s\+$//e +augroup end + +" Don't remember the current directory for a given file: +set viewoptions-=curdir +set viewoptions-=options +set sessionoptions-=options + +" Key mappings: +nnoremap j gj +nnoremap k gk +map +map +map +map +imap +imap +imap +imap +nmap ]q :cn +nmap [q :cp + +nnoremap w :w +nnoremap / :nohlsearch +nnoremap :nohlsearch +" Select just-pasted text: +nnoremap 0 `[v`] +" Select just-pasted text and re-indent: +nnoremap ) `[v`]= +nnoremap 1 :set relativenumber! +nnoremap ! :windo set norelativenumber +nnoremap m :marks +nnoremap v :vsplit +nnoremap s :split +nnoremap rp "_ddP + +lua <uu", [[:lua _G.insert_uuid()]], {noremap = true, silent = true}) +vim.api.nvim_set_keymap("i", "", [[:lua _G.insert_uuid()a]], {noremap = true, silent = true}) +EOF + +" Git mappings +" +" Copy Git permalink to clipboard for either current line or range +function! CopyGitURLToLineOrRange() range + if a:firstline == a:lastline + execute ".GBrowse!" + else + execute a:firstline . "," . a:lastline . "GBrowse!" + endif +endfunction + +function! OpenGitURLToLineOrRange() range + if a:firstline == a:lastline + execute ".GBrowse" + else + execute a:firstline . "," . a:lastline . "GBrowse" + endif +endfunction + +nnoremap ab :Git blame +nnoremap as :Gstatus +nnoremap ac :Commits +nnoremap ah :GitGutterLineHighlightsToggle +nnoremap aY :call CopyGitURLToLineOrRange() +vnoremap aY :call CopyGitURLToLineOrRange() +nnoremap ao :call OpenGitURLToLineOrRange() +nnoremap ap :execute 'silent !ghpr ' \| redraw! + +" echo filename of current buffer: +nmap fe :echom expand("%:p") +" yank filename of current buffer: +function! CopyToDefaultRegister() + let @" = expand("%:p") + echom expand("%:p") +endfunction +nmap fy :call CopyToDefaultRegister() +" and into + register: +function! CopyToSystemClipboard() + let @* = expand("%:p") + let @+ = expand("%:p") + echom expand("%:p") +endfunction +nmap fY :call CopyToSystemClipboard() + +" disable Ex mode +nnoremap Q + +function! ToggleQuickFix() + if empty(filter(getwininfo(), 'v:val.quickfix')) + copen + else + cclose + endif +endfunction +nmap q :call ToggleQuickFix() +nmap l :lclose + +" vim-markdown configuration: +let g:vim_markdown_conceal = 1 + +" fzf configuration: +let g:fzf_action = { + \ 'ctrl-t': 'tab split', + \ 'ctrl-s': 'split', + \ 'ctrl-v': 'vsplit' } +nmap t :Files +nmap T :GFiles +nmap b :Buffers +nmap gg :Rg + +" Lightline configuration: +packadd! lightline.vim " https://github.com/itchyny/lightline.vim.git +set laststatus=2 + +function! LightlineLSPErrorText() + let l:count = luaeval("vim.lsp.diagnostic.get_count(0, [[Error]])") + if l:count == 0 + return '' + endif + return l:count . 'E' +endfunction + +function! LightlineLSPWarningText() + let l:count = luaeval("vim.lsp.diagnostic.get_count(0, [[Warning]])") + if l:count == 0 + return '' + endif + return l:count . 'W' +endfunction + +function! LightlineLSPInformationText() + let l:count = luaeval("vim.lsp.diagnostic.get_count(0, [[Information]])") + if l:count == 0 + return '' + endif + return l:count . 'I' +endfunction + +let g:lightline = { + \ 'colorscheme': 'seoul256', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'readonly', 'filename', 'modified' ], + \ [ 'gitbranch' ], ['lsperror', 'lspwarn', 'lspinfo' ] ], + \ 'right': [ ['lineinfo'], ['percent'], ['filetype'], ['gobuild'] ], + \ }, + \ 'component_function': { + \ 'gobuild': 'go#statusline#Show', + \ 'gitbranch': 'FugitiveStatusline', + \ }, + \ 'component_expand': { + \ 'lsperror': 'LightlineLSPErrorText', + \ 'lspwarn': 'LightlineLSPWarningText', + \ 'lspinfo': 'LightlineLSPInformationText', + \ }, + \ 'component_type': { + \ 'lsperror': 'error', + \ 'lspwarn': 'warning', + \ }, + \ 'mode_map': { + \ 'n' : 'N', + \ 'i' : 'I', + \ 'R' : 'R', + \ 'v' : 'V', + \ 'V' : 'V-LINE', + \ "\": 'V-BLOCK', + \ 'c' : 'C', + \ 's' : 'S', + \ 'S' : 'S-LINE', + \ "\": 'S-BLOCK', + \ 't': 'TERM', + \ }, +\ } + +" vim-gitgutter configuration +packadd! vim-gitgutter " https://github.com/airblade/vim-gitgutter.git +set signcolumn=yes +nmap ]h (GitGutterNextHunk) +nmap [h (GitGutterPrevHunk) +omap ih (GitGutterTextObjectInnerPending) +omap ah (GitGutterTextObjectOuterPending) +xmap ih (GitGutterTextObjectInnerVisual) +xmap ah (GitGutterTextObjectOuterVisual) + +" vim-fugitive +packadd! vim-fugitive " https://github.com/tpope/vim-fugitive.git + +" vim-go +" Doesn't work in after/ftplugin/go.vim: +let g:go_def_mapping_enabled = 0 +packadd! vim-go " https://github.com/fatih/vim-go.git + +" load internal plugins: +runtime macros/matchit.vim + +" load other plugins: +packadd! rust.vim " https://github.com/rust-lang/rust.vim.git +packadd! tmux-complete.vim " https://github.com/wellle/tmux-complete.vim.git +packadd! vim-commentary " https://github.com/tpope/vim-commentary.git + +" Requires both fzf.vim plugin to be manually installed: +" https://github.com/junegunn/fzf/blob/master/plugin/fzf.vim +" and also this separate plugin, which is loaded here: +packadd! fzf.vim " https://github.com/junegunn/fzf.vim.git +packadd! vim-surround " https://github.com/tpope/vim-surround.git +packadd! vim-rhubarb " https://github.com/tpope/vim-rhubarb.git +packadd! editorconfig-vim " https://github.com/editorconfig/editorconfig-vim.git +packadd! vim-wordmotion " https://github.com/chaoren/vim-wordmotion.git + +" enable inline vim highlighting: +let g:vimsyn_embed= 'lPr' + +" Treesitter + +packadd! nvim-treesitter " https://github.com/nvim-treesitter/nvim-treesitter.git +packadd! nvim-treesitter-textobjects " https://github.com/nvim-treesitter/nvim-treesitter-textobjects.git +packadd! nvim-treesitter-refactor " https://github.com/nvim-treesitter/nvim-treesitter-refactor.git +packadd! playground " https://github.com/nvim-treesitter/playground.git + +lua <d"] = "@class.outer", + ["d"] = "@function.outer", + }, + }, + }, + playground = { + enable = true, + disable = {}, + updatetime = 25, + persist_queries = false, + keybindings = { + toggle_query_editor = 'o', + toggle_hl_groups = 'i', + toggle_injected_languages = 't', + toggle_anonymous_nodes = 'a', + toggle_language_display = 'I', + focus_language = 'f', + unfocus_language = 'F', + update = 'R', + goto_node = '', + show_help = '?', + }, + } +} +EOF + +" LSP + +packadd! nvim-lspconfig " https://github.com/neovim/nvim-lspconfig.git +packadd! lsp_signature.nvim " https://github.com/ray-x/lsp_signature.nvim.git +packadd! fzf-lsp.nvim " https://github.com/gfanto/fzf-lsp.nvim.git + +lua <lua vim.lsp.buf.definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gD', 'lua vim.lsp.buf.type_definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gd', 'lua vim.lsp.buf.definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gD', 'lua vim.lsp.buf.type_definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'e', 'lua vim.lsp.buf.rename()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'r', 'lua vim.lsp.buf.references()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'i', 'lua vim.lsp.buf.implementation()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ca', 'lua vim.lsp.buf.code_action()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ci', 'lua vim.lsp.buf.incoming_calls()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'co', 'lua vim.lsp.buf.outgoing_calls()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'K', 'lua vim.lsp.buf.hover()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', ']e', 'lua vim.lsp.diagnostic.goto_next({severity="Error"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', '[e', 'lua vim.lsp.diagnostic.goto_prev({severity="Error"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', ']d', 'lua vim.lsp.diagnostic.goto_next()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', '[d', 'lua vim.lsp.diagnostic.goto_prev()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'cd', 'lua vim.lsp.diagnostic.clear(0)', opts) + + -- fzf triggers: + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fr', 'References', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fi', 'Implementations', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fs', 'DocumentSymbols', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fw', 'WorkspaceSymbols', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fc', 'CodeActions', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fci', 'IncomingCalls', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'fco', 'OutgoingCalls', opts) + + require 'lsp_signature'.on_attach({ + hint_enable = false, + }) +end + +-- Go + +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true +capabilities.textDocument.completion.completionItem.resolveSupport = { + properties = { + 'documentation', + 'detail', + 'additionalTextEdits', + } +} + +nvim_lsp.gopls.setup{ + settings = { + gopls = { + staticcheck = true, + analyses = { + unusedparams = true, + shadow = true, + unusedwrite = true, + unusedresult = true, + nilness = true, + }, + }, + }, + capabilities = capabilities, + on_attach = on_attach, +} + +-- Ruby + +nvim_lsp.solargraph.setup{ + on_attach = on_attach, +} + +-- Lua + +local system_name +if vim.fn.has("mac") == 1 then + system_name = "macOS" +elseif vim.fn.has("unix") == 1 then + system_name = "Linux" +else + print("Unsupported system for sumneko") +end + +local sumneko_root_path = os.getenv("HOME").."/dev/lua-language-server" +local sumneko_binary = sumneko_root_path.."/bin/"..system_name.."/lua-language-server" + +local runtime_path = vim.split(package.path, ';') +table.insert(runtime_path, "lua/?.lua") +table.insert(runtime_path, "lua/?/init.lua") + +nvim_lsp.sumneko_lua.setup { + cmd = {sumneko_binary, "-E", sumneko_root_path .. "/main.lua"}; + settings = { + Lua = { + runtime = { + version = 'LuaJIT', + path = runtime_path, + }, + diagnostics = { + globals = {'vim'}, + }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + }, + telemetry = { + enable = false, + }, + }, + }, + on_attach = on_attach, +} +EOF + +" nvim-compe: + +packadd! nvim-compe " https://github.com/hrsh7th/nvim-compe +packadd! compe-tmux " https://github.com/andersevenrud/compe-tmux + +lua < compe#confirm('') +inoremap compe#close('') +inoremap compe#scroll({ 'delta': +4 }) +inoremap compe#scroll({ 'delta': -4 }) + +" TAB navigation support: +lua <" + elseif check_back_space() then + return t "" + else + return vim.fn['compe#complete']() + end +end +_G.s_tab_complete = function() + if vim.fn.pumvisible() == 1 then + return t "" + else + return t "" + end +end + +vim.api.nvim_set_keymap("i", "", "v:lua.tab_complete()", {expr = true}) +vim.api.nvim_set_keymap("s", "", "v:lua.tab_complete()", {expr = true}) +vim.api.nvim_set_keymap("i", "", "v:lua.s_tab_complete()", {expr = true}) +vim.api.nvim_set_keymap("s", "", "v:lua.s_tab_complete()", {expr = true}) +EOF diff --git a/script/installnvim b/script/installnvim new file mode 100755 index 0000000..b79fdcf --- /dev/null +++ b/script/installnvim @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# Clone or update nvim to $HOME/dev/neovim, build and install to $HOME/local +set -e + +mkdir -p $HOME/dev +destdir=$HOME/dev/neovim +if [ -d $destdir ]; then + echo "Updating nvim..." + cd $destdir + git pull --rebase +else + echo "Cloning nvim..." + cd $HOME/dev + git clone -q https://github.com/neovim/neovim.git neovim + cd $destdir +fi + +make CMAKE_BUILD_TYPE=Release CMAKE_INSTALL_PREFIX=$HOME/local +make install diff --git a/script/installvimplugins b/script/installvimplugins index 0856dd0..5dc977b 100755 --- a/script/installvimplugins +++ b/script/installvimplugins @@ -17,7 +17,7 @@ pluginhome=$HOME/.vim/pack/git-plugins/opt mkdir -p $pluginhome cd $pluginhome -grep packadd! $HOME/.vimrc | grep -o 'https.*$' | while read -r url ; do +grep packadd! $HOME/.config/nvim/init.vim | grep -o 'https.*$' | while read -r url ; do dirname=$(basename $url .git) if [ -d "$dirname" ]; then echo "Exists: $dirname" diff --git a/script/tmuxsess b/script/tmuxsess index e351c24..b17abc9 100755 --- a/script/tmuxsess +++ b/script/tmuxsess @@ -15,7 +15,7 @@ else fi tmux new -d -s $sessionname tmux rename-window -t $sessionname:1 cli -tmux new-window -t $sessionname -n vim vim +tmux new-window -t $sessionname -n vim nvim tmux select-window -t $sessionname:1 # https://github.com/tmux/tmux/issues/2064 sleep 0.5 diff --git a/script/updatedevenv b/script/updatedevenv index a945987..7ea3169 100755 --- a/script/updatedevenv +++ b/script/updatedevenv @@ -5,5 +5,11 @@ set -e updatealacritty -updatevim +updatenvim updatevimplugins + +echo "Installing gopls..." +cd $HOME +go get golang.org/x/tools/gopls@latest + +echo "Done" diff --git a/script/updatenvim b/script/updatenvim new file mode 120000 index 0000000..2932bd7 --- /dev/null +++ b/script/updatenvim @@ -0,0 +1 @@ +installnvim \ No newline at end of file diff --git a/script/uuidprint b/script/uuidprint new file mode 100755 index 0000000..e576825 --- /dev/null +++ b/script/uuidprint @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +# +# uuidprint - generate and print a lower-case UUID v4 + +uuidgen | tr '[:upper:]' '[:lower:]' | tr -d '\n' diff --git a/script/uuidyank b/script/uuidyank index bddd793..f7a3c97 100755 --- a/script/uuidyank +++ b/script/uuidyank @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# uuidc - generate and copy a lower-case UUID v4 +# uuidyank - generate and copy a lower-case UUID v4 # TODO: fix for Linux -uuidgen | tr '[:upper:]' '[:lower:]' | tr -d '\n' | pbcopy +uuidprint | pbcopy diff --git a/tmux.conf b/tmux.conf index 6eeb691..245a4d6 100644 --- a/tmux.conf +++ b/tmux.conf @@ -23,7 +23,7 @@ bind-key v split-window -h bind-key s split-window -v bind-key p new-window \; set window-status-style fg=white,bg=red bind-key c new-window -n 'cli' -bind-key e new-window -n 'vim' vim +bind-key e new-window -n 'vim' nvim bind-key C rename-window 'cli' bind-key E rename-window 'vim' diff --git a/vim/after/ftplugin/go.vim b/vim/after/ftplugin/go.vim index c479be4..26fc85d 100644 --- a/vim/after/ftplugin/go.vim +++ b/vim/after/ftplugin/go.vim @@ -29,13 +29,15 @@ nnoremap ds :GoDebugStep " Vim-Go configuration let g:go_gopls_enabled = 0 -let g:go_fmt_autosave = 0 +let g:go_fmt_autosave = 1 let g:go_imports_autosave = 0 +let g:go_textobj_enabled = 0 let g:go_auto_sameids = 0 let g:go_auto_type_info = 0 let g:go_code_completion_enabled = 0 let g:go_echo_command_info = 0 let g:go_echo_go_info = 0 +let g:go_textobj_enabled = 0 let g:go_highlight_diagnostic_errors = 0 let g:go_highlight_diagnostic_warnings = 0 let g:go_highlight_trailing_whitespace_error=0 diff --git a/vim/after/queries/go/textobjects.scm b/vim/after/queries/go/textobjects.scm new file mode 100644 index 0000000..bfcede0 --- /dev/null +++ b/vim/after/queries/go/textobjects.scm @@ -0,0 +1,28 @@ +;; key/value-like types. Works with struct values, struct definitions and parameter value/type pairs: +;; +;; @keyed_element.outer => key and value +;; @keyed_element.inner => value + +(keyed_element (_) . (_) @keyed_element.inner) @keyed_element.outer +(field_declaration type: (_) @keyed_element.inner) @keyed_element.outer +(parameter_declaration type: (_) @keyed_element.inner) @keyed_element.outer + +;; return statement + +(return_statement (_) @return) + +;; functions and methods with an optional preceeding comment: +;; +;; TODO: comment only matches a single line. + +(( + (comment)? @_start + . + (method_declaration) @_end +) (make-range! "function_with_comment" @_start @_end)) + +(( + (comment)? @_start + . + (function_declaration) @_end +) (make-range! "function_with_comment" @_start @_end)) diff --git a/zshenv b/zshenv index 929e8c9..c852a2f 100644 --- a/zshenv +++ b/zshenv @@ -4,8 +4,8 @@ export TERM=xterm-256color export XDG_CONFIG_HOME="$HOME/.config" -export EDITOR="vim" -export VISUAL="vim" +export EDITOR="nvim" +export VISUAL="nvim" # ZSH: export ZDOTDIR="$XDG_CONFIG_HOME/zsh" diff --git a/zshrc b/zshrc index 4b12ead..b7da40f 100644 --- a/zshrc +++ b/zshrc @@ -94,6 +94,7 @@ alias rgt="rg -g '*\_test.go' -g '!vendor/'" alias tm="tmux attach" alias tmd="tmux new -s default -c $HOME || tmux attach -t default" alias tms="tmuxsess" +alias vim="nvim" alias wg="sudo wg" alias wgdown="sudo wgdown" alias wgup="sudo wgup"