vimamsa 0.1.22 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
1
+ SETTINGS_DEFS = [
2
+ {
3
+ :label => "Tab / Indent",
4
+ :settings => [
5
+ { :key => [:tab, :width], :label => "Tab width", :type => :int, :min => 1, :max => 16, :step => 1 },
6
+ { :key => [:tab, :to_spaces_default], :label => "Use spaces instead of tabs (default)", :type => :bool },
7
+ { :key => [:indent_based_on_last_line], :label => "Auto-indent based on last line", :type => :bool },
8
+ ],
9
+ },
10
+ {
11
+ :label => "Font",
12
+ :settings => [
13
+ { :key => [:font, :family], :label => "Font family", :type => :string },
14
+ { :key => [:font, :size], :label => "Font size (pt)", :type => :int, :min => 4, :max => 72, :step => 1 },
15
+ ],
16
+ },
17
+ {
18
+ :label => "Appearance",
19
+ :settings => [
20
+ { :key => [:match, :highlight, :color], :label => "Search highlight color", :type => :string },
21
+ { :key => [:kbd, :show_prev_action], :label => "Show previous action in toolbar", :type => :bool },
22
+ ],
23
+ },
24
+ {
25
+ :label => "Behavior",
26
+ :settings => [
27
+ { :key => [:lsp, :enabled], :label => "Enable LSP (Language Server)", :type => :bool },
28
+ { :key => [:experimental], :label => "Enable experimental features", :type => :bool },
29
+ { :key => [:macro, :animation_delay], :label => "Macro animation delay (sec)", :type => :float, :min => 0.0, :max => 2.0, :step => 0.0001 },
30
+ ],
31
+ },
32
+ ]
33
+
34
+ class SettingsDialog
35
+ def initialize
36
+ @widgets = {}
37
+ @window = Gtk::Window.new
38
+ @window.set_transient_for($vmag.window) if $vmag&.window
39
+ @window.modal = true
40
+ @window.title = "Preferences"
41
+ @window.default_width = 500
42
+
43
+ outer = Gtk::Box.new(:vertical, 12)
44
+ # outer.margin = 16
45
+ @window.set_child(outer)
46
+
47
+ notebook = Gtk::Notebook.new
48
+ outer.append(notebook)
49
+
50
+ SETTINGS_DEFS.each do |section|
51
+ grid = Gtk::Grid.new
52
+ grid.row_spacing = 10
53
+ grid.column_spacing = 16
54
+ grid.margin_top = 12
55
+ grid.margin_bottom = 12
56
+ grid.margin_start = 12
57
+ grid.margin_end = 12
58
+
59
+ section[:settings].each_with_index do |s, row|
60
+ label = Gtk::Label.new(s[:label])
61
+ label.halign = :start
62
+ label.hexpand = true
63
+
64
+ widget = make_widget(s)
65
+ @widgets[s[:key]] = { :widget => widget, :type => s[:type] }
66
+
67
+ grid.attach(label, 0, row, 1, 1)
68
+ grid.attach(widget, 1, row, 1, 1)
69
+ end
70
+
71
+ notebook.append_page(grid, Gtk::Label.new(section[:label]))
72
+ end
73
+
74
+ hbox = Gtk::Box.new(:horizontal, 8)
75
+ hbox.halign = :end
76
+
77
+ cancel_btn = Gtk::Button.new(:label => "Cancel")
78
+ save_btn = Gtk::Button.new(:label => "Save")
79
+ cancel_btn.signal_connect("clicked") { @window.destroy }
80
+ save_btn.signal_connect("clicked") { save_and_close }
81
+
82
+ hbox.append(cancel_btn)
83
+ hbox.append(save_btn)
84
+ outer.append(hbox)
85
+
86
+ press = Gtk::EventControllerKey.new
87
+ press.set_propagation_phase(Gtk::PropagationPhase::CAPTURE)
88
+ @window.add_controller(press)
89
+ press.signal_connect("key-pressed") do |_g, keyval, _kc, _y|
90
+ if keyval == Gdk::Keyval::KEY_Escape
91
+ @window.destroy
92
+ true
93
+ else
94
+ false
95
+ end
96
+ end
97
+ end
98
+
99
+ def make_widget(s)
100
+ cur = get(s[:key])
101
+ case s[:type]
102
+ when :bool
103
+ w = Gtk::Switch.new
104
+ w.active = cur == true
105
+ w.valign = :center
106
+ w
107
+ when :int
108
+ adj = Gtk::Adjustment.new(cur.to_f, s[:min].to_f, s[:max].to_f, s[:step].to_f, s[:step].to_f * 5, 0.0)
109
+ Gtk::SpinButton.new(adj, s[:step].to_f, 0)
110
+ when :float
111
+ adj = Gtk::Adjustment.new(cur.to_f, s[:min].to_f, s[:max].to_f, s[:step].to_f, s[:step].to_f * 5, 0.0)
112
+ digits = s[:step].to_s.split(".").last.to_s.length
113
+ digits = 2 if digits < 2
114
+ Gtk::SpinButton.new(adj, s[:step].to_f, digits)
115
+ when :string
116
+ w = Gtk::Entry.new
117
+ w.text = cur.to_s
118
+ w
119
+ end
120
+ end
121
+
122
+ def save_and_close
123
+ @widgets.each do |key, info|
124
+ val = case info[:type]
125
+ when :bool then info[:widget].active?
126
+ when :int then info[:widget].value.to_i
127
+ when :float then info[:widget].value.to_f
128
+ when :string then info[:widget].text
129
+ end
130
+ set(key, val)
131
+ end
132
+ save_settings_to_file
133
+ gui_refresh_font
134
+ @window.destroy
135
+ end
136
+
137
+ def run
138
+ @window.show
139
+ end
140
+ end
141
+
142
+ def show_settings_dialog
143
+ SettingsDialog.new.run
144
+ end
145
+
146
+ def gui_refresh_font
147
+ return unless $vmag
148
+ provider = Gtk::CssProvider.new
149
+ provider.load(data: "textview { font-family: #{get(cnf.font.family)}; font-size: #{get(cnf.font.size)}pt; }")
150
+ for _k, window in $vmag.windows
151
+ view = window[:sw].child
152
+ next if view.nil?
153
+ view.style_context.add_provider(provider)
154
+ end
155
+ end
@@ -2,7 +2,6 @@
2
2
  class VSourceView < GtkSource::View
