#!/usr/local/bin/perl # Perl/Tk version of pretty # Julius C. Duque # v1.1.1 2003 November 12 Wednesday # v1.2.0 2003 November 14 Friday - Added hyphenation # v1.3.0 2003 November 16 Sunday - Added hyphenation of overfull lines use diagnostics; use strict; use warnings; use Tk; use Tk::Balloon; use TeX::Hyphen; my $INDENT_DEF = 0; my $LWIDTH_DEF = 70; my $VERSION = "1.3.0"; my $TITLE = "Paragraph Adjuster $VERSION"; my $AUTHOR = "Julius C. Duque"; my $indent = $INDENT_DEF; my $newline = 1; my $hyphenate = 1; my $width = $LWIDTH_DEF; my ($BOTH, $LEFT, $RIGHT, $CENTERED) = (1, 2, 3, 4); my $format_choice = $BOTH; # both left- and right-justified my ($infile, $outfile) = (); my $hyp = new TeX::Hyphen; local $/ = ""; # paragraph mode my $mw = new MainWindow(); drawButtons(); Tk::MainLoop(); sub processfile { my $retval = 0; open INFILE, $infile; if (open OUTFILE, "> $outfile") { while () { my @linein = split; $retval = printpar(@linein); last if ($retval); print OUTFILE "\n" if ($newline); } close INFILE; close OUTFILE; } printMessage("info", "OK", "File was successfully saved.") if (!$retval); } sub printpar { my (@par) = @_; my $firstline = 0; while (@par) { $firstline++; my ($buffer, $word); my ($charcount, $wordlen) = (0, 0); my $linewidth = $width; if ($firstline == 1) { $linewidth -= $indent; print OUTFILE " " x $indent; } while (($charcount < $linewidth) and (@par)) { $word = shift @par; $buffer .= $word; $wordlen = length($word); $charcount += $wordlen; $buffer .= " "; $charcount++; } chop $buffer; $charcount--; if ($charcount == $wordlen) { $linewidth = $wordlen; my ($pos, $pre_word_len) = (0, 0); if ($hyphenate) { if ($word =~ /^([^a-zA-Z]*)([a-zA-Z-']+)([^a-zA-Z]*)$/) { my $pre_word = $1; $pre_word_len = length($pre_word); my $stripped_word = $2; $pos = hyphenate_word($stripped_word, $width); $pos = 0 if ($wordlen <= $width); } if ($pos) { $charcount = $pre_word_len + $pos; my $post_word = substr $word, $charcount; unshift(@par, $post_word); $buffer = substr $word, 0, $charcount; $buffer .= "-"; $charcount++; } } } my $lineout = $buffer; if ($charcount > $linewidth) { my ($pos, $pre_word_len) = (0, 0); if ($hyphenate) { if ($word =~ /^([^a-zA-Z]*)([a-zA-Z-']+)([^a-zA-Z]*)$/) { my $pre_word = $1; $pre_word_len = length($pre_word); my $stripped_word = $2; my $unfilled = $linewidth - $charcount + $wordlen - $pre_word_len + 1; $pos = hyphenate_word($stripped_word, $unfilled); } } $charcount -= $wordlen; if ($pos == 0) { $charcount--; unshift(@par, $word); } else { my $post_word = substr $word, ($pre_word_len + $pos); unshift(@par, $post_word); $charcount = $charcount + $pre_word_len + $pos; } $lineout = substr $buffer, 0, $charcount; if ($pos) { $lineout .= "-"; $charcount++; } } my $spaces_to_fill = $linewidth - $charcount; if ($format_choice == $CENTERED) { my $leftfill = int($spaces_to_fill/2); print OUTFILE " " x $leftfill; } elsif ($format_choice == $RIGHT) { print OUTFILE " " x $spaces_to_fill; } elsif ($format_choice == $BOTH) { my $tempbuf = $lineout; my $replacements_made = 0; if (@par) { my $reps = 1; while (length($tempbuf) < $linewidth) { last if ($tempbuf !~ /\s/); if ($tempbuf =~ /(\S+ {$reps})(\S+)/) { $tempbuf =~ s/(\S+ {$reps})(\S+)/$1 $2/; $replacements_made++; $tempbuf = reverse $tempbuf; } else { $reps++; } } } if ($replacements_made % 2 == 0) { $lineout = $tempbuf; } else { $lineout = reverse $tempbuf; } } print OUTFILE "$lineout\n"; } } sub hyphenate_word { my ($tword, $unfilled) = @_; my @hyphen_places = $hyp->hyphenate($tword); if (@hyphen_places) { @hyphen_places = reverse @hyphen_places; foreach my $places (@hyphen_places) { return $places if ($places < $unfilled - 1); } } return 0; } sub drawButtons { $mw->title($TITLE); # Status bar widget my $status = $mw->Label(-width => 70, -relief => "sunken", -anchor => "w")->pack(-side => "bottom", -padx => 1, -pady => 1, -fill => "x"); # Create balloon widget my $b = $mw->Balloon(-statusbar => $status); # Create menu bar frame my $menubar = $mw->Frame(-borderwidth => 4, -relief => "ridge")-> pack(-side => "top", -fill => "x"); # Create Open File button my $openfilebutton = $menubar-> Button(-text => "Open File", -relief => "raised", -width => 10, -command => [\&fileDialog, $mw, "open"])->pack(-side => "left"); $b->attach($openfilebutton, -msg => "Open a file to be reformatted"); # Create Save File button my $savefilebutton = $menubar-> Button(-text => "Save To File", -relief => "raised", -width => 10, -command => sub { if (defined $infile and $infile ne "") { fileDialog($mw, "save"); } else { printMessage("warning", "OK", "You must open a file to reformat first."); } })->pack(-side => "left"); $b->attach($savefilebutton, -msg => "Proceed with reformatting and save result to a file"); # Create About button my $aboutbutton = $menubar->Button(-text => "About", -relief => "raised", -width => 10, -command => [\&printMessage, "info", "OK", "A Perl/Tk script created by $AUTHOR"])->pack(-side => "left"); $b->attach($aboutbutton, -msg => "$TITLE created by $AUTHOR"); # Create Quit button my $quitbutton = $menubar->Button(-text => "Dismiss", -relief => "raised", -width => 10, -command => sub { exit })-> pack(-side => "right"); $b->attach($quitbutton, -msg => "Quit this Perl/Tk script"); my $both = $mw->Radiobutton(-variable => \$format_choice, -value => $BOTH, -text => "Both left- and right-justified")-> pack(-side => "top", -anchor => "w"); $b->attach($both, -msg => "Each line is left- and right-justified"); my $left = $mw->Radiobutton(-variable => \$format_choice, -value => $LEFT, -text => "Left-justified")->pack(-side => "top", -anchor => "w"); $b->attach($left, -msg => "Each line is left-justified, ragged-right"); my $right = $mw->Radiobutton(-variable => \$format_choice, -value => $RIGHT, -text => "Right-justified")->pack(-side => "top", -anchor => "w"); $b->attach($right, -msg => "Each line is right-justified, ragged-left"); my $centered = $mw->Radiobutton(-variable => \$format_choice, -value => $CENTERED, -text => "Centered")->pack(-side => "top", -anchor => "w"); $b->attach($centered, -msg => "Each line is equidistant from the left and right margins"); $both->select; # Set default to $both my $chknewline = $mw->Checkbutton(-variable => \$newline, -text => "Insert empty lines between paragraphs")-> pack(-side => "top", -anchor => "w"); $b->attach($chknewline, -msg => "Insert a blank line between two consecutive paragraphs"); $chknewline->select; # Set default to $newline my $chkhyphen = $mw->Checkbutton(-variable => \$hyphenate, -text => "Hyphenate")-> pack(-side => "top", -anchor => "w"); $b->attach($chkhyphen, -msg => "Hyphenate word that does not fit on a line"); $chknewline->select; # Set default to $hyphenate my $f = $mw->Frame->pack(-side => "left"); my $l = $f->Label(-text => "Indention: ", -justify => "left"); $b->attach($l, -msg => "Number of spaces at the start of every paragraph"); Tk::grid($l, -row => 0, -column => 0); my $tindent = $f->Entry(-width => 2, -textvariable => \$indent, -justify => "right"); $b->attach($tindent, -msg => "Number of spaces at the start of every paragraph"); Tk::grid($tindent, -row => 0, -column => 1); $l = $f->Label(-text => "characters (default: $INDENT_DEF) ", -justify => "left"); $b->attach($l, -msg => "Number of spaces at the beginning of each paragraph"); Tk::grid($l, -row => 0, -column => 2); $l = $f->Label(-text => "Line width: ", -justify => "left"); Tk::grid($l, -row => 1, -column => 0); $b->attach($l, -msg => "Maximum length of every line"); my $tlwidth = $f->Entry(-width => 2, -textvariable => \$width, -justify => "right"); $b->attach($tlwidth, -msg => "Maximum length of every line"); Tk::grid($tlwidth, -row => 1, -column => 1); $l = $f->Label(-text => "characters (default: $LWIDTH_DEF)", -justify => "left"); $b->attach($l, -msg => "Maximum length of every line"); Tk::grid($l, -row => 1, -column => 2); } sub printMessage { my ($icon, $type, $outputmsg) = @_; my $msg = $mw->messageBox(-icon => $icon, -type => $type, -title => $TITLE, -message => $outputmsg); } sub fileDialog { my ($w, $operation) = @_; my @types = (["Text files", [qw/.txt .doc/]], ["Text files", "", "TEXT"], ["All files", "*"] ); if ($operation eq "open") { $infile = $w->getOpenFile(-filetypes => \@types); } if ($operation eq "save") { $outfile = $w->getSaveFile(-filetypes => \@types, -initialfile => "Untitled", -defaultextension => ".txt"); processfile() if (defined $outfile and $outfile ne ""); } } =head1 NAME paradj-tk - a small Perl script that reformats lines of ASCII text so that the resulting lines are justified in any of the following formats: left-justified, right-justified, centered, or both left- and right-justified (default). =head1 README Paragraph Adjuster with Hyphenation (PAwH) is a small Perl script that reformats lines of ASCII text so that the resulting lines are justified in any of the following formats: left-justified, right-justified, centered, or both left- and right-justified (default). PAwH has various switches, most are optional, to control its output. The only mandatory switch is the line width. For PAwH to work properly, input paragraphs must be separated by blank lines. PAwH is also capable of hyphenating a word that cannot be accommodated on a line. =head1 DESCRIPTION Paragraph Adjuster with Hyphenation (PAwH) is a small Perl script that reformats lines of ASCII text so that the resulting lines are justified in any of the following formats: left-justified, right-justified, centered, or both left- and right-justified (default). PAwH has various switches, most are optional, to control its output. The only mandatory switch is the line width. For PAwH to work properly, input paragraphs must be separated by blank lines. PAwH is also capable of hyphenating a word that cannot be accommodated on a line. =head1 COMMAND-LINE VERSION This is a Perl/Tk version of the command-line paradj.pl. =head1 PREREQUISITE You need Jan Pazdziora's Perl module, TeX::Hyphen, available from the Comprehensive Perl Archive Network (CPAN), to use the hyphenation feature. The latest is version 0.140. For Windows users, you can install TeX::Hyphen by following these steps: 1. Uncompress the TeX::Hyphen module, TeX-Hyphen-0.140.tar.gz. 2. Descend (cd) into the TeX-Hyphen-0.140/lib and copy the TeX directory into \lib. For example, if your Perl binaries are installed on E:\Perl, copy the TeX directory into E:\Perl\lib. =head1 COPYRIGHT AND LICENSE Copyright (C) 2003 Julius C. Duque <{jcduque}{at}{lycos}{dot}{com}> This library is free software; you can redistribute it and/or modify it under the same terms as the GNU General Public License. =pod SCRIPT CATEGORIES CPAN/Administrative Fun/Educational =cut