As you iterate over the lines in a section, you recognize the lines which represent list items, but pass each, separately, to sub item, never producing the data structure you described and never calling sub list.
What you need to do is detect the entire set of lines that represents a list and pass the set to one of the routines that have been suggested, then pass the resulting data structure to your list sub.
A start might be to redo the loop over lines in a section to facilitate processing groups of lines and then process all the lines of a list together. Maybe something like the following, untested suggestion might work for you.
for(my $lineno = 0; $lineno < @$section; $lineno++) {
my $line = $section->[$lineno];
if($line =~ m/^\[*#]/) {
# This line is the start of a list
my $start = $lineno;
# Where is the end?
my $end = $lineno;
$end++ while($section->[$end+1] =~ /^[\*#]/);
# Get all the lines that are part of the list
my @list_lines = @{$section}[$start..$end];
# Put one of the suggested answers to your initial
# request into a subroutine and pass it the set of lines
# that represents a single list, getting back the data
# structure you requested in your original post.
my $internal = parse_list(@list_lines);
# Extract the list type and contents from the data
# structure
my ($type, $list) = @$internal;
my $opt = '???'; # Where should $opt come from?
# And pass these to the list sub to produce the list.
list($tab, $type, $list, $opt);
# All the lines of the list have been dealt with. Move
# the line number (index into @$section) to the end of
# the list then carry on to process the rest of the
# section.
$lineno = $end;
} else {
# This line is something other than a list line
$line = convert_string($section->[$lineno], $line_magic);
line($tab, $line), next if $line =~ /^</;
line($tab, "<$line>"), next if $line =~ /^[bh]r$/;
$doc_magic->{$1}->(), next if $line =~ /^&\s+(.*)/;
blockquote($tab, $1), next if $line =~ /^bq\s(.*)/;
row($tab + 1, $1, row_line($2)), next if $line =~ /^\|\s(.+)\s
+\|\|(.+)$/;
heading($tab, $1, $2, { id => idify($2) }), next if $line =
+~ /^([1-6])\s+(.*)/;
paragraph($tab, $line, { class => 'author' }), next if $line =
+~ /^by /;
paragraph($tab, $line);
}
}