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

Returns a new instance of KeyBindingTree.



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

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
  @overwriting_state = nil # A branch which has priority over other branches

  @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.



46
47
48
# File 'lib/vimamsa/key_binding_tree.rb', line 46

def act_bindings
  @act_bindings
end

#CObject

Returns the value of attribute C.



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

def C
  @C
end

#cur_actionObject

Returns the value of attribute cur_action.



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

def cur_action
  @cur_action
end

#cur_stateObject

Returns the value of attribute cur_state.



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

def cur_state
  @cur_state
end

#default_modeObject

Returns the value of attribute default_mode.



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

def default_mode
  @default_mode
end

#default_mode_stackObject (readonly)

Returns the value of attribute default_mode_stack.



46
47
48
# File 'lib/vimamsa/key_binding_tree.rb', line 46

def default_mode_stack
  @default_mode_stack
end

#IObject

Returns the value of attribute I.



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

def I
  @I
end

#last_actionObject

Returns the value of attribute last_action.



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

def last_action
  @last_action
end

#match_stateObject

Returns the value of attribute match_state.



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

def match_state
  @match_state
end

#method_handles_repeatObject

Returns the value of attribute method_handles_repeat.



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

def method_handles_repeat
  @method_handles_repeat
end

#mode_root_stateObject (readonly)

Returns the value of attribute mode_root_state.



46
47
48
# File 'lib/vimamsa/key_binding_tree.rb', line 46

def mode_root_state
  @mode_root_state
end

#modifiersObject

Returns the value of attribute modifiers.



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

def modifiers
  @modifiers
end

#next_command_countObject

Returns the value of attribute next_command_count.



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

def next_command_count
  @next_command_count
end

#rootObject

Returns the value of attribute root.



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

def root
  @root
end

#state_trailObject (readonly)

Returns the value of attribute state_trail.



46
47
48
# File 'lib/vimamsa/key_binding_tree.rb', line 46

def state_trail
  @state_trail
end

Instance Method Details

#__set_mode(label) ⇒ Object



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

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



580
581
582
583
584
585
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
# File 'lib/vimamsa/key_binding_tree.rb', line 580

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



137
138
139
140
141
142
143
144
145
# File 'lib/vimamsa/key_binding_tree.rb', line 137

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



126
127
128
129
130
131
132
133
134
# File 'lib/vimamsa/key_binding_tree.rb', line 126

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



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
# File 'lib/vimamsa/key_binding_tree.rb', line 557

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



147
148
149
# File 'lib/vimamsa/key_binding_tree.rb', line 147

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

#cur_mode_strObject



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

def cur_mode_str()
  return @mode_root_state.key_name
end

#dump_stateObject



100
101
102
103
104
105
106
107
108
# File 'lib/vimamsa/key_binding_tree.rb', line 100

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



151
152
153
154
155
156
157
158
159
# File 'lib/vimamsa/key_binding_tree.rb', line 151

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



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
322
323
324
325
326
327
328
329
330
331
# File 'lib/vimamsa/key_binding_tree.rb', line 282

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



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

def get_cursor_type
  @mode_root_state.cursor_type
end

#get_modeObject



251
252
253
# File 'lib/vimamsa/key_binding_tree.rb', line 251

def get_mode
  return @cur_mode
end

#get_scopeObject



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

def get_scope
  @mode_root_state.scope
end

#get_state_trail_strObject



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/vimamsa/key_binding_tree.rb', line 378

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
      mode_str = st.to_s
      mode_str = "COMMAND" if mode_str == "C"
      mode_str = "INSERT" if mode_str == "I"
      mode_str = "VISUAL" if mode_str == "V"
      mode_str = "BROWSE" if mode_str == "B"

      s_trail << "[#{trailpfx}#{mode_str}]"
    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



683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
# File 'lib/vimamsa/key_binding_tree.rb', line 683

