Update vital-over.
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   vital/_over/Data/List.vim
	modified:   vital/_over/Over/Commandline/Base.vim
	new file:   vital/_over/Over/Commandline/Modules/AsyncUpdate.vim
	modified:   vital/_over/Over/Commandline/Modules/CursorMove.vim
	modified:   vital/_over/Over/Commandline/Modules/DrawCommandline.vim
	modified:   vital/_over/Over/Commandline/Modules/History.vim
	modified:   vital/_over/Over/Commandline/Modules/InsertRegister.vim
	modified:   vital/_over/Over/Commandline/Modules/KeyMapping.vim
	modified:   vital/_over/Over/Commandline/Modules/Redraw.vim
	modified:   vital/_over/Over/String.vim
	modified:   vital/over.vital

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   over/command_line/substitute.vim

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	../test/autoload/over/
	../test/plugin/
	../test_over/

diff --git a/autoload/vital/_over/Data/List.vim b/autoload/vital/_over/Data/List.vim
index e9a62c2..bd12753 100644
--- a/autoload/vital/_over/Data/List.vim
+++ b/autoload/vital/_over/Data/List.vim
@@ -278,6 +278,54 @@ function! s:find(list, default, f)
   return a:default
 endfunction

+" Returns the index of the first element which satisfies the given expr.
+function! s:find_index(xs, f, ...)
+  let len = len(a:xs)
+  let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
+  let default = a:0 > 1 ? a:2 : -1
+  if start >=# len || start < 0
+    return default
+  endif
+  for i in range(start, len - 1)
+    if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
+      return i
+    endif
+  endfor
+  return default
+endfunction
+
+" Returns the index of the last element which satisfies the given expr.
+function! s:find_last_index(xs, f, ...)
+  let len = len(a:xs)
+  let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : len - 1
+  let default = a:0 > 1 ? a:2 : -1
+  if start >=# len || start < 0
+    return default
+  endif
+  for i in range(start, 0, -1)
+    if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
+      return i
+    endif
+  endfor
+  return default
+endfunction
+
+" Similar to find_index but returns the list of indices satisfying the given expr.
+function! s:find_indices(xs, f, ...)
+  let len = len(a:xs)
+  let start = a:0 > 0 ? (a:1 < 0 ? len + a:1 : a:1) : 0
+  let result = []
+  if start >=# len || start < 0
+    return result
+  endif
+  for i in range(start, len - 1)
+    if eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
+      call add(result, i)
+    endif
+  endfor
+  return result
+endfunction
+
 " Return non-zero if a:list1 and a:list2 have any common item(s).
 " Return zero otherwise.
 function! s:has_common_items(list1, list2)
@@ -301,6 +349,83 @@ function! s:group_by(xs, f)
   return result
 endfunction

+function! s:_default_compare(a, b)
+  return a:a <# a:b ? -1 : a:a ># a:b ? 1 : 0
+endfunction
+
+function! s:binary_search(list, value, ...)
+  let Predicate = a:0 >= 1 ? a:1 : 's:_default_compare'
+  let dic = a:0 >= 2 ? a:2 : {}
+  let start = 0
+  let end = len(a:list) - 1
+
+  while 1
+    if start > end
+      return -1
+    endif
+
+    let middle = (start + end) / 2
+
+    let compared = call(Predicate, [a:value, a:list[middle]], dic)
+
+    if compared < 0
+      let end = middle - 1
+    elseif compared > 0
+      let start = middle + 1
+    else
+      return middle
+    endif
+  endwhile
+endfunction
+
+function! s:product(lists)
+  let result = [[]]
+  for pool in a:lists
+    let tmp = []
+    for x in result
+      let tmp += map(copy(pool), 'x + [v:val]')
+    endfor
+    let result = tmp
+  endfor
+  return result
+endfunction
+
+function! s:permutations(list, ...)
+  if a:0 > 1
+    throw 'vital: Data.List: too many arguments'
+  endif
+  let r = a:0 == 1 ? a:1 : len(a:list)
+  if r > len(a:list)
+    return []
+  elseif r < 0
+    throw 'vital: Data.List: {r} must be non-negative integer'
+  endif
+  let n = len(a:list)
+  let result = []
+  for indices in s:product(map(range(r), 'range(n)'))
+    if len(s:uniq(indices)) == r
+      call add(result, map(indices, 'a:list[v:val]'))
+    endif
+  endfor
+  return result
+endfunction
+
+function! s:combinations(list, r)
+  if a:r > len(a:list)
+    return []
+  elseif a:r < 0
+    throw 'vital: Data:List: {r} must be non-negative integer'
+  endif
+  let n = len(a:list)
+  let result = []
+  for indices in s:permutations(range(n), a:r)
+    if s:sort(copy(indices), 'a:a - a:b') == indices
+      call add(result, map(indices, 'a:list[v:val]'))
+    endif
+  endfor
+  return result
+endfunction
+
 let &cpo = s:save_cpo
 unlet s:save_cpo

