rbfind 1.13 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|