aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2018-07-12 01:16:10 +1200
committerTom Ryder <tom@sanctum.geek.nz>2018-07-12 01:16:10 +1200
commitab987c9355fc4595861c194ede44a6607174464d (patch)
treeeeb15ea8830fae06363ec5649861fbd050667dfe
parentMerge branch 'release/v1.0.0' (diff)
parentBump VERSION (diff)
downloadvim-insert-cancel-ab987c9355fc4595861c194ede44a6607174464d.tar.gz
vim-insert-cancel-ab987c9355fc4595861c194ede44a6607174464d.zip
Merge branch 'release/v2.0.0'v2.0.0
* release/v2.0.0: Bump VERSION Complete overhaul
-rw-r--r--VERSION2
-rw-r--r--doc/insert_cancel.txt24
-rw-r--r--plugin/insert_cancel.vim71
3 files changed, 55 insertions, 42 deletions
diff --git a/VERSION b/VERSION
index 3eefcb9..227cea2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0
+2.0.0
diff --git a/doc/insert_cancel.txt b/doc/insert_cancel.txt
index 5893a05..d6efbfa 100644
--- a/doc/insert_cancel.txt
+++ b/doc/insert_cancel.txt
@@ -10,22 +10,14 @@ something useful, and to fire |InsertLeave| afterwards where available.
REQUIREMENTS *insert_cancel-requirements*
This plugin is only available if 'compatible' is not set. It works better on
-newer versions of Vim.
-
-If you have |autocmd| and at least |version-7.4| (or |version-7.3| with patch
-867) it works really well, because it has |TextChanged| to lean on for
-watching |b:changedtick|.
-
-If you have |autocmd| and |version-7.0| to |version-7.3|, it leans on
-|CursorMoved| instead. This still seems pretty good, but I imagine it's more
-likely there are subtle gaps, and it's also not ideal in terms of performance
-because the event fires a lot without doing anything useful.
-
-If you have just |version6|, all the plugin has to go on are the |'[| and |']|
-marks. It still kind of works, but there are some big gaps; it won't undo text
-that was erased when insert mode was entered with |c| or |s| or its variants.
-It also may not undo new blank lines. Even this is still slightly better than
-just the intuitive mapping:
+newer versions of Vim. It works best if you have |autocmd| and at least
+|version-7.0|, because it leans on |CursorMoved|.
+
+If you don't have |autocmd| and |version7|, all the plugin has to go on are
+the |'[| and |']| marks. It still kind of works, but there are some big gaps;
+it won't undo text that was erased when insert mode was entered with |c| or
+|s| or its variants, and it also may not undo new blank lines. Even this is
+still rather better than just the intuitive mapping:
>
imap <C-C> <Esc>u
<
diff --git a/plugin/insert_cancel.vim b/plugin/insert_cancel.vim
index 61d0b49..51216d0 100644
--- a/plugin/insert_cancel.vim
+++ b/plugin/insert_cancel.vim
@@ -3,6 +3,8 @@
" change upon insert exit, if we made a change; intended for remapping
" insert-mode Ctrl-C to do something useful.
"
+" This was *way* harder to figure out than it looks.
+"
" Author: Tom Ryder <tom@sanctum.geek.nz>
" License: Same as Vim itself
"
@@ -14,38 +16,57 @@ if v:version < 600
endif
let g:loaded_insert_cancel = 1
-" Initialise s:changedtick so vint understands
-let s:changedtick = 0
+" On leaving insert mode, whether normally or via <Plug>InsertCancel, check if
+" changenr() exceeds the last time we cached it, and flag that a change has
+" taken place if it did
+function! s:Check()
+ if changenr() > b:insert_cancel_changenr
+ let b:insert_cancel_changed = 1
+ endif
+endfunction
-" Set up an appropriate hook to track b:changedtick before we hit InsertLeave
-if has('autocmd')
- augroup insert_cancel
- autocmd!
+" On entering insert mode, reset the changed flag and check for a new round of
+" changes since insert mode was opened
+function! s:Enter()
+ let b:insert_cancel_changed = 0
+ call s:Check()
+endfunction
- " Ideal; only runs when the text actually changes
- if v:version > 703 || v:version == 703 && has('patch867')
- autocmd TextChanged * let s:changedtick = b:changedtick
+" On cancelling insert mode, if we think we made a change, undo it
+function! s:Cancel()
- " Workable but wasteful and not quite as correct; updates every move
- elseif v:version >= 700
- autocmd CursorMoved * let s:changedtick = b:changedtick
+ " The flag exists, if it's on, undo
+ if exists('b:insert_cancel_changed')
+ if b:insert_cancel_changed
+ silent undo
endif
- augroup END
-endif
-
-" Try hard to figure out whether we made a change to undo, and undo it if so
-function! s:InsertCancel()
- if !&modified
- return
- endif
- if s:changedtick > 0 && b:changedtick > s:changedtick
- \ || line("'[") != line("']")
- \ || col("'[") != col("']")
+ " The flag didn't exist, fall back to marks; if the line number or column
+ " number of the marks for the last changed text aren't exactly equal, that
+ " suggests we changed something; undo it
+ elseif line("'[") != line("']") || col("'[") != col("']")
silent undo
endif
+
endfunction
-" Provide plugin mapping
+" Set up the hooks described for the functions above, if Vim is new enough to
+" support all the hooks required
+if has('autocmd') && v:version >= 700
+ augroup insert_cancel
+ autocmd!
+
+ " On buffer load and cursor move, cache the current change number
+ autocmd BufNewFile,BufRead,CursorMoved *
+ \ let b:insert_cancel_changenr = changenr()
+
+ " Function wrappers for entering and leaving insert mode
+ autocmd InsertEnter * call s:Enter()
+ autocmd InsertLeave * call s:Check()
+
+ augroup END
+endif
+
+" Mapping that exits insert mode normally and checks for a change to undo
inoremap <silent> <Plug>InsertCancel
- \ <Esc>:<C-U>call <SID>InsertCancel()<CR>
+ \ <Esc>:<C-U>call <SID>Cancel()<CR>