3
3
  attr_accessor :bufo, :autocp_active, :cpl_list
4
4
 
5
-
6
5
  # def initialize(title = nil,bufo=nil)
7
6
  def initialize(title, bufo)
8
7
  # super(:toplevel)
@@ -19,6 +18,7 @@ class VSourceView < GtkSource::View
19
18
  @tt = nil
20
19
 
21
20
  # Mainly after page-up or page-down
21
+
22
22
  signal_connect("move-cursor") do |widget, event|
23
23
  # if event.name == "GTK_MOVEMENT_PAGES" and (vma.actions.last_action == "page_up" or vma.actions.last_action == "page_down")
24
24
  # handle_scrolling()
@@ -174,9 +174,24 @@ class VSourceView < GtkSource::View
174
174
  i = coord_to_iter(x, y, true)
175
175
  pp i
176
176
  @range_start = i
177
+ @drag_start_x = x
178
+ @drag_start_y = y
177
179
  buf.start_selection
178
180
  end
179
181
 
182
+ @cnt_drag.signal_connect "drag-update" do |gesture, offset_x, offset_y|
183
+ next unless @range_start
184
+ cur_x = @drag_start_x + offset_x
185
+ cur_y = @drag_start_y + offset_y
186
+ debug "drag-update 2 #{cur_x} #{cur_y}"
187
+ i = coord_to_iter(cur_x, cur_y, true)
188
+ @bufo.set_pos(i) if !i.nil? and @last_iter != i
189
+ if !i.nil? and (@range_start - i).abs >= 2
190
+ vma.kbd.set_mode(:visual)
191
+ end
192
+ @last_iter = i
193
+ end
194
+
180
195
  @cnt_drag.signal_connect "drag-end" do |gesture, offsetx, offsety|
181
196
  debug "drag-end", 2
182
197
  if offsetx.abs < 5 and offsety.abs < 5
@@ -186,8 +201,7 @@ class VSourceView < GtkSource::View
186
201
  elsif vma.kbd.get_scope != :editor
187
202
  # Can't transition from editor wide mode to buffer specific mode
188
203
  vma.kbd.set_mode(:visual)
189
- else
190
- buf.end_selection
204
+ else # The normal case
191
205
  end
192
206
  @range_start = nil
193
207
  end
