@@ -545,23 +545,40 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig
545545 continue ;
546546 }
547547
548+ if ( IsLine ( delimiter ) )
549+ {
550+ var previousSignificantSibling = SkipTrailingWhitespace ( delimiter . PreviousSibling ) ;
551+
552+ // Trailing pipe at end-of-line (`| --- |`) is valid and does not add a new column.
553+ if ( previousSignificantSibling is PipeTableDelimiterInline )
554+ {
555+ isValidRow = columnDefinitions is { Count : > 0 } ;
556+ break ;
557+ }
558+
559+ if ( ! TryParseHeaderColumn ( previousSignificantSibling , out var align , out var delimiterCount ) )
560+ {
561+ break ;
562+ }
563+
564+ columnDefinitions ??= [ ] ;
565+ totalDelimiterCount += delimiterCount ;
566+ columnDefinitions . Add ( new TableColumnDefinition ( ) { Alignment = align , Width = delimiterCount } ) ;
567+ isValidRow = true ;
568+ break ;
569+ }
570+
548571 // Parse the content before this delimiter as a column definition (e.g., `:---`, `---:`, `:---:`)
549- // Skip if previous sibling is a pipe (empty cell) or whitespace
550- TableColumnAlign ? align = null ;
551- int delimiterCount = 0 ;
552- if ( delimiter . PreviousSibling != null &&
553- ! ( delimiter . PreviousSibling is PipeTableDelimiterInline ) &&
554- ! ( delimiter . PreviousSibling is LiteralInline li && li . Content . IsEmptyOrWhitespace ( ) ) &&
555- ! ParseHeaderString ( delimiter . PreviousSibling , out align , out delimiterCount ) )
572+ if ( ! TryParseHeaderColumn ( delimiter . PreviousSibling , out var pipeAlign , out var pipeDelimiterCount ) )
556573 {
557574 break ;
558575 }
559576
560577 // Create aligns until we may have a header row
561578
562579 columnDefinitions ??= new List < TableColumnDefinition > ( ) ;
563- totalDelimiterCount += delimiterCount ;
564- columnDefinitions . Add ( new TableColumnDefinition ( ) { Alignment = align , Width = delimiterCount } ) ;
580+ totalDelimiterCount += pipeDelimiterCount ;
581+ columnDefinitions . Add ( new TableColumnDefinition ( ) { Alignment = pipeAlign , Width = pipeDelimiterCount } ) ;
565582
566583 // If this is the last pipe, check for a trailing column definition (row without trailing pipe)
567584 // e.g., `| :--- | ---:` has content after the last pipe
@@ -576,28 +593,21 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig
576593 break ;
577594 }
578595
579- if ( ! ParseHeaderString ( nextSibling , out align , out delimiterCount ) )
596+ if ( ! TryParseHeaderColumn ( nextSibling , out var trailingAlign , out var trailingDelimiterCount ) )
580597 {
581598 break ;
582599 }
583- totalDelimiterCount += delimiterCount ;
584- isValidRow = true ;
585- columnDefinitions . Add ( new TableColumnDefinition ( ) { Alignment = align , Width = delimiterCount } ) ;
586- break ;
587- }
588-
589- // If we are on a Line delimiter, exit
590- if ( IsLine ( delimiter ) )
591- {
600+ totalDelimiterCount += trailingDelimiterCount ;
592601 isValidRow = true ;
602+ columnDefinitions . Add ( new TableColumnDefinition ( ) { Alignment = trailingAlign , Width = trailingDelimiterCount } ) ;
593603 break ;
594604 }
595605 }
596606 break ;
597607 }
598608
599609 // calculate the width of the columns in percent based on the delimiter count
600- if ( ! isValidRow || columnDefinitions == null )
610+ if ( ! isValidRow || columnDefinitions == null || totalDelimiterCount == 0 )
601611 {
602612 return null ;
603613 }
@@ -619,6 +629,34 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig
619629 return columnDefinitions ;
620630 }
621631
632+ private static bool TryParseHeaderColumn ( Inline ? inline , out TableColumnAlign ? align , out int delimiterCount )
633+ {
634+ align = null ;
635+ delimiterCount = 0 ;
636+
637+ if ( inline is null || inline is PipeTableDelimiterInline )
638+ {
639+ return false ;
640+ }
641+
642+ if ( inline is LiteralInline literal && literal . Content . IsEmptyOrWhitespace ( ) )
643+ {
644+ return false ;
645+ }
646+
647+ return ParseHeaderString ( inline , out align , out delimiterCount ) ;
648+ }
649+
650+ private static Inline ? SkipTrailingWhitespace ( Inline ? inline )
651+ {
652+ while ( inline is LiteralInline literal && literal . Content . IsEmptyOrWhitespace ( ) )
653+ {
654+ inline = inline . PreviousSibling ;
655+ }
656+
657+ return inline ;
658+ }
659+
622660 private static bool IsLine ( Inline inline )
623661 {
624662 return inline is LineBreakInline ;
0 commit comments