Update vital-over

This commit is contained in:
haya14busa 2014-02-09 21:21:26 +09:00
parent 19bdc5933c
commit 7acbd9996b
3 changed files with 428 additions and 29 deletions

View File

@ -0,0 +1,283 @@
" Utilities for list.
let s:save_cpo = &cpo
set cpo&vim
function! s:pop(list)
return remove(a:list, -1)
endfunction
function! s:push(list, val)
call add(a:list, a:val)
return a:list
endfunction
function! s:shift(list)
return remove(a:list, 0)
endfunction
function! s:unshift(list, val)
return insert(a:list, a:val)
endfunction
function! s:cons(x, xs)
return [a:x] + a:xs
endfunction
function! s:conj(xs, x)
return a:xs + [a:x]
endfunction
" Removes duplicates from a list.
function! s:uniq(list, ...)
if a:0
echomsg "Vital.Data.List.uniq() with 2 arguments is deprecated! Please use uniq_by() instead, if you still want to use the 2nd argument."
return s:uniq_by(a:list, a:1)
else
return s:uniq_by(a:list, 'v:val')
endif
endfunction
" Removes duplicates from a list.
function! s:uniq_by(list, f)
let list = map(copy(a:list), printf('[v:val, %s]', a:f))
let i = 0
let seen = {}
while i < len(list)
let key = string(list[i][1])
if has_key(seen, key)
call remove(list, i)
else
let seen[key] = 1
let i += 1
endif
endwhile
return map(list, 'v:val[0]')
endfunction
function! s:clear(list)
if !empty(a:list)
unlet! a:list[0 : len(a:list) - 1]
endif
return a:list
endfunction
" Concatenates a list of lists.
" XXX: Should we verify the input?
function! s:concat(list)
let memo = []
for Value in a:list
let memo += Value
endfor
return memo
endfunction
" Take each elements from lists to a new list.
function! s:flatten(list, ...)
let limit = a:0 > 0 ? a:1 : -1
let memo = []
if limit == 0
return a:list
endif
let limit -= 1
for Value in a:list
let memo +=
\ type(Value) == type([]) ?
\ s:flatten(Value, limit) :
\ [Value]
unlet! Value
endfor
return memo
endfunction
" Sorts a list with expression to compare each two values.
" a:a and a:b can be used in {expr}.
function! s:sort(list, expr)
if type(a:expr) == type(function('function'))
return sort(a:list, a:expr)
endif
let s:expr = a:expr
return sort(a:list, 's:_compare')
endfunction
function! s:_compare(a, b)
return eval(s:expr)
endfunction
" Sorts a list using a set of keys generated by mapping the values in the list
" through the given expr.
" v:val is used in {expr}
function! s:sort_by(list, expr)
let pairs = map(a:list, printf('[v:val, %s]', a:expr))
return map(s:sort(pairs,
\ 'a:a[1] ==# a:b[1] ? 0 : a:a[1] ># a:b[1] ? 1 : -1'), 'v:val[0]')
endfunction
" Returns a maximum value in {list} through given {expr}.
" Returns 0 if {list} is empty.
" v:val is used in {expr}
function! s:max_by(list, expr)
if empty(a:list)
return 0
endif
let list = map(copy(a:list), a:expr)
return a:list[index(list, max(list))]
endfunction
" Returns a minimum value in {list} through given {expr}.
" Returns 0 if {list} is empty.
" v:val is used in {expr}
" FIXME: -0x80000000 == 0x80000000
function! s:min_by(list, expr)
return s:max_by(a:list, '-(' . a:expr . ')')
endfunction
" Returns List of character sequence between [a:from, a:to]
" e.g.: s:char_range('a', 'c') returns ['a', 'b', 'c']
function! s:char_range(from, to)
return map(
\ range(char2nr(a:from), char2nr(a:to)),
\ 'nr2char(v:val)'
\)
endfunction
" Returns true if a:list has a:value.
" Returns false otherwise.
function! s:has(list, value)
return index(a:list, a:value) isnot -1
endfunction
" Returns true if a:list[a:index] exists.
" Returns false otherwise.
" NOTE: Returns false when a:index is negative number.
function! s:has_index(list, index)
" Return true when negative index?
" let index = a:index >= 0 ? a:index : len(a:list) + a:index
return 0 <= a:index && a:index < len(a:list)
endfunction
" similar to Haskell's Data.List.span
function! s:span(f, xs)
let border = len(a:xs)
for i in range(len(a:xs))
if !eval(substitute(a:f, 'v:val', string(a:xs[i]), 'g'))
let border = i
break
endif
endfor
return border == 0 ? [[], copy(a:xs)] : [a:xs[: border - 1], a:xs[border :]]
endfunction
" similar to Haskell's Data.List.break
function! s:break(f, xs)
return s:span(printf('!(%s)', a:f), a:xs)
endfunction
" similar to Haskell's Data.List.takeWhile
function! s:take_while(f, xs)
return s:span(a:f, a:xs)[0]
endfunction
" similar to Haskell's Data.List.partition
function! s:partition(f, xs)
return [filter(copy(a:xs), a:f), filter(copy(a:xs), '!(' . a:f . ')')]
endfunction
" similar to Haskell's Prelude.all
function! s:all(f, xs)
return !s:any(printf('!(%s)', a:f), a:xs)
endfunction
" similar to Haskell's Prelude.any
function! s:any(f, xs)
return !empty(filter(map(copy(a:xs), a:f), 'v:val'))
endfunction
" similar to Haskell's Prelude.and
function! s:and(xs)
return s:all('v:val', a:xs)
endfunction
" similar to Haskell's Prelude.or
function! s:or(xs)
return s:any('v:val', a:xs)
endfunction
" similar to Haskell's Prelude.foldl
function! s:foldl(f, init, xs)
let memo = a:init
for x in a:xs
let expr = substitute(a:f, 'v:val', string(x), 'g')
let expr = substitute(expr, 'v:memo', string(memo), 'g')
unlet memo
let memo = eval(expr)
endfor
return memo
endfunction
" similar to Haskell's Prelude.foldl1
function! s:foldl1(f, xs)
if len(a:xs) == 0
throw 'foldl1'
endif
return s:foldl(a:f, a:xs[0], a:xs[1:])
endfunction
" similar to Haskell's Prelude.foldr
function! s:foldr(f, init, xs)
return s:foldl(a:f, a:init, reverse(copy(a:xs)))
endfunction
" similar to Haskell's Prelude.fold11
function! s:foldr1(f, xs)
if len(a:xs) == 0
throw 'foldr1'
endif
return s:foldr(a:f, a:xs[-1], a:xs[0:-2])
endfunction
" similar to python's zip()
function! s:zip(...)
return map(range(min(map(copy(a:000), 'len(v:val)'))), "map(copy(a:000), 'v:val['.v:val.']')")
endfunction
" similar to zip(), but goes until the longer one.
function! s:zip_fill(xs, ys, filler)
if empty(a:xs) && empty(a:ys)
return []
elseif empty(a:ys)
return s:cons([a:xs[0], a:filler], s:zip_fill(a:xs[1 :], [], a:filler))
elseif empty(a:xs)
return s:cons([a:filler, a:ys[0]], s:zip_fill([], a:ys[1 :], a:filler))
else
return s:cons([a:xs[0], a:ys[0]], s:zip_fill(a:xs[1 :], a:ys[1: ], a:filler))
endif
endfunction
" Inspired by Ruby's with_index method.
function! s:with_index(list, ...)
let base = a:0 > 0 ? a:1 : 0
return s:zip(a:list, range(base, len(a:list)+base-1))
endfunction
" similar to Ruby's detect or Haskell's find.
" TODO spec and doc
function! s:find(list, default, f)
for x in a:list
if eval(substitute(a:f, 'v:val', string(x), 'g'))
return x
endif
endfor
return a:default
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)
return !empty(filter(copy(a:list1), 'index(a:list2, v:val) isnot -1'))
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:set et ts=2 sts=2 sw=2 tw=0:

