" A fundamental question for this plugin is whether insertmode " is always relevant. This is where we try to get an answer. function! s:IsEditableBuffer() if &buftype ==# 'nofile' \|| !&modifiable \|| &readonly return 0 else return 1 endif endfunction " Make sure insert mode is the default mode only when opening/switching " to files that you want to edit. function! s:InsertMode() if s:IsEditableBuffer() == 1 exe "set insertmode" else exe "set noinsertmode" endif endfunction " Count number of open buffers. They don't have to be visible. function! s:CountListedBuffers() let bfr_count = 0 for bfr in range(1, bufnr("$")) if buflisted(bfr) \&& ! empty(bufname(bfr)) \|| getbufvar(bfr, '&buftype') ==# 'help' let bfr_count += 1 endif endfor return bfr_count endfunction " The number of visible lines in the current buffer. " TODO: Include wrapped lines in the total, so that we can start scrolling " through *visible* lines rather than file lines. function! s:BufferLines() return line('w$') - line('w0') endfunction function! s:InsertAndSelectionBehaviour() " Intelligently set/unset insertmode augroup start_insertmode autocmd! if has('timers') == 1 " The timer here delays the call to check whether the current buffer " is an editable one. Without the delay, the check is often too early " to correctly get the value of `&buftype`, etc. autocmd BufEnter * call timer_start(1, {->execute('call s:InsertMode()')}) else autocmd BufEnter * call s:InsertMode() endif augroup END " Mostly changes the way selection works. " See: http://vimdoc.sourceforge.net/htmldoc/gui.html#:behave " An extract from the docs about the difference between `behave mswin` " and `behave xterm`: " mswin xterm " 'selectmode' 'mouse,key' '' " 'mousemodel' 'popup' 'extend' " 'keymodel' 'startsel,stopsel' '' " 'selection' 'exclusive' 'inclusive' behave mswin " Make 'v' commands default to Visual mode. " Not sure how useful this is because the mappings that use 'v'-based " commands don't seem to follow this option. Thus why you will see " after some selection-based commands to switch from Visual to Selection " Mode. So might be better to give experienced users who are pressing " 'v' in normal mode the expected behaviour. set selectmode+=cmd endfunction " All shortcuts in one function so they can be more easily controlled. function! g:SetShortcuts() if g:heresy_app_shortcuts == 1 " Completely exit vim inoremap :call heresy#CloseVim() snoremap :call heresy#CloseVim() nnoremap :call heresy#CloseVim() " Close current pane-like things. inoremap :call heresy#ClosePane() snoremap :call heresy#ClosePane() nnoremap :call heresy#ClosePane() " Save file inoremap :update " New file inoremap :edit " Open file (TODO: hook into netrw or NERDTree) inoremap :edit endif if g:heresy_copypaste_shortcuts == 1 " One of those curious features of Vim: without `onemore` when pasting " at the end of a line, pasted text gets put *before* the cursor. set virtualedit=onemore " Cut selected text / current line snoremap "+xi inoremap "+dd " Copy selected text / current line snoremap "+ygv inoremap "+Y " Paste system clipboard inoremap :call heresy#Paste() " The odd here is because one-off Normal Mode commands " don't seem to work as expected when some text is selected. Also just " using on its own seems to cause weird behaviour too. snoremap :call heresy#Paste() cnoremap " endif " Use for native terminal backgrounding. " The s used in the `snoremap` commands seem to prevent the selection " process itself being put in the undo history - so now the undo actually " undoes the last *text* activity. if g:heresy_undo_shortcuts == 1 " Undo inoremap u snoremap u " Redo inoremap snoremap endif if g:heresy_plugin_shortcuts == 1 " Update plugins inoremap :PlugUpdate " Install plugins " TODO: The tab key outputs CTRL+I instead of Tab -_- " inoremap :PlugInstall endif if g:heresy_find_shortcuts == 1 " Find inoremap / " Find selected word under cursor snoremap y/" " Find next " inoremap n " Find previous " inoremap N " Find and replace inoremap :%s/[FIND]/[REPLACE]/g " Jump to a line " inoremap :call heresy#GotoLine() " Multi-select VSCode style " snoremap ??? endif if g:heresy_line_shortcuts == 1 " Move the current / selected line(s) up inoremap :m -2 snoremap :m '<-2gv=gv inoremap :m -2 snoremap :m '<-2gv=gv " Move the current / selected line(s) down inoremap :m +1 snoremap :m '>+1gv=gv inoremap :m +1 snoremap :m '>+1gv=gv endif if g:heresy_tab_shortcuts == 1 " Open a new tab inoremap :tabnew snoremap :tabnew " Cycle through tabs inoremap :tabnext snoremap :tabnext " Cycle backwards through tabs inoremap :tabprevious snoremap :tabprevious endif if g:heresy_pane_shortcuts == 1 " Move between splits, panes, windows, etc and close them inoremap snoremap nnoremap inoremap snoremap nnoremap inoremap snoremap nnoremap inoremap snoremap nnoremap " This allows unsaved buffers to be kept in the background. set hidden end " TODO: Shift+TAB doesn't work in insert mode, but does in selection mode?? " TODO: In Neovim TAB doesn't work in mswin selection mode, but SHIFT+TAB does?? if g:heresy_indentation_shortcuts == 1 " Indenting snoremap >gv inoremap snoremap >gv " Unindenting snoremap snoremap ^ " The same but for selection behaviour inoremap ^ snoremap ^ " Tweaks PageUp behaviour to get cursor to first line on top page inoremap :call heresy#PageUp() endif endfunction function! heresy#CloseVim() let l:check = execute(":ls") if l:check =~ "+" let l:confirmed = confirm('There are unsaved buffers. Do you really want to quit Vim?', "&Yes\n&No", 2) if l:confirmed == 1 quitall! endif else quitall endif endfunction " Try to intuitively and intelligently close things like buffers, splits, " panes, quicklist, etc, basically anything that looks like a pane. function! heresy#ClosePane() let l:check = execute(":ls") if s:IsEditableBuffer() == 1 " TODO: These aren't actually formally associated with a buffer, although " conceptually they often are (eg; linting errors, file search). " Close any location lists on screen. exe "lclose" " Close any quickfix lists on screen. exe "cclose" if s:CountListedBuffers() > 1 " By default if the buffer is the only one on screen, closing it closes the " tab/window. So this little trick does a switch to the next buffer, " then closes the previous buffer. exe "bp\|bd #" elseif l:check =~ "%a +" let l:confirmed = confirm('Your active buffer is not saved. Close anyway?', "&Yes\n&No", 2) if l:confirmed == 1 quit! endif else quit endif else quit endif endfunction " By default Vim treats wrapped text as a single line even though it may " appear as many lines on screen. So here we try to make wrapped text behave " more conventionally. Please add any new types you might come across. function! s:SetWrappedTextNavigation() autocmd BufNewFile,BufRead *.{ \md, \mdown, \markdown, \txt, \textile, \rdoc, \org, \creole, \mediawiki \} setlocal filetype=markdown autocmd FileType \ \markdown, \rst, \asciidoc, \pod, \txt \ call s:WrappedTextBehaviour() endfunction function! s:WrappedTextBehaviour() " Allow text to wrap in text files setlocal linebreak wrap " Make arrow keys move through wrapped lines " TODO: " * Scroll window 1 wrapped soft line at a time rather than entire block " of wrapped lines -- I'm as good as certain this will need a patch to " (n)vim's internals. inoremap gk inoremap gj " For selection behaviour snoremap gk snoremap gj " HOME/END for *visible* lines, not literal lines inoremap g^ inoremap g$ " For selection behaviour inoremap g^ snoremap g^ inoremap g$ snoremap g$ endfunction function! heresy#GotoLine() let l:line_number = input('Goto line: ') execute line_number endfunction " Just to get PAGEUP to move to the first line when on the first page. function! heresy#PageUp() " If current line is higher than the size of the buffer if line(".") > s:BufferLines() " Normal PageUp execute "normal! \" else " Goto first line execute "normal! gg" endif endfunction function! heresy#Paste() set paste execute 'normal! "+P' set nopaste call feedkeys("\") endfunction function! g:heresy#StartHeresy() call s:InsertAndSelectionBehaviour() if g:heresy_better_wrap_navigation == 1 call s:SetWrappedTextNavigation() endif if g:heresy_shortcuts == 1 call g:SetShortcuts() endif endfunction " ALT+; for command prompt " inoremap : " snoremap : " inoremap : " snoremap : " nnoremap : " nnoremap : " replaces native for one-time normal mode commands. " inoremap " snoremap " Select word under cursor " inoremap viw " Select current line " inoremap V " Append next line to selection " snoremap gj " CTRL-A for selecting all text " inoremap gggHG " snoremap gggHG " CTRL+ALTt+k deletes the current line under the cursor " TODO: Doesn't work in terminal vim, even with vim-fixkey " inoremap "_dd " CTRL+ALT+d duplicates current line. " NB. Uses the named 'd' register. " TODO: Doesn't work in terminal vim, even with vim-fixkey " inoremap "dyy"dp