Description: |
When I started writing POD documents I got bored with previewing things with perldoc. Every time I made an edit I had to start up perldoc again, find where I had made the change, only to discover it wasn't quite right. Repeat until done.
To make this a little easier I threw together podwatch. A (very basic) POD viewer that tracks changes to the source file. When the source changes podwatch reads it in again, and moves to the place where the output changed.
Now I edit POD in one window, with podwatch running in another. Instant feedback whenever I hit save.
Hope you find it useful. |
#! /usr/bin/perl
# podwatch FILE
#
# adrianh@quietstars.com
# 20020520
#
# Copyright 2002-2003 Adrian Howard, All Rights Reserved.
#
# This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.
#
# 20020522
# - now moves changed line to the top on refresh
# - refactored move_by out from command subs
# - added help
# 20030117
# - tided up formatting a bit
# - added beep
# 20030118
# - added ReadMode 0 on quit (thanks to castaway)
use strict;
use warnings;
use Term::ReadKey;
use Pod::Text;
use IO::String;
$|=1;
ReadMode 3;
my $Filename = $ARGV[-1];
my $Help = <<'END_HELP';
===================================
SUMMARY OF KEYS
return - forward one line
space - forward one page
b - back one page
g - go to first line in file
G - go to last line in file
/ - search
r - refresh page
q - quit
===================================
END_HELP
my $Status_line = "(%5d) $Filename - h:elp q:uit";
my $Line_num = 0;
my $Modification_time = -1;
my $Page_length = -1;
my $Column_num = -1;
my @Pod = ();
my $Search = '';
my %Command = (
"undef" => \&beep,
"\n" => \&next_line,
" " => \&next_page,
"b" => \&prev_page,
"g" => \&end,
"G" => \&top,
"/" => \&search,
"r" => \&refresh,
"h" => \&help,
"q" => \&quit,
);
while (1) {
refresh() if changed();
my $key = ReadKey 0.25;
next unless $key;
&{$Command{$key} || $Command{'undef'}};
};
###########
sub beep {
print "\a"
};
sub next_line { move_by(+1) };
sub next_page { move_by(+$Page_length) };
sub prev_page { move_by(-$Page_length) };
sub top { move_by(-$Line_num) };
sub end { move_by($#Pod) };
sub help {
clear_status();
print $Help;
print status_line();
};
sub search {
clear_status();
print "/";
ReadMode 0;
my $input = <STDIN>;
ReadMode 3;
chomp($input);
$Search = $input eq '' ? $Search : $input;
my $final_line_num = $Line_num;
foreach my $n ($Line_num+1 .. $#Pod) {
if (eval {$Pod[$n] =~ /$Search/}) {
$final_line_num = $n;
last;
};
};
beep() if $Line_num == $final_line_num;
inc_line($final_line_num-$Line_num);
show_page();
};
sub quit {
print "\n";
ReadMode 0;
exit(0);
};
###########
sub clear_status {
print "\r", " " x length(status_line()), "\r";
};
sub status_line {
return(substr(sprintf($Status_line, $Line_num+1), 0, $Column_num))
+;
};
sub last_line {
return($Line_num + $Page_length - 1);
};
sub print_line {
my $line_num = shift;
my $line = $Pod[$line_num];
$line = "" unless defined($line);
print "\r$line";
my $status_line = status_line();
my $overlap = length($status_line) - length($line);
print " " x $overlap if $overlap > 0;
print "\n", $status_line;
};
sub inc_line($) {
my $n = shift;
my $start_line = $Line_num;
$Line_num += $n;
if ($Line_num < 0) {
$Line_num = 0
} elsif ($Line_num > $#Pod){
$Line_num = $#Pod;
};
return($start_line != $Line_num);
}
sub show_page {
print_line($_) foreach ($Line_num..last_line());
};
sub move_by {
my $n = shift;
if ($n < 0 || $n >= $Page_length) {
show_page() if inc_line($n);
} else {
foreach (1..$n) {
return unless inc_line(1);
print_line( last_line() )
};
};
};
###########
sub modification_time {
my $filename = shift;
return( (stat $filename)[9] || die "$filename ($!)\n" );
};
sub page_size {
my ($cols, $rows) = GetTerminalSize *STDOUT{IO};
die "cannot determine terminal size" unless $cols && $rows;
return($cols, $rows-1);
};
sub changed {
my ($cols, $rows) = page_size();
return(
$Modification_time != modification_time($Filename)
|| $Page_length != $rows || $Column_num != $cols
);
};
sub fetch_pod {
my $filename = shift;
my $pod = IO::String->new;
open(POD, $filename) or die "$Filename ($!)\n";
Pod::Text->new(
width => ($Column_num > 76 ? 76 : $Column_num)
)->parse_from_filehandle(*POD{IO}, $pod);
close(POD);
return(${$pod->string_ref});
};
sub refresh {
($Column_num, $Page_length) = page_size();
$Modification_time = modification_time($Filename);
my @old_pod = @Pod;
@Pod = split(/\n/, fetch_pod($Filename));
LINE: foreach my $n (0..$#Pod) {
my ($line, $old_line) = ($Pod[$n], $old_pod[$n]);
unless (defined($old_line) && $line eq $old_line) {
$Line_num = $n if ($Line_num > $n || $n > last_line());
last LINE;
};
};
inc_line(0);
show_page();
beep();
};
|