@@ -199,6 +213,19 @@ class VSourceView < GtkSource::View
199
213
  @click = click
200
214
 
201
215
  @range_start = nil
216
+
217
+ # Handle right click
218
+ rightclick = Gtk::GestureClick.new
219
+ rightclick.button = 3
220
+ self.add_controller(rightclick)
221
+ rightclick.signal_connect "pressed" do |gesture, n_press, x, y, z|
222
+ puts "SourceView, GestureClick rightclick released button=#{gesture.button} x=#{x} y=#{y}"
223
+ if gesture.button == 3
224
+ show_context_menu(x, y)
225
+ next true
226
+ end
227
+ end
228
+
202
229
  click.signal_connect "pressed" do |gesture, n_press, x, y, z|
203
230
  debug "SourceView, GestureClick released x=#{x} y=#{y}"
204
231
 
@@ -219,11 +246,19 @@ class VSourceView < GtkSource::View
219
246
  end
220
247
 
221
248
  @bufo.set_pos(i) if !i.nil?
249
+ if n_press == 2
250
+ #TODO: refactor to have one function for all line actions
251
+ if @bufo.module&.respond_to?(:select_line)
252
+ @bufo.module.select_line
253
+ else
254
+ @bufo.cur_nonwhitespace_word_action()
255
+ end
256
+ end
222
257
  true
223
258
  end
224
259
 
225
260
  click.signal_connect "released" do |gesture, n_press, x, y, z|
226
- debug "SourceView, GestureClick released x=#{x} y=#{y}"
261
+ debug "SourceView, GestureClick released x=#{x} y=#{y} button=#{gesture.button}"
227
262
 
228
263
  xloc = (x - gutter_width).to_i
229
264
  yloc = (y + visible_rect.y).to_i
@@ -587,7 +622,7 @@ class VSourceView < GtkSource::View
587
622
 
588
623
  mode = vma.kbd.get_mode
589
624
  ctype = vma.kbd.get_cursor_type
590
- ctype = :visual if vma.buf.selection_active?
625
+ ctype = :visual if @bufo.selection_active?
591
626
 
592
627
  if [:command, :replace, :browse].include?(ctype)
593
628
  set_cursor_color(ctype)
@@ -632,5 +667,44 @@ class VSourceView < GtkSource::View
632
667
  self.cursor_visible = true
633
668
  end
634
669
  end #end draw_cursor
635
- end
636
670
 
