texinfo-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[no subject]


From: Patrice Dumas
Date: Sun, 14 Apr 2024 13:39:45 -0400 (EDT)

branch: master
commit af3518537cc3dc58c62edd941097d3ad7d62348d
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Sun Apr 14 19:39:11 2024 +0200

    Add OutputUnits.pm.
    Change in comments.
---
 tp/Texinfo/OutputUnits.pm            | 950 +++++++++++++++++++++++++++++++++++
 tp/Texinfo/XS/convert/convert_html.c |   2 +-
 2 files changed, 951 insertions(+), 1 deletion(-)

diff --git a/tp/Texinfo/OutputUnits.pm b/tp/Texinfo/OutputUnits.pm
new file mode 100644
index 0000000000..3d588a3d78
--- /dev/null
+++ b/tp/Texinfo/OutputUnits.pm
@@ -0,0 +1,950 @@
+# OutputUnits.pm: setup and manage Texinfo document output units
+#
+# Copyright 2010-2024 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Original author: Patrice Dumas <pertusus@free.fr>
+
+package Texinfo::OutputUnits;
+
+use 5.00405;
+
+# See comment at start of HTML.pm
+use if $] >= 5.012, feature => 'unicode_strings';
+
+# stop \s from matching non-ASCII spaces, etc.  \p{...} can still be
+# used to match Unicode character classes.
+use if $] >= 5.014, re => '/a';
+
+use strict;
+
+# Can be used to check that there is no incorrect autovivfication
+# no autovivification qw(fetch delete exists store strict);
+
+use Carp qw(cluck confess);
+
+use Texinfo::StructTransfXS;
+
+use Texinfo::XSLoader;
+
+use Texinfo::Commands;
+use Texinfo::Common;
+use Texinfo::ManipulateTree;
+
+require Exporter;
+use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS);
+@ISA = qw(Exporter);
+
+%EXPORT_TAGS = ( 'all' => [ qw(
+  units_directions
+  units_file_directions
+  split_by_node
+  split_by_section
+  split_pages
+) ] );
+
+@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+$VERSION = '7.1dev';
+
+my $XS_structuring = Texinfo::XSLoader::XS_structuring_enabled();
+
+my %XS_overrides = (
+  "Texinfo::OutputUnits::rebuild_output_units"
+    => "Texinfo::StructTransfXS::rebuild_output_units",
+  "Texinfo::OutputUnits::_XS_unsplit"
+    => "Texinfo::StructTransfXS::unsplit",
+);
+
+# used in conversion only, and should only be loaded with XS converters
+my %XS_convert_overrides = (
+  # Not useful for HTML as functions, as the calling functions are
+  # already overriden
+  # Could be readded when other converters than HTML are done in C
+  #  "Texinfo::OutputUnits::split_by_node"
+  #    => "Texinfo::StructTransfXS::split_by_node");
+  #  "Texinfo::OutputUnits::split_by_section"
+  #    => "Texinfo::StructTransfXS::split_by_section");
+  #  "Texinfo::OutputUnits::split_pages"
+  #    => "Texinfo::StructTransfXS::split_pages"
+);
+
+our $module_loaded = 0;
+sub import {
+  if (!$module_loaded) {
+    if ($XS_structuring) {
+      for my $sub (keys %XS_overrides) {
+        Texinfo::XSLoader::override ($sub, $XS_overrides{$sub});
+      }
+    }
+    #if ($XS_convert) {
+    #  for my $sub (keys %XS_convert_overrides) {
+    #    Texinfo::XSLoader::override ($sub, $XS_convert_overrides{$sub});
+    #  }
+    #}
+    $module_loaded = 1;
+  }
+  # The usual import method
+  goto &Exporter::import;
+}
+
+# Return a list of output units.  Each output unit starts with a @node as its
+# first content (except possibly the first one).  It is important that this
+# function reassociates all the root commands such that the result does not
+# depend on the previous association (if any).
+sub split_by_node($)
+{
+  my $document = shift;
+  my $root = $document->tree();
+
+  my $output_units;
+
+  my $current = { 'unit_type' => 'unit' };
+  push @$output_units, $current;
+  my @pending_parts = ();
+  foreach my $content (@{$root->{'contents'}}) {
+    if ($content->{'cmdname'} and $content->{'cmdname'} eq 'part') {
+      push @pending_parts, $content;
+      next;
+    }
+    if ($content->{'cmdname'} and $content->{'cmdname'} eq 'node') {
+      if (not $current->{'unit_command'}) {
+        $current->{'unit_command'} = $content;
+      } else {
+        $current = { 'unit_type' => 'unit', 'unit_command' => $content,
+                    'tree_unit_directions' => {'prev' => $output_units->[-1]}};
+        $output_units->[-1]->{'tree_unit_directions'} = {}
+            if (! $output_units->[-1]->{'tree_unit_directions'});
+        $output_units->[-1]->{'tree_unit_directions'}->{'next'} = $current;
+        push @$output_units, $current;
+      }
+    }
+    if (@pending_parts) {
+      foreach my $part (@pending_parts) {
+        push @{$current->{'unit_contents'}}, $part;
+        $part->{'associated_unit'} = $current;
+      }
+      @pending_parts = ();
+    }
+    push @{$current->{'unit_contents'}}, $content;
+    #if (defined($content->{'associated_unit'})) {
+    #  print STDERR "Resetting node associated_unit for $content\n";
+    #}
+    $content->{'associated_unit'} = $current;
+  }
+  if (@pending_parts) {
+    foreach my $part (@pending_parts) {
+      push @{$current->{'unit_contents'}}, $part;
+      $part->{'associated_unit'} = $current;
+    }
+    @pending_parts = ();
+  }
+
+  return $output_units;
+}
+
+# Return a list of output units.  Each output unit starts with the @node
+# associated with a sectioning command or with the sectioning command if there
+# is no associated node.  It is important that this function reassociates all
+# the root commands such that the result does not depend on the previous
+# association (if any).
+sub split_by_section($)
+{
+  my $document = shift;
+  my $root = $document->tree();
+
+  my $output_units;
+
+  my $current = { 'unit_type' => 'unit' };
+  push @$output_units, $current;
+  foreach my $content (@{$root->{'contents'}}) {
+    my $new_section;
+    if ($content->{'cmdname'} and $content->{'cmdname'} eq 'node'
+        and $content->{'extra'}
+        and $content->{'extra'}->{'associated_section'}) {
+      $new_section = $content->{'extra'}->{'associated_section'};
+    } elsif ($content->{'cmdname'} and $content->{'cmdname'} eq 'part'
+             and $content->{'extra'}
+             and $content->{'extra'}->{'part_associated_section'}) {
+      $new_section = $content->{'extra'}->{'part_associated_section'};
+    } elsif ($content->{'cmdname'} and $content->{'cmdname'} ne 'node'
+             and $Texinfo::Commands::root_commands{$content->{'cmdname'}}) {
+      $new_section = $content;
+    }
+    if ($new_section) {
+      if (not defined($current->{'unit_command'})) {
+        $current->{'unit_command'} = $new_section;
+      } elsif ($new_section ne $current->{'unit_command'}) {
+        $current = { 'unit_type' => 'unit',
+                     'unit_command' => $new_section,
+                     'tree_unit_directions' => {'prev' => 
$output_units->[-1]}};
+        $output_units->[-1]->{'tree_unit_directions'} = {}
+            if (! $output_units->[-1]->{'tree_unit_directions'});
+        $output_units->[-1]->{'tree_unit_directions'}->{'next'} = $current;
+        push @$output_units, $current;
+      }
+    }
+    push @{$current->{'unit_contents'}}, $content;
+    #if ($content->{'associated_unit'}) {
+    #  print STDERR "Resetting section associated_unit for $content\n";
+    #}
+    $content->{'associated_unit'} = $current;
+  }
+  return $output_units;
+}
+
+sub _XS_unsplit($)
+{
+  my $document = shift;
+  return -3;
+}
+
+# remove the association with document units
+# NOTE not documented, but is internally used for tests only.
+# In the situation where unsplit is called, in the test suite, it is
+# always better to do it both for XS and perl.
+sub unsplit($)
+{
+  my $document = shift;
+
+  my $unsplit_needed = 0;
+  my $XS_unsplit_needed = _XS_unsplit($document);
+  if ($XS_unsplit_needed > 0) {
+    $unsplit_needed = 1;
+  }
+
+  my $root = $document->tree();
+  if (!$root->{'type'} or $root->{'type'} ne 'document_root'
+      or !$root->{'contents'}) {
+    return 0;
+  }
+  foreach my $content (@{$root->{'contents'}}) {
+    if ($content->{'associated_unit'}) {
+      delete $content->{'associated_unit'};
+      $unsplit_needed = 1;
+    }
+  }
+  return $unsplit_needed;
+}
+
+# does nothing in perl, the XS version reexports the output units
+sub rebuild_output_units($)
+{
+  my $output_units = shift;
+}
+
+# Associate top-level units with pages according to the splitting
+# specification.  Set 'first_in_page' on each unit to the unit
+# that is the first in the output page.
+sub split_pages($$)
+{
+  my $output_units = shift;
+  my $split = shift;
+
+  return undef if (!$output_units or !scalar(@$output_units));
+
+  my $split_level;
+  if (!$split) {
+    foreach my $output_unit (@$output_units) {
+      $output_unit->{'first_in_page'} = $output_units->[0];
+    }
+    return;
+  } elsif ($split eq 'chapter') {
+    $split_level = 1;
+  } elsif ($split eq 'section') {
+    $split_level = 2;
+  } elsif ($split ne 'node') {
+    warn "Unknown split specification: $split\n";
+  }
+
+  my $current_first_in_page;
+  foreach my $output_unit (@$output_units) {
+    my $level;
+    my $section = _output_unit_section($output_unit);
+    if (defined($section)) {
+      $level = $section->{'extra'}->{'section_level'};
+    }
+    #print STDERR "level($split_level) $level "
+    #       .output_unit_texi($output_unit)."\n";
+    if (!defined($split_level) or (defined($level) and $split_level >= $level)
+        or !$current_first_in_page) {
+      $current_first_in_page = $output_unit;
+    }
+    $output_unit->{'first_in_page'} = $current_first_in_page;
+  }
+}
+
+# Returns something associated to a label that can be used to setup a target
+# to the label.  If the target is an external node, create the output unit 
here,
+# if it is a node return the output unit that is supposed to be the
+# target for links to the node.  Otherwise there is no such element (yet),
+# for floats and anchor, return undef.
+sub _label_target_unit_element($)
+{
+  my $label = shift;
+  if ($label->{'extra'} and $label->{'extra'}->{'manual_content'}) {
+    # setup an output_unit for consistency with regular output units
+    my $external_node_unit = { 'unit_type' => 'external_node_unit',
+                               'unit_command' => $label };
+    return $external_node_unit;
+  } elsif ($label->{'cmdname'} and $label->{'cmdname'} eq 'node') {
+    return $label->{'associated_unit'};
+  } else {
+    # case of a @float or an @anchor, no target element defined at this stage
+    return undef;
+  }
+}
+
+sub _output_unit_section($)
+{
+  my $output_unit = shift;
+  if (not defined($output_unit->{'unit_command'})) {
+    return undef;
+  }
+  my $element = $output_unit->{'unit_command'};
+  if ($element->{'cmdname'} eq 'node') {
+    if ($element->{'extra'}
+        and $element->{'extra'}->{'associated_section'}) {
+      return $element->{'extra'}->{'associated_section'};
+    } else {
+      return undef;
+    }
+  } else {
+    return $element;
+  }
+}
+
+sub _output_unit_node($)
+{
+  my $output_unit = shift;
+  if (not defined($output_unit->{'unit_command'})) {
+    return undef;
+  }
+  my $element = $output_unit->{'unit_command'};
+  if ($element->{'cmdname'} eq 'node') {
+    return $element;
+  } else {
+    if ($element->{'extra'}
+        and $element->{'extra'}->{'associated_node'}) {
+      return $element->{'extra'}->{'associated_node'}
+    } else {
+      return undef;
+    }
+  }
+}
+
+# Do output units directions (like in texi2html) and store them
+# in 'directions'.
+# The directions are only created if pointing to other output units.
+sub units_directions($$$)
+{
+  my $customization_information = shift;
+  my $identifier_target = shift;
+  my $output_units = shift;
+  return if (!$output_units or !@$output_units);
+
+  my $node_top = $identifier_target->{'Top'};
+  foreach my $output_unit (@$output_units) {
+    my $directions = {};
+    $directions->{'This'} = $output_unit;
+    $directions->{'Forward'} = $output_unit->{'tree_unit_directions'}->{'next'}
+      if ($output_unit->{'tree_unit_directions'}
+          and $output_unit->{'tree_unit_directions'}->{'next'}
+          and defined($output_unit->{'tree_unit_directions'}->{'next'}
+                                                               ->{'unit_type'})
+          and $output_unit->{'tree_unit_directions'}->{'next'}
+                                                  ->{'unit_type'} eq 'unit');
+    $directions->{'Back'} = $output_unit->{'tree_unit_directions'}->{'prev'}
+      if ($output_unit->{'tree_unit_directions'}
+          and $output_unit->{'tree_unit_directions'}->{'prev'}
+          and defined($output_unit->{'tree_unit_directions'}->{'prev'}
+                                                               ->{'unit_type'})
+          and $output_unit->{'tree_unit_directions'}->{'prev'}
+                                                     ->{'unit_type'} eq 
'unit');
+    my $node = _output_unit_node($output_unit);
+    if (defined($node)) {
+      foreach my $direction(['NodeUp', 'up'], ['NodeNext', 'next'],
+                            ['NodePrev', 'prev']) {
+        $directions->{$direction->[0]}
+           = _label_target_unit_element(
+               $node->{'extra'}->{'node_directions'}->{$direction->[1]})
+            if ($node->{'extra'}->{'node_directions'}
+                and $node->{'extra'}->{'node_directions'}->{$direction->[1]});
+      }
+      # Now do NodeForward which is something like the following node.
+      my $associated_section;
+      my $automatic_directions
+        = (not ($node->{'args'} and scalar(@{$node->{'args'}}) > 1));
+      if ($automatic_directions and $node->{'extra'}
+          and $node->{'extra'}->{'associated_section'}) {
+        $associated_section = $node->{'extra'}->{'associated_section'};
+      }
+      my $menu_child = Texinfo::ManipulateTree::first_menu_node($node,
+                                                    $identifier_target);
+      if ($menu_child) {
+        $directions->{'NodeForward'}
+          = _label_target_unit_element($menu_child);
+      } elsif ($associated_section
+               and $associated_section->{'extra'}->{'section_childs'}
+               and $associated_section->{'extra'}->{'section_childs'}->[0]) {
+        $directions->{'NodeForward'}
+          = $associated_section->{'extra'}
+                  ->{'section_childs'}->[0]->{'associated_unit'};
+      } elsif ($node->{'extra'}->{'node_directions'}
+               and $node->{'extra'}->{'node_directions'}->{'next'}) {
+        $directions->{'NodeForward'}
+            = _label_target_unit_element(
+                  $node->{'extra'}->{'node_directions'}->{'next'});
+      } elsif ($node->{'extra'}->{'node_directions'}
+               and $node->{'extra'}->{'node_directions'}->{'up'}) {
+        my $up = $node->{'extra'}->{'node_directions'}->{'up'};
+        my @up_list = ($node);
+        # the condition with the up_list avoids infinite loops
+        # the last condition stops when the Top node is reached.
+        while (not (grep {$up eq $_} @up_list
+                    or ($node_top and $up eq $node_top))) {
+          if ($up->{'extra'}->{'node_directions'}
+              and defined($up->{'extra'}->{'node_directions'}->{'next'})) {
+            $directions->{'NodeForward'}
+              = _label_target_unit_element(
+                           $up->{'extra'}->{'node_directions'}->{'next'});
+            last;
+          }
+          push @up_list, $up;
+          last if (not $up->{'extra'}->{'node_directions'}
+                   or not $up->{'extra'}->{'node_directions'}->{'up'});
+          $up = $up->{'extra'}->{'node_directions'}->{'up'};
+        }
+      }
+
+      if ($directions->{'NodeForward'}
+          and $directions->{'NodeForward'}->{'unit_type'} eq 'unit'
+          and (!$directions->{'NodeForward'}->{'directions'}
+               or !$directions->{'NodeForward'}->{'directions'}
+                                                  ->{'NodeBack'})) {
+        $directions->{'NodeForward'}->{'directions'} = {}
+            if (! $directions->{'NodeForward'}->{'directions'});
+        $directions->{'NodeForward'}->{'directions'}
+                                       ->{'NodeBack'} = $output_unit;
+      }
+    }
+    my $section = _output_unit_section($output_unit);
+    if (not defined($section)) {
+      # If there is no associated section, find the previous element section.
+      # Use the FastForward of this element.
+      # Use it as FastBack if the section is top level, or use the FastBack.
+      my $section_output_unit;
+      my $current_unit = $output_unit;
+      while ($current_unit->{'tree_unit_directions'}
+             and $current_unit->{'tree_unit_directions'}->{'prev'}) {
+        $current_unit = $current_unit->{'tree_unit_directions'}->{'prev'};
+        $section = _output_unit_section($current_unit);
+        if (defined($section)) {
+          $section_output_unit = $current_unit;
+          last;
+        }
+      }
+      if ($section_output_unit) {
+        if ($section_output_unit->{'directions'}->{'FastForward'}) {
+          $directions->{'FastForward'}
+            = $section_output_unit->{'directions'}->{'FastForward'};
+        }
+        if ($section->{'extra'}->{'section_level'} <= 1) {
+          $directions->{'FastBack'} = $section_output_unit;
+        } elsif ($section_output_unit->{'directions'}->{'FastBack'}) {
+          $directions->{'FastBack'}
+            = $section_output_unit->{'directions'}->{'FastBack'};
+        }
+      }
+    } else {
+      foreach my $direction(['Up', 'up'], ['Next', 'next'],
+                            ['Prev', 'prev']) {
+        # in most cases $section->{'extra'}->{'section_directions'}
+        #          ->{$direction->[1]}
+        #                 ->{'associated_unit'} is defined
+        # but it may not be the case for the up of @top.
+        # The section may be its own up in cases like
+        #  @part part
+        #  @chapter chapter
+        # in that cas the direction is not set up
+        $directions->{$direction->[0]}
+         = $section->{'extra'}->{'section_directions'}->{$direction->[1]}
+             ->{'associated_unit'}
+          if ($section->{'extra'}->{'section_directions'}
+           and $section->{'extra'}->{'section_directions'}->{$direction->[1]}
+           and $section->{'extra'}->{'section_directions'}->{$direction->[1]}
+                                           ->{'associated_unit'}
+           and (!$section->{'associated_unit'}
+                or 
$section->{'extra'}->{'section_directions'}->{$direction->[1]}
+                    ->{'associated_unit'}
+                       ne $section->{'associated_unit'}));
+      }
+
+      # fastforward is the next element on same level than the upper parent
+      # element.
+      my $up = $section;
+      while ($up->{'extra'}->{'section_level'} > 1
+             and $up->{'extra'}->{'section_directions'}
+             and $up->{'extra'}->{'section_directions'}->{'up'}) {
+        $up = $up->{'extra'}->{'section_directions'}->{'up'};
+      }
+
+      if ($up->{'extra'}->{'section_level'} < 1
+          and $up->{'cmdname'} and $up->{'cmdname'} eq 'top'
+          and $up->{'extra'}->{'section_childs'}
+          and @{$up->{'extra'}->{'section_childs'}}) {
+        $directions->{'FastForward'}
+           = $up->{'extra'}->{'section_childs'}->[0]->{'associated_unit'};
+      } elsif ($up->{'extra'}->{'toplevel_directions'}
+               and $up->{'extra'}->{'toplevel_directions'}->{'next'}) {
+        $directions->{'FastForward'}
+          = $up->{'extra'}->{'toplevel_directions'}->{'next'}
+                                 ->{'associated_unit'};
+      } elsif ($up->{'extra'}->{'section_directions'}
+               and $up->{'extra'}->{'section_directions'}->{'next'}) {
+        $directions->{'FastForward'}
+          = $up->{'extra'}->{'section_directions'}->{'next'}
+                              ->{'associated_unit'};
+      }
+      # if the element isn't at the highest level, fastback is the
+      # highest parent element
+      if ($up and $up ne $section
+          and $up->{'associated_unit'}) {
+        $directions->{'FastBack'} = $up->{'associated_unit'};
+      } elsif ($section->{'extra'}->{'section_level'} <= 1
+               and $directions->{'FastForward'}) {
+        # the element is a top level element, we adjust the next
+        # toplevel element fastback
+        $directions->{'FastForward'}->{'directions'} = {}
+           if (! $directions->{'FastForward'}->{'directions'});
+        $directions->{'FastForward'}->{'directions'}->{'FastBack'}
+          = $output_unit;
+      }
+    }
+    if ($output_unit->{'directions'}) {
+      %{$output_unit->{'directions'}}
+        = (%{$output_unit->{'directions'}}, %$directions);
+    } else {
+      $output_unit->{'directions'} = $directions;
+    }
+  }
+  if ($customization_information->get_conf('DEBUG')) {
+    foreach my $output_unit (@$output_units) {
+      print STDERR 'Directions'
+       # uncomment to show the perl object name
+       #  . "($output_unit)"
+         . ': '.print_output_unit_directions($output_unit)."\n";
+    }
+  }
+}
+
+sub units_file_directions($)
+{
+  my $output_units = shift;
+  return if (!$output_units or !@$output_units);
+
+  my $current_filename;
+  my $first_unit_in_file;
+  # need to gather the directions before the FirstInFile* directions
+  # are added to the first element in the file.
+  my @first_unit_in_file_directions;
+  foreach my $output_unit (@$output_units) {
+    if (defined($output_unit->{'unit_filename'})) {
+      my $filename = $output_unit->{'unit_filename'};
+      my $current_output_unit = $output_unit;
+      if (not defined($current_filename)
+          or $filename ne $current_filename) {
+        $first_unit_in_file = $output_unit;
+        @first_unit_in_file_directions
+            = keys %{$output_unit->{'directions'}};
+        $current_filename = $filename;
+      }
+      while ($current_output_unit->{'tree_unit_directions'}
+             and $current_output_unit->{'tree_unit_directions'}->{'prev'}) {
+        $current_output_unit
+          = $current_output_unit->{'tree_unit_directions'}->{'prev'};
+        if (defined($current_output_unit->{'unit_filename'})) {
+          if ($current_output_unit->{'unit_filename'} ne $filename) {
+            $output_unit->{'directions'}->{'PrevFile'}
+                 = $current_output_unit;
+            last;
+          }
+        } else {
+          last;
+        }
+      }
+      $current_output_unit = $output_unit;
+      while ($current_output_unit->{'tree_unit_directions'}
+             and $current_output_unit->{'tree_unit_directions'}->{'next'}) {
+        $current_output_unit
+          = $current_output_unit->{'tree_unit_directions'}->{'next'};
+        if (defined($current_output_unit->{'unit_filename'})) {
+          if ($current_output_unit->{'unit_filename'} ne $filename) {
+            $output_unit->{'directions'}->{'NextFile'}
+               = $current_output_unit;
+            last;
+          }
+        } else {
+          last;
+        }
+      }
+    }
+    # set the directions of the first elements in file, to
+    # be used in footers for example
+    if (defined($first_unit_in_file)) {
+      foreach my $first_in_file_direction
+                (@first_unit_in_file_directions) {
+        $output_unit->{'directions'}
+                                ->{'FirstInFile'.$first_in_file_direction}
+          = $first_unit_in_file->{'directions'}
+                                         ->{$first_in_file_direction};
+      }
+    }
+  }
+}
+
+# used in debug messages
+sub output_unit_texi($)
+{
+  my $output_unit = shift;
+  if (!$output_unit) {
+    return "UNDEF OUTPUT UNIT";
+  }
+  if (!defined($output_unit->{'unit_type'})) {
+    # show the output_unit as element, as a possible bug is that
+    # an element was passed in argument instead of an output unit
+    return "unit $output_unit without type: ".
+       Texinfo::Common::debug_print_element_details($output_unit, 1)
+      .' '.Texinfo::Common::debug_print_output_unit($output_unit);
+  }
+
+  my $unit_command = $output_unit->{'unit_command'};
+
+  if ($output_unit->{'unit_type'} eq 'external_node_unit') {
+    return Texinfo::Convert::Texinfo::convert_to_texinfo(
+                            {'contents' => $unit_command->{'contents'}});
+  } elsif ($output_unit->{'unit_type'} eq 'special_unit') {
+    return "_SPECIAL_UNIT: $output_unit->{'special_unit_variety'}";
+  }
+
+  if (!$unit_command) {
+    # happens when there are only nodes and sections are used as elements
+    return "No associated command (type $output_unit->{'unit_type'})";
+  }
+  return Texinfo::Convert::Texinfo::root_heading_command_to_texinfo(
+                                                          $unit_command);
+}
+
+# Should be in the same order as relative_unit_direction_name
+# in main/output_unit.c
+my @relative_directions_order = ('This', 'Forward', 'Back', 'FastForward',
+ 'FastBack', 'Next', 'Prev', 'Up', 'SectionNext', 'SectionPrev',
+ 'SectionUp', 'NodeNext', 'NodePrev', 'NodeUp', 'NodeForward', 'NodeBack');
+my @file_directions_order = ('PrevFile', 'NextFile');
+my @all_directions_order
+    = (@relative_directions_order, @file_directions_order,
+       map {'FirstInFile'.$_} @relative_directions_order);
+
+# Used for debugging and in test suite, but not generally useful. Not
+# documented in pod section and not exportable as it should not, in
+# general, be used.
+sub print_output_unit_directions($)
+{
+  my $output_unit = shift;
+  my $result = 'output unit: '.output_unit_texi($output_unit)."\n";
+
+  if ($output_unit->{'directions'}) {
+    #foreach my $direction (sort(keys(%{$output_unit->{'directions'}}))) {
+    foreach my $direction (@all_directions_order) {
+      if (defined($output_unit->{'directions'}->{$direction})) {
+        $result .= "  $direction: ".
+         output_unit_texi($output_unit->{'directions'}->{$direction})."\n";
+      }
+    }
+  } else {
+    $result .= "  NO DIRECTION\n";
+  }
+  return $result;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Texinfo::OutputUnits - setup and manage Texinfo document output units
+
+=head1 SYNOPSIS
+
+  use Texinfo::OutputUnits qw(split_by_node split_by_section split_pages
+    units_directions units_file_directions);
+
+  # $document is a parsed Texinfo::Document document.
+  # When customization variables information is needed, it is obtained
+  # from the $document by calling the get_conf() method.
+  my $identifier_target = $document->labels_information();
+  my $output_units;
+  if ($split_at_nodes) {
+    $output_units = split_by_node($document);
+  } else {
+    $output_units = split_by_section($document);
+  }
+  split_pages($output_units, $split);
+  units_directions($document, $identifier_target, $output_units);
+  units_file_directions($output_units);
+
+=head1 NOTES
+
+The Texinfo Perl module main purpose is to be used in C<texi2any> to convert
+Texinfo to other formats.  There is no promise of API stability.
+
+=head1 DESCRIPTION
+
+You can convert a Texinfo parsed document to an output format in a Converter
+code by first splitting the nodes and sectioning commands in units and then
+converting those units.  We will call the main unit of output documents an
+I<output unit>.  Usually a node is associated with a following sectioning
+command, while a sectioning command is associated with a previous node; they
+both together make up the output unit.  Either the node or the sectioning
+command is considered to be the main element component.
+
+The module provides methods to setup output units associated with
+node and sectioning commands of a Texinfo parsed document. With
+C<split_by_node> nodes are used as the main component for the separation of
+output units, while with C<split_by_section> the sectioning command elements
+are used to separate output units.  The first mode is typical of Info format,
+while the second corresponds better to a traditional book.  Note that the
+result is different when there are unassociated sectioning commands or nodes,
+in the usual case of each node being associated with a sectioning command and
+each sectioning command being associated with a node, splitting by node or by
+section does not make much difference as each output unit will consist of the
+node and the associated section in both cases.
+
+Output units are used for conversion to HTML and Info output formats.  See
+L<< 
C<Texinfo::Convert::Converter::convert_output_unit>|Texinfo::Convert::Converter/$result
 = $converter->convert_output_unit($output_unit) >>
+for more information on conversion of output units in Converters.  Output units
+are not relevant for all the formats, the Texinfo tree can also be converted
+directly, see L<< 
C<Texinfo::Convert::Converter::output_tree>|Texinfo::Convert::Converter/$result 
= $converter->output_tree($document) >>.
+
+The output units may be further associated in I<pages>, which are not pages as
+in book pages, but more like web pages, and hold series of output units.
+The output units may have directions to other output units prepared
+by C<units_directions>.  C<units_file_directions> should also
+set direction related to files, provided files are associated with
+output units by the user.
+
+=head1 METHODS
+
+No method is exported in the default case.
+
+=head2 Output units creation
+
+Output units are hash references created with the following keys:
+
+=over
+
+=item C<type>
+
+The type of the output unit.  Set to C<unit> for output units associated
+with nodes and sectioning commands.
+
+=item C<unit_command>
+
+Main node or sectioning command associated with the output unit.
+
+=item C<unit_contents>
+
+This array reference holds all the nodes and sectioning commands Texinfo tree
+elements associated with the output unit (in order).  The Texinfo tree nodes
+and sectioning commands elements have an C<associated_unit> key set that points
+to the output unit.
+
+=item C<tree_unit_directions>
+
+Hash reference with I<next> and I<prev> pointing to the
+previous and the next output unit.
+
+=back
+
+Call one of the following methods to create output units and associate them
+with nodes and sectioning command Texinfo tree elements:
+
+=over
+
+=item $output_units = split_by_node($document)
+X<C<split_by_node>>
+
+Returns a reference array of output units where a node is associated to
+the following sectioning commands.  Sectioning commands without nodes
+are also with the previous node, while nodes without sectioning commands
+are alone in their output units.
+
+Each output unit I<unit_command> key points to the node command
+associated with the output unit.
+
+=item $output_units = split_by_section($document)
+X<C<split_by_section>>
+
+Similarly with C<split_by_node>, returns an array of output units.  This
+time, lone nodes are associated with the previous sections and lone
+sections makes up an output unit.
+
+Output units I<unit_command> keys point to the sectioning command associated
+with the output unit.
+
+=back
+
+=head2 Grouping output units in pages
+
+You can call C<split_pages> to group together output units:
+
+=over
+
+=item $pages = split_pages($output_units, $split)
+X<C<split_pages>>
+
+Add the I<first_in_page> key to each output unit in the array
+reference argument I<$output_units>, set to the first output unit in the group.
+
+The first output unit in the group is based on the value of I<$split>:
+
+=over
+
+=item chapter
+
+The output units are grouped at chapter or other toplevel sectioning commands.
+
+=item node
+
+Each output unit is on its own.
+
+=item section
+
+The output units are grouped at sectioning commands below chapter.
+
+=item value evaluating to false
+
+No splitting, all the output units are together.
+
+=back
+
+=back
+
+=head2 Setting output units directions
+
+You can call the following methods to set output units directions:
+
+=over
+
+=item units_directions($customization_information, $identifier_target, 
$output_units)
+X<C<units_directions>>
+
+Directions are set up for the output units in the array reference
+I<$output_units> given in argument. The corresponding hash is associated
+to the I<directions> key. In this hash, keys correspond to directions
+while values are output units.
+
+The following directions are set up:
+
+=over
+
+=item This
+
+The output unit itself.
+
+=item Forward
+
+Unit next.
+
+=item Back
+
+Previous output unit.
+
+=item NodeForward
+
+Following node output unit in reading order.  It is the next node unit, or the
+first in menu or the next of the up node.
+
+=item NodeBack
+
+Preceding node output unit.
+
+=item NodeUp
+
+=item NodeNext
+
+=item NodePrev
+
+The up, next and previous node output unit.
+
+=item Up
+
+=item Next
+
+=item Prev
+
+The up, next and previous section output unit.
+
+=item FastBack
+
+For top level output units, the previous top level output unit.  For other
+output units the up top level unit.  For example, for a chapter output unit it
+is the previous chapter output unit, for a subsection output unit it is the
+chapter output unit that contains the subsection.
+
+=item FastForward
+
+The next top level output unit.
+
+=back
+
+=item units_file_directions($output_units)
+X<C<units_file_directions>>
+
+In the directions reference described above for C<units_directions>,
+sets the I<PrevFile> and I<NextFile> directions to the output units in
+previous and following files.
+
+It also sets I<FirstInFile*> directions for all the output units by using
+the directions of the first output unit in file.  So, for example,
+I<FirstInFileNodeNext> is the output unit associated to the next node
+of the first output unit node in the file for each output unit in the file.
+
+The API for association of pages/output units to files is not defined yet.
+
+=back
+
+=head1 SEE ALSO
+
+L<Texinfo manual|http://www.gnu.org/s/texinfo/manual/texinfo/>,
+L<Texinfo::Document>, L<Texinfo::Convert::Converter>.
+
+=head1 AUTHOR
+
+Patrice Dumas, E<lt>pertusus@free.frE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2010- Free Software Foundation, Inc.  See the source file for
+all copyright years.
+
+This library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at
+your option) any later version.
+
+=cut
+
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index fecc4aa8f6..dab8a44f9b 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -15579,7 +15579,7 @@ default_format_special_body_about (CONVERTER *self,
 
       if (button->type == BST_direction)
         {
-         /* FIXME strip FirstInFile from $button to get active icon file? */
+         /* TODO strip FirstInFile from $button to get active icon file? */
           if (self->conf->ICONS.integer > 0
               && self->conf->ACTIVE_ICONS.icons->number > 0
               && self->conf->ACTIVE_ICONS.icons->list[direction]



reply via email to

[Prev in Thread] Current Thread [Next in Thread]