Class: KeyBindingTree

Inherits:
Object
  • Object
show all
Defined in:
lib/vimamsa/key_binding_tree.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeKeyBindingTree



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/vimamsa/key_binding_tree.rb', line 46

def initialize()
  @next_command_count = nil
  @modes = {}
  @root = State.new("ROOT")
  @cur_state = @root # used for building the tree
  @default_mode = nil
  @default_mode_stack = []
  @mode_history = []
  @state_trail = []
  @last_action = nil
  @cur_action = nil
  @method_handles_repeat = false

  @modifiers = { :ctrl => false, :shift => false, :alt => false } # TODO: create a queue
  @last_event = [nil, nil, nil, nil, nil]

  @override_keyhandling_callback = nil
  # Allows h["foo"]["faa"]=1
  @act_bindings = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
end

Instance Attribute Details

#act_bindingsObject (readonly)

Returns the value of attribute act_bindings.



44
45
46
# File 'lib/vimamsa/key_binding_tree.rb', line 44

def act_bindings
  @act_bindings
end

#CObject

Returns the value of attribute C.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def C
  @C
end

#cur_actionObject

Returns the value of attribute cur_action.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def cur_action
  @cur_action
end

#cur_stateObject

Returns the value of attribute cur_state.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def cur_state
  @cur_state
end

#default_modeObject

Returns the value of attribute default_mode.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def default_mode
  @default_mode
end

#default_mode_stackObject (readonly)

Returns the value of attribute default_mode_stack.



44
45
46
# File 'lib/vimamsa/key_binding_tree.rb', line 44

def default_mode_stack
  @default_mode_stack
end

#IObject

Returns the value of attribute I.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def I
  @I
end

#last_actionObject

Returns the value of attribute last_action.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def last_action
  @last_action
end

#match_stateObject

Returns the value of attribute match_state.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def match_state
  @match_state
end

#method_handles_repeatObject

Returns the value of attribute method_handles_repeat.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def method_handles_repeat
  @method_handles_repeat
end

#mode_root_stateObject (readonly)

Returns the value of attribute mode_root_state.



44
45
46
# File 'lib/vimamsa/key_binding_tree.rb', line 44

def mode_root_state
  @mode_root_state
end

#modifiersObject

Returns the value of attribute modifiers.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def modifiers
  @modifiers
end

#next_command_countObject

Returns the value of attribute next_command_count.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def next_command_count
  @next_command_count
end

#rootObject

Returns the value of attribute root.



43
44
45
# File 'lib/vimamsa/key_binding_tree.rb', line 43

def root
  @root
end

#state_trailObject (readonly)

Returns the value of attribute state_trail.



44
45
46
# File 'lib/vimamsa/key_binding_tree.rb', line 44

def state_trail
  @state_trail
end

Instance Method Details

#__set_mode(label) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/vimamsa/key_binding_tree.rb', line 208

def __set_mode(label)
  debug "__set_mode(#{label})"
  @mode_history << @mode_root_state

  # Check if label in form :label
  if @modes.has_key?(label)
    @mode_root_state = @modes[label]
    set_state_to_root
  else
    # Check if label matches mode name in string format
    for mode in @root.children
      if mode.key_name == label
        @mode_root_state = mode
      end
    end
  end
  @cur_mode = label

  if self.get_scope != :editor and !vma.buf.nil?
    vma.buf.mode_stack = @default_mode_stack.clone
  end

  if !vma.gui.view.nil?
    vma.gui.view.draw_cursor()  #TODO: handle outside this class
  end
end

#_bindkey(key, action, keywords: []) ⇒ Object



540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/vimamsa/key_binding_tree.rb', line 540