View File

@ -21,13 +21,20 @@ function! s:_vital_loaded(V)
for module in s:modules
let s:{module} = s:V.import('Over.Commandline.Modules.' . module)
endfor
let s:String = s:V.import("Over.String")
let s:String = s:V.import("Over.String")
let s:Signals = s:V.import("Over.Signals")
let s:base.variables.modules = s:Signals.make()
function! s:base.variables.modules.get_slot(val)
return a:val.slot.module
endfunction
endfunction
function! s:_vital_depends()
return ["Over.String"]
\ + map(copy(s:modules), "'Over.Commandline.Modules.' . v:val")
return [
\ "Over.String",
\ "Over.Signals",
\ ] + map(copy(s:modules), "'Over.Commandline.Modules.' . v:val")
endfunction
@ -45,6 +52,7 @@ function! s:make_plain(prompt)
let result.prompt = a:prompt
call result.connect("Enter")
call result.connect("Cancel")
call result.connect(result, "_")
return result
endfunction
@ -75,7 +83,6 @@ let s:base = {
\ "tap_key" : "",
\ "exit" : 0,
\ "keymapping" : {},
\ "modules" : {},
\ },
\ "highlights" : {
\ "prompt" : "NONE",
@ -166,28 +173,30 @@ function! s:base.connect(module, ...)
if type(a:module) == type("")
return call(self.connect, [s:get_module(a:module).make()] + a:000, self)
endif
let name = get(a:, 1, a:module.name)
let self.variables.modules[name] = a:module
let name = a:0 > 0 ? a:1 : a:module.name
let slot = self.variables.modules.find_first_by("get(v:val.slot, 'name', '') == " . string(name))
if empty(slot)
call self.variables.modules.connect({ "name" : name, "module" : a:module })
else
let slot.slot.module = a:module
endif
" let self.variables.modules[name] = a:module
endfunction
function! s:base.disconnect(name)
unlet self.variables.modules[a:name]
return self.variables.modules.disconnect_by(
\ "get(v:val.slot, 'name', '') == " . string(a:name)
\ )
" unlet self.variables.modules[a:name]
endfunction
for s:_ in ["enter", "leave", "char", "char_pre", "execute_pre", "execute_failed", "execute", "cancel"]
execute join([
\ "function! s:base._on_" . s:_ . "()",
\ " call map(copy(self.variables.modules), 'has_key(v:val, \"on_" . s:_ . "\") ? v:val.on_" . s:_ . "(self) : 0')",
\ " call self.on_" . s:_ . "()",
\ "endfunction",
\ ], "\n")
execute "function! s:base.on_" . s:_ . "()"
endfunction
endfor
unlet s:_
function! s:base.callevent(event)
call self.variables.modules.sort_by("has_key(v:val.slot.module, 'priority') ? v:val.slot.module.priority('" . a:event . "') : 0")
return self.variables.modules.call(a:event, [self])
" call map(filter(copy(self.variables.modules), "has_key(v:val, a:event)"), "v:val." . a:event . "(self)")
endfunction
function! s:base.cmap(lhs, rhs)
@ -310,16 +319,16 @@ endfunction
function! s:base._execute()
call s:redraw()
call self._on_execute_pre()
call self.callevent("on_execute_pre")
try
call self.execute()
catch
echohl ErrorMsg
echo matchstr(v:exception, 'Vim\((\w*)\)\?:\zs.*\ze')
echohl None
call self._on_execute_failed()
call self.callevent("on_execute_failed")
finally
call self._on_execute()
call self.callevent("on_execute")
endtry
endfunction
@ -328,7 +337,7 @@ function! s:base._main(...)
try
call self._init()
let self.line = deepcopy(s:String.make(get(a:, 1, "")))
call self._on_enter()
call self.callevent("on_enter")
while !self._is_exit()
call s:_echo_cmdline(self)
@ -339,18 +348,18 @@ function! s:base._main(...)
call self.setchar(self.variables.char)
call self._on_char_pre()
call self.callevent("on_char_pre")
call self.insert(self.variables.input)
call self._on_char()
call self.callevent("on_char")
endwhile
catch
echohl ErrorMsg | echo v:throwpoint . " " . v:exception | echohl None
return -1
finally
call self._finish()
call self._on_leave()
call s:redraw()
call self.callevent("on_leave")
endtry
call s:redraw()
return self.exit_code()
endfunction
@ -410,9 +419,12 @@ endfunction
function! s:base._get_keymapping()
let result = {}
for module in values(self.variables.modules)
" for module in values(self.variables.modules)
for module in self.variables.modules.slots()
if has_key(module, "keymapping")
call extend(result, module.keymapping(self))
if module isnot self
call extend(result, module.keymapping(self))
endif
endif
endfor
return extend(extend(result, self.variables.keymapping), self.keymapping())

View File

@ -0,0 +1,104 @@
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! s:_vital_loaded(V)
let s:V = a:V
let s:L = s:V.import("Data.List")
endfunction
function! s:_vital_depends()
return ["Data.List"]
endfunction
let s:base = {
\ "variables" : {
\ "slots" : [],
\ "counter" : 0,
\ }
\}
function! s:base.connect(slot)
let self.variables.counter += 1
let slot = { "id" : self.variables.counter, "slot" : a:slot }
call add(self.variables.slots, slot)
return slot
endfunction
function! s:base.disconnect(slot)
if empty(a:slot)
return -1
endif
for i in range(len(self.variables.slots))
if self.variables.slots[i].id == a:slot.id
unlet self.variables.slots[i]
return
endif
endfor
return -1
endfunction
function! s:base.disconnect_by(expr)
return self.disconnect(self.find_first_by(a:expr))
endfunction
function! s:call(list, func, ...)
let args = get(a:, 1, [])
let def = get(a:, 2, 0)
return map(copy(a:list), "has_key(v:val, a:func) ? call(v:val.".a:func.", args, v:val) : def")
endfunction
function! s:base.call(func, ...)
return call("s:call", [self.slots(), a:func] + a:000)
endfunction
function! s:base.find_by(expr)
return filter(copy(self.variables.slots), a:expr)
endfunction
function! s:base.find_first_by(expr)
return get(self.find_by(a:expr), 0, {})
endfunction
function! s:base.sort_by(expr)
let self.variables.slots = s:L.sort_by(self.variables.slots, a:expr)
endfunction
function! s:base.get_slot(val)
return a:val.slot
endfunction
function! s:base.slots()
return map(copy(self.variables.slots), "self.get_slot(v:val)")
endfunction
" function! s:base.dict()
" let result = {}
" for _ in self.variables.slots
" let result[_.id] = _.value
" endfor
" return result
" endfunction
function! s:make()
let result = deepcopy(s:base)
return result
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo