Class: VSourceView

Inherits:
GtkSource::View
  • Object
show all
Defined in:
lib/vimamsa/gui_sourceview.rb,
lib/vimamsa/gui_sourceview_autocomplete.rb

Overview

class VSourceView < Gtk::TextView

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(title, bufo) ⇒ VSourceView

def initialize(title = nil,bufo=nil)



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/vimamsa/gui_sourceview.rb', line 7

def initialize(title, bufo)
  # super(:toplevel)
  @highlight_matching_brackets = true
  @idle_func_running = false
  super()
  @bufo = bufo #object of Buffer class (buffer.rb)
  debug "vsource init"
  @last_keyval = nil
  @last_event = [nil, nil]
  @removed_controllers = []
  self.highlight_current_line = true

  @tt = nil

  # Mainly after page-up or page-down
  signal_connect("move-cursor") do |widget, event|
    # if event.name == "GTK_MOVEMENT_PAGES" and (vma.actions.last_action == "page_up" or vma.actions.last_action == "page_down")
    # handle_scrolling()
    # end

    # handle_scrolling()
    # curpos = buffer.cursor_position
    # debug "MOVE CURSOR (sig): #{curpos}"

    # run_as_idle proc {
    # curpos = buffer.cursor_position
    # debug "MOVE CURSOR (sig2): #{curpos}"
    # }

    false
  end

  return

  signal_connect "button-release-event" do |widget, event|
    vma.buf.set_pos(buffer.cursor_position)
    false
  end
  @curpos_mark = nil
end

Instance Attribute Details

#autocp_activeObject

Returns the value of attribute autocp_active.



3
4
5
# File 'lib/vimamsa/gui_sourceview.rb', line 3

def autocp_active
  @autocp_active
end

#bufoObject

Returns the value of attribute bufo.



3
4
5
# File 'lib/vimamsa/gui_sourceview.rb', line 3

def bufo
  @bufo
end

#cpl_listObject

Returns the value of attribute cpl_list.



3
4
5
# File 'lib/vimamsa/gui_sourceview.rb', line 3

def cpl_list
  @cpl_list
end

Instance Method Details

#after_actionObject



555
556
557
558
559
560
561
# File 'lib/vimamsa/gui_sourceview.rb', line 555

def after_action
  iterate_gui_main_loop
  handle_deltas
  iterate_gui_main_loop
  draw_cursor
  iterate_gui_main_loop
end

#autocp_exitObject



84
85
86
87
88
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 84

def autocp_exit
  @autocp_items = []
  @autocp_active = true
  hide_completions
end

#autocp_hilight(id) ⇒ Object



64
65
66
67
68
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 64

def autocp_hilight(id)
  l = @autocp_items[id]
  l.set_text("<span foreground='#00ff00' weight='ultrabold'>#{cpl_list[id]}</span>")
  l.use_markup = true
end

#autocp_selectObject



50
51
52
53
54
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 50

def autocp_select
  return if !@autocp_active
  bufo.complete_current_word(@cpl_list[@autocp_selected])
  autocp_exit
end

#autocp_select_nextObject



76
77
78
79
80
81
82
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 76

def autocp_select_next
  return if @autocp_selected >= cpl_list.size - 1
  debug "autocp_select_next", 2
  autocp_unhilight(@autocp_selected)
  @autocp_selected += 1
  autocp_hilight(@autocp_selected)
end

#autocp_select_previousObject



56
57
58
59
60
61
62
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 56

def autocp_select_previous
  return if @autocp_selected <= 0
  autocp_hilight(@autocp_selected)
  autocp_unhilight(@autocp_selected)
  @autocp_selected -= 1
  autocp_hilight(@autocp_selected)
end

#autocp_unhilight(id) ⇒ Object



70
71
72
73
74
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 70

def autocp_unhilight(id)
  l = @autocp_items[id]
  l.set_text("<span>#{cpl_list[id]}</span>")
  l.use_markup = true
end

