Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

podwatch: POD previewing tool

by adrianh (Chancellor)
on Jan 17, 2003 at 23:21 UTC ( #227856=sourcecode: print w/ replies, xml ) Need Help??

Category: Utility Scripts
Author/Contact Info Adrian Howard
/msg adrianh
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();
};

Comment on podwatch: POD previewing tool
Download Code
Re: podwatch: POD previewing tool
by castaway (Parson) on Jan 18, 2003 at 13:53 UTC
    Very nice :)
    Can I suggest a
    ReadMode 0;
    in the quit sub? It messes up my terminal else..
    C.
      Good point. Fixed. Thanks.

Back to Code Catacombs

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://227856]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2015-07-04 00:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (57 votes), past polls