vimamsa 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/custom_example.rb +12 -0
  3. data/lib/vimamsa/ack.rb +3 -4
  4. data/lib/vimamsa/actions.rb +1 -2
  5. data/lib/vimamsa/audio.rb +25 -1
  6. data/lib/vimamsa/buffer.rb +116 -591
  7. data/lib/vimamsa/buffer_changetext.rb +272 -0
  8. data/lib/vimamsa/buffer_cursor.rb +303 -0
  9. data/lib/vimamsa/buffer_list.rb +137 -133
  10. data/lib/vimamsa/buffer_manager.rb +15 -15
  11. data/lib/vimamsa/clipboard.rb +36 -0
  12. data/lib/vimamsa/conf.rb +136 -5
  13. data/lib/vimamsa/constants.rb +0 -10
  14. data/lib/vimamsa/debug.rb +9 -8
  15. data/lib/vimamsa/editor.rb +57 -84
  16. data/lib/vimamsa/encrypt.rb +6 -11
  17. data/lib/vimamsa/file_history.rb +0 -8
  18. data/lib/vimamsa/file_manager.rb +142 -10
  19. data/lib/vimamsa/gui.rb +106 -85
  20. data/lib/vimamsa/gui_dialog.rb +113 -0
  21. data/lib/vimamsa/gui_menu.rb +5 -1
  22. data/lib/vimamsa/gui_sourceview.rb +46 -29
  23. data/lib/vimamsa/gui_sourceview_autocomplete.rb +141 -0
  24. data/lib/vimamsa/gui_text.rb +49 -0
  25. data/lib/vimamsa/hyper_plain_text.rb +19 -5
  26. data/lib/vimamsa/key_actions.rb +41 -202
  27. data/lib/vimamsa/key_binding_tree.rb +129 -41
  28. data/lib/vimamsa/key_bindings_vimlike.rb +58 -48
  29. data/lib/vimamsa/langservp.rb +23 -3
  30. data/lib/vimamsa/macro.rb +35 -25
  31. data/lib/vimamsa/main.rb +7 -10
  32. data/lib/vimamsa/rbvma.rb +13 -11
  33. data/lib/vimamsa/search.rb +1 -1
  34. data/lib/vimamsa/search_replace.rb +106 -160
  35. data/lib/vimamsa/terminal.rb +34 -0
  36. data/lib/vimamsa/tests.rb +122 -0
  37. data/lib/vimamsa/util.rb +43 -4
  38. data/lib/vimamsa/version.rb +1 -1
  39. data/vimamsa.gemspec +5 -2
  40. metadata +59 -9
  41. /data/lib/vimamsa/{form_generator.rb → gui_form_generator.rb} +0 -0
@@ -12,9 +12,9 @@ $update_highlight = false
12
12
  $ifuncon = false
13
13
 
14
14
  class Buffer < String
15
- attr_reader :pos, :lpos, :cpos, :deltas, :edit_history, :fname, :call_func, :pathname, :basename, :dirname, :update_highlight, :marks, :is_highlighted, :syntax_detect_failed, :id, :lang, :images, :last_save
15
+ attr_reader :pos, :lpos, :cpos, :deltas, :edit_history, :fname, :call_func, :pathname, :basename, :dirname, :update_highlight, :marks, :is_highlighted, :syntax_detect_failed, :id, :lang, :images, :last_save, :access_time
16
16
  attr_writer :call_func, :update_highlight
17
- attr_accessor :gui_update_highlight, :update_hl_startpos, :update_hl_endpos, :hl_queue, :syntax_parser, :highlights, :gui_reset_highlight, :is_parsing_syntax, :line_ends, :bt, :line_action_handler, :module, :active_kbd_mode, :title, :subtitle, :paste_lines
17
+ attr_accessor :gui_update_highlight, :update_hl_startpos, :update_hl_endpos, :hl_queue, :syntax_parser, :highlights, :gui_reset_highlight, :is_parsing_syntax, :line_ends, :bt, :line_action_handler, :module, :active_kbd_mode, :title, :subtitle, :paste_lines, :mode_stack, :default_mode
18
18
 
19
19
  @@num_buffers = 0
20
20
 
@@ -22,12 +22,15 @@ class Buffer < String
22
22
  debug "Buffer.rb: def initialize"
23
23
  super(str)
24
24
 
25
+ update_access_time
25
26
  @images = []
26
27
  @audiofiles = []
27
28
  @lang = nil
28
29
  @id = @@num_buffers
29
30
  @@num_buffers += 1
30
31
  @version = 0
32
+ @default_mode = vma.kbd.default_mode
33
+ @mode_stack = [@default_mode]
31
34
  gui_create_buffer(@id, self)
32
35
  debug "NEW BUFFER fn=#{fname} ID:#{@id}"
33
36
 
@@ -74,7 +77,7 @@ class Buffer < String
74
77
  self << "\n" if self[-1] != "\n"
75
78
  @current_word = nil
76
79
  @active_kbd_mode = nil
77
- if conf(:enable_lsp)
80
+ if cnf.lsp.enabled?
78
81
  init_lsp
79
82
  end
80
83
  return self
@@ -89,17 +92,35 @@ class Buffer < String
89
92
  return x
90
93
  end
91
94
 
