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.
- checksums.yaml +4 -4
- data/custom_example.rb +12 -0
- data/lib/vimamsa/ack.rb +3 -4
- data/lib/vimamsa/actions.rb +1 -2
- data/lib/vimamsa/audio.rb +25 -1
- data/lib/vimamsa/buffer.rb +116 -591
- data/lib/vimamsa/buffer_changetext.rb +272 -0
- data/lib/vimamsa/buffer_cursor.rb +303 -0
- data/lib/vimamsa/buffer_list.rb +137 -133
- data/lib/vimamsa/buffer_manager.rb +15 -15
- data/lib/vimamsa/clipboard.rb +36 -0
- data/lib/vimamsa/conf.rb +136 -5
- data/lib/vimamsa/constants.rb +0 -10
- data/lib/vimamsa/debug.rb +9 -8
- data/lib/vimamsa/editor.rb +57 -84
- data/lib/vimamsa/encrypt.rb +6 -11
- data/lib/vimamsa/file_history.rb +0 -8
- data/lib/vimamsa/file_manager.rb +142 -10
- data/lib/vimamsa/gui.rb +106 -85
- data/lib/vimamsa/gui_dialog.rb +113 -0
- data/lib/vimamsa/gui_menu.rb +5 -1
- data/lib/vimamsa/gui_sourceview.rb +46 -29
- data/lib/vimamsa/gui_sourceview_autocomplete.rb +141 -0
- data/lib/vimamsa/gui_text.rb +49 -0
- data/lib/vimamsa/hyper_plain_text.rb +19 -5
- data/lib/vimamsa/key_actions.rb +41 -202
- data/lib/vimamsa/key_binding_tree.rb +129 -41
- data/lib/vimamsa/key_bindings_vimlike.rb +58 -48
- data/lib/vimamsa/langservp.rb +23 -3
- data/lib/vimamsa/macro.rb +35 -25
- data/lib/vimamsa/main.rb +7 -10
- data/lib/vimamsa/rbvma.rb +13 -11
- data/lib/vimamsa/search.rb +1 -1
- data/lib/vimamsa/search_replace.rb +106 -160
- data/lib/vimamsa/terminal.rb +34 -0
- data/lib/vimamsa/tests.rb +122 -0
- data/lib/vimamsa/util.rb +43 -4
- data/lib/vimamsa/version.rb +1 -1
- data/vimamsa.gemspec +5 -2
- metadata +59 -9
- /data/lib/vimamsa/{form_generator.rb → gui_form_generator.rb} +0 -0
data/lib/vimamsa/buffer.rb
CHANGED
@@ -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
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
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.
|
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
|
127
|
-
@lsp = LangSrv.get(@lang
|
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
|
-
|
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
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
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.
|
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|
|
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
|
-
|
365
|
-
if $experimental
|
383
|
+
if cnf.btree.experimental?
|
366
384
|
@bt = BufferTree.new(self)
|
367
|
-
if
|
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
|
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
|
-
|
690
|
+
vma.kbd.method_handles_repeat = true
|
761
691
|
repeat_num = 1
|
762
|
-
if
|
763
|
-
repeat_num =
|
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
|
-
|
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
|
1280
|
-
|
1281
|
-
|
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 =
|
1284
|
-
word_end =
|
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
|
-
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
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
|
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" +
|
1282
|
+
s += "\n" + vma.clipboard.get()
|
1726
1283
|
end
|
1727
1284
|
|
1728
|
-
|
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
|
-
|
1348
|
+
vma.kbd.method_handles_repeat = true
|
1792
1349
|
num_lines = 1
|
1793
|
-
if
|
1794
|
-
num_lines =
|
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
|
-
|
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
|
-
|
1359
|
+
vma.clipboard.set(self.fname)
|
1803
1360
|
end
|
1804
1361
|
|
1805
1362
|
def put_file_ref_to_clipboard
|
1806
|
-
|
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
|
-
|
1370
|
+
vma.clipboard.set(self[_start, _end])
|
1814
1371
|
end_visual_mode
|
1815
1372
|
end
|
1816
1373
|
|
1817
1374
|
def end_visual_mode()
|
1818
|
-
|
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
|
-
|
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
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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()
|