#check_controllersObject



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/vimamsa/gui_sourceview.rb', line 66

def check_controllers
  clist = self.observe_controllers
  to_remove = []
  (0..(clist.n_items - 1)).each { |x|
    ctr = clist.get_item(x)
    # Sometimes a GestureClick EventController appears from somewhere
    # not initiated from this file.

    # TODO: Check which of these are needed:
    # puts ctr.class
    # Gtk::DropTarget
    # Gtk::EventControllerFocus
    # Gtk::EventControllerKey
    # Gtk::EventControllerMotion
    # Gtk::EventControllerScroll
    # Gtk::GestureClick
    # Gtk::GestureDrag
    # Gtk::ShortcutController

    if ![@click, @dt].include?(ctr) and [Gtk::DropControllerMotion, Gtk::DropTarget, Gtk::GestureDrag, Gtk::GestureClick, Gtk::EventControllerKey].include?(ctr.class)
      to_remove << ctr
    end
  }
  if to_remove.size > 0
    to_remove.each { |x|
      # To avoid GC. https://github.com/ruby-gnome/ruby-gnome/issues/15790
      @removed_controllers << x
      self.remove_controller(x)
    }
  end
end

#coord_to_iter(xloc, yloc, transform_coord = false) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/vimamsa/gui_sourceview.rb', line 249

def coord_to_iter(xloc, yloc, transform_coord = false)
  if transform_coord
    xloc = (xloc - gutter_width).to_i
    yloc = (yloc + visible_rect.y).to_i
  end

  # Try to get exact character position
  i = get_iter_at_location(xloc, yloc)

  # If doesn't work, at least get the start of correct line
  # TODO: sometimes end of line is better choice
  if i.nil?
    r = get_line_at_y(yloc)
    i = r[0] if !r.nil?
  end

  return i.offset if !i.nil?
  return nil
end

#cur_pos_xyObject



430
431
432
# File 'lib/vimamsa/gui_sourceview.rb', line 430

def cur_pos_xy
  return pos_to_coord(buffer.cursor_position)
end

#cursor_visible_idle_funcObject



498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
# File 'lib/vimamsa/gui_sourceview.rb', line 498

def cursor_visible_idle_func
  # return false
  debug "cursor_visible_idle_func"
  # From https://picheta.me/articles/2013/08/gtk-plus--a-method-to-guarantee-scrolling.html

  # This is not the current buffer
  return false if vma.gui.view != self

  sleep(0.01)
  # intr = iterxy.intersect(vr)
  if is_cursor_visible == false
    # set_cursor_pos(buffer.cursor_position)

    itr = buffer.get_iter_at(:offset => buffer.cursor_position)

    within_margin = 0.075 #margin as a [0.0,0.5) fraction of screen size
    use_align = false
    xalign = 0.5 #0.0=top 1.0=bottom, 0.5=center
    yalign = 0.5

    scroll_to_iter(itr, within_margin, use_align, xalign, yalign)

    return true # Call this func again
  else
    @idle_func_running = false
    return false # Don't call this idle func again
  end
end

#draw_cursorObject



580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# File 'lib/vimamsa/gui_sourceview.rb', line 580

