vimamsa 0.1.21 → 0.1.22
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.
- checksums.yaml +4 -4
- data/README.md +12 -6
- data/install.sh +4 -0
- data/lib/vimamsa/buffer_cursor.rb +1 -1
- data/lib/vimamsa/buffer_list.rb +1 -1
- data/lib/vimamsa/editor.rb +6 -18
- data/lib/vimamsa/file_manager.rb +10 -3
- data/lib/vimamsa/gui.rb +31 -6
- data/lib/vimamsa/gui_sourceview.rb +7 -42
- data/lib/vimamsa/key_actions.rb +27 -4
- data/lib/vimamsa/key_binding_tree.rb +159 -23
- data/lib/vimamsa/key_bindings_vimlike.rb +146 -129
- data/lib/vimamsa/util.rb +25 -1
- data/lib/vimamsa/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3eba5b3c9a7821e14802295825b32369ff9440046b91b065ca2b1e82e44cc444
|
4
|
+
data.tar.gz: 16bd4a94226c3b07cb5d40cb6e395a09f8fbbb4e96e164af19b05415048a9812
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f74f902af54d82002d4b0d814e80cafc5326bfb712c0cd124c39be0bb2bf3f70d1eaabe6c2f05de619ee9e9ac4cf12a10a4350c568ca1b815129904b40797c48
|
7
|
+
data.tar.gz: a01c59f8358904e1ad511c4608de70bc31ac8bc8ccbbfa240eb897240a68f7673b7ae1bc124dcf312b94a6c7f12834d33dba692e6795713f083a5b2736ac6291
|
data/README.md
CHANGED
@@ -18,15 +18,21 @@ Vi/Vim -inspired experimental GUI-oriented text editor written with Ruby and GTK
|
|
18
18
|
- Ruby 3.0+
|
19
19
|
- GTK 4
|
20
20
|
|
21
|
+
|
21
22
|
## Installation
|
22
23
|
|
23
24
|
|
24
|
-
On Ubuntu:
|
25
|
+
On Ubuntu (22.04):
|
25
26
|
```
|
26
|
-
sudo apt install ruby-dev
|
27
|
+
sudo apt install ruby-dev build-essential
|
27
28
|
sudo gem install vimamsa
|
28
29
|
```
|
29
30
|
|
31
|
+
Run:
|
32
|
+
```
|
33
|
+
vimamsa
|
34
|
+
```
|
35
|
+
|
30
36
|
### Other install options
|
31
37
|
|
32
38
|
Install from sources:
|
@@ -51,7 +57,6 @@ vimamsa
|
|
51
57
|
Install packages for optional features:
|
52
58
|
```
|
53
59
|
sudo apt install ack-grep clang-format
|
54
|
-
gem install ripl ripl-multi_line differ parallel listen rufo language_server-protocol
|
55
60
|
```
|
56
61
|
|
57
62
|
For customization, edit ~/.vimamsa/custom.rb
|
@@ -63,7 +68,7 @@ For customization, edit ~/.vimamsa/custom.rb
|
|
63
68
|
|
64
69
|
## Key bindings
|
65
70
|
|
66
|
-
Key bindings are very much like in VIm. For details, see
|
71
|
+
Key bindings are very much like in VIm. For details, see menu item "Help -> Show key bindings" and file lib/vimamsa/key_bindings_vimlike.rb
|
67
72
|
|
68
73
|
Keys that work somewhat similarly as in Vim:
|
69
74
|
|
@@ -81,8 +86,9 @@ d y gU gu
|
|
81
86
|
Keys that work differently to Vim are documented in the tables below
|
82
87
|
|
83
88
|
Syntax:
|
84
|
-
|
85
|
-
|
89
|
+
|
90
|
+
- ctrl! means press and immediate release of ctrl key. Triggered by key up event when no other keys were pressed between key down and key up events.
|
91
|
+
- ctrl-x means press and hold ctrl key, press x
|
86
92
|
|
87
93
|
<table>
|
88
94
|
<colgroup>
|
data/install.sh
ADDED
@@ -141,7 +141,7 @@ class Buffer < String
|
|
141
141
|
end
|
142
142
|
|
143
143
|
def jump_to_next_instance_of_word()
|
144
|
-
if
|
144
|
+
if vma.kbd.last_action == vma.kbd.cur_action and @current_word != nil
|
145
145
|
# debug "REPEATING *"
|
146
146
|
else
|
147
147
|
start_search = [@pos - 150, 0].max
|
data/lib/vimamsa/buffer_list.rb
CHANGED
data/lib/vimamsa/editor.rb
CHANGED
@@ -74,7 +74,7 @@ class Editor
|
|
74
74
|
|
75
75
|
# build_key_bindings_tree
|
76
76
|
@kbd = KeyBindingTree.new()
|
77
|
-
$kbd = @kbd
|
77
|
+
$kbd = @kbd #TODO: remove global
|
78
78
|
require "vimamsa/key_bindings_vimlike"
|
79
79
|
|
80
80
|
$buffers = BufferList.new
|
@@ -261,6 +261,9 @@ class Editor
|
|
261
261
|
if p and !@file_content_search_paths.include?(p)
|
262
262
|
r.insert(0, p)
|
263
263
|
end
|
264
|
+
|
265
|
+
# Ensure that paths are in correct format
|
266
|
+
r = r.map{|x|File.expand_path(x)}
|
264
267
|
|
265
268
|
return r
|
266
269
|
end
|
@@ -365,21 +368,6 @@ def start_minibuffer_cmd(bufname, bufstr, cmd)
|
|
365
368
|
$minibuffer.call_func = method(cmd)
|
366
369
|
end
|
367
370
|
|
368
|
-
def show_key_bindings()
|
369
|
-
kbd_s = "❙Key bindings❙\n"
|
370
|
-
kbd_s << "\n⦁[Mode] keys : action⦁\n"
|
371
|
-
|
372
|
-
kbd_s << "[B]=Browse, [C]=Command, [I]=Insert, [V]=Visual\n"
|
373
|
-
kbd_s << "key!: Press key once, release before pressing any other keys\n"
|
374
|
-
|
375
|
-
kbd_s << "===============================================\n"
|
376
|
-
kbd_s << vma.kbd.to_s
|
377
|
-
kbd_s << "\n"
|
378
|
-
kbd_s << "===============================================\n"
|
379
|
-
b = create_new_buffer(kbd_s, "key-bindings")
|
380
|
-
gui_set_file_lang(b.id, "hyperplaintext")
|
381
|
-
#
|
382
|
-
end
|
383
371
|
|
384
372
|
def diff_buffer()
|
385
373
|
bufstr = ""
|
@@ -412,14 +400,14 @@ end
|
|
412
400
|
|
413
401
|
def minibuffer_end()
|
414
402
|
debug "minibuffer_end"
|
415
|
-
|
403
|
+
vma.kbd.set_mode(:command)
|
416
404
|
minibuffer_input = $minibuffer.to_s[0..-2]
|
417
405
|
return $minibuffer.call_func.call(minibuffer_input)
|
418
406
|
end
|
419
407
|
|
420
408
|
def minibuffer_cancel()
|
421
409
|
debug "minibuffer_cancel"
|
422
|
-
|
410
|
+
vma.kbd.set_mode(:command)
|
423
411
|
minibuffer_input = $minibuffer.to_s[0..-2]
|
424
412
|
# $minibuffer.call_func.call('')
|
425
413
|
end
|
data/lib/vimamsa/file_manager.rb
CHANGED
@@ -18,7 +18,7 @@ class FileManager
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.init()
|
21
|
-
reg_act(:start_file_selector, proc { FileManager.new.run; vma.kbd.set_mode(:file_exp)
|
21
|
+
reg_act(:start_file_selector, proc { FileManager.new.run; vma.kbd.set_mode(:file_exp) }, "File selector")
|
22
22
|
|
23
23
|
reg_act(:fexp_chdir_parent, proc { FileManager.chdir_parent }, "File selector")
|
24
24
|
reg_act(:fexp_select, proc { buf.module.select_line }, "")
|
@@ -162,13 +162,14 @@ class FileManager
|
|
162
162
|
#TODO:
|
163
163
|
end
|
164
164
|
|
165
|
+
# Main inteface, show contents of current dir
|
165
166
|
def dir_to_buf(dirpath, b = nil)
|
166
167
|
# File.stat("testfile").mtime
|
167
168
|
|
168
169
|
debug "last file: #{vma.buffers.last_file}", 2
|
169
170
|
lastf = vma.buffers.last_file
|
170
171
|
jumpto = nil
|
171
|
-
if File.dirname(lastf) == dirpath
|
172
|
+
if !lastf.nil? and File.dirname(lastf) == dirpath
|
172
173
|
jumpto = File.basename(lastf)
|
173
174
|
end
|
174
175
|
vma.buffers.last_dir = dirpath
|
@@ -231,6 +232,13 @@ class FileManager
|
|
231
232
|
else
|
232
233
|
@buf.set_line_and_column_pos(@header.size, 0)
|
233
234
|
end
|
235
|
+
|
236
|
+
if @cdirs.size > 0
|
237
|
+
r = vma.buf.line_range(2, @cdirs.size+1)
|
238
|
+
|
239
|
+
# Hilight works only if done after buffer is drawn
|
240
|
+
run_as_idle proc { Gui.hilight_range(vma.buf, r, color: "#4488ffff") }
|
241
|
+
end
|
234
242
|
end
|
235
243
|
|
236
244
|
def fullp(fn)
|
@@ -267,7 +275,6 @@ class FileManager
|
|
267
275
|
jump_to_file(fn)
|
268
276
|
# vma.buffers.set_current_buffer(idx)
|
269
277
|
vma.buffers.close_other_buffer(@buf.id)
|
270
|
-
|
271
278
|
else
|
272
279
|
open_with_default_program(fn)
|
273
280
|
end
|
data/lib/vimamsa/gui.rb
CHANGED
@@ -348,7 +348,7 @@ class VMAgui
|
|
348
348
|
sw.set_child(view)
|
349
349
|
end
|
350
350
|
|
351
|
-
|
351
|
+
#TODO: implement in gtk4
|
352
352
|
def init_header_bar()
|
353
353
|
header = Gtk::HeaderBar.new
|
354
354
|
@header = header
|
@@ -577,17 +577,36 @@ class VMAgui
|
|
577
577
|
|
578
578
|
reset_controllers
|
579
579
|
|
580
|
+
focus_controller = Gtk::EventControllerFocus.new
|
581
|
+
|
582
|
+
focus_controller.signal_connect("enter") do
|
583
|
+
debug "Gained focus"
|
584
|
+
draw_cursor_bug_workaround
|
585
|
+
end
|
586
|
+
@window.add_controller(focus_controller)
|
587
|
+
|
588
|
+
motion_controller = Gtk::EventControllerMotion.new
|
589
|
+
motion_controller.signal_connect("motion") do |controller, x, y|
|
590
|
+
# label.set_text("Mouse at: (%.1f, %.1f)" % [x, y])
|
591
|
+
# puts "MOVE #{x} #{y}"
|
592
|
+
|
593
|
+
# Cursor vanishes when hovering over menubar
|
594
|
+
draw_cursor_bug_workaround if y < 30
|
595
|
+
@last_cursor = [x, y]
|
596
|
+
@cursor_move_time = Time.now
|
597
|
+
end
|
598
|
+
@window.add_controller(motion_controller)
|
599
|
+
|
580
600
|
@windows[1] = new_window(1)
|
581
601
|
|
582
602
|
@last_adj_time = Time.now
|
583
603
|
|
584
|
-
|
585
604
|
# To show keyboard key binding state
|
586
605
|
@statnfo = Gtk::Label.new
|
587
|
-
|
606
|
+
|
588
607
|
# To show e.g. current folder
|
589
608
|
@subtitle = Gtk::Label.new("")
|
590
|
-
|
609
|
+
|
591
610
|
@statbox = Gtk::Box.new(:horizontal, 2)
|
592
611
|
@statnfo.set_size_request(150, 10)
|
593
612
|
@statbox.append(@subtitle)
|
@@ -618,6 +637,12 @@ class VMAgui
|
|
618
637
|
|
619
638
|
@window.show
|
620
639
|
|
640
|
+
surface = @window.native.surface
|
641
|
+
tt = Time.now
|
642
|
+
surface.signal_connect("layout") do
|
643
|
+
# puts "Window resized or moved, other redraw."
|
644
|
+
end
|
645
|
+
|
621
646
|
run_as_idle proc { idle_set_size }
|
622
647
|
|
623
648
|
prov = Gtk::CssProvider.new
|
@@ -666,9 +691,9 @@ class VMAgui
|
|
666
691
|
return true if Time.now - @monitor_time < 0.2
|
667
692
|
# Detect element resize
|
668
693
|
if swa.width != @sw_width
|
669
|
-
|
694
|
+
debug "Width change sw_width #{@sw_width}"
|
670
695
|
@sw_width = swa.width
|
671
|
-
DelayExecutioner.exec(id: :scale_images, wait: 0.7, callable: proc { vma.gui.scale_all_images })
|
696
|
+
DelayExecutioner.exec(id: :scale_images, wait: 0.7, callable: proc { debug ":scale_images"; vma.gui.scale_all_images })
|
672
697
|
end
|
673
698
|
@monitor_time = Time.now
|
674
699
|
return true
|
@@ -1,16 +1,7 @@
|
|
1
1
|
# class VSourceView < Gtk::TextView
|
2
2
|
class VSourceView < GtkSource::View
|
3
3
|
attr_accessor :bufo, :autocp_active, :cpl_list
|
4
|
-
# :highlight_matching_brackets
|
5
4
|
|
6
|
-
# def set_highlight_current_line(vbool)
|
7
|
-
# end
|
8
|
-
|
9
|
-
# def set_show_line_numbers(vbool)
|
10
|
-
# end
|
11
|
-
|
12
|
-
# def highlight_matching_brackets=(vbool)
|
13
|
-
# end
|
14
5
|
|
15
6
|
# def initialize(title = nil,bufo=nil)
|
16
7
|
def initialize(title, bufo)
|
@@ -27,29 +18,6 @@ class VSourceView < GtkSource::View
|
|
27
18
|
|
28
19
|
@tt = nil
|
29
20
|
|
30
|
-
# self.drag_dest_add_image_targets #TODO:gtk4
|
31
|
-
# self.drag_dest_add_uri_targets #TODO:gtk4
|
32
|
-
|
33
|
-
# signal_connect("drag-data-received") do |widget, event, x, y, data, info, time| #TODO:gtk4
|
34
|
-
# puts "drag-data-received"
|
35
|
-
# puts
|
36
|
-
# if data.uris.size >= 1
|
37
|
-
|
38
|
-
# imgpath = CGI.unescape(data.uris[0])
|
39
|
-
# m = imgpath.match(/^file:\/\/(.*)/)
|
40
|
-
# if m
|
41
|
-
# fp = m[1]
|
42
|
-
# handle_drag_and_drop(fp)
|
43
|
-
# end
|
44
|
-
# end
|
45
|
-
# true
|
46
|
-
# end
|
47
|
-
|
48
|
-
# signal_connect("show-completion") do |x, y, z|
|
49
|
-
# debug "SHOW-COMPLETION", 2
|
50
|
-
# false
|
51
|
-
# end
|
52
|
-
|
53
21
|
# Mainly after page-up or page-down
|
54
22
|
signal_connect("move-cursor") do |widget, event|
|
55
23
|
# if event.name == "GTK_MOVEMENT_PAGES" and (vma.actions.last_action == "page_up" or vma.actions.last_action == "page_down")
|
@@ -70,7 +38,6 @@ class VSourceView < GtkSource::View
|
|
70
38
|
|
71
39
|
return
|
72
40
|
|
73
|
-
#TODO:gtk4
|
74
41
|
signal_connect "button-release-event" do |widget, event|
|
75
42
|
vma.buf.set_pos(buffer.cursor_position)
|
76
43
|
false
|
@@ -115,7 +82,7 @@ class VSourceView < GtkSource::View
|
|
115
82
|
# Gtk::GestureDrag
|
116
83
|
# Gtk::ShortcutController
|
117
84
|
|
118
|
-
if
|
85
|
+
if ![@click, @dt].include?(ctr) and [Gtk::DropControllerMotion, Gtk::DropTarget, Gtk::GestureDrag, Gtk::GestureClick, Gtk::EventControllerKey].include?(ctr.class)
|
119
86
|
to_remove << ctr
|
120
87
|
end
|
121
88
|
}
|
@@ -157,11 +124,8 @@ class VSourceView < GtkSource::View
|
|
157
124
|
uri = v.value.gsub(/\r\n$/, "")
|
158
125
|
end
|
159
126
|
debug "dt,drop #{v.value},#{x},#{y}", 2
|
160
|
-
|
161
|
-
|
162
|
-
buf.handle_drag_and_drop(fp)
|
163
|
-
rescue URI::InvalidURIError
|
164
|
-
end
|
127
|
+
fp = uri_to_path(uri)
|
128
|
+
buf.handle_drag_and_drop(fp) if !fp.nil?
|
165
129
|
true
|
166
130
|
end
|
167
131
|
|
@@ -422,15 +386,15 @@ class VSourceView < GtkSource::View
|
|
422
386
|
|
423
387
|
keynfo = { :key_str => key_str, :key_name => keyname, :keyval => keyval }
|
424
388
|
debug keynfo.inspect
|
425
|
-
#
|
389
|
+
# vma.kbd.match_key_conf(key_str, nil, :key_press)
|
426
390
|
# debug "key_str=#{key_str} key_"
|
427
391
|
|
428
392
|
if key_str != "" # or prefixed_key_str != ""
|
429
393
|
if sig == :key_release and keyval == @last_keyval
|
430
|
-
|
394
|
+
vma.kbd.match_key_conf(key_str + "!", nil, :key_release)
|
431
395
|
@last_event = [keynfo, :key_release]
|
432
396
|
elsif sig == :key_press
|
433
|
-
|
397
|
+
vma.kbd.match_key_conf(key_str, nil, :key_press)
|
434
398
|
@last_event = [keynfo, key_str, :key_press]
|
435
399
|
end
|
436
400
|
end
|
@@ -669,3 +633,4 @@ class VSourceView < GtkSource::View
|
|
669
633
|
end
|
670
634
|
end #end draw_cursor
|
671
635
|
end
|
636
|
+
|
data/lib/vimamsa/key_actions.rb
CHANGED
@@ -19,12 +19,12 @@ def jump_to_next_edit
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def is_command_mode()
|
22
|
-
return true if
|
22
|
+
return true if vma.kbd.mode_root_state.to_s() == "C"
|
23
23
|
return false
|
24
24
|
end
|
25
25
|
|
26
26
|
def is_visual_mode()
|
27
|
-
return 1 if
|
27
|
+
return 1 if vma.kbd.mode_root_state.to_s() == "V"
|
28
28
|
return 0
|
29
29
|
end
|
30
30
|
|
@@ -69,7 +69,6 @@ reg_act(:set_executable, proc { buf.set_executable }, "Set current file permissi
|
|
69
69
|
reg_act(:close_current_buffer, proc { bufs.close_current_buffer(true) }, "Close current buffer")
|
70
70
|
reg_act(:comment_selection, proc { buf.comment_selection }, "")
|
71
71
|
reg_act(:delete_char_forward, proc { buf.delete(CURRENT_CHAR_FORWARD) }, "Delete char forward", { :group => [:edit, :basic] })
|
72
|
-
reg_act(:load_theme, proc { load_theme }, "Load theme")
|
73
72
|
reg_act(:gui_file_finder, proc { vma.FileFinder.start_gui }, "Fuzzy file finder")
|
74
73
|
reg_act(:gui_file_history_finder, proc { vma.FileHistory.start_gui }, "Fuzzy file history finder")
|
75
74
|
reg_act(:gui_search_replace, proc { gui_search_replace }, "Search and replace")
|
@@ -85,7 +84,7 @@ reg_act(:set_line_style_h4, proc { buf.set_line_style(:h4) }, "Set cur line as H
|
|
85
84
|
reg_act(:set_line_style_bold, proc { buf.set_line_style(:bold) }, "Set style of current line as bold")
|
86
85
|
reg_act(:set_line_style_title, proc { buf.set_line_style(:title) }, "Set style of current line as title")
|
87
86
|
reg_act(:clear_line_styles, proc { buf.set_line_style(:clear) }, "Clear styles of current line")
|
88
|
-
reg_act(:gui_select_buffer, proc {
|
87
|
+
reg_act(:gui_select_buffer, proc { vma.kbd.set_mode("S"); gui_select_buffer }, "Select buffer")
|
89
88
|
reg_act :open_file_dialog, "open_file_dialog", "Open file"
|
90
89
|
reg_act :minibuffer_end, proc { minibuffer_end }
|
91
90
|
reg_act(:invoke_replace, "invoke_replace", "")
|
@@ -98,6 +97,30 @@ reg_act :delete_to_word_end, proc { buf.delete2(:to_word_end) }, "Delete to file
|
|
98
97
|
reg_act :delete_to_next_word_start, proc { buf.delete2(:to_next_word) }, "Delete to start of next word", { :group => [:edit, :basic] }
|
99
98
|
reg_act :delete_to_line_start, proc { buf.delete2(:to_line_start) }, "Delete to line start", { :group => [:edit, :basic] }
|
100
99
|
|
100
|
+
|
101
|
+
reg_act(:ack_search, proc { gui_ack }, "")
|
102
|
+
|
103
|
+
reg_act(:copy_cur_line, proc {buf.copy_line}, "Copy the current line")
|
104
|
+
reg_act(:paste_before_cursor, proc {buf.paste(BEFORE)}, "Paste text before the cursor")
|
105
|
+
reg_act(:paste_after_cursor, proc {buf.paste(AFTER)}, "Paste text after the cursor")
|
106
|
+
reg_act(:redo, proc {buf.redo()}, "Redo the last undone action")
|
107
|
+
reg_act(:undo, proc {buf.undo()}, "Undo the last action")
|
108
|
+
reg_act(:jump_end_of_line, proc { buf.jump(END_OF_LINE) }, "Move to the end of the current line")
|
109
|
+
reg_act(:jump_end_of_buffer, proc {buf.jump(END_OF_BUFFER)}, "Move to the end of the buffer")
|
110
|
+
reg_act(:jump_start_of_buffer, proc { buf.jump(START_OF_BUFFER) }, "Move to the start of the buffer")
|
111
|
+
reg_act(:jump_beginning_of_line, proc { buf.jump(BEGINNING_OF_LINE) }, "Move to the beginning of the current line")
|
112
|
+
reg_act(:jump_next_word_end, proc { buf.jump_word(FORWARD,WORD_END) }, "Jump to the end of the next word")
|
113
|
+
reg_act(:jump_prev_word_start, proc { buf.jump_word(BACKWARD,WORD_START) }, "Jump to the start of the previous word")
|
114
|
+
reg_act(:jump_next_word_start, proc { buf.jump_word(FORWARD,WORD_START) }, "Jump to the start of the next word")
|
115
|
+
reg_act(:insert_mode, proc { vma.kbd.set_mode(:insert) }, "Switch to INSERT mode")
|
116
|
+
reg_act(:prev_mode, proc { vma.kbd.to_previous_mode }, "Return to the previous mode")
|
117
|
+
reg_act(:move_prev_line, proc { buf.move(BACKWARD_LINE) }, "Move the cursor to the previous line")
|
118
|
+
reg_act(:move_next_line, proc { buf.move(FORWARD_LINE) }, "Move the cursor to the next line")
|
119
|
+
reg_act(:move_backward_char, proc { buf.move(BACKWARD_CHAR) }, "Move one character backward")
|
120
|
+
reg_act(:start_visual_mode, proc { buf.start_selection;vma.kbd.set_mode(:visual) }, "Enter VISUAL mode (for selections)")
|
121
|
+
reg_act(:jump_last_edit, proc { buf.jump_to_last_edit }, "Jump to the last edit location")
|
122
|
+
|
123
|
+
|
101
124
|
reg_act :start_browse_mode, proc {
|
102
125
|
vma.kbd.set_mode(:browse)
|
103
126
|
bufs.reset_navigation
|
@@ -7,8 +7,8 @@
|
|
7
7
|
#
|
8
8
|
# Change mode from INSERT into COMMAND when ctrl key is released immediately
|
9
9
|
# after it has been pressed (there are no other key events between key press and key release).
|
10
|
-
# 'I ctrl!'=> '
|
11
|
-
# 'C ctrl!'=> '
|
10
|
+
# 'I ctrl!'=> 'vma.kbd.set_mode(:command)',
|
11
|
+
# 'C ctrl!'=> 'vma.kbd.set_mode(:insert)',
|
12
12
|
|
13
13
|
#
|
14
14
|
# In command mode: press keys "," "r" "v" and "b" sequentially.
|
@@ -18,9 +18,8 @@
|
|
18
18
|
# 'I ctrl-a'=> 'vma.buf.jump(BEGINNING_OF_LINE)',
|
19
19
|
#
|
20
20
|
|
21
|
-
|
22
21
|
class State
|
23
|
-
attr_accessor :key_name, :eval_rule, :children, :action, :label, :major_modes, :level, :cursor_type
|
22
|
+
attr_accessor :key_name, :eval_rule, :children, :action, :label, :major_modes, :level, :cursor_type, :keywords
|
24
23
|
attr_reader :cur_mode, :scope
|
25
24
|
|
26
25
|
def initialize(key_name, eval_rule = "", ctype = :command, scope: :buffer)
|
@@ -29,6 +28,7 @@ class State
|
|
29
28
|
@children = []
|
30
29
|
@scope = scope
|
31
30
|
@major_modes = []
|
31
|
+
@keywords = []
|
32
32
|
@action = nil
|
33
33
|
@level = 0
|
34
34
|
@cursor_type = ctype
|
@@ -86,7 +86,7 @@ class KeyBindingTree
|
|
86
86
|
|
87
87
|
def set_mode_stack(ms)
|
88
88
|
debug "set_mode_stack(#{ms})", 2
|
89
|
-
show_caller if cnf.debug? # TODO: remove
|
89
|
+
show_caller if cnf.debug? # TODO: remove
|
90
90
|
@default_mode_stack = ms
|
91
91
|
label = @default_mode_stack[-1]
|
92
92
|
@match_state = [@modes[label]]
|
@@ -110,7 +110,7 @@ class KeyBindingTree
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def to_previous_mode()
|
113
|
-
debug "to_previous_mode",2
|
113
|
+
debug "to_previous_mode", 2
|
114
114
|
debug @default_mode_stack
|
115
115
|
if @default_mode_stack.size > 1
|
116
116
|
@default_mode_stack.pop
|
@@ -135,7 +135,6 @@ class KeyBindingTree
|
|
135
135
|
@modes[label] = mode
|
136
136
|
if @root.nil?
|
137
137
|
show_caller
|
138
|
-
Ripl.start :binding => binding
|
139
138
|
end
|
140
139
|
@root.children << mode
|
141
140
|
mode.major_modes << major_mode_label
|
@@ -165,6 +164,7 @@ class KeyBindingTree
|
|
165
164
|
|
166
165
|
def match(key_name)
|
167
166
|
new_state = []
|
167
|
+
debug = false
|
168
168
|
@match_state.each { |parent|
|
169
169
|
parent.children.each { |c|
|
170
170
|
# printf(" KEY MATCH: ")
|
@@ -174,6 +174,9 @@ class KeyBindingTree
|
|
174
174
|
elsif c.key_name == key_name and c.eval_rule != ""
|
175
175
|
debug "CHECK EVAL: #{c.eval_rule}"
|
176
176
|
if eval(c.eval_rule)
|
177
|
+
# if eval_rule.match(/macro/)
|
178
|
+
debug = true
|
179
|
+
# end
|
177
180
|
new_state << c
|
178
181
|
debug "EVAL TRUE"
|
179
182
|
else
|
@@ -183,6 +186,10 @@ class KeyBindingTree
|
|
183
186
|
}
|
184
187
|
}
|
185
188
|
|
189
|
+
if debug
|
190
|
+
# require "pry"; binding.pry
|
191
|
+
end
|
192
|
+
|
186
193
|
if new_state.any? # Match found
|
187
194
|
@match_state = new_state
|
188
195
|
return new_state
|
@@ -262,14 +269,66 @@ class KeyBindingTree
|
|
262
269
|
@state_trail = [@mode_root_state]
|
263
270
|
end
|
264
271
|
|
272
|
+
def get_by_keywords(modes: [], keywords: [])
|
273
|
+
s = ""
|
274
|
+
stack = [[@root, ""]]
|
275
|
+
lines = []
|
276
|
+
|
277
|
+
# Traverse the tree (class State objects) using a stack
|
278
|
+
while stack.any?
|
279
|
+
t, p = *stack.pop # t = current state, p = current path
|
280
|
+
if t.children.any?
|
281
|
+
t.children.reverse.each { |c|
|
282
|
+
|
283
|
+
# Restrict by modes if specified
|
284
|
+
if c.level == 1 and !modes.empty?
|
285
|
+
next if !modes.include?(c.key_name)
|
286
|
+
end
|
287
|
+
|
288
|
+
if c.eval_rule.size > 0
|
289
|
+
new_p = "#{p} #{c.key_name}(#{c.eval_rule})"
|
290
|
+
else
|
291
|
+
if c.level == 1
|
292
|
+
new_p = "#{p} [#{c.key_name}]"
|
293
|
+
else
|
294
|
+
new_p = "#{p} #{c.key_name}"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
stack << [c, new_p]
|
298
|
+
}
|
299
|
+
# stack.concat[t.children]
|
300
|
+
|
301
|
+
else
|
302
|
+
method_desc = t.action
|
303
|
+
if t.action.class == Symbol
|
304
|
+
if vma.actions.include?(t.action)
|
305
|
+
a = vma.actions[t.action].method_name
|
306
|
+
if !a.nil? and !a.empty?
|
307
|
+
method_desc = a
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
if (keywords - t.keywords).empty? # All keywords are present
|
313
|
+
kw = ""
|
314
|
+
# kw = ", [#{t.keywords.join(",")}]" if !t.keywords.empty?
|
315
|
+
lines << p + " : #{method_desc}#{kw}"
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
s = lines.sort.join("\n")
|
320
|
+
return s
|
321
|
+
end
|
322
|
+
|
265
323
|
# Print key bindings to show as documentation or for debugging
|
266
324
|
def to_s()
|
267
|
-
|
325
|
+
return self.class.to_s
|
268
326
|
s = ""
|
269
327
|
# @cur_state = @root
|
270
328
|
stack = [[@root, ""]]
|
271
329
|
lines = []
|
272
330
|
|
331
|
+
# Traverse the tree (class State objects) using a stack
|
273
332
|
while stack.any?
|
274
333
|
t, p = *stack.pop # t = current state, p = current path
|
275
334
|
if t.children.any?
|
@@ -297,7 +356,9 @@ class KeyBindingTree
|
|
297
356
|
end
|
298
357
|
end
|
299
358
|
|
300
|
-
|
359
|
+
kw = ""
|
360
|
+
# kw = ", " + t.keywords.join(",") if !t.keywords.empty?
|
361
|
+
lines << p + " : #{method_desc}#{kw}"
|
301
362
|
end
|
302
363
|
end
|
303
364
|
s = lines.sort.join("\n")
|
@@ -426,11 +487,15 @@ class KeyBindingTree
|
|
426
487
|
else
|
427
488
|
|
428
489
|
# Don't execute action if one of the states has children
|
490
|
+
# TODO: why?
|
429
491
|
state_with_children = new_state.select { |s| s.children.any? }
|
430
492
|
s_act = new_state.select { |s| s.action != nil }
|
431
493
|
|
432
|
-
if s_act.any? and !state_with_children.any?
|
494
|
+
if s_act.any? #and !state_with_children.any?
|
433
495
|
eval_s = s_act.first.action if eval_s == nil
|
496
|
+
# if eval_s.to_s.match(/end_recording/)
|
497
|
+
# require "pry"; binding.pry
|
498
|
+
# end
|
434
499
|
debug "FOUND MATCH:#{eval_s}"
|
435
500
|
debug "CHAR: #{c}"
|
436
501
|
c.gsub!("\\", %q{\\\\} * 4) # Escape \ -chars
|
@@ -449,7 +514,12 @@ class KeyBindingTree
|
|
449
514
|
return true
|
450
515
|
end
|
451
516
|
|
452
|
-
def bindkey(key, action)
|
517
|
+
def bindkey(key, action, keywords: "")
|
518
|
+
# puts "keywords #{keywords}" if !keywords.empty?
|
519
|
+
if keywords.class == String
|
520
|
+
keywords = keywords.split(" ")
|
521
|
+
end
|
522
|
+
# puts "keywords #{keywords}" if !keywords.empty?
|
453
523
|
if key.class != Array
|
454
524
|
# Handle syntax like :
|
455
525
|
# "X esc || X ctrl!" => "vma.kbd.to_previous_mode",
|
@@ -464,10 +534,10 @@ class KeyBindingTree
|
|
464
534
|
msg = action[2]
|
465
535
|
reg_act(label, proc, msg)
|
466
536
|
end
|
467
|
-
key.each { |k| _bindkey(k, a) }
|
537
|
+
key.each { |k| _bindkey(k, a, keywords: keywords) }
|
468
538
|
end
|
469
539
|
|
470
|
-
def _bindkey(key, action)
|
540
|
+
def _bindkey(key, action, keywords: [])
|
471
541
|
key.strip!
|
472
542
|
key.gsub!(/\s+/, " ")
|
473
543
|
|
@@ -502,15 +572,18 @@ class KeyBindingTree
|
|
502
572
|
fatal_error("Error in keydef #{key.inspect}")
|
503
573
|
end
|
504
574
|
|
575
|
+
# puts "keywords #{keywords}"
|
505
576
|
modes.each { |mode_id|
|
506
|
-
mode_bind_key(mode_id, keydef, action)
|
577
|
+
mode_bind_key(mode_id, keydef, action, keywords: keywords)
|
578
|
+
|
579
|
+
# Map froma actions to keybindings (e.g. to show bindings in menu)
|
507
580
|
@act_bindings[mode_id][action] = keydef
|
508
581
|
}
|
509
582
|
end
|
510
583
|
|
511
584
|
# Binds a keyboard key combination to an action,
|
512
585
|
# for a given keyboard mode like insert ("I") or command ("C")
|
513
|
-
def mode_bind_key(mode_id, keydef, action)
|
586
|
+
def mode_bind_key(mode_id, keydef, action, keywords: [])
|
514
587
|
# debug "mode_bind_key #{mode_id.inspect}, #{keydef.inspect}, #{action.inspect}", 2
|
515
588
|
# Example:
|
516
589
|
# bindkey "C , f", :gui_file_finder
|
@@ -520,7 +593,7 @@ class KeyBindingTree
|
|
520
593
|
set_state(mode_id, "") # TODO: check is ok?
|
521
594
|
start_state = @cur_state
|
522
595
|
|
523
|
-
k_arr = keydef.split
|
596
|
+
k_arr = keydef.split #e.g. definition: "C y e" = > ["C", "y", "e"]
|
524
597
|
|
525
598
|
prev_state = nil
|
526
599
|
s1 = start_state
|
@@ -561,6 +634,7 @@ class KeyBindingTree
|
|
561
634
|
else
|
562
635
|
@cur_state.action = action
|
563
636
|
end
|
637
|
+
@cur_state.keywords = keywords
|
564
638
|
@cur_state = @root
|
565
639
|
end
|
566
640
|
|
@@ -614,13 +688,19 @@ class KeyBindingTree
|
|
614
688
|
end
|
615
689
|
end
|
616
690
|
|
617
|
-
def bindkey(key, action)
|
618
|
-
|
691
|
+
def bindkey(key, action, keywords: "")
|
692
|
+
vma.kbd.bindkey(key, action, keywords: keywords)
|
693
|
+
end
|
694
|
+
|
695
|
+
def add_keys(keywords, to_add)
|
696
|
+
to_add.each { |key, value|
|
697
|
+
bindkey(key, value, keywords: keywords)
|
698
|
+
}
|
619
699
|
end
|
620
700
|
|
621
701
|
def exec_action(action)
|
622
|
-
|
623
|
-
|
702
|
+
vma.kbd.last_action = vma.kbd.cur_action
|
703
|
+
vma.kbd.cur_action = action
|
624
704
|
if action.class == Symbol
|
625
705
|
return call_action(action)
|
626
706
|
elsif action.class == Proc
|
@@ -630,14 +710,70 @@ def exec_action(action)
|
|
630
710
|
end
|
631
711
|
end
|
632
712
|
|
713
|
+
def show_key_bindings()
|
714
|
+
kbd_s = "❙Key bindings❙\n"
|
715
|
+
kbd_s << "\n⦁[Mode] <keys> : <action>⦁\n"
|
716
|
+
done = []
|
717
|
+
|
718
|
+
kbd_s << "[B]=Browse, [C]=Command, [I]=Insert, [V]=Visual\n"
|
719
|
+
kbd_s << "<key>!: Press <key> once, release before pressing any other keys\n"
|
720
|
+
kbd_s << "===============================================\n"
|
721
|
+
kbd_s << "◼ Basic\n"
|
722
|
+
kbd_s << "◼◼ Command mode\n"
|
723
|
+
|
724
|
+
x = vma.kbd.get_by_keywords(modes: ["C"], keywords: ["intro"])
|
725
|
+
done.concat(x.lines); kbd_s << x
|
726
|
+
|
727
|
+
kbd_s << "\n"
|
728
|
+
kbd_s << "◼◼ Insert mode\n"
|
729
|
+
x = vma.kbd.get_by_keywords(modes: ["I"], keywords: ["intro"])
|
730
|
+
done.concat(x.lines); kbd_s << x
|
731
|
+
kbd_s << "\n"
|
732
|
+
kbd_s << "◼◼ Visual mode\n"
|
733
|
+
x = vma.kbd.get_by_keywords(modes: ["V"], keywords: ["intro"])
|
734
|
+
done.concat(x.lines); kbd_s << x
|
735
|
+
kbd_s << "\n"
|
736
|
+
|
737
|
+
kbd_s << "◼ Core\n"
|
738
|
+
x = vma.kbd.get_by_keywords(modes: [], keywords: ["core"])
|
739
|
+
x << vma.kbd.get_by_keywords(modes: ["X"], keywords: ["intro"])
|
740
|
+
|
741
|
+
done.concat(x.lines); kbd_s << x
|
742
|
+
kbd_s << "\n"
|
743
|
+
|
744
|
+
kbd_s << "◼ Debug / Experimental\n"
|
745
|
+
x = vma.kbd.get_by_keywords(modes: [], keywords: ["experimental"])
|
746
|
+
done.concat(x.lines); kbd_s << x
|
747
|
+
kbd_s << "\n"
|
748
|
+
|
749
|
+
kbd_s << "◼ Others\n"
|
750
|
+
# x = vma.kbd.get_by_keywords(modes: [], keywords:["experimental"])
|
751
|
+
# x = vma.kbd.to_s
|
752
|
+
x = vma.kbd.get_by_keywords(modes: [], keywords: [])
|
753
|
+
done << x.lines - done
|
754
|
+
kbd_s << (x.lines - done).join
|
755
|
+
kbd_s << "\n"
|
756
|
+
|
757
|
+
kbd_s << "===============================================\n"
|
758
|
+
# x = vma.kbd.to_s
|
759
|
+
# # require "pry"; binding.pry
|
760
|
+
# done << x.lines - done
|
761
|
+
# kbd_s << (x.lines - done).join
|
762
|
+
# kbd_s << "\n"
|
763
|
+
# kbd_s << "===============================================\n"
|
764
|
+
b = create_new_buffer(kbd_s, "key-bindings")
|
765
|
+
gui_set_file_lang(b.id, "hyperplaintext")
|
766
|
+
#
|
767
|
+
end
|
768
|
+
|
633
769
|
# Try to clear modifiers when program loses focus
|
634
770
|
# e.g. after alt-tab
|
635
771
|
# TODO
|
636
772
|
# def focus_out
|
637
|
-
|
638
|
-
|
773
|
+
# debug "RB Clear modifiers"
|
774
|
+
# vma.kbd.clear_modifiers()
|
639
775
|
# end
|
640
776
|
|
641
777
|
# def handle_key_event(event)
|
642
|
-
|
778
|
+
# vma.kbd.handle_key_event(event)
|
643
779
|
# end
|
@@ -4,6 +4,7 @@ vma.kbd.add_mode("V", :visual, :visual)
|
|
4
4
|
vma.kbd.add_mode("M", :minibuffer) #TODO: needed?
|
5
5
|
vma.kbd.add_mode("R", :readchar)
|
6
6
|
vma.kbd.add_minor_mode("audio", :audio, :command)
|
7
|
+
vma.kbd.add_minor_mode("macro", :macro, :command)
|
7
8
|
vma.kbd.add_mode("B", :browse, :browse, scope: :editor)
|
8
9
|
vma.kbd.add_mode("X", :replace, :replace, name: "Replace")
|
9
10
|
vma.kbd.set_default_mode(:command)
|
@@ -40,95 +41,44 @@ def insert_move(op)
|
|
40
41
|
_insert_move(op)
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
bindkey "C , t 2", :set_line_style_h2
|
74
|
-
bindkey "C , t 3", :set_line_style_h3
|
75
|
-
bindkey "C , t 4", :set_line_style_h4
|
76
|
-
bindkey "C , t b", :set_line_style_bold
|
77
|
-
bindkey "C , t t", :set_line_style_title
|
78
|
-
bindkey "C , t c", :clear_line_styles
|
79
|
-
bindkey "C , b", :start_buf_manager
|
80
|
-
bindkey "C , w", :toggle_active_window
|
81
|
-
bindkey "C , , w", :toggle_two_column
|
82
|
-
|
83
|
-
bindkey "C , u s", :audio_stop
|
84
|
-
bindkey "C , m a", "vma.kbd.set_mode(:audio)"
|
85
|
-
bindkey "audio s", :audio_stop
|
86
|
-
bindkey "audio f || audio right", [:audio_forward, proc { Audio.seek_forward }, "Seek forward in audio stream"]
|
87
|
-
bindkey "audio left", [:audio_backward, proc { Audio.seek_forward(-5.0) }, "Seek backward in audio stream"]
|
88
|
-
|
89
|
-
bindkey "audio space", :audio_stop
|
90
|
-
bindkey "audio q || audio esc", "vma.kbd.to_previous_mode"
|
44
|
+
add_keys "intro", {
|
45
|
+
"C y y" => :copy_cur_line,
|
46
|
+
"C P" => :paste_before_cursor,
|
47
|
+
"C p" => :paste_after_cursor,
|
48
|
+
"C v" => :start_visual_mode,
|
49
|
+
"C ctrl-r" => :redo,
|
50
|
+
"C u" => :undo,
|
51
|
+
"VC O" => :jump_end_of_line,
|
52
|
+
# NOTE: "G(condition)" need to be defined before "G"
|
53
|
+
"VC G(vma.kbd.next_command_count!=nil)" => "buf.jump_to_line()",
|
54
|
+
"VC G" => :jump_end_of_buffer,
|
55
|
+
"VC g ;" => :jump_last_edit,
|
56
|
+
"VC g g" => :jump_start_of_buffer,
|
57
|
+
"VC e" => :jump_next_word_end,
|
58
|
+
"VC b" => :jump_prev_word_start,
|
59
|
+
"VC w" => :jump_next_word_start,
|
60
|
+
"V esc" => "buf.end_visual_mode",
|
61
|
+
"V ctrl!" => "buf.end_visual_mode",
|
62
|
+
|
63
|
+
"C ctrl!" => :insert_mode,
|
64
|
+
"C i" => :insert_mode,
|
65
|
+
"I esc || I ctrl!" => :prev_mode,
|
66
|
+
"IX alt-b" => :jump_prev_word_start,
|
67
|
+
"IX alt-f" => :jump_next_word_start,
|
68
|
+
"IX ctrl-e" => :jump_end_of_line,
|
69
|
+
"IX ctrl-p" => :move_prev_line,
|
70
|
+
"IX ctrl-n" => :move_next_line,
|
71
|
+
"IX ctrl-b" => :move_backward_char,
|
72
|
+
"IX ctrl-a" => :jump_beginning_of_line,
|
73
|
+
}
|
91
74
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
bindkey "C d w", :delete_to_next_word_start
|
97
|
-
|
98
|
-
bindkey "C d 0", :delete_to_line_start
|
99
|
-
bindkey "C , , f", :file_finder
|
100
|
-
bindkey "VC h", :e_move_backward_char
|
101
|
-
bindkey "C , , .", :backup_all_buffers
|
102
|
-
bindkey "C z ", :start_browse_mode
|
103
|
-
bindkey "B h", :history_switch_backwards
|
104
|
-
bindkey "B l", :history_switch_forwards
|
105
|
-
bindkey "B z", "center_on_current_line();call_action(:exit_browse_mode)"
|
106
|
-
bindkey "B enter || B return || B esc || B j || B ctrl!", :exit_browse_mode
|
107
|
-
bindkey "B s", :page_up
|
108
|
-
bindkey "B d", :page_down
|
109
|
-
bindkey "B r", proc { vma.gui.page_down(multip: 0.25) }
|
110
|
-
bindkey "B e", proc { vma.gui.page_up(multip: 0.25) }
|
111
|
-
|
112
|
-
bindkey "B i", :jump_to_start_of_buffer
|
113
|
-
bindkey "B o", :jump_to_end_of_buffer
|
114
|
-
bindkey "B c", :close_current_buffer
|
115
|
-
bindkey "B ;", "buf.jump_to_last_edit"
|
116
|
-
bindkey "B q", :jump_to_last_edit
|
117
|
-
bindkey "B w", :jump_to_next_edit
|
118
|
-
# bindkey "C , d", :diff_buffer
|
119
|
-
#bindkey 'C , g', proc{invoke_grep_search}
|
120
|
-
bindkey "C , v", :auto_indent_buffer
|
121
|
-
bindkey "C , , d", :savedebug
|
122
|
-
bindkey "C , , u", :update_file_index
|
123
|
-
bindkey "C , s a", :buf_save_as
|
124
|
-
bindkey "C d d", [:delete_line, proc { buf.delete_line }, "Delete current line"]
|
125
|
-
bindkey "C enter || C return", [:line_action, proc { buf.handle_line_action() }, "Line action"]
|
126
|
-
bindkey "C p", [:paste_after, proc { buf.paste(AFTER) }, ""] # TODO: implement as replace for visual mode
|
127
|
-
bindkey "V d", [:delete_selection, proc { buf.delete(SELECTION) }, ""]
|
128
|
-
bindkey "V a d", [:delete_append_selection, proc { buf.delete(SELECTION, :append) }, "Delete and append selection"]
|
75
|
+
add_keys "intro delete", {
|
76
|
+
"C x" => :delete_char_forward,
|
77
|
+
"C d d" => [:delete_line, proc { buf.delete_line }, "Delete current line"]
|
78
|
+
}
|
129
79
|
|
130
80
|
|
131
|
-
|
81
|
+
add_keys "core", {
|
132
82
|
|
133
83
|
# File handling
|
134
84
|
"C ctrl-s" => :buf_save,
|
@@ -185,9 +135,6 @@ default_keys = {
|
|
185
135
|
"VCX down" => "buf.move(FORWARD_LINE)",
|
186
136
|
"VCX up" => "buf.move(BACKWARD_LINE)",
|
187
137
|
|
188
|
-
"VC w" => "buf.jump_word(FORWARD,WORD_START)",
|
189
|
-
"VC b" => "buf.jump_word(BACKWARD,WORD_START)",
|
190
|
-
"VC e" => "buf.jump_word(FORWARD,WORD_END)",
|
191
138
|
# 'C '=> 'buf.jump_word(BACKWARD,END)',#TODO
|
192
139
|
"VC f <char>" => "buf.jump_to_next_instance_of_char(<char>)",
|
193
140
|
"VC F <char>" => "buf.jump_to_next_instance_of_char(<char>,BACKWARD)",
|
@@ -197,14 +144,10 @@ default_keys = {
|
|
197
144
|
"VC /[1-9]/" => "vma.kbd.set_next_command_count(<char>)",
|
198
145
|
# 'VC number=/[0-9]/+ g'=> 'jump_to_line(<number>)',
|
199
146
|
# 'VC X=/[0-9]/+ * Y=/[0-9]/+ '=> 'x_times_y(<X>,<Y>)',
|
200
|
-
"VC G(vma.kbd.next_command_count!=nil)" => "buf.jump_to_line()",
|
201
147
|
"VC 0(vma.kbd.next_command_count!=nil)" => "set_next_command_count(<char>)",
|
202
148
|
"VC 0(vma.kbd.next_command_count==nil)" => "buf.jump(BEGINNING_OF_LINE)",
|
203
149
|
# 'C 0'=> 'buf.jump(BEGINNING_OF_LINE)',
|
204
|
-
"VC g g" => "buf.jump(START_OF_BUFFER)",
|
205
|
-
"VC g ;" => "buf.jump_to_last_edit",
|
206
150
|
"VC ^" => "buf.jump(BEGINNING_OF_LINE)",
|
207
|
-
"VC G" => "buf.jump(END_OF_BUFFER)",
|
208
151
|
# 'VC z z' => 'center_on_current_line',
|
209
152
|
"VC *" => "buf.jump_to_next_instance_of_word",
|
210
153
|
|
@@ -221,17 +164,8 @@ default_keys = {
|
|
221
164
|
|
222
165
|
"C C" => :content_search,
|
223
166
|
|
224
|
-
# Debug
|
225
|
-
"C , d r p" => "start_ripl",
|
226
|
-
"C , d o" => "vma.gui.clear_overlay",
|
227
|
-
"C , D" => "debug_print_buffer",
|
228
167
|
"C , c s" => "bufs.close_scrap_buffers",
|
229
|
-
"C , d b" => "debug_print_buffer",
|
230
|
-
"C , d c" => "debug_dump_clipboard",
|
231
|
-
"C , d d" => "debug_dump_deltas",
|
232
|
-
"C , d m" => :kbd_dump_state,
|
233
168
|
|
234
|
-
"VC O" => "buf.jump(END_OF_LINE)",
|
235
169
|
"VC $" => "buf.jump(END_OF_LINE)",
|
236
170
|
|
237
171
|
"C o" => 'buf.jump(END_OF_LINE);buf.insert_txt("\n");vma.kbd.set_mode(:insert)',
|
@@ -240,23 +174,18 @@ default_keys = {
|
|
240
174
|
"C I" => "buf.jump(FIRST_NON_WHITESPACE);vma.kbd.set_mode(:insert)",
|
241
175
|
"C a" => "buf.move(FORWARD_CHAR);vma.kbd.set_mode(:insert)",
|
242
176
|
"C J" => "buf.join_lines()",
|
243
|
-
"C u" => "buf.undo()",
|
244
177
|
|
245
178
|
"C ^" => "buf.jump(BEGINNING_OF_LINE)",
|
246
179
|
# "C /[1-9]/" => "vma.kbd.set_next_command_count(<char>)",
|
247
180
|
|
248
181
|
# Command mode only:
|
249
|
-
"C ctrl-r" => "buf.redo()", # TODO:???
|
250
|
-
"C v" => "buf.start_selection;vma.kbd.set_mode(:visual)",
|
251
|
-
"C P" => "buf.paste(BEFORE)", # TODO: implement as replace for visual mode
|
252
182
|
"C space <char>" => "buf.insert_txt(<char>)",
|
253
183
|
"C space space" => "buf.insert_txt(' ')",
|
254
|
-
"C y y" => "buf.copy_line",
|
255
184
|
"C y O" => "buf.copy(:to_line_end)",
|
256
185
|
"C y 0" => "buf.copy(:to_line_start)",
|
257
186
|
"C y e" => "buf.copy(:to_word_end)", # TODO
|
258
187
|
#### Deleting
|
259
|
-
"C x" => "buf.delete(CURRENT_CHAR_FORWARD)",
|
188
|
+
# "C x" => "buf.delete(CURRENT_CHAR_FORWARD)",
|
260
189
|
# 'C d k'=> 'delete_line(BACKWARD)', #TODO
|
261
190
|
# 'C d j'=> 'delete_line(FORWARD)', #TODO
|
262
191
|
# 'C d d'=> 'buf.delete_cur_line',
|
@@ -279,8 +208,7 @@ default_keys = {
|
|
279
208
|
# 'C 0($next_command_count==nil)'=> 'jump_to_beginning_of_line',
|
280
209
|
|
281
210
|
# Visual mode only:
|
282
|
-
|
283
|
-
"V ctrl!" => "buf.end_visual_mode",
|
211
|
+
|
284
212
|
"V y" => "buf.copy_active_selection()",
|
285
213
|
"V a y" => "buf.copy_active_selection(:append)",
|
286
214
|
"V g U" => :selection_upcase,
|
@@ -305,9 +233,7 @@ default_keys = {
|
|
305
233
|
# "CV ''" =>'jump_to_mark(NEXT_MARK)', #TODO
|
306
234
|
|
307
235
|
# Switch to another mode
|
308
|
-
"C i" => "vma.kbd.set_mode(:insert)",
|
309
236
|
"C R" => "vma.kbd.set_mode(:replace)",
|
310
|
-
"C ctrl!" => "vma.kbd.set_mode(:insert)",
|
311
237
|
|
312
238
|
# Replace mode
|
313
239
|
"X esc || X ctrl!" => "vma.kbd.to_previous_mode",
|
@@ -316,49 +242,140 @@ default_keys = {
|
|
316
242
|
# Macros
|
317
243
|
# (experimental, may not work correctly)
|
318
244
|
# "C q a" => 'vma.macro.start_recording("a")',
|
319
|
-
|
320
|
-
"
|
245
|
+
|
246
|
+
"macro q" => "vma.kbd.to_previous_mode; vma.macro.end_recording",
|
247
|
+
"macro q z" => "vma.kbd.to_previous_mode; vma.macro.end_recording",
|
248
|
+
|
249
|
+
# "VC q(vma.macro.is_recording==true)" => "vma.macro.end_recording", # TODO: does not work
|
250
|
+
# "VC o(vma.macro.is_recording==true)" => "vma.macro.end_recording", # TODO: does not work
|
251
|
+
# "VC q q(vma.macro.is_recording==true)" => "vma.macro.end_recording",
|
252
|
+
"VC q <char>" => "vma.kbd.set_mode(:macro);vma.macro.start_recording(<char>)",
|
321
253
|
# 'C q'=> 'vma.macro.end_recording', #TODO
|
322
|
-
"C q v" => "vma.macro.end_recording",
|
254
|
+
"C q v" => "vma.kbd.to_previous_mode; vma.macro.end_recording",
|
323
255
|
# 'C v'=> 'vma.macro.end_recording',
|
324
256
|
# "C M" => 'vma.macro.run_last_macro',
|
325
257
|
"C @ <char>" => "vma.macro.run_macro(<char>)",
|
326
258
|
"C , m S" => 'vma.macro.save_macro("a")',
|
327
259
|
"C , m s" => "vma.macro.save",
|
328
|
-
"C , t r" => "run_tests()",
|
329
260
|
|
330
261
|
# "C ." => "repeat_last_action", # TODO
|
331
262
|
"VC ;" => "repeat_last_find",
|
332
263
|
# "CV Q" => :quit,
|
333
264
|
"CV ctrl-q" => :quit,
|
334
|
-
"CV , R" => "restart_application",
|
335
265
|
# "I ctrl!" => "vma.kbd.to_previous_mode",
|
336
266
|
"C shift! s" => "buf.save",
|
337
267
|
"I ctrl-s" => "buf.save",
|
338
268
|
"I <char>" => "buf.insert_txt(<char>)",
|
339
|
-
"I esc || I ctrl!" => "vma.kbd.to_previous_mode",
|
340
269
|
|
341
270
|
"I ctrl-d" => "buf.delete2(:to_word_end)",
|
342
271
|
|
343
272
|
# Insert and Replace modes: Moving
|
344
|
-
"IX ctrl-a" => "buf.jump(BEGINNING_OF_LINE)",
|
345
|
-
"IX ctrl-b" => "buf.move(BACKWARD_CHAR)",
|
346
273
|
"IX ctrl-f" => "buf.move(FORWARD_CHAR)",
|
347
|
-
"IX ctrl-n" => "buf.move(FORWARD_LINE)",
|
348
|
-
"IX ctrl-p" => "buf.move(BACKWARD_LINE)",
|
349
|
-
"IX ctrl-e" => "buf.jump(END_OF_LINE)", # context: mode:I, buttons down: {C}
|
350
|
-
"IX alt-f" => "buf.jump_word(FORWARD,WORD_START)",
|
351
|
-
"IX alt-b" => "buf.jump_word(BACKWARD,WORD_START)",
|
352
274
|
|
353
|
-
"I ctrl-h" => :show_autocomplete,
|
354
275
|
"I ctrl-j" => "vma.buf.view.hide_completions",
|
355
276
|
|
356
277
|
"I space" => 'buf.insert_txt(" ")',
|
357
278
|
# "I return" => 'buf.insert_new_line()',
|
279
|
+
|
280
|
+
"CI ctrl-o" => :open_file_dialog,
|
281
|
+
"C , a" => :ack_search,
|
282
|
+
"C d w" => :delete_to_next_word_start,
|
283
|
+
|
284
|
+
"C d 0" => :delete_to_line_start,
|
285
|
+
"C , , f" => :file_finder,
|
286
|
+
"VC h" => :e_move_backward_char,
|
287
|
+
"C , , ." => :backup_all_buffers,
|
288
|
+
"C z " => :start_browse_mode,
|
289
|
+
"B h" => :history_switch_backwards,
|
290
|
+
"B l" => :history_switch_forwards,
|
291
|
+
"B z" => "center_on_current_line();call_action(:exit_browse_mode)",
|
292
|
+
"B enter || B return || B esc || B j || B ctrl!" => :exit_browse_mode,
|
293
|
+
"B s" => :page_up,
|
294
|
+
"B d" => :page_down,
|
295
|
+
"B r" => proc { vma.gui.page_down(multip: 0.25) },
|
296
|
+
"B e" => proc { vma.gui.page_up(multip: 0.25) },
|
297
|
+
|
298
|
+
"B i" => :jump_to_start_of_buffer,
|
299
|
+
"B o" => :jump_to_end_of_buffer,
|
300
|
+
"B c" => :close_current_buffer,
|
301
|
+
"B ;" => :jump_last_edit,
|
302
|
+
"B q" => :jump_to_last_edit,
|
303
|
+
"B w" => :jump_to_next_edit,
|
304
|
+
"C , v" => :auto_indent_buffer,
|
305
|
+
"C , , u" => :update_file_index,
|
306
|
+
"C , s a" => :buf_save_as,
|
307
|
+
"VC , r r" => :gui_search_replace,
|
308
|
+
"V , t b" => :set_style_bold,
|
309
|
+
"V , t l" => :set_style_link,
|
310
|
+
"V J" => :V_join_lines,
|
311
|
+
"V , t c" => :clear_formats,
|
312
|
+
"C , t h" => :set_line_style_heading,
|
313
|
+
"C , t 1" => :set_line_style_h1,
|
314
|
+
"C , t 2" => :set_line_style_h2,
|
315
|
+
"C , t 3" => :set_line_style_h3,
|
316
|
+
"C , t 4" => :set_line_style_h4,
|
317
|
+
"C , t b" => :set_line_style_bold,
|
318
|
+
"C , t t" => :set_line_style_title,
|
319
|
+
"C , t c" => :clear_line_styles,
|
320
|
+
"C , b" => :start_buf_manager,
|
321
|
+
"C , w" => :toggle_active_window,
|
322
|
+
"C , , w" => :toggle_two_column,
|
323
|
+
|
324
|
+
"VC s" => :easy_jump,
|
325
|
+
"I alt-s" => :easy_jump,
|
326
|
+
"VC , m f" => [:find_macro_gui, proc { vma.macro.find_macro_gui }, "Find named macro"],
|
327
|
+
"C , m n" => [:gui_name_macro, proc { vma.macro.gui_name_macro }, "Name last macro"],
|
328
|
+
"C , j r" => :jump_to_random,
|
329
|
+
"C , ; s k" => :show_key_bindings, #TODO: better binding,
|
330
|
+
"C , , c b" => :put_file_path_to_clipboard, #TODO: better binding or remove?,
|
331
|
+
"C , , e" => :encrypt_file, #TODO: better binding,
|
332
|
+
"C , ; u" => :set_unencrypted, #TODO: better binding,
|
333
|
+
"C , c b" => :close_current_buffer,
|
334
|
+
"V ctrl-c" => :comment_selection,
|
335
|
+
"C , f" => :gui_file_finder,
|
336
|
+
"C , h" => :gui_file_history_finder,
|
337
|
+
"C , z" => :gui_file_finder,
|
338
|
+
|
339
|
+
"C enter || C return" => [:line_action, proc { buf.handle_line_action() }, "Line action"],
|
340
|
+
"V d" => [:delete_selection, proc { buf.delete(SELECTION) }, ""],
|
341
|
+
"V a d" => [:delete_append_selection, proc { buf.delete(SELECTION, :append) }, "Delete and append selection"]
|
358
342
|
}
|
359
343
|
|
360
|
-
bindkey "
|
344
|
+
bindkey ["VCB M", "B m"], :run_last_macro
|
345
|
+
|
346
|
+
add_keys "experimental", {
|
347
|
+
"C ` k" => :lsp_debug,
|
348
|
+
"C ` j" => :lsp_jump_to_definition,
|
349
|
+
"C , u s" => :audio_stop,
|
361
350
|
|
362
|
-
|
363
|
-
|
351
|
+
"C , t r" => "run_tests()",
|
352
|
+
# "CV , R" => "restart_application", #TODO: does not work
|
353
|
+
"I ctrl-h" => :show_autocomplete, #TODO: does not work
|
354
|
+
"C , d m" => :kbd_dump_state,
|
355
|
+
"C , d d" => "debug_dump_deltas",
|
356
|
+
"C , d c" => "debug_dump_clipboard",
|
357
|
+
"C , d b" => "debug_print_buffer",
|
358
|
+
"C , D" => "debug_print_buffer",
|
359
|
+
"C , d o" => "vma.gui.clear_overlay",
|
360
|
+
# Debug
|
361
|
+
"C , d r p" => 'require "pry"; binding.pry', #TODO
|
362
|
+
#bindkey 'C , g', proc{invoke_grep_search}
|
363
|
+
# bindkey "C , d", :diff_buffer
|
364
|
+
"C , , d" => :savedebug,
|
365
|
+
"C , m a" => "vma.kbd.set_mode(:audio)",
|
366
|
+
"audio s" => :audio_stop,
|
364
367
|
}
|
368
|
+
|
369
|
+
|
370
|
+
bindkey "audio f || audio right", [:audio_forward, proc { Audio.seek_forward }, "Seek forward in audio stream"]
|
371
|
+
bindkey "audio left", [:audio_backward, proc { Audio.seek_forward(-5.0) }, "Seek backward in audio stream"]
|
372
|
+
|
373
|
+
bindkey "audio space", :audio_stop
|
374
|
+
bindkey "audio q || audio esc", "vma.kbd.to_previous_mode"
|
375
|
+
|
376
|
+
|
377
|
+
bindkey "C , i p", "generate_password_to_buf(15)"
|
378
|
+
|
379
|
+
# default_keys.each { |key, value|
|
380
|
+
# bindkey(key, value)
|
381
|
+
# }
|
data/lib/vimamsa/util.rb
CHANGED
@@ -3,6 +3,10 @@ require "open3"
|
|
3
3
|
VOWELS = %w(a e i o u)
|
4
4
|
CONSONANTS = %w(b c d f g h j k l m n p q r s t v w x y z)
|
5
5
|
|
6
|
+
def draw_cursor_bug_workaround()
|
7
|
+
DelayExecutioner.exec(id: :bug_workaround_draw_cursor, wait: 1.0, callable: proc { vma.gui.view.draw_cursor(); debug ":bug_workaround_draw_cursor"; false })
|
8
|
+
end
|
9
|
+
|
6
10
|
def running_wayland?
|
7
11
|
sess = ENV["DESKTOP_SESSION"]
|
8
12
|
sess ||= ENV["XDG_SESSION_DESKTOP"]
|
@@ -218,7 +222,7 @@ end
|
|
218
222
|
# Used for image scaling after window resize
|
219
223
|
|
220
224
|
class DelayExecutioner
|
221
|
-
|
225
|
+
attr_accessor :last_run, :wait_before_next
|
222
226
|
# Run 'callable.call' if 'wait' time elapsed from last exec call for this id
|
223
227
|
def self.exec(id:, wait:, callable:)
|
224
228
|
@@h ||= {}
|
@@ -226,6 +230,12 @@ class DelayExecutioner
|
|
226
230
|
if h[id].nil?
|
227
231
|
h[id] = DelayExecutioner.new(wait, callable)
|
228
232
|
end
|
233
|
+
o = h[id]
|
234
|
+
if !o.last_run.nil?
|
235
|
+
# if Time.now - o.last_run < o.wait_before_next
|
236
|
+
# return
|
237
|
+
# end
|
238
|
+
end
|
229
239
|
h[id].run
|
230
240
|
end
|
231
241
|
|
@@ -234,6 +244,8 @@ class DelayExecutioner
|
|
234
244
|
@proc = _proc
|
235
245
|
@lastt = Time.now
|
236
246
|
@thread_running = false
|
247
|
+
@last_run = nil
|
248
|
+
@wait_before_next = 0
|
237
249
|
end
|
238
250
|
|
239
251
|
def start_thread
|
@@ -242,6 +254,7 @@ class DelayExecutioner
|
|
242
254
|
sleep 0.1
|
243
255
|
if Time.now - @lastt > @wait_time
|
244
256
|
@proc.call
|
257
|
+
@last_run = Time.now
|
245
258
|
@thread_running = false
|
246
259
|
break
|
247
260
|
end
|
@@ -344,6 +357,17 @@ def is_existing_file(s)
|
|
344
357
|
return false
|
345
358
|
end
|
346
359
|
|
360
|
+
def uri_to_path(uri)
|
361
|
+
fp = nil
|
362
|
+
begin
|
363
|
+
x = URI::DEFAULT_PARSER.unescape(URI(uri).path)
|
364
|
+
rescue URI::InvalidURIError
|
365
|
+
else
|
366
|
+
fp = x # only if no exception
|
367
|
+
end
|
368
|
+
return fp
|
369
|
+
end
|
370
|
+
|
347
371
|
def is_image_file(fpath)
|
348
372
|
return false if !File.exist?(fpath)
|
349
373
|
# return false if !fpath.match(/.(jpg|jpeg|png)$/i)
|
data/lib/vimamsa/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vimamsa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sami Sieranoja
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -241,6 +241,7 @@ files:
|
|
241
241
|
- exe/vimamsa
|
242
242
|
- ext/vmaext/extconf.rb
|
243
243
|
- ext/vmaext/vmaext.c
|
244
|
+
- install.sh
|
244
245
|
- lang/hyperplaintext.lang
|
245
246
|
- lib/vimamsa.rb
|
246
247
|
- lib/vimamsa/ack.rb
|