aboutsummaryrefslogtreecommitdiff
path: root/autoload
diff options
context:
space:
mode:
authorThomas Buckley-Houston2017-05-30 09:24:00 +0000
committerThomas Buckley-Houston2017-05-30 09:24:00 +0000
commit79bd6b4273325f891d2fcdb2a79ede59e313e414 (patch)
tree48028cfaf00bdd6ef82b83afb638317db4a9a53d /autoload
parent37905d1bad1dd19cca13fd36022b0cffb811b699 (diff)
Formalise plugin: functions, autoload, tests
Diffstat (limited to 'autoload')
-rw-r--r--autoload/novim_mode.vim287
1 files changed, 287 insertions, 0 deletions
diff --git a/autoload/novim_mode.vim b/autoload/novim_mode.vim
new file mode 100644
index 0000000..f7408d3
--- /dev/null
+++ b/autoload/novim_mode.vim
@@ -0,0 +1,287 @@
+" 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
+ \|| bufname('%') =~# 'NERD_tree_'
+ 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!
+ autocmd BufEnter * call s:InsertMode()
+ 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 <C-G>
+ " 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:SetNoVimModeShortcuts()
+ " Basic interactions with the editor
+ if g:novim_mode_use_general_app_shortcuts == 1
+ " CTRL+q to completely exit vim
+ inoremap <silent> <C-Q> <C-O>:call novim_mode#ExitVim()<CR>
+ snoremap <silent> <C-Q> <C-O>:call novim_mode#ExitVim()<CR>
+ nnoremap <silent> <C-Q> :call novim_mode#ExitVim()<CR>
+
+ " CTRL+n for new file
+ inoremap <C-N> <C-O>:edit<Space>
+ " CTRL+o to open file
+ " TODO: hook into netrw or NERDTree
+ inoremap <C-O> <C-O>:edit<Space>
+ " CTRL+s saves
+ inoremap <silent> <C-S> <C-O>:update<CR>
+
+ " Goto line number
+ inoremap <C-G> <C-O>:call novim_mode#GotoLine()<CR>
+
+ " ALT+; for command prompt
+ inoremap <M-;> <C-O>:
+
+ " <ALT+o> replaces native <C-O> for one-time normal mode commands.
+ inoremap <M-o> <C-O>
+ snoremap <M-o> <C-O>
+ endif
+
+ " General fixes to editor behaviour
+ if g:novim_mode_use_editor_fixes == 1
+ " Fix HOME to go back to the first non-whitespace character of the line
+ inoremap <silent> <Home> <C-O>^
+
+ " Tweaks PageUp behaviour to get cursor to first line on top page
+ inoremap <silent> <PageUp> <C-O>:call novim_mode#PageUp()<CR>
+ endif
+
+ " Move between splits, panes, windows, etc and close them
+ if g:novim_mode_use_pane_controls == 1
+ inoremap <silent> <M-Left> <C-O><C-W><Left>
+ nnoremap <silent> <M-Left> <C-W><Left>
+ inoremap <silent> <M-Down> <C-O><C-W><Down>
+ nnoremap <silent> <M-Down> <C-W><Down>
+ inoremap <silent> <M-Up> <C-O><C-W><Up>
+ nnoremap <silent> <M-Up> <C-W><Up>
+ inoremap <silent> <M-Right> <C-O><C-W><Right>
+ nnoremap <silent> <M-Right> <C-W><Right>
+
+ " This allows unsaved buffers to be kept in the background.
+ set hidden
+
+ " CTRL+w to delete current pane-like things.
+ inoremap <silent> <C-W> <C-O>:call novim_mode#ClosePane()<CR>
+ snoremap <silent> <C-W> <C-O>:call novim_mode#ClosePane()<CR>
+ nnoremap <silent> <C-W> :call novim_mode#ClosePane()<CR>
+ end
+
+ " Selecting, copy, paste, etc
+ if g:novim_mode_use_copypasting == 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
+ " NB. All these use the named 'p' register.
+ inoremap <C-V> <C-O>"pP
+ snoremap <C-C> <C-O>"pyi
+ inoremap <C-C> <C-O>"pY
+ snoremap <C-X> <C-O>"pxi
+ inoremap <C-X> <C-O>"pdd
+ " Select word under cursor
+ inoremap <C-D> <C-O>viw<C-G>
+ " Select current line
+ inoremap <C-L> <C-O>V<C-G>
+ " Append next line to selection
+ snoremap <C-L> <C-O>gj
+
+ " CTRL-A for selecting all text
+ inoremap <C-A> <C-O>gg<C-O>gH<C-O>G
+ snoremap <C-A> <C-O><C-C>gggH<C-O>G
+ endif
+
+ " Indenting
+ if g:novim_mode_use_indenting == 1
+ " TODO: TAB doesn't work in mswin selection mode, but SHIFT+TAB does??
+ snoremap <Tab> <C-O>>gv
+ inoremap <M-]> <C-T>
+ snoremap <M-]> <C-O>>gv
+ " Unindenting
+ snoremap <S-Tab> <C-O><gv
+ inoremap <M-[> <C-D>
+ snoremap <M-[> <C-O><gv
+ endif
+
+ if g:novim_mode_use_finding == 1
+ " Find
+ inoremap <C-F> <C-O>/
+ " Find selected word under cursor
+ snoremap <C-F> <C-O>y/<C-R>"<CR>
+ " Find next
+ inoremap <F3> <C-O>n
+ " Find previous
+ inoremap <S-F3> <C-O>N
+ " Find and replace
+ inoremap <C-H> <C-O>:%s/[FIND]/[REPLACE]/g
+ " Clears highlighting.
+ " NB. Overriding ESC makes it harder to get into NORMAL mode.
+ inoremap <silent> <Esc> <C-O>:noh<CR>
+ endif
+
+ " Undo/redo
+ if g:novim_mode_use_undoing == 1
+ " Use <M-o><C-Z> for native terminal backgrounding.
+ " The <Esc>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.
+ inoremap <silent> <C-Z> <C-O>u
+ snoremap <silent> <C-Z> <Esc><C-O>u
+ " Map CTRL+u as well for now just because by default it deletes the line above
+ " the cursor.
+ inoremap <silent> <C-U> <C-O>u
+ snoremap <silent> <C-U> <Esc><C-O>u
+ " Redo
+ inoremap <silent> <C-Y> <C-O><C-R>
+ snoremap <silent> <C-Y> <Esc><C-O><C-R>
+ endif
+
+ " Useful, but not necessarily core or conventional, shortcuts for manipulating
+ " text.
+ if g:novim_mode_use_text_tricks == 1
+ " CTRL+ALTt+k deletes the current line under the cursor
+ inoremap <silent> <C-M-K> <C-O>"_dd
+
+ " CTRL+ALT+d duplicates current line.
+ " NB. Uses the named 'd' register.
+ inoremap <silent> <C-M-D> <C-O>"dyy<C-O>"dp
+
+ " CTRL+DOWN/UP moves the current/selected line(s) up and down
+ inoremap <silent> <C-Up> <C-O>:m -2<CR>
+ snoremap <silent> <C-Up> <C-O>:m '<-2<CR>gv=gv<C-G>
+ inoremap <silent> <C-Down> <C-O>:m +1<CR>
+ snoremap <silent> <C-Down> <C-O>:m '>+1<CR>gv=gv<C-G>
+ 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.
+function! s:SetWrappedTextNavigation()
+ " Allow text to wrap in text files
+ au BufNewFile,BufRead *.txt,*.md,*.markdown setlocal linebreak spell
+
+ " Make arrow keys move through wrapped lines
+ " TODO:
+ " * Make END key move to end of current wrapped piece of line.
+ " * Scroll window 1 wrapped soft line at a time rather an entire block of wrapped
+ " lines.
+ au BufNewFile,BufRead *.txt,*.md,*.markdown inoremap <buffer> <Up> <C-O>gk
+ au BufNewFile,BufRead *.txt,*.md,*.markdown inoremap <buffer> <Down> <C-O>gj
+endfunction
+
+" Try to intuitively and intelligently close things like buffers, splits,
+" panes, quicklist, etc, basically anything that looks like a pane.
+function! novim_mode#ClosePane()
+ if s:IsEditableBuffer() == 1
+ " 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 #"
+ else
+ quit
+ endif
+ else
+ quit
+ endif
+endfunction
+
+" TODO: Mention any unsaved buffers
+function! novim_mode#ExitVim()
+ let l:confirmed = confirm('Do you really want to quit Vim?', "&Yes\n&No", 2)
+ if l:confirmed == 1
+ quitall!
+ endif
+endfunction
+
+function! novim_mode#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! novim_mode#PageUp()
+ " If current line is higher than the size of the buffer
+ if line(".") > s:BufferLines()
+ " Normal PageUp
+ execute "normal! \<C-b>"
+ else
+ " Goto first line
+ execute "normal! gg"
+ endif
+endfunction
+
+function! g:novim_mode#StartNoVimMode()
+ call s:InsertAndSelectionBehaviour()
+
+ if g:novim_mode_use_better_wrap_navigation == 1
+ call s:SetWrappedTextNavigation()
+ endif
+
+ if g:novim_mode_use_shortcuts == 1
+ call g:SetNoVimModeShortcuts()
+ endif
+endfunction