def _bindkey(key, action, keywords: [])
  key.strip!
  key.gsub!(/\s+/, " ")

  # if key.class == Array
  # key.each { |k| bindkey(k, action) }
  # return
  # end
  # $action_list << { :action => action, :key => key }
  if !vma.actions.include?(action)
    if action.class == String
      reg_act(action, proc { eval(action) }, action)
    end
  end

  m = key.match(/^(\S+)\s(\S.*)$/)
  # Match/split e.g. "VC , , s" to "VC" and ", , s"
  if m
    modetmp = m[1]
    debug [key, modetmp, m].inspect

    # If all of first word are uppercase, e.g. in
    # "VCIX left" => "buf.move(BACKWARD_CHAR)",
    # interpret as each char representing a mode
    modes = modetmp.split("") if modetmp.match(/^\p{Lu}+$/) # Uppercase

    # If all of first word is down case, like in:
    # bindkey "audio space", :audio_stop
    # interpret as whole word representing a mode.
    modes = [modetmp] if modetmp.match(/^\p{Ll}+$/) # Lowercase
    keydef = m[2]
  else
    fatal_error("Error in keydef #{key.inspect}")
  end

  # puts "keywords #{keywords}"
  modes.each { |mode_id|
    mode_bind_key(mode_id, keydef, action, keywords: keywords)

    # Map froma actions to keybindings (e.g. to show bindings in menu)
    @act_bindings[mode_id][action] = keydef
  }
end

#add_minor_mode(id, label, major_mode_label) ⇒ Object

Add keyboard key binding mode based on another mode



133
134
135
136
137
138
139
140
141
# File 'lib/vimamsa/key_binding_tree.rb', line 133

def add_minor_mode(id, label, major_mode_label)
  mode = State.new(id)
  @modes[label] = mode
  if @root.nil?
    show_caller
  end
  @root.children << mode
  mode.major_modes << major_mode_label
end

#add_mode(id, label, cursortype = :command, name: nil, scope: :buffer) ⇒ Object



122
123
124
125
126
127
128
129
130
# File 'lib/vimamsa/key_binding_tree.rb', line 122

def add_mode(id, label, cursortype = :command, name: nil, scope: :buffer)
  mode = State.new(id, "", cursortype, scope: scope)
  mode.level = 1
  @modes[label] = mode
  @root.children << mode
  if @default_mode == nil
    set_default_mode(label)
  end
end

#bindkey(key, action, keywords: "") ⇒ Object



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/vimamsa/key_binding_tree.rb', line 517

def bindkey(key, action, keywords: "")
  # puts "keywords #{keywords}" if !keywords.empty?
  if keywords.class == String
    keywords = keywords.split(" ")
  end
  # puts "keywords #{keywords}" if !keywords.empty?
  if key.class != Array
    # Handle syntax like :
    # "X esc || X ctrl!" => "vma.kbd.to_previous_mode",
    key = key.split("||")
  end

  a = action
  if action.class == Array
    label = a[0]
    a = label
    proc = action[1]
    msg = action[2]
    reg_act(label, proc, msg)
  end
  key.each { |k| _bindkey(k, a, keywords: keywords) }
end

#clear_modifiersObject



143
144
145
# File 'lib/vimamsa/key_binding_tree.rb', line 143

def clear_modifiers()
  # @modifiers = [] #TODO:remove?
end

#cur_mode_strObject



239
240
241
# File 'lib/vimamsa/key_binding_tree.rb', line 239

def cur_mode_str()
  return @mode_root_state.key_name
end

#dump_stateObject



96
97
98
99
100
101
102
103
104
# File 'lib/vimamsa/key_binding_tree.rb', line 96

def dump_state
  debug "dump_state", 2
  pp ["@default_mode_stack", @default_mode_stack]
  pp ["@default_mode", @default_mode]
  pp ["vma.buf.mode_stack", vma.buf.mode_stack]
  pp ["scope", self.get_scope]
  # pp ["@mode_root_state", @mode_root_state]
  # pp ["@match_state", @match_state]
end

#find_state(key_name, eval_rule) ⇒ Object



147
148
149
150
151
152
153
154
155
# File 'lib/vimamsa/key_binding_tree.rb', line 147

def find_state(key_name, eval_rule)
  @cur_state.children.each { |s|
    if s.key_name == key_name and s.eval_rule == eval_rule
      # TODO check eval
      return s
    end
  }
  return nil
