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