95
+ #Check if this buffer is attached to any windows
96
+ def is_active
97
+ for k in vma.gui.windows.keys
98
+ return true if vma.gui.windows[k][:sw].child.bufo == self
99
+ end
100
+ return false
101
+ end
102
+
103
+ def update_access_time
104
+ @access_time = Time.now
105
+ end
106
+
107
+ # This function is to be called whenever keyboard events start affecting this buffer
108
+ # e.g. switching between buffers, opening a new (this) file
92
109
  def set_active
93
- if !@active_kbd_mode.nil?
94
- $kbd.set_mode(@active_kbd_mode)
95
- else
96
- $kbd.set_mode_to_default
110
+ debug "def set_active", 2
111
+ if vma.kbd.get_scope != :editor
112
+ # If current keyboard mode is not an editor wide mode spanning multiple buffers(e.g. browsing)
113
+ restore_kbd_mode
97
114
  end
98
- # gui_set_current_buffer(@id)
115
+ end
116
+
117
+ # Restore the previous keyboard mode specific to this buffer
118
+ def restore_kbd_mode
119
+ vma.kbd.set_mode_stack(@mode_stack.clone)
99
120
  end
100
121
 
101
122
  def set_executable
102
- if File.exists?(@fname)
123
+ if File.exist?(@fname)
103
124
  FileUtils.chmod("+x", @fname)
104
125
  message("Set executable: #{@fname}")
105
126
  end
@@ -113,6 +134,7 @@ class Buffer < String
113
134
  end
114
135
 
115
136
  def lsp_jump_to_def()
137
+ message("LSP not activated") if @lsp.nil?
116
138
  if !@lsp.nil?
117
139
  fpuri = URI.join("file:///", @fname).to_s
118
140
  r = @lsp.get_definition(fpuri, @lpos, @cpos)
@@ -123,8 +145,9 @@ class Buffer < String
123
145
  end
124
146
 
125
147
  def init_lsp()
126
- if conf(:enable_lsp) and !@lang.nil?
127
- @lsp = LangSrv.get(@lang.to_sym)
148
+ if cnf.lsp.enabled?
149
+ @lsp = LangSrv.get(@lang)
150
+
128
151
  if @lang == "php"
129
152
  # Ripl.start :binding => binding
130
153
  end
@@ -156,7 +179,7 @@ class Buffer < String
156
179
  debug "Guessed LANG: #{lang.id}"
157
180
  @lang = lang.id
158
181
  end
159
- puts @lang.inspect
182
+ debug @lang.inspect
160
183
 
161
184
  if @lang
162
185
  gui_set_file_lang(@id, @lang)
@@ -213,6 +236,7 @@ class Buffer < String
213
236
  $audiof = mf
214
237
  end
215
238
 
239
+ #TODO: remove?
216
240
  def reset_audio_widget_positions
217
241
  debug "reset_audio_widget_positions", 2
218
242
  for mc in @audiofiles
@@ -222,6 +246,11 @@ class Buffer < String
222
246
  return false
223
247
  end
224
248
 
249
+ def scan_all_words
250
+ words = self.scan(/\b\w+\b/).uniq
251
+ return words
252
+ end
253
+
225
254
  def add_image(imgpath, pos)
226
255
  return if !is_legal_pos(pos)
227
256
 
@@ -246,16 +275,6 @@ class Buffer < String
246
275
  gui_set_current_buffer(@id) #TODO: needed?
247
276
  end
248
277
 
249
- def is_legal_pos(pos, op = :read)
250
- return false if pos < 0
251
- if op == :add
252
- return false if pos > self.size
253
- elsif op == :read
254
- return false if pos >= self.size
255
- end
256
- return true
257
- end
258
-
259
278
  def set_encrypted(password)
260
279
  @crypt = Encrypt.new(password)
261
280
  message("Set buffer encrypted")
@@ -265,19 +284,18 @@ class Buffer < String
265
284
  @crypt = nil
266
285
  end
267
286
 
268
- def add_new_line(txt)
269
- # buf.jump(END_OF_LINE);buf.insert_txt("\n");
270
- end
271
-
272
- def insert_image_after_current_line(fname)
273
- lr = current_line_range()
274
- a = "⟦img:#{fname}⟧\n"
275
- b = " \n"
276
- txt = a + b
277
- insert_txt_at(txt, lr.end + 1)
278
- buf.view.handle_deltas
279
- imgpos = lr.end + 1 + a.size
280
- add_image(fname, imgpos)
287
+ def unindent
288
+ debug("unindent", 2)
289
+ conf(:tab_width).times {
290
+ p = @pos - 1
291
+ if p >= 0
292
+ if self[p] == " "
293
+ delete(BACKWARD_CHAR)
294
+ end
295
+ else
296
+ break
297
+ end
298
+ }
281
299
  end
282
300
 
283
301
  def handle_drag_and_drop(fname)
@@ -300,13 +318,14 @@ class Buffer < String
300
318
 
301
319
  def revert()
302
320
  return if !@fname
303
- return if !File.exists?(@fname)
321
+ return if !File.exist?(@fname)
304
322
  message("Revert buffer #{@fname}")
305
323
  str = read_file("", @fname)
306
324
  self.set_content(str)
307
325
  end
308
326
 
309
327
  def decrypt(password)
328
+ return if @encrypted_str.nil?
310
329
  begin
311
330
  @crypt = Encrypt.new(password)
312
331
  str = @crypt.decrypt(@encrypted_str)
@@ -347,11 +366,9 @@ class Buffer < String
347
366
  @ftype = nil
348
367
  if str[0..10] == "VMACRYPT001"
349
368
  @encrypted_str = str[11..-1]
350
- callback = proc { |x| decrypt_cur_buffer(x) }
351
- gui_one_input_action("Decrypt", "Password:", "decrypt", callback, { :hide => true })
369
+ callback = proc { |x| self.decrypt(x) }
370
+ gui_one_input_action("Decrypt file \n #{@fname}", "Password:", "decrypt", callback, { :hide => true })
352
371
  str = "ENCRYPTED"
353
- else
354
- # @crypt = nil
355
372
  end
356
373
 
357
374
  if (str[-1] != "\n")
@@ -360,11 +377,12 @@ class Buffer < String
360
377
 
361
378
  self.replace(str)
362
379
  @line_ends = scan_indexes(self, /\n/)
380
+ words = scan_all_words
381
+ Autocomplete.add_words(words)
363
382
 
364
- # @bt = BufferTree.new(str)
365
- if $experimental
383
+ if cnf.btree.experimental?
366
384
  @bt = BufferTree.new(self)
367
- if $debug
385
+ if cnf.debug?
368
386
  sanitycheck_btree()
369
387
  end
370
388
  end
@@ -426,65 +444,6 @@ class Buffer < String
426
444
  return fpath
427
445
  end
428
446
 
429
- def line(lpos)
430
- if @line_ends.size == 0
431
- return self
432
- end
433
-
434
- #TODO: implement using line_range()
435
- if lpos >= @line_ends.size
436
- debug("lpos too large") #TODO
437
- return ""
438
- elsif lpos == @line_ends.size
439
- end
440
- start = @line_ends[lpos - 1] + 1 if lpos > 0
441
- start = 0 if lpos == 0
442
- _end = @line_ends[lpos]
443
- debug "start: _#{start}, end: #{_end}"
444
- return self[start.._end]
445
- end
446
-
447
- def is_delta_ok(delta)
448
- ret = true
449
- pos = delta[0]
450
- if pos < 0
451
- ret = false
452
- debug "pos=#{pos} < 0"
453
- elsif pos > self.size
454
- debug "pos=#{pos} > self.size=#{self.size}"
455
- ret = false
456
- end
457
- if ret == false
458
- # crash("DELTA OK=#{ret}")
459
- end
460
- return ret
461
- end
462
-
463
- #TODO: change to apply=true as default
464
- def add_delta(delta, apply = false, auto_update_cpos = false)
465
- return if !is_delta_ok(delta)
466
- if delta[1] == DELETE
467
- return if delta[0] >= self.size
468
- # If go over length of buffer
469
- if delta[0] + delta[2] >= self.size
470
- delta[2] = self.size - delta[0]
471
- end
472
- end
473
-
474
- @edit_version += 1
475
- @redo_stack = []
476
- if apply
477
- delta = run_delta(delta, auto_update_cpos)
478
- else
479
- @deltas << delta
480
- end
481
- @edit_history << delta
482
- if self[-1] != "\n"
483
- add_delta([self.size, INSERT, 1, "\n"], true)
484
- end
485
- reset_larger_cpos #TODO: correct here?
486
- end
487
-
488
447
  def add_hl_update(startpos, endpos)
489
448
  return if @is_highlighted == false
490
449
 
@@ -501,7 +460,7 @@ class Buffer < String
501
460
  # delta[3]: text to add in case of insert
502
461
 
503
462
  @version += 1
504
- if $experimental
463
+ if cnf.btree.experimental?
505
464
  @bt.handle_delta(Delta.new(delta[0], delta[1], delta[2], delta[3]))
506
465
  end
507
466
 
@@ -585,35 +544,6 @@ class Buffer < String
585
544
  end
586
545
  end
587
546
 
588
- def jump_to_last_edit()
589
- return if @edit_pos_history.empty?
590
- @edit_pos_history_i += 1
591
-
592
- if @edit_pos_history_i > @edit_pos_history.size
593
- @edit_pos_history_i = 0
594
- end
595
-
596
- # if @edit_pos_history.size >= @edit_pos_history_i
597
- set_pos(@edit_pos_history[-@edit_pos_history_i])
598
- center_on_current_line
599
- return true
600
- # end
601
- end
602
-
603
- def jump_to_next_edit()
604
- return if @edit_pos_history.empty?
605
- @edit_pos_history_i -= 1
606
- @edit_pos_history_i = @edit_pos_history.size - 1 if @edit_pos_history_i < 0
607
- debug "@edit_pos_history_i=#{@edit_pos_history_i}"
608
- set_pos(@edit_pos_history[-@edit_pos_history_i])
609
- center_on_current_line
610
- return true
611
- end
612
-
613
- def jump_to_random_pos()
614
- set_pos(rand(self.size))
615
- end
616
-
617
547
  def undo()
618
548
  debug @edit_history.inspect
619
549
  return if !@edit_history.any?
@@ -757,10 +687,10 @@ class Buffer < String
757
687
  end
758
688
 
759
689
  def get_repeat_num()
760
- $method_handles_repeat = true
690
+ vma.kbd.method_handles_repeat = true
761
691
  repeat_num = 1
762
- if !$next_command_count.nil? and $next_command_count > 0
763
- repeat_num = $next_command_count
692
+ if !vma.kbd.next_command_count.nil? and vma.kbd.next_command_count > 0
693
+ repeat_num = vma.kbd.next_command_count
764
694
  end
765
695
  return repeat_num
766
696
  end
@@ -775,11 +705,6 @@ class Buffer < String
775
705
  end
776
706
  end
777
707
 
778
- def replace_range(range, text)
779
- delete_range(range.first, range.last)
780
- insert_txt_at(text, range.begin)
781
- end
782
-
783
708
  def current_line_range()
784
709
  range = line_range(@lpos, 1)
785
710
  return range
@@ -809,7 +734,7 @@ class Buffer < String
809
734
  debug range_id.inspect
810
735
  range = get_range(range_id)
811
736
  debug range.inspect
812
- set_clipboard(self[range])
737
+ vma.clipboard.set(self[range])
813
738
  end
814
739
 
815
740
  def recalc_line_ends()
@@ -891,148 +816,6 @@ class Buffer < String
891
816
  end
892
817
  end
893
818
 
894
- def at_end_of_line?()
895
- return (self[@pos] == "\n" or at_end_of_buffer?)
896
- end
897
-
898
- def at_end_of_buffer?()
899
- return @pos == self.size
900
- end
901
-
902
- def jump_to_pos(new_pos)
903
- set_pos(new_pos)
904
- end
905
-
906
- def set_pos(new_pos)
907
- if new_pos >= self.size
908
- @pos = self.size - 1 # TODO:??right side of last char
909
- elsif new_pos >= 0
910
- @pos = new_pos
911
- end
912
- gui_set_cursor_pos(@id, @pos)
913
- calculate_line_and_column_pos
914
-
915
- check_if_modified_outside
916
- end
917
-
918
- # Get the line number of character position
919
- def get_line_pos(pos)
920
- lpos = @line_ends.bsearch_index { |x, _| x >= pos }
921
- return lpos
922
- end
923
-
924
- # Calculate the two dimensional column and line positions based on
925
- # (one dimensional) position in the buffer.
926
- def get_line_and_col_pos(pos)
927
- pos = self.size if pos > self.size
928
- pos = 0 if pos < 0
929
-
930
- lpos = get_line_pos(pos)
931
-
932
- lpos = @line_ends.size if lpos == nil
933
- cpos = pos
934
- cpos -= @line_ends[lpos - 1] + 1 if lpos > 0
935
-
936
- return [lpos, cpos]
937
- end
938
-
939
- def calculate_line_and_column_pos(reset = true)
940
- @lpos, @cpos = get_line_and_col_pos(@pos)
941
- reset_larger_cpos if reset
942
- end
943
-
944
- def set_line_and_column_pos(lpos, cpos, _reset_larger_cpos = true)
945
- @lpos = lpos if !lpos.nil?
946
- @cpos = cpos if !cpos.nil?
947
- if @lpos > 0
948
- new_pos = @line_ends[@lpos - 1] + 1
949
- else
950
- new_pos = 0
951
- end
952
-
953
- if @cpos > (line(@lpos).size - 1)
954
- debug("$cpos too large: #{@cpos} #{@lpos}")
955
- if @larger_cpos < @cpos
956
- @larger_cpos = @cpos
957
- end
958
- @cpos = line(@lpos).size - 1
959
- end
960
- new_pos += @cpos
961
- set_pos(new_pos)
962
- reset_larger_cpos if _reset_larger_cpos
963
- end
964
-
965
- # Calculate the one dimensional array index based on column and line positions
966
- def calculate_pos_from_cpos_lpos(reset = true)
967
- set_line_and_column_pos(nil, nil)
968
- end
969
-
970
- def delete2(range_id, mark = nil)
971
- # if mark != nil
972
- # debug mark, 2
973
- # return
974
- # end
975
-
976
- @paste_lines = false
977
- range = get_range(range_id, mark: mark)
978
- return if range == nil
979
- debug "RANGE"
980
- debug range.inspect
981
- debug range.inspect
982
- debug "------"
983
- delete_range(range.first, range.last)
984
- pos = [range.first, @pos].min
985
- set_pos(pos)
986
- end
987
-
988
- def delete(op, x = nil)
989
- @paste_lines = false
990
- # Delete selection
991
- if op == SELECTION && visual_mode?
992
- (startpos, endpos) = get_visual_mode_range2
993
- delete_range(startpos, endpos, x)
994
- @pos = [@pos, @selection_start].min
995
- end_visual_mode
996
- #return
997
-
998
- # Delete current char
999
- elsif op == CURRENT_CHAR_FORWARD
1000
- return if @pos >= self.size - 1 # May not delete last '\n'
1001
- add_delta([@pos, DELETE, 1], true)
1002
-
1003
- # Delete current char and then move backward
1004
- elsif op == CURRENT_CHAR_BACKWARD
1005
- add_delta([@pos, DELETE, 1], true)
1006
- @pos -= 1
1007
-
1008
- # Delete the char before current char and move backward
1009
- elsif op == BACKWARD_CHAR and @pos > 0
1010
- add_delta([@pos - 1, DELETE, 1], true)
1011
- @pos -= 1
1012
- elsif op == FORWARD_CHAR #TODO: ok?
1013
- add_delta([@pos + 1, DELETE, 1], true)
1014
- end
1015
- set_pos(@pos)
1016
- #recalc_line_ends
1017
- calculate_line_and_column_pos
1018
- #need_redraw!
1019
- end
1020
-
1021
- def delete_range(startpos, endpos, x = nil)
1022
- s = self[startpos..endpos]
1023
- if startpos == endpos or s == ""
1024
- return
1025
- end
1026
- if x == :append
1027
- debug "APPEND"
1028
- s += "\n" + get_clipboard()
1029
- end
1030
- set_clipboard(s)
1031
- add_delta([startpos, DELETE, (endpos - startpos + 1)], true)
1032
- #recalc_line_ends
1033
- calculate_line_and_column_pos
1034
- end
1035
-
1036
819
  # Ranges to use in delete or copy operations
