texinfo-commits
[Top][All Lists]
Advanced

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

branch master updated: * tp/Texinfo/ParserNonXS.pm (_close_command_clean


From: Patrice Dumas
Subject: branch master updated: * tp/Texinfo/ParserNonXS.pm (_close_command_cleanup): separate multitable head and body only if the multitable has contents.
Date: Sun, 29 Sep 2024 05:44:07 -0400

This is an automated email from the git hooks/post-receive script.

pertusus pushed a commit to branch master
in repository texinfo.

The following commit(s) were added to refs/heads/master by this push:
     new 741d1405a2 * tp/Texinfo/ParserNonXS.pm (_close_command_cleanup): 
separate multitable head and body only if the multitable has contents.
741d1405a2 is described below

commit 741d1405a22abf471802a5b8ee2a029873353526
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Sun Jun 16 00:02:20 2024 +0200

    * tp/Texinfo/ParserNonXS.pm (_close_command_cleanup): separate
    multitable head and body only if the multitable has contents.
    
    * tp/Texinfo/ParserNonXS.pm (_close_command_cleanup),
    tp/Texinfo/XS/parsetexi/close.c (close_command_cleanup): update code
    taking into account that
    i) there cannot be ignorable_spaces_after_command before before_item,
    as it is added only after commands, and inside commands arguments.
    ii) there cannot be an @end in before_item, as soon as an @end is seen
    it is popped from the element it is in, before closing.
    iii) there can only be before_item or elements associated with @*item
    directly in block item at commands.
    
    * tp/Texinfo/XS/parsetexi/utils.c (item_line_parent): use explicit
    command enums.
    
    * tp/Texinfo/XS/main/convert_utils.c
    (find_root_command_next_heading_command): fix condition.
    
    * tp/Texinfo/ParserNonXS.pm (_expand_macro_arguments): fix condition.
    
    * tp/Texinfo/Document.pm (new_document): do not initialize explicitely
    'included_files' to give the same output as with XS.
    
    * tp/Texinfo/XS/main/manipulate_indices.c
    (idx_leading_text_or_command), tp/Texinfo/Indices.pm
    (_idx_leading_text_or_command), tp/Texinfo/XS/main/utils.c
    (is_content_empty), tp/Texinfo/Common.pm (is_content_empty): handle
    text element first.
    
    * tp/Texinfo/XS/main/node_name_normalization.c
    (convert_to_normalized_internal),
    tp/Texinfo/Convert/NodeNameNormalization.pm (%ignored_text_types)
    (_convert): handle text first, including ignored text types, and the
    remaining elements afterwards.
    
    * tp/Texinfo/Translations.pm (_substitute_element_array),
    tp/Texinfo/XS/main/translations.c (substitute_element_array): check
    for text first, as there is no recursion in that case.
    
    * tp/Texinfo/XS/main/tree_types.h (CONTAINER, ELEMENT),
    tp/Texinfo/XS/main/tree.c (new_command_element),
    tp/Texinfo/XS/parsetexi/end_line.c (end_line_starting_block),
    tp/Texinfo/XS/parsetexi/indices.c
    (set_non_ignored_space_in_index_before_command): move cmd from
    ELEMENT to CONTAINER, as text element do not have a command name.
    Update users, making sure in particular that element_command_name,
    element_builtin_cmd, element_builtin_data_cmd and similar functions
    and macros are never called for a text element.
    
    * tp/Texinfo/XS/parsetexi/separator.c (handle_open_brace): rename
    command variable as cmd.
    
    * tp/t/test_document.t: fix the calls to is().
    
    * tp/Makefile.tres, tp/t/05paragraph.t
    (indent_before_macro_definition_and_other): add test with command that
    are skipped between @indent and the next paragraph.
---
 ChangeLog                                          |  61 +++
 tp/Makefile.tres                                   |   1 +
 tp/Texinfo/Common.pm                               |  10 +-
 tp/Texinfo/Convert/NodeNameNormalization.pm        |  28 +-
 tp/Texinfo/Document.pm                             |   3 +-
 tp/Texinfo/Indices.pm                              |  24 +-
 tp/Texinfo/ParserNonXS.pm                          | 133 +++---
 tp/Texinfo/Translations.pm                         |  15 +-
 tp/Texinfo/XS/convert/call_html_perl_function.c    |  12 +-
 tp/Texinfo/XS/convert/convert_html.c               | 109 ++---
 tp/Texinfo/XS/convert/converter.c                  |   2 +-
 tp/Texinfo/XS/main/build_perl_info.c               |   4 +-
 tp/Texinfo/XS/main/builtin_commands.c              |  16 +-
 tp/Texinfo/XS/main/builtin_commands.h              |   5 +-
 tp/Texinfo/XS/main/convert_to_texinfo.c            |   2 +-
 tp/Texinfo/XS/main/convert_to_text.c               |  96 ++---
 tp/Texinfo/XS/main/convert_utils.c                 |  18 +-
 tp/Texinfo/XS/main/debug.c                         |  10 +-
 tp/Texinfo/XS/main/manipulate_indices.c            |  55 +--
 tp/Texinfo/XS/main/manipulate_tree.c               |   7 +-
 tp/Texinfo/XS/main/node_name_normalization.c       |  63 +--
 tp/Texinfo/XS/main/output_unit.c                   |   8 +-
 tp/Texinfo/XS/main/targets.c                       |   4 +-
 tp/Texinfo/XS/main/translations.c                  |  24 +-
 tp/Texinfo/XS/main/tree.c                          |   7 +-
 tp/Texinfo/XS/main/tree_types.h                    |   3 +-
 tp/Texinfo/XS/main/unicode.c                       |  14 +-
 tp/Texinfo/XS/main/utils.c                         |  52 ++-
 tp/Texinfo/XS/parsetexi/close.c                    | 154 +++----
 tp/Texinfo/XS/parsetexi/commands.h                 |   2 +-
 tp/Texinfo/XS/parsetexi/debug_parser.c             |   8 +-
 tp/Texinfo/XS/parsetexi/def.c                      |  12 +-
 tp/Texinfo/XS/parsetexi/end_line.c                 |  94 +++--
 tp/Texinfo/XS/parsetexi/handle_commands.c          |  42 +-
 tp/Texinfo/XS/parsetexi/indices.c                  |  19 +-
 tp/Texinfo/XS/parsetexi/macro.c                    |  18 +-
 tp/Texinfo/XS/parsetexi/menus.c                    |   4 +-
 tp/Texinfo/XS/parsetexi/multitable.c               |  53 ++-
 tp/Texinfo/XS/parsetexi/parser.c                   | 205 +++++----
 tp/Texinfo/XS/parsetexi/separator.c                | 109 +++--
 tp/Texinfo/XS/structuring_transfo/structuring.c    |  63 +--
 .../XS/structuring_transfo/transformations.c       |  71 ++--
 tp/t/05paragraph.t                                 |  20 +
 .../indent_before_macro_definition_and_other.pl    | 463 +++++++++++++++++++++
 tp/t/test_document.t                               |  12 +-
 45 files changed, 1382 insertions(+), 753 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dd388ab037..fd48871e50 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,64 @@
+2024-06-15  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/ParserNonXS.pm (_close_command_cleanup): separate
+       multitable head and body only if the multitable has contents.
+
+       * tp/Texinfo/ParserNonXS.pm (_close_command_cleanup),
+       tp/Texinfo/XS/parsetexi/close.c (close_command_cleanup): update code
+       taking into account that
+       i) there cannot be ignorable_spaces_after_command before before_item,
+       as it is added only after commands, and inside commands arguments.  
+       ii) there cannot be an @end in before_item, as soon as an @end is seen
+       it is popped from the element it is in, before closing.
+       iii) there can only be before_item or elements associated with @*item
+       directly in block item at commands.
+
+       * tp/Texinfo/XS/parsetexi/utils.c (item_line_parent): use explicit
+       command enums.
+
+       * tp/Texinfo/XS/main/convert_utils.c
+       (find_root_command_next_heading_command): fix condition.
+
+       * tp/Texinfo/ParserNonXS.pm (_expand_macro_arguments): fix condition.
+
+       * tp/Texinfo/Document.pm (new_document): do not initialize explicitely
+       'included_files' to give the same output as with XS.
+
+       * tp/Texinfo/XS/main/manipulate_indices.c
+       (idx_leading_text_or_command), tp/Texinfo/Indices.pm
+       (_idx_leading_text_or_command), tp/Texinfo/XS/main/utils.c
+       (is_content_empty), tp/Texinfo/Common.pm (is_content_empty): handle
+       text element first.
+
+       * tp/Texinfo/XS/main/node_name_normalization.c
+       (convert_to_normalized_internal),
+       tp/Texinfo/Convert/NodeNameNormalization.pm (%ignored_text_types)
+       (_convert): handle text first, including ignored text types, and the
+       remaining elements afterwards.
+
+       * tp/Texinfo/Translations.pm (_substitute_element_array),
+       tp/Texinfo/XS/main/translations.c (substitute_element_array): check
+       for text first, as there is no recursion in that case.
+
+       * tp/Texinfo/XS/main/tree_types.h (CONTAINER, ELEMENT),
+       tp/Texinfo/XS/main/tree.c (new_command_element),
+       tp/Texinfo/XS/parsetexi/end_line.c (end_line_starting_block),
+       tp/Texinfo/XS/parsetexi/indices.c
+       (set_non_ignored_space_in_index_before_command): move cmd from
+       ELEMENT to CONTAINER, as text element do not have a command name.
+       Update users, making sure in particular that element_command_name,
+       element_builtin_cmd, element_builtin_data_cmd and similar functions
+       and macros are never called for a text element.
+
+       * tp/Texinfo/XS/parsetexi/separator.c (handle_open_brace): rename
+       command variable as cmd.
+
+       * tp/t/test_document.t: fix the calls to is().
+
+       * tp/Makefile.tres, tp/t/05paragraph.t
+       (indent_before_macro_definition_and_other): add test with command that
+       are skipped between @indent and the next paragraph.
+
 2024-06-13  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/XS/main/tree_types.h (KEY_PAIR),
diff --git a/tp/Makefile.tres b/tp/Makefile.tres
index 3d4fe8c96a..7c92b9c843 100644
--- a/tp/Makefile.tres
+++ b/tp/Makefile.tres
@@ -1712,6 +1712,7 @@ test_files_generated_list = 
$(test_tap_files_generated_list) \
   t/results/paragraph/comment_in_quotation.pl \
   t/results/paragraph/double_style_paragraph.pl \
   t/results/paragraph/image_in_paragraph.pl \
+  t/results/paragraph/indent_before_macro_definition_and_other.pl \
   t/results/paragraph/no_paragraph_commands.pl \
   t/results/paragraph/paragraph_command.pl \
   t/results/paragraph/paragraph_count_and_example.pl \