671
+ CONTEXT_MENU_ITEMS = [
672
+ ["Paste", :paste_after_cursor],
673
+ ["Previous buffer", :history_switch_backwards],
674
+ ]
675
+
676
+ CONTEXT_MENU_ITEMS_SELECTION = [
677
+ ["Copy", :copy_selection],
678
+ ["Cut", :cut_selection],
679
+ ]
680
+
681
+ def init_context_menu
682
+ all_items = CONTEXT_MENU_ITEMS + CONTEXT_MENU_ITEMS_SELECTION
683
+ all_items.each do |label, action_id|
684
+ actkey = "ctx_#{action_id}"
685
+ unless vma.gui.app.lookup_action(actkey)
686
+ act = Gio::SimpleAction.new(actkey)
687
+ vma.gui.app.add_action(act)
688
+ act.signal_connect("activate") do
689
+ call_action(action_id)
690
+ after_action
691
+ end
692
+ end
693
+ end
694
+ @context_menu = Gtk::PopoverMenu.new
695
+ @context_menu.set_parent(self)
696
+ @context_menu.has_arrow = false
697
+ end
698
+
699
+ def show_context_menu(x, y)
700
+ init_context_menu if @context_menu.nil?
701
+ menu = Gio::Menu.new
702
+ CONTEXT_MENU_ITEMS.each { |label, action_id| menu.append(label, "app.ctx_#{action_id}") }
703
+ if @bufo.selection_active?
704
+ CONTEXT_MENU_ITEMS_SELECTION.each { |label, action_id| menu.append(label, "app.ctx_#{action_id}") }
705
+ end
706
+ @context_menu.set_menu_model(menu)
707
+ @context_menu.set_pointing_to(Gdk::Rectangle.new(x.to_i, y.to_i, 1, 1))
708
+ @context_menu.popup
709
+ end
710
+ end
@@ -35,9 +35,19 @@ reg_act(:lsp_jump_to_definition, proc { vma.buf.lsp_jump_to_def }, "LSP jump to
35
35
 
36
36
  reg_act(:eval_buf, proc { vma.buf.eval_whole_buf }, "Eval whole current buffer as ruby code (DANGEROUS)")
37
37
 
38
+ reg_act(:show_settings, proc { show_settings_dialog }, "Show settings")
39
+ reg_act(:cut_selection, proc { buf.delete(SELECTION) }, "Cut selection to clipboard")
40
+
41
+ reg_act(:insert_backspace, proc { buf.selection_active? ? buf.delete(SELECTION) : buf.delete(BACKWARD_CHAR) }, "Delete backwards")
42
+ reg_act(:insert_select_up, proc { insert_select_move(BACKWARD_LINE) }, "Select texte upwards")
43
+ reg_act(:insert_select_down, proc { insert_select_move(BACKWARD_CHAR) }, "Select text downwards")
44
+
45
+ reg_act(:copy_selection, proc { buf.copy_active_selection }, "Copy selection to clipboard")
38
46
  reg_act(:enable_debug, proc { cnf.debug = true }, "Enable debug")
39
47
  reg_act(:disable_debug, proc { cnf.debug = false }, "Disable debug")
40
48
 
49
+ reg_act(:experimental_eval, proc { bindkey "V , e", "vma.buf.convert_selected_text(:eval)" }, "Enable key binding:\"[VISUAL] , e:\" Eval selected text")
50
+
41
51
  reg_act(:easy_jump, proc { EasyJump.start }, "Easy jump")
42
52
  reg_act(:gui_ensure_cursor_visible, proc { vma.gui.view.ensure_cursor_visible }, "Scroll to current cursor position")
43
53
  reg_act(:gui_refresh_cursor, proc { vma.buf.refresh_cursor }, "Refresh cursor")
@@ -46,17 +56,18 @@ reg_act(:savedebug, "savedebug", "Save debug info", { :group => :debug })
46
56
  reg_act(:open_file_dialog, "open_file_dialog", "Open file", { :group => :file })
47
57
  reg_act(:create_new_file, "create_new_file", "Create new file", { :group => :file })
48
58
  reg_act(:backup_all_buffers, proc { backup_all_buffers }, "Backup all buffers", { :group => :file })
49
- reg_act(:e_move_forward_char, "e_move_forward_char", "", { :group => [:move, :basic] })
50
- reg_act(:e_move_backward_char, "e_move_backward_char", "", { :group => [:move, :basic] })
59
+ reg_act(:e_move_forward_char, "e_move_forward_char", "Move forward", { :group => [:move, :basic] })
60
+ reg_act(:e_move_backward_char, "e_move_backward_char", "Move forward", { :group => [:move, :basic] })
51
61
  # reg_act(:history_switch_backwards, proc{bufs.history_switch_backwards}, "", { :group => :file })
52
- reg_act(:history_switch_backwards, proc{bufs.history_switch(-1)}, "", { :group => :file })
53
- reg_act(:history_switch_forwards, proc{bufs.history_switch(+1)}, "", { :group => :file })
62
+ reg_act(:history_switch_backwards, proc{bufs.history_switch(-1)}, "Prev buffer", { :group => :file })
63
+ reg_act(:history_switch_forwards, proc{bufs.history_switch(+1)}, "Next buffer", { :group => :file })
64
+ reg_act(:print_buffer_access_list, proc { bufs.print_by_access_time }, "Print buffers by access time", { :group => :file })
54
65
  reg_act(:center_on_current_line, "center_on_current_line", "", { :group => :view })
55
66
  reg_act(:run_last_macro, proc { vma.macro.run_last_macro }, "Run last recorded or executed macro", { :group => :macro })
56
- reg_act(:jump_to_next_edit, "jump_to_next_edit", "")
57
- reg_act(:jump_to_last_edit, proc { buf.jump_to_last_edit }, "")
67
+ reg_act(:jump_to_next_edit, "jump_to_next_edit", "Jump to next edit pos")
68
+ reg_act(:jump_to_last_edit, proc { buf.jump_to_last_edit }, "Jump to last edit pos")
58
69
  reg_act(:jump_to_random, proc { buf.jump_to_random_pos }, "")
59
- reg_act(:insert_new_line, proc { buf.insert_new_line() }, "")
70
+ reg_act(:insert_new_line, proc { buf.insert_new_line() }, "Insert new line")
60
71
  reg_act(:show_key_bindings, proc { show_key_bindings }, "Show key bindings")
61
72
  reg_act(:put_file_path_to_clipboard, proc { buf.put_file_path_to_clipboard }, "Put file path of current file to clipboard")
62
73
  reg_act(:put_file_ref_to_clipboard, proc { buf.put_file_ref_to_clipboard }, "Put file ref of current file to clipboard")
@@ -67,11 +78,15 @@ reg_act(:set_unencrypted, proc { buf.set_unencrypted }, "Set current file to sav
67
78
  reg_act(:set_executable, proc { buf.set_executable }, "Set current file permissions to executable")
68
79
  # reg_act(:close_all_buffers, proc { bufs.close_all_buffers() }, "Close all buffers")
69
80
  reg_act(:close_current_buffer, proc { bufs.close_current_buffer(true) }, "Close current buffer")
70
- reg_act(:comment_selection, proc { buf.comment_selection }, "")
81
+ reg_act(:toggle_file_panel, proc { vma.gui.toggle_file_panel }, "Toggle file panel")
82
+ reg_act(:comment_selection, proc { buf.comment_selection }, "Comment selection")
71
83
  reg_act(:delete_char_forward, proc { buf.delete(CURRENT_CHAR_FORWARD) }, "Delete char forward", { :group => [:edit, :basic] })
72
84
  reg_act(:gui_file_finder, proc { vma.FileFinder.start_gui }, "Fuzzy file finder")
73
85
  reg_act(:gui_file_history_finder, proc { vma.FileHistory.start_gui }, "Fuzzy file history finder")
74
86
  reg_act(:gui_search_replace, proc { gui_search_replace }, "Search and replace")
87
+ reg_act(:find_next, proc { $search.jump_to_next() }, "Find next")
88
+
89
+
75
90
  reg_act(:set_style_bold, proc { buf.style_transform(:bold) }, "Set text weight to bold")
76
91
  reg_act(:set_style_link, proc { buf.style_transform(:link) }, "Set text as link")
77
92
  reg_act(:V_join_lines, proc { vma.buf.convert_selected_text(:joinlines) }, "Join lines")
@@ -87,8 +102,10 @@ reg_act(:clear_line_styles, proc { buf.set_line_style(:clear) }, "Clear styles o
87
102
  reg_act(:gui_select_buffer, proc { vma.kbd.set_mode("S"); gui_select_buffer }, "Select buffer")
88
103
  reg_act :open_file_dialog, "open_file_dialog", "Open file"
89
104
  reg_act :minibuffer_end, proc { minibuffer_end }
90
- reg_act(:invoke_replace, "invoke_replace", "")
105
+ reg_act(:invoke_replace, "invoke_replace", "Invoke replace")
91
106
  reg_act(:diff_buffer, "diff_buffer", "")
107
+ reg_act(:git_diff_buffer, proc { git_diff_buffer }, "Show git diff of current file")
108
+ reg_act(:diff_buffer_jump_to_source, proc { diff_buffer_jump_to_source }, "Jump to corresponding line in source from diff buffer")
92
109
  # reg_act(:invoke_grep_search, proc{invoke_grep_search}, "")
93
110
  reg_act(:invoke_grep_search, proc { gui_grep }, "Grep current buffer")
94
111
  reg_act(:ack_search, proc { gui_ack }, "") #invoke_ack_search
@@ -98,7 +115,7 @@ reg_act :delete_to_next_word_start, proc { buf.delete2(:to_next_word) }, "Delete
98
115
  reg_act :delete_to_line_start, proc { buf.delete2(:to_line_start) }, "Delete to line start", { :group => [:edit, :basic] }
99
116
 
100
117
 
101
- reg_act(:ack_search, proc { gui_ack }, "")
118
+ reg_act(:ack_search, proc { gui_ack }, "Ack")
102
119
 
103
120
  reg_act(:copy_cur_line, proc {buf.copy_line}, "Copy the current line")
104
121
  reg_act(:paste_before_cursor, proc {buf.paste(BEFORE)}, "Paste text before the cursor")
@@ -119,6 +136,8 @@ reg_act(:move_next_line, proc { buf.move(FORWARD_LINE) }, "Move the cursor to th
119
136
  reg_act(:move_backward_char, proc { buf.move(BACKWARD_CHAR) }, "Move one character backward")
120
137
  reg_act(:start_visual_mode, proc { buf.start_selection;vma.kbd.set_mode(:visual) }, "Enter VISUAL mode (for selections)")
121
138
  reg_act(:jump_last_edit, proc { buf.jump_to_last_edit }, "Jump to the last edit location")
139
+ reg_act(:install_demo_files, proc { install_demo_files }, "Install and show Demo")
140
+ reg_act(:reload_customrb, proc { reload_customrb }, "Reload custom.rb")
122
141
 
123
142
 
124
143
  reg_act :start_browse_mode, proc {
@@ -188,6 +207,9 @@ act_list = {
188
207
 
189
208
  :backward_line => { :proc => proc { buf.move(BACKWARD_LINE) },
190
209
  :desc => "Move one line backward", :group => [:move, :basic] },
210
+
211
+ :increment_word => { :proc => proc { buf.increment_current_word},
212
+ :desc => "Increment word", :group => [:edit, :extra] },
191
213
 
192
214
  # { :proc => proc { },
193
215
  # :desc => "", :group => : },
@@ -19,7 +19,7 @@
19
19
  #
20
20
 
21
21
  class State
22
- attr_accessor :key_name, :eval_rule, :children, :action, :label, :major_modes, :level, :cursor_type, :keywords
22
+ attr_accessor :key_name, :eval_rule, :children, :action, :label, :major_modes, :level, :cursor_type, :keywords, :root, :parent
23
23
  attr_reader :cur_mode, :scope
24
24
 
25
25
  def initialize(key_name, eval_rule = "", ctype = :command, scope: :buffer)
@@ -31,6 +31,8 @@ class State
31
31
  @keywords = []
32
32
  @action = nil
33
33
  @level = 0
34
+ @root = self # parent of a parent ... until mode root
35
+ @parent = nil
34
36
  @cursor_type = ctype
35
37
  end
36
38
 
@@ -55,6 +57,7 @@ class KeyBindingTree
55
57
  @last_action = nil
56
58
  @cur_action = nil
57
59
  @method_handles_repeat = false
60
+ @overwriting_state = nil # A branch which has priority over other branches
58
61
 
59
62
  @modifiers = { :ctrl => false, :shift => false, :alt => false } # TODO: create a queue
60
63
  @last_event = [nil, nil, nil, nil, nil]
@@ -68,8 +71,9 @@ class KeyBindingTree
68
71
  return if get_mode == :label
69
72
  @match_state = [@modes[label]] # used for matching input
70
73
  @mode_root_state = @modes[label]
71
- # @default_mode = label
72
- @default_mode_stack << label
74
+
75
+ #TODO: should not happen? @default_mode_stack[-1] should be always the same as get_mode ?
76
+ @default_mode_stack << label if label != @default_mode_stack[-1]
73
77
 
74
78
  __set_mode(label)
75
79
  if !vma.buf.nil?
@@ -258,11 +262,17 @@ class KeyBindingTree
258
262
  end
259
263
 
260
264
  def set_state_to_root
265
+ # if root state is a minor mode
261
266
  if @mode_root_state.major_modes.size == 1
262
- modelabel = @mode_root_state.major_modes[0]
263
- mmode = @modes[modelabel]
264
- @match_state = [@mode_root_state, mmode]
267
+ modelabel = @mode_root_state.major_modes[0] #TODO: support multiple inheritance?
268
+ parent_mode = @modes[modelabel]
269
+ # Have two branches for the matching (both major and minor modes)
270
+ # @mode_root_state = minor, parent_mode = major
271
+ @match_state = [@mode_root_state, parent_mode]
272
+ @overwriting_state = @mode_root_state # States from this branch have priority over others.
265
273
  else
274
+ # if root state is a major mode
275
+ @overwriting_state = nil
266
276
  @match_state = [@mode_root_state]
267
277
  end
268
278
 
@@ -378,7 +388,13 @@ class KeyBindingTree
378
388
  mmid = st.major_modes.first
379
389
  trailpfx = "#{@modes[mmid].to_s}>"
380
390
  end
381
- s_trail << "[#{trailpfx}#{st.to_s}]"
391
+ mode_str = st.to_s
392
+ mode_str = "COMMAND" if mode_str == "C"
393
+ mode_str = "INSERT" if mode_str == "I"
394
+ mode_str = "VISUAL" if mode_str == "V"
395
+ mode_str = "BROWSE" if mode_str == "B"
396
+
397
+ s_trail << "[#{trailpfx}#{mode_str}]"
382
398
  else
383
399
  s_trail << " #{st.to_s}"
384
400
  end
@@ -491,7 +507,31 @@ class KeyBindingTree
491
507
  state_with_children = new_state.select { |s| s.children.any? }
492
508
  s_act = new_state.select { |s| s.action != nil }
493
509
 
494
- if s_act.any? #and !state_with_children.any?
510
+ # Multiple matching states/modes (search has forked)
511
+ if new_state.size > 1
512
+ # puts "AAA"
513
+ # Conflict: One of them has actions (matching should stop),
514
+ # another has children (matching should continue)
515
+ if s_act.any? and state_with_children.any?
516
+ # puts "AAA1"
517
+ a = s_act[0]
518
+ b = state_with_children[0]
519
+ # Running major+minor mode. Minor mode overwriting the major mode
520
+ if a.root == @overwriting_state or b.root == @overwriting_state
521
+ # puts "AAA3:del"
522
+ # Remove those states not belonging to the overwriting branch (minor mode)
523
+ [s_act, state_with_children, new_state].each { |z| z.delete_if { |x| x.root != @overwriting_state } }
524
+ end
525
+ end
526
+ end
527
+ # new_state[0].root.key_name
528
+
529
+ if s_act.any? and state_with_children.any?
530
+ # debug "Conflict: s_act.any? and state_with_children.any?"
531
+ # require "pry"; binding.pry
532
+ end
533
+
534
+ if s_act.any? and !state_with_children.any?
495
535
  eval_s = s_act.first.action if eval_s == nil
496
536
  # if eval_s.to_s.match(/end_recording/)
497
537
  # require "pry"; binding.pry
@@ -625,6 +665,8 @@ class KeyBindingTree
625
665
  end
626
666
  s1 = new_state
627
667
  @cur_state.children << new_state
668
+ new_state.root = @cur_state.root
669
+ new_state.parent = @cur_state
628
670
  end
629
671
 
630
672
  set_state(key_name, eval_rule) # TODO: check is ok?
@@ -639,6 +681,7 @@ class KeyBindingTree
639
681
  end
640
682
 
641
683
  def handle_key_bindigs_action(action, c)
684
+ trail_str = get_state_trail_str[0]
642
685
  # $acth << action #TODO:needed here?
643
686
  @method_handles_repeat = false #TODO:??
644
687
  n = 1
@@ -685,6 +728,21 @@ class KeyBindingTree
685
728
  if !(action.class == String and action.include?("set_next_command_count"))
686
729
  @next_command_count = nil
687
730
  end
731
+
732
+ if cnf.kbd.show_prev_action? and trail_str.class==String
733
+ len_limit = 35
734
+ action_desc = "UNK"
735
+ if action.class == String && (m = action.match(/\Abuf\.insert_txt\((.+)\)\z/))
736
+ char_part = m[1].gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
737
+ action_desc = "insert #{char_part}"
738
+ puts action_desc.inspect
739
+ else
740
+ action_desc = vma.actions[action]&.method_name || action.to_s
741
+ action_desc = action_desc[0..len_limit] if action_desc.size > len_limit
742
+ end
743
+ trail_str = trail_str.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
744
+ vma.gui.action_trail_label.markup = "<span weight='bold'>#{action_desc}|#{trail_str}</span>"
745
+ end
688
746
  end
689
747
  end
690
748
 
@@ -734,6 +792,12 @@ def show_key_bindings()
734
792
  done.concat(x.lines); kbd_s << x
735
793
  kbd_s << "\n"
736
794
 
795
+ kbd_s << "◼ Hyper Plaintext\n"
796
+ x = vma.kbd.get_by_keywords(modes: ["C"], keywords: ["hyperplaintext"])
797
+ x2 = vma.kbd.get_by_keywords(modes: ["V"], keywords: ["hyperplaintext"])
798
+ done.concat(x.lines); kbd_s << x << "\n" << x2
799
+ kbd_s << "\n"
800
+
737
801
  kbd_s << "◼ Core\n"
738
802
  x = vma.kbd.get_by_keywords(modes: [], keywords: ["core"])
739
803
  x << vma.kbd.get_by_keywords(modes: ["X"], keywords: ["intro"])