end

#get_by_keywords(modes: [], keywords: []) ⇒ Object



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/vimamsa/key_binding_tree.rb', line 272

def get_by_keywords(modes: [], keywords: [])
  s = ""
  stack = [[@root, ""]]
  lines = []

  # Traverse the tree (class State objects) using a stack
  while stack.any?
    t, p = *stack.pop # t = current state, p = current path
    if t.children.any?
      t.children.reverse.each { |c|

        # Restrict by modes if specified
        if c.level == 1 and !modes.empty?
          next if !modes.include?(c.key_name)
        end

        if c.eval_rule.size > 0
          new_p = "#{p} #{c.key_name}(#{c.eval_rule})"
        else
          if c.level == 1
            new_p = "#{p} [#{c.key_name}]"
          else
            new_p = "#{p} #{c.key_name}"
          end
        end
        stack << [c, new_p]
      }
      # stack.concat[t.children]

    else
      method_desc = t.action
      if t.action.class == Symbol
        if vma.actions.include?(t.action)
          a = vma.actions[t.action].method_name
          if !a.nil? and !a.empty?
            method_desc = a
          end
        end
      end

      if (keywords - t.keywords).empty? # All keywords are present
        kw = ""
        # kw = ", [#{t.keywords.join(",")}]" if !t.keywords.empty?
        lines << p + " : #{method_desc}#{kw}"
      end
    end
  end
  s = lines.sort.join("\n")
  return s
end

#get_cursor_typeObject



243
244
245
# File 'lib/vimamsa/key_binding_tree.rb', line 243

def get_cursor_type
  @mode_root_state.cursor_type
end

#get_modeObject



247
248
249
# File 'lib/vimamsa/key_binding_tree.rb', line 247

def get_mode
  return @cur_mode
end

#get_scopeObject



235
236
237
# File 'lib/vimamsa/key_binding_tree.rb', line 235

def get_scope
  @mode_root_state.scope
end

#get_state_trail_strObject



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/vimamsa/key_binding_tree.rb', line 368

def get_state_trail_str
  s_trail = ""
  last_state = @state_trail.last
  last_state = last_state[0] if last_state.class == Array
  first = true
  for st in @state_trail
    st = st[0] if st.class == Array
    if first
      trailpfx = ""
      if !st.major_modes.empty?
        mmid = st.major_modes.first
        trailpfx = "#{@modes[mmid].to_s}>"
      end
      s_trail << "[#{trailpfx}#{st.to_s}]"
    else
      s_trail << " #{st.to_s}"
    end
    first = false
  end
  children = ""
  for cstate in last_state.children
    act_s = "..."
    act_s = cstate.action.to_s if cstate.action != nil
    children << "  #{cstate.to_s} #{act_s}\n"
  end
  if !@next_command_count.nil?
    s_trail << " #{@next_command_count}"
  end
  return [s_trail, children]
end

#handle_key_bindigs_action(action, c) ⇒ Object



641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
# File 'lib/vimamsa/key_binding_tree.rb', line 641

def handle_key_bindigs_action(action, c)
  # $acth << action #TODO:needed here?
  @method_handles_repeat = false #TODO:??
  n = 1
  if @next_command_count and !(action.class == String and action.include?("set_next_command_count"))
    n = @next_command_count
    debug("COUNT command #{n} times")
  end

  begin
    n.times do
      ret = exec_action(action)

      if vma.macro.is_recording and ret != false
        debug "RECORD ACTION:#{action}", 2
        vma.macro.record_action(action)
      end
      break if @method_handles_repeat
      # Some methods have specific implementation for repeat,
      #   like '5yy' => copy next five lines. (copy_line())
      # By default the same command is just repeated n times
      #   like '20j' => go to next line 20 times.
      # But methods can also handle the number input themselves if vma.kbd.method_handles_repeat=true is set,
    end
    # run_as_idle proc { vma.buf.refresh_cursor; vma.buf.refresh_cursor }, delay: 0.05
  rescue SyntaxError
    message("SYNTAX ERROR with eval cmd #{action}: " + $!.to_s)
    # rescue NoMethodError
    # debug("NoMethodError with eval cmd #{action}: " + $!.to_s)
    # rescue NameError
    # debug("NameError with eval cmd #{action}: " + $!.to_s)
    # raise
  rescue Exception => e
    puts "BACKTRACE"
    puts e.backtrace
    puts e.inspect
    puts "BACKTRACE END"
    if $!.class == SystemExit
      exit
    else
      crash("Error with action: #{action}: ", e)
    end
  end

  if !(action.class == String and action.include?("set_next_command_count"))
    @next_command_count = nil
  end