diff --git a/autoload/vital/_over/Over/Commandline/Base.vim b/autoload/vital/_over/Over/Commandline/Base.vim
index dc44464..8ee2255 100644
--- a/autoload/vital/_over/Over/Commandline/Base.vim
+++ b/autoload/vital/_over/Over/Commandline/Base.vim
@@ -8,7 +8,6 @@ function! s:_vital_loaded(V)
 	let s:String  = s:V.import("Over.String")
 	let s:Signals = s:V.import("Over.Signals")
 	let s:Module = s:V.import("Over.Commandline.Modules")
-	let s:List = s:V.import("Data.List")
 	let s:base.variables.modules = s:Signals.make()
 	function! s:base.variables.modules.get_slot(val)
 		return a:val.slot.module
@@ -21,7 +20,6 @@ function! s:_vital_depends()
 \		"Over.String",
 \		"Over.Signals",
 \		"Over.Commandline.Modules",
-\		"Data.List",
 \	]
 endfunction

@@ -368,7 +366,7 @@ function! s:base._input(input, ...)
 		let key = a:input
 	endif

-	for char in s:_split_keys(key)
+	for char in s:String.split_by_keys(key)
 		let self.variables.input_key = char
 		let self.variables.char = char
 		call self.setchar(self.variables.char)
@@ -379,6 +377,24 @@ function! s:base._input(input, ...)
 endfunction

+function! s:base._update()
+" 	call self.callevent("on_update")
+" 	if !getchar(1)
+" 		continue
+" 	endif
+"
+" 	call self._input(s:getchar(0))
+" 	call self.draw()
+
+	call self.callevent("on_update")
+	call self._input(s:getchar())
+	if self._is_exit()
+		return -1
+	endif
+	call self.draw()
+endfunction
+
+
 function! s:base._main(...)
 	try
 		call self._init()
@@ -388,18 +404,9 @@ function! s:base._main(...)
 		call self.draw()
 		while !self._is_exit()
 			try
-" 				call self.callevent("on_update")
-" 				if !getchar(1)
-" 					continue
-" 				endif
-"
-" 				call self._input(s:_getchar(0))
-" 				call self.draw()
-				call self._input(s:_getchar())
-				if self._is_exit()
+				if self._update()
 					break
 				endif
-				call self.draw()
 			catch
 				call self.callevent("on_exception")
 			endtry
@@ -438,7 +445,7 @@ endfunction

 function! s:_unmap(mapping, key)
-	let keys = s:_split_keys(a:key)
+	let keys = s:String.split_by_keys(a:key)
 	if len(keys) > 1
 		return join(map(keys, 's:_unmap(a:mapping, v:val)'), '')
 	endif
@@ -468,158 +475,23 @@ function! s:base._get_keymapping()
 endfunction

-function! s:_getchar(...)
+function! s:getchar(...)
+	let mode = get(a:, 1, 0)
 	while 1
-		let char = call("getchar", a:000)
+		" Workaround for https://github.com/osyo-manga/vital-over/issues/53
+		try
+			let char = call("getchar", a:000)
+		catch /^Vim:Interrupt$/
+			let char = 3 " <C-c>
+		endtry
 		" Workaround for the <expr> mappings
-		if char !=# "\x80\xfd`"
-			return type(char) == type(0) ? nr2char(char) : char
+		if string(char) !=# "\x80\xfd`"
+			return mode == 1 ? !!char
+\				 : type(char) == type(0) ? nr2char(char) : char
 		endif
 	endwhile
 endfunction

