vimamsa 0.1.13 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
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()