def handle_key_bindigs_action(action, c)
  trail_str = get_state_trail_str[0]
  # $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

  if cnf.kbd.show_prev_action? and trail_str.class==String
    len_limit = 35
    action_desc = "UNK"
    if action.class == String && (m = action.match(/\Abuf\.insert_txt\((.+)\)\z/))
      char_part = m[1].gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
      action_desc = "insert #{char_part}"
      puts action_desc.inspect
    else
      action_desc = vma.actions[action]&.method_name || action.to_s
      action_desc = action_desc[0..len_limit] if action_desc.size > len_limit
    end
    trail_str = trail_str.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
    vma.gui.action_trail_label.markup = "<span weight='bold'>#{action_desc}|#{trail_str}</span>"
  end
end

#match(key_name) ⇒ Object



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
202
203
204
205
# File 'lib/vimamsa/key_binding_tree.rb', line 169

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



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
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
# File 'lib/vimamsa/key_binding_tree.rb', line 428

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 }

    # Multiple matching states/modes (search has forked)
    if new_state.size > 1
      # puts "AAA"
      # Conflict: One of them has actions (matching should stop),
      # another has children (matching should continue)
      if s_act.any? and state_with_children.any?
        # puts "AAA1"
        a = s_act[0]
        b = state_with_children[0]
        # Running major+minor mode. Minor mode overwriting the major mode
        if a.root == @overwriting_state or b.root == @overwriting_state
          # puts "AAA3:del"
          # Remove those states not belonging to the overwriting branch (minor mode)
          [s_act, state_with_children, new_state].each { |z| z.delete_if { |x| x.root != @overwriting_state } }
        end
      end
    end
    # new_state[0].root.key_name

    if s_act.any? and state_with_children.any?
      # debug "Conflict: s_act.any? and state_with_children.any?"
      # require "pry"; binding.pry
    end

    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”)



626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
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
# File 'lib/vimamsa/key_binding_tree.rb', line 626

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
      new_state.root = @cur_state.root
      new_state.parent = @cur_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



165
166
167
# File 'lib/vimamsa/key_binding_tree.rb', line 165

def remove_keyhandling_override()
  @override_keyhandling_callback = nil
end

#set_default_mode(label) ⇒ Object



84
85
86
87
88
89
# File 'lib/vimamsa/key_binding_tree.rb', line 84

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



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

def set_keyhandling_override(_callback)
  @override_keyhandling_callback = _callback
end

#set_mode(label) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/vimamsa/key_binding_tree.rb', line 70

def set_mode(label)
  return if get_mode == :label
  @match_state = [@modes[label]] # used for matching input
  @mode_root_state = @modes[label]
  
  #TODO: should not happen? @default_mode_stack[-1] should be always the same as get_mode ?
  @default_mode_stack << label if label != @default_mode_stack[-1]

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

#set_mode_stack(ms) ⇒ Object



91
92
93
94
95
96
97
98
# File 'lib/vimamsa/key_binding_tree.rb', line 91

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



110
111
112
113
114
# File 'lib/vimamsa/key_binding_tree.rb', line 110

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



415
416
417
418
419
420
421
422
# File 'lib/vimamsa/key_binding_tree.rb', line 415

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



255
256
257
258
259
260
261
262
# File 'lib/vimamsa/key_binding_tree.rb', line 255

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



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/vimamsa/key_binding_tree.rb', line 264

def set_state_to_root
  # if root state is a minor mode
  if @mode_root_state.major_modes.size == 1
    modelabel = @mode_root_state.major_modes[0] #TODO: support multiple inheritance?
    parent_mode = @modes[modelabel]
    # Have two branches for the matching (both major and minor modes)
    # @mode_root_state = minor, parent_mode = major
    @match_state = [@mode_root_state, parent_mode]
    @overwriting_state = @mode_root_state # States from this branch have priority over others.
  else
    # if root state is a major mode
    @overwriting_state = nil
    @match_state = [@mode_root_state]
  end

  @state_trail = [@mode_root_state]
end

#show_state_trailObject



207
208
209
210
# File 'lib/vimamsa/key_binding_tree.rb', line 207

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

#to_previous_modeObject



116
117
118
119
120
121
122
123
124
# File 'lib/vimamsa/key_binding_tree.rb', line 116

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



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
367
368
369
370
371
372
373
374
375
376
# File 'lib/vimamsa/key_binding_tree.rb', line 334

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