-
-function! s:_split(str, pat)
-	let pat = '\%#=2' . a:pat
-	let list = split(a:str,  pat . '\zs')
-	return s:List.flatten(map(list, 'v:val == a:pat ? a:pat : v:val =~ pat . ''$'' ? split(v:val, pat) + [a:pat] : v:val'))
-endfunction
-
-
-function! s:_split_keystring(str, pats, ...)
-	if a:str =~ '^<Over>(.\{-})$'
-\	|| a:str =~ "^\<Plug>(.\\{-})$"
-		return [a:str]
-	endif
-	let pats = a:pats
-	let index = get(a:, 1, 0)
-	if !exists("+regexpengine")
-\	|| index > len(pats)
-\	|| len(filter(copy(pats), 'a:str =~ ''\%#=2'' . v:val')) == 0
-		if len(filter(copy(pats), 'a:str ==# v:val')) == 0
-			return split(a:str, '\zs')
-		else
-			return [a:str]
-		endif
-	endif
-	if len(filter(copy(pats), 'a:str == v:val')) == 1
-		return [a:str]
-	endif
-
-	let result = []
-	let pat = pats[index]
-	let list = s:_split(a:str, pat)
-	let result += eval(join(map(list, "s:_split_keystring(v:val, pats, index+1)"), "+"))
-	return result
-endfunction
-
-
-
-
-let s:special_keys = [
-\	"\<BS>",
-\	"\<Down>",
-\	"\<Up>",
-\	"\<Left>",
-\	"\<Right>",
-\	"\<Home>",
-\	"\<End>",
-\	"\<Insert>",
-\	"\<Delete>",
-\	"\<PageUp>",
-\	"\<PageDown>",
-\	"\<F1>",
-\	"\<F2>",
-\	"\<F3>",
-\	"\<F4>",
-\	"\<F5>",
-\	"\<F6>",
-\	"\<F7>",
-\	"\<F8>",
-\	"\<F9>",
-\	"\<F10>",
-\	"\<F11>",
-\	"\<F12>",
-\	"\<A-BS>",
-\	"\<A-Down>",
-\	"\<A-Up>",
-\	"\<A-Left>",
-\	"\<A-Right>",
-\	"\<A-Home>",
-\	"\<A-End>",
-\	"\<A-Insert>",
-\	"\<A-Delete>",
-\	"\<A-PageUp>",
-\	"\<A-PageDown>",
-\	"\<A-F1>",
-\	"\<A-F2>",
-\	"\<A-F3>",
-\	"\<A-F4>",
-\	"\<A-F5>",
-\	"\<A-F6>",
-\	"\<A-F7>",
-\	"\<A-F8>",
-\	"\<A-F9>",
-\	"\<A-F10>",
-\	"\<A-F11>",
-\	"\<A-F12>",
-\	"\<A-Tab>",
-\	"\<C-BS>",
-\	"\<C-Down>",
-\	"\<C-Up>",
-\	"\<C-Left>",
-\	"\<C-Right>",
-\	"\<C-Home>",
-\	"\<C-End>",
-\	"\<C-Insert>",
-\	"\<C-Delete>",
-\	"\<C-PageUp>",
-\	"\<C-PageDown>",
-\	"\<C-Tab>",
-\	"\<C-F1>",
-\	"\<C-F2>",
-\	"\<C-F3>",
-\	"\<C-F4>",
-\	"\<C-F5>",
-\	"\<C-F6>",
-\	"\<C-F7>",
-\	"\<C-F8>",
-\	"\<C-F9>",
-\	"\<C-F10>",
-\	"\<C-F11>",
-\	"\<C-F12>",
-\	"\<S-Down>",
-\	"\<S-Up>",
-\	"\<S-Left>",
-\	"\<S-Right>",
-\	"\<S-Home>",
-\	"\<S-Insert>",
-\	"\<S-PageUp>",
-\	"\<S-PageDown>",
-\	"\<S-F1>",
-\	"\<S-F2>",
-\	"\<S-F3>",
-\	"\<S-F4>",
-\	"\<S-F5>",
-\	"\<S-F6>",
-\	"\<S-F7>",
-\	"\<S-F8>",
-\	"\<S-F9>",
-\	"\<S-F10>",
-\	"\<S-F11>",
-\	"\<S-F12>",
-\	"\<S-Tab>",
-\]
-" Issues #45
-" \	"\<S-End>",
-" \	"\<S-Delete>",
-
-function! s:_split_keys(str)
-	return s:_split_keystring(a:str, s:special_keys)
-endfunction
-
-
-
 let &cpo = s:save_cpo
 unlet s:save_cpo