def draw_cursor
  sv = vma.gui.active_window[:sw].child
  return if sv.nil?
  if sv != self # if we are not the current buffer
    sv.draw_cursor
    return
  end

  mode = vma.kbd.get_mode
  ctype = vma.kbd.get_cursor_type
  ctype = :visual if vma.buf.selection_active?

  if [:command, :replace, :browse].include?(ctype)
    set_cursor_color(ctype)

    if !self.overwrite?
      self.overwrite = true

      # (Via trial and error) This combination is needed to make cursor visible:
      # TODO: determine why "self.cursor_visible = true" is not enough
      self.cursor_visible = false
      self.cursor_visible = true
    end
  elsif ctype == :visual
    set_cursor_color(ctype)
    # debug "VISUAL MODE"
    (_start, _end) = @bufo.get_visual_mode_range2
    # debug "#{_start}, #{_end}"
    itr = buffer.get_iter_at(:offset => _start)
    itr2 = buffer.get_iter_at(:offset => _end + 1)
    # Pango-CRITICAL **: pango_layout_get_cursor_pos: assertion 'index >= 0 && index <= layout->length' failed
    buffer.select_range(itr, itr2)
  elsif ctype == :insert
    set_cursor_color(ctype)
    self.overwrite = false
    debug "INSERT MODE"
  else # TODO
  end

  if [:insert, :command, :replace, :browse].include?(ctype)
    # Place cursor where it already is
    # Without this hack, the cursor doesn't always get drawn
    pos = @bufo.pos
    itr = buffer.get_iter_at(:offset => pos)
    buffer.place_cursor(itr)
  end

  # Sometimes we lose focus and the cursor vanishes because of that
  # TODO: determine why&when
  if !self.has_focus?
    self.grab_focus
    self.cursor_visible = false
    self.cursor_visible = true
  end
end

#ensure_cursor_visibleObject



544
545
546
547
548
549
550
551
552
553
# File 'lib/vimamsa/gui_sourceview.rb', line 544

def ensure_cursor_visible
  # return
  debug "@idle_func_running=#{@idle_func_running}"
  return if @idle_func_running
  if is_cursor_visible == false
    @idle_func_running = true
    debug "Starting idle func"
    GLib::Idle.add(proc { cursor_visible_idle_func })
  end
end

#focus_inObject



105
106
107
108
109
110
# File 'lib/vimamsa/gui_sourceview.rb', line 105

def focus_in()
  set_cursor_color(@ctype)
  self.cursor_visible = false
  self.cursor_visible = true
  self.grab_focus
end

#focus_outObject



98
99
100
101
102
103
# File 'lib/vimamsa/gui_sourceview.rb', line 98

def focus_out()
  set_cursor_color(:inactive)

  # This does not seem to work: (TODO:why?)
  # self.cursor_visible = false
end

#gutter_widthObject



52
53
54
55
56
# File 'lib/vimamsa/gui_sourceview.rb', line 52

def gutter_width()
  winwidth = width
  view_width = visible_rect.width
  gutter_width = winwidth - view_width
end

#handle_deltasObject



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
# File 'lib/vimamsa/gui_sourceview.rb', line 434

def handle_deltas()
  any_change = false
  while d = @bufo.deltas.shift
    any_change = true
    pos = d[0]
    op = d[1]
    num = d[2]
    txt = d[3]
    if op == DELETE
      startiter = buffer.get_iter_at(:offset => pos)
      enditer = buffer.get_iter_at(:offset => pos + num)
      buffer.delete(startiter, enditer)
    elsif op == INSERT
      startiter = buffer.get_iter_at(:offset => pos)
      buffer.insert(startiter, txt)
    end
  end
  if any_change
    #TODO: only when necessary
    self.set_cursor_pos(pos)
  end

  # sanity_check #TODO
end

#handle_key_event(keyval, keyname, sig) ⇒ Object

def handle_key_event(event, sig)



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/vimamsa/gui_sourceview.rb', line 301

