vimamsa 0.1.14 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
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
- $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
58
- return true
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
- provider.load(data: "textview { font-family: Monospace; font-size: 11pt; }")
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, :overlay1, :overlay2, :sws, :two_c
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
- puts "Removing controllers:"
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
- puts "key-pressed #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
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
- puts "key released #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
528
+ debug "key released #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
512
529
  buf.view.handle_key_event(keyval, keystr, :key_release)
513
- # vma.kbd.match_key_conf(keystr, nil, :key_press)
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.set_size_request(width, height)
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
- # @overlay.add(@sw) #TODO:gtk4
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
- if vma.buffers.size > 1
751
- last = vma.buffers.get_last_visited_id
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 == @sw1.child.bufo.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 && !@sw2.child.nil? && id == @sw2.child.bufo.id
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
@@ -1,5 +1,5 @@
1
1
  module Gui
2
- def self.confirm(title, callback)
2
+ def self.confirm(title, callback, param: nil)
3
3
  params = {}
4
4
  params["title"] = title
5
5
  params["inputs"] = {}
@@ -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.TwoColumn", { :label => "Start two column mode", :action => :toggle_two_column }
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
- if !buf.visual_mode?
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
- buf.end_visual_mode
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::GDK_KEY_ISO_Left_Tab] = "tab"
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 ctype == :command
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