On Mon, Jan 06, 2025 at 07:33:45AM +0000, Werner LEMBERG wrote:
> 
> [texinfo 7.2]
> 
> 
> The documentation in the 'Direction' section of 'texi2any_api' says
> 
>   _Index_
>        The first output unit with ‘@printindex’.
> 
> This is not ideal.  Assuming that a large document has multiple
> indices, the most general index is normally the last one, not the
> first.

It seems to me that it is more natural to use the first index, whatever
type it is, and it is more robust, the specified index may not exist or
be merged into another one.

> I thus suggest to make it configurable to which index the 'Index'
> direction points to – I can naively imagine to add an optional
> argument to `format_navigation_button` (and probably other commands)
> that takes the argument of the `@printindex`, for example,
> 
> ```
> my_index = {'direction' => 'Index',
>             'index'     => 'cp'};
> format_navigation_button($converter, my_index);
> ```

It seems to me that the only information to pass is the selected index
name.

> Note that my Perl abilities are limited (and I have zero experience
> with `texi2any`'s API); I'm sure there are better possibilities to
> handle this.

The existing HTML customization API (with some knowledge of the tree)
can be used as is.  It is possible to
* determine the node associated to the selected printindex
* register a function to format the 'Index' button to return the
  formatted button.
Find attached a possible init file doing what you want.  I have
hardcoded the selected printindex.

To do this, I tried to follow the documentation.  Everything
is described or linked to in the "GNU Texinfo texi2any Output
Customization manual"
  https://www.gnu.org/software/texinfo/manual/texi2any_api/
Unfortunately, the information is all over the place and there aren't
that many relevant examples.

The code is probably overly general, however, part could be simplified
if, for instance, a simple href without most of the attributes is
acceptable, or if it is known that nothing can fail.

I'll try to improve the documentation, added to the tp TODO...

-- 
Pat
# Copyright 2011-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/>.

use strict;

my $selected_index_name = 'cp';

my @buttons_specs = ('SECTION_BUTTONS', 'CHAPTER_BUTTONS',
                             'TOP_BUTTONS',
                       'CHAPTER_FOOTER_BUTTONS', 'SECTION_FOOTER_BUTTONS',
                       'NODE_FOOTER_BUTTONS', 'MISC_BUTTONS',
                       'TOP_FOOTER_BUTTONS', 'LINKS_BUTTONS');

# set once
my $default_buttons;

# reset for each document
my $index_printindex_top_level_node;

sub _index_button_printindex($)
{
  my $self = shift;
  my $result = '';
  # Should not be possible
  if (!$index_printindex_top_level_node) {
    print STDERR "BUG: _index_button_printindex: no top level node\n";
    return ($result, 0);
  }

  my $href = $self->command_href($index_printindex_top_level_node);
  if (!defined($href)) {
    print STDERR "ERROR: _index_button_printindex: no href\n";
    return ($result, 0);
  }

  my $button = 'Index';
  my $active;

  # Following code is a cut and paste of _default_format_button else case
  # for the # button is active case only

      my $btitle = '';
      my $description = $self->direction_string($button, 'description', 'string');
      if (defined($description)) {
        $btitle = ' title="' . $description . '"';
      }
      if ($self->get_conf('USE_ACCESSKEY')) {
        my $accesskey = $self->direction_string($button, 'accesskey', 'string');
        if (defined($accesskey) and $accesskey ne '') {
          $btitle .= " accesskey=\"$accesskey\"";
        }
      }
      if ($self->get_conf('USE_REL_REV')) {
        my $button_rel = $self->direction_string($button, 'rel', 'string');
        if (defined($button_rel) and $button_rel ne '') {
          $btitle .= " rel=\"$button_rel\"";
        }
      }
      if ($self->get_conf('ICONS')) {
        my $active_icon;
        my $active_icons = $self->get_conf('ACTIVE_ICONS');
        if ($active_icons) {
        # TODO strip FirstInFile from $button to get $active_icon?
          $active_icon = $active_icons->{$button};
        }
        if (defined($active_icon) and $active_icon ne '') {
          my $button_name_string = $self->direction_string($button,
                                                           'button', 'string');
          $active = "<a href=\"$href\"${btitle}>".
             &{$self->formatting_function('format_button_icon_img')}($self,
                      $button_name_string, $active_icon,
                      $self->from_element_direction($button, 'string')) ."</a>";
        } else {
          # use text
          my $button_text = $self->direction_string($button, 'text');
          $button_text = '' if (!defined($button_text));
          $active = '['."<a href=\"$href\"${btitle}>".$button_text."</a>".']';
        }
      } else {
        # use text
        my $button_text = $self->direction_string($button, 'text');
        $button_text = '' if (!defined($button_text));
        $active = '['."<a href=\"$href\"${btitle}>".$button_text."</a>".']';
      }
    return ($active, 0);
}

sub _replace_button_for_specific_index
{
  my ($self, $document, $stage) = @_;

  # find the node the selected index printindex is in
  $index_printindex_top_level_node = undef;

  my $global_commands_information
    = $document->global_commands_information();
  if ($global_commands_information
      and $global_commands_information->{'printindex'}) {
    foreach my $element (@{$global_commands_information->{'printindex'}}) {
      if ($element->{'extra'} and $element->{'extra'}->{'misc_args'}
          and $element->{'extra'}->{'misc_args'}->[0] eq $selected_index_name) {
        my ($output_unit, $top_level_element)
           = $self->get_element_root_command_element($element);
        if ($top_level_element) {
          if ($top_level_element->{'cmdname'} eq 'node') {
            $index_printindex_top_level_node = $top_level_element;
          } elsif ($top_level_element->{'extra'}
                   and $top_level_element->{'extra'}->{'associated_node'}) {
            $index_printindex_top_level_node
              = $top_level_element->{'extra'}->{'associated_node'};
          }
          last if ($index_printindex_top_level_node);
        }
      }
    }
  }

  # gather default buttons if not already done.
  # Used to set up the modified buttons or reused if the selected printindex
  # was not found
  if (!defined($default_buttons)) {
    foreach my $buttons_spec (@buttons_specs) {
      $default_buttons->{$buttons_spec} = $self->get_conf($buttons_spec);
    }
  }

  # set/reset the buttons for every document to simply handle all the
  # possible cases of found/not found printindex
  if (defined($index_printindex_top_level_node)) {
    foreach my $buttons_spec (@buttons_specs) {
      my $reference_buttons_list = $default_buttons->{$buttons_spec};
      my @modified_buttons;
      for (my $i = 0; $i < scalar (@$reference_buttons_list); $i++) {
        if (ref($reference_buttons_list->[$i]) eq ''
            and $reference_buttons_list->[$i] eq 'Index') {
          push @modified_buttons, \&_index_button_printindex;
        } else {
          push @modified_buttons, $reference_buttons_list->[$i];
        }
      }
      $self->set_conf($buttons_spec, \@modified_buttons);
    }
  } else {
    # reset defaults
    foreach my $buttons_spec (@buttons_specs) {
      $self->set_conf($buttons_spec, $default_buttons->{$buttons_spec});
    }
  }

  return 0;
}

texinfo_register_handler('structure', \&_replace_button_for_specific_index);

Reply via email to