1037
820
  def get_range(range_id, mark: nil)
1038
821
  range = nil
@@ -1040,7 +823,7 @@ class Buffer < String
1040
823
  # TODO: better way to make the search than + 150 from current position
1041
824
  wmarks = get_word_end_marks(@pos, @pos + 150)
1042
825
  if wmarks.any?
1043
- range = @pos..wmarks[0]
826
+ range = @pos..(wmarks[0])
1044
827
  end
1045
828
  elsif range_id == :to_next_word # start of
1046
829
  wmarks = get_word_start_marks(@pos, @pos + 150)
@@ -1276,15 +1059,28 @@ class Buffer < String
1276
1059
  end
1277
1060
  end
1278
1061
 
1279
- def get_cur_nonwhitespace_word()
1280
- wem = scan_marks(@pos, @pos + 200, /(?<=\S)\s/, -1)
1281
- wsm = scan_marks(@pos - 200, @pos, /((?<=\s)\S)|^\S/)
1062
+ def get_word_in_pos(p, boundary: :space)
1063
+ maxws = 200 # max word size
1064
+ if boundary == :space
1065
+ wem = scan_marks(p, p + maxws, /(?<=\S)\s/, -1)
1066
+ wsm = scan_marks(p - maxws, p, /((?<=\s)\S)|^\S/)
1067
+ word_start = wsm[-1]
1068
+ word_end = wem[0]
1069
+ elsif boundary == :word
1070
+ wsm = scan_marks(p - maxws, p, /\b\w/)
1071
+ word_start = wsm[-1]
1072
+ word_end = p
1073
+ end
1282
1074
 
1283
- word_start = wsm[-1]
1284
- word_end = wem[0]
1285
- word_start = pos if word_start == nil
1286
- word_end = pos if word_end == nil
1075
+ word_start = p if word_start == nil
1076
+ word_end = p if word_end == nil
1287
1077
  word = self[word_start..word_end]
1078
+
1079
+ return [word, (word_start..word_end)]
1080
+ end
1081
+
1082
+ def get_cur_nonwhitespace_word()
1083
+ (word, range) = get_word_in_pos(@pos, boundary: :space)
1288
1084
  debug "'WORD: #{word}'"
1289
1085
  # message("Open link #{word}")
1290
1086
  linep = get_file_line_pointer(word)
@@ -1324,141 +1120,6 @@ class Buffer < String
1324
1120
  handle_word(wnfo)
1325
1121
  end
1326
1122
 
