textbringer 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/CHANGES.md +10 -0
- data/exe/textbringer +34 -30
- data/lib/textbringer/commands.rb +1 -0
- data/lib/textbringer/commands/buffers.rb +1 -1
- data/lib/textbringer/commands/windows.rb +8 -2
- data/lib/textbringer/controller.rb +52 -10
- data/lib/textbringer/keymap.rb +1 -0
- data/lib/textbringer/modes/c_mode.rb +3 -5
- data/lib/textbringer/plugin.rb +9 -4
- data/lib/textbringer/utils.rb +25 -1
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +7 -6
- data/textbringer.gemspec +1 -3
- metadata +5 -34
- data/Guardfile +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df46cdf2ec8419a33fbfd4e23f41272bd4204ba2
|
4
|
+
data.tar.gz: 47179c38f72119aa5c4b96f01c80d28f10660531
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b39cb72604f03c738a02b37fcc7c8d74bef47590ddde2293e6207f7be1147572395b760a02bcc74537872de3152967f447bcfb03b1fb83f447c274eff0322371
|
7
|
+
data.tar.gz: 864a8f20870885c9fb7c2252779cbe269f08ed34b1650b06233172fb69eac9fcdf76da5b6292150db4940ba7ce14b3f308b89c78084be811fd0f255553e8c720
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.2.2
|
2
|
+
|
3
|
+
* Rename read_char to read_event and add read_char as a new method.
|
4
|
+
* Add next_tick and background for background threads.
|
5
|
+
* Add the force: option to kill_buffer.
|
6
|
+
* bind C-? ([delete] on Mac) to backward_delete_char.
|
7
|
+
Pull request #23 by moguno.
|
8
|
+
* Make commands module_functions.
|
9
|
+
* Use fiddley instead of ffi.
|
10
|
+
|
1
11
|
## 0.2.1
|
2
12
|
|
3
13
|
* Add revert_buffer and revert_buffer_with_encoding.
|
data/exe/textbringer
CHANGED
@@ -16,40 +16,44 @@ end
|
|
16
16
|
$VERBOSE = nil
|
17
17
|
|
18
18
|
Controller.current = Controller.new
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
ARGV.
|
26
|
-
|
19
|
+
begin
|
20
|
+
Window.start do
|
21
|
+
begin
|
22
|
+
Plugin.load_plugins
|
23
|
+
load_user_config
|
24
|
+
ruby_mode
|
25
|
+
if ARGV.size > 0
|
26
|
+
ARGV.each do |arg|
|
27
|
+
find_file(arg)
|
28
|
+
end
|
27
29
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
if Buffer.dumped_buffers_exist?(CONFIG[:buffer_dump_dir])
|
31
|
+
Window.redisplay
|
32
|
+
if yes_or_no?("Dumped buffers found; restore them?")
|
33
|
+
buffers = Buffer.load_dumped_buffers(CONFIG[:buffer_dump_dir])
|
34
|
+
switch_to_buffer(buffers.last)
|
35
|
+
end
|
34
36
|
end
|
37
|
+
rescue Exception => e
|
38
|
+
show_exception(e)
|
35
39
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
begin
|
41
|
-
trap(:CONT) { Window.redraw }
|
42
|
-
rescue ArgumentError
|
43
|
-
end
|
44
|
-
begin
|
45
|
-
loop do
|
46
|
-
Controller.current.command_loop(TOP_LEVEL_TAG)
|
47
|
-
Window.redisplay
|
40
|
+
Window.redisplay
|
41
|
+
begin
|
42
|
+
trap(:CONT) { Window.redraw }
|
43
|
+
rescue ArgumentError
|
48
44
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
begin
|
46
|
+
loop do
|
47
|
+
Controller.current.command_loop(TOP_LEVEL_TAG)
|
48
|
+
Window.redisplay
|
49
|
+
end
|
50
|
+
rescue Exception => e
|
51
|
+
if !e.is_a?(SystemExit)
|
52
|
+
Buffer.dump_unsaved_buffers(CONFIG[:buffer_dump_dir])
|
53
|
+
end
|
54
|
+
raise
|
52
55
|
end
|
53
|
-
raise
|
54
56
|
end
|
57
|
+
ensure
|
58
|
+
Controller.current.close
|
55
59
|
end
|
data/lib/textbringer/commands.rb
CHANGED
@@ -26,6 +26,7 @@ module Textbringer
|
|
26
26
|
def define_command(name, doc: "No documentation", &block)
|
27
27
|
name = name.intern
|
28
28
|
Commands.send(:define_method, name, &block)
|
29
|
+
Commands.send(:module_function, name)
|
29
30
|
Commands.command_table[name] = Command.new(name, block, doc)
|
30
31
|
name
|
31
32
|
end
|
@@ -171,7 +171,7 @@ module Textbringer
|
|
171
171
|
define_command(:quoted_insert,
|
172
172
|
doc: "Read a character, and insert it.") do
|
173
173
|
|n = number_prefix_arg|
|
174
|
-
c = Controller.current.
|
174
|
+
c = Controller.current.read_event
|
175
175
|
if !c.is_a?(String)
|
176
176
|
raise EditorError, "Invalid key"
|
177
177
|
end
|
@@ -100,11 +100,12 @@ module Textbringer
|
|
100
100
|
end
|
101
101
|
|
102
102
|
define_command(:kill_buffer, doc: "Kill buffer.") do
|
103
|
-
|buffer = read_buffer("Kill buffer: ", default: Buffer.current.name)
|
103
|
+
|buffer = read_buffer("Kill buffer: ", default: Buffer.current.name),
|
104
|
+
force: false|
|
104
105
|
if buffer.is_a?(String)
|
105
106
|
buffer = Buffer[buffer]
|
106
107
|
end
|
107
|
-
if buffer.modified?
|
108
|
+
if !force && buffer.modified?
|
108
109
|
next unless yes_or_no?("The last change is not saved; kill anyway?")
|
109
110
|
message("Arioch! Arioch! Blood and souls for my Lord Arioch!")
|
110
111
|
end
|
@@ -112,6 +113,11 @@ module Textbringer
|
|
112
113
|
if Buffer.current.nil?
|
113
114
|
switch_to_buffer(Buffer.other)
|
114
115
|
end
|
116
|
+
Window.list(include_echo_area: true).each do |window|
|
117
|
+
if window.buffer == buffer
|
118
|
+
window.buffer = Buffer.current
|
119
|
+
end
|
120
|
+
end
|
115
121
|
end
|
116
122
|
end
|
117
123
|
end
|
@@ -36,6 +36,14 @@ module Textbringer
|
|
36
36
|
@recording_keyboard_macro = nil
|
37
37
|
@last_keyboard_macro = nil
|
38
38
|
@executing_keyboard_macro = nil
|
39
|
+
@next_tick_queue = []
|
40
|
+
@next_tick_queue_mutex = Mutex.new
|
41
|
+
@next_tick_input, @next_tick_output = IO.pipe
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
@next_tick_input.close
|
46
|
+
@next_tick_output.close
|
39
47
|
end
|
40
48
|
|
41
49
|
def command_loop(tag)
|
@@ -43,7 +51,7 @@ module Textbringer
|
|
43
51
|
loop do
|
44
52
|
begin
|
45
53
|
echo_input
|
46
|
-
c =
|
54
|
+
c = read_event
|
47
55
|
break if c.nil?
|
48
56
|
Window.echo_area.clear_message
|
49
57
|
@last_key = c
|
@@ -92,22 +100,56 @@ module Textbringer
|
|
92
100
|
end
|
93
101
|
|
94
102
|
def wait_input(msecs)
|
103
|
+
# TODO: Check @next_tick_queue
|
95
104
|
if executing_keyboard_macro?
|
96
105
|
return @executing_keyboard_macro.first
|
97
106
|
end
|
98
107
|
Window.current.wait_input(msecs)
|
99
108
|
end
|
100
109
|
|
101
|
-
def
|
102
|
-
|
110
|
+
def next_tick(&block)
|
111
|
+
@next_tick_queue_mutex.synchronize do
|
112
|
+
@next_tick_queue.push(block)
|
113
|
+
end
|
114
|
+
@next_tick_output.write("\n")
|
115
|
+
end
|
116
|
+
|
117
|
+
def read_event
|
118
|
+
event = read_event_nonblock
|
119
|
+
if event
|
120
|
+
return event
|
121
|
+
end
|
122
|
+
loop do
|
123
|
+
if Window.echo_area.active?
|
124
|
+
wait_files = [STDIN]
|
125
|
+
else
|
126
|
+
wait_files = [STDIN, @next_tick_input]
|
127
|
+
end
|
128
|
+
files, = IO.select(wait_files, [], [], 1)
|
129
|
+
# KEY_RESIZE may be returned even if STDIN is not included in files.
|
130
|
+
event = read_event_nonblock
|
131
|
+
if event
|
132
|
+
return event
|
133
|
+
end
|
134
|
+
if !Window.echo_area.active? && files&.include?(@next_tick_input)
|
135
|
+
c = @next_tick_input.read_nonblock(1, exception: false)
|
136
|
+
if !c.nil? && c != :wait_readable
|
137
|
+
block = @next_tick_queue_mutex.synchronize {
|
138
|
+
@next_tick_queue.shift
|
139
|
+
}
|
140
|
+
block.call
|
141
|
+
Window.redisplay
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
103
145
|
end
|
104
146
|
|
105
|
-
def
|
106
|
-
|
147
|
+
def read_event_nonblock
|
148
|
+
read_event_with_keyboard_macro(:read_event_nonblock)
|
107
149
|
end
|
108
150
|
|
109
151
|
def received_keyboard_quit?
|
110
|
-
while key =
|
152
|
+
while key = read_event_nonblock
|
111
153
|
if GLOBAL_MAP.lookup([key]) == :keyboard_quit
|
112
154
|
return true
|
113
155
|
end
|
@@ -208,9 +250,9 @@ module Textbringer
|
|
208
250
|
|
209
251
|
private
|
210
252
|
|
211
|
-
def
|
253
|
+
def read_event_with_keyboard_macro(read_event_method)
|
212
254
|
if !executing_keyboard_macro?
|
213
|
-
c =
|
255
|
+
c = call_read_event_method(read_event_method)
|
214
256
|
if @recording_keyboard_macro
|
215
257
|
@recording_keyboard_macro.push(c)
|
216
258
|
end
|
@@ -220,8 +262,8 @@ module Textbringer
|
|
220
262
|
end
|
221
263
|
end
|
222
264
|
|
223
|
-
def
|
224
|
-
Window.current.send(
|
265
|
+
def call_read_event_method(read_event_method)
|
266
|
+
Window.current.send(read_event_method)
|
225
267
|
end
|
226
268
|
end
|
227
269
|
end
|
data/lib/textbringer/keymap.rb
CHANGED
@@ -109,6 +109,7 @@ module Textbringer
|
|
109
109
|
GLOBAL_MAP.define_key(?\C-d, :delete_char)
|
110
110
|
GLOBAL_MAP.define_key(:backspace, :backward_delete_char)
|
111
111
|
GLOBAL_MAP.define_key(?\C-h, :backward_delete_char)
|
112
|
+
GLOBAL_MAP.define_key(?\C-?, :backward_delete_char)
|
112
113
|
GLOBAL_MAP.define_key(?\C-a, :beginning_of_line)
|
113
114
|
GLOBAL_MAP.define_key(:home, :beginning_of_line)
|
114
115
|
GLOBAL_MAP.define_key(?\C-e, :end_of_line)
|
@@ -78,8 +78,8 @@ module Textbringer
|
|
78
78
|
(?<singleline_comment> \/\/ .*(?:\\\n.*)*(?<!\\)\n )
|
79
79
|
) |
|
80
80
|
(?<partial_comment>
|
81
|
-
(?<
|
82
|
-
(?<
|
81
|
+
(?<partial_multiline_comment> \/\* (?:.|\n)* ) |
|
82
|
+
(?<partial_singleline_comment> \/\/ .*? \\\n (?:.|\n)* )
|
83
83
|
) |
|
84
84
|
(?<keyword>
|
85
85
|
(?: #{KEYWORDS.join("|")} ) \b
|
@@ -177,10 +177,9 @@ module Textbringer
|
|
177
177
|
|
178
178
|
def lex(s)
|
179
179
|
tokens = []
|
180
|
-
pos = 0
|
181
180
|
line = 1
|
182
181
|
column = 0
|
183
|
-
|
182
|
+
s.scan(TOKEN_REGEXP) do
|
184
183
|
text = $&
|
185
184
|
token_name = TOKEN_NAMES.find { |name| $~[name] }
|
186
185
|
if text.empty?
|
@@ -194,7 +193,6 @@ module Textbringer
|
|
194
193
|
else
|
195
194
|
column += text.size
|
196
195
|
end
|
197
|
-
pos += text.size
|
198
196
|
end
|
199
197
|
tokens
|
200
198
|
end
|
data/lib/textbringer/plugin.rb
CHANGED
@@ -2,9 +2,14 @@
|
|
2
2
|
|
3
3
|
module Textbringer
|
4
4
|
module Plugin
|
5
|
+
class << self
|
6
|
+
attr_accessor :directory
|
7
|
+
end
|
8
|
+
|
9
|
+
@directory = File.expand_path("~/.textbringer/plugins")
|
10
|
+
|
5
11
|
def self.load_plugins
|
6
|
-
files = Gem.find_files("textbringer_plugin.rb")
|
7
|
-
files.group_by { |file|
|
12
|
+
files = Gem.find_files("textbringer_plugin.rb").group_by { |file|
|
8
13
|
file.slice(/([^\/]+)-[\w.]+\/lib\/textbringer_plugin\.rb\z/, 1)
|
9
14
|
}.map { |gem, versions|
|
10
15
|
versions.sort_by { |version|
|
@@ -12,10 +17,10 @@ module Textbringer
|
|
12
17
|
1)
|
13
18
|
Gem::Version.create(v)
|
14
19
|
}.last
|
15
|
-
}.
|
20
|
+
} + Dir.glob(File.join(directory, "*/**/textbringer_plugin.rb"))
|
21
|
+
files.each do |file|
|
16
22
|
load(file)
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
21
|
-
|
data/lib/textbringer/utils.rb
CHANGED
@@ -49,8 +49,32 @@ module Textbringer
|
|
49
49
|
sleep(secs)
|
50
50
|
end
|
51
51
|
|
52
|
+
def background
|
53
|
+
Thread.start do
|
54
|
+
begin
|
55
|
+
yield
|
56
|
+
rescue Exception => e
|
57
|
+
next_tick do
|
58
|
+
raise e
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def next_tick(*args, &block)
|
65
|
+
Controller.current.next_tick(*args, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_event
|
69
|
+
Controller.current.read_event
|
70
|
+
end
|
71
|
+
|
52
72
|
def read_char
|
53
|
-
Controller.current.
|
73
|
+
event = Controller.current.read_event
|
74
|
+
if !event.is_a?(String)
|
75
|
+
raise EditorError, "Non character event: #{event.inspect}"
|
76
|
+
end
|
77
|
+
event
|
54
78
|
end
|
55
79
|
|
56
80
|
def received_keyboard_quit?
|
data/lib/textbringer/version.rb
CHANGED
data/lib/textbringer/window.rb
CHANGED
@@ -322,7 +322,7 @@ module Textbringer
|
|
322
322
|
self == @@current
|
323
323
|
end
|
324
324
|
|
325
|
-
def
|
325
|
+
def read_event
|
326
326
|
key = get_char
|
327
327
|
if key.is_a?(Integer)
|
328
328
|
if PDCurses.dll_loaded?
|
@@ -340,10 +340,10 @@ module Textbringer
|
|
340
340
|
end
|
341
341
|
end
|
342
342
|
|
343
|
-
def
|
343
|
+
def read_event_nonblock
|
344
344
|
@window.nodelay = true
|
345
345
|
begin
|
346
|
-
|
346
|
+
read_event
|
347
347
|
ensure
|
348
348
|
@window.nodelay = false
|
349
349
|
end
|
@@ -553,7 +553,7 @@ module Textbringer
|
|
553
553
|
|
554
554
|
def scroll_up
|
555
555
|
if @bottom_of_window.location == @buffer.point_max
|
556
|
-
raise
|
556
|
+
raise RangeError, "End of buffer"
|
557
557
|
end
|
558
558
|
@buffer.point_to_mark(@bottom_of_window)
|
559
559
|
@buffer.previous_line
|
@@ -563,7 +563,7 @@ module Textbringer
|
|
563
563
|
|
564
564
|
def scroll_down
|
565
565
|
if @top_of_window.location == @buffer.point_min
|
566
|
-
raise
|
566
|
+
raise RangeError, "Beginning of buffer"
|
567
567
|
end
|
568
568
|
@buffer.point_to_mark(@top_of_window)
|
569
569
|
@buffer.next_line
|
@@ -928,7 +928,8 @@ module Textbringer
|
|
928
928
|
if width > max_width
|
929
929
|
@buffer.forward_char
|
930
930
|
break
|
931
|
-
elsif width == max_width || @buffer.beginning_of_line?
|
931
|
+
elsif width == max_width || @buffer.beginning_of_line? ||
|
932
|
+
@buffer.point_at_mark?(@top_of_window)
|
932
933
|
break
|
933
934
|
end
|
934
935
|
@buffer.backward_char
|
data/textbringer.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_runtime_dependency "curses", "~> 1.2"
|
25
25
|
spec.add_runtime_dependency "unicode-display_width", "~> 1.1"
|
26
26
|
spec.add_runtime_dependency "clipboard", "~> 1.1"
|
27
|
-
spec.add_runtime_dependency "
|
27
|
+
spec.add_runtime_dependency "fiddley", ">= 0.0.5"
|
28
28
|
spec.add_runtime_dependency "editorconfig"
|
29
29
|
|
30
30
|
spec.add_development_dependency "bundler", "~> 1.14"
|
@@ -33,7 +33,5 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_development_dependency "simplecov"
|
34
34
|
spec.add_development_dependency "codecov"
|
35
35
|
spec.add_development_dependency "bundler-audit"
|
36
|
-
spec.add_development_dependency "guard"
|
37
|
-
spec.add_development_dependency "guard-shell"
|
38
36
|
spec.add_development_dependency "ripper-tags"
|
39
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: textbringer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -53,19 +53,19 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: fiddley
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.0.5
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.0.5
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: editorconfig
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,34 +164,6 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: guard
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - ">="
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - ">="
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: guard-shell
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - ">="
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '0'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - ">="
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '0'
|
195
167
|
- !ruby/object:Gem::Dependency
|
196
168
|
name: ripper-tags
|
197
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -221,7 +193,6 @@ files:
|
|
221
193
|
- ".travis.yml"
|
222
194
|
- CHANGES.md
|
223
195
|
- Gemfile
|
224
|
-
- Guardfile
|
225
196
|
- LICENSE.txt
|
226
197
|
- README.md
|
227
198
|
- Rakefile
|
data/Guardfile
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# A sample Guardfile
|
2
|
-
# More info at https://github.com/guard/guard#readme
|
3
|
-
|
4
|
-
## Uncomment and set this to only include directories you want to watch
|
5
|
-
# directories %w(app lib config test spec features) \
|
6
|
-
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
-
|
8
|
-
## Note: if you are using the `directories` clause above and you are not
|
9
|
-
## watching the project directory ('.'), then you will want to move
|
10
|
-
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
-
#
|
12
|
-
# $ mkdir config
|
13
|
-
# $ mv Guardfile config/
|
14
|
-
# $ ln -s config/Guardfile .
|
15
|
-
#
|
16
|
-
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
-
|
18
|
-
guard :shell do
|
19
|
-
watch(%r'^(lib|test)/.+\.rb$') do
|
20
|
-
`bundle exec tbtags -R`
|
21
|
-
end
|
22
|
-
end
|