end

#match(key_name) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/vimamsa/key_binding_tree.rb', line 165

def match(key_name)
  new_state = []
  debug = false
  @match_state.each { |parent|
    parent.children.each { |c|
      # printf(" KEY MATCH: ")
      # debug [c.key_name, key_name].inspect
      if c.key_name == key_name and c.eval_rule == ""
        new_state << c
      elsif c.key_name == key_name and c.eval_rule != ""
        debug "CHECK EVAL: #{c.eval_rule}"
        if eval(c.eval_rule)
          # if eval_rule.match(/macro/)
          debug = true
          # end
          new_state << c
          debug "EVAL TRUE"
        else
          debug "EVAL FALSE"
        end
      end
    }
  }

  if debug
    # require "pry"; binding.pry
  end

  if new_state.any? # Match found
    @match_state = new_state
    return new_state
    # return true
  else # No match found
    # @match_state = [@C] #TODO
    return nil
  end
end

#match_key_conf(c, translated_c, event_type) ⇒ Object

Modifies state of key binding tree (move to new state) based on received event Checks child nodes of current state if they match received event if yes, change state to child if no, go back to root



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
# File 'lib/vimamsa/key_binding_tree.rb', line 412

def match_key_conf(c, translated_c, event_type)
  debug "MATCH KEY CONF: #{[c, translated_c]}"

  if !@override_keyhandling_callback.nil?
    ret = @override_keyhandling_callback.call(c, event_type)
    return if ret
  end

  eval_s = nil

  new_state = match(c)
  # #TODO:
  # new_state = match(translated_c)
  # if new_state == nil and translated_c.index("shift") == 0
  # new_state = match(c)
  # end

  if new_state == nil
    s1 = match_state[0].children.select { |s| s.key_name.include?("<char>") } # TODO: [0]
    if s1.any? and (c.size == 1) and event_type == :key_press
      eval_s = s1.first.action.clone
      # eval_s.gsub!("<char>","'#{c}'") #TODO: remove
      new_state = [s1.first]
    end
  end

  if new_state == nil
    # Child is regexp like /[1-9]/ in:
    # 'C /[1-9]/'=> 'set_next_command_count(<char>)',
    # Execute child regexps one until matches
    s1 = match_state[0].children.select { |s|
      s.key_name =~ /^\/.*\/$/
    } # TODO: [0]

    if s1.any? and c.size == 1
      s1.each { |x|
        m = /^\/(.*)\/$/.match(x.key_name)
        if m != nil
          m2 = Regexp.new(m[1]).match(c)
          if m2 != nil
            eval_s = x.action.clone
            new_state = [x]
            break
          end

          return true
        end
      }
      # eval_s = s1.first.action.clone
      # eval_s.gsub!("<char>","'#{c}'")
      # new_state = [s1.first]
    end
  end

  if new_state != nil
    @state_trail << new_state
  end

  if new_state == nil
    debug("NO MATCH")
    if event_type == :key_press and c != "shift"
      # TODO:include other modifiers in addition to shift?
      set_state_to_root
      printf(", BACK TO ROOT") if cnf.debug?
    end

    if event_type == :key_release and c == "shift!"
      # Pressing a modifier key (shift) sets state back to root
      # only on key release when no other key has been pressed
      # after said modifier key (shift).
      set_state_to_root
      printf(", BACK TO ROOT") if cnf.debug?
    end

    printf("\n") if cnf.debug?
  else

    # Don't execute action if one of the states has children
    # TODO: why?
    state_with_children = new_state.select { |s| s.children.any? }
    s_act = new_state.select { |s| s.action != nil }

    if s_act.any? #and !state_with_children.any?
      eval_s = s_act.first.action if eval_s == nil
      # if eval_s.to_s.match(/end_recording/)
      # require "pry"; binding.pry
      # end
      debug "FOUND MATCH:#{eval_s}"
      debug "CHAR: #{c}"
      c.gsub!("\\", %q{\\\\} * 4) # Escape \ -chars
      c.gsub!("'", "#{'\\' * 4}'") # Escape ' -chars

      eval_s.gsub!("<char>", "'#{c}'") if eval_s.class == String
      debug eval_s
      debug c
      handle_key_bindigs_action(eval_s, c)
      set_state_to_root
    end
  end

  show_state_trail #TODO: check if changed

  return true