def handle_key_event(keyval, keyname, sig)
  if $update_cursor
    handle_scrolling
  end
  debug $view.visible_rect.inspect

  debug "key event" + [keyval, @last_keyval, keyname, sig].to_s
  # debug event

  # key_name = event.string
  #TODO:??
  # if event.state.control_mask?
  # key_name = Gdk::Keyval.to_name(event.keyval)
  # Gdk::Keyval.to_name()
  # end

  keyval_trans = {}
  keyval_trans[Gdk::Keyval::KEY_Control_L] = "ctrl"
  keyval_trans[Gdk::Keyval::KEY_Control_R] = "ctrl"

  keyval_trans[Gdk::Keyval::KEY_Escape] = "esc"

  keyval_trans[Gdk::Keyval::KEY_Return] = "enter"
  keyval_trans[Gdk::Keyval::KEY_ISO_Enter] = "enter"
  keyval_trans[Gdk::Keyval::KEY_KP_Enter] = "enter"
  keyval_trans[Gdk::Keyval::KEY_Alt_L] = "alt"
  keyval_trans[Gdk::Keyval::KEY_Alt_R] = "alt"
  keyval_trans[Gdk::Keyval::KEY_Caps_Lock] = "caps"

  keyval_trans[Gdk::Keyval::KEY_BackSpace] = "backspace"
  keyval_trans[Gdk::Keyval::KEY_KP_Page_Down] = "pagedown"
  keyval_trans[Gdk::Keyval::KEY_KP_Page_Up] = "pageup"
  keyval_trans[Gdk::Keyval::KEY_Page_Down] = "pagedown"
  keyval_trans[Gdk::Keyval::KEY_Page_Up] = "pageup"
  keyval_trans[Gdk::Keyval::KEY_Left] = "left"
  keyval_trans[Gdk::Keyval::KEY_Right] = "right"
  keyval_trans[Gdk::Keyval::KEY_Down] = "down"
  keyval_trans[Gdk::Keyval::KEY_Up] = "up"
  keyval_trans[Gdk::Keyval::KEY_space] = "space"

  keyval_trans[Gdk::Keyval::KEY_Shift_L] = "shift"
  keyval_trans[Gdk::Keyval::KEY_Shift_R] = "shift"
  keyval_trans[Gdk::Keyval::KEY_Tab] = "tab"
  keyval_trans[Gdk::Keyval::KEY_ISO_Left_Tab] = "tab"

  key_trans = {}
  key_trans["\e"] = "esc"
  tk = keyval_trans[keyval]
  keyname = tk if !tk.nil?

  key_str_parts = []
  key_str_parts << "ctrl" if vma.kbd.modifiers[:ctrl]
  key_str_parts << "alt" if vma.kbd.modifiers[:alt]
  key_str_parts << "shift" if vma.kbd.modifiers[:shift]
  key_str_parts << "meta" if vma.kbd.modifiers[:meta]
  key_str_parts << "super" if vma.kbd.modifiers[:super]
  key_str_parts << keyname

  # After remapping capslock to control in gnome-tweak tool,
  # if pressing and immediately releasing the capslock (control) key,
  # we get first "caps" on keydown and ctrl-"caps" on keyup (keyval 65509, Gdk::Keyval::KEY_Caps_Lock)
  # If mapping capslock to ctrl in hardware, we get keyval 65507 (Gdk::Keyval::KEY_Control_L) instead
  if key_str_parts[0] == "ctrl" and key_str_parts[1] == "caps"
    # Replace ctrl-caps with ctrl
    key_str_parts.delete_at(1)
  end

  if key_str_parts[0] == key_str_parts[1]
    # We don't want "ctrl-ctrl" or "alt-alt"
    # TODO:There should be a better way to do this
    key_str_parts.delete_at(0)
  end

  if key_str_parts[0] == "shift" and key_str_parts.size == 2
    if key_str_parts[1].size == 1 # and key_str_parts[1].match(/^[[:upper:]]$/)
      #"shift-P" to just "P" etc.
      # but keep shift-tab as is
      key_str_parts.delete_at(0)
    end
  end

  key_str = key_str_parts.join("-")
  if key_str == "\u0000"
    key_str = ""
  end

  keynfo = { :key_str => key_str, :key_name => keyname, :keyval => keyval }
  debug keynfo.inspect
  # vma.kbd.match_key_conf(key_str, nil, :key_press)
  # debug "key_str=#{key_str} key_"

  if key_str != "" # or prefixed_key_str != ""
    if sig == :key_release and keyval == @last_keyval
      vma.kbd.match_key_conf(key_str + "!", nil, :key_release)
      @last_event = [keynfo, :key_release]
    elsif sig == :key_press
      vma.kbd.match_key_conf(key_str, nil, :key_press)
      @last_event = [keynfo, key_str, :key_press]
    end
  end
  @last_keyval = keyval

  handle_deltas

  # set_focus(5)
  # false

  draw_cursor #TODO: only when needed