1327
- def jump_to_next_instance_of_word()
1328
- if $kbd.last_action == $kbd.cur_action and @current_word != nil
1329
- # debug "REPEATING *"
1330
- else
1331
- start_search = [@pos - 150, 0].max
1332
-
1333
- search_str1 = self[start_search..(@pos)]
1334
- wsmarks = scan_indexes(search_str1, /(?<=[^\p{Word}])\p{Word}/)
1335
- a = wsmarks[-1]
1336
- a = 0 if a == nil
1337
-
1338
- search_str2 = self[(@pos)..(@pos + 150)]
1339
- wemarks = scan_indexes(search_str2, /(?<=\p{Word})[^\p{Word}]/)
1340
- b = wemarks[0]
1341
- word_start = (@pos - search_str1.size + a + 1)
1342
- word_start = 0 if !(word_start >= 0)
1343
- @current_word = self[word_start..(@pos + b - 1)]
1344
- end
1345
-
1346
- #TODO: search for /[^\p{Word}]WORD[^\p{Word}]/
1347
- position_of_next_word = self.index(@current_word, @pos + 1)
1348
- if position_of_next_word != nil
1349
- set_pos(position_of_next_word)
1350
- else #Search from beginning
1351
- position_of_next_word = self.index(@current_word)
1352
- set_pos(position_of_next_word) if position_of_next_word != nil
1353
- end
1354
- center_on_current_line
1355
- return true
1356
- end
1357
-
1358
- def jump_word(direction, wordpos)
1359
- offset = 0
1360
- if direction == FORWARD
1361
- debug "POS: #{@pos},"
1362
- search_str = self[(@pos)..(@pos + 250)]
1363
- return if search_str == nil
1364
- if wordpos == WORD_START # vim 'w'
1365
- wsmarks = scan_indexes(search_str, /(?<=[^\p{Word}])\p{Word}|\Z/) # \Z = end of string, just before last newline.
1366
- wsmarks2 = scan_indexes(search_str, /\n[ \t]*\n/) # "empty" lines that have whitespace
1367
- wsmarks2 = wsmarks2.collect { |x| x + 1 }
1368
- wsmarks = (wsmarks2 + wsmarks).sort.uniq
1369
- offset = 0
1370
- if wsmarks.any?
1371
- next_pos = @pos + wsmarks[0] + offset
1372
- set_pos(next_pos)
1373
- end
1374
- elsif wordpos == WORD_END
1375
- search_str = self[(@pos + 1)..(@pos + 150)]
1376
- wsmarks = scan_indexes(search_str, /(?<=\p{Word})[^\p{Word}]/)
1377
- offset = -1
1378
- if wsmarks.any?
1379
- next_pos = @pos + 1 + wsmarks[0] + offset
1380
- set_pos(next_pos)
1381
- end
1382
- end
1383
- end
1384
- if direction == BACKWARD # vim 'b'
1385
- start_search = @pos - 150 #TODO 150 length limit
1386
- start_search = 0 if start_search < 0
1387
- search_str = self[start_search..(@pos - 1)]
1388
- return if search_str == nil
1389
- wsmarks = scan_indexes(search_str,
1390
- #/(^|(\W)\w|\n)/) #TODO 150 length limit
1391
- #/^|(?<=[^\p{Word}])\p{Word}|(?<=\n)\n/) #include empty lines?
1392
- /\A|(?<=[^\p{Word}])\p{Word}/) # Start of string or nonword,word.
1393
-
1394
- offset = 0
1395
-
1396
- if wsmarks.any?
1397
- next_pos = start_search + wsmarks.last + offset
1398
- set_pos(next_pos)
1399
- end
1400
- end
1401
- end
1402
-
1403
- def jump_to_mark(mark_char)
1404
- p = @marks[mark_char]
1405
- set_pos(p) if p
1406
- center_on_current_line
1407
- return true
1408
- end
1409
-
1410
- def jump(target)
1411
- if target == START_OF_BUFFER
1412
- set_pos(0)
1413
- end
1414
- if target == END_OF_BUFFER
1415
- set_pos(self.size - 1)
1416
- end
1417
- if target == BEGINNING_OF_LINE
1418
- @cpos = 0
1419
- calculate_pos_from_cpos_lpos
1420
- end
1421
- if target == END_OF_LINE
1422
- @cpos = line(@lpos).size - 1
1423
- calculate_pos_from_cpos_lpos
1424
- end
1425
-
1426
- if target == FIRST_NON_WHITESPACE
1427
- l = current_line()
1428
- debug l.inspect
1429
- @cpos = line(@lpos).size - 1
1430
- a = scan_indexes(l, /\S/)
1431
- debug a.inspect
1432
- if a.any?
1433
- @cpos = a[0]
1434
- else
1435
- @cpos = 0
1436
- end
1437
- calculate_pos_from_cpos_lpos
1438
- end
1439
- end
1440
-
1441
- def jump_to_line(line_n = 1)
1442
-
1443
- # $method_handles_repeat = true
1444
- # if !$next_command_count.nil? and $next_command_count > 0
1445
- # line_n = $next_command_count
1446
- # debug "jump to line:#{line_n}"
1447
- # end
1448
- debug "jump to line:#{line_n}"
1449
- line_n = get_repeat_num() if line_n == 1
1450
-
1451
- if line_n > @line_ends.size
1452
- debug("lpos too large") #TODO
1453
- return
1454
- end
1455
- if line_n == 1
1456
- set_pos(0)
1457
- else
1458
- set_pos(@line_ends[line_n - 2] + 1)
1459
- end
1460
- end
1461
-
1462
1123
  def join_lines()
1463
1124
  if @lpos >= @line_ends.size - 1 # Cursor is on last line
1464
1125
  debug("ON LAST LINE")
@@ -1472,29 +1133,6 @@ class Buffer < String
1472
1133
  end
1473
1134
  end
1474
1135
 
1475
- def jump_to_next_instance_of_char(char, direction = FORWARD)
1476
-
1477
- #return if at_end_of_line?
1478
- if direction == FORWARD
1479
- position_of_next_char = self.index(char, @pos + 1)
1480
- if position_of_next_char != nil
1481
- @pos = position_of_next_char
1482
- end
1483
- elsif direction == BACKWARD
1484
- start_search = @pos - 250
1485
- start_search = 0 if start_search < 0
1486
- search_substr = self[start_search..(@pos - 1)]
1487
- _pos = search_substr.reverse.index(char)
1488
- if _pos != nil
1489
- @pos -= (_pos + 1)
1490
- end
1491
- end
1492
- m = method("jump_to_next_instance_of_char")
1493
- set_last_command({ method: m, params: [char, direction] })
1494
- $last_find_command = { char: char, direction: direction }
1495
- set_pos(@pos)
1496
- end
1497
-
1498
1136
  def replace_with_char(char)
1499
1137
  debug "self_pos:'#{self[@pos]}'"
1500
1138
  return if self[@pos] == "\n"
