5 vidir - edit directories and filenames
9 B<vidir> [B<--verbose>] [I<directory>|I<file>|B<->]...
13 B<vidir> allows editing of directories and filenames in a text editor. If no
14 I<directory> is specified, the filenames of the current directory are edited.
16 When editing a directory, each item in the directory will appear on its own
17 numbered line. These numbers are how vidir keeps track of what items are
18 changed. Delete lines to remove files from the directory, or
19 edit filenames to rename files. You can also switch pairs of numbers to
22 Filenames to be edited may be given any combination of I<directory>s (which
23 will be expanded to the non-recursive list of all files within I<directory>),
24 I<file>s, or I<->. If the latter is specified, B<vidir> reads a list of
25 filenames from stdin and displays those for editing.
33 Verbosely display the actions taken by the program.
49 Edit subdirectory contents too. To delete subdirectories,
50 delete all their contents and the subdirectory itself in the editor.
52 =item find -type f | vidir -
54 Edit all files under the current directory and subdirectories.
58 =head1 ENVIRONMENT VARIABLES
68 Also supported to determine what editor to use.
74 Copyright 2006 by Joey Hess <id@joeyh.name>
76 Licensed under the GNU GPL.
81 use File
::Path
qw(make_path);
89 if (! GetOptions
("verbose|v" => \
$verbose)) {
90 die "Usage: $0 [--verbose] [directory|file|-]\n";
97 foreach my $item (@ARGV) {
99 push @dir, map { chomp; $_ } <STDIN
>;
101 open(STDIN
, "/dev/tty") || die "reopen: $!\n";
105 opendir(DIR
, $item) || die "$0: cannot read $item: $!\n";
106 push @dir, map { "$item$_" } sort readdir(DIR
);
114 if (grep(/[[:cntrl:]]/, @dir)) {
115 die "$0: control characters in filenames are not supported\n";
118 my $tmp=File
::Temp
->new(TEMPLATE
=> "dirXXXXX", DIR
=> File
::Spec
->tmpdir);
119 open (OUT
, ">".$tmp->filename) || die "$0: cannot create ".$tmp->filename.": $!\n";
124 next if /^(.*\/)?\
.$/ || /^(.*\
/)?\.\.$/;
126 print OUT
"$c\t$_\n";
129 close OUT
|| die "$0: cannot write ".$tmp->filename.": $!\n";
132 if (-x
"/usr/bin/editor") {
133 @editor="/usr/bin/editor";
135 if (exists $ENV{EDITOR
}) {
136 @editor=split(' ', $ENV{EDITOR
});
138 if (exists $ENV{VISUAL
}) {
139 @editor=split(' ', $ENV{VISUAL
});
141 $ret=system(@editor, $tmp);
143 die "@editor exited nonzero, aborting\n";
146 open (IN
, $tmp->filename) || die "$0: cannot read ".$tmp->filename.": $!\n";
149 if (/^(\d+)\t{0,1}(.*)/) {
152 if (! exists $item{$num}) {
153 die "$0: unknown item number $num\n";
155 elsif ($name ne $item{$num}) {
156 next unless length $name;
158 my $dir=dirname
($name);
160 if (! (-e
$src || -l
$src) ) {
161 print STDERR
"$0: $src does not exist\n";
167 if (-e
$name || -l
$name) {
170 while (-e
$tmp || -l
$tmp) {
174 if (! rename($name, $tmp)) {
175 print STDERR
"$0: failed to rename $name to $tmp: $!\n";
179 print "'$name' -> '$tmp'\n";
181 foreach my $item (keys %item) {
182 if ($item{$item} eq $name) {
188 if ((! -d
$dir) && (! make_path
($dir, {
191 print STDERR
"$0: failed to create directory tree $dir: $!\n";
194 elsif (! rename($src, $name)) {
195 print STDERR
"$0: failed to rename $src to $name: $!\n";
200 foreach (values %item) {
201 s
,^\Q
$src\E
($|/),$name$1,;
205 print "'$src' => '$name'\n";
215 die "$0: unable to parse line \"$_\", aborting\n";
218 close IN
|| die "$0: cannot read ".$tmp->filename.": $!\n";
219 unlink($tmp.'~') if -e
$tmp.'~';
224 if (-d
$file && ! -l
$file) {
232 foreach my $item (reverse sort values %item) {
234 print STDERR
"$0: failed to remove $item: $!\n";
238 print "removed '$item'\n";