end

#handle_scrollingObject



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/vimamsa/gui_sourceview.rb', line 269

def handle_scrolling()
  return # TODO
  # curpos = buffer.cursor_position
  # debug "MOVE CURSOR: #{curpos}"
  return nil if vma.gui.nil?
  return nil if @bufo.nil?
  vma.gui.run_after_scrolling proc {
    debug "START UPDATE POS AFTER SCROLLING", 2
    bc = window_to_buffer_coords(Gtk::TextWindowType::WIDGET, gutter_width + 2, 60)
    if !bc.nil?
      i = coord_to_iter(bc[0], bc[1])
      if !i.nil?
        @bufo.set_pos(i)
      end
    end
    $update_cursor = false
  }
end

#hide_completionsObject



43
44
45
46
47
48
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 43

def hide_completions
  if @acwin.class == Gtk::Popover
    @acwin.hide
  end
  @autocp_active = false
end

#is_cursor_visibleObject



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
# File 'lib/vimamsa/gui_sourceview.rb', line 527

def is_cursor_visible
  vr = visible_rect
  iter = buffer.get_iter_at(:offset => buffer.cursor_position)
  iterxy = get_iter_location(iter)
  iterxy.width = 1 if iterxy.width == 0
  iterxy.height = 1 if iterxy.height == 0

  intr = iterxy.intersect(vr)
  if intr.nil?
    debug iterxy.inspect
    debug vr.inspect
    return false
  else
    return true
  end
end

#pos_to_coord(i) ⇒ Object



411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/vimamsa/gui_sourceview.rb', line 411

def pos_to_coord(i)
  b = buffer
  iter = b.get_iter_at(:offset => i)
  iterxy = get_iter_location(iter)
  winw = width #TODO

  view_width = visible_rect.width
  gutter_width = winw - view_width #TODO

  x = iterxy.x + gutter_width
  y = iterxy.y

  # buffer_to_window_coords(Gtk::TextWindowType::TEXT, iterxy.x, iterxy.y).inspect
  # debug buffer_to_window_coords(Gtk::TextWindowType::TEXT, x, y).inspect
  (x, y) = buffer_to_window_coords(Gtk::TextWindowType::TEXT, x, y)

  return [x, y]
end

#register_signalsObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/vimamsa/gui_sourceview.rb', line 112