diff --git a/autoload/vital/_over/Over/Commandline/Modules/AsyncUpdate.vim b/autoload/vital/_over/Over/Commandline/Modules/AsyncUpdate.vim
new file mode 100644
index 0000000..6e0f41f
--- /dev/null
+++ b/autoload/vital/_over/Over/Commandline/Modules/AsyncUpdate.vim
@@ -0,0 +1,39 @@
+scriptencoding utf-8
+let s:save_cpo = &cpo
+set cpo&vim
+
+function! s:_vital_loaded(V)
+	let s:V = a:V
+	let s:Base = s:V.import("Over.Commandline.Base")
+endfunction
+
+
+let s:module = {
+\	"name" : "AsyncUpdate"
+\}
+
+function! s:module.on_enter(cmdline)
+	function! a:cmdline._update()
+		call self.callevent("on_update")
+		try
+			if !getchar(1)
+				return
+			endif
+			let key = s:Base.getchar(0)
+		catch /^Vim:Interrupt$/
+			let key = "\<C-c>"
+		endtry
+
+		call self._input(key)
+		call self.draw()
+	endfunction
+endfunction
+
+
+function! s:make()
+	return deepcopy(s:module)
+endfunction
+
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/autoload/vital/_over/Over/Commandline/Modules/CursorMove.vim b/autoload/vital/_over/Over/Commandline/Modules/CursorMove.vim
index c3a02e8..fb27800 100644
--- a/autoload/vital/_over/Over/Commandline/Modules/CursorMove.vim
+++ b/autoload/vital/_over/Over/Commandline/Modules/CursorMove.vim
@@ -21,6 +21,15 @@ function! s:module.on_char_pre(cmdline)
 \		|| a:cmdline.is_input("\<End>")
 		call a:cmdline.setline(a:cmdline.line.length())
 		call a:cmdline.setchar('')
+	elseif a:cmdline.is_input("\<C-Left>")
+\		|| a:cmdline.is_input("\<S-Left>")
+		call a:cmdline.setline(strridx(a:cmdline.backward()[:-2], ' ') + 1)
+		call a:cmdline.setchar('')
+	elseif a:cmdline.is_input("\<C-Right>")
+\		|| a:cmdline.is_input("\<S-Right>")
+		let p = stridx(a:cmdline.forward()[1:], ' ')
+		call a:cmdline.setline(p != -1 ? a:cmdline.line.pos() + p + 2 : a:cmdline.line.length())
+		call a:cmdline.setchar('')
 	endif
 endfunction

diff --git a/autoload/vital/_over/Over/Commandline/Modules/DrawCommandline.vim b/autoload/vital/_over/Over/Commandline/Modules/DrawCommandline.vim
index 7953657..7e57887 100644
--- a/autoload/vital/_over/Over/Commandline/Modules/DrawCommandline.vim
+++ b/autoload/vital/_over/Over/Commandline/Modules/DrawCommandline.vim
@@ -42,7 +42,7 @@ function! s:_redraw(cmdline)
 	let left = a:cmdline.get_prompt() . a:cmdline.getline() . (empty(a:cmdline.line.pos_word()) ? " " : "")
 	let width = len(left) + 1

-	if	a:cmdline.get_suffix() != ""
+	if a:cmdline.get_suffix() != ""
 		let width += len(s:suffix(left, a:cmdline.get_suffix())) - 1
 	endif

diff --git a/autoload/vital/_over/Over/Commandline/Modules/History.vim b/autoload/vital/_over/Over/Commandline/Modules/History.vim
index 4e6db3c..14b272d 100644
--- a/autoload/vital/_over/Over/Commandline/Modules/History.vim
+++ b/autoload/vital/_over/Over/Commandline/Modules/History.vim
@@ -8,31 +8,43 @@ let s:module = {
 \}

 function! s:module.histories()
-	return map(range(&history), 'histget(self.mode, v:val * -1)')
+	return map(range(1, &history), 'histget(self.mode, v:val * -1)')
 endfunction

+function! s:_should_match_cmdline(cmdline)
+	return a:cmdline.is_input("\<Up>")
+\		|| a:cmdline.is_input("\<Down>")
+endfunction

