if ($self->in_preformatted()) { $result .= ''.$heading.''."\n"; } else { # if the level was changed, set the command name right if ($cmdname ne 'node' and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) { $cmdname = $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level]; } $result .= &{$self->{'format_heading_text'}}($self, $cmdname, $heading, $heading_level +$self->get_conf('CHAPTER_HEADER_LEVEL') -1, $command); } } $result .= $content if (defined($content)); my $table_of_contents_was_output = 0.; if ($self->get_conf('CONTENTS_OUTPUT_LOCATION') eq 'after_top' and $cmdname eq 'top' and $self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'} and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) { foreach my $content_command_name ('contents', 'shortcontents') { if ($self->get_conf($content_command_name)) { my $contents_text = $self->_contents_inline_element($content_command_name, undef); if ($contents_text ne '') { $result .= $contents_text; #$result .= $contents_text . $self->get_conf('DEFAULT_RULE')."\n"; $table_of_contents_was_output = 1; } } } } if (not $table_of_contents_was_output and $self->get_conf('FORMAT_MENU') eq 'sectiontoc' and $sectioning_commands{$cmdname} and ($cmdname ne 'top' or (not ($self->_has_contents_or_shortcontents() and $self->get_conf('CONTENTS_OUTPUT_LOCATION') eq 'inline')))) { $result .= _mini_toc($self, $command); } return $result; } foreach my $command (keys(%sectioning_commands), 'node') { $default_commands_conversion{$command} = \&_convert_heading_command; } sub _convert_raw_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($cmdname eq $self->{'output_format'}) { return $content; } $self->line_warn(sprintf(__("raw format %s is not converted"), $cmdname), $command->{'line_nr'}); return $self->protect_text($content); } foreach my $command (keys(%format_raw_commands)) { $default_commands_conversion{$command} = \&_convert_raw_command; } sub _convert_inline_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; my $format_arg = shift @$args; my $format; if (defined($format_arg)) { $format = $format_arg->{'monospacetext'}; } return '' if (!defined($format) or $format eq ''); my $arg_index = undef; if ($inline_format_commands{$cmdname}) { if ($cmdname eq 'inlinefmtifelse' and ! $self->{'expanded_formats_hash'}->{$format}) { $arg_index = 1; } elsif ($self->{'expanded_formats_hash'}->{$format}) { $arg_index = 0; } } elsif (defined($command->{'extra'}->{'expand_index'})) { $arg_index = 0; } if (defined($arg_index) and $arg_index < scalar(@$args)) { my $text_arg = $args->[$arg_index]; if ($text_arg) { if ($text_arg->{'normal'}) { return $text_arg->{'normal'}; } elsif ($text_arg->{'raw'}) { return $text_arg->{'raw'}; } } } return ''; } foreach my $command (keys(%inline_commands)) { $default_commands_conversion{$command} = \&_convert_inline_command; } sub _indent_with_table ($) { my $content = shift; return '
 '.$content."
\n"; } my $html_menu_entry_index = 0; sub _convert_preformatted_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; my $extra_classes; # this is mainly for classes as there are purprosely no classes # for small* my $main_cmdname; if ($small_alias{$cmdname}) { $main_cmdname = $small_alias{$cmdname}; } else { $main_cmdname = $cmdname; } if ($cmdname eq 'menu') { $html_menu_entry_index = 0; } elsif ($cmdname eq 'example') { if ($command->{'args'}) { $extra_classes = []; for my $example_arg (@{$command->{'args'}}) { # convert or remove all @-commands, using simple ascii and unicode # characters my $converted_arg = Texinfo::Convert::NodeNameNormalization::convert($example_arg); if ($converted_arg ne '') { push @$extra_classes, $converted_arg; } } } } elsif ($main_cmdname eq 'lisp') { $main_cmdname = 'example'; $extra_classes = ['lisp']; } if ($content ne '' and !$self->in_string()) { if ($self->get_conf('COMPLEX_FORMAT_IN_TABLE')) { if ($indented_preformatted_commands{$cmdname}) { return _indent_with_table ($content); } else { return $content."\n"; } } else { return $self->_attribute_class('div', $main_cmdname, $extra_classes).">\n".$content.''."\n"; } } else { return $content; } } foreach my $preformatted_command (keys(%preformatted_commands)) { $default_commands_conversion{$preformatted_command} = \&_convert_preformatted_command; } sub _convert_indented_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; # no class for @small* variants $cmdname = $small_alias{$cmdname} if $small_alias{$cmdname}; if ($content ne '' and !$self->in_string()) { if ($self->get_conf('COMPLEX_FORMAT_IN_TABLE')) { return _indent_with_table ($content); } else { return $self->_attribute_class('blockquote', $cmdname).">\n" .$content.''."\n"; } } else { return $content; } } $default_commands_conversion{'indentedblock'} = \&_convert_indented_command; sub _convert_verbatim_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if (!$self->in_string) { return $self->_attribute_class('pre', $cmdname).'>' .$content . ''; } else { return $content; } } $default_commands_conversion{'verbatim'} = \&_convert_verbatim_command; sub _convert_displaymath_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($self->in_string) { return $content; } my $result = ''; $result .= $self->_attribute_class('div', 'displaymath').'>'; if ($self->get_conf('HTML_MATH') and $self->get_conf('HTML_MATH') eq 'mathjax') { $self->{'element_math'} = 1; $result .= $self->_attribute_class('em', 'tex2jax_process').'>' ."\\[$content\\]".''; } else { $result .= $self->_attribute_class('em').'>'."$content".''; } $result .= ''; return $result; } $default_commands_conversion{'displaymath'} = \&_convert_displaymath_command; sub _convert_verbatiminclude_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; my $verbatim_include_verbatim = $self->Texinfo::Common::expand_verbatiminclude($command); if (defined($verbatim_include_verbatim)) { return $self->convert_tree($verbatim_include_verbatim); } else { return ''; } } $default_commands_conversion{'verbatiminclude'} = \&_convert_verbatiminclude_command; sub _convert_command_noop($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; return $content; } $default_commands_conversion{'raggedright'} = \&_convert_command_noop; $default_commands_conversion{'flushleft'} = \&_convert_command_noop; $default_commands_conversion{'flushright'} = \&_convert_command_noop; $default_commands_conversion{'group'} = \&_convert_command_noop; sub _convert_sp_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; if (defined($command->{'extra'}->{'misc_args'}->[0])) { my $sp_nr = $command->{'extra'}->{'misc_args'}->[0]; if ($self->in_preformatted() or $self->in_string()) { return "\n" x $sp_nr; } else { return "
\n" x $sp_nr; } } } $default_commands_conversion{'sp'} = \&_convert_sp_command; sub _convert_exdent_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; # FIXME do something better with css and span? my $preformatted = $self->in_preformatted(); if ($self->in_preformatted() or $self->in_string()) { return $self->_convert_preformatted_type($cmdname, $command, $args->[0]->{'normal'} ."\n"); } else { # ignore alignment information return "

".$args->[0]->{'normal'} ."\n

"; } } $default_commands_conversion{'exdent'} = \&_convert_exdent_command; sub _convert_center_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; if ($self->in_string()) { return $self->_convert_preformatted_type($cmdname, $command, $args->[0]->{'normal'}."\n"); } else { return "
".$args->[0]->{'normal'}."\n
"; } } $default_commands_conversion{'center'} = \&_convert_center_command; sub _convert_author_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; return '' if (!$args->[0] or !$command->{'extra'}->{'titlepage'}); if (!$self->in_string()) { return "$args->[0]->{'normal'}
\n"; } else { return $args->[0]->{'normal'}."\n"; } } $default_commands_conversion{'author'} = \&_convert_author_command; sub _convert_title_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; return '' if (!$args->[0]); if (!$self->in_string()) { return "

$args->[0]->{'normal'}

\n"; } else { return $args->[0]->{'normal'}; } } $default_commands_conversion{'title'} = \&_convert_title_command; sub _convert_subtitle_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; return '' if (!$args->[0]); if (!$self->in_string()) { return "

$args->[0]->{'normal'}

\n"; } else { return $args->[0]->{'normal'}; } } $default_commands_conversion{'subtitle'} = \&_convert_subtitle_command; sub _convert_insertcopying_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; if ($self->{'extra'} and $self->{'extra'}->{'copying'}) { return $self->convert_tree({'contents' => $self->{'extra'}->{'copying'}->{'contents'}}); } return ''; } $default_commands_conversion{'insertcopying'} = \&_convert_insertcopying_command; sub _convert_listoffloats_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; if (!$self->in_string() and $command->{'extra'} and $command->{'extra'}->{'type'} and defined($command->{'extra'}->{'type'}->{'normalized'}) and $self->{'floats'} and $self->{'floats'}->{$command->{'extra'}->{'type'}->{'normalized'}} and @{$self->{'floats'}->{$command->{'extra'}->{'type'}->{'normalized'}}}) { my $listoffloats_name = $command->{'extra'}->{'type'}->{'normalized'}; my $result = $self->_attribute_class('dl', 'listoffloats').">\n" ; foreach my $float (@{$self->{'floats'}->{$listoffloats_name}}) { my $float_href = $self->command_href($float); next if (!$float_href); $result .= '
'; my $float_text = $self->command_text($float); if (defined($float_text) and $float_text ne '') { if ($float_href) { $result .= "$float_text"; } else { $result .= $float_text; } } $result .= '
'; my $caption; if ($float->{'extra'}->{'shortcaption'}) { $caption = $float->{'extra'}->{'shortcaption'}; } elsif ($float->{'extra'}->{'caption'}) { $caption = $float->{'extra'}->{'caption'}; } my $caption_text; if ($caption) { $caption_text = $self->convert_tree_new_formatting_context( $caption->{'args'}->[0], $cmdname, 'listoffloats'); } else { $caption_text = ''; } $result .= '
'.$caption_text.'
'."\n"; } return $result . "\n"; } else { return ''; } } $default_commands_conversion{'listoffloats'} = \&_convert_listoffloats_command; sub _in_preformatted_in_menu($) { my $self = shift; return 1 if ($self->get_conf('SIMPLE_MENU')); my @pre_classes = $self->preformatted_classes_stack(); foreach my $pre_class (@pre_classes) { return 1 if ($preformatted_commands{$pre_class}); } return 0; } sub _convert_menu_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; return $content if ($cmdname eq 'detailmenu'); $html_menu_entry_index = 0; if ($content !~ /\S/) { return ''; } # This can probably only happen with incorrect input, # for instance menu in copying # FIXME check? if ($self->in_string()) { return $content; } my $begin_row = ''; my $end_row = ''; if ($self->_in_preformatted_in_menu()) { $begin_row = ''; $end_row = ''; } return $self->_attribute_class('table', 'menu') ." border=\"0\" cellspacing=\"0\">${begin_row}\n" . $content . "${end_row}\n"; } $default_commands_conversion{'menu'} = \&_convert_menu_command; $default_commands_conversion{'detailmenu'} = \&_convert_menu_command; sub _convert_float_command($$$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; my $content = shift; my ($caption, $prepended) = Texinfo::Common::float_name_caption($self, $command); my $caption_text = ''; my $prepended_text; if ($self->in_string()) { if ($prepended) { $prepended_text = $self->convert_tree_new_formatting_context( $prepended, 'float prepended'); } else { $prepended_text = ''; } if ($caption) { $caption_text = $self->convert_tree_new_formatting_context( {'contents' => $caption->{'args'}->[0]->{'contents'}}, 'float caption'); } return $prepended.$content.$caption_text; } my $id = $self->command_id($command); my $label; if (defined($id) and $id ne '') { $label = ""; } else { $label = ''; } if ($prepended) { if ($caption) { # prepend the prepended tree to the first paragraph my @caption_original_contents = @{$caption->{'args'}->[0]->{'contents'}}; my @caption_contents; my $new_paragraph; while (@caption_original_contents) { my $content = shift @caption_original_contents; if ($content->{'type'} and $content->{'type'} eq 'paragraph') { %{$new_paragraph} = %{$content}; $new_paragraph->{'contents'} = [@{$content->{'contents'}}]; unshift (@{$new_paragraph->{'contents'}}, {'cmdname' => 'strong', 'args' => [{'type' => 'brace_command_arg', 'contents' => [$prepended]}]}); push @caption_contents, $new_paragraph; last; } else { push @caption_contents, $content; } } push @caption_contents, @caption_original_contents; if ($new_paragraph) { $caption_text = $self->convert_tree_new_formatting_context( {'contents' => \@caption_contents}, 'float caption'); $prepended_text = ''; } } if ($caption_text eq '') { $prepended_text = $self->convert_tree_new_formatting_context( $prepended, 'float prepended'); if ($prepended_text ne '') { $prepended_text = '

'.$prepended_text.'

'; } } } else { $prepended_text = ''; } if ($caption and $caption_text eq '') { $caption_text = $self->convert_tree_new_formatting_context( $caption->{'args'}->[0], 'float caption'); } if ($prepended_text.$caption_text ne '') { $prepended_text = $self->_attribute_class('div','float-caption'). '>' . $prepended_text; $caption_text .= ''; } return $self->_attribute_class('div','float'). '>' .$label."\n".$content. $prepended_text.$caption_text . ''; } $default_commands_conversion{'float'} = \&_convert_float_command; sub _convert_quotation_command($$$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; my $content = shift; #$cmdname = $small_alias{$cmdname} # if $small_alias{$cmdname}; my $attribution = ''; if ($command->{'extra'} and $command->{'extra'}->{'authors'}) { foreach my $author (@{$command->{'extra'}->{'authors'}}) { my $centered_author = $self->gdt("\@center --- \@emph{{author}}\n", {'author' => $author->{'args'}->[0]->{'contents'}}); $centered_author->{'parent'} = $command; $attribution .= $self->convert_tree($centered_author); } } if (!$self->in_string()) { return "
\n" . $content . "
\n" . $attribution; } else { return $content.$attribution; } } $default_commands_conversion{'quotation'} = \&_convert_quotation_command; sub _convert_cartouche_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($content =~ /\S/ and !$self->in_string()) { return $self->_attribute_class('table', 'cartouche') ." border=\"1\">\n". $content ."\n"; } return $content; } $default_commands_conversion{'cartouche'} = \&_convert_cartouche_command; sub _convert_itemize_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($self->in_string()) { return $content; } if ($command->{'extra'}->{'command_as_argument'} and $command->{'extra'}->{'command_as_argument'}->{'cmdname'} eq 'bullet') { return "\n"; } else { return $self->_attribute_class('ul',$NO_BULLET_LIST_CLASS).">\n" . $content . "\n"; } } $default_commands_conversion{'itemize'} = \&_convert_itemize_command; sub _convert_enumerate_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($self->in_string()) { return $content; } if ($content eq '') { return ''; } my $specification = $command->{'extra'}->{'enumerate_specification'}; if (defined $specification) { my ($start, $type); if ($specification =~ /^\d*$/ and $specification ne '1') { $start = $specification; } elsif ($specification =~ /^[A-Z]$/) { $start = 1 + ord($specification) - ord('A'); $type = 'A'; } elsif ($specification =~ /^[a-z]$/) { $start = 1 + ord($specification) - ord('a'); $type = 'a'; } if (defined $type and defined $start) { return "
    \n" . $content . "
\n"; } elsif (defined $start) { return "
    \n" . $content . "
\n"; } } return "
    \n" . $content . "
\n"; } $default_commands_conversion{'enumerate'} = \&_convert_enumerate_command; sub _convert_multitable_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($self->in_string()) { return $content; } if ($content =~ /\S/) { return "\n" . $content . "
\n"; } else { return ''; } } $default_commands_conversion{'multitable'} = \&_convert_multitable_command; sub _convert_xtable_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($self->in_string()) { return $content; } if ($content ne '') { return "
\n" . $content . "
\n"; } else { return ''; } } $default_commands_conversion{'table'} = \&_convert_xtable_command; $default_commands_conversion{'ftable'} = \&_convert_xtable_command; $default_commands_conversion{'vtable'} = \&_convert_xtable_command; sub _convert_item_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; if ($self->in_string()) { return $content; } if ($command->{'parent'}->{'cmdname'} and $command->{'parent'}->{'cmdname'} eq 'itemize') { my $prepend ; my $itemize = $command->{'parent'}; if ($itemize->{'extra'}->{'command_as_argument'} and $itemize->{'extra'}->{'command_as_argument'}->{'cmdname'} eq 'bullet') { $prepend = ''; } else { # Setting multiple expansion should not be needed, except in # case of invalid constructs $prepend = $self->convert_tree_new_formatting_context( $itemize->{'args'}->[0], $command->{'cmdname'}, 'item_prepended'); } if ($content =~ /\S/) { return '
  • ' . $prepend .' '. $content . '
  • '; } else { return ''; } } elsif ($command->{'parent'}->{'cmdname'} and $command->{'parent'}->{'cmdname'} eq 'enumerate') { if ($content =~ /\S/) { return '
  • ' . ' ' . $content . '
  • '; } else { return ''; } } elsif ($command->{'parent'}->{'type'} and $command->{'parent'}->{'type'} eq 'table_term') { # FIXME instead use the code of Plaintext or DocBook. my $args = $content; if ($args->[0]) { my $tree = $self->_table_item_content_tree($command, [$args->[0]->{'tree'}]); my $result = $self->convert_tree ($tree); foreach my $command_name (reverse($self->commands_stack())) { if ($preformatted_code_commands{$command_name}) { $result = '' .$result. ''; last; } } my $index_id = $self->command_id ($command); my $anchor; if (defined($index_id)) { $anchor = $self->_get_copiable_anchor($index_id); $index_id = " id='$index_id'"; } else { $anchor = ''; $index_id = ''; } return "$result$anchor\n"; } else { return ''; } } elsif ($command->{'parent'}->{'type'} and $command->{'parent'}->{'type'} eq 'row') { return $self->_convert_tab_command ($cmdname, $command, $content); } return ''; } $default_commands_conversion{'item'} = \&_convert_item_command; $default_commands_conversion{'headitem'} = \&_convert_item_command; $default_commands_conversion{'itemx'} = \&_convert_item_command; sub _convert_tab_command ($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = shift; my $cell_nr = $command->{'extra'}->{'cell_number'}; my $row = $command->{'parent'}; my $row_cmdname = $row->{'contents'}->[0]->{'cmdname'}; my $multitable = $row->{'parent'}->{'parent'}; my $fractions = ''; my $cf = $multitable->{'extra'}->{'columnfractions'}; if ($cf) { if (exists($cf->{'extra'}->{'misc_args'}->[$cell_nr-1])) { my $fraction = sprintf('%d', 100*$cf->{'extra'}->{'misc_args'}->[$cell_nr-1]); $fractions = " width=\"$fraction%\""; } } $content =~ s/^\s*//; $content =~ s/\s*$//; if ($self->in_string()) { return $content; } if ($row_cmdname eq 'headitem') { return "" . $content . ''; } else { return "" . $content . ''; } } $default_commands_conversion{'tab'} = \&_convert_tab_command; sub _convert_xref_commands($$$$) { my $self = shift; my $cmdname = shift; my $root = shift; my $args = shift; my $tree; my $name; if ($cmdname ne 'inforef' and defined($args->[2]->{'normal'}) and $args->[2]->{'normal'} ne '') { $name = $args->[2]->{'normal'}; } elsif (defined($args->[1]->{'normal'}) and $args->[1]->{'normal'} ne '') { $name = $args->[1]->{'normal'} } if ($cmdname eq 'inforef') { $args->[3] = $args->[2]; $args->[2] = undef; } my $file_arg_tree; my $file = ''; if (defined($args->[3]->{'monospacetext'}) and $args->[3]->{'monospacetext'} ne '') { $file_arg_tree = $args->[3]->{'tree'}; $file = $args->[3]->{'monospacetext'}; } my $book = ''; $book = $args->[4]->{'normal'} if (defined($args->[4]->{'normal'})); # internal reference if ($cmdname ne 'inforef' and $book eq '' and $file eq '' and $root->{'extra'}->{'node_argument'} and defined($root->{'extra'}->{'node_argument'}->{'normalized'}) and !$root->{'extra'}->{'node_argument'}->{'manual_content'} and $self->{'labels'} and $self->{'labels'}->{$root->{'extra'}->{'node_argument'}->{'normalized'}}) { my $node = $self->label_command($root->{'extra'}->{'node_argument'}->{'normalized'}); # This is the node if USE_NODES, otherwise this may be the sectioning # command (if the sectioning command is really associated to the node) my $command = $self->command_element_command($node); $command = $node if (!$node->{'extra'}->{'associated_section'} or $node->{'extra'}->{'associated_section'} ne $command); my $href = $self->command_href($command, undef, $root); if (!defined($name)) { if ($self->get_conf('xrefautomaticsectiontitle') eq 'on' and $node->{'extra'}->{'associated_section'}) { $command = $node->{'extra'}->{'associated_section'}; $name = $self->command_text($command, 'text_nonumber'); } elsif ($node->{'cmdname'} eq 'float') { if (!$self->get_conf('XREF_USE_FLOAT_LABEL')) { $name = $self->command_text($command); } if (!defined($name) or $name eq '') { if (defined($args->[0]->{'monospace'})) { $name = $args->[0]->{'monospace'}; } else { $name = ''; } } } elsif (!$self->get_conf('XREF_USE_NODE_NAME_ARG') and (defined($self->get_conf('XREF_USE_NODE_NAME_ARG')) or !$self->in_preformatted())) { $name = $self->command_text($command, 'text_nonumber'); #die "$command $command->{'normalized'}" if (!defined($name)); } elsif (defined($args->[0]->{'monospace'})) { $name = $args->[0]->{'monospace'}; } else { $name = ''; } } my $reference = $name; $reference = "$name" if ($href ne '' and !$self->in_string()); # maybe use {'extra'}->{'node_argument'}? my $is_section = ($command->{'cmdname'} ne 'node' and $command->{'cmdname'} ne 'anchor' and $command->{'cmdname'} ne 'float'); if ($cmdname eq 'pxref') { $tree = $self->gdt('see {reference_name}', { 'reference_name' => {'type' => '_converted', 'text' => $reference} }); } elsif ($cmdname eq 'xref' or $cmdname eq 'inforef') { $tree = $self->gdt('See {reference_name}', { 'reference_name' => {'type' => '_converted', 'text' => $reference} }); } elsif ($cmdname eq 'ref') { $tree = $self->gdt('{reference_name}', { 'reference_name' => {'type' => '_converted', 'text' => $reference} }); } } else { # external reference my $node_entry = {}; $node_entry->{'node_content'} = $root->{'extra'}->{'node_argument'}->{'node_content'} if ($root->{'extra'}->{'node_argument'} and $root->{'extra'}->{'node_argument'}->{'node_content'}); $node_entry->{'normalized'} = $root->{'extra'}->{'node_argument'}->{'normalized'} if ($root->{'extra'}->{'node_argument'} and exists($root->{'extra'}->{'node_argument'}->{'normalized'})); # file argument takes precedence over the file in the node (file)node entry if (defined($file_arg_tree) and $file ne '') { $node_entry->{'manual_content'} = $file_arg_tree->{'contents'}; } elsif ($root->{'extra'}->{'node_argument'} and $root->{'extra'}->{'node_argument'}->{'manual_content'}) { $node_entry->{'manual_content'} = $root->{'extra'}->{'node_argument'}->{'manual_content'}; my $file_with_node_tree = {'type' => '_code', 'contents' => [@{$node_entry->{'manual_content'}}]}; $file = $self->convert_tree($file_with_node_tree, 'node file in ref'); } my $href = $self->command_href($node_entry, undef, $root); if ($book eq '') { if (!defined($name)) { my $node_name = $self->command_text($node_entry); $name = $node_name; } elsif ($file ne '') { $name = "($file)$name"; } } elsif (!defined($name) and $node_entry->{'node_content'}) { my $node_no_file_tree = {'type' => '_code', 'contents' => [@{$node_entry->{'node_content'}}]}; my $node_name = $self->convert_tree($node_no_file_tree, 'node in ref'); if (defined($node_name) and ($self->get_conf('KEEP_TOP_EXTERNAL_REF') or $node_name ne 'Top')) { $name = $node_name; } } # not exactly sure when it happens. Something like @ref{(file),,,Manual}? $name = $args->[0]->{'monospace'} if (!defined($name) # FIXME could it really be Top? and ($self->get_conf('KEEP_TOP_EXTERNAL_REF') or $args->[0]->{'monospace'} ne 'Top')); $name = '' if (!defined($name)); my $reference = $name; my $book_reference = ''; if (!$self->in_string() and $href ne '') { # attribute to distiguish links to Texinfo manuals from other links # and to provide manual name of target my $attribute = ''; if ($file) { $attribute = "data-manual=\"".$self->protect_text($file)."\" "; } if ($name ne '') { $reference = "$name"; } elsif ($book ne '') { $book_reference = "$book"; } } if ($cmdname eq 'pxref') { if (($book ne '') and ($href ne '') and ($reference ne '')) { $tree = $self->gdt('see {reference} in @cite{{book}}', { 'reference' => {'type' => '_converted', 'text' => $reference}, 'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($book_reference ne '') { $tree = $self->gdt('see @cite{{book_reference}}', { 'book_reference' => {'type' => '_converted', 'text' => $book_reference }}); } elsif (($book ne '') and ($reference ne '')) { $tree = $self->gdt('see `{section}\' in @cite{{book}}', { 'section' => {'type' => '_converted', 'text' => $reference}, 'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($book ne '') { # should seldom or even never happen $tree = $self->gdt('see @cite{{book}}', {'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($href ne '') { $tree = $self->gdt('see {reference}', { 'reference' => {'type' => '_converted', 'text' => $reference} }); } elsif ($reference ne '') { $tree = $self->gdt('see `{section}\'', { 'section' => {'type' => '_converted', 'text' => $reference} }); } } elsif ($cmdname eq 'xref' or $cmdname eq 'inforef') { if (($book ne '') and ($href ne '') and ($reference ne '')) { $tree = $self->gdt('See {reference} in @cite{{book}}', { 'reference' => {'type' => '_converted', 'text' => $reference}, 'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($book_reference ne '') { $tree = $self->gdt('See @cite{{book_reference}}', { 'book_reference' => {'type' => '_converted', 'text' => $book_reference }}); } elsif (($book ne '') and ($reference ne '')) { $tree = $self->gdt('See `{section}\' in @cite{{book}}', { 'section' => {'type' => '_converted', 'text' => $reference}, 'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($book ne '') { # should seldom or even never happen $tree = $self->gdt('See @cite{{book}}', {'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($href ne '') { $tree = $self->gdt('See {reference}', { 'reference' => {'type' => '_converted', 'text' => $reference} }); } elsif ($reference ne '') { $tree = $self->gdt('See `{section}\'', { 'section' => {'type' => '_converted', 'text' => $reference} }); } } else { if (($book ne '') and ($href ne '') and ($reference ne '')) { $tree = $self->gdt('{reference} in @cite{{book}}', { 'reference' => {'type' => '_converted', 'text' => $reference}, 'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($book_reference ne '') { $tree = $self->gdt('@cite{{book_reference}}', { 'book_reference' => {'type' => '_converted', 'text' => $book_reference }}); } elsif (($book ne '') and ($reference ne '')) { $tree = $self->gdt('`{section}\' in @cite{{book}}', { 'section' => {'type' => '_converted', 'text' => $reference}, 'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($book ne '') { # should seldom or even never happen $tree = $self->gdt('@cite{{book}}', {'book' => {'type' => '_converted', 'text' => $book }}); } elsif ($href ne '') { $tree = $self->gdt('{reference}', { 'reference' => {'type' => '_converted', 'text' => $reference} }); } elsif ($reference ne '') { $tree = $self->gdt('`{section}\'', { 'section' => {'type' => '_converted', 'text' => $reference} }); } } if (!defined($tree)) { # May happen if there is no argument #die "external: $cmdname, ($args), '$name' '$file' '$book' '$href' '$reference'. tree undef"; return ''; } } return $self->convert_tree($tree); } foreach my $command(keys(%ref_commands)) { $default_commands_conversion{$command} = \&_convert_xref_commands; } sub _convert_index_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; my $index_id = $self->command_id($command); if (defined($index_id) and $index_id ne '' and !@{$self->{'multiple_pass'}} and !$self->in_string()) { my $result = ""; $result .= "\n" unless ($self->in_preformatted()); return $result; } return ''; } $default_commands_conversion{'cindex'} = \&_convert_index_command; my %formatted_index_entries; sub _convert_printindex_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $args = shift; my $index_name; if ($command->{'extra'} and $command->{'extra'}->{'misc_args'} and defined($command->{'extra'}->{'misc_args'}->[0])) { $index_name = $command->{'extra'}->{'misc_args'}->[0]; } else { return ''; } if (!$self->{'index_entries_by_letter'} or !$self->{'index_entries_by_letter'}->{$index_name} or !@{$self->{'index_entries_by_letter'}->{$index_name}}) { return ''; } #foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) { # print STDERR "IIIIIII $letter_entry->{'letter'}\n"; # foreach my $index_entry (@{$letter_entry->{'entries'}}) { # print STDERR " ".join('|', keys(%$index_entry))."||| $index_entry->{'key'}\n"; # } #} return '' if ($self->in_string()); $self->_new_document_context($cmdname); my $result = ''; # First do the summary letters linking to the letters done below my %letter_id; my @non_alpha = (); my @alpha = (); # collect the links my $symbol_idx = 0; foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) { my $letter = $letter_entry->{'letter'}; my $index_element_id = $self->_element_direction($self->{'current_element'}, 'This', 'target'); if (!defined($index_element_id)) { $index_element_id = $target_prefix; } my $is_symbol = $letter !~ /^[[:alpha:]]/; my $identifier; if ($is_symbol) { $symbol_idx++; $identifier = $index_element_id . "_${index_name}_symbol-$symbol_idx"; } else { $identifier = $index_element_id . "_${index_name}_letter-${letter}"; } $letter_id{$letter} = $identifier; my $summary_letter_link = $self->_attribute_class('a', 'summary-letter') ." href=\"#$identifier\">".$self->protect_text($letter).''; if ($is_symbol) { push @non_alpha, $summary_letter_link; } else { push @alpha, $summary_letter_link; } } # Format the summary letters my $join = ''; my $non_alpha_text = ''; my $alpha_text = ''; $join = "   \n
    \n" if (@non_alpha and @alpha); if (@non_alpha) { $non_alpha_text = join("\n   \n", @non_alpha) . "\n"; } if (@alpha) { $alpha_text = join("\n   \n", @alpha) . "\n   \n"; } # format the summary my $summary = "
    " . $self->convert_tree($self->gdt('Jump to')) .":   " . $non_alpha_text . $join . $alpha_text . "
    \n"; $result .= $summary; # now format the index entries $result .= $self->_attribute_class('table', "index-$index_name") ." border=\"0\">\n" . "" . $self->convert_tree($self->gdt('Index Entry')) . "  " . $self->convert_tree($self->gdt('Section')) ."\n" . " ".$self->get_conf('DEFAULT_RULE') ."\n"; foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) { my $letter = $letter_entry->{'letter'}; my $entries_text = ''; foreach my $index_entry_ref (@{$letter_entry->{'entries'}}) { # to avoid double error messages set ignore_notice if an entry was # already formatted once, for example if there are multiple printindex. my $already_formatted; if (!$formatted_index_entries{$index_entry_ref}) { $formatted_index_entries{$index_entry_ref} = 1; } else { $already_formatted = 1; $self->{'ignore_notice'}++; } my $entry; if ($index_entry_ref->{'in_code'}) { $entry = $self->convert_tree({'type' => '_code', 'contents' => $index_entry_ref->{'content'}}); } else { $entry = $self->convert_tree({'contents' => $index_entry_ref->{'content'}}); } $entry .= $self->convert_index_subentries($index_entry_ref); if ($already_formatted) { $self->{'ignore_notice'}--; } next if ($entry !~ /\S/); $entry = '' .$entry .'' if ($index_entry_ref->{'in_code'}); my $entry_href = $self->command_href($index_entry_ref->{'command'}); my $associated_command; if ($self->get_conf('NODE_NAME_IN_INDEX')) { $associated_command = $index_entry_ref->{'node'}; if (!defined($associated_command)) { $associated_command = $self->command_node($index_entry_ref->{'command'}); } } if (!$associated_command) { $associated_command = $self->command_element_command($index_entry_ref->{'command'}); if (!$associated_command) { # Use Top if not associated command found $associated_command = $self->element_command($self->global_element('Top')); } } my ($associated_command_href, $associated_command_text); if ($associated_command) { $associated_command_href = $self->command_href($associated_command); $associated_command_text = $self->command_text($associated_command); } $entries_text .= '' . "$entry" . $self->get_conf('INDEX_ENTRY_COLON') . ' '; $entries_text .= "$associated_command_text" if ($associated_command_href); $entries_text .= "\n"; } # a letter and associated indice entries $result .= '' . "".$self->protect_text($letter) . "\n" . $entries_text . " ".$self->get_conf('DEFAULT_RULE')."\n"; } $result .= "\n"; pop @{$self->{'document_context'}}; return $result .$summary; } $default_commands_conversion{'printindex'} = \&_convert_printindex_command; sub _contents_inline_element($$$) { my $self = shift; my $cmdname = shift; my $command = shift; my $content = &{$self->{'format_contents'}}($self, $cmdname, $command); if ($content) { my $element_name = $contents_command_element_name{$cmdname}; my $special_element = $self->special_element($element_name); my $heading; my $result = "
    command_id($special_element); if ($id ne '') { $result .= " id=\"$id\""; } $heading = $self->command_text($special_element); } else { # happens when called as convert() and not output() #cluck "$cmdname special element not defined"; $heading = $self->convert_tree ($self->get_conf('SPECIAL_ELEMENTS_NAME')->{$element_name}); } $result .= ">\n"; my $class = $self->get_conf('SPECIAL_ELEMENTS_CLASS')->{$element_name}; $result .= &{$self->{'format_heading_text'}}($self, $class.'-heading', $heading, $self->get_conf('CHAPTER_HEADER_LEVEL'))."\n"; $result .= $content . "
    \n"; return $result; } return ''; } sub _convert_informative_command($$$$) { my $self = shift; my $cmdname = shift; my $command = shift; return '' if ($self->in_string()); $cmdname = 'shortcontents' if ($cmdname eq 'summarycontents'); $self->_informative_command($command); if ($self->get_conf('CONTENTS_OUTPUT_LOCATION') eq 'inline' and ($cmdname eq 'contents' or $cmdname eq 'shortcontents') and $self->get_conf($cmdname) and $self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'} and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) { return $self->_contents_inline_element($cmdname, $command); } if ($cmdname eq 'documentlanguage') { $self->_translate_names(); } return ''; } foreach my $informative_command (@informative_global_commands) { $default_commands_conversion{$informative_command} = \&_convert_informative_command; } # associate same formatting function for @small* command # as for the associated @-command foreach my $small_command (keys(%small_alias)) { $default_commands_conversion{$small_command} = $default_commands_conversion{$small_alias{$small_command}}; } # Keys are tree element types, values are function references to convert # elements of that type. Can be overridden with # Texinfo::Config::texinfo_types_conversion, setup by # Texinfo::Config::texinfo_register_type_formatting() my %default_types_conversion; sub default_types_conversion($$) { my $self = shift; my $type = shift; return $default_types_conversion{$type}; } # Ignored commands foreach my $type ('empty_line_after_command', 'preamble', 'preamble_before_setfilename', 'empty_spaces_after_command', 'spaces_at_end', 'empty_spaces_before_argument', 'empty_spaces_before_paragraph', 'empty_spaces_after_close_brace') { $default_types_conversion{$type} = undef; } my %paragraph_style = ( 'center' => 'center', 'flushleft' => 'left', 'flushright' => 'right', ); sub _quotation_arg_to_prepend($$) { my $self = shift; my $command = shift; if ($command->{'parent'} and $command->{'parent'}->{'cmdname'} and ($command->{'parent'}->{'cmdname'} eq 'quotation' or $command->{'parent'}->{'cmdname'} eq 'smallquotation') and $command->{'parent'}->{'args'} and $command->{'parent'}->{'args'}->[0] and $command->{'parent'}->{'args'}->[0]->{'contents'} and @{$command->{'parent'}->{'args'}->[0]->{'contents'}}) { return $self->convert_tree($self->gdt('@b{{quotation_arg}:} ', {'quotation_arg' => $command->{'parent'}->{'args'}->[0]->{'contents'}})); } return undef; } sub _convert_paragraph_type($$$$) { my $self = shift; my $type = shift; my $command = shift; my $content = shift; if ($self->paragraph_number() == 1) { my $in_format = $self->top_format(); if ($in_format) { # no first paragraph in those environment to avoid extra spacing if ($in_format eq 'itemize' or $in_format eq 'enumerate' or $in_format eq 'multitable') { return $content; } else { my $prepended = $self->_quotation_arg_to_prepend($command); $content = $prepended.$content if (defined($prepended)); } } } return $content if ($self->in_string()); if ($content =~ /\S/) { my $align = $self->in_align(); if ($align and $paragraph_style{$align}) { return "

    ".$content."

    "; } else { return "

    ".$content."

    "; } } else { return ''; } } $default_types_conversion{'paragraph'} = \&_convert_paragraph_type; sub _preformatted_class() { my $self = shift; my $pre_class; my @pre_classes = $self->preformatted_classes_stack(); foreach my $class (@pre_classes) { # FIXME maybe add or $pre_class eq 'menu-preformatted' to override # 'menu-preformatted' with 'menu-comment'? $pre_class = $class unless ($pre_class and $preformatted_code_commands{$pre_class} and !($preformatted_code_commands{$class} or $class eq 'menu-preformatted')); } return $pre_class; } sub _convert_preformatted_type($$$$) { my $self = shift; my $type = shift; my $command = shift; my $content = shift; if (!defined($content)) { cluck "content undef in _convert_preformatted_type " .Texinfo::Common::_print_current($command); } my $current = $command; # !defined preformatted_number may happen if there is something before the # first preformatted. For example an @exdent. if ($self->preformatted_number() and $self->preformatted_number() == 1) { my $prepended = $self->_quotation_arg_to_prepend($command); $content = $prepended.$content if (defined($prepended)); } return '' if ($content eq ''); return $content if ($type eq 'rawpreformatted'); my $pre_class = $self->_preformatted_class(); if ($self->top_format() eq 'multitable') { $content =~ s/^\s*//; $content =~ s/\s*$//; } # menu_entry_description is always in a preformatted container # in the tree, as the whole menu is meant to be an # environment where spaces and newlines are preserved. # # However, if not in preformatted block command (nor in SIMPLE_MENU), # we don't preserve spaces and newlines in menu_entry_description, # instead the whole menu_entry is in a table, so here, not
      if ($command->{'parent'}->{'type'} 
          and $command->{'parent'}->{'type'} eq 'menu_entry_description'
          and !$self->_in_preformatted_in_menu()) {
        return $content;
      }
    
      if ($self->in_string()) {
        return $content;
      }
      $content =~ s/^\n/\n\n/; # a newline immediately after a 
     is ignored.
      my $result = $self->_attribute_class('pre', $pre_class).">".$content."
    "; # this may happen with lines without textual content # between a def* and def*x. if ($command->{'parent'}->{'cmdname'} and $command->{'parent'}->{'cmdname'} =~ /^def/) { $result = '
    '.$result.'
    '; } return $result; } $default_types_conversion{'preformatted'} = \&_convert_preformatted_type; $default_types_conversion{'rawpreformatted'} = \&_convert_preformatted_type; sub _convert_bracketed_type($$$$) { my $self = shift; my $type = shift; my $command = shift; my $content = shift; #print STDERR "$self $type $command $content\n";