@@ -1619,98 +1257,17 @@ class Buffer < String
1619
1257
  @need_redraw = false
1620
1258
  end
1621
1259
 
1622
- # Create a new line after current line and insert text on that line
1623
- def put_to_new_next_line(txt)
1624
- l = current_line_range()
1625
- insert_txt_at(txt, l.end + 1)
1626
- set_pos(l.end + 1)
1627
- end
1628
-
1629
- # Start asynchronous read of system clipboard
1630
- def paste_start(at, register)
1631
- @clipboard_paste_running = true
1632
- clipboard = vma.gui.window.display.clipboard
1633
- clipboard.read_text_async do |_clipboard, result|
1634
- begin
1635
- text = clipboard.read_text_finish(result)
1636
- rescue Gio::IOError::NotSupported
1637
- # Happens when pasting from KeePassX and clipboard cleared
1638
- debug Gio::IOError::NotSupported
1639
- else
1640
- paste_finish(text, at, register)
1641
- end
1642
- end
1643
- end
1644
-
1645
- def paste_finish(text, at, register)
1646
- debug "PASTE: #{text}"
1647
-
1648
- # If we did not put this text to clipboard
1649
- if text != $clipboard[-1]
1650
- @paste_lines = false
1651
- end
1652
-
1653
- text = sanitize_input(text)
1654
-
1655
- $clipboard << text
1656
-
1657
- return if text == ""
1658
-
1659
- if @paste_lines
1660
- debug "PASTE LINES"
1661
- put_to_new_next_line(text)
1662
- else
1663
- if at_end_of_buffer? or at_end_of_line? or at == BEFORE
1664
- pos = @pos
1665
- else
1666
- pos = @pos + 1
1667
- end
1668
- insert_txt_at(text, pos)
1669
- set_pos(pos + text.size)
1670
- end
1671
- set_pos(@pos)
1672
- @clipboard_paste_running = false
1673
- end
1674
-
1675
- def paste(at = AFTER, register = nil)
1676
- # Macro's don't work with asynchronous call using GTK
1677
- # TODO: implement as synchronous?
1678
- # Use internal clipboard
1679
- if vma.macro.running_macro
1680
- text = get_clipboard()
1681
- paste_finish(text, at, register)
1682
- else
1683
- # Get clipboard using GUI
1684
- paste_start(at, register)
1685
- end
1686
- return true
1687
- end
1688
-
1689
- def delete_line()
1690
- $method_handles_repeat = true
1691
- num_lines = 1
1692
- if !$next_command_count.nil? and $next_command_count > 0
1693
- num_lines = $next_command_count
1694
- debug "copy num_lines:#{num_lines}"
1695
- end
1696
- lrange = line_range(@lpos, num_lines)
1697
- s = self[lrange]
1698
- add_delta([lrange.begin, DELETE, lrange.end - lrange.begin + 1], true)
1699
- set_clipboard(s)
1700
- update_pos(lrange.begin)
1701
- @paste_lines = true
1702
- #recalc_line_ends
1703
- end
1704
-
1705
- def update_pos(pos)
1706
- @pos = pos
1707
- calculate_line_and_column_pos
1260
+ def start_visual_mode()
1261
+ @visual_mode = true
1262
+ @selection_start = @pos
1263
+ $kbd.set_mode(:visual)
1708
1264
  end
1709
1265
 
1710
- def start_visual_mode()
1266
+ def start_selection()
1711
1267
  @visual_mode = true
1712
1268
  @selection_start = @pos
1713
1269
  $kbd.set_mode(:visual)
1270
+ #TODO: implement without setting kbd mode
1714
1271
  end
1715
1272
 
1716
1273
  def copy_active_selection(x = nil)
@@ -1722,10 +1279,10 @@ class Buffer < String
1722
1279
  s = self[get_visual_mode_range]
1723
1280
  if x == :append
1724
1281
  debug "APPEND"
1725
- s += "\n" + get_clipboard()
1282
+ s += "\n" + vma.clipboard.get()
1726
1283
  end
1727
1284
 
1728
- set_clipboard(s)
1285
+ vma.clipboard.set(s)
1729
1286
  end_visual_mode
1730
1287
  return true
1731
1288
  end
@@ -1788,37 +1345,42 @@ class Buffer < String
1788
1345
  end
1789
1346
 
1790
1347
  def copy_line()
1791
- $method_handles_repeat = true
1348
+ vma.kbd.method_handles_repeat = true
1792
1349
  num_lines = 1
1793
- if !$next_command_count.nil? and $next_command_count > 0
1794
- num_lines = $next_command_count
1350
+ if !vma.kbd.next_command_count.nil? and vma.kbd.next_command_count > 0
1351
+ num_lines = vma.kbd.next_command_count
1795
1352
  debug "copy num_lines:#{num_lines}"
1796
1353
  end
1797
- set_clipboard(self[line_range(@lpos, num_lines)])
1354
+ vma.clipboard.set(self[line_range(@lpos, num_lines)])
1798
1355
  @paste_lines = true
1799
1356
  end
1800
1357
 
1801
1358
  def put_file_path_to_clipboard
1802
- set_clipboard(self.fname)
1359
+ vma.clipboard.set(self.fname)
1803
1360
  end
1804
1361
 
