textbringer 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +22 -8
- data/CHANGES.md +11 -0
- data/Guardfile +1 -1
- data/exe/tbtags +26 -0
- data/exe/textbringer +1 -0
- data/lib/textbringer.rb +6 -0
- data/lib/textbringer/buffer.rb +158 -83
- data/lib/textbringer/commands.rb +18 -6
- data/lib/textbringer/commands/buffers.rb +187 -43
- data/lib/textbringer/commands/clipboard.rb +23 -6
- data/lib/textbringer/commands/ctags.rb +3 -23
- data/lib/textbringer/commands/files.rb +10 -7
- data/lib/textbringer/commands/help.rb +114 -0
- data/lib/textbringer/commands/isearch.rb +13 -7
- data/lib/textbringer/commands/keyboard_macro.rb +86 -0
- data/lib/textbringer/commands/misc.rb +43 -2
- data/lib/textbringer/commands/register.rb +128 -0
- data/lib/textbringer/commands/replace.rb +4 -3
- data/lib/textbringer/commands/windows.rb +49 -22
- data/lib/textbringer/config.rb +2 -1
- data/lib/textbringer/controller.rb +89 -23
- data/lib/textbringer/keymap.rb +60 -2
- data/lib/textbringer/modes/help_mode.rb +42 -0
- data/lib/textbringer/modes/programming_mode.rb +35 -28
- data/lib/textbringer/modes/ruby_mode.rb +28 -10
- data/lib/textbringer/plugin.rb +21 -0
- data/lib/textbringer/ring.rb +84 -0
- data/lib/textbringer/utils.rb +28 -0
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +59 -5
- data/textbringer.gemspec +1 -1
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68977203d454a58e4191f2b74aba7239793f01ed
|
4
|
+
data.tar.gz: fc172a9d8466197a4cd2383d1fd25a04b5f31056
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 428028614b59f7c75b9740ce2567f7f40887e2df3b13f4a860416c0b742ffcc41c117011a77d5b31f9138bb79f79e8b5142c288f72d803ee676881ceaf1b4eeb
|
7
|
+
data.tar.gz: 5da641c9f7a42d4535a3f3889200fb97c83987f8223fba81a2c7d5e7324649804281c4965dcefce897762ba7dac400a406d93f483601ec9745f201fafe5e5ded
|
data/.travis.yml
CHANGED
@@ -1,13 +1,27 @@
|
|
1
|
-
sudo: false
|
2
|
-
os:
|
3
|
-
- linux
|
4
|
-
- osx
|
5
1
|
language: ruby
|
6
|
-
rvm:
|
7
|
-
- 2.3.3
|
8
|
-
- 2.4.0
|
9
|
-
- ruby-head
|
10
2
|
matrix:
|
3
|
+
include:
|
4
|
+
- os: linux
|
5
|
+
dist: trusty
|
6
|
+
sudo: false
|
7
|
+
rvm: 2.3.3
|
8
|
+
- os: linux
|
9
|
+
dist: trusty
|
10
|
+
sudo: false
|
11
|
+
rvm: 2.4.0
|
12
|
+
- os: linux
|
13
|
+
dist: trusty
|
14
|
+
sudo: false
|
15
|
+
rvm: ruby-head
|
16
|
+
- os: osx
|
17
|
+
osx_image: xcode8.2
|
18
|
+
rvm: 2.3.3
|
19
|
+
- os: osx
|
20
|
+
osx_image: xcode8.2
|
21
|
+
rvm: 2.4.0
|
22
|
+
- os: osx
|
23
|
+
osx_image: xcode8.2
|
24
|
+
rvm: ruby-head
|
11
25
|
allow_failures:
|
12
26
|
- os: osx
|
13
27
|
- rvm: ruby-head
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 0.1.9
|
2
|
+
|
3
|
+
* Support registers.
|
4
|
+
* Support plugins.
|
5
|
+
* Support global mark ring.
|
6
|
+
* Support keyboard macro.
|
7
|
+
* Support help (describe_bindings, describe_command, and describe_key).
|
8
|
+
* Add tbtags.
|
9
|
+
* Add the commands back_to_indentation, indent_region, delete_indentation,
|
10
|
+
shrink_window, and shrink_window_if_larger_than_buffer.
|
11
|
+
|
1
12
|
## 0.1.8
|
2
13
|
|
3
14
|
* Support syntax highlighting.
|
data/Guardfile
CHANGED
data/exe/tbtags
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "ripper-tags"
|
4
|
+
|
5
|
+
module Textbringer
|
6
|
+
module TagParser
|
7
|
+
def on_method_add_arg(call, args)
|
8
|
+
call_name = call&.slice(0)
|
9
|
+
first_arg = args&.slice(0) == :args && args[1]
|
10
|
+
if call_name == :fcall && first_arg && call[1][0] == "define_command"
|
11
|
+
[:def, args[1][0], call[1][1]]
|
12
|
+
else
|
13
|
+
super(call, args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RipperTags::Parser.prepend(Textbringer::TagParser)
|
20
|
+
|
21
|
+
begin
|
22
|
+
RipperTags.process_args(ARGV)
|
23
|
+
rescue => e
|
24
|
+
STDERR.printf("%s: %s\n", File.basename($0), e)
|
25
|
+
exit(1)
|
26
|
+
end
|
data/exe/textbringer
CHANGED
data/lib/textbringer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative "textbringer/version"
|
2
2
|
require_relative "textbringer/config"
|
3
3
|
require_relative "textbringer/errors"
|
4
|
+
require_relative "textbringer/ring"
|
4
5
|
require_relative "textbringer/buffer"
|
5
6
|
require_relative "textbringer/window"
|
6
7
|
require_relative "textbringer/keymap"
|
@@ -17,6 +18,9 @@ require_relative "textbringer/commands/replace"
|
|
17
18
|
require_relative "textbringer/commands/dabbrev"
|
18
19
|
require_relative "textbringer/commands/ctags"
|
19
20
|
require_relative "textbringer/commands/clipboard"
|
21
|
+
require_relative "textbringer/commands/register"
|
22
|
+
require_relative "textbringer/commands/keyboard_macro"
|
23
|
+
require_relative "textbringer/commands/help"
|
20
24
|
require_relative "textbringer/mode"
|
21
25
|
require_relative "textbringer/modes/fundamental_mode"
|
22
26
|
require_relative "textbringer/modes/programming_mode"
|
@@ -24,4 +28,6 @@ require_relative "textbringer/modes/ruby_mode"
|
|
24
28
|
require_relative "textbringer/modes/c_mode"
|
25
29
|
require_relative "textbringer/modes/backtrace_mode"
|
26
30
|
require_relative "textbringer/modes/completion_list_mode"
|
31
|
+
require_relative "textbringer/modes/help_mode"
|
32
|
+
require_relative "textbringer/plugin"
|
27
33
|
require_relative "textbringer/controller"
|
data/lib/textbringer/buffer.rb
CHANGED
@@ -52,6 +52,7 @@ module Textbringer
|
|
52
52
|
@@list = []
|
53
53
|
@@current = nil
|
54
54
|
@@minibuffer = nil
|
55
|
+
@@global_mark_ring = nil
|
55
56
|
|
56
57
|
def self.auto_detect_encodings
|
57
58
|
@@auto_detect_encodings
|
@@ -90,6 +91,10 @@ module Textbringer
|
|
90
91
|
@@minibuffer ||= Buffer.new(name: "*Minibuffer*")
|
91
92
|
end
|
92
93
|
|
94
|
+
def self.global_mark_ring
|
95
|
+
@@global_mark_ring ||= Ring.new(CONFIG[:global_mark_ring_max])
|
96
|
+
end
|
97
|
+
|
93
98
|
def self.last
|
94
99
|
if @@list.last == @@current
|
95
100
|
@@list[-2]
|
@@ -210,13 +215,16 @@ module Textbringer
|
|
210
215
|
@gap_end = 0
|
211
216
|
@marks = []
|
212
217
|
@mark = nil
|
218
|
+
@mark_ring = Ring.new(CONFIG[:mark_ring_max],
|
219
|
+
on_delete: ->(mark) { mark.delete })
|
213
220
|
@current_line = 1
|
214
221
|
@current_column = 1 # One-based character count
|
215
222
|
@goal_column = nil # Zero-based display width count
|
216
|
-
@yank_start = new_mark
|
217
223
|
@undo_stack = []
|
218
224
|
@redo_stack = []
|
219
225
|
@undoing = false
|
226
|
+
@composite_edit_level = 0
|
227
|
+
@composite_edit_actions = []
|
220
228
|
@version = 0
|
221
229
|
@modified = false
|
222
230
|
@mode = FundamentalMode.new(self)
|
@@ -283,12 +291,24 @@ module Textbringer
|
|
283
291
|
end
|
284
292
|
end
|
285
293
|
|
294
|
+
def read_only_edit
|
295
|
+
self.read_only = false
|
296
|
+
begin
|
297
|
+
yield
|
298
|
+
ensure
|
299
|
+
self.read_only = true
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
286
303
|
def kill
|
287
304
|
@@table.delete(@name)
|
288
305
|
@@list.delete(self)
|
289
306
|
if @@current == self
|
290
307
|
@@current = nil
|
291
308
|
end
|
309
|
+
@marks.each do |mark|
|
310
|
+
mark.detach
|
311
|
+
end
|
292
312
|
end
|
293
313
|
|
294
314
|
def current?
|
@@ -767,8 +787,63 @@ module Textbringer
|
|
767
787
|
end
|
768
788
|
|
769
789
|
def set_mark(pos = @point)
|
770
|
-
@mark
|
790
|
+
if @mark
|
791
|
+
@mark.location = pos
|
792
|
+
else
|
793
|
+
push_mark(pos)
|
794
|
+
end
|
795
|
+
end
|
796
|
+
|
797
|
+
# Set mark at pos, and push the mark on the mark ring.
|
798
|
+
# Unlike Emacs, the new mark is pushed on the mark ring instead of
|
799
|
+
# the old one.
|
800
|
+
def push_mark(pos = @point)
|
801
|
+
@mark = new_mark
|
771
802
|
@mark.location = pos
|
803
|
+
@mark_ring.push(@mark)
|
804
|
+
if self != Buffer.minibuffer
|
805
|
+
global_mark_ring = Buffer.global_mark_ring
|
806
|
+
if global_mark_ring.empty? || global_mark_ring.current.buffer != self
|
807
|
+
push_global_mark(pos)
|
808
|
+
end
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
def on_global_mark_ring?
|
813
|
+
mark_ring = Buffer.global_mark_ring
|
814
|
+
if mark_ring.empty?
|
815
|
+
return false
|
816
|
+
end
|
817
|
+
current = mark_ring.current
|
818
|
+
if current&.buffer == self
|
819
|
+
return true
|
820
|
+
end
|
821
|
+
next_mark = mark_ring[-1]
|
822
|
+
if next_mark&.buffer == self
|
823
|
+
return true
|
824
|
+
end
|
825
|
+
false
|
826
|
+
end
|
827
|
+
|
828
|
+
def push_global_mark(pos = @point, force: false)
|
829
|
+
if force || !on_global_mark_ring?
|
830
|
+
mark = new_mark
|
831
|
+
mark.location = pos
|
832
|
+
Buffer.global_mark_ring.push(mark)
|
833
|
+
true
|
834
|
+
else
|
835
|
+
false
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
839
|
+
def pop_mark
|
840
|
+
return if @mark_ring.empty?
|
841
|
+
@mark = @mark_ring.rotate(1)
|
842
|
+
end
|
843
|
+
|
844
|
+
def pop_to_mark
|
845
|
+
goto_char(mark)
|
846
|
+
pop_mark
|
772
847
|
end
|
773
848
|
|
774
849
|
def set_visible_mark(pos = @point)
|
@@ -783,8 +858,17 @@ module Textbringer
|
|
783
858
|
end
|
784
859
|
end
|
785
860
|
|
861
|
+
def self.region_boundaries(s, e)
|
862
|
+
if s > e
|
863
|
+
[e, s]
|
864
|
+
else
|
865
|
+
[s, e]
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
786
869
|
def copy_region(s = @point, e = mark, append = false)
|
787
|
-
|
870
|
+
s, e = Buffer.region_boundaries(s, e)
|
871
|
+
str = substring(s, e)
|
788
872
|
if append && !KILL_RING.empty?
|
789
873
|
KILL_RING.current.concat(str)
|
790
874
|
else
|
@@ -800,9 +884,7 @@ module Textbringer
|
|
800
884
|
def delete_region(s = @point, e = mark)
|
801
885
|
check_read_only_flag
|
802
886
|
old_pos = @point
|
803
|
-
|
804
|
-
s, e = e, s
|
805
|
-
end
|
887
|
+
s, e = Buffer.region_boundaries(s, e)
|
806
888
|
update_line_and_column(old_pos, s)
|
807
889
|
save_point do
|
808
890
|
str = substring(s, e)
|
@@ -868,7 +950,9 @@ module Textbringer
|
|
868
950
|
end
|
869
951
|
|
870
952
|
def insert_for_yank(s)
|
871
|
-
|
953
|
+
if @mark.nil? || !point_at_mark?(@mark)
|
954
|
+
push_mark
|
955
|
+
end
|
872
956
|
insert(s)
|
873
957
|
end
|
874
958
|
|
@@ -877,8 +961,8 @@ module Textbringer
|
|
877
961
|
end
|
878
962
|
|
879
963
|
def yank_pop
|
880
|
-
delete_region
|
881
|
-
insert_for_yank(KILL_RING.
|
964
|
+
delete_region
|
965
|
+
insert_for_yank(KILL_RING.rotate(1))
|
882
966
|
end
|
883
967
|
|
884
968
|
def undo
|
@@ -963,7 +1047,7 @@ module Textbringer
|
|
963
1047
|
|
964
1048
|
def looking_at?(re)
|
965
1049
|
if re.is_a?(Regexp)
|
966
|
-
r =
|
1050
|
+
r = /\G#{re}/
|
967
1051
|
else
|
968
1052
|
r = "\\G(?:#{re})"
|
969
1053
|
end
|
@@ -1049,19 +1133,21 @@ module Textbringer
|
|
1049
1133
|
b = match_beginning(0)
|
1050
1134
|
e = match_end(0)
|
1051
1135
|
goto_char(b)
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1136
|
+
composite_edit do
|
1137
|
+
delete_region(b, e)
|
1138
|
+
insert(new_str)
|
1139
|
+
end
|
1055
1140
|
end
|
1056
1141
|
|
1057
1142
|
def replace_regexp_forward(regexp, to_str)
|
1058
1143
|
result = 0
|
1059
1144
|
rest = substring(point, point_max)
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1145
|
+
composite_edit do
|
1146
|
+
delete_region(point, point_max)
|
1147
|
+
new_str = rest.gsub(new_regexp(regexp)) {
|
1148
|
+
result += 1
|
1149
|
+
m = Regexp.last_match
|
1150
|
+
to_str.gsub(/\\(?:([0-9]+)|(&)|(\\))/) { |s|
|
1065
1151
|
case
|
1066
1152
|
when $1
|
1067
1153
|
m[$1.to_i]
|
@@ -1070,10 +1156,10 @@ module Textbringer
|
|
1070
1156
|
when $3
|
1071
1157
|
"\\"
|
1072
1158
|
end
|
1159
|
+
}
|
1073
1160
|
}
|
1074
|
-
|
1075
|
-
|
1076
|
-
merge_undo(2)
|
1161
|
+
insert(new_str)
|
1162
|
+
end
|
1077
1163
|
result
|
1078
1164
|
end
|
1079
1165
|
|
@@ -1095,16 +1181,22 @@ module Textbringer
|
|
1095
1181
|
/\A\0*\z/ =~ @contents[@gap_start...@gap_end] ? true : false
|
1096
1182
|
end
|
1097
1183
|
|
1098
|
-
def
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1184
|
+
def composite_edit
|
1185
|
+
@composite_edit_level += 1
|
1186
|
+
begin
|
1187
|
+
yield
|
1188
|
+
ensure
|
1189
|
+
@composite_edit_level -= 1
|
1190
|
+
if @composite_edit_level == 0 && !@composite_edit_actions.empty?
|
1191
|
+
action = CompositeAction.new(self,
|
1192
|
+
@composite_edit_actions.first.location)
|
1193
|
+
@composite_edit_actions.each do |i|
|
1194
|
+
action.add_action(i)
|
1195
|
+
end
|
1196
|
+
action.version = @composite_edit_actions.first.version
|
1197
|
+
push_undo(action)
|
1198
|
+
@composite_edit_actions.clear
|
1105
1199
|
end
|
1106
|
-
action.version = actions.first.version
|
1107
|
-
@undo_stack.push(action)
|
1108
1200
|
end
|
1109
1201
|
end
|
1110
1202
|
|
@@ -1189,9 +1281,10 @@ module Textbringer
|
|
1189
1281
|
|
1190
1282
|
def gsub(*args, &block)
|
1191
1283
|
s = to_s.gsub(*args, &block)
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1284
|
+
composite_edit do
|
1285
|
+
delete_region(point_min, point_max)
|
1286
|
+
insert(s)
|
1287
|
+
end
|
1195
1288
|
self
|
1196
1289
|
end
|
1197
1290
|
|
@@ -1343,14 +1436,18 @@ module Textbringer
|
|
1343
1436
|
|
1344
1437
|
def push_undo(action)
|
1345
1438
|
return if @undoing || @undo_limit == 0
|
1346
|
-
if @
|
1347
|
-
@
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1439
|
+
if @composite_edit_level > 0
|
1440
|
+
@composite_edit_actions.push(action)
|
1441
|
+
else
|
1442
|
+
if @undo_stack.size >= @undo_limit
|
1443
|
+
@undo_stack[0, @undo_stack.size + 1 - @undo_limit] = []
|
1444
|
+
end
|
1445
|
+
if !modified?
|
1446
|
+
action.version = @version
|
1447
|
+
end
|
1448
|
+
@undo_stack.push(action)
|
1449
|
+
@redo_stack.clear
|
1351
1450
|
end
|
1352
|
-
@undo_stack.push(action)
|
1353
|
-
@redo_stack.clear
|
1354
1451
|
end
|
1355
1452
|
|
1356
1453
|
def new_regexp(s)
|
@@ -1369,70 +1466,48 @@ module Textbringer
|
|
1369
1466
|
end
|
1370
1467
|
|
1371
1468
|
class Mark
|
1372
|
-
attr_reader :buffer
|
1469
|
+
attr_reader :buffer, :file_name
|
1373
1470
|
attr_accessor :location
|
1374
1471
|
|
1375
1472
|
def initialize(buffer, location)
|
1376
1473
|
@buffer = buffer
|
1474
|
+
@file_name = nil
|
1377
1475
|
@location = location
|
1378
1476
|
end
|
1379
1477
|
|
1380
|
-
def
|
1381
|
-
@buffer
|
1382
|
-
end
|
1383
|
-
|
1384
|
-
def dup
|
1385
|
-
mark = @buffer.new_mark
|
1386
|
-
mark.location = @location
|
1387
|
-
mark
|
1388
|
-
end
|
1389
|
-
end
|
1390
|
-
|
1391
|
-
class KillRing
|
1392
|
-
def initialize(max = 30)
|
1393
|
-
@max = max
|
1394
|
-
@ring = []
|
1395
|
-
@current = -1
|
1478
|
+
def inspect
|
1479
|
+
"#<Mark:#{@buffer&.name || @file_name}:#{@location}>"
|
1396
1480
|
end
|
1397
1481
|
|
1398
|
-
def
|
1399
|
-
@
|
1400
|
-
|
1482
|
+
def delete
|
1483
|
+
if @buffer
|
1484
|
+
@buffer.marks.delete(self)
|
1485
|
+
end
|
1401
1486
|
end
|
1402
1487
|
|
1403
|
-
def
|
1404
|
-
|
1405
|
-
if @ring.size < @max
|
1406
|
-
@ring.insert(@current, str)
|
1407
|
-
else
|
1408
|
-
if @current == @max
|
1409
|
-
@current = 0
|
1410
|
-
end
|
1411
|
-
@ring[@current] = str
|
1412
|
-
end
|
1488
|
+
def deleted?
|
1489
|
+
!@buffer.marks.include?(self)
|
1413
1490
|
end
|
1414
1491
|
|
1415
|
-
def
|
1416
|
-
if @
|
1417
|
-
|
1418
|
-
|
1419
|
-
@current -= n
|
1420
|
-
if @current < 0
|
1421
|
-
@current += @ring.size
|
1492
|
+
def detach
|
1493
|
+
if @buffer
|
1494
|
+
@file_name = @buffer.file_name
|
1495
|
+
@buffer = nil
|
1422
1496
|
end
|
1423
|
-
@ring[@current]
|
1424
1497
|
end
|
1425
1498
|
|
1426
|
-
def
|
1427
|
-
@
|
1499
|
+
def detached?
|
1500
|
+
@buffer.nil?
|
1428
1501
|
end
|
1429
1502
|
|
1430
|
-
def
|
1431
|
-
@
|
1503
|
+
def dup
|
1504
|
+
mark = @buffer.new_mark
|
1505
|
+
mark.location = @location
|
1506
|
+
mark
|
1432
1507
|
end
|
1433
1508
|
end
|
1434
1509
|
|
1435
|
-
KILL_RING =
|
1510
|
+
KILL_RING = Ring.new
|
1436
1511
|
|
1437
1512
|
class UndoableAction
|
1438
1513
|
attr_accessor :version
|