-function! s:module.on_enter(...)
+function! s:_reset()
 	let s:cmdhist = []
 	let s:count = 0
+	let s:is_match_mode = 0 " <Up>/<Down>: true, <C-n>/<C-p>: false
+endfunction
+
+function! s:module.on_enter(...)
+	call s:_reset()
 endfunction

 function! s:module.on_char_pre(cmdline)
 	if !a:cmdline.is_input("\<Up>") && !a:cmdline.is_input("\<Down>")
-		let s:cmdhist = []
-		let s:count = 0
+	\	&& !a:cmdline.is_input("\<C-p>") && !a:cmdline.is_input("\<C-n>")
+		call s:_reset()
 		return
 	else
 		if s:count == 0 && empty(s:cmdhist)
+		\	|| s:is_match_mode != s:_should_match_cmdline(a:cmdline)
 			let cmdline = '^' . a:cmdline.getline()
-			let s:cmdhist = filter(self.histories(), 'v:val =~ cmdline')
+			let s:is_match_mode = s:_should_match_cmdline(a:cmdline)
+			let s:cmdhist = [a:cmdline.getline()] + (s:is_match_mode ?
+			\	filter(self.histories(), 'v:val =~ cmdline') : self.histories())
 		endif
 	endif
 	call a:cmdline.setchar("")
-	if a:cmdline.is_input("\<Down>")
+	if a:cmdline.is_input("\<Down>") || a:cmdline.is_input("\<C-n>")
 		let s:count = max([s:count - 1, 0])
 	endif
-	if a:cmdline.is_input("\<Up>")
+	if a:cmdline.is_input("\<Up>") || a:cmdline.is_input("\<C-p>")
 		let s:count = min([s:count + 1, len(s:cmdhist)])
 	endif
 	call a:cmdline.setline(get(s:cmdhist, s:count, a:cmdline.getline()))
diff --git a/autoload/vital/_over/Over/Commandline/Modules/InsertRegister.vim b/autoload/vital/_over/Over/Commandline/Modules/InsertRegister.vim
index 93c8404..bce7fe3 100644
--- a/autoload/vital/_over/Over/Commandline/Modules/InsertRegister.vim
+++ b/autoload/vital/_over/Over/Commandline/Modules/InsertRegister.vim
@@ -31,14 +31,28 @@ let s:module = {
 \}

-function! s:module.on_enter(...)
+
+function! s:module.reset()
 	let self.cword = expand("<cword>")
 	let self.cWORD = expand("<cWORD>")
 	let self.cfile = expand("<cfile>")
+endfunction
+
+function! s:module.on_enter(...)
+	call self.reset()
 " 	let self.prefix_key = ""
 endfunction

+function! s:get_cmdline_cword(backword, cword)
+	let backword = matchstr(a:backword, '.\{-}\zs\w\+$')
+	if &incsearch == 0 || a:cword == "" || a:backword == "" || stridx(a:cword, backword) != 0
+		return a:cword
+	endif
+	return a:cword[len(backword) : ]
+endfunction
+
+
 function! s:module.on_char_pre(cmdline)
 	if a:cmdline.is_input("\<C-r>")
 		call a:cmdline.setchar('"')
@@ -57,7 +71,7 @@ function! s:module.on_char_pre(cmdline)
 		elseif char == "="
 			call a:cmdline.setchar(s:input(a:cmdline))
 		elseif char == "\<C-w>"
-			call a:cmdline.setchar(self.cword)
+			call a:cmdline.setchar(s:get_cmdline_cword(a:cmdline.backward(), self.cword))
 		elseif char == "\<C-a>"
 			call a:cmdline.setchar(self.cWORD)
 		elseif char == "\<C-f>"
diff --git a/autoload/vital/_over/Over/Commandline/Modules/KeyMapping.vim b/autoload/vital/_over/Over/Commandline/Modules/KeyMapping.vim
index 0cb217b..9119286 100644
--- a/autoload/vital/_over/Over/Commandline/Modules/KeyMapping.vim
+++ b/autoload/vital/_over/Over/Commandline/Modules/KeyMapping.vim
@@ -48,6 +48,16 @@ function! s:emacs.keymapping(cmdline)
 \			"noremap" : 1,
 \			"lock" : 1,
 \		},