def register_signals()
  check_controllers

  # TODO: accept GLib::Type::STRING also?
  @dt = Gtk::DropTarget.new(GLib::Type["GFile"], [Gdk::DragAction::COPY, Gdk::DragAction::MOVE])
  # GLib::Type::INVALID

  self.add_controller(@dt)
  @dt.signal_connect "drop" do |obj, v, x, y|
    if v.value.gtype == GLib::Type["GLocalFile"]
      uri = v.value.uri
    elsif v.value.class == String
      uri = v.value.gsub(/\r\n$/, "")
    end
    debug "dt,drop #{v.value},#{x},#{y}", 2
    fp = uri_to_path(uri)
    buf.handle_drag_and_drop(fp) if !fp.nil?
    true
  end

  @dt.signal_connect "enter" do |gesture, x, y, z, m|
    debug "dt,enter", 2
    Gdk::DragAction::COPY
  end

  @dt.signal_connect "motion" do |obj, x, y|
    debug "dt,move", 2

    Gdk::DragAction::COPY
  end

  # dc = Gtk::DropControllerMotion.new
  # self.add_controller(dc)
  # dc.signal_connect "enter" do |gesture, x, y|
  # debug "enter", 2
  # debug [x, y]
  # # Ripl.start :binding => binding
  # true
  # end

  # dc.signal_connect "motion" do |gesture, x, y|
  # debug "move", 2
  # debug [x, y]
  # true
  # end

  # Implement mouse selections using @cnt_mo and @cnt_drag
  @cnt_mo = Gtk::EventControllerMotion.new
  self.add_controller(@cnt_mo)
  @cnt_mo.signal_connect "motion" do |gesture, x, y|
    if !@range_start.nil? and !x.nil? and !y.nil? and buf.visual_mode?
      i = coord_to_iter(x, y, true)
      @bufo.set_pos(i) if !i.nil? and @last_iter != i
      @last_iter = i
    end
  end

  @last_coord = nil
  @cnt_drag = Gtk::GestureDrag.new
  self.add_controller(@cnt_drag)
  @cnt_drag.signal_connect "drag-begin" do |gesture, x, y|
    debug "drag-begin", 2
    i = coord_to_iter(x, y, true)
    pp i
    @range_start = i
    buf.start_selection
  end

  @cnt_drag.signal_connect "drag-end" do |gesture, offsetx, offsety|
    debug "drag-end", 2
    if offsetx.abs < 5 and offsety.abs < 5
      debug "Not enough drag", 2
      buf.end_selection
      # elsif !buf.visual_mode? and vma.kbd.get_scope != :editor
    elsif vma.kbd.get_scope != :editor
      # Can't transition from editor wide mode to buffer specific mode
      vma.kbd.set_mode(:visual)
    else
      buf.end_selection
    end
    @range_start = nil
  end

  click = Gtk::GestureClick.new
  click.set_propagation_phase(Gtk::PropagationPhase::CAPTURE)
  self.add_controller(click)
  # Detect mouse click
  @click = click

  @range_start = nil
  click.signal_connect "pressed" do |gesture, n_press, x, y, z|
    debug "SourceView, GestureClick released x=#{x} y=#{y}"

    if buf.visual_mode?
      buf.end_visual_mode
    end

    xloc = (x - gutter_width).to_i
    yloc = (y + visible_rect.y).to_i
    debug "xloc=#{xloc} yloc=#{yloc}"

    i = coord_to_iter(xloc, yloc)
    # @range_start = i

    # This needs to happen after xloc calculation, otherwise xloc gets a wrong value (around 200 bigger)
    if vma.gui.current_view != self
      vma.gui.set_current_view(self)
    end

    @bufo.set_pos(i) if !i.nil?
    true
  end

  click.signal_connect "released" do |gesture, n_press, x, y, z|
    debug "SourceView, GestureClick released x=#{x} y=#{y}"

    xloc = (x - gutter_width).to_i
    yloc = (y + visible_rect.y).to_i
    debug "xloc=#{xloc} yloc=#{yloc}"

    # This needs to happen after xloc calculation, otherwise xloc gets a wrong value (around 200 bigger)
    if vma.gui.current_view != self
      vma.gui.set_current_view(self)
    end

    i = coord_to_iter(xloc, yloc)

    # if i != @range_start
    # debug "RANGE #{[@range_start, i]}", 2
    # end

    @bufo.set_pos(i) if !i.nil?
    # @range_start = nil
    true
  end
end

#sanity_checkObject



459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/vimamsa/gui_sourceview.rb', line 459

def sanity_check()
  a = buffer.text
  b = buf.to_s
  # debug "===================="
  # debug a.lines[0..10].join()
  # debug "===================="
  # debug b.lines[0..10].join()
  # debug "===================="
  if a == b
    debug "Buffers match"
  else
    debug "ERROR: Buffer's don't match."
  end
end

#set_content(str) ⇒ Object



48
49
50
# File 'lib/vimamsa/gui_sourceview.rb', line 48

def set_content(str)
  self.buffer.set_text(str)
end

#set_cursor_color(ctype) ⇒ Object



563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
# File 'lib/vimamsa/gui_sourceview.rb', line 563