end

#mode_bind_key(mode_id, keydef, action, keywords: []) ⇒ Object

Binds a keyboard key combination to an action, for a given keyboard mode like insert (“I”) or command (“C”)



586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
# File 'lib/vimamsa/key_binding_tree.rb', line 586

def mode_bind_key(mode_id, keydef, action, keywords: [])
  # debug "mode_bind_key #{mode_id.inspect}, #{keydef.inspect}, #{action.inspect}", 2
  # Example:
  # bindkey "C , f", :gui_file_finder
  # mode_id = "C", keydef = ", f"
  # and action = :gui_file_finder

  set_state(mode_id, "") # TODO: check is ok?
  start_state = @cur_state

  k_arr = keydef.split #e.g. definition: "C y e" = > ["C", "y", "e"]

  prev_state = nil
  s1 = start_state

  k_arr.each_with_index { |k, idx|
    # check if key has rules for context like q has in
    # "C q(cntx.recording_macro==true)"
    last_item = false
    if k_arr.size - 1 == idx
      last_item = true
    end
    match = /(.+)\((.*)\)/.match(k)
    eval_rule = ""
    if match
      key_name = match[1]
      eval_rule = match[2]
    else
      key_name = k
    end

    prev_state = s1
    # Create a new state for key if it doesn't exist
    s1 = find_state(key_name, eval_rule)
    if s1 == nil or last_item
      new_state = State.new(key_name, eval_rule)
      if last_item
        # Override existing key definition
        @cur_state.children.delete(s1)
      end
      s1 = new_state
      @cur_state.children << new_state
    end

    set_state(key_name, eval_rule) # TODO: check is ok?
  }
  if action == :delete_state
    prev_state.children.delete(cur_state)
  else
    @cur_state.action = action
  end
  @cur_state.keywords = keywords
  @cur_state = @root
end

#remove_keyhandling_overrideObject



161
162
163
# File 'lib/vimamsa/key_binding_tree.rb', line 161

def remove_keyhandling_override()
  @override_keyhandling_callback = nil
end

#set_default_mode(label) ⇒ Object



80
81
82
83
84
85
# File 'lib/vimamsa/key_binding_tree.rb', line 80

def set_default_mode(label)
  @match_state = [@modes[label]]
  @mode_root_state = @modes[label]
  @default_mode = label
  set_mode_stack [label]
end

#set_keyhandling_override(_callback) ⇒ Object



157
158
159
# File 'lib/vimamsa/key_binding_tree.rb', line 157

def set_keyhandling_override(_callback)
  @override_keyhandling_callback = _callback
end

#set_mode(label) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/vimamsa/key_binding_tree.rb', line 67

def set_mode(label)
  return if get_mode == :label
  @match_state = [@modes[label]] # used for matching input
  @mode_root_state = @modes[label]
  # @default_mode = label
  @default_mode_stack << label

  __set_mode(label)
  if !vma.buf.nil?
    # vma.buf.mode_stack = @default_mode_stack.clone
  end