diff --git a/tp/Texinfo/Common.pm b/tp/Texinfo/Common.pm
index 94713d8558..a9ba2c254f 100644
--- a/tp/Texinfo/Common.pm
+++ b/tp/Texinfo/Common.pm
@@ -1574,6 +1574,13 @@ sub is_content_empty($;$)
     return 1;
   }
   foreach my $content (@{$tree->{'contents'}}) {
+    if (defined($content->{'text'})) {
+      if ($content->{'text'} =~ /\S/) {
+        return 0;
+      } else {
+        next;
+      }
+    }
     if ($content->{'cmdname'}) {
       if ($content->{'type'} and $content->{'type'} eq 'index_entry_command') {
         if ($do_not_ignore_index_entries) {
@@ -1607,9 +1614,6 @@ sub is_content_empty($;$)
         return 0;
       }
     }
-    if (defined($content->{'text'}) and $content->{'text'} =~ /\S/) {
-      return 0;
-    }
     if (not is_content_empty($content, $do_not_ignore_index_entries)) {
       return 0;
     }
diff --git a/tp/Texinfo/Convert/NodeNameNormalization.pm 
b/tp/Texinfo/Convert/NodeNameNormalization.pm
index 9af104eb85..8276b3331d 100644
--- a/tp/Texinfo/Convert/NodeNameNormalization.pm
+++ b/tp/Texinfo/Convert/NodeNameNormalization.pm
@@ -80,14 +80,20 @@ foreach my $ignored_brace_command ('anchor', 'footnote', 
'shortcaption',
   $ignored_brace_commands{$ignored_brace_command} = 1;
 }
 
-my %ignored_types;
-foreach my $type ('ignorable_spaces_after_command',
-            'postamble_after_end',
-            'preamble_before_beginning',
+my %ignored_text_types;
+foreach my $type (
+            'ignorable_spaces_after_command',
             'spaces_at_end',
             'spaces_before_paragraph',
             'space_at_end_menu_node',
             'spaces_after_close_brace') {
+  $ignored_text_types{$type} = 1;
+}
+
+my %ignored_types;
+foreach my $type (
+            'postamble_after_end',
+            'preamble_before_beginning') {
   $ignored_types{$type} = 1;
 }
 
@@ -258,6 +264,14 @@ sub _convert($)
 {
   my $element = shift;
 
+  if (defined($element->{'text'})) {
+    return ''
+      if ($element->{'type'} and $ignored_text_types{$element->{'type'}});
+    my $result = $element->{'text'};
+    $result =~ s/\s+/ /g;
+    return $result;
+  }
+
   return '' if (($element->{'type'} and $ignored_types{$element->{'type'}})
           or ($element->{'cmdname'}
              and ($ignored_brace_commands{$element->{'cmdname'}}
@@ -266,11 +280,6 @@ sub _convert($)
                      and $element->{'args'}->[0]->{'type'}
                      and ($element->{'args'}->[0]->{'type'} eq 'line_arg'
                          or $element->{'args'}->[0]->{'type'} eq 
'rawline_arg')))));
-  my $result = '';
-  if (defined($element->{'text'})) {
-    $result = $element->{'text'};
-    $result =~ s/\s+/ /g;
-  }
   if ($element->{'cmdname'}) {
     my $cmdname = $element->{'cmdname'};
     if (defined($normalize_node_nobrace_symbol_text{$cmdname})) {
@@ -319,6 +328,7 @@ sub _convert($)
       return _convert($element->{'args'}->[0]);
     }
   }
+  my $result = '';
   if ($element->{'contents'}) {
     foreach my $content (@{$element->{'contents'}}) {
       $result .= _convert($content);
diff --git a/tp/Texinfo/Document.pm b/tp/Texinfo/Document.pm
index 7557bed127..92b99d96a5 100644
--- a/tp/Texinfo/Document.pm
+++ b/tp/Texinfo/Document.pm
@@ -106,7 +106,8 @@ sub new_document($)
     'internal_references' => [],
     'global_info' => {'input_perl_encoding' => 'utf-8',
                     'input_encoding_name' => 'utf-8',
-                    'included_files' => [],},
+                    #'included_files' => [],
+                    },
     'commands_info' => {},
     'identifiers_target' => {},
     'labels_list' => [],
diff --git a/tp/Texinfo/Indices.pm b/tp/Texinfo/Indices.pm
index c3ac4bc453..1a22d404a7 100644
--- a/tp/Texinfo/Indices.pm
+++ b/tp/Texinfo/Indices.pm
@@ -508,6 +508,21 @@ sub _idx_leading_text_or_command($$)
 
   return (undef, undef) if (!$tree->{'contents'});
   foreach my $content (@{$tree->{'contents'}}) {
+    if (defined($content->{'text'})) {
+      if ($content->{'text'} =~ /\S/) {
+        my $result_text = $content->{'text'};
+        $result_text =~ s/^\s*//;
+        if (defined($ignore_chars)) {
+          $result_text =~ s/[$ignore_chars]//g;
+          $result_text =~ s/^\s*//;
+          next if ($result_text eq '');
+        }
+        return ($result_text, undef);
+      } else {
+        next;
+      }
+    }
+
     if ($content->{'cmdname'}) {
       my $cmdname = $content->{'cmdname'};
       if ($Texinfo::Commands::formatted_nobrace_commands{$cmdname}) {
@@ -547,15 +562,6 @@ sub _idx_leading_text_or_command($$)
                                               $ignore_chars);
         }
       }
-    } elsif (defined($content->{'text'}) and $content->{'text'} =~ /\S/) {
-      my $result_text = $content->{'text'};
-      $result_text =~ s/^\s*//;
-      if (defined($ignore_chars)) {
-        $result_text =~ s/[$ignore_chars]//g;
-        $result_text =~ s/^\s*//;
-        next if ($result_text eq '');
-      }
-      return ($result_text, undef);
     } elsif ($content->{'contents'}) {
       return _idx_leading_text_or_command($content, $ignore_chars);
     }
diff --git a/tp/Texinfo/ParserNonXS.pm b/tp/Texinfo/ParserNonXS.pm
index abbe3ee122..4fbd334ae7 100644
--- a/tp/Texinfo/ParserNonXS.pm
+++ b/tp/Texinfo/ParserNonXS.pm
@@ -1940,31 +1940,32 @@ sub _close_command_cleanup($$) {
   # tree.  Also determine the multitable_body and multitable_head with
   # @item or @headitem rows.
   if ($current->{'cmdname'} eq 'multitable') {
-    my $in_head_or_rows;
-    my @contents;
-    @contents = @{$current->{'contents'}} if ($current->{'contents'});
-    $current->{'contents'} = [];
-    foreach my $row (@contents) {
-      if ($row->{'type'} and $row->{'type'} eq 'row') {
-        delete $row->{'cells_count'};
-        if ($row->{'contents'}->[0]->{'cmdname'} eq 'headitem') {
-          if (!$in_head_or_rows) {
-            push @{$current->{'contents'}}, {'type' => 'multitable_head',
-                                             'parent' => $current};
-            $in_head_or_rows = 1;
-          }
-        } elsif ($row->{'contents'}->[0]->{'cmdname'} eq 'item') {
-          if (!defined($in_head_or_rows) or $in_head_or_rows) {
-            push @{$current->{'contents'}}, {'type' => 'multitable_body',
-                                             'parent' => $current};
-            $in_head_or_rows = 0;
+    if ($current->{'contents'}) {
+      my $in_head_or_rows;
+      my @contents = @{$current->{'contents'}};
+      $current->{'contents'} = [];
+      foreach my $row (@contents) {
+        if ($row->{'type'} and $row->{'type'} eq 'row') {
+          delete $row->{'cells_count'};
+          if ($row->{'contents'}->[0]->{'cmdname'} eq 'headitem') {
+            if (!$in_head_or_rows) {
+              push @{$current->{'contents'}}, {'type' => 'multitable_head',
+                                               'parent' => $current};
+              $in_head_or_rows = 1;
+            }
+          } elsif ($row->{'contents'}->[0]->{'cmdname'} eq 'item') {
+            if (!defined($in_head_or_rows) or $in_head_or_rows) {
+              push @{$current->{'contents'}}, {'type' => 'multitable_body',
+                                               'parent' => $current};
+              $in_head_or_rows = 0;
+            }
           }
+          push @{$current->{'contents'}->[-1]->{'contents'}}, $row;
+          $row->{'parent'} = $current->{'contents'}->[-1];
+        } else {
+          push @{$current->{'contents'}}, $row;
+          $in_head_or_rows = undef;
         }
-        push @{$current->{'contents'}->[-1]->{'contents'}}, $row;
-        $row->{'parent'} = $current->{'contents'}->[-1];
-      } else {
-        push @{$current->{'contents'}}, $row;
-        $in_head_or_rows = undef;
       }
     }
   } elsif ($block_commands{$current->{'cmdname'}}
@@ -1995,72 +1996,34 @@ sub _close_command_cleanup($$) {
   # remove empty before_item.
   # warn if not empty before_item, but format is empty
   if ($blockitem_commands{$current->{'cmdname'}}) {
-    if ($current->{'contents'} and scalar(@{$current->{'contents'}})) {
-      my $leading_spaces = 0;
-      my $before_item;
-      if ($current->{'contents'}->[0]->{'type'}
-          and $current->{'contents'}->[0]->{'type'} eq 
'ignorable_spaces_after_command'
-          and $current->{'contents'}->[1]
-          and $current->{'contents'}->[1]->{'type'}
-          and $current->{'contents'}->[1]->{'type'} eq 'before_item') {
-        $leading_spaces = 1;
-        $before_item = $current->{'contents'}->[1];
-      } elsif ($current->{'contents'}->[0]->{'type'}
-              and $current->{'contents'}->[0]->{'type'} eq 'before_item') {
-        $before_item = $current->{'contents'}->[0];
-      }
-      if ($before_item) {
-        if ($before_item->{'contents'}
-            and scalar(@{$before_item->{'contents'}}) > 0
-            and $before_item->{'contents'}->[-1]->{'cmdname'}
-            and $before_item->{'contents'}->[-1]->{'cmdname'} eq 'end') {
-          my $end = _pop_element_from_contents($self, $before_item);
-          $end->{'parent'} = $current;
-          push @{$current->{'contents'}}, $end;
-        }
-        # remove empty before_items.  Both conditions can happen, the first
-        # if the before item remained empty, the second if after removing end
-        # and spaces it became empty.
-        if (_is_container_empty($before_item)
-            and not $before_item->{'source_marks'}) {
-          if ($leading_spaces) {
-            my $space = shift @{$current->{'contents'}};
-            shift @{$current->{'contents'}};
-            unshift @{$current->{'contents'}}, $space;
-          } else {
-            shift @{$current->{'contents'}};
-          }
-        } else {
-          # warn if not empty before_item, but format is empty
+    if ($current->{'contents'}
+        and $current->{'contents'}->[0]->{'type'}
+        and $current->{'contents'}->[0]->{'type'} eq 'before_item') {
+      my $before_item = $current->{'contents'}->[0];
+      if (_is_container_empty($before_item)
+          and not $before_item->{'source_marks'}) {
+        # remove empty before_item
+        shift @{$current->{'contents'}};
+      } else {
+        # The elements that can appear right in a block item command
+        # besides before_item are either an @*item or are associated
+        # with items
+        if (scalar(@{$current->{'contents'}}) == 1) {
+          # no @*item, only before_item.  Warn if before_item is not empty
           my $empty_before_item = 1;
           if ($before_item->{'contents'}) {
             foreach my $before_item_content (@{$before_item->{'contents'}}) {
-              if (!$before_item_content->{'cmdname'} or
-                    ($before_item_content->{'cmdname'} ne 'c'
-                     and $before_item_content->{'cmdname'} ne 'comment')) {
+              if (!$before_item_content->{'cmdname'}
+                 or ($before_item_content->{'cmdname'} ne 'c'
+                      and $before_item_content->{'cmdname'} ne 'comment')) {
                 $empty_before_item = 0;
                 last;
               }
             }
           }
           if (!$empty_before_item) {
-            my $empty_format = 1;
-            foreach my $format_content (@{$current->{'contents'}}) {
-              next if ($format_content eq $before_item);
-              if (($format_content->{'cmdname'}
-                   and ($format_content->{'cmdname'} ne 'c'
-                        and $format_content->{'cmdname'} ne 'comment'
-                        and $format_content->{'cmdname'} ne 'end'))
-                  or ($format_content->{'type'} and
-                   ($format_content->{'type'} ne 
'ignorable_spaces_after_command'))) {
-                $empty_format = 0;
-                last;
-              }
-            }
-            if ($empty_format) {
-              $self->_line_warn(sprintf(__("\@%s has text but no \@item"),
-                           $current->{'cmdname'}), $current->{'source_info'});
-            }
+            $self->_line_warn(sprintf(__("\@%s has text but no \@item"),
+                         $current->{'cmdname'}), $current->{'source_info'});
           }
         }
       }
@@ -2658,7 +2621,7 @@ sub _expand_macro_arguments($$$$$)
 
   $line =~ s/^{(\s*)//;
   if ($1 ne '') {
-    $argument->{'info'} = {} if (!$current->{'info'});
+    $argument->{'info'} = {} if (!$argument->{'info'});
     $argument->{'info'}->{'spaces_before_argument'} = {'text' => $1};
   }
 
@@ -4687,8 +4650,12 @@ sub _end_line($$$)
   return $current;
 }
 
-# $command may be undef if we are after a wrong other command such as
-# a buggy @tab.
+# Add an "ignorable_spaces_after_command" element containing the
+# whitespace at the beginning of the rest of the line after skipspaces
+# commands, if COMMAND is undef.  Otherwise add an
+# "internal_spaces_after_command" text element, after line commands
+# or commands starting a block, that will end up in COMMAND info
+# spaces_before_argument.
 sub _start_empty_line_after_command($$$$) {
   my ($self, $line, $current, $command) = @_;
 
diff --git a/tp/Texinfo/Translations.pm b/tp/Texinfo/Translations.pm
index ef74689de0..46e7e26111 100644
--- a/tp/Texinfo/Translations.pm
+++ b/tp/Texinfo/Translations.pm
@@ -360,13 +360,16 @@ sub _substitute_element_array($$) {
 
   for (my $idx = 0; $idx < $nr; $idx++) {
     my $element = $array->[$idx];
-    if ($element->{'cmdname'} and $element->{'cmdname'} eq 'txiinternalvalue') 
{
-      my $name = $element->{'args'}->[0]->{'contents'}->[0]->{'text'};
-      if ($replaced_substrings->{$name}) {
-        $array->[$idx] = $replaced_substrings->{$name};
+    if (!defined($element->{'text'})) {
+      if ($element->{'cmdname'}
+          and $element->{'cmdname'} eq 'txiinternalvalue') {
+        my $name = $element->{'args'}->[0]->{'contents'}->[0]->{'text'};
+        if ($replaced_substrings->{$name}) {
+          $array->[$idx] = $replaced_substrings->{$name};
+        }
+      } else {
+        _substitute($element, $replaced_substrings);
       }
-    } else {
-      _substitute($element, $replaced_substrings);
     }
   }
 }
diff --git a/tp/Texinfo/XS/convert/call_html_perl_function.c 
b/tp/Texinfo/XS/convert/call_html_perl_function.c
index 46fdbcb349..e00680e497 100644
--- a/tp/Texinfo/XS/convert/call_html_perl_function.c
+++ b/tp/Texinfo/XS/convert/call_html_perl_function.c
@@ -2007,7 +2007,11 @@ call_commands_conversion (CONVERTER *self, const enum 
command_id cmd,
 
   build_tree_to_build (&self->tree_to_build);
 
-  /* could also be builtin_command_data[cmd].cmdname) */
+  /* could also be builtin_command_data[cmd].cmdname as cmd
+     can only be < BUILTIN_CMD_NUMBER for two reasons:
+      - cmd is element_builtin_cmd (element) in convert_to_html_internal
+      - registered cmd are < BUILTIN_CMD_NUMBER
+   */
   command_name = element_command_name (element);
 
   formatting_reference_sv = formatting_reference->sv_reference;
@@ -2075,7 +2079,11 @@ call_commands_open (CONVERTER *self, const enum 
command_id cmd,
 
   formatting_reference_sv = self->commands_open[cmd].sv_reference;
 
-  /* could also be builtin_command_data[cmd].cmdname) */
+  /* could also be builtin_command_data[cmd].cmdname as cmd
+     can only be < BUILTIN_CMD_NUMBER for two reasons:
+      - cmd is element_builtin_cmd (element) in convert_to_html_internal
+      - registered cmd are < BUILTIN_CMD_NUMBER
+   */
   command_name = element_command_name (element);
 
   if (self->modified_state)
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index f778944804..eebe12ac2d 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -478,7 +478,7 @@ get_element_root_command_element (CONVERTER *self, const 
ELEMENT *command)
       const ELEMENT *root_command = root_unit->root;
       if (self->conf->USE_NODES.o.integer > 0)
         {
-          if (root_command->cmd != CM_node)
+          if (root_command->e.c->cmd != CM_node)
             {
               const ELEMENT *associated_node =
                            lookup_extra_element (root_command,
@@ -487,7 +487,7 @@ get_element_root_command_element (CONVERTER *self, const 
ELEMENT *command)
                 root_unit->root = associated_node;
             }
         }
-      else if (root_command->cmd == CM_node)
+      else if (root_command->e.c->cmd == CM_node)
         {
           const ELEMENT *associated_section
                               = lookup_extra_element (root_command,
@@ -2083,7 +2083,7 @@ new_sectioning_command_target (CONVERTER *self, const 
ELEMENT *command)
 
   target_base = normalized_to_id (normalized_name);
 
-  if (!strlen (target_base) && command->cmd == CM_top)
+  if (!strlen (target_base) && command->e.c->cmd == CM_top)
     {
       /* @top is allowed to be empty.  In that case it gets this target name */
       free (target_base);
@@ -3530,7 +3530,7 @@ html_command_node (CONVERTER *self, const ELEMENT 
*command)
               if (root_unit->root)
                 {
                   const ELEMENT *root_command = root_unit->root;
-                  if (root_command && root_command->cmd == CM_node)
+                  if (root_command && root_command->e.c->cmd == CM_node)
                     target_info->node_command = root_command;
                   else
                     {
@@ -3898,14 +3898,15 @@ html_internal_command_tree (CONVERTER *self, const 
ELEMENT *command,
                                    SUIT_type_heading, special_unit_variety);
               tree->tree = heading_tree;
             }
-          else if (command->cmd == CM_node || command->cmd == CM_anchor)
+          else if (command->e.c->cmd == CM_node
+                   || command->e.c->cmd == CM_anchor)
             {
               ELEMENT *root_code = new_element_added (tree, ET__code);
               add_to_contents_as_array (root_code, command->e.c->args.list[0]);
               tree->tree = root_code;
               add_tree_to_build (self, tree->tree);
             }
-          else if (command->cmd == CM_float)
+          else if (command->e.c->cmd == CM_float)
             {
               tree->tree = float_type_number (self, command);
               tree->status = tree_added_status_new_tree;
@@ -3935,7 +3936,7 @@ html_internal_command_tree (CONVERTER *self, const 
ELEMENT *command,
                   add_element_to_named_string_element_list (
                               replaced_substrings, "number", e_number);
 
-                  if (command->cmd == CM_appendix)
+                  if (command->e.c->cmd == CM_appendix)
                     {
                       int status;
                       int section_level = lookup_extra_integer (command,
@@ -4047,7 +4048,7 @@ html_internal_command_text (CONVERTER *self, const 
ELEMENT *command,
           if (!command_tree->tree)
             return strdup ("");
 
-          if (command->cmd)
+          if (command->e.c->cmd)
             {
               const char *command_name = element_command_name (command);
               context_name = command_name;
@@ -4140,7 +4141,7 @@ html_command_text (CONVERTER *self, const ELEMENT 
*command,
       else
         tree_root = command_tree->tree;
 
-      if (command->cmd)
+      if (command->e.c->cmd)
         /* this never happens, as the external node label tree
            element is never directly an @-command.  It can be an @-command
            argument, in a menu, or a reconstituted tree. */
@@ -4371,7 +4372,7 @@ from_element_direction (CONVERTER *self, int direction,
         {
           if (target_unit->unit_command)
             {
-              if (target_unit->unit_command->cmd == CM_node)
+              if (target_unit->unit_command->e.c->cmd == CM_node)
                 command = target_unit->unit_command;
               else
                 {
@@ -4388,7 +4389,7 @@ from_element_direction (CONVERTER *self, int direction,
         {
           if (target_unit->unit_command)
             {
-              if (target_unit->unit_command->cmd != CM_node)
+              if (target_unit->unit_command->e.c->cmd != CM_node)
                 command = target_unit->unit_command;
               else
                 {
@@ -5297,7 +5298,7 @@ html_prepare_output_units_global_targets (CONVERTER *self)
         {
           const OUTPUT_UNIT *document_unit = root_unit->output_unit;
           const ELEMENT *root_command = root_unit->root;
-          if (root_command && root_command->cmd == CM_node)
+          if (root_command && root_command->e.c->cmd == CM_node)
             {
               const ELEMENT *associated_section
                 = lookup_extra_element (root_command,
@@ -5307,7 +5308,7 @@ html_prepare_output_units_global_targets (CONVERTER *self)
             }
        /* find the first level 1 sectioning element to associate the printindex
            with */
-          if (root_command && root_command->cmd != CM_node)
+          if (root_command && root_command->e.c->cmd != CM_node)
             {
               while (1)
                 {
@@ -5583,7 +5584,7 @@ html_set_pages_files (CONVERTER *self, const 
OUTPUT_UNIT_LIST *output_units,
                 {
                   const ELEMENT *root_command
                      = file_output_unit->unit_contents.list[j];
-                  if (root_command->cmd == CM_node)
+                  if (root_command->e.c->cmd == CM_node)
                     {
                       const ELEMENT *node_target = 0;
                       const char *normalized = lookup_extra_string 
(root_command,
@@ -5660,7 +5661,7 @@ html_set_pages_files (CONVERTER *self, const 
OUTPUT_UNIT_LIST *output_units,
                   const ELEMENT *command = file_output_unit->unit_command;
                   if (command)
                     {
-                      if (command->cmd == CM_top && !node_top
+                      if (command->e.c->cmd == CM_top && !node_top
                           && top_node_filename_str)
                         {
                    /* existing top_node_filename can happen, see
@@ -6431,7 +6432,7 @@ html_default_format_contents (CONVERTER *self, const enum 
command_id cmd,
                                                    &status);
          const ELEMENT_LIST *section_childs
            = lookup_extra_contents (section, AI_key_section_childs);
-         if (section->cmd != CM_top)
+         if (section->e.c->cmd != CM_top)
             {
               char *text;
               char *href;
@@ -6513,7 +6514,7 @@ html_default_format_contents (CONVERTER *self, const enum 
command_id cmd,
                = lookup_extra_directions (section, AI_key_section_directions);
               if (section_directions
                   && section_directions->list[D_next]
-                  && section->cmd != CM_top)
+                  && section->e.c->cmd != CM_top)
                 {
                   text_append_n (&result, "</li>\n", 6);
                   if (section == top_section)
@@ -6525,7 +6526,7 @@ html_default_format_contents (CONVERTER *self, const enum 
command_id cmd,
                   int is_top_section = 0;
                   if (section == top_section)
                     {
-                      if (section->cmd != CM_top)
+                      if (section->e.c->cmd != CM_top)
                         text_append_n (&result, "</li>\n", 6);
                       break;
                     }
@@ -7278,7 +7279,7 @@ file_header_information (CONVERTER *self, const ELEMENT 
*command,
 
           add_tree_to_build (self, title_tree);
 
-          if (command->cmd)
+          if (command->e.c->cmd)
             xasprintf (&context_str, "file_header_title-element-@%s",
                        element_command_name (command));
           else if (command->type)
@@ -7508,7 +7509,7 @@ html_default_format_begin_file (CONVERTER *self, const 
char *filename,
   if (output_unit)
     {
       element_command = output_unit->unit_command;
-      if (element_command && element_command->cmd != CM_node)
+      if (element_command && element_command->e.c->cmd != CM_node)
         {
           node_command = lookup_extra_element (element_command,
                                                AI_key_associated_node);
@@ -8290,7 +8291,7 @@ html_default_format_element_header (CONVERTER *self,
 
   /* Do the heading if the command is the first command in the element */
   if ((output_unit->unit_contents.list[0] == command
-       || (!output_unit->unit_contents.list[0]->cmd
+       || (!output_unit->unit_contents.list[0]->e.c->cmd
            && output_unit->unit_contents.list[1] == command))
         /* and there is more than one element */
       && (output_unit->tree_unit_directions[D_next]
@@ -9754,12 +9755,12 @@ html_accent_entities_html_accent_internal (CONVERTER 
*self, const char *text,
 
   /* do not return a dotless i or j as such if it is further composed
      with an accented letter, return the letter as is */
-  if (element->cmd == CM_dotless
+  if (element->e.c->cmd == CM_dotless
   /* corresponds to perl exists unicode_accented_letters{accent}->{text} */
       && (!strcmp (text_set, "i") || !strcmp (text_set, "j")))
     {
       if (element->parent && element->parent->parent
-          && element->parent->parent->cmd)
+          && element->parent->parent->e.c->cmd)
         {
           enum command_id p_cmd
             = element_builtin_cmd (element->parent->parent);
@@ -9774,7 +9775,7 @@ html_accent_entities_html_accent_internal (CONVERTER 
*self, const char *text,
   if (use_numeric_entities)
     {
       char *formatted_accent
-        = xml_numeric_entity_accent (element->cmd, text_set);
+        = xml_numeric_entity_accent (element->e.c->cmd, text_set);
       if (formatted_accent)
         {
           free (text_set);
@@ -9785,18 +9786,19 @@ html_accent_entities_html_accent_internal (CONVERTER 
*self, const char *text,
     {
       char *formatted_accent;
       if (strlen (text_set) == 1 && isascii_alpha (*text_set)
-          && self->accent_entities[element->cmd].entity
-          && self->accent_entities[element->cmd].characters
-          && strlen (self->accent_entities[element->cmd].characters)
-          && strrchr (self->accent_entities[element->cmd].characters,
+          && self->accent_entities[element->e.c->cmd].entity
+          && self->accent_entities[element->e.c->cmd].characters
+          && strlen (self->accent_entities[element->e.c->cmd].characters)
+          && strrchr (self->accent_entities[element->e.c->cmd].characters,
                        *text_set))
         {
           xasprintf (&formatted_accent, "&%s%s;", text_set,
-                     self->accent_entities[element->cmd].entity);
+                     self->accent_entities[element->e.c->cmd].entity);
           free (text_set);
           return formatted_accent;
         }
-      formatted_accent = xml_numeric_entity_accent (element->cmd, text_set);
+      formatted_accent = xml_numeric_entity_accent (element->e.c->cmd,
+                                                    text_set);
       if (formatted_accent)
         {
           free (text_set);
@@ -9878,7 +9880,7 @@ css_string_accent (CONVERTER *self, const char *text,
 {
   char *text_set = set_case_if_only_word_characters (text, set_case);
 
-  if (element->cmd == CM_dotless)
+  if (element->e.c->cmd == CM_dotless)
     {
       /* corresponds in perl, and for dotless, to
  Texinfo::Convert::Unicode::unicode_accented_letters{$accent}->{$text} */
@@ -9894,13 +9896,13 @@ css_string_accent (CONVERTER *self, const char *text,
         }
     }
 
-  if (unicode_diacritics[element->cmd].text)
+  if (unicode_diacritics[element->e.c->cmd].text)
     {
       char *accent_and_diacritic;
       char *normalized_accent_text;
       static TEXT accented_text;
       text_init (&accented_text);
-      if (element->cmd == CM_tieaccent)
+      if (element->e.c->cmd == CM_tieaccent)
         {
           /* tieaccent diacritic is naturally and correctly composed
              between two characters */
@@ -9982,7 +9984,7 @@ css_string_accent (CONVERTER *self, const char *text,
 
                   /* add the tie accent */
                   text_printf (&accented_text, "\\%s ",
-                               unicode_diacritics[element->cmd].hex_codepoint);
+                         unicode_diacritics[element->e.c->cmd].hex_codepoint);
                   /* add the remaining, second character or escaped text
                      and everything else after (which is in general invalid
                      but we do not care) */
@@ -10005,7 +10007,7 @@ css_string_accent (CONVERTER *self, const char *text,
          if yes use the merged character, if not output text and diacitic
          to be set up for composition */
       xasprintf (&accent_and_diacritic, "%s%s",
-                 text, unicode_diacritics[element->cmd].text);
+                 text, unicode_diacritics[element->e.c->cmd].text);
       normalized_accent_text = normalize_NFC (accent_and_diacritic);
       free (accent_and_diacritic);
       /* check if the normalization led to merging text and diacritic
@@ -10017,7 +10019,7 @@ css_string_accent (CONVERTER *self, const char *text,
              such that they could be composed */
           text_append (&accented_text, text);
           text_printf (&accented_text, "\\%s ",
-                   unicode_diacritics[element->cmd].hex_codepoint);
+                   unicode_diacritics[element->e.c->cmd].hex_codepoint);
         }
       else
         {
@@ -10332,7 +10334,7 @@ convert_heading_command (CONVERTER *self, const enum 
command_id cmd,
   /* No situation where this could happen */
   if (html_in_string (self))
     {
-      if (element->cmd != CM_node)
+      if (element->e.c->cmd != CM_node)
         {
           char *heading = html_command_text (self, element, HTT_string);
           text_append (result, heading);
@@ -10366,7 +10368,7 @@ convert_heading_command (CONVERTER *self, const enum 
command_id cmd,
 
   text_init (&tables_of_contents);
   text_append (&tables_of_contents, "");
-  if (element->cmd == CM_top
+  if (element->e.c->cmd == CM_top
       && self->conf->CONTENTS_OUTPUT_LOCATION.o.string
       && !strcmp (self->conf->CONTENTS_OUTPUT_LOCATION.o.string, "after_top")
       && self->document->sections_list
@@ -11573,7 +11575,7 @@ convert_float_command (CONVERTER *self, const enum 
command_id cmd,
     }
 
   if (caption_element)
-    caption_command_name = builtin_command_name (caption_element->cmd);
+    caption_command_name = builtin_command_name (caption_element->e.c->cmd);
 
   classes = new_string_list ();
   add_string (builtin_command_name (cmd), classes);
@@ -11928,7 +11930,7 @@ convert_itemize_command (CONVERTER *self, const enum 
command_id cmd,
                                               AI_key_command_as_argument);
   if (command_as_argument)
     {
-      if (command_as_argument->cmd == CM_click)
+      if (command_as_argument->e.c->cmd == CM_click)
         {
           command_as_argument_name = lookup_extra_string (command_as_argument,
                                                           AI_key_clickstyle);
@@ -12453,7 +12455,7 @@ convert_xref_commands (CONVERTER *self, const enum 
command_id cmd,
               else
                 name = html_command_text (self, target_root, 
HTT_text_nonumber);
             }
-          else if (target_node->cmd == CM_float)
+          else if (target_node->e.c->cmd == CM_float)
             {
               if (self->conf->XREF_USE_FLOAT_LABEL.o.integer <= 0)
                 {
@@ -14912,7 +14914,7 @@ convert_menu_entry_type (CONVERTER *self, const enum 
element_type type,
                          formatted_nodedescription_nr);
             }
 
-          if (node_description->cmd == CM_nodedescription)
+          if (node_description->e.c->cmd == CM_nodedescription)
             description_element = node_description->e.c->args.list[0];
           else
             {
@@ -14934,7 +14936,7 @@ convert_menu_entry_type (CONVERTER *self, const enum 
element_type type,
 
           if (formatted_nodedescription_nr > 1)
             free (multiple_formatted);
-          if (node_description->cmd != CM_nodedescription)
+          if (node_description->e.c->cmd != CM_nodedescription)
             {
               remove_tree_to_build (self, description_element);
               description_element->e.c->contents.list = 0;
@@ -15060,7 +15062,7 @@ convert_menu_entry_type (CONVERTER *self, const enum 
element_type type,
                          formatted_nodedescription_nr);
             }
 
-          if (node_description->cmd == CM_nodedescription)
+          if (node_description->e.c->cmd == CM_nodedescription)
             description_element = node_description->e.c->args.list[0];
           else
             {
@@ -15076,7 +15078,7 @@ convert_menu_entry_type (CONVERTER *self, const enum 
element_type type,
 
           if (formatted_nodedescription_nr > 1)
             free (multiple_formatted);
-          if (node_description->cmd != CM_nodedescription)
+          if (node_description->e.c->cmd != CM_nodedescription)
             {
               remove_tree_to_build (self, description_element);
               description_element->e.c->contents.list = 0;
@@ -15232,10 +15234,10 @@ convert_def_line_type (CONVERTER *self, const enum 
element_type type,
 
   parsed_def = definition_arguments_content (element);
 
-  if (element->cmd)
-    original_def_cmd = element->cmd;
+  if (element->e.c->cmd)
+    original_def_cmd = element->e.c->cmd;
   else
-    original_def_cmd = element->parent->cmd;
+    original_def_cmd = element->parent->e.c->cmd;
 
   if (builtin_command_data[original_def_cmd].flags & CF_def_alias)
     {
@@ -15257,11 +15259,11 @@ convert_def_line_type (CONVERTER *self, const enum 
element_type type,
     original_cmd = original_def_cmd;
 
   /* parent is defblock, we do not put it in class */
-  if (element->cmd == CM_defline || element->cmd == CM_deftypeline)
-    def_cmd = element->cmd;
+  if (element->e.c->cmd == CM_defline || element->e.c->cmd == CM_deftypeline)
+    def_cmd = element->e.c->cmd;
   else
   /* the parent is the def both for def* def_line and def*x */
-    def_cmd = element->parent->cmd;
+    def_cmd = element->parent->e.c->cmd;
 
   if (builtin_command_data[def_cmd].flags & CF_def_alias)
     {
@@ -18556,8 +18558,7 @@ convert_to_html_internal (CONVERTER *self, const 
ELEMENT *element,
     }
 
   if (cmd
-      && (element->type != ET_def_line
-          && element->type != ET_definfoenclose_command
+      && (element->type != ET_definfoenclose_command
           && element->type != ET_index_entry_command))
     {
       enum command_id data_cmd = element_builtin_data_cmd (element);
@@ -18836,7 +18837,7 @@ convert_to_html_internal (CONVERTER *self, const 
ELEMENT *element,
 
           html_convert_command_update_context (self, data_cmd);
 
-          if (element->cmd == CM_node)
+          if (element->e.c->cmd == CM_node)
             {
               self->current_node = element;
               self->modified_state |= HMSF_current_node;
diff --git a/tp/Texinfo/XS/convert/converter.c 
b/tp/Texinfo/XS/convert/converter.c
index a722681104..92df7114f2 100644
--- a/tp/Texinfo/XS/convert/converter.c
+++ b/tp/Texinfo/XS/convert/converter.c
@@ -624,7 +624,7 @@ convert_accents (CONVERTER *self, const ELEMENT *accent,
     {
       char *explanation;
       xasprintf (&explanation, "ACCENT ARG %s",
-                 builtin_command_name (accent->cmd));
+                 builtin_command_name (accent->e.c->cmd));
       arg_text = (*convert_tree) (self, accent_stack->argument, explanation);
       free (explanation);
     }
diff --git a/tp/Texinfo/XS/main/build_perl_info.c 
b/tp/Texinfo/XS/main/build_perl_info.c
index c7b058e093..143c981869 100644
--- a/tp/Texinfo/XS/main/build_perl_info.c
+++ b/tp/Texinfo/XS/main/build_perl_info.c
@@ -697,7 +697,7 @@ element_to_perl_hash (ELEMENT *e, int avoid_recursion)
 #define store_flag(flag) \
   if (e->flags & EF_##flag) \
     store_info_integer (e, 1, "extra", #flag, &extra_hv);
-  if (e->cmd)
+  if (e->e.c->cmd)
     {
       enum command_id data_cmd;
       unsigned long flags;
@@ -788,7 +788,7 @@ element_to_perl_hash (ELEMENT *e, int avoid_recursion)
                           e->e.c->string_info[sit_command_name],
                           "info", "command_name", &info_hv);
                 }
-              if (e->cmd == CM_verb && e->e.c->args.number > 0)
+              if (e->e.c->cmd == CM_verb && e->e.c->args.number > 0)
                 {
                   store_info_string (e, e->e.c->string_info[sit_delimiter],
                                      "info", "delimiter", &info_hv);
diff --git a/tp/Texinfo/XS/main/builtin_commands.c 
b/tp/Texinfo/XS/main/builtin_commands.c
index be7126c4c0..3cdc136eb1 100644
--- a/tp/Texinfo/XS/main/builtin_commands.c
+++ b/tp/Texinfo/XS/main/builtin_commands.c
@@ -68,12 +68,12 @@ lookup_builtin_command (const char *cmdname)
 const char *
 element_command_name (const ELEMENT *e)
 {
-  if (e->cmd && e->cmd < BUILTIN_CMD_NUMBER
+  if (e->e.c->cmd && e->e.c->cmd < BUILTIN_CMD_NUMBER
     /* this can happen if a tree portion is copied and to simplify
        following code the generic command is used in the copy */
-      && e->cmd != CM_index_entry_command
-      && e->cmd != CM_definfoenclose_command)
-    return builtin_command_data[e->cmd].cmdname;
+      && e->e.c->cmd != CM_index_entry_command
+      && e->e.c->cmd != CM_definfoenclose_command)
+    return builtin_command_data[e->e.c->cmd].cmdname;
   else if (e->type == ET_definfoenclose_command
            || e->type == ET_index_entry_command
            || type_data[e->type].flags & TF_macro_call)
@@ -90,13 +90,13 @@ element_command_name (const ELEMENT *e)
 enum command_id
 element_builtin_cmd (const ELEMENT *e)
 {
-  if (e->cmd && e->cmd < BUILTIN_CMD_NUMBER)
-    return e->cmd;
+  if (e->e.c->cmd && e->e.c->cmd < BUILTIN_CMD_NUMBER)
+    return e->e.c->cmd;
   else if (e->type == ET_definfoenclose_command)
     return CM_definfoenclose_command;
   else if (e->type == ET_index_entry_command)
     return CM_index_entry_command;
-  else if (e->cmd)
+  else if (e->e.c->cmd)
     {
       char *debug_str = print_element_debug (e, 0);
       fprintf (stderr, "BUG: element_builtin_cmd: unexpected %s; add code?\n",
@@ -116,7 +116,7 @@ element_builtin_cmd (const ELEMENT *e)
 enum command_id
 element_builtin_data_cmd (const ELEMENT *e)
 {
-  if (e->cmd == CM_item
+  if (e->e.c->cmd == CM_item
       && e->parent->type == ET_table_term)
     return CM_item_LINE;
 
diff --git a/tp/Texinfo/XS/main/builtin_commands.h 
b/tp/Texinfo/XS/main/builtin_commands.h
index abeb333034..eb5c2be1df 100644
--- a/tp/Texinfo/XS/main/builtin_commands.h
+++ b/tp/Texinfo/XS/main/builtin_commands.h
@@ -33,8 +33,9 @@ extern COMMAND builtin_command_data[];
    (!(e) ? 0 : (builtin_command_data[(e)->cmd].flags))
 #define builtin_command_name(cmd) (builtin_command_data[cmd].cmdname)
 /* no builtin_ prefix, as it is not used in parser, so no ambiguity */
-#define command_other_flags(e) \
-   (!(e) ? 0 : (builtin_command_data[(e)->cmd].other_flags))
+/* should not be called on a text element */
+#define command_other_flags(elt) \
+   (!(elt) ? 0 : (builtin_command_data[(elt)->e.c->cmd].other_flags))
 
 enum command_id lookup_builtin_command (const char *cmdname);
 const char *element_command_name (const ELEMENT *e);
diff --git a/tp/Texinfo/XS/main/convert_to_texinfo.c 
b/tp/Texinfo/XS/main/convert_to_texinfo.c
index fb4b6e6dfd..1f9a421480 100644
--- a/tp/Texinfo/XS/main/convert_to_texinfo.c
+++ b/tp/Texinfo/XS/main/convert_to_texinfo.c
@@ -156,7 +156,7 @@ convert_to_texinfo_internal (const ELEMENT *e, TEXT *result)
     }
   else
     {
-      if (e->cmd
+      if (e->e.c->cmd
           || e->type == ET_def_line)
         {
           expand_cmd_args_to_texi (e, result);
diff --git a/tp/Texinfo/XS/main/convert_to_text.c 
b/tp/Texinfo/XS/main/convert_to_text.c
index fe43a619f9..580a19efe5 100644
--- a/tp/Texinfo/XS/main/convert_to_text.c
+++ b/tp/Texinfo/XS/main/convert_to_text.c
@@ -217,7 +217,7 @@ static char *
 ascii_accent (CONVERTER *self, const char *text,
               const ELEMENT *command, int set_case)
 {
-  const enum command_id cmd = command->cmd;
+  const enum command_id cmd = command->e.c->cmd;
   TEXT accent_text;
 
   text_init (&accent_text);
@@ -312,7 +312,7 @@ char *
 text_brace_no_arg_command (const ELEMENT *e, TEXT_OPTIONS *options)
 {
   char *result = 0;
-  enum command_id cmd = e->cmd;
+  enum command_id cmd = e->e.c->cmd;
   const char *encoding = 0;
 
   if (options->encoding)
@@ -598,34 +598,34 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
      with the right flags.  If an element can be a user-defined element,
      data_cmd need to be used for all access to arrays of command_id to
      avoid an index > max index of builtin command  */
-  if (element->cmd)
+  if (element->e.c->cmd)
       data_cmd = element_builtin_data_cmd (element);
 
   if ((element->type == ET_brace_args_command
-       && (element->cmd == CM_anchor
-           || element->cmd == CM_sortas
-           || element->cmd == CM_seealso
-           || element->cmd == CM_seeentry
-           || element->cmd == CM_footnote
-           || element->cmd == CM_hyphenation
-           || element->cmd == CM_errormsg))
+       && (element->e.c->cmd == CM_anchor
+           || element->e.c->cmd == CM_sortas
+           || element->e.c->cmd == CM_seealso
+           || element->e.c->cmd == CM_seeentry
+           || element->e.c->cmd == CM_footnote
+           || element->e.c->cmd == CM_hyphenation
+           || element->e.c->cmd == CM_errormsg))
       || (element->type == ET_context_brace_command
-          && (element->cmd == CM_shortcaption
-              || element->cmd == CM_caption))
+          && (element->e.c->cmd == CM_shortcaption
+              || element->e.c->cmd == CM_caption))
       || (element->type == ET_block_command
-          && (element->cmd == CM_titlepage /* ignored_block_commands */
-               || element->cmd == CM_copying
-               || element->cmd == CM_documentdescription
-               || element->cmd == CM_ignore
-               || element->cmd == CM_nodedescriptionblock)
-              || ((element->cmd == CM_html
-                   || element->cmd == CM_html
-                   || element->cmd == CM_tex
-                   || element->cmd == CM_xml
-                   || element->cmd == CM_docbook
-                   || element->cmd == CM_latex)
+          && (element->e.c->cmd == CM_titlepage /* ignored_block_commands */
+               || element->e.c->cmd == CM_copying
+               || element->e.c->cmd == CM_documentdescription
+               || element->e.c->cmd == CM_ignore
+               || element->e.c->cmd == CM_nodedescriptionblock)
+              || ((element->e.c->cmd == CM_html
+                   || element->e.c->cmd == CM_html
+                   || element->e.c->cmd == CM_tex
+                   || element->e.c->cmd == CM_xml
+                   || element->e.c->cmd == CM_docbook
+                   || element->e.c->cmd == CM_latex)
                   && !format_expanded_p (text_options->expanded_formats,
-                                    builtin_command_name (element->cmd))))
+                                    builtin_command_name (element->e.c->cmd))))
        /* here ignore most of the line commands, and also @*macro */
       || ((element->type == ET_line_command
            || element->type == ET_lineraw_command
@@ -633,8 +633,8 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
           && !(builtin_command_data[data_cmd].other_flags
                                              & CF_formatted_line)
           && !(builtin_command_data[data_cmd].flags & CF_def)
-          && !(element->cmd == CM_sp
-               || element->cmd == CM_verbatiminclude))
+          && !(element->e.c->cmd == CM_sp
+               || element->e.c->cmd == CM_verbatiminclude))
       || element->type == ET_postamble_after_end
       || element->type == ET_preamble_before_beginning)
     return;
@@ -642,7 +642,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
   if (data_cmd
       && builtin_command_data[data_cmd].flags & CF_brace
       && builtin_command_data[data_cmd].data == BRACE_inline
-      && element->cmd != CM_inlinefmtifelse)
+      && element->e.c->cmd != CM_inlinefmtifelse)
     if (builtin_command_data[data_cmd].other_flags & CF_inline_format)
       {
         char *format = lookup_extra_string (element, AI_key_format);
@@ -716,7 +716,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
           ADD(text);
           free (text);
         }
-      else if (element->cmd == CM_image)
+      else if (element->e.c->cmd == CM_image)
         {
           text_options->code_state++;
           convert_to_text_internal (element->e.c->args.list[0],
@@ -724,7 +724,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
           text_options->code_state--;
           return;
         }
-      else if (element->cmd == CM_email)
+      else if (element->e.c->cmd == CM_email)
         {
           if (element->e.c->args.number >= 2)
             {
@@ -745,7 +745,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
           text_options->code_state--;
           return;
         }
-      else if (element->cmd == CM_uref || element->cmd == CM_url)
+      else if (element->e.c->cmd == CM_uref || element->e.c->cmd == CM_url)
         {
           TEXT url_text;
 
@@ -812,10 +812,10 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
                && builtin_command_data[data_cmd].data == BRACE_inline)
         {
           int arg_index = 1;
-          if (element->cmd == CM_inlineraw)
+          if (element->e.c->cmd == CM_inlineraw)
             text_options->raw_state++;
 
-          if (element->cmd == CM_inlinefmtifelse)
+          if (element->e.c->cmd == CM_inlinefmtifelse)
             {
               char *format = lookup_extra_string (element, AI_key_format);
               if (!format
@@ -828,7 +828,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
             convert_to_text_internal (element->e.c->args.list[arg_index],
                                       text_options, result);
 
-          if (element->cmd == CM_inlineraw)
+          if (element->e.c->cmd == CM_inlineraw)
             text_options->raw_state--;
           return;
         }
@@ -839,7 +839,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
                         && builtin_command_data[data_cmd].flags & CF_math)))
         {
           int in_code = 0;
-          if (element->cmd == CM_sc)
+          if (element->e.c->cmd == CM_sc)
             text_options->set_case++;
 
           if (builtin_command_data[data_cmd].other_flags & CF_brace_code
@@ -853,15 +853,15 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
           if (in_code)
             text_options->code_state--;
 
-          if (element->cmd == CM_sc)
+          if (element->e.c->cmd == CM_sc)
             text_options->set_case--;
           return;
         }
       /* block commands */
-      else if (element->cmd == CM_quotation
-               || element->cmd == CM_smallquotation
-               || element->cmd == CM_float
-               || element->cmd == CM_cartouche)
+      else if (element->e.c->cmd == CM_quotation
+               || element->e.c->cmd == CM_smallquotation
+               || element->e.c->cmd == CM_float
+               || element->e.c->cmd == CM_cartouche)
         {
           if (element->e.c->args.number >= 0)
             {
@@ -905,12 +905,12 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
         }
       else if (builtin_command_data[data_cmd].other_flags & CF_formatted_line)
         {
-          if (element->cmd != CM_node)
+          if (element->e.c->cmd != CM_node)
             {
               TEXT text;
               text_init (&text);
               text_append (&text, "");
-              if (element->cmd != CM_page)
+              if (element->e.c->cmd != CM_page)
                 convert_to_text_internal (element->e.c->args.list[0],
                                           text_options, &text);
               if (builtin_command_data[data_cmd].flags & CF_sectioning_heading)
@@ -936,7 +936,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
         {
           convert_def_line (element, text_options, result);
         }
-      else if (element->cmd == CM_sp)
+      else if (element->e.c->cmd == CM_sp)
         {
           const STRING_LIST *misc_args
              = lookup_extra_misc_args (element, AI_key_misc_args);
@@ -951,7 +951,7 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
                   ADD("\n");
             }
         }
-      else if (element->cmd == CM_verbatiminclude)
+      else if (element->e.c->cmd == CM_verbatiminclude)
         {
           ELEMENT *verbatim_include_verbatim = 0;
           ERROR_MESSAGE_LIST *error_messages = 0;
@@ -982,8 +982,8 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
               destroy_element_and_children (verbatim_include_verbatim);
             }
         }
-      else if (element->cmd && CM_item
-               && element->parent->cmd == CM_enumerate)
+      else if (element->e.c->cmd && CM_item
+               && element->parent->e.c->cmd == CM_enumerate)
         {
           int status;
           char *enumerate_specification = lookup_extra_string (element->parent,
@@ -1053,12 +1053,12 @@ convert_to_text_internal (const ELEMENT *element, 
TEXT_OPTIONS *text_options,
            && (builtin_command_data[data_cmd].flags & CF_preformatted_code)
                || builtin_command_data[data_cmd].flags & CF_math
                || (builtin_command_data[data_cmd].flags & CF_block
-                   && builtin_command_data[element->cmd].data == BLOCK_raw))
+                   && builtin_command_data[element->e.c->cmd].data == 
BLOCK_raw))
           || element->type == ET_menu_entry_node)
         in_code = 1;
-      else if (element->cmd
+      else if (element->e.c->cmd
                && builtin_command_data[data_cmd].flags & CF_block
-               && builtin_command_data[element->cmd].data == BLOCK_format_raw)
+               && builtin_command_data[element->e.c->cmd].data == 
BLOCK_format_raw)
         in_raw = 1;
 
       if (in_raw)
diff --git a/tp/Texinfo/XS/main/convert_utils.c 
b/tp/Texinfo/XS/main/convert_utils.c
index bcaaf4b50a..58b506efb9 100644
--- a/tp/Texinfo/XS/main/convert_utils.c
+++ b/tp/Texinfo/XS/main/convert_utils.c
@@ -165,7 +165,7 @@ find_innermost_accent_contents (const ELEMENT *element)
                     {
          /* if accent is tieaccent, keep everything and do not try to
             nest more */
-                      if (current->cmd != CM_tieaccent)
+                      if (current->e.c->cmd != CM_tieaccent)
                         {
                           current = content;
                           argument.number = 0;
@@ -223,7 +223,7 @@ add_heading_number (OPTIONS *options, const ELEMENT 
*current, char *text,
                                                   "number", number);
           add_string_to_named_string_element_list (substrings,
                                              "section_title", text);
-          if (current->cmd == CM_appendix)
+          if (current->e.c->cmd == CM_appendix)
             {
               int status;
               int section_level
@@ -252,7 +252,7 @@ add_heading_number (OPTIONS *options, const ELEMENT 
*current, char *text,
     }
   else
     {
-      if (current->cmd == CM_appendix)
+      if (current->e.c->cmd == CM_appendix)
         {
           int status;
           int section_level = lookup_extra_integer (current,
@@ -456,7 +456,7 @@ expand_verbatiminclude (ERROR_MESSAGE_LIST *error_messages,
     {
       message_list_command_error (error_messages, options, current,
                                   "@%s: could not find %s",
-                                  builtin_command_name (current->cmd),
+                                  builtin_command_name (current->e.c->cmd),
                                   file_name_text);
     }
   free (file_name);
@@ -890,7 +890,9 @@ find_root_command_next_heading_command (const ELEMENT *root,
                        "BUG: in top level unexpected normal_text: '%s'\n",
                        text);
             /* only whitespace characters */
-              if (! text[strspn (text, whitespace_chars)] == '\0')
+              if (text[strspn (text, whitespace_chars)] == '\0')
+                continue;
+              else
                 return 0;
             }
           else
@@ -918,9 +920,9 @@ find_root_command_next_heading_command (const ELEMENT *root,
               if (other_flags & CF_formatted_line
                   || other_flags & CF_formattable_line
                   || (do_not_ignore_contents
-                      && (content->cmd == CM_contents
-                          || content->cmd == CM_shortcontents
-                          || content->cmd == CM_summarycontents)))
+                      && (content->e.c->cmd == CM_contents
+                          || content->e.c->cmd == CM_shortcontents
+                          || content->e.c->cmd == CM_summarycontents)))
                 return 0;
               else
                 continue;
diff --git a/tp/Texinfo/XS/main/debug.c b/tp/Texinfo/XS/main/debug.c
index dc3967397a..72bcd1e100 100644
--- a/tp/Texinfo/XS/main/debug.c
+++ b/tp/Texinfo/XS/main/debug.c
@@ -31,9 +31,9 @@
 const char *
 debug_element_command_name (const ELEMENT *e)
 {
-  if (e->cmd == CM_TAB)
+  if (e->e.c->cmd == CM_TAB)
     return "\\t";
-  else if (e->cmd == CM_NEWLINE)
+  else if (e->e.c->cmd == CM_NEWLINE)
     return "\\n";
   else
     return element_command_name (e);
@@ -99,7 +99,7 @@ print_element_debug (const ELEMENT *e, int print_parent)
     }
   else
     {
-      if (e->cmd)
+      if (e->e.c->cmd)
         text_printf (&text, "@%s", debug_element_command_name (e));
       if (e->e.c->args.number)
         text_printf (&text, "[A%d]", e->e.c->args.number);
@@ -109,8 +109,8 @@ print_element_debug (const ELEMENT *e, int print_parent)
   if (print_parent && e->parent)
     {
       text_append (&text, " <- ");
-      if (e->parent->cmd)
-        text_printf (&text, "@%s", element_command_name (e->parent));
+      if (e->parent->e.c->cmd)
+        text_printf (&text, "@%s", debug_element_command_name (e->parent));
       if (e->parent->type)
         text_printf (&text, "(%s)", type_data[e->parent->type].name);
     }
diff --git a/tp/Texinfo/XS/main/manipulate_indices.c 
b/tp/Texinfo/XS/main/manipulate_indices.c
index 8ce1dce10b..34f61d80ce 100644
--- a/tp/Texinfo/XS/main/manipulate_indices.c
+++ b/tp/Texinfo/XS/main/manipulate_indices.c
@@ -1252,7 +1252,37 @@ idx_leading_text_or_command (ELEMENT *tree, const char 
*ignore_chars)
     {
       ELEMENT *content = tree->e.c->contents.list[i];
 
-      if (content->cmd)
+      if (content->type == ET_normal_text)
+        {
+          if (content->e.text->end > 0
+              && content->e.text->text[strspn
+                           (content->e.text->text, whitespace_chars)] != '\0')
+            {
+              char *p = content->e.text->text;
+              p += strspn (p, whitespace_chars);
+              if (ignore_chars)
+                {
+                  char *text = strip_index_ignore_chars (p, ignore_chars);
+                  INDEX_ENTRY_TEXT_OR_COMMAND *result = 0;
+
+                  if (text[strspn (text, whitespace_chars)] != '\0')
+                    result = new_index_entry_text_or_command (text, 0);
+
+                  free (text);
+
+                  if (result)
+                    return result;
+                  else
+                    continue;
+                }
+              else
+                return new_index_entry_text_or_command (p, 0);
+            }
+          else
+            continue;
+        }
+
+      if (content->e.c->cmd)
         {
           enum command_id data_cmd = element_builtin_data_cmd (content);
 
@@ -1316,29 +1346,6 @@ idx_leading_text_or_command (ELEMENT *tree, const char 
*ignore_chars)
                 }
             }
         }
-      else if (content->type == ET_normal_text
-               && content->e.text->end > 0
-               && content->e.text->text[strspn 
-                           (content->e.text->text, whitespace_chars)] != '\0')
-        {
-          char *p = content->e.text->text;
-          p += strspn (p, whitespace_chars);
-          if (ignore_chars)
-            {
-              char *text = strip_index_ignore_chars (p, ignore_chars);
-              INDEX_ENTRY_TEXT_OR_COMMAND *result = 0;
-
-              if (text[strspn (text, whitespace_chars)] != '\0')
-                result = new_index_entry_text_or_command (text, 0);
-
-              free (text);
-
-              if (result)
-                return result;
-            }
-          else
-            return new_index_entry_text_or_command (p, 0);
-        }
       else if (content->e.c->contents.number > 0)
         return idx_leading_text_or_command (content, ignore_chars);
     }
diff --git a/tp/Texinfo/XS/main/manipulate_tree.c 
b/tp/Texinfo/XS/main/manipulate_tree.c
index 58e8e5b78f..9bc1532a57 100644
--- a/tp/Texinfo/XS/main/manipulate_tree.c
+++ b/tp/Texinfo/XS/main/manipulate_tree.c
@@ -157,8 +157,8 @@ copy_tree_internal (ELEMENT* current)
 
   if (type_data[current->type].flags & TF_text)
     new = new_text_element (current->type);
-  else if (current->cmd)
-    new = new_command_element (current->type, current->cmd);
+  else if (current->e.c->cmd)
+    new = new_command_element (current->type, current->e.c->cmd);
   else
     new = new_element (current->type);
 
@@ -213,7 +213,8 @@ copy_tree_internal (ELEMENT* current)
       int string_info_nr = 1;
       if (current->type == ET_definfoenclose_command
           || current->type == ET_index_entry_command
-          || current->type == ET_lineraw_command || current->cmd == CM_verb)
+          || current->type == ET_lineraw_command
+          || current->e.c->cmd == CM_verb)
         string_info_nr = 2;
       for (i = 0; i < string_info_nr; i++)
         if (current->e.c->string_info[i])
diff --git a/tp/Texinfo/XS/main/node_name_normalization.c 
b/tp/Texinfo/XS/main/node_name_normalization.c
index a07d20a295..5ade1fa621 100644
--- a/tp/Texinfo/XS/main/node_name_normalization.c
+++ b/tp/Texinfo/XS/main/node_name_normalization.c
@@ -48,30 +48,14 @@ int ref_5_args_order[] = {0, 1, 2, 4, 3, -1};
 void
 convert_to_normalized_internal (const ELEMENT *e, TEXT *result)
 {
-  if ((e->type == ET_ignorable_spaces_after_command
-       || e->type == ET_postamble_after_end
-       || e->type == ET_preamble_before_beginning
-       || e->type == ET_spaces_at_end
-       || e->type == ET_spaces_before_paragraph
-       || e->type == ET_space_at_end_menu_node
-       || e->type == ET_spaces_after_close_brace)
-      || (e->cmd
-          && ((e->cmd == CM_anchor
-               || e->cmd == CM_footnote
-               || e->cmd == CM_shortcaption
-               || e->cmd == CM_caption
-               || e->cmd == CM_hyphenation
-               || e->cmd == CM_sortas
-               || e->cmd == CM_seealso
-               || e->cmd == CM_seeentry)
-             /* here ignore the line commands */
-              || (e->e.c->args.number > 0
-                  && (e->e.c->args.list[0]->type == ET_line_arg
-                      || e->e.c->args.list[0]->type == ET_rawline_arg)))))
-    return;
-  else if (type_data[e->type].flags & TF_text)
+  if (type_data[e->type].flags & TF_text)
     {
-      if (e->e.text->end > 0)
+      if (e->type != ET_ignorable_spaces_after_command
+          && e->type != ET_spaces_at_end
+          && e->type != ET_spaces_before_paragraph
+          && e->type != ET_space_at_end_menu_node
+          && e->type != ET_spaces_after_close_brace
+          && e->e.text->end > 0)
         {
           char *text_norm_spaces = collapse_spaces (e->e.text->text);
           ADD(text_norm_spaces);
@@ -80,11 +64,28 @@ convert_to_normalized_internal (const ELEMENT *e, TEXT 
*result)
       return;
     }
 
-  if (e->cmd)
+  if ((e->type == ET_postamble_after_end
+       || e->type == ET_preamble_before_beginning)
+      || (e->e.c->cmd
+          && ((e->e.c->cmd == CM_anchor
+               || e->e.c->cmd == CM_footnote
+               || e->e.c->cmd == CM_shortcaption
+               || e->e.c->cmd == CM_caption
+               || e->e.c->cmd == CM_hyphenation
+               || e->e.c->cmd == CM_sortas
+               || e->e.c->cmd == CM_seealso
+               || e->e.c->cmd == CM_seeentry)
+             /* here ignore the line commands */
+              || (e->e.c->args.number > 0
+                  && (e->e.c->args.list[0]->type == ET_line_arg
+                      || e->e.c->args.list[0]->type == ET_rawline_arg)))))
+    return;
+
+  if (e->e.c->cmd)
     {
-      if (command_normalization_text[e->cmd])
-        ADD(command_normalization_text[e->cmd]);
-      else if (e->cmd == CM_click)
+      if (command_normalization_text[e->e.c->cmd])
+        ADD(command_normalization_text[e->e.c->cmd]);
+      else if (e->e.c->cmd == CM_click)
         {
           enum command_id cmd;
           char *command_name = lookup_extra_string (e, AI_key_clickstyle);
@@ -95,7 +96,7 @@ convert_to_normalized_internal (const ELEMENT *e, TEXT 
*result)
                 ADD(command_normalization_text[cmd]);
             }
         }
-      else if (builtin_command_data[e->cmd].flags & CF_accent)
+      else if (builtin_command_data[e->e.c->cmd].flags & CF_accent)
         {
           if (e->e.c->args.number > 0)
             {
@@ -117,11 +118,11 @@ convert_to_normalized_internal (const ELEMENT *e, TEXT 
*result)
               free (accent_text.text);
             }
         }
-      else if (builtin_command_data[e->cmd].flags & CF_ref)
+      else if (builtin_command_data[e->e.c->cmd].flags & CF_ref)
         {
           int index = 0;
           int *arguments_order = ref_5_args_order;
-          if (e->cmd == CM_inforef || e->cmd == CM_link)
+          if (e->e.c->cmd == CM_inforef || e->e.c->cmd == CM_link)
             arguments_order = ref_3_args_order;
           while (arguments_order[index] >= 0)
             {
@@ -150,7 +151,7 @@ convert_to_normalized_internal (const ELEMENT *e, TEXT 
*result)
       else if (e->e.c->args.number > 0
                && (e->e.c->args.list[0]->type == ET_brace_container
                    || e->e.c->args.list[0]->type == ET_brace_arg
-                   || e->cmd == CM_math))
+                   || e->e.c->cmd == CM_math))
         {
           convert_to_normalized_internal (e->e.c->args.list[0], result);
           return;
diff --git a/tp/Texinfo/XS/main/output_unit.c b/tp/Texinfo/XS/main/output_unit.c
index 1ae321579a..258d1193b0 100644
--- a/tp/Texinfo/XS/main/output_unit.c
+++ b/tp/Texinfo/XS/main/output_unit.c
@@ -308,7 +308,7 @@ output_unit_section (OUTPUT_UNIT *output_unit)
     return 0;
 
   element = output_unit->unit_command;
-  if (element->cmd == CM_node)
+  if (element->e.c->cmd == CM_node)
     {
       ELEMENT *associated_section
          = lookup_extra_element (element, AI_key_associated_section);
@@ -331,7 +331,7 @@ output_unit_node (OUTPUT_UNIT *output_unit)
 
   element = output_unit->unit_command;
 
-  if (element->cmd == CM_node)
+  if (element->e.c->cmd == CM_node)
     return element;
   else
    {
@@ -459,7 +459,7 @@ label_target_unit_element (ELEMENT *label)
       external_node_unit->unit_command = label;
       return external_node_unit;
     }
-  else if (label->cmd == CM_node)
+  else if (label->e.c->cmd == CM_node)
     return label->e.c->associated_unit;
   else
  /* case of a @float or an @anchor, no target element defined at this stage */
@@ -720,7 +720,7 @@ units_directions (LABEL_LIST *identifiers_target,
 
           up_section_childs = lookup_extra_contents (up, 
AI_key_section_childs);
           if (status >= 0 && up_section_level < 1
-              && up->cmd == CM_top && up_section_childs
+              && up->e.c->cmd == CM_top && up_section_childs
               && up_section_childs->number > 0)
             {
               directions[RUD_type_FastForward]
diff --git a/tp/Texinfo/XS/main/targets.c b/tp/Texinfo/XS/main/targets.c
index f8cb00ecd7..0bddce1f4f 100644
--- a/tp/Texinfo/XS/main/targets.c
+++ b/tp/Texinfo/XS/main/targets.c
@@ -255,12 +255,12 @@ existing_label_error (DOCUMENT* document, ELEMENT 
*element, char *normalized,
       char *label_element_texi = convert_contents_to_texinfo (label_element);
       message_list_command_error (error_messages, document->options,
                      element, "@%s `%s' previously defined",
-                     builtin_command_name (element->cmd),
+                     builtin_command_name (element->e.c->cmd),
                      label_element_texi);
       message_list_line_error_ext (error_messages, document->options,
                       MSG_error, 1, &existing_target->e.c->source_info,
                       "here is the previous definition as @%s",
-                      builtin_command_name (existing_target->cmd));
+                      builtin_command_name (existing_target->e.c->cmd));
       free (label_element_texi);
     }
 }
diff --git a/tp/Texinfo/XS/main/translations.c 
b/tp/Texinfo/XS/main/translations.c
index 0f8ece7a40..038a9b1a2c 100644
--- a/tp/Texinfo/XS/main/translations.c
+++ b/tp/Texinfo/XS/main/translations.c
@@ -394,22 +394,26 @@ substitute_element_array (ELEMENT_LIST *list,
   for (; idx < list->number; idx++)
     {
       ELEMENT *e = list->list[idx];
-      if (e->cmd == CM_txiinternalvalue)
+      if (! (type_data[e->type].flags & TF_text))
         {
-          char *name = 
e->e.c->args.list[0]->e.c->contents.list[0]->e.text->text;
-          int i;
-          for (i = 0; i < replaced_substrings->number; i++)
+          if (e->e.c->cmd == CM_txiinternalvalue)
             {
-              if (!strcmp (name, replaced_substrings->list[i].name))
+              char *name = e->e.c->args.list[0]->e.c->contents.list[0]
+                                                            ->e.text->text;
+              int i;
+              for (i = 0; i < replaced_substrings->number; i++)
                 {
-                  list->list[idx] = replaced_substrings->list[i].element;
-                  destroy_element_and_children (e);
-                  break;
+                  if (!strcmp (name, replaced_substrings->list[i].name))
+                    {
+                      list->list[idx] = replaced_substrings->list[i].element;
+                      destroy_element_and_children (e);
+                      break;
+                    }
                 }
             }
+          else
+            substitute (e, replaced_substrings);
         }
-      else if (! (type_data[e->type].flags & TF_text))
-        substitute (e, replaced_substrings);
     }
 }
 
diff --git a/tp/Texinfo/XS/main/tree.c b/tp/Texinfo/XS/main/tree.c
index a20b06ebd7..687ed5325a 100644
--- a/tp/Texinfo/XS/main/tree.c
+++ b/tp/Texinfo/XS/main/tree.c
@@ -118,9 +118,10 @@ ELEMENT *
 new_command_element (enum element_type type, enum command_id cmd)
 {
   ELEMENT *e = new_element (type);
-  e->cmd = cmd;
   int string_info_nr = 1;
 
+  e->e.c->cmd = cmd;
+
   if (type == ET_definfoenclose_command || type == ET_index_entry_command
       || type == ET_lineraw_command || cmd == CM_verb)
     string_info_nr = 2;
@@ -248,12 +249,12 @@ destroy_element (ELEMENT *e)
 
       if (e->type == ET_definfoenclose_command
           || e->type == ET_index_entry_command
-          || e->type == ET_lineraw_command || e->cmd == CM_verb
+          || e->type == ET_lineraw_command || e->e.c->cmd == CM_verb
           || type_data[e->type].flags & TF_macro_call)
         {
           string_info_nr = 2;
         }
-      else if (e->cmd != CM_NONE)
+      else if (e->e.c->cmd != CM_NONE)
         string_info_nr = 1;
 
       for (i = 0; i < string_info_nr; i++)
diff --git a/tp/Texinfo/XS/main/tree_types.h b/tp/Texinfo/XS/main/tree_types.h
index 7e42cda46f..4c306e5282 100644
--- a/tp/Texinfo/XS/main/tree_types.h
+++ b/tp/Texinfo/XS/main/tree_types.h
@@ -324,6 +324,7 @@ typedef struct CONTAINER {
     OUTPUT_UNIT *associated_unit;
     /* depends on the element */
     char **string_info;
+    enum command_id cmd;
 } CONTAINER;
 
 /* indices in ELEMENT elt_info */
@@ -357,8 +358,6 @@ typedef struct ELEMENT {
     struct ELEMENT **elt_info;
     SOURCE_MARK_LIST source_mark_list;
 
-    enum command_id cmd;
-
     union {
       TEXT *text;
       CONTAINER *c;
diff --git a/tp/Texinfo/XS/main/unicode.c b/tp/Texinfo/XS/main/unicode.c
index 2825983dd9..32967afe85 100644
--- a/tp/Texinfo/XS/main/unicode.c
+++ b/tp/Texinfo/XS/main/unicode.c
@@ -105,9 +105,9 @@ unicode_accent (const char *text, const ELEMENT *e)
   what is going on for that character.
   */
 
-  if (e->cmd == CM_dotless)
+  if (e->e.c->cmd == CM_dotless)
     {
-      if (!e->parent || !e->parent->parent || !e->parent->parent->cmd
+      if (!e->parent || !e->parent->parent || !e->parent->parent->e.c->cmd
           || !unicode_diacritics[element_builtin_cmd (e->parent->parent)].text)
         {
           if (!strcmp (text, "i"))
@@ -120,10 +120,10 @@ unicode_accent (const char *text, const ELEMENT *e)
       return strdup (text);
     }
 
-  if (unicode_diacritics[e->cmd].text)
+  if (unicode_diacritics[e->e.c->cmd].text)
     {
       static TEXT accented_text;
-      if (e->cmd == CM_tieaccent)
+      if (e->e.c->cmd == CM_tieaccent)
         {
           /* tieaccent diacritic is naturally and correctly composed
              between two characters */
@@ -154,7 +154,7 @@ unicode_accent (const char *text, const ELEMENT *e)
                   text_init (&accented_text);
                   text_append (&accented_text, first_char_text);
                   free (first_char_text);
-                  text_append (&accented_text, 
unicode_diacritics[e->cmd].text);
+                  text_append (&accented_text, 
unicode_diacritics[e->e.c->cmd].text);
                   next_text = string_from_utf8 (next);
                   text_append (&accented_text, next_text);
                   free (next_text);
@@ -168,7 +168,7 @@ unicode_accent (const char *text, const ELEMENT *e)
         }
       text_init (&accented_text);
       text_append (&accented_text, text);
-      text_append (&accented_text, unicode_diacritics[e->cmd].text);
+      text_append (&accented_text, unicode_diacritics[e->e.c->cmd].text);
       result = normalize_NFC (accented_text.text);
       free (accented_text.text);
     }
@@ -285,7 +285,7 @@ format_eight_bit_accents_stack (CONVERTER *self, const char 
*text,
     #    underbar.
     */
       if (!strcmp (new_eight_bit, prev_eight_bit)
-          && !(stack->stack[j]->cmd == CM_dotless
+          && !(stack->stack[j]->e.c->cmd == CM_dotless
                && !strcmp (results_stack[j], "i")))
         {
           free (new_eight_bit);
diff --git a/tp/Texinfo/XS/main/utils.c b/tp/Texinfo/XS/main/utils.c
index e1811d5546..32f517ea36 100644
--- a/tp/Texinfo/XS/main/utils.c
+++ b/tp/Texinfo/XS/main/utils.c
@@ -642,7 +642,9 @@ item_line_parent (ELEMENT *current)
   /* this code handles current being a user defined command even tough
      it is not clear that it may happen */
   cmd = element_builtin_cmd (current);
-  if (builtin_command_data[cmd].data == BLOCK_item_line)
+  if (cmd == CM_table
+      || cmd == CM_ftable
+      || cmd == CM_vtable)
     return current;
 
   return 0;
@@ -651,10 +653,10 @@ item_line_parent (ELEMENT *current)
 ELEMENT *
 get_label_element (const ELEMENT *e)
 {
-  if ((e->cmd == CM_node || e->cmd == CM_anchor)
+  if ((e->e.c->cmd == CM_node || e->e.c->cmd == CM_anchor)
       && e->e.c->args.number > 0)
     return e->e.c->args.list[0];
-  else if (e->cmd == CM_float && e->e.c->args.number >= 2)
+  else if (e->e.c->cmd == CM_float && e->e.c->args.number >= 2)
     return e->e.c->args.list[1];
   return 0;
 }
@@ -1364,7 +1366,7 @@ destroy_accent_stack (ACCENTS_STACK *accent_stack)
 int
 section_level (const ELEMENT *section)
 {
-  int level = command_structuring_level[section->cmd];
+  int level = command_structuring_level[section->e.c->cmd];
   int status;
   int section_modifier = lookup_extra_integer (section, AI_key_level_modifier,
                                                &status);
@@ -1372,8 +1374,8 @@ section_level (const ELEMENT *section)
     {
       level -= section_modifier;
       if (level < min_level)
-        if (command_structuring_level[section->cmd] < min_level)
-          level = command_structuring_level[section->cmd];
+        if (command_structuring_level[section->e.c->cmd] < min_level)
+          level = command_structuring_level[section->e.c->cmd];
         else
           level = min_level;
       else if (level > max_level)
@@ -1394,13 +1396,13 @@ section_level_adjusted_command_name (const ELEMENT 
*element)
      not called */
   if (status == 0)
     {
-      if (command_structuring_level[element->cmd] != heading_level)
+      if (command_structuring_level[element->e.c->cmd] != heading_level)
         {
-          return level_to_structuring_command[element->cmd][heading_level];
+          return 
level_to_structuring_command[element->e.c->cmd][heading_level];
         }
     }
 
-  return element->cmd;
+  return element->e.c->cmd;
 }
 
 /* corresponding perl function in Common.pm */
@@ -1414,8 +1416,24 @@ is_content_empty (const ELEMENT *tree, int 
do_not_ignore_index_entries)
   for (i = 0; i < tree->e.c->contents.number; i++)
     {
       const ELEMENT *content = tree->e.c->contents.list[i];
-      enum command_id data_cmd = element_builtin_data_cmd (content);
+      enum command_id data_cmd;
 
+      if (type_data[content->type].flags & TF_text)
+        {
+          if (content->e.text->end == 0)
+            return 1;
+          else
+            {
+              const char *text = content->e.text->text;
+              /* only whitespace characters */
+              if (! text[strspn (text, whitespace_chars)] == '\0')
+                return 0;
+              else
+                continue;
+            }
+        }
+
+      data_cmd = element_builtin_data_cmd (content);
       if (data_cmd)
         {
           unsigned long flags = builtin_command_data[data_cmd].flags;
@@ -1452,19 +1470,7 @@ is_content_empty (const ELEMENT *tree, int 
do_not_ignore_index_entries)
         }
       if (content->type == ET_paragraph)
         return 0;
-      if (type_data[content->type].flags & TF_text)
-        {
-          if (content->e.text->end == 0)
-            return 1;
-          else
-            {
-              const char *text = content->e.text->text;
-              /* only whitespace characters */
-              if (! text[strspn (text, whitespace_chars)] == '\0')
-                return 0;
-            }
-        }
-      else if (! is_content_empty (content, do_not_ignore_index_entries))
+      if (! is_content_empty (content, do_not_ignore_index_entries))
         return 0;
     }
   return 1;
diff --git a/tp/Texinfo/XS/parsetexi/close.c b/tp/Texinfo/XS/parsetexi/close.c
index e472a01002..ed304c1d84 100644
--- a/tp/Texinfo/XS/parsetexi/close.c
+++ b/tp/Texinfo/XS/parsetexi/close.c
@@ -51,25 +51,26 @@ close_brace_command (ELEMENT *current,
 
   counter_pop (&count_remaining_args);
 
-  if (command_data(current->cmd).data == BRACE_context)
+  if (command_data(current->e.c->cmd).data == BRACE_context)
     {
-      if (current->cmd == CM_math)
+      if (current->e.c->cmd == CM_math)
         {
           if (pop_context () != ct_math)
             fatal ("math context expected");
         }
       else if (pop_context () != ct_brace_command)
         fatal ("context brace command context expected");
-      if (current->cmd == CM_footnote)
+      if (current->e.c->cmd == CM_footnote)
         nesting_context.footnote--;
-      if (current->cmd == CM_caption || current->cmd == CM_shortcaption)
+      if (current->e.c->cmd == CM_caption
+          || current->e.c->cmd == CM_shortcaption)
         nesting_context.caption--;
     }
 
   if (command_flags(current) & CF_contain_basic_inline)
     (void) pop_command (&nesting_context.basic_inline_stack);
 
-  if (current->cmd != CM_verb)
+  if (current->e.c->cmd != CM_verb)
     goto yes;
   delimiter = current->e.c->string_info[sit_delimiter];
   if (!delimiter || !*delimiter)
@@ -81,22 +82,22 @@ close_brace_command (ELEMENT *current,
         command_error (current,
                         "@end %s seen before @%s closing brace",
                         command_name(closed_block_command),
-                        command_name(current->cmd));
+                        command_name(current->e.c->cmd));
       else if (interrupting_command)
         command_error (current,
                         "@%s seen before @%s closing brace",
                         command_name(interrupting_command),
-                        command_name(current->cmd));
+                        command_name(current->e.c->cmd));
       else if (missing_brace)
          command_error (current,
                         "@%s missing closing brace",
-                        command_name(current->cmd));
+                        command_name(current->e.c->cmd));
     }
   else if (missing_brace)
     {
       command_error (current,
                       "@%s missing closing delimiter sequence: %s}",
-                      command_name(current->cmd),
+                      command_name(current->e.c->cmd),
                       delimiter);
     }
   current = current->parent;
@@ -112,10 +113,10 @@ close_all_style_commands (ELEMENT *current,
 {
   while (current->parent
          && (command_flags(current->parent) & CF_brace)
-         && !(command_data(current->parent->cmd).data == BRACE_context))
+         && !(command_data(current->parent->e.c->cmd).data == BRACE_context))
     {
       debug ("CLOSING(all_style_commands) @%s",
-             command_name(current->parent->cmd));
+             command_name(current->parent->e.c->cmd));
       current = close_brace_command (current->parent,
                            closed_block_command, interrupting_command, 1);
     }
@@ -146,7 +147,8 @@ remove_empty_content (ELEMENT *current)
   if (current->e.c->contents.number == 1)
     {
       ELEMENT *child_element = last_contents_child (current);
-      if ((!child_element->cmd) && is_container_empty (child_element))
+      if (!(type_data[child_element->type].flags & TF_at_command)
+          && is_container_empty (child_element))
         {
           transfer_source_marks (child_element, current);
 
@@ -200,10 +202,10 @@ close_container (ELEMENT *current)
 void
 close_command_cleanup (ELEMENT *current)
 {
-  if (!current->cmd)
+  if (!current->e.c->cmd)
     return;
 
-  if (current->cmd == CM_multitable)
+  if (current->e.c->cmd == CM_multitable)
     {
       int in_head_or_rows = -1, i;
       ELEMENT_LIST old_contents = current->e.c->contents;
@@ -223,7 +225,7 @@ close_command_cleanup (ELEMENT *current)
               if (counter_index < 0)
                 fprintf (stderr, "BUG: could not remove row counter\n");
               /* Check if we need to open a new container. */
-              if (contents_child_by_index (row, 0)->cmd == CM_headitem)
+              if (contents_child_by_index (row, 0)->e.c->cmd == CM_headitem)
                 {
                   if (in_head_or_rows <= 0)
                     {
@@ -232,7 +234,7 @@ close_command_cleanup (ELEMENT *current)
                       in_head_or_rows = 1;
                     }
                 }
-              else if (contents_child_by_index (row, 0)->cmd == CM_item)
+              else if (contents_child_by_index (row, 0)->e.c->cmd == CM_item)
                 {
                   if (in_head_or_rows == 1 || in_head_or_rows == -1)
                     {
@@ -253,22 +255,22 @@ close_command_cleanup (ELEMENT *current)
       free (old_contents.list);
 
     }
-  else if (current->cmd == CM_itemize || current->cmd == CM_enumerate)
+  else if (current->e.c->cmd == CM_itemize || current->e.c->cmd == 
CM_enumerate)
     {
       counter_pop (&count_items);
     }
 
   /* Put everything after the last @def*x command in a def_item type
      container. */
-  if (command_data(current->cmd).flags & CF_def
-      || current->cmd == CM_defblock)
+  if (command_data(current->e.c->cmd).flags & CF_def
+      || current->e.c->cmd == CM_defblock)
     {
       gather_def_item (current, 0);
     }
 
-  if (current->cmd == CM_table
-      || current->cmd == CM_ftable
-      || current->cmd == CM_vtable)
+  if (current->e.c->cmd == CM_table
+      || current->e.c->cmd == CM_ftable
+      || current->e.c->cmd == CM_vtable)
     {
       if (current->e.c->contents.number > 0)
         gather_previous_item (current, 0);
@@ -276,84 +278,48 @@ close_command_cleanup (ELEMENT *current)
 
   /* Block commands that contain @item's - e.g. @multitable, @table,
      @itemize. */
-  if (command_data(current->cmd).flags & CF_blockitem
-      && current->e.c->contents.number > 0)
+  if (command_data(current->e.c->cmd).flags & CF_blockitem
+      && current->e.c->contents.number > 0
+      && current->e.c->contents.list[0]->type == ET_before_item)
     {
-      int have_leading_spaces = 0;
-      ELEMENT *before_item = 0;
-      if (current->e.c->contents.number >= 2
-          && current->e.c->contents.list[0]->type
-                              == ET_ignorable_spaces_after_command
-          && current->e.c->contents.list[1]->type == ET_before_item)
-        {
-          have_leading_spaces = 1;
-          before_item = current->e.c->contents.list[1];
-        }
-      else if (current->e.c->contents.number >= 1
-          && current->e.c->contents.list[0]->type == ET_before_item)
+      ELEMENT *before_item = current->e.c->contents.list[0];
+
+      /* If the ET_before_item is empty, remove it.  Note that the
+         some before_item content could also have been reparented in
+         gather_previous_item */
+      if (is_container_empty (before_item)
+          && before_item->source_mark_list.number == 0)
         {
-          before_item = current->e.c->contents.list[0];
+          ELEMENT *removed = remove_from_contents (current, 0);
+          destroy_element (removed);
         }
-
-      if (before_item)
+      else /* Non-empty ET_before_item */
         {
-          /* Reparent @end from a ET_before_item to the block command */
-          ELEMENT *e = last_contents_child (before_item);
-          if (e && e->cmd == CM_end)
-            {
-              add_to_element_contents (current,
-                                     pop_element_from_contents (before_item));
-            }
-
-          /* Now if the ET_before_item is empty, remove it.  Note that the
-             some before_item content could also have been reparented in
-             gather_previous_item */
-          if (is_container_empty (before_item)
-              && before_item->source_mark_list.number == 0)
-            {
-              ELEMENT *removed = remove_from_contents (current,
-                                                have_leading_spaces ? 1 : 0);
-              destroy_element (removed);
-            }
-          else /* Non-empty ET_before_item */
+          /* The elements that can appear right in a block item command
+             besides before_item are either an @*item or are associated
+             with items */
+          if (current->e.c->contents.number == 1)
             {
+       /* no @*item, only before_item.  Warn if before_item is not empty */
               int empty_before_item = 1, i;
-              /* Check if contents consist soley of @comment's. */
+              /* Check if contents consist solely of @comment's. */
               for (i = 0; i < before_item->e.c->contents.number; i++)
                 {
-                  enum command_id c = before_item->e.c->contents.list[i]->cmd;
-                  if (c != CM_c && c != CM_comment)
+                  ELEMENT *content = before_item->e.c->contents.list[i];
+                /* content can be spaces text element such as empty_line */
+                  if (!(content->type == ET_lineraw_command
+                        && (content->e.c->cmd == CM_c
+                            || content->e.c->cmd == CM_comment)))
                     {
                       empty_before_item = 0;
+                      break;
                     }
-                }
+               }
 
               if (!empty_before_item)
                 {
-                  int empty_format = 1;
-                  /* Check for an element that could represent an @item in the
-                     block.  The type of this element will depend on the block
-                     command we are in. */
-                  for (i = 0; i < current->e.c->contents.number; i++)
-                    {
-                      ELEMENT *e = current->e.c->contents.list[i];
-                      if (e == before_item)
-                        continue;
-                      if ((e->cmd != CM_NONE
-                           && (e->cmd != CM_c && e->cmd != CM_comment
-                               && e->cmd != CM_end))
-                          /* FIXME check if ET_NONE is ok */
-                          || (e->type != ET_NONE
-                              && e->type != ET_ignorable_spaces_after_command))
-                        {
-                          empty_format = 0;
-                          break;
-                        }
-                    }
-
-                  if (empty_format)
-                    command_warn (current, "@%s has text but no @item",
-                                  command_name(current->cmd));
+                  command_warn (current, "@%s has text but no @item",
+                            command_name(current->e.c->cmd));
                 }
             }
         }
@@ -403,9 +369,9 @@ close_current (ELEMENT *current,
                enum command_id interrupting_command)
 {
   /* Element is a command */
-  if (current->cmd)
+  if (current->e.c->cmd)
     {
-      enum command_id cmd = current->cmd;
+      enum command_id cmd = current->e.c->cmd;
       debug ("CLOSING(close_current) @%s", command_name(cmd));
       if (command_flags(current) & CF_brace)
         {
@@ -514,9 +480,9 @@ close_commands (ELEMENT *current, enum command_id 
closed_block_command,
   current = end_preformatted (current, closed_block_command, interrupting);
 
   while (current->parent
-         && (!closed_block_command || current->cmd != closed_block_command)
+         && (!closed_block_command || current->e.c->cmd != 
closed_block_command)
      /* Stop if in a root command. */
-         && !(current->cmd && command_flags(current) & CF_root)
+         && !(current->e.c->cmd && command_flags(current) & CF_root)
      /* Stop if at a type at the root */
          && !(current->type == ET_before_node_section))
     {
@@ -524,13 +490,13 @@ close_commands (ELEMENT *current, enum command_id 
closed_block_command,
       current = close_current (current, closed_block_command, interrupting);
     }
 
-  if (closed_block_command && current->cmd == closed_block_command)
+  if (closed_block_command && current->e.c->cmd == closed_block_command)
     {
-      pop_block_command_contexts (current->cmd);
+      pop_block_command_contexts (current->e.c->cmd);
       *closed_element = current;
       current = current->parent;
 
-      if (command_data((*closed_element)->cmd).data == BLOCK_conditional)
+      if (command_data((*closed_element)->e.c->cmd).data == BLOCK_conditional)
         /* In ignored conditional. */
         close_ignored_block_conditional (current);
     }
@@ -538,7 +504,7 @@ close_commands (ELEMENT *current, enum command_id 
closed_block_command,
     {
       if (closed_block_command)
         line_error ("unmatched `@end %s'", command_name(closed_block_command));
-      if (! ((current->cmd && command_flags(current) & CF_root)
+      if (! ((current->e.c->cmd && command_flags(current) & CF_root)
              || (current->type == ET_before_node_section)
              || (current->type == ET_root_line)
              || (current->type == ET_document_root)))
diff --git a/tp/Texinfo/XS/parsetexi/commands.h 
b/tp/Texinfo/XS/parsetexi/commands.h
index e69667293c..dd6a56b207 100644
--- a/tp/Texinfo/XS/parsetexi/commands.h
+++ b/tp/Texinfo/XS/parsetexi/commands.h
@@ -31,7 +31,7 @@ enum command_id lookup_command (const char *cmdname);
    ? builtin_command_data[(id)] \
    : user_defined_command_data[(id) & ~USER_COMMAND_BIT])
 
-#define command_flags(e) (!(e) ? 0 : (command_data((e)->cmd).flags))
+#define command_flags(elt) (!(elt) ? 0 : (command_data((elt)->e.c->cmd).flags))
 #define command_name(cmd) (command_data(cmd).cmdname)
 
 int close_preformatted_command (enum command_id cmd_id);
diff --git a/tp/Texinfo/XS/parsetexi/debug_parser.c 
b/tp/Texinfo/XS/parsetexi/debug_parser.c
index 56be2874ef..90fe30a8d1 100644
--- a/tp/Texinfo/XS/parsetexi/debug_parser.c
+++ b/tp/Texinfo/XS/parsetexi/debug_parser.c
@@ -120,8 +120,8 @@ print_element_debug_parser (const ELEMENT *e, int 
print_parent)
     }
   else
     {
-      if (e->cmd)
-        text_printf (&text, "@%s", debug_parser_command_name (e->cmd));
+      if (e->e.c->cmd)
+        text_printf (&text, "@%s", debug_parser_command_name (e->e.c->cmd));
       if (e->e.c->args.number)
         text_printf (&text, "[A%d]", e->e.c->args.number);
       if (e->e.c->contents.number)
@@ -130,8 +130,8 @@ print_element_debug_parser (const ELEMENT *e, int 
print_parent)
   if (print_parent && e->parent)
     {
       text_append (&text, " <- ");
-      if (e->parent->cmd)
-        text_printf (&text, "@%s", command_name (e->parent->cmd));
+      if (e->parent->e.c->cmd)
+        text_printf (&text, "@%s", command_name (e->parent->e.c->cmd));
       if (e->parent->type)
         text_printf (&text, "(%s)", type_data[e->parent->type].name);
     }
diff --git a/tp/Texinfo/XS/parsetexi/def.c b/tp/Texinfo/XS/parsetexi/def.c
index e458abfcf2..dc332f8608 100644
--- a/tp/Texinfo/XS/parsetexi/def.c
+++ b/tp/Texinfo/XS/parsetexi/def.c
@@ -23,6 +23,7 @@
 #include "command_ids.h"
 #include "tree_types.h"
 #include "text.h"
+#include "types_data.h"
 #include "tree.h"
 #include "builtin_commands.h"
 #include "extra.h"
@@ -42,14 +43,14 @@ gather_def_item (ELEMENT *current, enum command_id 
next_command)
 {
   int contents_count, i;
 
-  if (!current->cmd)
+  if (!current->e.c->cmd)
     return;
 
   /* Check this isn't an "x" type command.
      "This may happen for a construct like:
      @deffnx a b @section
      but otherwise the end of line will lead to the command closing." */
-  if (command_data(current->cmd).flags & CF_line)
+  if (command_data(current->e.c->cmd).flags & CF_line)
     return;
 
   contents_count = current->e.c->contents.number;
@@ -72,7 +73,7 @@ gather_def_item (ELEMENT *current, enum command_id 
next_command)
       int j;
       ELEMENT *def_item;
 
-      if (current->cmd == CM_defblock
+      if (current->e.c->cmd == CM_defblock
        /* all content between @defblock and first @def*line */
           && i == contents_count)
         type = ET_before_defline;
@@ -481,8 +482,9 @@ parse_def (enum command_id command, ELEMENT *current)
           continue;
         }
       if (e->type == ET_def_line_arg && e->e.c->contents.number == 1
-          && e->e.c->contents.list[0]->cmd
-          && e->e.c->contents.list[0]->cmd != CM_code)
+          && !(type_data[e->e.c->contents.list[0]->type].flags & TF_text)
+          && e->e.c->contents.list[0]->e.c->cmd
+          && e->e.c->contents.list[0]->e.c->cmd != CM_code)
         {
           type = set_type_not_arg;
         }
diff --git a/tp/Texinfo/XS/parsetexi/end_line.c 
b/tp/Texinfo/XS/parsetexi/end_line.c
index 6024d5b2a5..1faf894968 100644
--- a/tp/Texinfo/XS/parsetexi/end_line.c
+++ b/tp/Texinfo/XS/parsetexi/end_line.c
@@ -25,6 +25,7 @@
 #include "element_types.h"
 #include "tree_types.h"
 #include "text.h"
+#include "types_data.h"
 #include "tree.h"
 #include "extra.h"
 #include "builtin_commands.h"
@@ -112,7 +113,7 @@ parse_line_command_args (ELEMENT *line_command)
   enum command_id cmd;
   const char *line;
 
-  cmd = line_command->cmd;
+  cmd = line_command->e.c->cmd;
   if (arg->e.c->contents.number == 0)
    {
      command_error (line_command, "@%s missing argument", command_name(cmd));
@@ -787,9 +788,9 @@ end_line_starting_block (ELEMENT *current)
   enum command_id command;
 
   if (current->parent->flags & EF_def_line)
-    command = current->parent->parent->cmd;
+    command = current->parent->parent->e.c->cmd;
   else
-    command = current->parent->cmd;
+    command = current->parent->e.c->cmd;
 
   if (command_data(command).flags & CF_contain_basic_inline)
       (void) pop_command (&nesting_context.basic_inline_stack_block);
@@ -837,23 +838,25 @@ end_line_starting_block (ELEMENT *current)
             {
               max_columns++;
             }
-          else if (e->type == ET_normal_text && e->e.text->end > 0)
+          else if (e->type == ET_normal_text)
             {
               /*
               TODO: this should be a warning or an error - all prototypes
               on a @multitable line should be in braces, as documented in the
               Texinfo manual.
+              if (e->e.text->end > 0)
+                 .....
                */
             }
           else
             {
-              if (e->cmd != CM_c && e->cmd != CM_comment)
+              if (e->e.c->cmd != CM_c && e->e.c->cmd != CM_comment)
                 {
                   char *texi;
                   texi = convert_to_texinfo (e);
                   command_warn (current->parent,
                                 "unexpected argument on @%s line: %s",
-                                command_name(current->parent->cmd),
+                                command_name(current->parent->e.c->cmd),
                                 texi);
                   free (texi);
                 }
@@ -902,7 +905,7 @@ end_line_starting_block (ELEMENT *current)
               ELEMENT *g;
               if (current->e.c->args.list[0]->e.c->contents.number > 1)
                 command_error (current, "superfluous argument to @%s",
-                               command_name(current->cmd));
+                               command_name(current->e.c->cmd));
               g = current->e.c->args.list[0]->e.c->contents.list[0];
               /* Check if @enumerate specification is either a single
                  letter or a string of digits. */
@@ -949,12 +952,12 @@ end_line_starting_block (ELEMENT *current)
             {
               ELEMENT *e = k_command_as_arg->k.element;
               if (!(command_flags(e) & CF_brace)
-                  || (command_data(e->cmd).data == BRACE_noarg))
+                  || (command_data(e->e.c->cmd).data == BRACE_noarg))
                 {
                   command_error (current,
                                  "command @%s not accepting argument in brace "
                                  "should not be on @%s line",
-                                 command_name(e->cmd),
+                                 command_name(e->e.c->cmd),
                                  command_name(command));
                   k_command_as_arg->key = AI_key_none;
                   k_command_as_arg->type = extra_deleted;
@@ -983,13 +986,21 @@ end_line_starting_block (ELEMENT *current)
                 }
               for (; i < e->e.c->contents.number; i++)
                 {
+                  int not_command_as_arg = 0;
                   ELEMENT *f = contents_child_by_index (e, i);
-                  if (f->cmd != CM_c
-                      && f->cmd != CM_comment
-                      && !(f->type == ET_normal_text
-                           && f->e.text->end > 0
-                           && !*(f->e.text->text
-                                 + strspn (f->e.text->text, 
whitespace_chars))))
+                  if (f->type == ET_normal_text)
+                    {
+                      if (f->e.text->end > 0
+                          && *(f->e.text->text
+                                 + strspn (f->e.text->text, whitespace_chars)))
+                        not_command_as_arg = 1;
+                    }
+                  else if (!(f->type == ET_lineraw_command
+                             && (f->e.c->cmd == CM_c
+                                 || f->e.c->cmd == CM_comment)))
+                    not_command_as_arg = 1;
+
+                  if (not_command_as_arg)
                     {
                       k_command_as_arg->key = AI_key_none;
                       k_command_as_arg->type = extra_deleted;
@@ -1004,12 +1015,12 @@ end_line_starting_block (ELEMENT *current)
                   && command_as_arg_e->e.c->args.number <= 0
               /* only brace commands are registered as command_as_argument
                  so we can assume that the following is true:
-                 && command_data(command_as_arg_e->cmd).flags & CF_brace
+                 && command_data(command_as_arg_e->e.c->cmd).flags & CF_brace
                */
-                  && command_data(command_as_arg_e->cmd).data != BRACE_noarg)
+                  && command_data(command_as_arg_e->e.c->cmd).data != 
BRACE_noarg)
                 {
                    command_warn (current, "@%s expected braces",
-                                 command_name(command_as_arg_e->cmd));
+                                 command_name(command_as_arg_e->e.c->cmd));
                 }
             }
         }
@@ -1018,7 +1029,7 @@ end_line_starting_block (ELEMENT *current)
       k = lookup_extra (current, AI_key_command_as_argument);
       if (k && k->k.element)
         {
-          enum command_id as_argument_cmd = k->k.element->cmd;
+          enum command_id as_argument_cmd = k->k.element->e.c->cmd;
           if (as_argument_cmd
               && (command_data(as_argument_cmd).flags & CF_accent))
             {
@@ -1220,7 +1231,7 @@ end_line_misc_line (ELEMENT *current)
   int included_file = 0;
   SOURCE_MARK *include_source_mark = 0;
 
-  data_cmd = cmd = current->parent->cmd;
+  data_cmd = cmd = current->parent->e.c->cmd;
   /* we are in a command line context, so the @item command information is
      associated to CM_item_LINE */
   if (cmd == CM_item)
@@ -1267,7 +1278,7 @@ end_line_misc_line (ELEMENT *current)
       else
         {
           add_extra_string (current, AI_key_text_arg, text);
-          if (current->cmd == CM_end)
+          if (current->e.c->cmd == CM_end)
             {
               const char *line = text;
 
@@ -1306,7 +1317,7 @@ end_line_misc_line (ELEMENT *current)
             {
               /* An error message is issued below. */
             }
-          else if (current->cmd == CM_include)
+          else if (current->e.c->cmd == CM_include)
             {
               int status;
               char *fullpath, *sys_filename;
@@ -1346,7 +1357,7 @@ end_line_misc_line (ELEMENT *current)
                   free (fullpath);
                 }
             }
-          else if (current->cmd == CM_verbatiminclude)
+          else if (current->e.c->cmd == CM_verbatiminclude)
             {
               char *fullpath, *sys_filename;
               GLOBAL_INFO *global_info = &parsed_document->global_info;
@@ -1362,7 +1373,7 @@ end_line_misc_line (ELEMENT *current)
                 add_string (fullpath, &global_info->included_files);
               free (fullpath);
             }
-          else if (current->cmd == CM_documentencoding)
+          else if (current->e.c->cmd == CM_documentencoding)
             {
               int i;
               char *normalized_text;
@@ -1479,7 +1490,7 @@ end_line_misc_line (ELEMENT *current)
                 }
               free (normalized_text);
             }
-          else if (current->cmd == CM_documentlanguage)
+          else if (current->e.c->cmd == CM_documentlanguage)
             {
               const char *p;
 
@@ -1555,11 +1566,11 @@ end_line_misc_line (ELEMENT *current)
               *p1 = '\0';
             }
           command_error (current, "bad argument to @%s: %s",
-                         command_name(current->cmd), p);
+                         command_name(current->e.c->cmd), p);
           free (texi_line);
         }
     }
-  else if (current->cmd == CM_node)
+  else if (current->e.c->cmd == CM_node)
     {
       int i;
       ELEMENT *label_element;
@@ -1612,7 +1623,7 @@ end_line_misc_line (ELEMENT *current)
         }
       current_node = current;
     }
-  else if (current->cmd == CM_listoffloats)
+  else if (current->e.c->cmd == CM_listoffloats)
     {
       parse_float_type (current);
     }
@@ -1621,36 +1632,37 @@ end_line_misc_line (ELEMENT *current)
       if (command_flags(current) & CF_index_entry_command)
         {
           current->e.c->string_info[sit_command_name]
-            = strdup (command_name(current->cmd));
+            = strdup (command_name(current->e.c->cmd));
         }
       /* All the other "line" commands. Check they have an argument. Empty
          @top is allowed. */
       if (current->e.c->args.list[0]->e.c->contents.number == 0
-          && current->cmd != CM_top)
+          && current->e.c->cmd != CM_top)
         {
           command_warn (current, "@%s missing argument",
-                        command_name(current->cmd));
+                        command_name(current->e.c->cmd));
         }
       else
         {
-          if ((current->parent->cmd == CM_ftable
-               || current->parent->cmd == CM_vtable)
-              && (current->cmd == CM_item || current->cmd == CM_itemx))
+          if ((current->parent->e.c->cmd == CM_ftable
+               || current->parent->e.c->cmd == CM_vtable)
+              && (current->e.c->cmd == CM_item
+                  || current->e.c->cmd == CM_itemx))
             {
-              enter_index_entry (current->parent->cmd,
+              enter_index_entry (current->parent->e.c->cmd,
                                  current);
             }
           else if (command_flags(current) & CF_index_entry_command)
           /* Index commands */
             {
-              enter_index_entry (current->cmd, current);
+              enter_index_entry (current->e.c->cmd, current);
             }
           /* if there is a brace command interrupting an index or subentry
              command, replace the internal 
internal_spaces_before_brace_in_index
              text type with its final type depending on whether there is
              text after the brace command. */
           if ((command_flags(current) & CF_index_entry_command
-                || current->cmd == CM_subentry))
+                || current->e.c->cmd == CM_subentry))
             {
               set_non_ignored_space_in_index_before_command (
                                                      
current->e.c->args.list[0]);
@@ -1673,7 +1685,7 @@ end_line_misc_line (ELEMENT *current)
       /* If not a conditional */
       if (command_data(end_id).data != BLOCK_conditional
           /* ignored conditional */
-          || current->cmd == end_id
+          || current->e.c->cmd == end_id
           /* not a non-ignored conditional */
           || (conditional_number == 0
               || top_conditional_stack ()->command != end_id))
@@ -1691,7 +1703,7 @@ end_line_misc_line (ELEMENT *current)
 
               add_to_element_contents (closed_command, end_elt);
 
-              if (command_data(closed_command->cmd).data == BLOCK_menu
+              if (command_data(closed_command->e.c->cmd).data == BLOCK_menu
                   && command_data(current_context_command ()).data
                                                               == BLOCK_menu)
                 {
@@ -1763,7 +1775,7 @@ end_line_misc_line (ELEMENT *current)
   else if (cmd == CM_columnfractions)
     {
       /* Check if in multitable. */
-      if (!current->parent || current->parent->cmd != CM_multitable)
+      if (!current->parent || current->parent->e.c->cmd != CM_multitable)
         {
           line_error ("@columnfractions only meaningful on a @multitable 
line");
         }
@@ -1798,7 +1810,7 @@ end_line_misc_line (ELEMENT *current)
               add_extra_element (current, AI_key_associated_part, 
current_part);
               add_extra_element (current_part, AI_key_part_associated_section,
                                  current);
-              if (current->cmd == CM_top)
+              if (current->e.c->cmd == CM_top)
                 {
                   line_error_ext (MSG_warning, 0, 
&current_part->e.c->source_info,
                          "@part should not be associated with @top");
diff --git a/tp/Texinfo/XS/parsetexi/handle_commands.c 
b/tp/Texinfo/XS/parsetexi/handle_commands.c
index 9d3db12c85..6b49e3a0cd 100644
--- a/tp/Texinfo/XS/parsetexi/handle_commands.c
+++ b/tp/Texinfo/XS/parsetexi/handle_commands.c
@@ -52,11 +52,11 @@
 static ELEMENT *
 item_container_parent (const ELEMENT *current)
 {
-  if ((current->cmd == CM_item
+  if ((current->e.c->cmd == CM_item
        || current->type == ET_before_item)
       && current->parent
-      && ((current->parent->cmd == CM_itemize
-           || current->parent->cmd == CM_enumerate)))
+      && ((current->parent->e.c->cmd == CM_itemize
+           || current->parent->e.c->cmd == CM_enumerate)))
     {
       return current->parent;
     }
@@ -90,8 +90,10 @@ check_no_text (const ELEMENT *current)
                    && g->e.text->end > 0
                    && g->e.text->text[strspn 
                                        (g->e.text->text, whitespace_chars)])
-                  || (g->cmd && g->cmd != CM_c
-                      && g->cmd != CM_comment
+                  /* empty_line text is possible */
+                  || (type_data[g->type].flags & TF_at_command
+                      && g->e.c->cmd != CM_c
+                      && g->e.c->cmd != CM_comment
                       && g->type != ET_index_entry_command))
                 {
                   after_paragraph = 1;
@@ -110,7 +112,7 @@ in_paragraph (ELEMENT *current)
 {
   while (current->parent
          && (command_flags(current->parent) & CF_brace)
-         && !(command_data(current->parent->cmd).data == BRACE_context))
+         && !(command_data(current->parent->e.c->cmd).data == BRACE_context))
     {
       current = current->parent->parent;
     }
@@ -419,7 +421,7 @@ handle_other_command (ELEMENT *current, const char 
**line_inout,
                 {
                   line_error ("@%s not meaningful inside `@%s' block",
                               command_name(cmd),
-                              command_name(parent->cmd));
+                              command_name(parent->e.c->cmd));
                 }
               current = begin_preformatted (current);
             }
@@ -428,7 +430,7 @@ handle_other_command (ELEMENT *current, const char 
**line_inout,
             {
               line_error ("@%s not meaningful inside `@%s' block",
                           command_name(cmd),
-                          command_name(parent->cmd));
+                          command_name(parent->e.c->cmd));
               current = begin_preformatted (current);
             }
           /* In a @multitable */
@@ -581,7 +583,7 @@ handle_line_command (ELEMENT *current, const char 
**line_inout,
           const ELEMENT *p = current;
           while (p)
             {
-              if (p->cmd == CM_copying)
+              if (p->e.c->cmd == CM_copying)
                 {
                   line_error ("@%s not allowed inside `@copying' block",
                               command_name(cmd));
@@ -773,7 +775,7 @@ handle_line_command (ELEMENT *current, const char 
**line_inout,
                                             AI_key_node_description);
                   if (e_description)
                     {
-                      if (e_description->cmd == cmd)
+                      if (e_description->e.c->cmd == cmd)
                         line_warn ("multiple node @nodedescription");
                       else
                         /* silently replace nodedescriptionblock */
@@ -795,14 +797,14 @@ handle_line_command (ELEMENT *current, const char 
**line_inout,
               ELEMENT *parent = current->parent;
 
               if (!(command_flags(parent) & CF_index_entry_command)
-                  && parent->cmd != CM_subentry)
+                  && parent->e.c->cmd != CM_subentry)
                 {
                   line_warn ("@subentry should only occur in an index entry");
                 }
 
               add_extra_element (parent, AI_key_subentry, command_e);
 
-              if (parent->cmd == CM_subentry)
+              if (parent->e.c->cmd == CM_subentry)
                 {
                   int status;
                   int parent_level
@@ -879,7 +881,7 @@ handle_line_command (ELEMENT *current, const char 
**line_inout,
 
               command_e->flags |= EF_def_line;
 
-              cmdname = current->cmd;
+              cmdname = current->e.c->cmd;
               if (cmdname != CM_defblock)
                 after_paragraph = check_no_text (current);
               else
@@ -942,13 +944,13 @@ handle_line_command (ELEMENT *current, const char 
**line_inout,
               parent = parent->parent;
               if (parent->type == ET_brace_command_context)
                 break;
-              if (parent->cmd == CM_titlepage)
+              if (parent->e.c->cmd == CM_titlepage)
                 {
                   add_extra_element (current, AI_key_titlepage, parent);
                   found = 1; break;
                 }
-              else if (parent->cmd == CM_quotation
-                       || parent->cmd == CM_smallquotation)
+              else if (parent->e.c->cmd == CM_quotation
+                       || parent->e.c->cmd == CM_smallquotation)
                 {
                   ELEMENT_LIST *l = add_extra_contents (parent,
                                                         AI_key_authors, 0);
@@ -1149,13 +1151,13 @@ handle_block_command (ELEMENT *current, const char 
**line_inout,
       bla = new_element (ET_block_line_arg);
       add_to_element_args (current, bla);
 
-      if (command_data (current->cmd).args_number > 1)
+      if (command_data (current->e.c->cmd).args_number > 1)
         {
           counter_push (&count_remaining_args,
                         current,
-                        command_data (current->cmd).args_number - 1);
+                        command_data (current->e.c->cmd).args_number - 1);
         }
-      else if (command_data (current->cmd).flags & CF_variadic)
+      else if (command_data (current->e.c->cmd).flags & CF_variadic)
         {
           /* Unlimited args */
           counter_push (&count_remaining_args, current,
@@ -1212,7 +1214,7 @@ handle_brace_command (ELEMENT *current, const char 
**line_inout,
   if (cmd == CM_sortas)
     {
       if (!(command_flags(current->parent) & CF_index_entry_command)
-          && current->parent->cmd != CM_subentry)
+          && current->parent->e.c->cmd != CM_subentry)
         {
           line_warn ("@%s should only appear in an index entry",
                      command_name(cmd));
diff --git a/tp/Texinfo/XS/parsetexi/indices.c 
b/tp/Texinfo/XS/parsetexi/indices.c
index ea55680a80..5051b19bdc 100644
--- a/tp/Texinfo/XS/parsetexi/indices.c
+++ b/tp/Texinfo/XS/parsetexi/indices.c
@@ -23,6 +23,7 @@
 #include "tree_types.h"
 /* document used in complete_indices */
 #include "document_types.h"
+#include "types_data.h"
 #include "tree.h"
 #include "extra.h"
 #include "builtin_commands.h"
@@ -328,15 +329,17 @@ set_non_ignored_space_in_index_before_command (ELEMENT 
*content)
           /* set to "spaces_at_end" in case there are only spaces after */
           e->type = ET_spaces_at_end;
         }
-      else if (pending_spaces_element
-                && ! (e->cmd == CM_sortas
-                       || e->cmd == CM_seeentry
-                       || e->cmd == CM_seealso
-                       || e->type == ET_spaces_after_close_brace)
-                && (! check_space_element (e)))
+      else if (pending_spaces_element)
         {
-          pending_spaces_element->type = ET_normal_text;
-          pending_spaces_element = 0;
+          if (! (!(type_data[e->type].flags & TF_text)
+                 && (e->e.c->cmd == CM_sortas
+                     || e->e.c->cmd == CM_seeentry
+                     || e->e.c->cmd == CM_seealso))
+              && (! check_space_element (e)))
+            {
+              pending_spaces_element->type = ET_normal_text;
+              pending_spaces_element = 0;
+            }
         }
     }
 }
diff --git a/tp/Texinfo/XS/parsetexi/macro.c b/tp/Texinfo/XS/parsetexi/macro.c
index db24b63276..b0c0d3d159 100644
--- a/tp/Texinfo/XS/parsetexi/macro.c
+++ b/tp/Texinfo/XS/parsetexi/macro.c
@@ -790,7 +790,7 @@ handle_macro (ELEMENT *current, const char **line_inout, 
enum command_id cmd)
   macro_expansion_nr++;
   debug ("MACRO EXPANSION NUMBER %d %s", macro_expansion_nr, 
command_name(cmd));
 
-  if (macro->cmd != CM_rmacro)
+  if (macro->e.c->cmd != CM_rmacro)
     {
       if (expanding_macro (command_name(cmd)))
         {
@@ -810,7 +810,7 @@ handle_macro (ELEMENT *current, const char **line_inout, 
enum command_id cmd)
       error = 1;
     }
 
-  if (macro->cmd == CM_linemacro)
+  if (macro->e.c->cmd == CM_linemacro)
     {
       macro_call_element = new_element (ET_linemacro_call);
       expand_linemacro_arguments (macro, &line, cmd, macro_call_element);
@@ -823,9 +823,9 @@ handle_macro (ELEMENT *current, const char **line_inout, 
enum command_id cmd)
       p = line + strspn (line, whitespace_chars);
       if (*p == '{')
         {
-          if (macro->cmd == CM_macro)
+          if (macro->e.c->cmd == CM_macro)
             macro_call_element = new_element (ET_macro_call);
-          else if (macro->cmd == CM_rmacro)
+          else if (macro->e.c->cmd == CM_rmacro)
             macro_call_element = new_element (ET_rmacro_call);
           if (p - line > 0)
             {
@@ -847,17 +847,17 @@ handle_macro (ELEMENT *current, const char **line_inout, 
enum command_id cmd)
           /* As agreed on the bug-texinfo mailing list, no warn when zero
              arg and not called with {}. */
 
-          if (macro->cmd == CM_macro)
+          if (macro->e.c->cmd == CM_macro)
             macro_call_element = new_element (ET_macro_call);
-          else if (macro->cmd == CM_rmacro)
+          else if (macro->e.c->cmd == CM_rmacro)
             macro_call_element = new_element (ET_rmacro_call);
         }
       else
         {
           ELEMENT *arg_elt = new_element (ET_line_arg);
-          if (macro->cmd == CM_macro)
+          if (macro->e.c->cmd == CM_macro)
             macro_call_element = new_element (ET_macro_call_line);
-          else if (macro->cmd == CM_rmacro)
+          else if (macro->e.c->cmd == CM_rmacro)
             macro_call_element = new_element (ET_rmacro_call_line);
           add_to_element_args (macro_call_element, arg_elt);
 
@@ -942,7 +942,7 @@ handle_macro (ELEMENT *current, const char **line_inout, 
enum command_id cmd)
 
   debug ("MACROBODY: %s||||||", expanded_macro_text);
 
-  if (macro->cmd == CM_linemacro)
+  if (macro->e.c->cmd == CM_linemacro)
     macro_source_mark = new_source_mark (SM_type_linemacro_expansion);
   else
     macro_source_mark = new_source_mark (SM_type_macro_expansion);
diff --git a/tp/Texinfo/XS/parsetexi/menus.c b/tp/Texinfo/XS/parsetexi/menus.c
index 95fb42070e..856b94811d 100644
--- a/tp/Texinfo/XS/parsetexi/menus.c
+++ b/tp/Texinfo/XS/parsetexi/menus.c
@@ -307,7 +307,9 @@ end_line_menu_entry (ELEMENT *current)
       ELEMENT *last = last_contents_child (current);
 
       if (last
-          && (last->cmd == CM_c || last->cmd == CM_comment))
+         /* last can be a text element */
+          && last->type == ET_lineraw_command
+          && (last->e.c->cmd == CM_c || last->e.c->cmd == CM_comment))
         {
           end_comment = pop_element_from_contents (current);
           last = last_contents_child (current);
diff --git a/tp/Texinfo/XS/parsetexi/multitable.c 
b/tp/Texinfo/XS/parsetexi/multitable.c
index 034688012b..1afbcd2ca0 100644
--- a/tp/Texinfo/XS/parsetexi/multitable.c
+++ b/tp/Texinfo/XS/parsetexi/multitable.c
@@ -31,9 +31,9 @@
 ELEMENT *
 item_multitable_parent (ELEMENT *current)
 {
-  if (current->cmd == CM_headitem
-      || current->cmd == CM_item
-      || current->cmd == CM_tab)
+  if (current->e.c->cmd == CM_headitem
+      || current->e.c->cmd == CM_item
+      || current->e.c->cmd == CM_tab)
     {
       if (current->parent && current->parent->parent)
         current = current->parent->parent;
@@ -43,7 +43,7 @@ item_multitable_parent (ELEMENT *current)
       current = current->parent;
     }
 
-  if (current->cmd == CM_multitable)
+  if (current->e.c->cmd == CM_multitable)
     return current;
 
   return 0;
@@ -70,7 +70,7 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
     {
       /* before_item before the first @item, nothing to do for now */
       if (next_command == CM_itemx)
-        line_error ("@itemx should not begin @%s", command_name 
(current->cmd));
+        line_error ("@itemx should not begin @%s", command_name 
(current->e.c->cmd));
       return;
     }
 
@@ -82,7 +82,9 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
   for (i = contents_count - 1; i >= 0; i--)
     {
       e = contents_child_by_index (current, i);
-      if (e->cmd == CM_item || e->cmd == CM_itemx)
+      /* e can be a text element with spaces, mainly empty_line */
+      if (e->type == ET_line_command
+          && (e->e.c->cmd == CM_item || e->e.c->cmd == CM_itemx))
         {
           begin = i + 1;
           break;
@@ -94,7 +96,7 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
   /* Find the 'end' */
   if (next_command)
     {
-      /* Don't absorb trailing index entries as they are included with a
+      /* Don't absorb trailing index entries as they may be included with a
          following @item. */
       for (i = contents_count - 1; i >= begin; i--)
         {
@@ -121,6 +123,7 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
   if (type == ET_table_definition)
     {
       ELEMENT *before_item = 0;
+      int before_item_content_nr = 0;
       ELEMENT *table_entry = new_element (ET_table_entry);
       ELEMENT *table_term = new_element (ET_table_term);
       add_to_element_contents (table_entry, table_term);
@@ -129,6 +132,11 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
          do the same for ET_table_term, starting from the beginning of the
          table_definition going back to the previous table entry or beginning
          of the table. */
+      /* Most of the content is already in a table_entry.  There is always
+         an @item/@itemx line command gathered, and also possibly index_entries
+         left after the table_entry (see just above), and, in case of @itemx
+         the inter_item element, if there is one.  Nothing else should
+         end up in the table_term */
        for (i = begin - 1; i >= 0; i--)
          {
            e = contents_child_by_index (current, i);
@@ -138,7 +146,10 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
           /* register the before_item if we reached it in order to
              reparent some before_item content to the first item */
                if (e->type == ET_before_item)
-                 before_item = e;
+                 {
+                   before_item = e;
+                   before_item_content_nr = before_item->e.c->contents.number;
+                 }
                term_begin = i + 1;
                break;
              }
@@ -151,21 +162,25 @@ gather_previous_item (ELEMENT *current, enum command_id 
next_command)
       for (i = 0; i < table_term->e.c->contents.number; i++)
         contents_child_by_index (table_term, i)->parent = table_term;
       remove_slice_from_contents (current, term_begin, begin);
-      if (before_item)
+      if (before_item && before_item_content_nr > 0)
         {
-          if (before_item->e.c->contents.number > 0)
-            debug ("REPARENT before_item content");
+          debug ("REPARENT before_item content");
           /* Reparent any trailing index entries in the before_item to the
              beginning of table term. */
-          while (before_item->e.c->contents.number > 0
-                   && (last_contents_child (before_item)->type
-                         == ET_index_entry_command
-                       || last_contents_child (before_item)->cmd == CM_c
-                       || last_contents_child (before_item)->cmd
-                         == CM_comment))
+          for (i = 0; i < before_item_content_nr; i++)
             {
-              ELEMENT *e = pop_element_from_contents (before_item);
-              insert_into_contents (table_term, e, 0);
+              ELEMENT* last_elt = last_contents_child (before_item);
+           /* last_elt can be a spaces text element, such as empty_line */
+              if (last_elt->type == ET_index_entry_command
+                  || (last_elt->type == ET_lineraw_command
+                      && (last_elt->e.c->cmd == CM_c
+                          || last_elt->e.c->cmd == CM_comment)))
+                {
+                  ELEMENT *e = pop_element_from_contents (before_item);
+                  insert_into_contents (table_term, e, 0);
+                }
+              else
+                 break;
             }
         }
 
diff --git a/tp/Texinfo/XS/parsetexi/parser.c b/tp/Texinfo/XS/parsetexi/parser.c
index 818e39e324..cb6b289bc8 100644
--- a/tp/Texinfo/XS/parsetexi/parser.c
+++ b/tp/Texinfo/XS/parsetexi/parser.c
@@ -42,6 +42,7 @@
 #include "counter.h"
 /* for nesting_context */
 #include "context_stack.h"
+#include "convert_to_texinfo.h"
 #include "commands.h"
 #include "debug_parser.h"
 #include "errors_parser.h"
@@ -167,17 +168,22 @@ read_comment (const char *line, int *has_comment)
 int
 check_space_element (ELEMENT *e)
 {
-  if (!(
-          e->cmd == CM_SPACE
-        || e->cmd == CM_TAB
-        || e->cmd == CM_NEWLINE
-        || e->cmd == CM_c
-        || e->cmd == CM_comment
-        || e->cmd == CM_COLON
-        || (type_data[e->type].flags & TF_text
-            && (e->e.text->end == 0
-                || !*(e->e.text->text
-                        + strspn (e->e.text->text, whitespace_chars))))
+  if (type_data[e->type].flags & TF_text)
+    {
+      if (e->e.text->end == 0
+          || !*(e->e.text->text
+                      + strspn (e->e.text->text, whitespace_chars)))
+        return 1;
+      else
+        return 0;
+    }
+  else if (!(
+          e->e.c->cmd == CM_SPACE
+        || e->e.c->cmd == CM_TAB
+        || e->e.c->cmd == CM_NEWLINE
+        || e->e.c->cmd == CM_c
+        || e->e.c->cmd == CM_comment
+        || e->e.c->cmd == CM_COLON
      ))
     {
       return 0;
@@ -198,22 +204,27 @@ text_contents_to_plain_text (ELEMENT *e, int 
*superfluous_arg)
 
   TEXT result; int i;
 
+  /* FIXME check if that can happen, probably not.  If yes, the
+     string should be strdup'ed */
   if (!e)
     return "";
   text_init (&result);
   for (i = 0; i < e->e.c->contents.number; i++)
     {
       const ELEMENT *e1 = contents_child_by_index (e, i);
-      if (type_data[e1->type].flags & TF_text && e1->e.text->end > 0)
-        ADD(e1->e.text->text);
-      else if (e1->cmd == CM_AT_SIGN
-               || e1->cmd == CM_atchar)
+      if (type_data[e1->type].flags & TF_text)
+        {
+          if (e1->e.text->end > 0)
+            ADD(e1->e.text->text);
+        }
+      else if (e1->e.c->cmd == CM_AT_SIGN
+               || e1->e.c->cmd == CM_atchar)
         ADD("@");
-      else if (e1->cmd == CM_OPEN_BRACE
-               || e1->cmd == CM_lbracechar)
+      else if (e1->e.c->cmd == CM_OPEN_BRACE
+               || e1->e.c->cmd == CM_lbracechar)
         ADD("{");
-      else if (e1->cmd == CM_CLOSE_BRACE
-               || e1->cmd == CM_rbracechar)
+      else if (e1->e.c->cmd == CM_CLOSE_BRACE
+               || e1->e.c->cmd == CM_rbracechar)
         ADD("}");
       else
         *superfluous_arg = 1;
@@ -330,7 +341,7 @@ int
 register_global_command (ELEMENT *current)
 {
   GLOBAL_COMMANDS *global_commands = &parsed_document->global_commands;
-  enum command_id cmd = current->cmd;
+  enum command_id cmd = current->e.c->cmd;
   if (cmd == CM_summarycontents)
     cmd = CM_shortcontents;
 
@@ -438,11 +449,17 @@ rearrange_tree_beginning (ELEMENT *before_node_section, 
int document_descriptor)
     {
       ELEMENT *before_setfilename
          = new_element (ET_preamble_before_setfilename);
-      while (before_node_section->e.c->contents.number > 0
-             && before_node_section->e.c->contents.list[0]->cmd != 
CM_setfilename)
+      while (before_node_section->e.c->contents.number > 0)
         {
-          ELEMENT *e = remove_from_contents (before_node_section, 0);
-          add_to_element_contents (before_setfilename, e);
+          ELEMENT *content = before_node_section->e.c->contents.list[0];
+          if (type_data[content->type].flags & TF_text
+              || content->e.c->cmd != CM_setfilename)
+            {/* e should be the same as content */
+              ELEMENT *e = remove_from_contents (before_node_section, 0);
+              add_to_element_contents (before_setfilename, e);
+            }
+          else
+            break;
         }
       if (before_setfilename->e.c->contents.number > 0)
         insert_into_contents (before_node_section, before_setfilename, 0);
@@ -464,8 +481,8 @@ rearrange_tree_beginning (ELEMENT *before_node_section, int 
document_descriptor)
             add_to_element_list (first_types,
                             remove_from_contents (before_node_section, 0));
           else if (next_content->type == ET_paragraph
-                   || (next_content->cmd
-                       && !(command_data(next_content->cmd).flags
+                   || (!(type_data[next_content->type].flags & TF_text)
+                       && !(command_data(next_content->e.c->cmd).flags
                                                       & CF_preamble)))
             break;
           else
@@ -590,14 +607,28 @@ begin_paragraph (ELEMENT *current)
               if (child->type == ET_empty_line
                   || child->type == ET_paragraph)
                 break;
-              if (command_data(child->cmd).flags & CF_close_paragraph)
+              if (type_data[child->type].flags & TF_at_command
+                  && command_data(child->e.c->cmd).flags & CF_close_paragraph)
                 break;
-              if (child->cmd == CM_indent
-                  || child->cmd == CM_noindent)
+              /* after an indent there are ignorable_spaces_after_command
+                 skip through spaces only text element that could be there */
+              if (type_data[child->type].flags & TF_text) {}
+              else if (child->e.c->cmd == CM_indent
+                  || child->e.c->cmd == CM_noindent)
                 {
-                  indent = child->cmd;
+                  indent = child->e.c->cmd;
                   break;
                 }
+         /* skip through @macro definitions, raw block commands, ignored
+            conditional block commands, @author, informational commands,
+            commands meant for titlepage such as @vskip or @title, index
+            commands and types such as def_line (but cannot find an @*indent
+            before), a few brace commands that can be out of paragraphs and
+            do not close paragraphs such as @anchor or @image
+              else
+                fprintf(stderr, "INDENT search skipping through %s\n",
+                        print_element_debug_parser(child, 0));
+                */
               i--;
             }
         }
@@ -969,12 +1000,16 @@ isolate_last_space (ELEMENT *current)
   /* Store a final comment command in the 'info' hash, except for brace
      commands */
   if (current->type != ET_brace_container
-      && current->type != ET_brace_arg
-      && (last_contents_child (current)->cmd == CM_c
-          || last_contents_child (current)->cmd == CM_comment))
+      && current->type != ET_brace_arg)
     {
-      current->elt_info[eit_comment_at_end]
-         = pop_element_from_contents (current);
+      last_elt = last_contents_child (current);
+      if (last_elt->type == ET_lineraw_command
+          && (last_elt->e.c->cmd == CM_c
+              || last_elt->e.c->cmd == CM_comment))
+        {
+          current->elt_info[eit_comment_at_end]
+            = pop_element_from_contents (current);
+        }
     }
 
   if (current->e.c->contents.number == 0)
@@ -1030,18 +1065,19 @@ start_empty_line_after_command (ELEMENT *current, const 
char **line_inout,
   ELEMENT *e;
   int len;
 
-  len = strspn (line, whitespace_chars_except_newline);
-  e = new_text_element (ET_ignorable_spaces_after_command);
-  add_to_element_contents (current, e);
-  text_append_n (e->e.text, line, len);
-  line += len;
-
   if (command)
     {
+      e = new_text_element (ET_internal_spaces_after_command);
       internal_space_holder = command;
-      e->type = ET_internal_spaces_after_command;
     }
+  else
+    e = new_text_element (ET_ignorable_spaces_after_command);
+
+  add_to_element_contents (current, e);
 
+  len = strspn (line, whitespace_chars_except_newline);
+  text_append_n (e->e.text, line, len);
+  line += len;
   *line_inout = line;
 }
 
@@ -1072,8 +1108,8 @@ int
 parent_of_command_as_argument (ELEMENT *current)
 {
   return current->type == ET_block_line_arg
-    && (current->parent->cmd == CM_itemize
-        || command_data(current->parent->cmd).data == BLOCK_item_line)
+    && (current->parent->e.c->cmd == CM_itemize
+        || command_data(current->parent->e.c->cmd).data == BLOCK_item_line)
     && (current->e.c->contents.number == 1);
 }
 
@@ -1082,11 +1118,11 @@ void
 register_command_as_argument (ELEMENT *cmd_as_arg)
 {
   debug ("FOR PARENT @%s command_as_argument %s",
-         command_name(cmd_as_arg->parent->parent->cmd),
-         command_name(cmd_as_arg->cmd));
+         command_name(cmd_as_arg->parent->parent->e.c->cmd),
+         command_name(cmd_as_arg->e.c->cmd));
   add_extra_element (cmd_as_arg->parent->parent,
                      AI_key_command_as_argument, cmd_as_arg);
-  if (cmd_as_arg->cmd == CM_kbd
+  if (cmd_as_arg->e.c->cmd == CM_kbd
       && kbd_formatted_as_code (cmd_as_arg->parent->parent)) {
     cmd_as_arg->parent->parent->flags |= EF_command_as_argument_kbd_code;
   }
@@ -1169,7 +1205,7 @@ check_valid_nesting (ELEMENT *current, enum command_id 
cmd)
 
   int ok = 0; /* Whether nesting is allowed. */
 
-  enum command_id outer = current->parent->cmd;
+  enum command_id outer = current->parent->e.c->cmd;
   unsigned long outer_flags = command_data(outer).flags;
   unsigned long cmd_flags = command_data(cmd).flags;
 
@@ -1259,7 +1295,7 @@ check_valid_nesting (ELEMENT *current, enum command_id 
cmd)
 
   if (!ok)
     {
-      invalid_parent = current->parent->cmd;
+      invalid_parent = current->parent->e.c->cmd;
       if (!invalid_parent)
         {
           /* current_context () == ct_def.  Find def block containing
@@ -1268,7 +1304,7 @@ check_valid_nesting (ELEMENT *current, enum command_id 
cmd)
           while (d->parent
                  && !(d->parent->flags & EF_def_line))
             d = d->parent;
-          invalid_parent = d->parent->parent->cmd;
+          invalid_parent = d->parent->parent->e.c->cmd;
         }
 
       line_warn ("@%s should not appear in @%s",
@@ -1397,16 +1433,17 @@ process_remaining_on_line (ELEMENT **current_inout, 
const char **line_inout)
   debug_nonl ("PROCESS "); debug_print_protected_string (line); debug ("");
   */
 
+  /* at this point we are necessarily in a command or container */
   /********* BLOCK_raw ******************/
   if (command_flags(current) & CF_block
-      && (command_data(current->cmd).data == BLOCK_raw))
+      && (command_data(current->e.c->cmd).data == BLOCK_raw))
     {
       const char *p = line;
       enum command_id cmd = 0;
       int closed_nested_raw = 0;
       /* Check if we are using a macro within a macro. */
-      if (current->cmd == CM_macro || current->cmd == CM_rmacro
-          || current->cmd == CM_linemacro)
+      if (current->e.c->cmd == CM_macro || current->e.c->cmd == CM_rmacro
+          || current->e.c->cmd == CM_linemacro)
         {
           p += strspn (p, whitespace_chars);
           if (!strncmp (p, "@macro", strlen ("@macro")))
@@ -1427,7 +1464,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
           if (*p && !strchr (whitespace_chars, *p))
             cmd = 0;
         }
-      else if (current->cmd == CM_ignore)
+      else if (current->e.c->cmd == CM_ignore)
         {
           p += strspn (p, whitespace_chars);
           if (!strncmp (p, "@ignore", strlen ("@ignore")))
@@ -1440,7 +1477,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
       if (cmd)
         {
           debug ("RAW SECOND LEVEL %s in @%s", command_name(cmd),
-                 command_name(current->cmd));
+                 command_name(current->e.c->cmd));
           push_raw_block_stack (cmd);
         }
       /* Else check if line is "@end ..." for current command. */
@@ -1449,7 +1486,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
           enum command_id top_stack_cmd = raw_block_stack_top ();
           if (top_stack_cmd == CM_NONE)
             {/* current is the first command */
-              top_stack_cmd = current->cmd;
+              top_stack_cmd = current->e.c->cmd;
             }
           if (is_end_current_command (top_stack_cmd, &p, &end_cmd))
             {
@@ -1540,15 +1577,15 @@ process_remaining_on_line (ELEMENT **current_inout, 
const char **line_inout)
     } /********* BLOCK_raw *************/
   /********* (ignored) BLOCK_conditional ******************/
   else if (command_flags(current) & CF_block
-      && (command_data(current->cmd).data == BLOCK_conditional))
+      && (command_data(current->e.c->cmd).data == BLOCK_conditional))
     {
       const char *p = line;
 
       /* check for nested @ifset (so that @end ifset doesn't end the
          the outermost @ifset). */
-      if (current->cmd == CM_ifclear || current->cmd == CM_ifset
-          || current->cmd == CM_ifcommanddefined
-          || current->cmd == CM_ifcommandnotdefined)
+      if (current->e.c->cmd == CM_ifclear || current->e.c->cmd == CM_ifset
+          || current->e.c->cmd == CM_ifcommanddefined
+          || current->e.c->cmd == CM_ifcommandnotdefined)
         {
           ELEMENT *e;
           p += strspn (p, whitespace_chars);
@@ -1561,7 +1598,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
                 {
                   cmd = lookup_command (command);
                   free (command);
-                  if (cmd == current->cmd)
+                  if (cmd == current->e.c->cmd)
                     {
                       e = new_command_element (ET_block_command, cmd);
                       add_to_element_contents (current, e);
@@ -1575,7 +1612,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
 
       p = line;
       /* Else check if line is "@end ..." for current command. */
-      if (is_end_current_command (current->cmd, &p, &end_cmd))
+      if (is_end_current_command (current->e.c->cmd, &p, &end_cmd))
         {
           ELEMENT *e;
 
@@ -1607,7 +1644,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
     } /********* (ignored) BLOCK_conditional *************/
 
   /* Check if parent element is 'verb' */
-  else if (current->parent && current->parent->cmd == CM_verb)
+  else if (current->parent && current->parent->e.c->cmd == CM_verb)
     {
       const char *q;
       const char *delimiter
@@ -1658,8 +1695,8 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
         }
     } /* CM_verb */
   else if (command_flags(current) & CF_block
-           && command_data(current->cmd).data == BLOCK_format_raw
-           && !parser_format_expanded_p (command_name(current->cmd)))
+           && command_data(current->e.c->cmd).data == BLOCK_format_raw
+           && !parser_format_expanded_p (command_name(current->e.c->cmd)))
     {
       ELEMENT *e_elided_rawpreformatted;
       ELEMENT *e_empty_line;
@@ -1680,11 +1717,11 @@ process_remaining_on_line (ELEMENT **current_inout, 
const char **line_inout)
           else
             {
               line_dummy = line;
-              if (is_end_current_command (current->cmd, &line_dummy,
+              if (is_end_current_command (current->e.c->cmd, &line_dummy,
                                           &dummy))
                 {
                   debug ("CLOSED ignored raw preformated %s",
-                         command_name(current->cmd));
+                         command_name(current->e.c->cmd));
                   break;
                 }
               else
@@ -1895,7 +1932,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
      Need to be done as early as possible such that no other condition
      prevail and lead to a missed command */
   if (command_flags(current) & CF_brace && *line != '{'
-      && command_data(current->cmd).data != BRACE_accent
+      && command_data(current->e.c->cmd).data != BRACE_accent
       && parent_of_command_as_argument (current->parent))
     {
       register_command_as_argument (current);
@@ -1904,7 +1941,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
 
   /* command but before an opening brace, otherwise current
      would be an argument type and not the command, and a new
-     @-command was found.  This means that the current->cmd
+     @-command was found.  This means that the current->e.c->cmd
      argument (an opening brace, or a character after spaces for
      accent commands) was not found and there is already a new command.
 
@@ -1918,7 +1955,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
   if (command_flags(current) & CF_brace && (cmd || command))
     {
       line_error ("@%s expected braces",
-                  command_name(current->cmd));
+                  command_name(current->e.c->cmd));
       if (current->e.c->contents.number > 0)
         gather_spaces_after_cmd_before_arg (current);
       current = current->parent;
@@ -1972,7 +2009,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
   if (command_flags(current) & CF_brace && *line != '{')
     {
       debug_nonl ("BRACE CMD: no brace after @%s||| ",
-                  command_name (current->cmd));
+                  command_name (current->e.c->cmd));
       debug_print_protected_string (line); debug ("");
 
       if (strchr (whitespace_chars, *line)
@@ -1988,7 +2025,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
                if (*(line + i) == '\n')
                  {
                    line_warn ("command `@%s' must not be followed by new line",
-                              command_name(current->cmd));
+                              command_name(current->e.c->cmd));
                    if (current_context () == ct_def
                        || current_context () == ct_line)
                      {
@@ -2046,7 +2083,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
                  {
                    debug ("BRACE CMD before brace second newline stops 
spaces");
                    line_error ("@%s expected braces",
-                               command_name(current->cmd));
+                               command_name(current->e.c->cmd));
                    gather_spaces_after_cmd_before_arg (current);
                    current = current->parent;
                  }
@@ -2082,11 +2119,11 @@ process_remaining_on_line (ELEMENT **current_inout, 
const char **line_inout)
 
           e2 = new_text_element (ET_normal_text);
           text_append_n (e2->e.text, line, char_len);
-          debug ("ACCENT @%s following_arg: %s", command_name(current->cmd),
+          debug ("ACCENT @%s following_arg: %s", 
command_name(current->e.c->cmd),
                  e2->e.text->text);
           add_to_element_contents (e, e2);
 
-          if (current->cmd == CM_dotless
+          if (current->e.c->cmd == CM_dotless
               && *line != 'i' && *line != 'j')
             {
               line_error ("@dotless expects `i' or `j' as argument, "
@@ -2098,7 +2135,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
       else
         {
           line_error ("@%s expected braces",
-                      command_name(current->cmd));
+                      command_name(current->e.c->cmd));
           if (current->e.c->contents.number > 0)
             gather_spaces_after_cmd_before_arg (current);
           current = current->parent;
@@ -2296,7 +2333,7 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
           the internal space type is not processed and remains as is in
           the final tree. */
           && (command_flags(current->parent) & CF_index_entry_command
-               || current->parent->cmd == CM_subentry))
+               || current->parent->e.c->cmd == CM_subentry))
         {
           ELEMENT *last_elt = last_contents_child (current);
 
@@ -2388,7 +2425,8 @@ process_remaining_on_line (ELEMENT **current_inout, const 
char **line_inout)
       /* comma as a command argument separator */
       if (counter_value (&count_remaining_args, current->parent) > 0)
         current = handle_comma (current, &line);
-      else if (current->type == ET_line_arg && current->parent->cmd == CM_node)
+      else if (current->type == ET_line_arg
+               && current->parent->e.c->cmd == CM_node)
         line_warn ("superfluous arguments for node");
       else
         current = merge_text (current, ",", 1, 0);
@@ -2516,11 +2554,12 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
          element type can be changed in 'abort_empty_line' when more text is
          read. */
       if (!(((command_flags(current) & CF_block)
-             && ((command_data(current->cmd).data == BLOCK_raw
-                  || command_data(current->cmd).data == BLOCK_conditional)
-                 || (command_data(current->cmd).data == BLOCK_format_raw
-                     && !parser_format_expanded_p 
(command_name(current->cmd)))))
-            || (current->parent && current->parent->cmd == CM_verb))
+             && ((command_data(current->e.c->cmd).data == BLOCK_raw
+                  || command_data(current->e.c->cmd).data == BLOCK_conditional)
+                 || (command_data(current->e.c->cmd).data == BLOCK_format_raw
+                     && !parser_format_expanded_p
+                                              
(command_name(current->e.c->cmd)))))
+            || (current->parent && current->parent->e.c->cmd == CM_verb))
           && current_context () != ct_def)
         {
           ELEMENT *e;
diff --git a/tp/Texinfo/XS/parsetexi/separator.c 
b/tp/Texinfo/XS/parsetexi/separator.c
index 1670ff294d..607f4cd47d 100644
--- a/tp/Texinfo/XS/parsetexi/separator.c
+++ b/tp/Texinfo/XS/parsetexi/separator.c
@@ -53,23 +53,22 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
 
   if (command_flags(current) & CF_brace)
     {
-      enum command_id command;
+      enum command_id cmd = current->e.c->cmd;
       ELEMENT *arg;
 
-      command = current->cmd;
 
       /* if there is already content it is for spaces_after_cmd_before_arg */
       if (current->e.c->contents.number > 0)
         gather_spaces_after_cmd_before_arg (current);
 
-      if (command_data(command).flags & CF_contain_basic_inline)
-        push_command (&nesting_context.basic_inline_stack, command);
+      if (command_data(cmd).flags & CF_contain_basic_inline)
+        push_command (&nesting_context.basic_inline_stack, cmd);
 
       counter_push (&count_remaining_args, current,
-                    command_data(current->cmd).args_number);
+                    command_data(cmd).args_number);
       counter_dec (&count_remaining_args);
 
-      if (command == CM_verb)
+      if (cmd == CM_verb)
         {
           arg = new_element (ET_brace_container);
           add_to_element_args (current, arg);
@@ -96,24 +95,24 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
               line += char_len;
             }
         }
-      else if (command_data(command).data == BRACE_context)
+      else if (command_data(cmd).data == BRACE_context)
         {
           arg = new_element (ET_brace_command_context);
           add_to_element_args (current, arg);
           current = arg;
-          if (command == CM_caption || command == CM_shortcaption)
+          if (cmd == CM_caption || cmd == CM_shortcaption)
             {
 #define float floatxx
               ELEMENT *float;
-              const char *caption_cmdname = command_name(command);
+              const char *caption_cmdname = command_name(cmd);
               nesting_context.caption++;
               if (!current->parent->parent
-                  || current->parent->parent->cmd != CM_float)
+                  || current->parent->parent->e.c->cmd != CM_float)
                 {
                   float = current->parent;
-                  while (float->parent && float->cmd != CM_float)
+                  while (float->parent && float->e.c->cmd != CM_float)
                     float = float->parent;
-                  if (float->cmd != CM_float)
+                  if (float->e.c->cmd != CM_float)
                     {
                       line_error ("@%s is not meaningful outside "
                                   "`@float' environment",
@@ -128,16 +127,16 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
                 float = current->parent->parent;
               if (float)
                 {
-                  if ((command == CM_caption
+                  if ((cmd == CM_caption
                        && lookup_extra_element (float, AI_key_caption))
-                      || (command == CM_shortcaption
+                      || (cmd == CM_shortcaption
                           && lookup_extra_element (float, 
AI_key_shortcaption)))
                     line_warn ("ignoring multiple @%s",
                                caption_cmdname);
                   else
                     {
                       add_extra_element (current->parent, AI_key_float, float);
-                      if (command == CM_caption)
+                      if (cmd == CM_caption)
                         add_extra_element (float, AI_key_caption,
                                            current->parent);
                       else
@@ -147,25 +146,25 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
                 }
 #undef float
             }
-          else if (command == CM_footnote)
+          else if (cmd == CM_footnote)
             {
               nesting_context.footnote++;
             }
 
           /* Add to context stack. */
-          switch (command)
+          switch (cmd)
             {
             case CM_footnote:
-              push_context (ct_brace_command, command);
+              push_context (ct_brace_command, cmd);
               break;
             case CM_caption:
-              push_context (ct_brace_command, command);
+              push_context (ct_brace_command, cmd);
               break;
             case CM_shortcaption:
-              push_context (ct_brace_command, command);
+              push_context (ct_brace_command, cmd);
               break;
             case CM_math:
-              push_context (ct_math, command);
+              push_context (ct_math, cmd);
               break;
             default:
               fatal ("no context for command");
@@ -186,8 +185,8 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
       else /* not context brace */
         {
           /* Commands that disregard leading whitespace. */
-          if (command_data(command).data == BRACE_arguments
-              || command_data(command).data == BRACE_inline)
+          if (command_data(cmd).data == BRACE_arguments
+              || command_data(cmd).data == BRACE_inline)
             {
               arg = new_element (ET_brace_arg);
               ELEMENT *e;
@@ -195,8 +194,8 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
               add_to_element_contents (arg, e);
               internal_space_holder = arg;
 
-              if (command == CM_inlineraw)
-                push_context (ct_inlineraw, command);
+              if (cmd == CM_inlineraw)
+                push_context (ct_inlineraw, cmd);
             }
           else
             {
@@ -206,12 +205,12 @@ handle_open_brace (ELEMENT *current, const char 
**line_inout)
           current = arg;
         }
       debug_nonl ("OPENED @%s, remaining: %d ",
-                  command_name (current->parent->cmd),
+                  command_name (current->parent->e.c->cmd),
                   counter_value (&count_remaining_args, current->parent) > 0 ?
                    counter_value (&count_remaining_args, current->parent) : 0);
       debug_parser_print_element (current, 0); debug ("");
     }
-  else if (current->parent && (current->parent->cmd == CM_multitable
+  else if (current->parent && (current->parent->e.c->cmd == CM_multitable
                                || current->parent->flags & EF_def_line))
     {
       ELEMENT *b, *e;
@@ -314,10 +313,10 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
       abort_empty_line (&current);
 
       /* determine if trailing spaces are ignored */
-      if (command_data(current->parent->cmd).data == BRACE_arguments)
+      if (command_data(current->parent->e.c->cmd).data == BRACE_arguments)
         isolate_last_space (current);
 
-      closed_command = current->parent->cmd;
+      closed_command = current->parent->e.c->cmd;
       debug ("CLOSING(brace) @%s", command_data(closed_command).cmdname);
 
       if (current->e.c->contents.number > 0
@@ -330,7 +329,7 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
           current->parent->e.c->source_info = current_source_info;
           if (current->e.c->contents.number == 0)
             line_error ("empty argument in @%s",
-                        command_name(current->parent->cmd));
+                        command_name(current->parent->e.c->cmd));
           else
             {
               check_register_target_element_label (current, current->parent);
@@ -471,7 +470,7 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
                || closed_command == CM_abbr
                || closed_command == CM_acronym)
         {
-          if (current->parent->cmd == CM_inlineraw)
+          if (current->parent->e.c->cmd == CM_inlineraw)
             {
               if (ct_inlineraw != pop_context ())
                 fatal ("inlineraw context expected");
@@ -480,7 +479,7 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
               || current->parent->e.c->args.list[0]->e.c->contents.number == 0)
             {
               line_warn ("@%s missing first argument",
-                         command_name(current->parent->cmd));
+                         command_name(current->parent->e.c->cmd));
             }
         }
       else if (closed_command == CM_errormsg)
@@ -535,19 +534,19 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
         {
           register_command_as_argument (current->parent);
         }
-      else if (current->parent->cmd == CM_sortas
-               || current->parent->cmd == CM_seeentry
-               || current->parent->cmd == CM_seealso)
+      else if (current->parent->e.c->cmd == CM_sortas
+               || current->parent->e.c->cmd == CM_seeentry
+               || current->parent->e.c->cmd == CM_seealso)
         {
           ELEMENT *subindex_elt;
           if (current->parent->parent
               && current->parent->parent->parent
               && ((command_flags(current->parent->parent->parent)
                     & CF_index_entry_command)
-                  || current->parent->parent->parent->cmd == CM_subentry))
+                  || current->parent->parent->parent->e.c->cmd == CM_subentry))
             {
               subindex_elt = current->parent->parent->parent;
-              if (current->parent->cmd == CM_sortas)
+              if (current->parent->e.c->cmd == CM_sortas)
                 {
                   int superfluous_arg;
                   char *arg = text_contents_to_plain_text (current,
@@ -560,7 +559,7 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
               else
                 {
                   ELEMENT *index_elt = subindex_elt;
-                  while (index_elt->cmd == CM_subentry)
+                  while (index_elt->e.c->cmd == CM_subentry)
                     {
                       ELEMENT *subentry_parent
                         = lookup_extra_element (index_elt,
@@ -570,7 +569,7 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
                       else
                         index_elt = subentry_parent;
                     }
-                  if (current->parent->cmd == CM_seeentry)
+                  if (current->parent->e.c->cmd == CM_seeentry)
                     add_extra_element (index_elt, AI_key_seeentry,
                                        current->parent);
                   else
@@ -581,13 +580,13 @@ handle_close_brace (ELEMENT *current, const char 
**line_inout)
         }
       register_global_command (current->parent);
 
-      if (current->parent->cmd == CM_anchor
-          || current->parent->cmd == CM_hyphenation
-          || current->parent->cmd == CM_caption
-          || current->parent->cmd == CM_shortcaption
-          || current->parent->cmd == CM_sortas
-          || current->parent->cmd == CM_seeentry
-          || current->parent->cmd == CM_seealso)
+      if (current->parent->e.c->cmd == CM_anchor
+          || current->parent->e.c->cmd == CM_hyphenation
+          || current->parent->e.c->cmd == CM_caption
+          || current->parent->e.c->cmd == CM_shortcaption
+          || current->parent->e.c->cmd == CM_sortas
+          || current->parent->e.c->cmd == CM_seeentry
+          || current->parent->e.c->cmd == CM_seealso)
         {
           ELEMENT *e;
           e = new_text_element (ET_spaces_after_close_brace);
@@ -628,7 +627,7 @@ handle_comma (ELEMENT *current, const char **line_inout)
   type = current->type;
   current = current->parent;
 
-  if (command_data(current->cmd).data == BRACE_inline)
+  if (command_data(current->e.c->cmd).data == BRACE_inline)
     {
       int expandp = 0;
       const char *format = lookup_extra_string (current, AI_key_format);
@@ -653,9 +652,9 @@ handle_comma (ELEMENT *current, const char **line_inout)
           else
             {
               debug ("INLINE: %s", inline_type);
-              if (current->cmd == CM_inlineraw
-                  || current->cmd == CM_inlinefmt
-                  || current->cmd == CM_inlinefmtifelse)
+              if (current->e.c->cmd == CM_inlineraw
+                  || current->e.c->cmd == CM_inlinefmt
+                  || current->e.c->cmd == CM_inlinefmtifelse)
                 {
                   if (parser_format_expanded_p (inline_type))
                     {
@@ -665,13 +664,13 @@ handle_comma (ELEMENT *current, const char **line_inout)
                   else
                     expandp = 0;
                 }
-              else if (current->cmd == CM_inlineifset
-                       || current->cmd == CM_inlineifclear)
+              else if (current->e.c->cmd == CM_inlineifset
+                       || current->e.c->cmd == CM_inlineifclear)
                 {
                   expandp = 0;
                   if (fetch_value (inline_type))
                     expandp = 1;
-                  if (current->cmd == CM_inlineifclear)
+                  if (current->e.c->cmd == CM_inlineifclear)
                     expandp = !expandp;
                   if (expandp)
                     add_extra_integer (current, AI_key_expand_index, 1);
@@ -683,7 +682,7 @@ handle_comma (ELEMENT *current, const char **line_inout)
             }
 
           /* Skip first argument for a false @inlinefmtifelse */
-          if (!expandp && current->cmd == CM_inlinefmtifelse)
+          if (!expandp && current->e.c->cmd == CM_inlinefmtifelse)
             {
               ELEMENT *e;
               ELEMENT *arg;
@@ -746,7 +745,7 @@ handle_comma (ELEMENT *current, const char **line_inout)
               expandp = 1;
             }
         }
-      else if (current->cmd == CM_inlinefmtifelse)
+      else if (current->e.c->cmd == CM_inlinefmtifelse)
         {
           /* Second part of @inlinefmtifelse when condition is true.  Discard
              second argument. */
diff --git a/tp/Texinfo/XS/structuring_transfo/structuring.c 
b/tp/Texinfo/XS/structuring_transfo/structuring.c
index c90b0f3a0e..610bf90674 100644
--- a/tp/Texinfo/XS/structuring_transfo/structuring.c
+++ b/tp/Texinfo/XS/structuring_transfo/structuring.c
@@ -54,7 +54,7 @@ new_block_command (ELEMENT *element)
   ELEMENT *end_spaces_before = new_text_element (ET_other_text);
   ELEMENT *end_spaces_after = new_text_element (ET_other_text);
   ELEMENT *command_name_text = new_text_element (ET_normal_text);
-  const char *command_name = builtin_command_name (element->cmd);
+  const char *command_name = builtin_command_name (element->e.c->cmd);
 
   text_append (arg_spaces_after->e.text, "\n");
   args->elt_info[eit_spaces_after_argument] = arg_spaces_after;
@@ -102,15 +102,15 @@ sectioning_structure (DOCUMENT *document)
       ELEMENT *content = root->e.c->contents.list[i];
       int level;
 
-      if (!content->cmd || content->cmd == CM_node
-          || content->cmd == CM_bye)
+      if (!content->e.c->cmd || content->e.c->cmd == CM_node
+          || content->e.c->cmd == CM_bye)
         continue;
 
       document->modified_information |= F_DOCM_tree;
 
       add_to_element_list (sections_list, content);
 
-      if (content->cmd == CM_top && !section_top)
+      if (content->e.c->cmd == CM_top && !section_top)
         section_top = content;
 
       level = section_level (content);
@@ -140,7 +140,7 @@ sectioning_structure (DOCUMENT *document)
                 {
                   message_list_command_error (error_messages, options, content,
                         "raising the section level of @%s which is too low",
-                                 builtin_command_name (content->cmd));
+                                 builtin_command_name (content->e.c->cmd));
                   level = prev_section_level + 1;
                 }
               add_to_element_list (section_childs, content);
@@ -193,7 +193,7 @@ sectioning_structure (DOCUMENT *document)
                     with being below the sectioning root, something need to
                     be done */
                     {
-                      if (builtin_command_name (content->cmd == CM_part))
+                      if (builtin_command_name (content->e.c->cmd == CM_part))
                         {
          /* the first part just appeared, and there was no @top first in
             document.  Mark that the sectioning root level needs to be updated
@@ -205,21 +205,21 @@ sectioning_structure (DOCUMENT *document)
                  */
                             message_list_command_warn (error_messages, options,
                               content, 0, "no chapter-level command before 
@%s",
-                                   builtin_command_name (content->cmd));
+                                   builtin_command_name (content->e.c->cmd));
                         }
                       else
                         {
                           message_list_command_warn (error_messages, options,
                                  content, 0,
           "lowering the section level of @%s appearing after a lower element",
-                                 builtin_command_name (content->cmd));
+                                 builtin_command_name (content->e.c->cmd));
                           level = sec_root_level +1;
                         }
                     }
                 }
               if ((command_other_flags (content) & CF_appendix)
                   && !in_appendix && level <= number_top_level
-                  && up->cmd == CM_part)
+                  && up->e.c->cmd == CM_part)
                 {
                   up = sec_root;
                 }
@@ -285,7 +285,7 @@ sectioning_structure (DOCUMENT *document)
             */
            if (number_top_level == 0)
              number_top_level = 1;
-           if (content->cmd != CM_top)
+           if (content->e.c->cmd != CM_top)
              {
                if (!(command_other_flags (content) & CF_unnumbered))
                  command_unnumbered[level] = 0;
@@ -347,7 +347,7 @@ sectioning_structure (DOCUMENT *document)
             }
         }
       previous_section = content;
-      if (content->cmd != CM_part && level <= number_top_level)
+      if (content->e.c->cmd != CM_part && level <= number_top_level)
         {
           if (previous_toplevel || (section_top && section_top != content))
             {
@@ -370,7 +370,7 @@ sectioning_structure (DOCUMENT *document)
             }
           previous_toplevel = content;
         }
-      else if (content->cmd == CM_part)
+      else if (content->e.c->cmd == CM_part)
         {
           ELEMENT *part_associated_section
             = lookup_extra_element (content, AI_key_part_associated_section);
@@ -378,7 +378,7 @@ sectioning_structure (DOCUMENT *document)
             {
               message_list_command_warn (error_messages, options, content,
                             0, "no sectioning command associated with @%s",
-                                      builtin_command_name (content->cmd));
+                                   builtin_command_name (content->e.c->cmd));
             }
         }
     }
@@ -405,7 +405,7 @@ warn_non_empty_parts (DOCUMENT *document)
       const ELEMENT *part = global_commands->part.list[i];
       if (!is_content_empty (part, 0))
         message_list_command_warn (error_messages, options, part, 0,
-                      "@%s not empty", builtin_command_name (part->cmd));
+                      "@%s not empty", builtin_command_name (part->e.c->cmd));
     }
 }
 
@@ -443,7 +443,7 @@ check_menu_entry (DOCUMENT *document, enum command_id cmd,
                   menu_content, 0,
                   "@%s entry node name `%s' different from %s name `%s'",
                   builtin_command_name (cmd), entry_node_texi,
-                  builtin_command_name (menu_node->cmd), menu_node_texi);
+                  builtin_command_name (menu_node->e.c->cmd), menu_node_texi);
               free (entry_node_texi);
               free (menu_node_texi);
             }
@@ -477,7 +477,7 @@ get_node_node_childs_from_sectioning (const ELEMENT *node)
         }
        /* Special case for @top.  Gather all the children of the @part 
following
           @top. */
-      if (associated_section->cmd == CM_top)
+      if (associated_section->e.c->cmd == CM_top)
         {
           const ELEMENT *current = associated_section;
           while (1)
@@ -489,7 +489,7 @@ get_node_node_childs_from_sectioning (const ELEMENT *node)
                   && section_directions->list[D_next])
                 {
                   current = section_directions->list[D_next];
-                  if (current->cmd == CM_part)
+                  if (current->e.c->cmd == CM_part)
                     {
                       ELEMENT_LIST *section_childs
                        = lookup_extra_contents (current, 
AI_key_section_childs);
@@ -537,7 +537,7 @@ register_referenced_node (ELEMENT *node, char 
**referenced_identifiers,
   size_t referenced_identifier_number = *referenced_identifier_number_ptr;
   char *normalized;
 
-  if (node->cmd != CM_node)
+  if (node->e.c->cmd != CM_node)
     return referenced_identifiers;
 
   normalized = lookup_extra_string (node, AI_key_normalized);
@@ -843,7 +843,7 @@ set_menus_node_directions (DOCUMENT *document)
                ELEMENT *menu = menus->list[j];
                message_list_command_warn (error_messages, options,
                              menu, 0, "multiple @%s",
-                             builtin_command_name (menu->cmd));
+                             builtin_command_name (menu->e.c->cmd));
             }
         }
 
@@ -871,7 +871,7 @@ set_menus_node_directions (DOCUMENT *document)
                           if (!manual_content)
                             {
                               if (check_menu_entries)
-                                check_menu_entry (document, menu->cmd,
+                                check_menu_entry (document, menu->e.c->cmd,
                                                   menu_content, content);
                               char *normalized
                                 = lookup_extra_string (content,
@@ -954,7 +954,7 @@ set_menus_node_directions (DOCUMENT *document)
 
                           if (!manual_content)
                             check_menu_entry (document,
-                                              detailmenu->cmd,
+                                              detailmenu->e.c->cmd,
                                               menu_content, content);
                           break;
                         }
@@ -985,7 +985,7 @@ section_direction_associated_node (const ELEMENT *section,
                                                     AI_key_associated_node);
           if ((direction_bases[i] != AI_key_toplevel_directions
                || direction == D_up
-               || section_to->cmd != CM_top)
+               || section_to->e.c->cmd != CM_top)
               && associated_node)
             return associated_node;
         }
@@ -1331,7 +1331,7 @@ nodes_tree (DOCUMENT *document)
       int is_target;
       int automatic_directions;
 
-      if (node->cmd != CM_node)
+      if (node->e.c->cmd != CM_node)
         continue;
 
       normalized = lookup_extra_string (node, AI_key_normalized);
@@ -1474,7 +1474,8 @@ nodes_tree (DOCUMENT *document)
                 "%s pointer `%s' (for node `%s') different from %s name `%s'",
                                        direction_texts[direction],
                                        direction_texi, node_texi,
-                                       builtin_command_name (node_target->cmd),
+                                       builtin_command_name
+                                                   (node_target->e.c->cmd),
                                        node_target_texi);
                                    free (direction_texi);
                                    free (node_texi);
@@ -1572,7 +1573,7 @@ associate_internal_references (DOCUMENT *document)
                   char *label_texi = link_element_to_texi (label_element);
                   message_list_command_error (error_messages, options,
                              ref, "@%s reference to nonexistent node `%s'",
-                             builtin_command_name (ref->cmd), label_texi);
+                             builtin_command_name (ref->e.c->cmd), label_texi);
                   free (label_texi);
                 }
             }
@@ -1592,8 +1593,8 @@ associate_internal_references (DOCUMENT *document)
                       message_list_command_warn (error_messages,
                                 options, ref, 0,
                                 "@%s to `%s', different from %s name `%s'",
-                                builtin_command_name (ref->cmd), label_texi,
-                                builtin_command_name (node_target->cmd),
+                                builtin_command_name (ref->e.c->cmd), 
label_texi,
+                                builtin_command_name (node_target->e.c->cmd),
                                 target_texi);
                       free (label_texi);
                       free (target_texi);
@@ -1647,8 +1648,8 @@ number_floats (DOCUMENT *document)
                       && section_directions->list[D_up])
                     {
                       ELEMENT *up_elt = section_directions->list[D_up];
-                      if (up_elt->cmd
-                          && command_structuring_level[up_elt->cmd] > 0)
+                      if (up_elt->e.c->cmd
+                          && command_structuring_level[up_elt->e.c->cmd] > 0)
                         {
                           up = up_elt;
                           continue;
@@ -1868,7 +1869,7 @@ new_complete_node_menu (const ELEMENT *node, DOCUMENT 
*document,
         }
     }
 
-  if (section && section->cmd == CM_top && options)
+  if (section && section->e.c->cmd == CM_top && options)
     {
       const char *normalized = lookup_extra_string (node, AI_key_normalized);
       if (normalized && !strcmp (normalized, "Top"))
@@ -2201,7 +2202,7 @@ new_complete_menu_master_menu (ERROR_MESSAGE_LIST 
*error_messages,
       ELEMENT *associated_section
           = lookup_extra_element (node, AI_key_associated_section);
       if (normalized && !strcmp (normalized, "Top")
-          && associated_section && associated_section->cmd == CM_top)
+          && associated_section && associated_section->e.c->cmd == CM_top)
         {
           ELEMENT_LIST *menus = new_list ();
           ELEMENT *detailmenu;
diff --git a/tp/Texinfo/XS/structuring_transfo/transformations.c 
b/tp/Texinfo/XS/structuring_transfo/transformations.c
index 395d080f40..167c23759e 100644
--- a/tp/Texinfo/XS/structuring_transfo/transformations.c
+++ b/tp/Texinfo/XS/structuring_transfo/transformations.c
@@ -375,6 +375,11 @@ relate_index_entries_to_table_items_in (ELEMENT *table,
           */
           for (j = 0; j < term->e.c->contents.number; j++)
             {
+              /* see gather_previous_item, CM_item a term can only contain
+                 leading index entries that were left out of the
+                 preceding table_entry, or from the beginning of the table
+                 and the @item command line
+               */
               ELEMENT *content = term->e.c->contents.list[j];
               if (content->type == ET_index_entry_command)
                 {
@@ -393,7 +398,7 @@ relate_index_entries_to_table_items_in (ELEMENT *table,
                    }
                 }
               /* the command in the tree is CM_item, not CM_item_LINE */
-              else if (content->cmd == CM_item)
+              else if (content->e.c->cmd == CM_item)
                 {
                   if (!item)
                     item = content;
@@ -426,7 +431,8 @@ relate_index_entries_to_table_items_internal (const char 
*type,
                                               ELEMENT *current,
                                               void *argument)
 {
-  if (current->cmd && current->cmd == CM_table)
+  if (type_data[current->type].flags & TF_at_command
+      && current->e.c->cmd == CM_table)
     {
       INDEX_LIST *indices_info = (INDEX_LIST *)argument;
       relate_index_entries_to_table_items_in (current, indices_info);
@@ -442,6 +448,7 @@ relate_index_entries_to_table_items_in_tree (ELEMENT *tree,
                indices_info);
 }
 
+/* in itemize or enumerate */
 void
 move_index_entries_after_items (ELEMENT *current)
 {
@@ -450,8 +457,9 @@ move_index_entries_after_items (ELEMENT *current)
 
   for (i = 0; i < current->e.c->contents.number; i++)
     {
+      /* item can only be before_item, @item, or @end */
       ELEMENT *item = current->e.c->contents.list[i];
-      if (previous && item->cmd && item->cmd == CM_item
+      if (previous && item->e.c->cmd && item->e.c->cmd == CM_item
           && previous->e.c->contents.number > 0)
         {
           ELEMENT *previous_ending_container;
@@ -472,9 +480,9 @@ move_index_entries_after_items (ELEMENT *current)
               ELEMENT *content = 
previous_ending_container->e.c->contents.list[j];
               if (content->type == ET_index_entry_command)
                 last_entry_idx = j;
-              else if (!content->cmd
-                       || (content->cmd != CM_comment
-                           && content->cmd != CM_c))
+              else if ((!type_data[content->type].flags & TF_at_command)
+                       || (content->e.c->cmd != CM_comment
+                           && content->e.c->cmd != CM_c))
                 break;
             }
 
@@ -525,8 +533,9 @@ move_index_entries_after_items_internal (const char *type,
                                          ELEMENT *current,
                                          void *argument)
 {
-  if (current->cmd && (current->cmd == CM_enumerate
-                       || current->cmd == CM_itemize))
+  if (type_data[current->type].flags & TF_at_command
+      && (current->e.c->cmd == CM_enumerate
+          || current->e.c->cmd == CM_itemize))
     {
       move_index_entries_after_items (current);
     }
@@ -585,7 +594,9 @@ new_node (ERROR_MESSAGE_LIST *error_messages, ELEMENT 
*node_tree,
     }
 
   last_content = last_contents_child (node_tree);
-  if (last_content->cmd == CM_c || last_content->cmd == CM_comment)
+  if (!(type_data[last_content->type].flags & TF_text)
+      && (last_content->e.c->cmd == CM_c
+          || last_content->e.c->cmd == CM_comment))
     {
       comment_at_end = pop_element_from_contents (node_tree);
       last_content = last_contents_child (node_tree);
@@ -683,7 +694,8 @@ reassociate_to_node (const char *type, ELEMENT *current, 
void *argument)
   ELEMENT *added_node = new_previous->list[0];
   ELEMENT *previous_node = new_previous->list[1];
 
-  if (current->cmd == CM_menu)
+  if (type_data[current->type].flags & TF_at_command
+      && current->e.c->cmd == CM_menu)
     {
       ELEMENT_LIST *added_node_menus;
       if (previous_node)
@@ -724,12 +736,13 @@ reassociate_to_node (const char *type, ELEMENT *current, 
void *argument)
     }
   /* what is really important is to avoid commands without extra information,
      such as text, though it is even better to be precise */
-  else if (current->cmd == CM_nodedescription
-           || current->cmd == CM_nodedescriptionblock
+  else if (!(type_data[current->type].flags & TF_text)
+           && (current->e.c->cmd == CM_nodedescription
+               || current->e.c->cmd == CM_nodedescriptionblock
            /* following for index entries */
-           || current->cmd == CM_item || current->cmd == CM_itemx
-           || current->type == ET_index_entry_command
-           || (current->parent && current->parent->flags & EF_def_line))
+               || current->e.c->cmd == CM_item || current->e.c->cmd == CM_itemx
+               || current->type == ET_index_entry_command
+               || (current->parent && current->parent->flags & EF_def_line)))
     {
       ELEMENT *element_node = lookup_extra_element (current, 
AI_key_element_node);
       if (element_node)
@@ -787,7 +800,7 @@ insert_nodes_for_sectioning_commands (DOCUMENT *document)
 
               document->modified_information |= F_DOCM_tree;
 
-              if (content->cmd == CM_top)
+              if (content->e.c->cmd == CM_top)
                 {
                   ELEMENT *top_node_text = new_text_element (ET_normal_text);
                   new_node_tree = new_element (ET_NONE);
@@ -821,7 +834,7 @@ insert_nodes_for_sectioning_commands (DOCUMENT *document)
                 }
             }
         }
-      if (content->cmd == CM_node)
+      if (content->e.c->cmd == CM_node)
         {
           int is_target = (content->flags & EF_is_target);
           if (is_target)
@@ -847,8 +860,8 @@ reference_to_arg_internal (const char *type,
                            ELEMENT *e,
                            void *argument)
 {
-  if (e->cmd
-      && builtin_command_data[e->cmd].flags & CF_ref)
+  if (type_data[e->type].flags & TF_at_command
+      && builtin_command_data[e->e.c->cmd].flags & CF_ref)
     {
       DOCUMENT *document = (DOCUMENT *) argument;
       int index = 0;
@@ -859,7 +872,7 @@ reference_to_arg_internal (const char *type,
       ELEMENT *new = new_element (ET_NONE);
       new->parent = e->parent;
       add_to_element_list (container, new);
-      if (e->cmd == CM_inforef || e->cmd == CM_link)
+      if (e->e.c->cmd == CM_inforef || e->e.c->cmd == CM_link)
         arguments_order = ref_3_args_order;
       while (arguments_order[index] >= 0)
         {
@@ -1055,7 +1068,8 @@ complete_node_menu (ELEMENT *node, int use_sections)
               const ELEMENT *last_menu_content
                 = last_contents_child (current_menu);
 
-              if (last_menu_content->cmd != CM_end)
+              if (!(type_data[last_menu_content->type].flags & TF_at_command)
+                  || last_menu_content->e.c->cmd != CM_end)
                 offset_at_end = 0;
               insert_list_slice_into_contents (current_menu,
                                 current_menu->e.c->contents.number + 
offset_at_end,
@@ -1082,7 +1096,7 @@ get_non_automatic_nodes_with_sections (const ELEMENT 
*root)
   for (i = 0; i < root->e.c->contents.number; i++)
     {
       ELEMENT *content = root->e.c->contents.list[i];
-      if (content->cmd && content->cmd == CM_node
+      if (content->e.c->cmd && content->e.c->cmd == CM_node
           && content->e.c->args.number <= 1)
         {
           const ELEMENT *associated_section
@@ -1176,8 +1190,10 @@ regenerate_master_menu (DOCUMENT *document, int 
use_sections)
       for (detailmenu_index = 0; detailmenu_index < menu->e.c->contents.number;
            detailmenu_index++)
         {
+          /* entry should be one of the menu specific containers, a
+             @detailmenu or @end */
           const ELEMENT *entry = menu->e.c->contents.list[detailmenu_index];
-          if (entry->cmd == CM_detailmenu)
+          if (entry->e.c->cmd == CM_detailmenu)
             {
               size_t j;
               ELEMENT *removed = remove_from_contents (menu, detailmenu_index);
@@ -1225,7 +1241,10 @@ regenerate_master_menu (DOCUMENT *document, int 
use_sections)
   last_menu = menus->list[menus->number -1];
   index = last_menu->e.c->contents.number;
   last_content = last_contents_child (last_menu);
-  if (last_content && last_content->cmd == CM_end)
+  /* In a regular setting the last content is @end, but here we also
+     allow for a missing @end, including for an empty @menu.  In that
+     case last_content could be one of the menu specific containers */
+  if (last_content && last_content->e.c->cmd == CM_end)
     index--;
 
   new_detailmenu_e->parent = last_menu;
@@ -1331,7 +1350,7 @@ protect_hashchar_at_line_beginning_internal (const char 
*type,
                           ELEMENT *parent_for_warn = parent;
                           while (parent_for_warn)
                             {
-                              if (parent_for_warn->cmd
+                              if (parent_for_warn->e.c->cmd
                                   && parent_for_warn->e.c->source_info.line_nr)
                                 {
                                   DOCUMENT *document = (DOCUMENT *) argument;
@@ -1341,7 +1360,7 @@ protect_hashchar_at_line_beginning_internal (const char 
*type,
                                     &document->error_messages,
                                     options, parent_for_warn, 0,
                                     "could not protect hash character in @%s",
-                                builtin_command_name (parent_for_warn->cmd));
+                                builtin_command_name 
(parent_for_warn->e.c->cmd));
                                   break;
                                 }
                               parent_for_warn = parent_for_warn->parent;
diff --git a/tp/t/05paragraph.t b/tp/t/05paragraph.t
index 7139e4021f..b18e87f156 100644
--- a/tp/t/05paragraph.t
+++ b/tp/t/05paragraph.t
@@ -143,6 +143,26 @@ in flushleft
 
 @end flushright
 '],
+['indent_before_macro_definition_and_other',
+'
+@indent
+@author someone
+@image{my_image}
+@vskip 0pt plus 1filll
+@html
+<code>in c</code>
+@end html
+@ifnothtml
+not html
+@end ifnothtml
+@setchapternewpage on
+@anchor{spot}
+@cpindex ei
+@macro aaa {g}
+ll /g/
+@end macro
+HHERE
+'],
 );
 
 my @test_invalid = (
diff --git a/tp/t/results/paragraph/indent_before_macro_definition_and_other.pl 
b/tp/t/results/paragraph/indent_before_macro_definition_and_other.pl
new file mode 100644
index 0000000000..27e1fc7e5b
--- /dev/null
+++ b/tp/t/results/paragraph/indent_before_macro_definition_and_other.pl
@@ -0,0 +1,463 @@
+use vars qw(%result_texis %result_texts %result_trees %result_errors 
+   %result_indices %result_sectioning %result_nodes %result_menus
+   %result_floats %result_converted %result_converted_errors 
+   %result_elements %result_directions_text %result_indices_sort_strings);
+
+use utf8;
+
+$result_trees{'indent_before_macro_definition_and_other'} = {
+  'contents' => [
+    {
+      'contents' => [
+        {
+          'text' => '
+',
+          'type' => 'empty_line'
+        },
+        {
+          'cmdname' => 'indent',
+          'source_info' => {
+            'line_nr' => 2
+          }
+        },
+        {
+          'text' => '
+',
+          'type' => 'ignorable_spaces_after_command'
+        },
+        {
+          'args' => [
+            {
+              'contents' => [
+                {
+                  'text' => 'someone'
+                }
+              ],
+              'info' => {
+                'spaces_after_argument' => {
+                  'text' => '
+'
+                }
+              },
+              'type' => 'line_arg'
+            }
+          ],
+          'cmdname' => 'author',
+          'extra' => {},
+          'info' => {
+            'spaces_before_argument' => {
+              'text' => ' '
+            }
+          },
+          'source_info' => {
+            'line_nr' => 3
+          }
+        },
+        {
+          'args' => [
+            {
+              'contents' => [
+                {
+                  'text' => 'my_image'
+                }
+              ],
+              'type' => 'brace_arg'
+            }
+          ],
+          'cmdname' => 'image',
+          'extra' => {
+            'input_encoding_name' => 'utf-8'
+          },
+          'source_info' => {
+            'line_nr' => 4
+          }
+        },
+        {
+          'text' => '
+'
+        },
+        {
+          'args' => [
+            {
+              'text' => ' 0pt plus 1filll
+',
+              'type' => 'rawline_arg'
+            }
+          ],
+          'cmdname' => 'vskip'
+        },
+        {
+          'args' => [
+            {
+              'info' => {
+                'spaces_after_argument' => {
+                  'text' => '
+'
+                }
+              },
+              'type' => 'block_line_arg'
+            }
+          ],
+          'cmdname' => 'html',
+          'contents' => [
+            {
+              'contents' => [
+                {
+                  'text' => '<code>in c</code>
+'
+                }
+              ],
+              'type' => 'rawpreformatted'
+            },
+            {
+              'args' => [
+                {
+                  'contents' => [
+                    {
+                      'text' => 'html'
+                    }
+                  ],
+                  'info' => {
+                    'spaces_after_argument' => {
+                      'text' => '
+'
+                    }
+                  },
+                  'type' => 'line_arg'
+                }
+              ],
+              'cmdname' => 'end',
+              'extra' => {
+                'text_arg' => 'html'
+              },
+              'info' => {
+                'spaces_before_argument' => {
+                  'text' => ' '
+                }
+              },
+              'source_info' => {
+                'line_nr' => 8
+              }
+            }
+          ],
+          'source_info' => {
+            'line_nr' => 6
+          },
+          'source_marks' => [
+            {
+              'counter' => 1,
+              'element' => {
+                'args' => [
+                  {
+                    'info' => {
+                      'spaces_after_argument' => {
+                        'text' => '
+'
+                      }
+                    },
+                    'type' => 'block_line_arg'
+                  }
+                ],
+                'cmdname' => 'ifnothtml',
+                'contents' => [
+                  {
+                    'text' => 'not html
+',
+                    'type' => 'raw'
+                  },
+                  {
+                    'args' => [
+                      {
+                        'contents' => [
+                          {
+                            'text' => 'ifnothtml'
+                          }
+                        ],
+                        'info' => {
+                          'spaces_after_argument' => {
+                            'text' => '
+'
+                          }
+                        },
+                        'type' => 'line_arg'
+                      }
+                    ],
+                    'cmdname' => 'end',
+                    'extra' => {
+                      'text_arg' => 'ifnothtml'
+                    },
+                    'info' => {
+                      'spaces_before_argument' => {
+                        'text' => ' '
+                      }
+                    },
+                    'source_info' => {
+                      'line_nr' => 11
+                    }
+                  }
+                ],
+                'source_info' => {
+                  'line_nr' => 9
+                }
+              },
+              'sourcemark_type' => 'ignored_conditional_block'
+            }
+          ]
+        },
+        {
+          'args' => [
+            {
+              'contents' => [
+                {
+                  'text' => 'on'
+                }
+              ],
+              'info' => {
+                'spaces_after_argument' => {
+                  'text' => '
+'
+                }
+              },
+              'type' => 'line_arg'
+            }
+          ],
+          'cmdname' => 'setchapternewpage',
+          'extra' => {
+            'misc_args' => [
+              'on'
+            ]
+          },
+          'info' => {
+            'spaces_before_argument' => {
+              'text' => ' '
+            }
+          },
+          'source_info' => {
+            'line_nr' => 12
+          }
+        },
+        {
+          'args' => [
+            {
+              'contents' => [
+                {
+                  'text' => 'spot'
+                }
+              ],
+              'type' => 'brace_arg'
+            }
+          ],
+          'cmdname' => 'anchor',
+          'extra' => {
+            'is_target' => 1,
+            'normalized' => 'spot'
+          },
+          'source_info' => {
+            'line_nr' => 13
+          }
+        },
+        {
+          'text' => '
+',
+          'type' => 'spaces_after_close_brace'
+        },
+        {
+          'args' => [
+            {
+              'contents' => [
+                {
+                  'text' => 'ei'
+                }
+              ],
+              'info' => {
+                'spaces_after_argument' => {
+                  'text' => '
+'
+                }
+              },
+              'type' => 'line_arg'
+            }
+          ],
+          'cmdname' => 'cpindex',
+          'extra' => {
+            'index_entry' => [
+              'cp',
+              1
+            ]
+          },
+          'info' => {
+            'command_name' => 'cpindex',
+            'spaces_before_argument' => {
+              'text' => ' '
+            }
+          },
+          'source_info' => {
+            'line_nr' => 14
+          },
+          'type' => 'index_entry_command'
+        },
+        {
+          'args' => [
+            {
+              'text' => 'aaa',
+              'type' => 'macro_name'
+            },
+            {
+              'text' => 'g',
+              'type' => 'macro_arg'
+            }
+          ],
+          'cmdname' => 'macro',
+          'contents' => [
+            {
+              'text' => 'll /g/
+',
+              'type' => 'raw'
+            },
+            {
+              'args' => [
+                {
+                  'contents' => [
+                    {
+                      'text' => 'macro'
+                    }
+                  ],
+                  'info' => {
+                    'spaces_after_argument' => {
+                      'text' => '
+'
+                    }
+                  },
+                  'type' => 'line_arg'
+                }
+              ],
+              'cmdname' => 'end',
+              'extra' => {
+                'text_arg' => 'macro'
+              },
+              'info' => {
+                'spaces_before_argument' => {
+                  'text' => ' '
+                }
+              },
+              'source_info' => {
+                'line_nr' => 17
+              }
+            }
+          ],
+          'info' => {
+            'arg_line' => ' aaa {g}
+'
+          },
+          'source_info' => {
+            'line_nr' => 15
+          }
+        },
+        {
+          'contents' => [
+            {
+              'text' => 'HHERE
+'
+            }
+          ],
+          'extra' => {
+            'indent' => 1
+          },
+          'type' => 'paragraph'
+        }
+      ],
+      'type' => 'before_node_section'
+    }
+  ],
+  'type' => 'document_root'
+};
+
+$result_texis{'indent_before_macro_definition_and_other'} = '
+@indent
+@author someone
+@image{my_image}
+@vskip 0pt plus 1filll
+@html
+<code>in c</code>
+@end html
+@setchapternewpage on
+@anchor{spot}
+@cpindex ei
+@macro aaa {g}
+ll /g/
+@end macro
+HHERE
+';
+
+
+$result_texts{'indent_before_macro_definition_and_other'} = '
+someone
+my_image
+<code>in c</code>
+HHERE
+';
+
+$result_errors{'indent_before_macro_definition_and_other'} = [
+  {
+    'error_line' => 'warning: @author not meaningful outside `@titlepage\' and 
`@quotation\' environments
+',
+    'line_nr' => 3,
+    'text' => '@author not meaningful outside `@titlepage\' and `@quotation\' 
environments',
+    'type' => 'warning'
+  },
+  {
+    'error_line' => 'warning: entry for index `cp\' outside of any node
+',
+    'line_nr' => 14,
+    'text' => 'entry for index `cp\' outside of any node',
+    'type' => 'warning'
+  }
+];
+
+
+$result_floats{'indent_before_macro_definition_and_other'} = {};
+
+
+$result_indices_sort_strings{'indent_before_macro_definition_and_other'} = {
+  'cp' => [
+    'ei'
+  ]
+};
+
+
+
+$result_converted{'plaintext'}->{'indent_before_macro_definition_and_other'} = 
'[my_image]
+   HHERE
+';
+
+$result_converted_errors{'plaintext'}->{'indent_before_macro_definition_and_other'}
 = [
+  {
+    'error_line' => 'warning: could not find @image file `my_image.txt\' nor 
alternate text
+',
+    'line_nr' => 4,
+    'text' => 'could not find @image file `my_image.txt\' nor alternate text',
+    'type' => 'warning'
+  }
+];
+
+
+
+$result_converted{'html_text'}->{'indent_before_macro_definition_and_other'} = 
'
+<img class="image" src="my_image.jpg" alt="my_image">
+<code>in c</code>
+<a class="anchor" id="spot"></a><a class="index-entry-id" id="index-ei"></a>
+<p>HHERE
+</p>';
+
+$result_converted_errors{'html_text'}->{'indent_before_macro_definition_and_other'}
 = [
+  {
+    'error_line' => 'warning: @image file `my_image\' (for HTML) not found, 
using `my_image.jpg\'
+',
+    'line_nr' => 4,
+    'text' => '@image file `my_image\' (for HTML) not found, using 
`my_image.jpg\'',
+    'type' => 'warning'
+  }
+];
+
+
+1;
diff --git a/tp/t/test_document.t b/tp/t/test_document.t
index a2e9f146c8..dc4b5e96e8 100644
--- a/tp/t/test_document.t
+++ b/tp/t/test_document.t
@@ -27,13 +27,15 @@ T
 
 my $global_info = $document->global_information();
 
-is ('input_encoding_name|input_perl_encoding',
-    join('|', sort(keys(%$global_info))), 'initial global info keys');
+is (join('|', sort(keys(%$global_info))),
+    'input_encoding_name|input_perl_encoding',
+    'initial global info keys');
 
 $document->set_document_global_info('toto', 'la tete a');
 
-is ('input_encoding_name|input_perl_encoding|toto',
-    join('|', sort(keys(%$global_info))), 'with set global info keys');
+is (join('|', sort(keys(%$global_info))),
+    'input_encoding_name|input_perl_encoding|toto',
+    'with set global info keys');
 
-is ('la tete a', $global_info->{'toto'}, 'check global info set value');
+is ($global_info->{'toto'}, 'la tete a', 'check global info set value');
 



reply via email to

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