6262"""
6363
6464import os
65+ import re
6566import sys
6667import json
6768import copy
@@ -486,24 +487,109 @@ def _make_output_code_blocks(md):
486487 is_inside_backticks = False
487488
488489 def is_output_line (line , prev_line , output_lines ):
490+ if (
491+ output_lines
492+ and "\x08 " in output_lines [- 1 ]
493+ and not output_lines [- 1 ].replace ("\x08 " , "" ).strip ()
494+ ):
495+ # We already started a block and the last line is just deletes, that
496+ # implies that the current line will be part of the block (progress
497+ # bar being re-written).
498+ return True
499+
489500 if line .startswith (" " ) and len (line ) >= 5 :
490- if output_lines or (lines [i - 1 ].strip () == "" and line .strip ()):
501+ # Non-empty indented line
502+ if output_lines :
503+ # Continuation of the output block
504+ return True
505+ if not prev_line .strip ():
506+ # Begining of an output block
507+ return True
508+ elif not line .strip ():
509+ # Empty line
510+ if output_lines :
511+ # Continuation of the output block
491512 return True
513+ elif line .strip ()[0 ] in ("\x1b " , "\x08 " ):
514+ # Line starts with ESC or delete character, it must be a progress
515+ # bar, which is often not indented.
516+ return True
492517 return False
493518
494519 def flush (output_lines , final_lines ):
495520 final_lines .append ('<div class="k-default-codeblock">' )
496521 final_lines .append ("```" )
497- if len (output_lines ) == 1 :
498- line = output_lines [0 ]
499- final_lines .append (line [4 :])
500- else :
501- for line in output_lines :
502- final_lines .append (line [4 :])
522+
523+ # When not None, we are in a progress bar and this is its last state.
524+ progress_bar = None
525+ # Used to dedupe empty lines. Also used when in a progress bar.
526+ previous_line_empty = False
527+
528+ for line in output_lines :
529+ # Unindent.
530+ if line .startswith (" " ):
531+ # Normal block is indented by 4 spaces.
532+ line = line [4 :]
533+ else :
534+ # Progress bar and empty lines.
535+ line = line .strip ()
536+
537+ if "\x1b " in line or "\x08 " in line :
538+ # This is a progress bar.
539+ if "\x1b " in line :
540+ # Remove escape sequences.
541+ line = re .sub (r"\x1b\[[0-9][0-9]?m" , "" , line )
542+
543+ if "\x08 " in line :
544+ # Delete characters, remove everything up to the last one.
545+ line = line [line .rindex ("\x08 " ) + 1 :].strip ()
546+
547+ if previous_line_empty and progress_bar is None :
548+ # We're starting a progress bar, flush the empty line.
549+ final_lines .append ("" )
550+
551+ if progress_bar is None or line :
552+ # Update latest progress bar content.
553+ progress_bar = line
554+
555+ previous_line_empty = not line
556+ # When in a progress bar, don't append.
557+ continue
558+
559+ if progress_bar is not None and not line :
560+ # In a progress bar with an empty line.
561+ previous_line_empty = True
562+ # We're staying in the progress bar, don't append.
563+ continue
564+
565+ # If we get here, we're not / no longer in a progress bar.
566+
567+ if progress_bar :
568+ # Flush progress bar content with the last value.
569+ final_lines .append (progress_bar )
570+ progress_bar = None
571+
572+ if line :
573+ if previous_line_empty :
574+ # Flush empty line before appending non-empty line.
575+ final_lines .append ("" )
576+ final_lines .append (line )
577+ previous_line_empty = False
578+ else :
579+ previous_line_empty = True
580+
581+ if progress_bar :
582+ # Flush progress bar content with the last value.
583+ final_lines .append (progress_bar )
584+
503585 final_lines .append ("```" )
504586 final_lines .append ("</div>" )
505587
506- for i , line in enumerate (lines ):
588+ if previous_line_empty :
589+ # If the last line in the block was empty, put it after the block.
590+ final_lines .append ("" )
591+
592+ for line in lines :
507593 if line .startswith ("```" ):
508594 is_inside_backticks = not is_inside_backticks
509595 final_lines .append (line )
@@ -513,7 +599,7 @@ def flush(output_lines, final_lines):
513599 final_lines .append (line )
514600 continue
515601
516- if i > 0 and is_output_line (line , lines [- 1 ], output_lines ):
602+ if final_lines and is_output_line (line , final_lines [- 1 ], output_lines ):
517603 output_lines .append (line )
518604 elif not line :
519605 if output_lines :
0 commit comments