App-PFT
view release on metacpan or search on metacpan
bin/pft-edit view on Meta::CPAN
pft edit -B -r -y2014 -d27 -m Aug
=head1 SEE ALSO
L<pft-init(1)>, L<pft-make(1)>
=cut
use strict;
use warnings;
use App::PFT;
use PFT::Tree;
use PFT::Date;
use Pod::Usage;
use Encode;
use Encode::Locale;
use Getopt::Long qw/GetOptionsFromArray/;
Getopt::Long::Configure qw/bundling/;
my %opts;
my %datespec;
GetOptions(
'year|y=i' => sub { $datespec{y} = $_[1] },
'month|m=s' => sub { $datespec{m} = $_[1] },
'day|d=i' => sub { $datespec{d} = $_[1] },
'B!' => \$opts{B},
'M!' => \$opts{M},
'T!' => \$opts{T},
'P!' => \$opts{P},
'author|a=s' => sub { $opts{author} = $_[1] },
'tag|t=s@' => sub { push @{$opts{tags}}, $_[1] },
'resume|r!' => sub { $opts{back} = 0 },
'back=i' => sub { $opts{back} = int($_[1]) },
'editor=s' => sub { $opts{editor} = $_[1] },
'stdin!' => sub { $opts{stdin} = 1 },
'append!' => sub { $opts{append} = 1 },
'select=i' => sub { $opts{select} = $_[1] },
'raw!' => sub { $opts{raw} = 1 },
'help|h!' => sub {
pod2usage
-exitval => 1,
-verbose => 2,
-input => App::PFT::help_of 'edit',
},
) or exit 1;
$opts{B} = 1 if !$opts{M} &&
grep defined, $opts{back}, map $datespec{$_}, qw(y m d);
do {
my @sel = grep $opts{$_}, qw(B M T P);
if (@sel != 1) {
local $, = ' -';
say STDERR 'Select exactly one mode: -B -M -T -P';
exit 2
}
};
my $tree = eval{ PFT::Tree->new } || do {
say STDERR $@ =~ s/ at.*$//rs;
exit 3
};
my $conf = eval{ $tree->conf } || do {
say STDERR 'Configuration error: ', $@ =~ s/ at.*$//rs;
exit 4
};
my($entry, $hdr);
# The following block defines $entry as the entry we are going to edit.
# In some of the cases also $hdr will be defined with the corresponding header.
eval {
if (defined $opts{back}) {
my @entries;
if (keys %datespec) {
my $date = PFT::Date->from_spec(%datespec);
@entries = $tree->content->blog_at($date);
die 'none for the specified date ', $date unless @entries;
}
else {
@entries = $tree->content->blog_back($opts{back});
die "cannot go back $opts{back} days" unless @entries;
}
if (@entries == 1) {
$entry = $entries[0];
}
elsif (exists $opts{select}) {
$entry = $entries[$opts{select}];
die 'invalid index ', $opts{select} unless defined $entry;
}
else {
say STDERR 'Multiple entries:';
for (my $idx = 0; $idx < @entries; $idx ++) {
my $hdr = $entries[$idx]->header;
say STDERR sprintf("%d: %s",
$idx,
$hdr ? $hdr->title : $_->name
)
}
die 'disambiguate by providing --select=<index>'
}
$hdr = eval{ $entry->header }; # Might be malformed.
} elsif ($opts{T}) {
die 'mandatory title' unless @ARGV;
$hdr = PFT::Header->new(
title => join(' ', @ARGV),
author => $conf->{site}{author},
);
$entry = $tree->content->new_tag($hdr)
} else {
if ($opts{M}) {
$hdr = PFT::Header->new(
author => $conf->{site}{author},
date => PFT::Date->from_spec(%datespec)->derive(d => undef),
)
} elsif ($opts{B}) {
$hdr = PFT::Header->new(
title => join(' ', @ARGV) || 'Today',
author => $conf->{site}{author},
tags => $opts{tags} || [],
date => eval{ PFT::Date->from_spec(%datespec) } || do {
say STDERR 'Invalid date: ', $@ =~ s/ at.*$//rs;
},
)
} elsif ($opts{P}) {
die 'mandatory title' unless @ARGV;
$hdr = PFT::Header->new(
title => join(' ', @ARGV),
author => $conf->{site}{author},
tags => $opts{tags} || [],
)
} else { die "unhandled case? This is a bug" }
$entry = $tree->content->new_entry($hdr)
}
1; # can be 1 only if there was no error.
}
or $@ && do {
say STDERR 'Editing entry: ', $@ =~ s/at .*$//rs;
exit 6
};
sub edit_file {
my $path = $entry->path;
my $editor = $opts{editor}
|| $conf->{system}{editor}
|| $ENV{EDITOR}
|| do {
say STDERR "Cannot infer editor. Try setting env EDITOR or to";
say STDERR "define it in configuration file (system -> editor)";
exit 5
};
if ($editor =~ s/(?<!%)%s/$path/g) {
system($editor)
}
else {
system($editor, $path)
}
}
sub feed_file {
my $mode = '>';
my $skip_header = $opts{raw} || !defined $hdr;
if ($opts{stdin}) {
die "Supported --stdin or --append, not both" if $opts{append};
}
elsif ($opts{append}) {
if (-f $entry->path) {
$mode .= '>';
$skip_header = 1;
}
}
open my $out, "$mode:encoding(locale)", $entry->path
or die 'Cannot open ', $entry->path, ": $!";
$hdr->dump($out) unless $skip_header;
print $out <STDIN>;
close $out;
}
eval {
if ($opts{stdin} or $opts{append}) {
feed_file
}
else {
edit_file
}
if ($entry->exists) {
if ($entry->void) {
say STDERR "Removing empty entry at ", $entry->path;
$entry->unlink;
}
else {
$entry->make_consistent;
}
}
} or $@ && do {
say STDERR "After editing: ", $@ =~ s/at .*$//sr;
exit 7
}
( run in 0.352 second using v1.01-cache-2.11-cpan-e93a5daba3e )