1805
1362
  def put_file_ref_to_clipboard
1806
- set_clipboard(self.fname + ":#{@lpos}")
1363
+ vma.clipboard.set(self.fname + ":#{@lpos}")
1807
1364
  end
1808
1365
 
1809
1366
  def delete_active_selection() #TODO: remove this function
1810
1367
  return if !@visual_mode #TODO: this should not happen
1811
1368
 
1812
1369
  _start, _end = get_visual_mode_range
1813
- set_clipboard(self[_start, _end])
1370
+ vma.clipboard.set(self[_start, _end])
1814
1371
  end_visual_mode
1815
1372
  end
1816
1373
 
1817
1374
  def end_visual_mode()
1818
- return if !visual_mode?
1375
+ debug "end_visual_mode, #{vma.kbd.get_mode}, #{visual_mode?}", 2
1376
+ vma.kbd.dump_state
1377
+ return if vma.kbd.get_mode != :visual
1378
+ if !visual_mode?
1379
+ debug "end_visual_mode, !visual_mode?"
1380
+ # TODO: should not happen
1381
+ end
1819
1382
  debug "End visual mode"
1820
- #TODO:take previous mode (insert|command) from stack?
1821
- $kbd.set_mode(:command)
1383
+ vma.kbd.to_previous_mode
1822
1384
  @visual_mode = false
1823
1385
  return true
1824
1386
  end
@@ -1870,7 +1432,7 @@ class Buffer < String
1870
1432
  savepath = ""
1871
1433
 
1872
1434
  # If current file has fname, save to that fname
1873
- # Else search for previously open files and save to the directory of
1435
+ # Else search for previously opened files and save to the directory of
1874
1436
  # the last viewed file that has a filename
1875
1437
  # selffers[$buffer_history.reverse[1]].fname
1876
1438
 
@@ -1894,7 +1456,7 @@ class Buffer < String
1894
1456
  # Keeping this code from GTK3 in case want to do this manually at some point
1895
1457
  # if !confirmed
1896
1458
  # @unconfirmed_path = fpath
1897
- # if File.exists?(fpath) and File.file?(fpath)
1459
+ # if File.exist?(fpath) and File.file?(fpath)
1898
1460
  # params = {}
1899
1461
  # params["title"] = "The file already exists, overwrite? \r #{fpath}"
1900
1462
  # params["inputs"] = {}
@@ -1903,7 +1465,7 @@ class Buffer < String
1903
1465
  # params[:callback] = callback
1904
1466
  # PopupFormGenerator.new(params).run
1905
1467
  # return
1906
- # elsif File.exists?(fpath) #and File.directory?(fpath)
1468
+ # elsif File.exist?(fpath) #and File.directory?(fpath)
1907
1469
  # params = {}
1908
1470
  # params["title"] = "Can't write to the destination.\r #{fpath}"
1909
1471
  # params["inputs"] = {}
@@ -1947,7 +1509,7 @@ class Buffer < String
1947
1509
  #TODO: show message box
1948
1510
  end
1949
1511
  @last_save = Time.now
1950
- puts "file saved on #{@last_save}"
1512
+ debug "file saved on #{@last_save}"
1951
1513
  sleep 3
1952
1514
  }
1953
1515
  end
@@ -1986,51 +1548,14 @@ class Buffer < String
1986
1548
  end
1987
1549
 
1988
1550
  def save()
1989
- check_if_modified_outside
1551
+ check_if_modified_outside #TODO
1990
1552
  if !@fname
1991
1553
  save_as()
1992
1554
  return
1993
1555
  end
1994
1556
  message("Saving file #{@fname}")
1995
1557
  write_contents_to_file(@fname)
1996
- end
1997
-
1998
- # Indents whole buffer using external program
1999
- def indent()
2000
- file = Tempfile.new("out")
2001
- infile = Tempfile.new("in")
2002
- file.write(self.to_s)
2003
- file.flush
2004
- bufc = "FOO"
2005
-
2006
- tmppos = @pos
2007
-
2008
- message("Auto format #{@fname}")
2009
-
2010
- ftype = get_file_type()
2011
- if ["chdr", "c", "cpp", "cpphdr"].include?(ftype)
2012
-
2013
- #C/C++/Java/JavaScript/Objective-C/Protobuf code
2014
- system("clang-format -style='{BasedOnStyle: LLVM, ColumnLimit: 100, SortIncludes: false}' #{file.path} > #{infile.path}")
2015
- bufc = IO.read(infile.path)
2016
- elsif ftype == "Javascript"
2017
- cmd = "clang-format #{file.path} > #{infile.path}'"
2018
- debug cmd
2019
- system(cmd)
2020
- bufc = IO.read(infile.path)
2021
- elsif ftype == "ruby"
2022
- cmd = "rufo #{file.path}"
2023
- debug cmd
2024
- system(cmd)
2025
- bufc = IO.read(file.path)
2026
- else
2027
- message("No auto-format handler for file of type: #{ftype}")
2028
- return
2029
- end
2030
- self.update_content(bufc)
2031
- center_on_current_line #TODO: needed?
2032
- file.close; file.unlink
2033
- infile.close; infile.unlink
1558
+ hook.call(:file_saved, self)
2034
1559
  end
2035
1560
 
2036
1561
  def close()