vimamsa 0.1.14 → 0.1.15
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 +11 -13
- 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 +5 -1
- data/lib/vimamsa/gui_sourceview.rb +38 -17
- 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 +31 -21
- 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 +11 -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,9 @@ 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 }
|
47
51
|
|
48
|
-
add_to_menu "View.TwoColumn", { :label => "
|
52
|
+
add_to_menu "View.TwoColumn", { :label => "Toggle two column mode", :action => :toggle_two_column }
|
49
53
|
|
50
54
|
|
51
55
|
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
|
|
@@ -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
|
data/lib/vimamsa/gui_text.rb
CHANGED
@@ -1,11 +1,41 @@
|
|
1
1
|
module Gui
|
2
|
-
def self.
|
2
|
+
def self.hilight_range(bf, r, color: "#aa0000ff", weight: nil, tag: nil)
|
3
|
+
vbuf = bf.view.buffer
|
4
|
+
|
5
|
+
if tag.nil?
|
6
|
+
tag = vma.gui.view.buffer.create_tag
|
7
|
+
tag.weight = weight if !weight.nil?
|
8
|
+
tag.foreground = color
|
9
|
+
end
|
10
|
+
|
11
|
+
itr = vbuf.get_iter_at(:offset => r.begin)
|
12
|
+
itr2 = vbuf.get_iter_at(:offset => r.last)
|
13
|
+
vbuf.apply_tag(tag, itr, itr2)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.highlight_match(bf, str, color: "#aa0000ff", weight: 650)
|
17
|
+
r = Regexp.new(Regexp.escape(str), Regexp::IGNORECASE)
|
18
|
+
tag = vma.gui.view.buffer.create_tag
|
19
|
+
tag.weight = weight
|
20
|
+
tag.foreground = color
|
21
|
+
ind = scan_indexes(bf, r)
|
22
|
+
ind.each { |x|
|
23
|
+
r = x..(x + str.size)
|
24
|
+
self.hilight_range(bf, r, tag: tag)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.highlight_match_old(bf, str, color: "#aa0000ff")
|
3
29
|
vbuf = bf.view.buffer
|
4
30
|
r = Regexp.new(Regexp.escape(str), Regexp::IGNORECASE)
|
5
31
|
|
6
32
|
hlparts = []
|
7
33
|
|
8
|
-
tt = vma.gui.view.buffer.
|
34
|
+
tt = vma.gui.view.buffer.tag_table.lookup("highlight_match_tag")
|
35
|
+
if tt.nil?
|
36
|
+
tt = vma.gui.view.buffer.create_tag("highlight_match_tag")
|
37
|
+
end
|
38
|
+
|
9
39
|
tt.weight = 650
|
10
40
|
tt.foreground = color
|
11
41
|
|
@@ -39,12 +39,23 @@ def hpt_check_cur_word(w)
|
|
39
39
|
# return true
|
40
40
|
else
|
41
41
|
message "File not found: #{fpfx}"
|
42
|
+
newfn = fcands[0]
|
43
|
+
if File.extname(newfn) == ""
|
44
|
+
newfn = fcands[1]
|
45
|
+
end
|
46
|
+
Gui.confirm("File does not exist. Create a new file? \r #{newfn}",
|
47
|
+
proc{hpt_create_new_file(newfn)})
|
48
|
+
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
45
52
|
return nil
|
46
53
|
end
|
47
54
|
|
55
|
+
def hpt_create_new_file(fn)
|
56
|
+
create_new_file(fn)
|
57
|
+
end
|
58
|
+
|
48
59
|
def translate_path(fn, bf)
|
49
60
|
if File.exist?(fn)
|
50
61
|
outfn = fn
|