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