+\		"\<A-b>" : {
+\			"key" : "\<S-Left>",
+\			"noremap" : 1,
+\			"lock" : 1,
+\		},
+\		"\<A-f>" : {
+\			"key" : "\<S-Right>",
+\			"noremap" : 1,
+\			"lock" : 1,
+\		},
 \	}
 endfunction

diff --git a/autoload/vital/_over/Over/Commandline/Modules/Redraw.vim b/autoload/vital/_over/Over/Commandline/Modules/Redraw.vim
index d64b171..480ed21 100644
--- a/autoload/vital/_over/Over/Commandline/Modules/Redraw.vim
+++ b/autoload/vital/_over/Over/Commandline/Modules/Redraw.vim
@@ -39,8 +39,12 @@ function! s:module.redraw(cmdline)
 	redraw
 	" Workaround for the :set cedit=<C-c>
 	" https://github.com/osyo-manga/vital-over/issues/52
+	" https://github.com/Lokaltog/vim-easymotion/issues/177#issuecomment-53663431
 	if &cedit != "<C-c>"
+\	||(v:version >= 704 && has("patch441"))
 		normal! :
+	else
+		execute "normal! :\<Esc>"
 	endif
 endfunction

diff --git a/autoload/vital/_over/Over/String.vim b/autoload/vital/_over/Over/String.vim
index b19cff7..2c1094c 100644
--- a/autoload/vital/_over/Over/String.vim
+++ b/autoload/vital/_over/Over/String.vim
@@ -3,17 +3,30 @@ let s:save_cpo = &cpo
 set cpo&vim

+function! s:_vital_loaded(V)
+	let s:V = a:V
+	let s:List = s:V.import("Data.List")
+endfunction
+
+
+function! s:_vital_depends()
+	return [
+\		"Data.List",
+\	]
+endfunction
+
+
 function! s:_clamp(x, max, min)
 	return min([max([a:x, a:max]), a:min])
 endfunction

 let s:base = {}
-
+
 function! s:base.set(item)
 	return type(a:item) == type("") ? self.set_str(a:item)
-\			 : type(a:item) == type(0)  ? self.set_pos(a:item)
-\			 : self
+\		 : type(a:item) == type(0)  ? self.set_pos(a:item)
+\		 : self
 endfunction

 function! s:base.str()
@@ -97,5 +110,158 @@ function! s:make(...)
 endfunction

