lib/ver/mode.rb in ver-2009.10.14 vs lib/ver/mode.rb in ver-2009.11.28
- old
+ new
@@ -8,10 +8,14 @@
end
}
attr_accessor :callback, :name, :arguments
+ def inspect
+ "#<Mode #@name>"
+ end
+
def initialize(name, callback)
@name, @callback = name, callback
@stack = []
@map = {}
@ancestors = []
@@ -26,11 +30,15 @@
@ancestors.unshift ancestor
end
end
def find_ancestor(name)
- callback.modes[name.to_sym]
+ if found = callback.modes[name.to_sym]
+ return found
+ else
+ raise "Mode #{name} is not specified yet"
+ end
end
def ancestors(*done, &block)
yield self
@@ -55,16 +63,20 @@
def bind(keychain, action_name = nil, &block)
keychain = keychain.dup
total = hash = {}
while key = keychain.shift
- register key
+ if key.is_a?(Symbol)
+ canonical = callback.modes[key]
+ else
+ canonical = register(key)
+ end
if keychain.empty?
- hash[key] = block || action_name
+ hash[canonical] = block || action_name
else
- hash = hash[key] = {}
+ hash = hash[canonical] = {}
end
end
@map.replace @map.merge(total, &MERGER)
end
@@ -79,11 +91,11 @@
def enter_key(key)
@stack << key
ancestors do |ancestor|
- result = ancestor.attempt_execute(@stack)
+ result = ancestor.attempt_execute(@stack.dup)
case result
when nil # nothing matched yet, but possible in future
return nil
when false # nothing possible
@@ -98,37 +110,66 @@
# no ancestors or all failed
@stack.clear
enter_missing(key)
rescue => ex
- puts ex, *ex.backtrace
+ VER.error(ex)
@stack.clear
end
def enter_missing(key)
execute(@missing, key) if @missing
end
- def attempt_execute(original_stack)
+ def attempt_execute(original_stack, lookup = false)
if arguments
stack, arg = Mode.split_stack(original_stack)
else
stack, arg = original_stack, nil
end
if stack.empty?
arg ? nil : false
else
- executable = stack.inject(@map){|keys, key| keys.fetch(key) }
+ executable = @map
+ while key = stack.shift
+ previous = executable
+ executable = executable[key]
- execute(executable, *arg)
+ case executable
+ when nil
+ # FIXME: this allows only one mode
+ if found = previous.find{|prev_key, prev_value| prev_key.is_a?(Mode) }
+ mode, action = found
+ looked = mode.attempt_execute([key, *stack], true)
+
+ case looked
+ when false
+ return false
+ when nil
+ return nil
+ else
+ cmd, cmd_arg = looked
+ return nil if cmd.is_a?(Hash)
+ return execute(action, cmd, arg)
+ end
+ else
+ return false
+ end
+ end
+ end
+
+ if lookup
+ return executable, arg
+ else
+ execute(executable, *arg)
+ end
end
- rescue KeyError
- false
end
def execute(executable, *arg)
+ arg = [*arg].compact # doesn't allow nil
case executable
when Hash
return nil
when Symbol
callback.send(executable, *arg)
@@ -139,20 +180,25 @@
else
return false
end
true
+ rescue ArgumentError => ex
+ callback.message("#{executable} : #{ex}")
+ true
end
def self.split_stack(stack)
- return stack, nil if stack[0] == '0'
+ first = stack[0]
+ return stack, nil if first == '0' || first == '<KeyPress-0>'
- pivot = stack.index{|c| c !~ /\d/ }
+ pivot = stack.index{|c| c !~ /^(<KeyPress-\d+>|\d+)$/ }
if pivot == 0
return stack, nil
elsif pivot
- return stack[pivot..-1], stack[0..pivot].join.to_i
+ keys, args = stack[pivot..-1], stack[0..pivot]
+ return keys, args.join.scan(/\d+/).join.to_i
else
return [], stack.join.to_i
end
end
end