vimamsa 0.1.14 → 0.1.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/custom_example.rb +9 -2
- data/lib/vimamsa/actions.rb +1 -2
- data/lib/vimamsa/buffer.rb +79 -31
- data/lib/vimamsa/buffer_changetext.rb +18 -1
- data/lib/vimamsa/buffer_list.rb +126 -139
- data/lib/vimamsa/buffer_manager.rb +34 -23
- data/lib/vimamsa/clipboard.rb +1 -0
- data/lib/vimamsa/conf.rb +6 -0
- data/lib/vimamsa/constants.rb +0 -10
- data/lib/vimamsa/debug.rb +5 -0
- data/lib/vimamsa/editor.rb +17 -7
- data/lib/vimamsa/file_history.rb +0 -8
- data/lib/vimamsa/file_manager.rb +6 -3
- data/lib/vimamsa/gui.rb +105 -55
- data/lib/vimamsa/gui_dialog.rb +1 -1
- data/lib/vimamsa/gui_menu.rb +7 -1
- data/lib/vimamsa/gui_sourceview.rb +58 -18
- data/lib/vimamsa/gui_sourceview_autocomplete.rb +141 -0
- data/lib/vimamsa/gui_text.rb +32 -2
- data/lib/vimamsa/hyper_plain_text.rb +11 -0
- data/lib/vimamsa/key_actions.rb +29 -10
- data/lib/vimamsa/key_binding_tree.rb +84 -14
- data/lib/vimamsa/key_bindings_vimlike.rb +44 -23
- data/lib/vimamsa/langservp.rb +23 -3
- data/lib/vimamsa/main.rb +4 -0
- data/lib/vimamsa/rbvma.rb +2 -0
- data/lib/vimamsa/search_replace.rb +35 -27
- data/lib/vimamsa/terminal.rb +12 -0
- data/lib/vimamsa/util.rb +40 -2
- data/lib/vimamsa/version.rb +1 -1
- data/vimamsa.gemspec +3 -2
- metadata +8 -7
data/lib/vimamsa/gui.rb
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
$idle_scroll_to_mark = false
|
2
2
|
|
3
|
+
$removed_controllers = []
|
4
|
+
|
5
|
+
def gui_remove_controllers(widget)
|
6
|
+
clist = widget.observe_controllers
|
7
|
+
to_remove = []
|
8
|
+
(0..(clist.n_items - 1)).each { |x|
|
9
|
+
ctr = clist.get_item(x)
|
10
|
+
to_remove << ctr
|
11
|
+
}
|
12
|
+
if to_remove.size > 0
|
13
|
+
# debug "Removing controllers:"
|
14
|
+
# pp to_remove
|
15
|
+
to_remove.each { |x|
|
16
|
+
# To avoid GC. https://github.com/ruby-gnome/ruby-gnome/issues/15790
|
17
|
+
$removed_controllers << x
|
18
|
+
widget.remove_controller(x)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
3
23
|
def gui_open_file_dialog(dirpath)
|
4
24
|
dialog = Gtk::FileChooserDialog.new(:title => "Open file",
|
5
25
|
:action => :open,
|
@@ -53,17 +73,15 @@ def get_visible_area()
|
|
53
73
|
return [startpos, endpos]
|
54
74
|
end
|
55
75
|
|
56
|
-
def page_up
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
def page_down
|
62
|
-
$view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), 1, false)
|
63
|
-
return true
|
64
|
-
end
|
65
|
-
|
76
|
+
# def page_up
|
77
|
+
# $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
|
78
|
+
# return true
|
79
|
+
# end
|
66
80
|
|
81
|
+
# def page_down
|
82
|
+
# $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), 1, false)
|
83
|
+
# return true
|
84
|
+
# end
|
67
85
|
|
68
86
|
def gui_create_buffer(id, bufo)
|
69
87
|
debug "gui_create_buffer(#{id})"
|
@@ -71,7 +89,6 @@ def gui_create_buffer(id, bufo)
|
|
71
89
|
view = VSourceView.new(nil, bufo)
|
72
90
|
|
73
91
|
view.register_signals()
|
74
|
-
cnf.debug = true
|
75
92
|
|
76
93
|
ssm = GtkSource::StyleSchemeManager.new
|
77
94
|
ssm.set_search_path(ssm.search_path << ppath("styles/"))
|
@@ -85,10 +102,10 @@ def gui_create_buffer(id, bufo)
|
|
85
102
|
view.set_buffer(buf1)
|
86
103
|
|
87
104
|
provider = Gtk::CssProvider.new
|
88
|
-
|
105
|
+
|
106
|
+
provider.load(data: "textview { font-family: #{cnf.font.family!}; font-size: #{cnf.font.size!}pt; }")
|
89
107
|
view.style_context.add_provider(provider)
|
90
108
|
view.wrap_mode = :char
|
91
|
-
pp $cnf
|
92
109
|
view.set_tab_width(conf(:tab_width))
|
93
110
|
|
94
111
|
$vmag.buffers[id] = view
|
@@ -114,7 +131,8 @@ end
|
|
114
131
|
|
115
132
|
def gui_set_buffer_contents(id, txt)
|
116
133
|
debug "gui_set_buffer_contents(#{id}, txt)"
|
117
|
-
vma.gui.buffers[id].buffer.set_text(txt)
|
134
|
+
# vma.gui.buffers[id].buffer.set_text(txt)
|
135
|
+
vma.gui.buffers[id].set_content(txt)
|
118
136
|
end
|
119
137
|
|
120
138
|
#TODO: remove
|
@@ -135,7 +153,7 @@ def gui_set_window_title(wtitle, subtitle = "")
|
|
135
153
|
end
|
136
154
|
|
137
155
|
class VMAgui
|
138
|
-
attr_accessor :buffers, :sw, :sw1, :sw2, :view, :buf1, :window, :delex, :statnfo, :overlay, :
|
156
|
+
attr_accessor :buffers, :sw, :sw1, :sw2, :view, :buf1, :window, :delex, :statnfo, :overlay, :sws, :two_c
|
139
157
|
attr_reader :two_column, :windows, :subtitle, :app
|
140
158
|
|
141
159
|
def initialize()
|
@@ -327,7 +345,6 @@ class VMAgui
|
|
327
345
|
overlay = Gtk::Overlay.new
|
328
346
|
overlay.set_child(sw)
|
329
347
|
@vbox.attach(overlay, 0, 3, 2, 1)
|
330
|
-
$sw2 = sw
|
331
348
|
sw.set_size_request(-1, 12)
|
332
349
|
|
333
350
|
view = VSourceView.new(nil, nil)
|
@@ -465,8 +482,8 @@ class VMAgui
|
|
465
482
|
end
|
466
483
|
}
|
467
484
|
if to_remove.size > 0
|
468
|
-
|
469
|
-
pp to_remove
|
485
|
+
# debug "Removing controllers:"
|
486
|
+
# pp to_remove
|
470
487
|
to_remove.each { |x| @window.remove_controller(x) }
|
471
488
|
end
|
472
489
|
|
@@ -480,7 +497,7 @@ class VMAgui
|
|
480
497
|
name = Gdk::Keyval.to_name(keyval)
|
481
498
|
uki = Gdk::Keyval.to_unicode(keyval)
|
482
499
|
keystr = uki.chr("UTF-8")
|
483
|
-
|
500
|
+
debug "key pressed #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
|
484
501
|
buf.view.handle_key_event(keyval, keystr, :key_press)
|
485
502
|
true
|
486
503
|
end
|
@@ -501,19 +518,16 @@ class VMAgui
|
|
501
518
|
# button1_mask?
|
502
519
|
# ...
|
503
520
|
# button5_mask?
|
504
|
-
true
|
521
|
+
true # = handled, do not propagate further
|
505
522
|
end
|
506
523
|
|
507
524
|
press.signal_connect "key-released" do |gesture, keyval, keycode, y|
|
508
525
|
name = Gdk::Keyval.to_name(keyval)
|
509
526
|
uki = Gdk::Keyval.to_unicode(keyval)
|
510
527
|
keystr = uki.chr("UTF-8")
|
511
|
-
|
528
|
+
debug "key released #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
|
512
529
|
buf.view.handle_key_event(keyval, keystr, :key_release)
|
513
|
-
#
|
514
|
-
# buf.view.handle_deltas
|
515
|
-
# buf.view.handle_key_event(keyval, keystr, :key_press)
|
516
|
-
true
|
530
|
+
true # = handled, do not propagate further
|
517
531
|
end
|
518
532
|
end
|
519
533
|
|
@@ -527,8 +541,8 @@ class VMAgui
|
|
527
541
|
end
|
528
542
|
}
|
529
543
|
if to_remove.size > 0
|
530
|
-
puts "Removing controllers:"
|
531
|
-
pp to_remove
|
544
|
+
# puts "Removing controllers:"
|
545
|
+
# pp to_remove
|
532
546
|
to_remove.each { |x| vma.gui.window.remove_controller(x) }
|
533
547
|
end
|
534
548
|
end
|
@@ -538,9 +552,8 @@ class VMAgui
|
|
538
552
|
sleep 0.1
|
539
553
|
width = @window.width / 2
|
540
554
|
height = @window.height - 5
|
541
|
-
# Ripl.start :binding => binding
|
542
555
|
@window.unmaximize
|
543
|
-
@window.
|
556
|
+
@window.set_default_size(width, height)
|
544
557
|
return false
|
545
558
|
end
|
546
559
|
|
@@ -575,7 +588,6 @@ class VMAgui
|
|
575
588
|
@sw = Gtk::ScrolledWindow.new
|
576
589
|
@sw.set_policy(:automatic, :automatic)
|
577
590
|
|
578
|
-
|
579
591
|
@last_adj_time = Time.now
|
580
592
|
@sw.vadjustment.signal_connect("value-changed") { |x|
|
581
593
|
# pp x.page_increment
|
@@ -585,17 +597,10 @@ class VMAgui
|
|
585
597
|
# pp x.value
|
586
598
|
# pp x
|
587
599
|
@last_adj_time = Time.now
|
588
|
-
# puts "@sw.vadjustment"
|
589
600
|
}
|
590
601
|
|
591
|
-
# @sw.signal_connect("clicked") { puts "Hello World!" }
|
592
|
-
# @sw.signal_connect("key-pressed") { puts "Hello World!" }
|
593
602
|
@overlay = Gtk::Overlay.new
|
594
|
-
|
595
|
-
@overlay.add_overlay(@sw) #TODO:gtk4
|
596
|
-
@overlay1 = @overlay
|
597
|
-
|
598
|
-
# init_header_bar #TODO:gtk4
|
603
|
+
@overlay.add_overlay(@sw)
|
599
604
|
|
600
605
|
@statnfo = Gtk::Label.new
|
601
606
|
@subtitle = Gtk::Label.new("")
|
@@ -623,8 +628,6 @@ class VMAgui
|
|
623
628
|
|
624
629
|
init_minibuffer
|
625
630
|
|
626
|
-
# p = Gtk::Popover.new
|
627
|
-
|
628
631
|
name = "save"
|
629
632
|
window = @window
|
630
633
|
action = Gio::SimpleAction.new(name)
|
@@ -661,16 +664,6 @@ class VMAgui
|
|
661
664
|
|
662
665
|
@window.show
|
663
666
|
|
664
|
-
press = Gtk::GestureClick.new
|
665
|
-
press.button = Gdk::BUTTON_SECONDARY
|
666
|
-
@window.add_controller(press)
|
667
|
-
press.signal_connect "pressed" do |gesture, n_press, x, y|
|
668
|
-
puts "FOOBARpressed"
|
669
|
-
# clear_surface(surface)
|
670
|
-
# drawing_area.queue_draw
|
671
|
-
end
|
672
|
-
@sw1 = @sw
|
673
|
-
|
674
667
|
prov = Gtk::CssProvider.new
|
675
668
|
# See gtk-4.9.4/gtk/theme/Default/_common.scss on how to theme
|
676
669
|
# gtksourceview/gtksourcestyleschemepreview.c
|
@@ -696,6 +689,7 @@ class VMAgui
|
|
696
689
|
min-width: 15px;
|
697
690
|
}
|
698
691
|
|
692
|
+
popover background > contents { padding: 8px; border-radius: 20px; }
|
699
693
|
")
|
700
694
|
@window.style_context.add_provider(prov)
|
701
695
|
|
@@ -715,6 +709,28 @@ class VMAgui
|
|
715
709
|
Vimamsa::Menu.new(@menubar, @app)
|
716
710
|
end
|
717
711
|
|
712
|
+
def toggle_two_column
|
713
|
+
if @two_column
|
714
|
+
set_one_column
|
715
|
+
else
|
716
|
+
set_two_column
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
def set_one_column
|
721
|
+
return if !@two_column
|
722
|
+
@windows[2][:sw].set_child(nil)
|
723
|
+
@windows.delete(2)
|
724
|
+
|
725
|
+
@pane.set_start_child(nil)
|
726
|
+
@pane.set_end_child(nil)
|
727
|
+
|
728
|
+
@vbox.remove(@pane)
|
729
|
+
@vbox.attach(@overlay, 0, 2, 2, 1)
|
730
|
+
@vbox.attach(@statbox, 1, 1, 1, 1)
|
731
|
+
@two_column = false
|
732
|
+
end
|
733
|
+
|
718
734
|
def set_two_column
|
719
735
|
return if @two_column
|
720
736
|
# @window.set_default_size(800, 600) #TODO:gtk4
|
@@ -732,10 +748,10 @@ class VMAgui
|
|
732
748
|
|
733
749
|
@vbox.remove(@overlay)
|
734
750
|
|
735
|
-
# numbers: left, top, width, height
|
736
751
|
@pane.set_start_child(@overlay2)
|
737
752
|
@pane.set_end_child(@overlay)
|
738
753
|
|
754
|
+
# numbers: left, top, width, height
|
739
755
|
@vbox.attach(@pane, 0, 2, 2, 1)
|
740
756
|
|
741
757
|
@sw2.vexpand = true
|
@@ -747,8 +763,8 @@ class VMAgui
|
|
747
763
|
@sw2.show
|
748
764
|
@two_column = true
|
749
765
|
|
750
|
-
|
751
|
-
|
766
|
+
last = vma.buffers.get_last_visited_id
|
767
|
+
if !last.nil?
|
752
768
|
set_buffer_to_window(last, 2)
|
753
769
|
else
|
754
770
|
bf = create_new_buffer "\n\n", "buff", false
|
@@ -833,19 +849,53 @@ class VMAgui
|
|
833
849
|
$vbuf = buf1
|
834
850
|
|
835
851
|
# Check if buffer is already open in another column
|
836
|
-
if @two_column and @active_column == 2 and id == @
|
852
|
+
if @two_column and @active_column == 2 and id == @windows[1][:sw].child.bufo.id
|
837
853
|
toggle_active_window
|
838
|
-
elsif @two_column && @active_column == 1 && !@
|
854
|
+
elsif @two_column && @active_column == 1 && !@windows[2][:sw].child.nil? && id == @windows[2][:sw].child.bufo.id
|
839
855
|
#TODO: should not need !@sw2.child.nil? here. If this happens then other column is empty.
|
840
856
|
toggle_active_window
|
841
857
|
else
|
858
|
+
#TODO: improve
|
859
|
+
@overlay.remove_overlay(@sw)
|
860
|
+
@sw.set_child(nil)
|
861
|
+
# Creating a new ScrolledWindow every time to avoid a layout bug
|
862
|
+
# https://gitlab.gnome.org/GNOME/gtk/-/issues/6189
|
863
|
+
@sw = new_scrolled_window
|
842
864
|
@sw.set_child(view)
|
865
|
+
@overlay.add_overlay(@sw)
|
866
|
+
@active_window[:sw] = @sw
|
843
867
|
end
|
844
868
|
view.grab_focus
|
845
869
|
|
846
870
|
idle_ensure_cursor_drawn
|
847
871
|
end
|
848
872
|
|
873
|
+
def new_scrolled_window
|
874
|
+
sw = Gtk::ScrolledWindow.new
|
875
|
+
sw.set_policy(:automatic, :automatic)
|
876
|
+
@last_adj_time = Time.now
|
877
|
+
sw.vadjustment.signal_connect("value-changed") { |x|
|
878
|
+
@last_adj_time = Time.now
|
879
|
+
debug "@sw.vadjustment #{x.value}", 2
|
880
|
+
}
|
881
|
+
return sw
|
882
|
+
end
|
883
|
+
|
884
|
+
def page_down(multip: 1.0)
|
885
|
+
va = @sw.vadjustment
|
886
|
+
newval = va.value + va.page_increment * multip
|
887
|
+
va.value = newval
|
888
|
+
@sw.child.set_cursor_to_top
|
889
|
+
end
|
890
|
+
|
891
|
+
def page_up(multip: 1.0)
|
892
|
+
va = @sw.vadjustment
|
893
|
+
newval = va.value - va.page_increment * multip
|
894
|
+
newval = 0 if newval < 0
|
895
|
+
va.value = newval
|
896
|
+
@sw.child.set_cursor_to_top
|
897
|
+
end
|
898
|
+
|
849
899
|
def idle_ensure_cursor_drawn
|
850
900
|
run_as_idle proc { self.ensure_cursor_drawn }
|
851
901
|
end
|
data/lib/vimamsa/gui_dialog.rb
CHANGED
data/lib/vimamsa/gui_menu.rb
CHANGED
@@ -31,6 +31,9 @@ module Vimamsa
|
|
31
31
|
add_to_menu "Edit.Redo", { :label => "Redo edit", :action => :edit_redo }
|
32
32
|
add_to_menu "Edit.SearchReplace", { :label => "Search and replace", :action => :gui_search_replace }
|
33
33
|
add_to_menu "Edit.Find", { :label => "Find", :action => :find_in_buffer }
|
34
|
+
|
35
|
+
add_to_menu "Edit.StartCompletion", { :label => "StartCompletion", :action => :start_autocomplete }
|
36
|
+
add_to_menu "Edit.ShowCompletion", { :label => "ShowCompletion", :action => :show_autocomplete }
|
34
37
|
|
35
38
|
add_to_menu "Actions.SearchForActions", { :label => "Search for Actions", :action => :search_actions }
|
36
39
|
|
@@ -44,8 +47,11 @@ module Vimamsa
|
|
44
47
|
add_to_menu "Actions.experimental.DisableDebug", { :label => "Disable debug", :action => :disable_debug }
|
45
48
|
add_to_menu "Actions.experimental.ShowImages", { :label => "Show images ⟦img:path⟧", :action => :show_images }
|
46
49
|
|
50
|
+
add_to_menu "Actions.debug.dumpkbd", { :label => "Dump kbd state", :action => :kbd_dump_state }
|
51
|
+
|
47
52
|
|
48
|
-
add_to_menu "View.
|
53
|
+
add_to_menu "View.BufferManager", { :label => "Show open files", :action => :start_buf_manager }
|
54
|
+
add_to_menu "View.TwoColumn", { :label => "Toggle two column mode", :action => :toggle_two_column }
|
49
55
|
|
50
56
|
|
51
57
|
add_to_menu "Actions.EncryptFile", { :label => "Encrypt file", :action => :encrypt_file }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# class VSourceView < Gtk::TextView
|
2
2
|
class VSourceView < GtkSource::View
|
3
|
-
attr_accessor :bufo
|
3
|
+
attr_accessor :bufo, :autocp_active, :cpl_list
|
4
4
|
# :highlight_matching_brackets
|
5
5
|
|
6
6
|
# def set_highlight_current_line(vbool)
|
@@ -18,7 +18,7 @@ class VSourceView < GtkSource::View
|
|
18
18
|
@highlight_matching_brackets = true
|
19
19
|
@idle_func_running = false
|
20
20
|
super()
|
21
|
-
@bufo = bufo #object of Buffer class buffer.rb
|
21
|
+
@bufo = bufo #object of Buffer class (buffer.rb)
|
22
22
|
debug "vsource init"
|
23
23
|
@last_keyval = nil
|
24
24
|
@last_event = [nil, nil]
|
@@ -45,13 +45,14 @@ class VSourceView < GtkSource::View
|
|
45
45
|
# true
|
46
46
|
# end
|
47
47
|
|
48
|
+
# signal_connect("show-completion") do |x, y, z|
|
49
|
+
# debug "SHOW-COMPLETION", 2
|
50
|
+
# false
|
51
|
+
# end
|
52
|
+
|
48
53
|
# Mainly after page-up or page-down
|
49
54
|
signal_connect("move-cursor") do |widget, event|
|
50
55
|
if event.name == "GTK_MOVEMENT_PAGES" and (last_action == "page_up" or last_action == "page_down")
|
51
|
-
# Ripl.start :binding => binding
|
52
|
-
|
53
|
-
debug("MOVE-CURSOR", 2)
|
54
|
-
# $update_cursor = true
|
55
56
|
handle_scrolling()
|
56
57
|
end
|
57
58
|
|
@@ -77,6 +78,11 @@ class VSourceView < GtkSource::View
|
|
77
78
|
@curpos_mark = nil
|
78
79
|
end
|
79
80
|
|
81
|
+
def set_content(str)
|
82
|
+
delete_cursorchar
|
83
|
+
self.buffer.set_text(str)
|
84
|
+
end
|
85
|
+
|
80
86
|
def gutter_width()
|
81
87
|
winwidth = width
|
82
88
|
view_width = visible_rect.width
|
@@ -106,8 +112,6 @@ class VSourceView < GtkSource::View
|
|
106
112
|
end
|
107
113
|
}
|
108
114
|
if to_remove.size > 0
|
109
|
-
debug "Removing controllers:"
|
110
|
-
pp to_remove
|
111
115
|
to_remove.each { |x|
|
112
116
|
# To avoid GC. https://github.com/ruby-gnome/ruby-gnome/issues/15790
|
113
117
|
@removed_controllers << x
|
@@ -138,17 +142,17 @@ class VSourceView < GtkSource::View
|
|
138
142
|
i = coord_to_iter(x, y, true)
|
139
143
|
pp i
|
140
144
|
@range_start = i
|
141
|
-
|
142
|
-
buf.start_visual_mode
|
143
|
-
end
|
145
|
+
buf.start_selection
|
144
146
|
end
|
145
147
|
|
146
148
|
@cnt_drag.signal_connect "drag-end" do |gesture, offsetx, offsety|
|
147
149
|
debug "drag-end", 2
|
148
|
-
|
149
|
-
# Not enough drag
|
150
150
|
if offsetx.abs < 5 and offsety.abs < 5
|
151
|
-
|
151
|
+
debug "Not enough drag", 2
|
152
|
+
@range_start = nil
|
153
|
+
elsif !buf.visual_mode? and vma.kbd.get_scope != :editor
|
154
|
+
# Can't transition from editor wide mode to buffer specific mode
|
155
|
+
buf.start_visual_mode
|
152
156
|
end
|
153
157
|
@range_start = nil
|
154
158
|
end
|
@@ -228,6 +232,7 @@ class VSourceView < GtkSource::View
|
|
228
232
|
end
|
229
233
|
|
230
234
|
def handle_scrolling()
|
235
|
+
return # TODO
|
231
236
|
delete_cursorchar
|
232
237
|
# curpos = buffer.cursor_position
|
233
238
|
# debug "MOVE CURSOR: #{curpos}"
|
@@ -247,6 +252,19 @@ class VSourceView < GtkSource::View
|
|
247
252
|
}
|
248
253
|
end
|
249
254
|
|
255
|
+
def set_cursor_to_top
|
256
|
+
debug "set_cursor_to_top", 2
|
257
|
+
delete_cursorchar
|
258
|
+
bc = window_to_buffer_coords(Gtk::TextWindowType::WIDGET, gutter_width + 2, 60)
|
259
|
+
if !bc.nil?
|
260
|
+
i = coord_to_iter(bc[0], bc[1])
|
261
|
+
if !i.nil?
|
262
|
+
@bufo.set_pos(i)
|
263
|
+
set_cursor_pos(i)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
250
268
|
# def handle_key_event(event, sig)
|
251
269
|
def handle_key_event(keyval, keyname, sig)
|
252
270
|
delete_cursorchar
|
@@ -291,7 +309,7 @@ class VSourceView < GtkSource::View
|
|
291
309
|
keyval_trans[Gdk::Keyval::KEY_Shift_L] = "shift"
|
292
310
|
keyval_trans[Gdk::Keyval::KEY_Shift_R] = "shift"
|
293
311
|
keyval_trans[Gdk::Keyval::KEY_Tab] = "tab"
|
294
|
-
keyval_trans[Gdk::Keyval::
|
312
|
+
keyval_trans[Gdk::Keyval::KEY_ISO_Left_Tab] = "tab"
|
295
313
|
|
296
314
|
key_trans = {}
|
297
315
|
key_trans["\e"] = "esc"
|
@@ -368,6 +386,10 @@ class VSourceView < GtkSource::View
|
|
368
386
|
return [x, y]
|
369
387
|
end
|
370
388
|
|
389
|
+
def cur_pos_xy
|
390
|
+
return pos_to_coord(buffer.cursor_position)
|
391
|
+
end
|
392
|
+
|
371
393
|
def handle_deltas()
|
372
394
|
delete_cursorchar
|
373
395
|
any_change = false
|
@@ -411,7 +433,6 @@ class VSourceView < GtkSource::View
|
|
411
433
|
|
412
434
|
def set_cursor_pos(pos)
|
413
435
|
delete_cursorchar
|
414
|
-
# return
|
415
436
|
itr = buffer.get_iter_at(:offset => pos)
|
416
437
|
itr2 = buffer.get_iter_at(:offset => pos + 1)
|
417
438
|
buffer.place_cursor(itr)
|
@@ -436,7 +457,7 @@ class VSourceView < GtkSource::View
|
|
436
457
|
end
|
437
458
|
|
438
459
|
def cursor_visible_idle_func
|
439
|
-
return false
|
460
|
+
# return false
|
440
461
|
debug "cursor_visible_idle_func"
|
441
462
|
# From https://picheta.me/articles/2013/08/gtk-plus--a-method-to-guarantee-scrolling.html
|
442
463
|
|
@@ -502,6 +523,22 @@ class VSourceView < GtkSource::View
|
|
502
523
|
end
|
503
524
|
end
|
504
525
|
|
526
|
+
def set_cursor_color(ctype)
|
527
|
+
if @ctype != ctype
|
528
|
+
bg = $confh[:mode][ctype][:cursor][:background]
|
529
|
+
if bg.class == String
|
530
|
+
if !@cursor_prov.nil?
|
531
|
+
self.style_context.remove_provider(@cursor_prov)
|
532
|
+
end
|
533
|
+
prov = Gtk::CssProvider.new
|
534
|
+
prov.load(data: ".view text selection { background-color: #{bg}; color: #ffffff; }")
|
535
|
+
self.style_context.add_provider(prov)
|
536
|
+
@cursor_prov = prov
|
537
|
+
end
|
538
|
+
@ctype == ctype
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
505
542
|
def draw_cursor
|
506
543
|
# if @tt.nil?
|
507
544
|
# @tt = buffer.create_tag("font_tag")
|
@@ -512,7 +549,8 @@ class VSourceView < GtkSource::View
|
|
512
549
|
ctype = vma.kbd.get_cursor_type
|
513
550
|
delete_cursorchar
|
514
551
|
vma.gui.remove_overlay_cursor
|
515
|
-
if
|
552
|
+
if [:command, :replace, :browse].include?(ctype)
|
553
|
+
set_cursor_color(ctype)
|
516
554
|
if @bufo[@bufo.pos] == "\n"
|
517
555
|
# If we are at end of line, it's not possible to draw the cursor by making a selection. I tried to do this by drawing an overlay, but that generates issues. If moving the cursor causes the ScrolledWindow to be scrolled, these errors randomly appear and the whole view shows blank:
|
518
556
|
# (ruby:21016): Gtk-WARNING **: 19:52:23.181: Trying to snapshot GtkSourceView 0x55a97524c8c0 without a current allocation
|
@@ -538,7 +576,9 @@ class VSourceView < GtkSource::View
|
|
538
576
|
buffer.select_range(itr, itr2)
|
539
577
|
end
|
540
578
|
# elsif @bufo.visual_mode?
|
579
|
+
|
541
580
|
elsif ctype == :visual
|
581
|
+
set_cursor_color(ctype)
|
542
582
|
# debug "VISUAL MODE"
|
543
583
|
(_start, _end) = @bufo.get_visual_mode_range2
|
544
584
|
# debug "#{_start}, #{_end}"
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# require "trie"
|
2
|
+
require "rambling-trie"
|
3
|
+
|
4
|
+
class Autocomplete
|
5
|
+
@@trie = Rambling::Trie.create
|
6
|
+
|
7
|
+
def self.init
|
8
|
+
vma.hook.register(:file_saved, self.method("update_index"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.update_index(bu)
|
12
|
+
debug "self.update_index", 2
|
13
|
+
add_words bu.scan_all_words
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.update_dict
|
17
|
+
for bu in vma.buffers.list
|
18
|
+
for w in bu.scan_all_words
|
19
|
+
trie << w
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@@trie = trie
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.add_words(words)
|
26
|
+
for w in words
|
27
|
+
@@trie << w
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.word_list
|
32
|
+
return @@dict.keys
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.matching_words(beginning)
|
36
|
+
return @@trie.scan(beginning)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class VSourceView < GtkSource::View
|
41
|
+
def hide_completions
|
42
|
+
if @acwin.class == Gtk::Popover
|
43
|
+
@acwin.hide
|
44
|
+
end
|
45
|
+
@autocp_active = false
|
46
|
+
end
|
47
|
+
|
48
|
+
def autocp_select
|
49
|
+
return if !@autocp_active
|
50
|
+
bufo.complete_current_word(@cpl_list[@autocp_selected])
|
51
|
+
autocp_exit
|
52
|
+
end
|
53
|
+
|
54
|
+
def autocp_select_previous
|
55
|
+
return if @autocp_selected <= 0
|
56
|
+
autocp_hilight(@autocp_selected)
|
57
|
+
autocp_unhilight(@autocp_selected)
|
58
|
+
@autocp_selected -= 1
|
59
|
+
autocp_hilight(@autocp_selected)
|
60
|
+
end
|
61
|
+
|
62
|
+
def autocp_hilight(id)
|
63
|
+
l = @autocp_items[id]
|
64
|
+
l.set_text("<span foreground='#00ff00' weight='ultrabold'>#{cpl_list[id]}</span>")
|
65
|
+
l.use_markup = true
|
66
|
+
end
|
67
|
+
|
68
|
+
def autocp_unhilight(id)
|
69
|
+
l = @autocp_items[id]
|
70
|
+
l.set_text("<span>#{cpl_list[id]}</span>")
|
71
|
+
l.use_markup = true
|
72
|
+
end
|
73
|
+
|
74
|
+
def autocp_select_next
|
75
|
+
return if @autocp_selected >= cpl_list.size - 1
|
76
|
+
debug "autocp_select_next", 2
|
77
|
+
autocp_unhilight(@autocp_selected)
|
78
|
+
@autocp_selected += 1
|
79
|
+
autocp_hilight(@autocp_selected)
|
80
|
+
end
|
81
|
+
|
82
|
+
def autocp_exit
|
83
|
+
@autocp_items = []
|
84
|
+
@autocp_active = true
|
85
|
+
hide_completions
|
86
|
+
end
|
87
|
+
|
88
|
+
def try_autocomplete
|
89
|
+
end
|
90
|
+
|
91
|
+
def show_completions
|
92
|
+
hide_completions
|
93
|
+
bu = vma.buf
|
94
|
+
(w, range) = bu.get_word_in_pos(bu.pos - 1, boundary: :word)
|
95
|
+
debug [w, range].to_s, 2
|
96
|
+
matches = Autocomplete.matching_words w
|
97
|
+
return if matches.empty?
|
98
|
+
@autocp_active = true
|
99
|
+
@cpl_list = cpl_list = matches
|
100
|
+
win = Gtk::Popover.new()
|
101
|
+
win.parent = self
|
102
|
+
vbox = Gtk::Grid.new()
|
103
|
+
win.set_child(vbox)
|
104
|
+
|
105
|
+
i = 0
|
106
|
+
@autocp_items = []
|
107
|
+
@autocp_selected = 0
|
108
|
+
for x in cpl_list
|
109
|
+
l = Gtk::Label.new(x)
|
110
|
+
@autocp_items << l
|
111
|
+
# numbers: left, top, width, height
|
112
|
+
vbox.attach(l, 0, i, 1, 1)
|
113
|
+
i += 1
|
114
|
+
end
|
115
|
+
autocp_hilight(0)
|
116
|
+
(x, y) = cur_pos_xy
|
117
|
+
rec = Gdk::Rectangle.new(x, y + 8, 10, 10)
|
118
|
+
win.has_arrow = false
|
119
|
+
win.set_pointing_to(rec)
|
120
|
+
win.autohide = false
|
121
|
+
win.popup
|
122
|
+
gui_remove_controllers(win)
|
123
|
+
@acwin = win
|
124
|
+
end
|
125
|
+
|
126
|
+
def start_autocomplete
|
127
|
+
return
|
128
|
+
# Roughly following these examples:
|
129
|
+
# https://stackoverflow.com/questions/52359721/howto-maintain-gtksourcecompletion-when-changing-buffers-in-a-gtksourceview
|
130
|
+
# and gedit-plugins-41.0/plugins/wordcompletion/gedit-word-completion-plugin.c
|
131
|
+
# .. but it doesn't work. So implementing using Popover.
|
132
|
+
# Keeping this for reference
|
133
|
+
|
134
|
+
cp = self.completion
|
135
|
+
prov = GtkSource::CompletionWords.new("Autocomplete") # (name,icon)
|
136
|
+
prov.register(self.buffer)
|
137
|
+
cp.add_provider(prov)
|
138
|
+
pp prov
|
139
|
+
self.show_completion
|
140
|
+
end
|
141
|
+
end
|