rbfind 1.13 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rbfind +413 -416
- data/lib/rbfind.rb +568 -731
- data/lib/rbfind/core.rb +82 -0
- data/lib/rbfind/csv.rb +54 -0
- data/lib/{humansiz.rb → rbfind/humansiz.rb} +30 -9
- data/lib/rbfind/table.rb +114 -0
- metadata +9 -6
data/lib/rbfind.rb
CHANGED
@@ -2,34 +2,13 @@
|
|
2
2
|
# rbfind.rb -- Find replacement with many features
|
3
3
|
#
|
4
4
|
|
5
|
-
|
5
|
+
require "rbfind/core"
|
6
|
+
require "rbfind/csv"
|
6
7
|
|
7
|
-
SPECIAL_DIRS = %w(. ..)
|
8
|
-
CUR_DIR, SUPER_DIR = *SPECIAL_DIRS
|
9
8
|
|
10
|
-
|
11
|
-
s = SPECIAL_DIRS.dup
|
12
|
-
each { |f|
|
13
|
-
next if s.delete f
|
14
|
-
yield f
|
15
|
-
}
|
16
|
-
end
|
17
|
-
|
18
|
-
method_defined? :children or def children
|
19
|
-
entries - SPECIAL_DIRS
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
class File
|
25
|
-
class Stat
|
26
|
-
def identical? oth
|
27
|
-
oth = self.class.new oth unless self.class === oth
|
28
|
-
dev == oth.dev and ino == oth.ino
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
9
|
+
module RbFind
|
32
10
|
|
11
|
+
VERSION = "2.0.1".freeze
|
33
12
|
|
34
13
|
=begin rdoc
|
35
14
|
|
@@ -40,128 +19,126 @@ tool.
|
|
40
19
|
|
41
20
|
In Ruby programs, you may call:
|
42
21
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
# more terse
|
50
|
-
RbFind.run do puts path end
|
51
|
-
RbFind.run "dir" do puts path end
|
22
|
+
RbFind.run do puts path end
|
23
|
+
RbFind.run "dir" do puts path end
|
24
|
+
RbFind.run "dir1", "dir2" do puts path end
|
25
|
+
RbFind.run %w(dir1 dir2) do puts path end
|
26
|
+
RbFind.run "dir", :max_depth => 3 do puts path end
|
52
27
|
|
53
28
|
|
54
29
|
== File properties
|
55
30
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
f.readlink # symlink pointer or nil (*)
|
82
|
-
f.broken_link? # what you expect
|
83
|
-
f.arrow # ls-style "-> symlink" suffix (*)
|
31
|
+
name # file name (*)
|
32
|
+
path # file path relative to working directory (*)
|
33
|
+
fullpath # full file path (*)
|
34
|
+
path! # directories with a slash appended (*)
|
35
|
+
fullpath! # directories with a slash appended (*)
|
36
|
+
dirname # dirname of path
|
37
|
+
ext # file name extension
|
38
|
+
without_ext # file name without extension
|
39
|
+
depth # step depth
|
40
|
+
hidden? # filename starting with "." (No Windows version, yet.)
|
41
|
+
visible? # not hidden?
|
42
|
+
stat # file status information (File::Stat object)
|
43
|
+
mode # access mode (like 0755, 0644)
|
44
|
+
mtime # modify time (atime, ctime as well)
|
45
|
+
mage # age in seconds since walk started
|
46
|
+
age # alias for mage
|
47
|
+
user # owner
|
48
|
+
owner # dto. (alias)
|
49
|
+
group # group owner
|
50
|
+
user! # owner, "." if process owner
|
51
|
+
owner! # dto. (alias)
|
52
|
+
group! # group owner, "." if process owner
|
53
|
+
readlink # symlink pointer or nil (*)
|
54
|
+
broken_link? # what you expect
|
55
|
+
arrow # ls-style "-> symlink" suffix (*)
|
84
56
|
|
85
57
|
# (*) = colored version available (see below)
|
86
58
|
|
87
|
-
|
88
|
-
|
59
|
+
empty? # directory is empty
|
60
|
+
entries # directory entries
|
89
61
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
62
|
+
open { |o| ... } # open file
|
63
|
+
read n = nil # read first n bytes, nil reads to eof
|
64
|
+
lines { |l,i| ... } # open file and yield each |line,lineno|
|
65
|
+
grep re # lines with `l =~ re and colsep path, i, l'
|
66
|
+
binary? n = 1 # test whether first n blocks contain null characters
|
67
|
+
bin? # alias for binary?
|
96
68
|
|
97
|
-
|
69
|
+
vimswap? # it is a Vim swapfile
|
98
70
|
|
99
71
|
Further will be redirected to the stat object (selective):
|
100
72
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
73
|
+
directory?
|
74
|
+
executable?
|
75
|
+
file?
|
76
|
+
pipe?
|
77
|
+
socket?
|
78
|
+
symlink?
|
107
79
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
80
|
+
readable?
|
81
|
+
writable?
|
82
|
+
size
|
83
|
+
zero?
|
112
84
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
85
|
+
uid
|
86
|
+
gid
|
87
|
+
owned?
|
88
|
+
grpowned?
|
117
89
|
|
118
|
-
|
90
|
+
dir? # alias for directory?
|
119
91
|
|
120
92
|
Derivated from stat:
|
121
93
|
|
122
|
-
|
123
|
-
|
94
|
+
stype # one-letter (short) version of ftype
|
95
|
+
modes # rwxr-xr-x style modes
|
124
96
|
|
125
|
-
|
126
|
-
|
97
|
+
filesize # returns size for files, else nil
|
98
|
+
filesize { |s| s > 1024 } # returns block result for files
|
127
99
|
|
128
100
|
|
129
101
|
== Actions
|
130
102
|
|
131
|
-
|
132
|
-
|
103
|
+
done # exit from current entry
|
104
|
+
done! # dto.
|
105
|
+
prune # do not descend directory; abort current entry
|
106
|
+
prune! # dto.
|
107
|
+
no_vcs # omit .svn, CVS and .git directories
|
108
|
+
novcs # dto.
|
133
109
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
110
|
+
colsep path, ... # output parameters in a line separated by colons
|
111
|
+
col_sep # dto. (alias)
|
112
|
+
tabsep path, ... # separate by tabs
|
113
|
+
tab_sep #
|
114
|
+
spcsep path, ... # separate by spaces
|
115
|
+
spc_sep #
|
116
|
+
spacesep path, ... #
|
117
|
+
space_sep #
|
118
|
+
p # alias for space_sep
|
119
|
+
csv sep, path, ... # separate by user-defined separator
|
143
120
|
|
144
|
-
|
121
|
+
rename newname # rename, but leave it in the same directory
|
145
122
|
|
146
123
|
|
147
124
|
== Color support
|
148
125
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
126
|
+
cname # colorized name
|
127
|
+
cpath # colorized path
|
128
|
+
cpath! # colorized path!
|
129
|
+
cfullpath # colorized fullpath
|
130
|
+
cfullpath! # colorized fullpath!
|
131
|
+
creadlink # colored symlink pointer
|
132
|
+
carrow # colored "-> symlink" suffix
|
156
133
|
|
157
|
-
|
158
|
-
|
134
|
+
color arg # colorize argument
|
135
|
+
colour arg # alias
|
159
136
|
|
160
137
|
RbFind.colors str # define colors
|
161
138
|
RbFind.colours str # alias
|
162
139
|
|
163
140
|
Default color setup is "xxHbexfxcxdxbxegedabagacadAx".
|
164
|
-
In case you did not call RbFind.colors, the environment variables
|
141
|
+
In case you did not call RbFind::Walk.colors, the environment variables
|
165
142
|
RBFIND_COLORS and RBFIND_COLOURS are looked up. If neither is given
|
166
143
|
but LSCOLORS is set, the fields 2-13 default to that.
|
167
144
|
A Gnu LS_COLOR-style string may also be given, though glob patterns will
|
@@ -191,7 +168,7 @@ Derivated from stat:
|
|
191
168
|
13 whiteout
|
192
169
|
14 unknown
|
193
170
|
|
194
|
-
|
171
|
+
suffix # ls-like suffixes |@=/%* for pipe, ..., executable
|
195
172
|
|
196
173
|
|
197
174
|
== Encoding issues
|
@@ -199,7 +176,7 @@ Derivated from stat:
|
|
199
176
|
Ruby raises an ArgumentError if, for example, an ISO8859-1-encoded
|
200
177
|
string gets read in as UTF-8-encoded and then is matched against a
|
201
178
|
UTF-8-encoded regular expression. This will happen if you are
|
202
|
-
running RbFind from an environment with something like
|
179
|
+
running RbFind::Walk from an environment with something like
|
203
180
|
LANG="de_DE.UTF-8" and if you are searching directories containing
|
204
181
|
single-byte encoded file names or files with single-byte or binary
|
205
182
|
content.
|
@@ -221,752 +198,612 @@ variables because these will be used in the further processing.
|
|
221
198
|
|
222
199
|
Find them all:
|
223
200
|
|
224
|
-
RbFind.
|
201
|
+
RbFind.run do puts path end
|
225
202
|
|
226
203
|
Omit version control:
|
227
204
|
|
228
|
-
RbFind.
|
229
|
-
|
230
|
-
puts
|
205
|
+
RbFind.run "myproject" do
|
206
|
+
prune if name == ".svn"
|
207
|
+
puts path
|
231
208
|
end
|
232
209
|
|
233
210
|
# or even
|
234
|
-
RbFind.
|
235
|
-
|
236
|
-
puts
|
211
|
+
RbFind.run "myproject" do
|
212
|
+
novcs
|
213
|
+
puts path
|
237
214
|
end
|
238
215
|
|
239
216
|
Mention directory contents before directory itself:
|
240
217
|
|
241
|
-
RbFind.
|
242
|
-
puts
|
218
|
+
RbFind.run "myproject", depth_first: true do
|
219
|
+
puts path
|
243
220
|
end
|
244
221
|
|
245
222
|
Limit search depth:
|
246
223
|
|
247
|
-
RbFind.
|
248
|
-
puts
|
224
|
+
RbFind.run max_depth: 2 do
|
225
|
+
puts path
|
249
226
|
end
|
250
227
|
|
251
228
|
Unsorted (alphabetical sort is default):
|
252
229
|
|
253
|
-
RbFind.
|
254
|
-
puts
|
230
|
+
RbFind.run sort: false do
|
231
|
+
puts path
|
255
232
|
end
|
256
233
|
|
257
234
|
Reverse sort:
|
258
235
|
|
259
|
-
RbFind.
|
260
|
-
puts
|
236
|
+
RbFind.run sort: true, reverse: true do
|
237
|
+
puts path
|
261
238
|
end
|
262
239
|
|
263
240
|
Sort without case sensitivity and preceding dot:
|
264
241
|
|
265
242
|
s = proc { |x| x =~ /^\.?/ ; $'.downcase }
|
266
|
-
RbFind.
|
267
|
-
puts
|
243
|
+
RbFind.run sort: s do
|
244
|
+
puts path
|
268
245
|
end
|
269
246
|
|
270
247
|
=end
|
271
248
|
|
272
|
-
class RbFind
|
273
249
|
|
274
|
-
|
250
|
+
class Done < Exception ; end
|
251
|
+
class Prune < Exception ; end
|
275
252
|
|
276
253
|
class <<self
|
277
|
-
|
278
|
-
|
279
|
-
params = case args.last
|
280
|
-
when Hash then args.pop
|
281
|
-
end
|
282
|
-
args.flatten!
|
283
|
-
if args.any? then
|
284
|
-
count = 0
|
285
|
-
args.each do |path|
|
286
|
-
f = new path, count, params, &block
|
287
|
-
count = f.count
|
288
|
-
end
|
289
|
-
else
|
290
|
-
f = new nil, 0, params, &block
|
291
|
-
f.count
|
292
|
-
end
|
293
|
-
end
|
294
|
-
def run *args, &block
|
295
|
-
open *args do |f| f.instance_eval &block end
|
254
|
+
def run *args, **params, &block
|
255
|
+
Walk.run *args, **params, &block
|
296
256
|
end
|
297
257
|
end
|
298
258
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
dl = :do_level_depth if params.delete :depth
|
308
|
-
md = params.delete :max_depth ; @max_depth = md.to_i if md
|
309
|
-
st = params.delete :sort ; @sort = sort_parser st
|
310
|
-
@follow = params.delete :follow
|
311
|
-
@error = params.delete :error
|
312
|
-
params.empty? or
|
313
|
-
raise RuntimeError, "Unknown parameter(s): #{params.keys.join ','}."
|
314
|
-
end
|
315
|
-
@do_level = method dl||:do_level
|
316
|
-
|
317
|
-
@ostat = $stdout.stat
|
318
|
-
@ostat = nil unless @ostat.file?
|
319
|
-
|
320
|
-
@start, @count = Time.now, count
|
321
|
-
@wd = Dir.getwd
|
322
|
-
if path then
|
323
|
-
@max_depth += 1 if @max_depth
|
324
|
-
File.lstat path
|
325
|
-
@wd = nil unless absolute_path? path
|
326
|
-
@levels.push path
|
327
|
-
walk
|
328
|
-
else
|
329
|
-
build_path
|
330
|
-
scan_dir
|
259
|
+
class Walk
|
260
|
+
|
261
|
+
class <<self
|
262
|
+
def run *args, **params, &block
|
263
|
+
i = new **params, &block
|
264
|
+
i.run *args
|
265
|
+
i.count
|
266
|
+
end
|
331
267
|
end
|
332
|
-
end
|
333
268
|
|
334
|
-
|
269
|
+
private
|
335
270
|
|
336
|
-
|
271
|
+
def initialize max_depth: nil, depth_first: nil, follow: nil,
|
272
|
+
sort: true, reverse: false, error: nil, &block
|
273
|
+
@max_depth = max_depth
|
274
|
+
@depth_first = depth_first
|
275
|
+
@follow = follow
|
276
|
+
@sort = sort_parser sort, reverse
|
277
|
+
@error = error
|
278
|
+
@block = block
|
337
279
|
|
338
|
-
|
280
|
+
ostat = $stdout.stat
|
281
|
+
@ostat = ostat if ostat.file?
|
339
282
|
|
340
|
-
|
341
|
-
|
342
|
-
def fullpath ; @fullpath ; end
|
343
|
-
def path! ; append_slash @path ; end
|
344
|
-
def fullpath! ; append_slash @fullpath ; end
|
283
|
+
@wd, @start, @count = Dir.getwd, Time.now, 0
|
284
|
+
end
|
345
285
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
286
|
+
def sort_parser st, rev
|
287
|
+
r = case st
|
288
|
+
when Proc then proc { |l| l.sort_by! &st }
|
289
|
+
when nil, false, nil, "" then proc { }
|
290
|
+
else proc { |l| l.sort! }
|
291
|
+
end
|
292
|
+
rev ? proc { |l| r.call l ; l.reverse! } : r
|
293
|
+
end
|
350
294
|
|
351
|
-
|
352
|
-
def without_ext ; name[ /^(.+?)(?:\.[^.]+)?$/, 1 ].to_s ; end
|
295
|
+
public
|
353
296
|
|
354
|
-
|
297
|
+
attr_reader :wd, :start, :count, :depth
|
355
298
|
|
356
|
-
|
357
|
-
|
299
|
+
def run *args
|
300
|
+
@levels, @depth = [], 0
|
301
|
+
args.flatten!
|
302
|
+
args.compact!
|
303
|
+
if args.empty? then
|
304
|
+
visit_dir Dir::CUR_DIR
|
305
|
+
else
|
306
|
+
args.each { |base|
|
307
|
+
handle_error do
|
308
|
+
File.exists? base or raise "`#{base}` doesn't exist."
|
309
|
+
visit_depth base
|
310
|
+
end
|
311
|
+
}
|
312
|
+
end
|
313
|
+
ensure
|
314
|
+
@levels = @depth = nil
|
315
|
+
end
|
358
316
|
|
359
|
-
|
360
|
-
def mode ; stat.mode ; end
|
317
|
+
private
|
361
318
|
|
362
|
-
|
363
|
-
|
364
|
-
|
319
|
+
def join_path
|
320
|
+
(File.join @levels).freeze
|
321
|
+
end
|
365
322
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
323
|
+
def visit filename
|
324
|
+
@depth += 1
|
325
|
+
visit_depth filename
|
326
|
+
ensure
|
327
|
+
@depth -= 1
|
371
328
|
end
|
372
|
-
end
|
373
329
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
330
|
+
def visit_depth filename
|
331
|
+
@levels.push filename.dup.freeze
|
332
|
+
p_, @path = @path, join_path
|
333
|
+
if @depth_first then
|
334
|
+
enter_dir
|
335
|
+
call_block or raise "#{self.class}: prune doesn't work with :depth_first."
|
336
|
+
else
|
337
|
+
call_block and enter_dir
|
338
|
+
end
|
339
|
+
@count += 1
|
340
|
+
ensure
|
341
|
+
@path = p_
|
342
|
+
@levels.pop
|
343
|
+
end
|
344
|
+
|
345
|
+
def enter_dir
|
346
|
+
return unless File.directory? @path
|
347
|
+
if File.symlink? @path then
|
348
|
+
return unless @follow and handle_error do
|
349
|
+
d = @path.dup
|
350
|
+
while d != Dir::CUR_DIR do
|
351
|
+
d, = File.split d
|
352
|
+
raise "cyclic recursion in #@path" if File.identical? d, @path
|
353
|
+
end
|
354
|
+
true
|
355
|
+
end
|
356
|
+
end
|
357
|
+
handle_error do
|
358
|
+
visit_dir @path
|
359
|
+
end
|
360
|
+
end
|
381
361
|
|
382
|
-
|
362
|
+
def visit_dir dir
|
363
|
+
return if @max_depth and @max_depth == @depth
|
364
|
+
list = (Dir.new dir).children
|
365
|
+
@sort.call list
|
366
|
+
list.each { |f| visit f }
|
367
|
+
ensure
|
368
|
+
end
|
383
369
|
|
384
|
-
|
385
|
-
|
386
|
-
|
370
|
+
def call_block
|
371
|
+
e = Entry.new @levels.last, @path, self
|
372
|
+
handle_error do
|
373
|
+
$_, $. = e.name, count
|
374
|
+
begin
|
375
|
+
e.instance_eval &@block
|
376
|
+
rescue Done
|
377
|
+
ensure
|
378
|
+
if !(e.name.equal? @levels.last) && e.name != @levels.last then
|
379
|
+
p = @path
|
380
|
+
e.name == (File.basename e.name) or
|
381
|
+
raise "#{self.class}: rename to `#{e.name}' may not be a path."
|
382
|
+
e.name.freeze
|
383
|
+
@levels.pop
|
384
|
+
@levels.push e.name
|
385
|
+
@path = join_path
|
386
|
+
File.rename p, @path
|
387
|
+
end
|
388
|
+
end
|
389
|
+
true
|
390
|
+
end
|
391
|
+
rescue Prune
|
392
|
+
end
|
387
393
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
394
|
+
def handle_error
|
395
|
+
yield
|
396
|
+
rescue
|
397
|
+
case @error
|
398
|
+
when Proc then @error.call
|
399
|
+
when String then instance_eval @error
|
400
|
+
else raise
|
401
|
+
end
|
402
|
+
nil
|
403
|
+
end
|
392
404
|
|
393
|
-
def now ; @start ; end
|
394
|
-
def age ; @start - stat.mtime ; end
|
395
|
-
alias age_secs age
|
396
|
-
alias age_s age_secs
|
397
|
-
|
398
|
-
# :stopdoc:
|
399
|
-
MINUTE = 60
|
400
|
-
HOUR = 60*MINUTE
|
401
|
-
DAY = 24*HOUR
|
402
|
-
# :startdoc:
|
403
|
-
|
404
|
-
def age_mins ; age / MINUTE ; end
|
405
|
-
alias age_m age_mins
|
406
|
-
def age_hours ; age / HOUR ; end
|
407
|
-
alias age_h age_hours
|
408
|
-
def age_days ; age / DAY ; end
|
409
|
-
alias age_d age_days
|
410
|
-
|
411
|
-
private
|
412
|
-
|
413
|
-
def method_missing sym, *args, &block
|
414
|
-
stat.send sym, *args, &block
|
415
|
-
rescue NoMethodError
|
416
|
-
super
|
417
405
|
end
|
418
406
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
def stype
|
427
|
-
m = stat.mode >> 12 rescue nil
|
428
|
-
case m
|
429
|
-
when 001 then "p"
|
430
|
-
when 002 then "c"
|
431
|
-
when 004 then "d"
|
432
|
-
when 006 then "b"
|
433
|
-
when 010 then "-"
|
434
|
-
when 012 then "l"
|
435
|
-
when 014 then "s"
|
436
|
-
when 016 then "w"
|
437
|
-
when nil then "#"
|
438
|
-
else "?"
|
407
|
+
|
408
|
+
class Entry
|
409
|
+
|
410
|
+
attr_reader :path, :name
|
411
|
+
|
412
|
+
def initialize name, path, walk
|
413
|
+
@name, @path, @walk = name, path, walk
|
439
414
|
end
|
440
|
-
end
|
441
415
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
h = m & 07
|
450
|
-
m >>= 3
|
451
|
-
r.insert 0, ((h & 01).nonzero? ? "x" : "-")
|
452
|
-
r.insert 0, ((h & 02).nonzero? ? "w" : "-")
|
453
|
-
r.insert 0, ((h & 04).nonzero? ? "r" : "-")
|
454
|
-
}
|
455
|
-
if (m & 04).nonzero? then
|
456
|
-
r[ 2] = r[ 2, 1] == "x" ? "s" : "S"
|
457
|
-
end
|
458
|
-
if (m & 02).nonzero? then
|
459
|
-
r[ 5] = r[ 5, 1] == "x" ? "s" : "S"
|
460
|
-
end
|
461
|
-
if (m & 01).nonzero? then
|
462
|
-
r[ 8] = r[ 8, 1] == "x" ? "t" : "T"
|
463
|
-
end
|
464
|
-
r
|
465
|
-
end
|
416
|
+
def depth ; @walk.depth ; end
|
417
|
+
def now ; @walk.start ; end
|
418
|
+
|
419
|
+
def fullpath ; @fullpath ||= File.absolute_path @path, @walk.wd ; end
|
420
|
+
|
421
|
+
def stat ; @stat ||= File.lstat @path ; end
|
422
|
+
def rstat ; @rstat ||= File.stat @path ; end
|
466
423
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
else
|
478
|
-
stat.size if file?
|
424
|
+
|
425
|
+
private
|
426
|
+
def append_slash s ; (File.directory? s) ? (File.join s, "") : s ; end
|
427
|
+
public
|
428
|
+
|
429
|
+
def path! ; append_slash path ; end
|
430
|
+
def fullpath! ; append_slash fullpath ; end
|
431
|
+
|
432
|
+
def dirname
|
433
|
+
File.basename File.dirname fullpath
|
479
434
|
end
|
480
|
-
end
|
481
435
|
|
482
436
|
|
483
|
-
|
484
|
-
|
485
|
-
def cfullpath ; color fullpath ; end
|
486
|
-
def cpath! ; color path! ; end
|
487
|
-
def cfullpath! ; color fullpath! ; end
|
437
|
+
def ext ; File.extname name ; end
|
438
|
+
def without_ext ; name[ /^(.+?)(?:\.[^.]+)?$/, 1 ].to_s ; end
|
488
439
|
|
489
|
-
|
490
|
-
|
491
|
-
end
|
492
|
-
alias colour color
|
440
|
+
def hidden? ; name =~ /^\./ ; end
|
441
|
+
def visible? ; not hidden? ; end
|
493
442
|
|
494
|
-
DEFAULT_COLORS = "xxHbexfxcxdxbxegedabagacadAx"
|
495
443
|
|
496
|
-
|
444
|
+
def mode ; stat.mode ; end
|
497
445
|
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
t, c = a.split "="
|
503
|
-
h[ t] = c
|
504
|
-
}
|
505
|
-
%w(rs or di ln so pi ex bd cd su sg tw ow - -).map { |t| h[ t] }
|
446
|
+
private
|
447
|
+
def method_missing sym, *args, &block
|
448
|
+
if stat.respond_to? sym then
|
449
|
+
stat.send sym, *args, &block
|
506
450
|
else
|
507
|
-
|
508
|
-
str.scan /(.)(.)/i do
|
509
|
-
fg, bg = $~.captures.map { |x| x.downcase.ord - ?a.ord }
|
510
|
-
a = []
|
511
|
-
case fg
|
512
|
-
when 0..7 then a.push 30 + fg
|
513
|
-
end
|
514
|
-
a.push 1 if $1 == $1.upcase
|
515
|
-
case bg
|
516
|
-
when 0..7 then a.push 40 + bg
|
517
|
-
end
|
518
|
-
e = a.join ";"
|
519
|
-
cols.push e
|
520
|
-
end
|
521
|
-
cols
|
451
|
+
super
|
522
452
|
end
|
523
453
|
end
|
524
|
-
|
454
|
+
public
|
455
|
+
|
456
|
+
def dir? ; stat.directory? ; end
|
457
|
+
|
458
|
+
def aage ; @walk.start - stat.atime ; end
|
459
|
+
def mage ; @walk.start - stat.mtime ; end
|
460
|
+
def cage ; @walk.start - stat.ctime ; end
|
461
|
+
alias age mage
|
525
462
|
|
526
|
-
|
527
|
-
|
528
|
-
|
463
|
+
# :call-seq:
|
464
|
+
# filesize => nil or int
|
465
|
+
# filesize { |size| ... } => obj
|
466
|
+
#
|
467
|
+
# Returns the files size. When the object is not a regular file,
|
468
|
+
# nil will be returned or the block will not be called.
|
469
|
+
#
|
470
|
+
def filesize
|
471
|
+
stat.file? or return
|
472
|
+
if block_given? then
|
473
|
+
yield stat.size
|
474
|
+
else
|
475
|
+
stat.size
|
476
|
+
end
|
529
477
|
end
|
530
|
-
alias coloured colored
|
531
478
|
|
532
479
|
private
|
480
|
+
def etc
|
481
|
+
Etc
|
482
|
+
rescue NameError
|
483
|
+
require "etc" and retry
|
484
|
+
raise
|
485
|
+
end
|
486
|
+
def get_user u ; (etc.getpwuid u).name rescue u.to_s ; end
|
487
|
+
def get_group g ; (etc.getgrgid g).name rescue g.to_s ; end
|
488
|
+
public
|
533
489
|
|
534
|
-
def
|
535
|
-
|
536
|
-
env = DEFAULT_COLORS.dup
|
537
|
-
els = ENV[ "LSCOLORS"]
|
538
|
-
if els then
|
539
|
-
env[ 2*2, els.length] = els
|
540
|
-
end
|
541
|
-
env
|
542
|
-
)
|
490
|
+
def user
|
491
|
+
get_user stat.uid
|
543
492
|
end
|
493
|
+
alias owner user
|
544
494
|
|
545
|
-
|
495
|
+
def user!
|
496
|
+
u = stat.uid
|
497
|
+
u == Process.uid ? "." : (get_user u)
|
498
|
+
end
|
499
|
+
alias owner! user!
|
546
500
|
|
501
|
+
def group
|
502
|
+
get_group stat.gid
|
503
|
+
end
|
547
504
|
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
def suffix
|
552
|
-
m = stat.mode >> 12 rescue nil
|
553
|
-
case m
|
554
|
-
when 001 then "|"
|
555
|
-
when 002 then " "
|
556
|
-
when 004 then "/"
|
557
|
-
when 006 then " "
|
558
|
-
when 010 then stat.executable? ? "*" : " "
|
559
|
-
when 012 then "@"
|
560
|
-
when 014 then "="
|
561
|
-
when 016 then "%"
|
562
|
-
else "?"
|
505
|
+
def group!
|
506
|
+
g = stat.gid
|
507
|
+
g == Process.gid ? "." : (get_group g)
|
563
508
|
end
|
564
|
-
end
|
565
509
|
|
566
|
-
autoload :Etc, "etc"
|
567
510
|
|
568
|
-
|
569
|
-
# user() -> str
|
570
|
-
#
|
571
|
-
# Return user name or uid as string if unavailable.
|
572
|
-
#
|
573
|
-
def user
|
574
|
-
u = stat.uid
|
575
|
-
(Etc.getpwuid u).name rescue u.to_s
|
576
|
-
end
|
577
|
-
alias owner user
|
578
|
-
|
579
|
-
# :call-seq:
|
580
|
-
# group() -> str
|
581
|
-
#
|
582
|
-
# Return group name or gid as string if unavailable.
|
583
|
-
#
|
584
|
-
def group
|
585
|
-
g = stat.gid
|
586
|
-
(Etc.getgrgid g).name rescue g.to_s
|
587
|
-
end
|
511
|
+
def readlink ; File.readlink @path if stat.symlink? ; end
|
588
512
|
|
513
|
+
def broken_link?
|
514
|
+
return if stat.symlink?
|
515
|
+
rstat
|
516
|
+
false
|
517
|
+
rescue
|
518
|
+
true
|
519
|
+
end
|
589
520
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
# +nil+ is returned.
|
595
|
-
#
|
596
|
-
def empty?
|
597
|
-
read_dir.each_child { |f| return false }
|
598
|
-
true
|
599
|
-
rescue Errno::ENOTDIR
|
600
|
-
end
|
521
|
+
ARROW = " -> "
|
522
|
+
def arrow
|
523
|
+
ARROW + (File.readlink @path) if stat.symlink?
|
524
|
+
end
|
601
525
|
|
602
|
-
# :call-seq:
|
603
|
-
# contains?( name) -> true or false
|
604
|
-
#
|
605
|
-
# Check whether a directory contains an entry.
|
606
|
-
#
|
607
|
-
def contains? name
|
608
|
-
c = File.join @path, name
|
609
|
-
File.exists? c
|
610
|
-
end
|
611
526
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
527
|
+
|
528
|
+
# :call-seq:
|
529
|
+
# empty?() -> true or false
|
530
|
+
#
|
531
|
+
# Look up if the directory is empty. If the object is not a directory
|
532
|
+
# or not accessible, +nil+ is returned.
|
533
|
+
#
|
534
|
+
def empty?
|
535
|
+
(Dir.new @path).each_child { |f| return false }
|
536
|
+
true
|
537
|
+
rescue Errno::ENOTDIR
|
538
|
+
end
|
539
|
+
|
540
|
+
# :call-seq:
|
541
|
+
# contains?( name) -> true or false
|
542
|
+
#
|
543
|
+
# Check whether a directory contains an entry.
|
544
|
+
#
|
545
|
+
def contains? name
|
546
|
+
File.exists? File.join @path, name
|
547
|
+
end
|
548
|
+
|
549
|
+
# :call-seq:
|
550
|
+
# entries() -> ary
|
551
|
+
#
|
552
|
+
# Return all entries in an array. If the object is not a directory,
|
553
|
+
# +nil+ is returned.
|
554
|
+
#
|
555
|
+
def entries
|
556
|
+
(Dir.new @path).children
|
557
|
+
rescue Errno::ENOTDIR
|
558
|
+
end
|
559
|
+
alias children entries
|
560
|
+
|
561
|
+
|
562
|
+
def vcs?
|
563
|
+
%w(CVS .svn .git .hg .fslckout).include? name
|
564
|
+
end
|
565
|
+
|
566
|
+
|
567
|
+
# :call-seq:
|
568
|
+
# open() { |h| ... } -> obj
|
569
|
+
#
|
570
|
+
# Open the file for reading. If the object is not a regular file,
|
571
|
+
# nothing will be done.
|
572
|
+
#
|
573
|
+
def open &block
|
574
|
+
@ostat and @ostat.identical? @path and
|
575
|
+
raise "Refusing to open output file."
|
635
576
|
File.open @path, &block if file?
|
636
577
|
end
|
637
|
-
end
|
638
578
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
579
|
+
# :call-seq:
|
580
|
+
# read( n = nil) -> str or nil
|
581
|
+
# read( n = nil) { |b| ... } -> nil
|
582
|
+
#
|
583
|
+
# Read the first +n+ bytes or return +nil+ for others than regular
|
584
|
+
# files. +nil+ reads to end of file. If a block is given, chonks of
|
585
|
+
# +n+ bytes (or all) will be yielded.
|
586
|
+
#
|
587
|
+
def read n = nil
|
588
|
+
open { |o|
|
589
|
+
if block_given? then
|
590
|
+
if n then
|
591
|
+
while (r = o.read n) do
|
592
|
+
yield r
|
593
|
+
end
|
594
|
+
else
|
595
|
+
yield o.read
|
653
596
|
end
|
654
597
|
else
|
655
|
-
|
598
|
+
o.read n
|
656
599
|
end
|
657
|
-
|
658
|
-
|
659
|
-
end
|
660
|
-
}
|
661
|
-
end
|
600
|
+
}
|
601
|
+
end
|
662
602
|
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
603
|
+
# :call-seq:
|
604
|
+
# lines { |l,i| ... } -> nil
|
605
|
+
#
|
606
|
+
# Yield line by line together with the line number <code>i</code>.
|
607
|
+
#
|
608
|
+
def lines
|
609
|
+
block_given? or return lines do end
|
610
|
+
r = false
|
611
|
+
open { |file|
|
612
|
+
n = 0
|
613
|
+
file.each_line { |l|
|
614
|
+
l.chomp!
|
615
|
+
n += 1
|
616
|
+
$_, $. = l, n
|
617
|
+
r ||= true if yield l, n
|
618
|
+
}
|
619
|
+
r
|
678
620
|
}
|
679
|
-
|
680
|
-
}
|
681
|
-
end
|
621
|
+
end
|
682
622
|
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
end
|
689
|
-
lines { |l,i|
|
690
|
-
l.scrub!
|
691
|
-
l =~ re or next
|
692
|
-
if color then
|
693
|
-
l = "#$`\e[#{color}m#$&\e[m#$'"
|
623
|
+
def grep re, color = nil
|
624
|
+
case color
|
625
|
+
when /\A\d+(?:;\d+)*\z/, nil, false then
|
626
|
+
when true then color = "31;1" # red
|
627
|
+
else raise "Illegal color spec: #{color}"
|
694
628
|
end
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
629
|
+
lines { |l,i|
|
630
|
+
l.scrub!
|
631
|
+
l =~ re or next
|
632
|
+
color and l = "#$`\e[#{color}m#$&\e[m#$'"
|
633
|
+
colsep @path, i, l
|
634
|
+
true
|
635
|
+
}
|
636
|
+
end
|
699
637
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
638
|
+
# :call-seq:
|
639
|
+
# binary?( n = 1) -> true or false
|
640
|
+
#
|
641
|
+
# Test whether the first <code>n</code> blocks contain null characters.
|
642
|
+
#
|
643
|
+
def binary? n = 1
|
644
|
+
bs = stat.blksize
|
645
|
+
open { |file|
|
646
|
+
loop do
|
647
|
+
if n then
|
648
|
+
break if n <= 0
|
649
|
+
n -= 1
|
650
|
+
end
|
651
|
+
b = file.read bs
|
652
|
+
b or break
|
653
|
+
return true if b[ "\0"]
|
713
654
|
end
|
714
|
-
|
715
|
-
|
716
|
-
|
655
|
+
}
|
656
|
+
false
|
657
|
+
end
|
658
|
+
alias bin? binary?
|
659
|
+
|
660
|
+
def vimswap?
|
661
|
+
if name =~ /\A(\..+)?\.sw[a-z]\z/i then
|
662
|
+
mark = read 5
|
663
|
+
mark == "b0VIM"
|
717
664
|
end
|
718
|
-
|
719
|
-
false
|
720
|
-
end
|
721
|
-
alias bin? binary?
|
665
|
+
end
|
722
666
|
|
723
667
|
|
724
|
-
# :stopdoc:
|
725
|
-
class Prune < Exception ; end
|
726
|
-
# :startdoc:
|
727
|
-
|
728
|
-
# :call-seq:
|
729
|
-
# prune() -> (does not return)
|
730
|
-
#
|
731
|
-
# Abandon the current object (directory) and ignore all subdirectories.
|
732
|
-
#
|
733
|
-
def prune ; raise Prune ; end
|
734
|
-
|
735
|
-
# :call-seq:
|
736
|
-
# novcs() -> nil
|
737
|
-
#
|
738
|
-
# Perform <code>prune</code> if the current object is a CVS, Subversion or
|
739
|
-
# Git directory.
|
740
|
-
#
|
741
|
-
def novcs
|
742
|
-
prune if %w(CVS .svn .git .hg .fslckout).include? name
|
743
|
-
end
|
744
|
-
alias no_vcs novcs
|
745
|
-
|
746
|
-
# :call-seq:
|
747
|
-
# vimswap? -> true or false
|
748
|
-
#
|
749
|
-
# Check whether the current object is a Vim swapfile.
|
750
|
-
#
|
751
|
-
def vimswap?
|
752
|
-
if name =~ /\A(\..+)?\.sw[a-z]\z/i then
|
753
|
-
mark = read 5
|
754
|
-
mark == "b0VIM"
|
755
|
-
end
|
756
|
-
end
|
757
668
|
|
758
|
-
|
759
|
-
|
669
|
+
def done ; raise Done ; end
|
670
|
+
alias done! done
|
760
671
|
|
761
|
-
|
762
|
-
|
763
|
-
end
|
764
|
-
alias col_sep colsep
|
672
|
+
def prune ; raise Prune ; end
|
673
|
+
alias prune! prune
|
765
674
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
675
|
+
def novcs
|
676
|
+
prune if vcs?
|
677
|
+
end
|
678
|
+
alias no_vcs novcs
|
770
679
|
|
771
|
-
def spcsep *args
|
772
|
-
csv " ", *args
|
773
|
-
end
|
774
|
-
alias spc_sep spcsep
|
775
|
-
alias space_sep spc_sep
|
776
|
-
alias spacesep spcsep
|
777
|
-
alias p spcsep
|
778
|
-
|
779
|
-
def csv sep, *args
|
780
|
-
e = args.join sep
|
781
|
-
puts e
|
782
|
-
end
|
783
680
|
|
784
|
-
|
785
|
-
p = @path
|
786
|
-
nb = File.basename newname
|
787
|
-
newname == nb or raise RuntimeError,
|
788
|
-
"#{self.class}: rename to `#{newname}' may not be a path."
|
789
|
-
nb.freeze
|
790
|
-
@levels.pop
|
791
|
-
@levels.push nb
|
792
|
-
build_path
|
793
|
-
File.rename p, @path
|
794
|
-
nil
|
795
|
-
end
|
681
|
+
include Csv
|
796
682
|
|
797
|
-
private
|
798
683
|
|
799
|
-
|
800
|
-
case st
|
801
|
-
when Proc then st
|
802
|
-
when Numeric then st
|
803
|
-
when true then +1
|
804
|
-
when false then 0
|
805
|
-
when nil then +1
|
806
|
-
else
|
807
|
-
case st.to_s
|
808
|
-
when "^", "reverse", /^desc/, /^-/ then -1
|
809
|
-
when "unsorted", "*" then 0
|
810
|
-
else +1
|
811
|
-
end
|
812
|
-
end
|
813
|
-
end
|
684
|
+
def rename newname ; @name = newname ; end
|
814
685
|
|
815
|
-
def absolute_path? p
|
816
|
-
loop do
|
817
|
-
q = File.dirname p
|
818
|
-
break if q == p
|
819
|
-
p = q
|
820
|
-
end
|
821
|
-
p != Dir::CUR_DIR
|
822
|
-
end
|
823
686
|
|
824
|
-
def build_path
|
825
|
-
@path = File.join @levels
|
826
|
-
@fullpath = if @wd then
|
827
|
-
File.join @wd, @path
|
828
|
-
else
|
829
|
-
@path
|
830
|
-
end
|
831
|
-
if @path.empty? then @path = Dir::CUR_DIR end
|
832
|
-
@fullpath.freeze
|
833
|
-
@path.freeze
|
834
|
-
end
|
835
687
|
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
end
|
688
|
+
def cname ; color name ; end
|
689
|
+
def cpath ; color path ; end
|
690
|
+
def cfullpath ; color fullpath ; end
|
691
|
+
def cpath! ; color path! ; end
|
692
|
+
def cfullpath! ; color fullpath! ; end
|
842
693
|
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
694
|
+
def creadlink
|
695
|
+
l = readlink
|
696
|
+
if l then
|
697
|
+
s = rstat rescue nil
|
698
|
+
color_stat l, s
|
699
|
+
end
|
848
700
|
end
|
849
|
-
scan_dir
|
850
|
-
end
|
851
701
|
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
scan_dir
|
856
|
-
ensure
|
857
|
-
@path, @fullpath = path, fullpath
|
858
|
-
end
|
859
|
-
begin
|
860
|
-
call_block
|
861
|
-
rescue Prune
|
862
|
-
raise RuntimeError, "#{self.class}: prune doesn't work with :depth."
|
702
|
+
def carrow
|
703
|
+
r = creadlink
|
704
|
+
ARROW + r if r
|
863
705
|
end
|
864
|
-
end
|
865
706
|
|
866
|
-
def call_block
|
867
|
-
set_predefs name, count
|
868
|
-
@block.call self
|
869
|
-
end
|
870
707
|
|
871
|
-
|
872
|
-
|
873
|
-
b.local_variable_set "_", [ l, n]
|
874
|
-
b.eval "$_, $. = *_"
|
875
|
-
end
|
876
|
-
|
877
|
-
def read_dir
|
878
|
-
handle_error Errno::EACCES do
|
879
|
-
Dir.new @path
|
708
|
+
def color arg
|
709
|
+
color_stat arg, stat
|
880
710
|
end
|
881
|
-
|
711
|
+
alias colour color
|
882
712
|
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
713
|
+
private
|
714
|
+
|
715
|
+
def color_stat arg, s
|
716
|
+
m = s.mode if s
|
717
|
+
code = case m && m >> 12
|
718
|
+
when 001 then 5
|
719
|
+
when 002 then 8
|
720
|
+
when 004 then
|
721
|
+
if (m & 0002).nonzero? then
|
722
|
+
if (m & 01000).nonzero? then 11
|
723
|
+
else 12
|
724
|
+
end
|
725
|
+
else 2
|
726
|
+
end
|
727
|
+
when 006 then 7
|
728
|
+
when 010 then
|
729
|
+
if (m & 0111).nonzero? then
|
730
|
+
if (m & 04000).nonzero? then 9
|
731
|
+
elsif (m & 02000).nonzero? then 10
|
732
|
+
else 6
|
733
|
+
end
|
734
|
+
else col_type or 0
|
735
|
+
end
|
736
|
+
when 012 then 3
|
737
|
+
when 014 then 4
|
738
|
+
when 016 then 13
|
739
|
+
when nil then 1
|
740
|
+
else 14
|
893
741
|
end
|
742
|
+
self.class.colored arg, code
|
894
743
|
end
|
895
|
-
dir = (read_dir or return).children
|
896
|
-
if @sort.respond_to? :call then
|
897
|
-
dir = dir.sort_by &@sort
|
898
|
-
elsif @sort and @sort.nonzero? then
|
899
|
-
dir.sort!
|
900
|
-
dir.reverse! if @sort < 0
|
901
|
-
end
|
902
|
-
dir.each { |f|
|
903
|
-
f.freeze
|
904
|
-
begin
|
905
|
-
@levels.push f
|
906
|
-
walk
|
907
|
-
ensure
|
908
|
-
@levels.pop
|
909
|
-
end
|
910
|
-
}
|
911
|
-
end
|
912
744
|
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
else
|
921
|
-
raise
|
745
|
+
def col_type
|
746
|
+
# Overwrite this to define custom colors
|
747
|
+
# Example:
|
748
|
+
# case ext
|
749
|
+
# when ".png", /\.jpe?g$/, /\.tiff?$/ then 15
|
750
|
+
# when /\.tar\.(gz|bz2)$/ then 16
|
751
|
+
# end
|
922
752
|
end
|
923
|
-
nil
|
924
|
-
end
|
925
753
|
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
754
|
+
DEFAULT_COLORS = "xxHbexfxcxdxbxegedabagacadAx"
|
755
|
+
|
756
|
+
class <<self
|
757
|
+
|
758
|
+
def colored arg, num
|
759
|
+
colors col_str
|
760
|
+
"\e[#{@colors[num]}m#{arg}\e[m"
|
761
|
+
end
|
762
|
+
alias coloured colored
|
763
|
+
|
764
|
+
def colors str
|
765
|
+
@colors ||= if str =~ /:/ then
|
766
|
+
h = {}
|
767
|
+
(str.split ":").each { |a|
|
768
|
+
t, c = a.split "="
|
769
|
+
h[ t] = c
|
770
|
+
}
|
771
|
+
%w(rs or di ln so pi ex bd cd su sg tw ow - -).map { |t| h[ t] }
|
772
|
+
else
|
773
|
+
cols = []
|
774
|
+
str.scan /(.)(.)/i do
|
775
|
+
fg, bg = $~.captures.map { |x| x.downcase.ord - ?a.ord }
|
776
|
+
a = []
|
777
|
+
case fg
|
778
|
+
when 0..7 then a.push 30 + fg
|
779
|
+
end
|
780
|
+
a.push 1 if $1 == $1.upcase
|
781
|
+
case bg
|
782
|
+
when 0..7 then a.push 40 + bg
|
783
|
+
end
|
784
|
+
e = a.join ";"
|
785
|
+
cols.push e
|
945
786
|
end
|
946
|
-
|
787
|
+
cols
|
947
788
|
end
|
948
|
-
|
949
|
-
|
950
|
-
when 016 then 13
|
951
|
-
when nil then 1
|
952
|
-
else 14
|
953
|
-
end
|
954
|
-
self.class.colored arg, code
|
955
|
-
end
|
789
|
+
end
|
790
|
+
alias colours colors
|
956
791
|
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
792
|
+
private
|
793
|
+
|
794
|
+
def col_str
|
795
|
+
ENV[ "RBFIND_COLORS"] || ENV[ "RBFIND_COLOURS"] || ENV[ "LS_COLORS"] || (
|
796
|
+
env = DEFAULT_COLORS.dup
|
797
|
+
els = ENV[ "LSCOLORS"]
|
798
|
+
if els then
|
799
|
+
env[ 2*2, els.length] = els
|
800
|
+
end
|
801
|
+
env
|
802
|
+
)
|
803
|
+
end
|
965
804
|
|
966
|
-
class <<self
|
967
|
-
def find *args
|
968
|
-
raise NotImplementedError, "This is not the standard Find."
|
969
805
|
end
|
806
|
+
|
970
807
|
end
|
971
808
|
|
972
809
|
end
|