+
+function! s:_split(str, pat)
+	let pat = (exists("+regexpengine") ? '\%#=2' : '') . a:pat
+	let list = split(a:str,  pat . '\zs')
+	return s:List.flatten(map(list, 'v:val == a:pat ? a:pat : v:val =~ pat . ''$'' ? split(v:val, pat) + [a:pat] : v:val'))
+endfunction
+
+
+function! s:_split_keystring(str, pats, ...)
+	if a:str =~ '^<Over>(.\{-})$'
+\	|| a:str =~ "^\<Plug>(.\\{-})$"
+		return [a:str]
+	endif
+	let pats = a:pats
+	let index = get(a:, 1, 0)
+	if !exists("+regexpengine")
+\	|| index > len(pats)
+\	|| len(filter(copy(pats), 'a:str =~ ''\%#=2'' . v:val')) == 0
+		if len(filter(copy(pats), 'a:str ==# v:val')) == 0
+			return split(a:str, '\zs')
+		else
+			return [a:str]
+		endif
+	endif
+	if len(filter(copy(pats), 'a:str == v:val')) == 1
+		return [a:str]
+	endif
+
+	let result = []
+	let pat = pats[index]
+	let list = s:_split(a:str, pat)
+	let result += eval(join(map(list, "s:_split_keystring(v:val, pats, index+1)"), "+"))
+	return result
+endfunction
+
+
+let s:special_keys = [
+\	"\<BS>",
+\	"\<Down>",
+\	"\<Up>",
+\	"\<Left>",
+\	"\<Right>",
+\	"\<Home>",
+\	"\<End>",
+\	"\<Insert>",
+\	"\<Delete>",
+\	"\<PageUp>",
+\	"\<PageDown>",
+\	"\<F1>",
+\	"\<F2>",
+\	"\<F3>",
+\	"\<F4>",
+\	"\<F5>",
+\	"\<F6>",
+\	"\<F7>",
+\	"\<F8>",
+\	"\<F9>",
+\	"\<F10>",
+\	"\<F11>",
+\	"\<F12>",
+\	"\<A-BS>",
+\	"\<A-Down>",
+\	"\<A-Up>",
+\	"\<A-Left>",
+\	"\<A-Right>",
+\	"\<A-Home>",
+\	"\<A-End>",
+\	"\<A-Insert>",
+\	"\<A-Delete>",
+\	"\<A-PageUp>",
+\	"\<A-PageDown>",
+\	"\<A-F1>",
+\	"\<A-F2>",
+\	"\<A-F3>",
+\	"\<A-F4>",
+\	"\<A-F5>",
+\	"\<A-F6>",
+\	"\<A-F7>",
+\	"\<A-F8>",
+\	"\<A-F9>",
+\	"\<A-F10>",
+\	"\<A-F11>",
+\	"\<A-F12>",
+\	"\<A-Tab>",
+\	"\<C-BS>",
+\	"\<C-Down>",
+\	"\<C-Up>",
+\	"\<C-Left>",
+\	"\<C-Right>",
+\	"\<C-Home>",
+\	"\<C-End>",
+\	"\<C-Insert>",
+\	"\<C-Delete>",
+\	"\<C-PageUp>",
+\	"\<C-PageDown>",
+\	"\<C-Tab>",
+\	"\<C-F1>",
+\	"\<C-F2>",
+\	"\<C-F3>",
+\	"\<C-F4>",
+\	"\<C-F5>",
+\	"\<C-F6>",
+\	"\<C-F7>",
+\	"\<C-F8>",
+\	"\<C-F9>",
+\	"\<C-F10>",
+\	"\<C-F11>",
+\	"\<C-F12>",
+\	"\<S-Down>",
+\	"\<S-Up>",
+\	"\<S-Left>",
+\	"\<S-Right>",
+\	"\<S-Home>",
+\	"\<S-Insert>",
+\	"\<S-PageUp>",
+\	"\<S-PageDown>",
+\	"\<S-F1>",
+\	"\<S-F2>",
+\	"\<S-F3>",
+\	"\<S-F4>",
+\	"\<S-F5>",
+\	"\<S-F6>",
+\	"\<S-F7>",
+\	"\<S-F8>",
+\	"\<S-F9>",
+\	"\<S-F10>",
+\	"\<S-F11>",
+\	"\<S-F12>",
+\	"\<S-Tab>",
+\]
+" Issues #45
+" \	"\<S-End>",
+" \	"\<S-Delete>",
+
+
+" Workaround
+" https://github.com/osyo-manga/vital-over/pull/63
+" http://lingr.com/room/vim/archives/2014/10/29#message-20492403
+if exists("+regexpengine")
+	function! s:_split_keystring(str, ...)
+		return split(a:str, '\%#=2' . "\\m\\%(" . get(a:, 1, '') . "\x80\xfc.\\%(\x80..\\|.\\)\\zs\\|\x80..\\zs\\|.\\zs\\)")
+	endfunction
+
+	function! s:split_by_keys(str)
+		return s:_split_keystring(a:str, "\\%(\<Plug>\\|<Over>\\)(.\\{-})\\zs\\|")
+	endfunction
+else
+	function! s:split_by_keys(str)
+		return s:_split_keystring(a:str, s:special_keys)
+	endfunction
+endif
+
+
 let &cpo = s:save_cpo
 unlet s:save_cpo
diff --git a/autoload/vital/over.vital b/autoload/vital/over.vital
index 0aeccd1..7012ca6 100644
--- a/autoload/vital/over.vital
+++ b/autoload/vital/over.vital
@@ -1,5 +1,5 @@
 over
-1f70614
+4724200

 Over
 Over.Commandline
Fix modified buffer.
On branch master
このブランチは 'origin/master' よりも1コミット進んでいます。
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   over/command_line/substitute.vim

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	../test/autoload/over/
	../test/plugin/
	../test_over/

diff --git a/autoload/over/command_line/substitute.vim b/autoload/over/command_line/substitute.vim
index 317ab57..7bb34a9 100644
--- a/autoload/over/command_line/substitute.vim
+++ b/autoload/over/command_line/substitute.vim
@@ -115,6 +115,10 @@ endfunction

 function! s:substitute_preview(line)
+	if &modifiable == 0
+		return
+	endif
+
 	if over#command_line#is_input("\<CR>")
 		return
 	endif