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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6dafe6a94443fe1e79c7a9316973fc43ec01525
4
- data.tar.gz: 8332b5d2ef6dd7cbb4df030b9e2ce79a4551be83
3
+ metadata.gz: 68977203d454a58e4191f2b74aba7239793f01ed
4
+ data.tar.gz: fc172a9d8466197a4cd2383d1fd25a04b5f31056
5
5
  SHA512:
6
- metadata.gz: 5d7687449b608e273a1a0a11155e80e07543095e0bf73deab13740767166274590803d28e203a5816a6526d44a25bf49ac36855deecc1833a007b4a84525b933
7
- data.tar.gz: 4cf790621ce7c55960cc7e0087fb6dac140280d60adf20e2e0b9b88f69eef252226cf9bdbf975614bdf56658cbc90de074f568c4a9775fb0c983206fa5951293
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
@@ -17,6 +17,6 @@
17
17
 
18
18
  guard :shell do
19
19
  watch(%r'^(lib|test)/.+\.rb$') do
20
- `ripper-tags -R`
20
+ `bundle exec tbtags -R`
21
21
  end
22
22
  end
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
@@ -18,6 +18,7 @@ $VERBOSE = nil
18
18
  Controller.current = Controller.new
19
19
  Window.start do
20
20
  begin
21
+ Plugin.load_plugins
21
22
  load_user_config
22
23
  ruby_mode
23
24
  if ARGV.size > 0
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"
@@ -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 ||= new_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
- str = s <= e ? substring(s, e) : substring(e, s)
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
- if s > e
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
- mark_to_point(@yank_start)
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(@yank_start.location, @point)
881
- insert_for_yank(KILL_RING.current(1))
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 = Regexp.new("\\G(?:#{re.source})", re.options)
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
- delete_region(b, e)
1053
- insert(new_str)
1054
- merge_undo(2)
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
- delete_region(point, point_max)
1061
- new_str = rest.gsub(new_regexp(regexp)) {
1062
- result += 1
1063
- m = Regexp.last_match
1064
- to_str.gsub(/\\(?:([0-9]+)|(&)|(\\))/) { |s|
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
- insert(new_str)
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 merge_undo(n)
1099
- return if @undoing || @undo_limit == 0
1100
- actions = @undo_stack.pop(n)
1101
- if actions
1102
- action = CompositeAction.new(self, actions.first.location)
1103
- actions.each do |i|
1104
- action.add_action(i)
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
- delete_region(point_min, point_max)
1193
- insert(s)
1194
- merge_undo(2)
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 @undo_stack.size >= @undo_limit
1347
- @undo_stack[0, @undo_stack.size + 1 - @undo_limit] = []
1348
- end
1349
- if !modified?
1350
- action.version = @version
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 delete
1381
- @buffer.marks.delete(self)
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 clear
1399
- @ring.clear
1400
- @current = -1
1482
+ def delete
1483
+ if @buffer
1484
+ @buffer.marks.delete(self)
1485
+ end
1401
1486
  end
1402
1487
 
1403
- def push(str)
1404
- @current += 1
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 current(n = 0)
1416
- if @ring.empty?
1417
- raise EditorError, "Kill ring is empty"
1418
- end
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 empty?
1427
- @ring.empty?
1499
+ def detached?
1500
+ @buffer.nil?
1428
1501
  end
1429
1502
 
1430
- def size
1431
- @ring.size
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 = KillRing.new
1510
+ KILL_RING = Ring.new
1436
1511
 
1437
1512
  class UndoableAction
1438
1513
  attr_accessor :version