end

#set_mode_stack(ms) ⇒ Object



87
88
89
90
91
92
93
94
# File 'lib/vimamsa/key_binding_tree.rb', line 87

def set_mode_stack(ms)
  debug "set_mode_stack(#{ms})", 2
  show_caller if cnf.debug? # TODO: remove
  @default_mode_stack = ms
  label = @default_mode_stack[-1]
  @match_state = [@modes[label]]
  @mode_root_state = @modes[label]
end

#set_mode_to_defaultObject



106
107
108
109
110
# File 'lib/vimamsa/key_binding_tree.rb', line 106

def set_mode_to_default()
  # set_mode(@default_mode)
  set_mode_stack [@default_mode_stack[0]]
  __set_mode(@default_mode_stack[0])
end

#set_next_command_count(num) ⇒ Object



399
400
401
402
403
404
405
406
# File 'lib/vimamsa/key_binding_tree.rb', line 399

def set_next_command_count(num)
  if @next_command_count != nil
    @next_command_count = @next_command_count * 10 + num.to_i
  else
    @next_command_count = num.to_i
  end
  debug("NEXT COMMAND COUNT: #{@next_command_count}")
end

#set_state(key_name, eval_rule = "") ⇒ Object



251
252
253
254
255
256
257
258
# File 'lib/vimamsa/key_binding_tree.rb', line 251

def set_state(key_name, eval_rule = "")
  new_state = find_state(key_name, eval_rule)
  if new_state != nil
    @cur_state = new_state
  else
    @cur_state = @mode_root_state # TODO
  end
end

#set_state_to_rootObject



260
261
262
263
264
265
266
267
268
269
270
# File 'lib/vimamsa/key_binding_tree.rb', line 260

def set_state_to_root
  if @mode_root_state.major_modes.size == 1
    modelabel = @mode_root_state.major_modes[0]
    mmode = @modes[modelabel]
    @match_state = [@mode_root_state, mmode]
  else
    @match_state = [@mode_root_state]
  end

  @state_trail = [@mode_root_state]
end

#show_state_trailObject



203
204
205
206
# File 'lib/vimamsa/key_binding_tree.rb', line 203

def show_state_trail
  (st, children) = get_state_trail_str()
  vma.gui.statnfo.markup = "<span weight='ultrabold'>#{st}</span>"
end

#to_previous_modeObject



112
113
114
115
116
117
118
119
120
# File 'lib/vimamsa/key_binding_tree.rb', line 112

def to_previous_mode()
  debug "to_previous_mode", 2
  debug @default_mode_stack
  if @default_mode_stack.size > 1
    @default_mode_stack.pop
  end
  debug @default_mode_stack
  __set_mode(@default_mode_stack[-1])
end

#to_sObject

Print key bindings to show as documentation or for debugging



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/vimamsa/key_binding_tree.rb', line 324

def to_s()
  return self.class.to_s
  s = ""
  # @cur_state = @root
  stack = [[@root, ""]]
  lines = []

  # Traverse the tree (class State objects) using a stack
  while stack.any?
    t, p = *stack.pop # t = current state, p = current path
    if t.children.any?
      t.children.reverse.each { |c|
        if c.eval_rule.size > 0
          new_p = "#{p} #{c.key_name}(#{c.eval_rule})"
        else
          if c.level == 1
            new_p = "#{p} [#{c.key_name}]"
          else
            new_p = "#{p} #{c.key_name}"
          end
        end
        stack << [c, new_p]
      }
      # stack.concat[t.children]
    else
      method_desc = t.action
      if t.action.class == Symbol
        if vma.actions.include?(t.action)
          a = vma.actions[t.action].method_name
          if !a.nil? and !a.empty?
            method_desc = a
          end
        end
      end

      kw = ""
      # kw = ", " + t.keywords.join(",") if !t.keywords.empty?
      lines << p + " : #{method_desc}#{kw}"
    end
  end
  s = lines.sort.join("\n")
  return s
end