def set_cursor_color(ctype)
  if @ctype != ctype
    bg = $confh[:mode][ctype][:cursor][:background]
    if bg.class == String
      if !@cursor_prov.nil?
        self.style_context.remove_provider(@cursor_prov)
      end
      prov = Gtk::CssProvider.new
      # prov.load(data: ".view text selection { background-color: #{bg}; color: #ffffff; }")
      prov.load(data: ".view text selection { background-color: #{bg}; color: #ffffff; } .view { caret-color: #{bg};  }")
      self.style_context.add_provider(prov)
      @cursor_prov = prov
    end
    @ctype == ctype
  end
end

#set_cursor_pos(pos) ⇒ Object



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
# File 'lib/vimamsa/gui_sourceview.rb', line 474

def set_cursor_pos(pos)
  itr = buffer.get_iter_at(:offset => pos)
  itr2 = buffer.get_iter_at(:offset => pos + 1)
  buffer.place_cursor(itr)

  within_margin = 0.075 #margin as a [0.0,0.5) fraction of screen size
  use_align = false
  xalign = 0.5 #0.0=top 1.0=bottom, 0.5=center
  yalign = 0.5

  if @curpos_mark.nil?
    @curpos_mark = buffer.create_mark("cursor", itr, false)
  else
    buffer.move_mark(@curpos_mark, itr)
  end
  scroll_to_mark(@curpos_mark, within_margin, use_align, xalign, yalign)
  $idle_scroll_to_mark = true
  ensure_cursor_visible

  # draw_cursor

  return true
end

#set_cursor_to_topObject



288
289
290
291
292
293
294
295
296
297
298
# File 'lib/vimamsa/gui_sourceview.rb', line 288

def set_cursor_to_top
  debug "set_cursor_to_top", 2
  bc = window_to_buffer_coords(Gtk::TextWindowType::WIDGET, gutter_width + 2, 60)
  if !bc.nil?
    i = coord_to_iter(bc[0], bc[1])
    if !i.nil?
      @bufo.set_pos(i)
      set_cursor_pos(i)
    end
  end
end

#show_completionsObject



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 93

def show_completions
  hide_completions
  bu = vma.buf
  (w, range) = bu.get_word_in_pos(bu.pos - 1, boundary: :word)
  debug [w, range].to_s, 2
  matches = Autocomplete.matching_words w
  return if matches.empty?
  @autocp_active = true
  @cpl_list = cpl_list = matches
  win = Gtk::Popover.new()
  win.parent = self
  vbox = Gtk::Grid.new()
  win.set_child(vbox)

  i = 0
  @autocp_items = []
  @autocp_selected = 0
  for x in cpl_list
    l = Gtk::Label.new(x)
    @autocp_items << l
    # numbers: left, top, width, height
    vbox.attach(l, 0, i, 1, 1)
    i += 1
  end
  autocp_hilight(0)
  (x, y) = cur_pos_xy
  rec = Gdk::Rectangle.new(x, y + 8, 10, 10)
  win.has_arrow = false
  win.set_pointing_to(rec)
  win.autohide = false
  win.popup
  gui_remove_controllers(win)
  @acwin = win
end

#show_controllersObject



58
59
60
61
62
63
64
# File 'lib/vimamsa/gui_sourceview.rb', line 58

def show_controllers
  clist = self.observe_controllers
  (0..(clist.n_items - 1)).each { |x|
    ctr = clist.get_item(x)
    pp ctr
  }
end

#start_autocompleteObject



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 128

def start_autocomplete
  return
  # Roughly following these examples:
  # https://stackoverflow.com/questions/52359721/howto-maintain-gtksourcecompletion-when-changing-buffers-in-a-gtksourceview
  # and gedit-plugins-41.0/plugins/wordcompletion/gedit-word-completion-plugin.c
  # .. but it doesn't work. So implementing using Popover.
  # Keeping this for reference

  cp = self.completion
  prov = GtkSource::CompletionWords.new("Autocomplete") # (name,icon)
  prov.register(self.buffer)
  cp.add_provider(prov)
  pp prov
  self.show_completion
end

#try_autocompleteObject



90
91
# File 'lib/vimamsa/gui_sourceview_autocomplete.rb', line 90

def try_autocomplete
end