-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilter
executable file
·149 lines (130 loc) · 5.38 KB
/
filter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env raku
# filter - Filter a list of filenames, outputting only those whose extension denotes a specified "type".
# Usage:
#
# filter [--print=FORMAT] [--invert] <type>
#
# TYPE can be abbreviated when unambiguous. Use --print=types to get a list of supported types.
#
# If --print is provided, just print the list of extensions that would be used rather than filtering.
# --print's output format can be one of: find, space, newline (the default), or types (newline-separated list of supported types).
# --print=find will print the extensions as arguments for the "find" command.
# Examples:
# List all the video files in ~/media:
# find ~/media | filter v
# List every image and video file in your home directory:
# find ~/ | filter visual
# List files whose file extensions are not recognized by filter:
# find ~/ | filter --invert supported
# Code:
our %types := { # initial definition should have fundamental types only, not compound types like "visual" or "media".
text => qw/ txt text log md org /,
config => qw/ csv xml json ini yaml yml conf cnf service /,
script => qw/ sh bash fish py tcl perl raku rb /, # "scripting languages"
source => qw/ lisp cl factor c cpp h rs zig /, # compiled languages
document => qw/ pdf epub doc docx odt rtf /,
image => qw/ bmp gif jpeg jpg png webp /,
audio => qw/ aac aif aiff flac m4a mp3 ogg opus wav wma /,
video => qw/ avi flv m2t m4v mkv mov mp4 ogv webm wmv /,
archive => qw/ 7z bz2 gz rar tar tgz zip /,
directory => ("/", ),
};
%types{"visual"} = (|%types{"image"}, |%types{"video"});
%types{"media"} = (|%types{"image"}, |%types{"audio"}, |%types{"video"});
%types{"code"} = (|%types{"script"}, |%types{"source"});
%types{"supported"} = %types.values.reduce({ $^a.Array.append($^b.Array); }).List;
sub types() {
#= Get a list of supported types.
return (|%types.keys, |("all", ));
}
sub normalize-type($_) {
#= Get the "canonical" un-abbreviated name of the type.
return "text" if /^ t(e?xt(ual)?)? $/;
return "config" if /^ co?nf(ig)? $/;
return "script" if /^ scr(ipt)? $/;
return "source" if /^ s(ou)?rce? $/;
return "document" if /^ do(c(u(ment)?)?)? $/;
return "image" if /^ ( i(ma?ge?s?)? | p(ic(tures?)?)? ) $/;
return "audio" if /^ ( a(udio)? | mu(sic)? | s(ound)? ) $/;
return "video" if /^ v(ideos?)? $/;
return "archive" if /^ ( c(omp(ress(ed)?)?)? | ar(ch(ive)?)? ) $/;
return "visual" if /^ vis(ual)? $/;
return "media" if /^ me(dia)? $/;
return "code" if /^ code $/;
return "supported" if /^ su(p(port(ed)?)?)? $/;
return "directory" if /^ d(ir(ectory)?)? $/;
return "all" if /^ ( a(ll|ny) | '*' ) $/;
fail "Unknown type \"$_\". Try instead one of: " ~ types().sort.join(", ") ~ ".";
}
sub type-extensions($type is copy) {
#= Get a list of file extensions for TYPE.
if ($type ~~ /^\./) {
return $type.split(",").map(*.subst(/^\./, "")).List;
}
return %types{normalize-type($type)};
}
sub extension-of($filename) {
#= Get the lowercased file extension of FILENAME. If it's a directory, "/" is returned.
return "/" if ($filename.IO.d);
return $filename.IO.extension.lc;
}
sub is-type($filename, $type) {
#= True when FILENAME is of the specified type.
if ($type eq 'all') {
return True;
}
return extension-of($filename) ~~ any(|type-extensions($type));
}
sub GENERATE-USAGE(&main, |capture) is export {
&*GENERATE-USAGE(&main, |capture).subst('{types}', "all, " ~ types().sort.join(", "), :g);
}
sub MAIN(
$type? is copy, #= The type to filter to. A file extension (including period) can be specified, or a media type (or an abbreviation of one). Supported media types are: {types}.
Bool :$invert=False, #= "Invert" the output; only print non-matches.
:$print is copy, #= Print the extensions for TYPE rather than filtering. A value can be provided to change the format. Supported formats are: newline, space, find.
) {
if ($print.defined) {
$type //= "supported";
my $extensions = type-extensions($type);
if ($type eq 'all') {
fail "Printing all is not implemented; maybe try \"supported\" instead?";
}
if ($invert) {
$extensions = (type-extensions("supported") ⊖ $extensions).keys;
}
given $print {
when $_ === True or any(qw/ n nl newline /) {
type-extensions($type).map(&say);
}
when any(qw/ s sp space spaces /) {
type-extensions($type).join(" ").say;
}
when any(qw/ find bfs /) {
$extensions.map(
{
if ($_ eq '/') {
"-type\nd";
} else {
"-iname\n*." ~ $_;
}
}).join("\n-or\n").say;
}
when any(qw/ types type /) {
%types.keys.map(&say);
}
default {
fail "Unknown --print format: \"$_\". Try instead one of: newline, space, find, types.";
}
}
exit;
}
fail "A type must be provided. Try one of: " ~ types().sort.join(", ") ~ "." unless $type.defined;
for $*IN.lines {
my $is = is-type($_, $type);
if ($invert) {
.say unless $is;
} else {
.say when $is;
};
};
}