\n" . $note_para . "\n\n"; } elsif ($note_para =~ /^[*\#]+\s/) { # E.g., "# ..." or "* ..." # The paragraph represents a bulleted or numbered list; we # convert each list item to a single line and process the whole # list using Textile. $note_para =~ s/\n([^*\#])/ $1/g; $note_html .= $textile->process($note_para) . "\n" } else { # The paragraph represents a normal block of text; we convert # the paragraph to a single line and process the line using # Textile to produce HTML enclosed in
...
tags. $note_para =~ s/\n/ /g; $note_html .= "\n" . $textile->process($note_para) . "\n"; } } # Fix up popup notes to open links in new windows, for those links # that would typically be displayed by the browser in the current window. $note_html =~ s///ig if $do_popups; return $note_html; } # Print a code line with references if any, possibly folded and/or numbered. sub print_line { my ($ofh, $line, $line_num, $fold, $pending_ref, $current_ref) = @_; # We assume that $line is a single newline-terminated line with no tabs, # backspaces, or other control characters, and no multi-byte characters. # This is a valid assumption in the context of this program. chomp $line; # don't count newline when folding # Build the string of note references, and keep track of its length # as it will be displayedi, so we can fold if necessary. my $ref_str = ""; my $ref_str_len = 0; if ($pending_ref) { $ref_str = " \#"; $ref_str_len += 1; while ($pending_ref <= $current_ref) { # See how long reference will display, and if we are folding # start a new line if necessary. $ref_str_len += length($pending_ref) + 3; # ' [nn]' if ($fold && $ref_col + $ref_str_len - 1 > $fold) { $ref_str .= "\n" . ' ' x ($ref_col - 1) . "\#"; $ref_str_len = length($pending_ref) + 4; # reset } # Add links (of the proper type) pointing to the notes, # with title and note number interpolated as global variables. $link_title = shift @pending_titles; $link_note_num = $pending_ref; $ref_str .= " [" . interpolate($template{$do_popups ? 'popup_link' : 'footnote_link'}) . "]"; $pending_ref++; } } # Keep track of the length of the last line we will display for this code # line so we can properly compute where to put the note references. my $last_line_len = length($line); # If folding is requested, do it, breaking on spaces where possible. if ($fold) { my $folded_line = ""; while (length($line) > $fold) { my $last_space = rindex(substr($line,0,$fold), ' '); if ($last_space < 0) { # no space prior to fold point $folded_line .= substr($line, 0, $fold) . "\n"; $line = substr($line, $fold); } else { $folded_line .= substr($line, 0, $last_space) . "\n"; $line = substr($line, $last_space+1); } } $folded_line .= $line; # what's left over after folding $last_line_len = length($line); $line = $folded_line; } # Replace HTML special characters with character entities. # Note: This must be done *before* adding the note reference links. $line = escape_html_specials($line); # Add any references to the last line displayed if there's room, # otherwise if we're folding display another line with just the references. # Note that $ref_col is the column in which we wish to start the comment # containing the references (i.e., the '#' character). However we want # to separate the comment by at least two spaces from the code itself; # these extra spaces are already included in $ref_str. if ($ref_str) { if ($fold && $last_line_len >= $ref_col-2) { $line .= "\n"; # start new line just for references $last_line_len = 0; } my $padding = $last_line_len >= $ref_col-2 ? 0 : $ref_col - $last_line_len - 3; $line .= " " while ($padding--); $line .= $ref_str; } # Add line numbers if requested. if ($line_num) { my $line_num_str = sprintf("%5d", $line_num); $line =~ s/^/ /gm; # put in enough space for line number $line =~ s/^ {5}/$line_num_str/; } print {$ofh} $line . "\n"; } # Create a note link title given a note (in HTML form). sub link_title { my ($note) = @_; my $link_title = ""; # Look for the first non-blank line, strip HTML tags out, and then # return up to the first 10 words. foreach $link_title (split "\n", $note) { if ($link_title) { $link_title =~ s/<[^>]*>//g; $link_title =~ s/^((?:\S+\s){10}).*$/$1.../; return $link_title; } } return ""; } # Make sure string is suitable for HTML output by replacing special # characters like '&' with the corresponding HTML character entities.. sub escape_html_specials { my ($string) = @_; my %character_entities = ( # Character entities for HTML specials '<' => '<', '>' => '>', '&' => '&', '"' => '"', ); my $specials_re = # alteration regexp for HTML specials join '|', keys %character_entities; $string =~ s/($specials_re)/$character_entities{$1}/g; return $string; } # Make sure string is suitable for a JavaScript string literal. sub escape_string { my ($string) = @_; # Escape any quote and backslash characters in the string. # (Since the string may be used in JavaScript delimited with either # a single quote or a double quote, make sure we escape both.) $string =~ s/(\\|\'|\")/\\$1/g; # Escape any newlines. $string =~ s/\n/\\n/g; # Escape '/' in '' to prevent HTML 4.01 validation problems. $string =~ s!!<\\/!g; return $string; } # Interpolate the values of Perl variables into a string. # (Note that the variables must either be global or lexical with file scope. # Also note that this recognizes only scalar variables of the form $foo.)) sub interpolate { my ($string) = @_; $string =~ s/(\$\w+)/$1/gee; return $string; } __DATA__ html_begin \n\n\n\n\n code_end\n js_begin js_popup \n popup_link $link_note_num footnote_link $link_note_num footnote_header \n
$foo + 2
).
## A text paragraph is concluded with a "blank" comment as follows
## (or by a code line).
##
## You can also include preformatted text to refer to one or more
## lines of Perl code (or other content intended to be included
## verbatim) as part of the inline note; as with Pod, preformatted
## text is marked by indenting it more than a regular text paragraph.
##
## $str =~ s/($escape_re)/$escape{$1}/g;
##
## You can include URLs in the preformatted text and they will be
## automatically converted to links; for example, see
##
## http://www.example.com/an-example.html
## ftp://ftp.example.com/pub/foo.tar.gz
##
## You can also include HTML links in regular text paragraphs,
## either by using the standard HTML tag or by using the
## Textile syntax "text of link":http://www.example.com/foo.html.
##
## You can include bulleted lists or numbered lists using
## the standard Textile markup conventions:
##
## * Bulleted list items start with '*'.
## * Don't indent them, or they'll be taken as preformatted text!
## ** You can have sublists...
## *** ...or even sub-sublists
##
## # Mark numbered list items with an initial '#'.
## # Textile will add numbers automatically.
##
## h3. A Final Note
##
## Last but not least, you can use "h3.", "h4.", etc., to provide
## a header for the beginning of an inline note and subheaders
## within it.
The inline notes do not appear as part of the Perl code in the
generated HTML. Instead each code line with an inline note (or notes)
preceding it is displayed with a righthand Perl comment including note
references in the form '[123]'; the note number is either an internal
link pointing to a footnote at the end of the document, or a link to
display a popup window containing the note.
The generated HTML document and the popup note windows contain only
standard HTML, and should properly validate unless you've included
non-standard HTML markup in your inline notes. In particular, the
main HTML document should validate as HTML 4.01 Strict, while the
popup notes should validate as HTML 4.01 Transitional. (In popup notes
we use the C