@@ -22,17 +22,11 @@ namespace Ted;
2222/// </summary>
2323public sealed partial class TedApp : Window
2424{
25- private const int MaximumAutomaticFoldingDocumentLength = 1_000_000 ;
26-
27- private readonly BraceFoldingStrategy _braceFoldingStrategy ;
28-
2925 // Per-instance config path. Defaults to the real ~/.tui location; tests inject a temp path so they
3026 // never touch the developer's real config (and stay parallel-safe — no env/static mutation).
3127 private readonly string _configPath ;
3228 private readonly Shortcut _fileNameShortcut ;
3329 private readonly MenuItem _previewMarkdownMenuItem ;
34- private TextDocument ? _foldingDocument ;
35- private bool _foldingUpdateNeeded ;
3630
3731 /// <summary>Initializes a new <see cref="TedApp" />.</summary>
3832 /// <param name="readOnly">Opens the editor read-only.</param>
@@ -78,9 +72,8 @@ public TedApp (bool readOnly = false, string? configPath = null)
7872 Editor . IndentationStrategy =
7973 EditorSettings . AutoIndent ? new DefaultIndentationStrategy ( ) : null ;
8074
81- // Enable brace-based folding. The strategy re-scans on each document change.
82- _braceFoldingStrategy = new BraceFoldingStrategy ( ) ;
83- InstallFolding ( ) ;
75+ // Enable brace-based folding. The editor handles the full lifecycle automatically.
76+ Editor . FoldingStrategy = new BraceFoldingStrategy ( ) ;
8477
8578 ShowOpenDialog = ShowDefaultOpenDialog ;
8679 ShowSaveDialog = ShowDefaultSaveDialog ;
@@ -573,259 +566,4 @@ private void ShowSettingsDialog ()
573566
574567 dialog . Dispose ( ) ;
575568 }
576-
577- /// <summary>
578- /// Creates a <see cref="FoldingManager" /> for the current document and wires up
579- /// automatic fold updates on document changes.
580- /// </summary>
581- private void InstallFolding ( )
582- {
583- if ( Editor . Document is null )
584- {
585- SetFoldingDocument ( null ) ;
586-
587- return ;
588- }
589-
590- if ( Editor . Document . TextLength > MaximumAutomaticFoldingDocumentLength )
591- {
592- SetFoldingDocument ( null ) ;
593- Editor . FoldingManager = null ;
594-
595- return ;
596- }
597-
598- FoldingManager fm = new ( Editor . Document ) ;
599- Editor . FoldingManager = fm ;
600- _braceFoldingStrategy . UpdateFoldings ( fm , Editor . Document ) ;
601- SetFoldingDocument ( Editor . Document ) ;
602- }
603-
604- private void UpdateFoldings ( )
605- {
606- if ( Editor . FoldingManager is null || Editor . Document is null )
607- {
608- return ;
609- }
610-
611- if ( Editor . Document . TextLength > MaximumAutomaticFoldingDocumentLength )
612- {
613- SetFoldingDocument ( null ) ;
614- Editor . FoldingManager = null ;
615-
616- return ;
617- }
618-
619- _braceFoldingStrategy . UpdateFoldings ( Editor . FoldingManager ,
620- Editor . Document ) ;
621- }
622-
623- private void SetFoldingDocument ( TextDocument ? document )
624- {
625- if ( ReferenceEquals ( _foldingDocument , document ) )
626- {
627- return ;
628- }
629-
630- if ( _foldingDocument is not null )
631- {
632- _foldingDocument . Changed -= OnFoldingDocumentChanged ;
633- _foldingDocument . UpdateFinished -= OnFoldingDocumentUpdateFinished ;
634- }
635-
636- _foldingDocument = document ;
637- _foldingUpdateNeeded = false ;
638-
639- if ( _foldingDocument is not null )
640- {
641- _foldingDocument . Changed += OnFoldingDocumentChanged ;
642- _foldingDocument . UpdateFinished += OnFoldingDocumentUpdateFinished ;
643- }
644- }
645-
646- private void OnFoldingDocumentChanged ( object ? sender , DocumentChangeEventArgs e )
647- {
648- _foldingUpdateNeeded |= FoldingChangeMayAffectStructure ( e ) ;
649- }
650-
651- private void OnFoldingDocumentUpdateFinished ( object ? sender , EventArgs e )
652- {
653- if ( ! _foldingUpdateNeeded )
654- {
655- return ;
656- }
657-
658- _foldingUpdateNeeded = false ;
659- UpdateFoldings ( ) ;
660- }
661-
662- private bool FoldingChangeMayAffectStructure ( DocumentChangeEventArgs e )
663- {
664- if ( TryGetMappedStructuralChange ( e , out var mappedStructuralChange ) )
665- {
666- return mappedStructuralChange ;
667- }
668-
669- return ContainsFoldingStructuralCharacter ( e . InsertedText )
670- || ContainsFoldingStructuralCharacter ( e . RemovedText ) ;
671- }
672-
673- private bool TryGetMappedStructuralChange ( DocumentChangeEventArgs e , out bool structuralChange )
674- {
675- structuralChange = false ;
676- OffsetChangeMap map = e . OffsetChangeMap ;
677- var hasInsertion = false ;
678- var hasRemoval = false ;
679-
680- if ( map . Count == 0 )
681- {
682- return false ;
683- }
684-
685- foreach ( OffsetChangeMapEntry entry in map )
686- {
687- hasInsertion |= entry . InsertionLength > 0 ;
688- hasRemoval |= entry . RemovalLength > 0 ;
689-
690- if ( entry . InsertionLength > 0 && entry . RemovalLength > 0 )
691- {
692- return false ;
693- }
694- }
695-
696- if ( ! hasInsertion && ! hasRemoval )
697- {
698- return false ;
699- }
700-
701- if ( hasInsertion && hasRemoval )
702- {
703- return false ;
704- }
705-
706- structuralChange = hasInsertion
707- ? MappedInsertionsContainFoldingStructuralCharacter ( map , e . InsertedText , e . Offset )
708- : MappedRemovalsContainFoldingStructuralCharacter ( map , e . RemovedText , e . Offset , e . RemovalLength ) ;
709-
710- return true ;
711- }
712-
713- private bool MappedInsertionsContainFoldingStructuralCharacter ( OffsetChangeMap map , ITextSource text ,
714- int baseOffset )
715- {
716- if ( InsertionEntriesUseInsertedTextCoordinates ( map , baseOffset , text . TextLength ) )
717- {
718- return MappedInsertionsContainFoldingStructuralCharacterWithoutShift ( map , text , baseOffset ) ;
719- }
720-
721- var insertedShift = 0 ;
722-
723- foreach ( OffsetChangeMapEntry entry in map )
724- {
725- if ( entry . InsertionLength == 0 )
726- {
727- continue ;
728- }
729-
730- var relativeOffset = entry . Offset - baseOffset + insertedShift ;
731-
732- if ( ContainsFoldingStructuralCharacter ( text , relativeOffset , entry . InsertionLength ) )
733- {
734- return true ;
735- }
736-
737- insertedShift += entry . InsertionLength ;
738- }
739-
740- return false ;
741- }
742-
743- private bool MappedInsertionsContainFoldingStructuralCharacterWithoutShift (
744- OffsetChangeMap map ,
745- ITextSource text ,
746- int baseOffset )
747- {
748- foreach ( OffsetChangeMapEntry entry in map )
749- {
750- if ( entry . InsertionLength == 0 )
751- {
752- continue ;
753- }
754-
755- var relativeOffset = entry . Offset - baseOffset ;
756-
757- if ( ContainsFoldingStructuralCharacter ( text , relativeOffset , entry . InsertionLength ) )
758- {
759- return true ;
760- }
761- }
762-
763- return false ;
764- }
765-
766- private bool MappedRemovalsContainFoldingStructuralCharacter (
767- OffsetChangeMap map ,
768- ITextSource text ,
769- int baseOffset ,
770- int removalLength )
771- {
772- if ( ! RemovalEntriesUseRemovedTextCoordinates ( map , baseOffset , removalLength ) )
773- {
774- return MappedInsertionsContainFoldingStructuralCharacter ( map . Invert ( ) , text , baseOffset ) ;
775- }
776-
777- foreach ( OffsetChangeMapEntry entry in map )
778- {
779- if ( entry . RemovalLength == 0 )
780- {
781- continue ;
782- }
783-
784- var relativeOffset = entry . Offset - baseOffset ;
785-
786- if ( ContainsFoldingStructuralCharacter ( text , relativeOffset , entry . RemovalLength ) )
787- {
788- return true ;
789- }
790- }
791-
792- return false ;
793- }
794-
795- private static bool RemovalEntriesUseRemovedTextCoordinates ( OffsetChangeMap map , int baseOffset , int removalLength )
796- {
797- return map . Count > 0
798- && map [ 0 ] . RemovalLength > 0
799- && map [ 0 ] . Offset + map [ 0 ] . RemovalLength == baseOffset + removalLength ;
800- }
801-
802- private static bool InsertionEntriesUseInsertedTextCoordinates ( OffsetChangeMap map , int baseOffset ,
803- int insertionLength )
804- {
805- return map . Count > 0
806- && map [ ^ 1 ] . InsertionLength > 0
807- && map [ ^ 1 ] . Offset + map [ ^ 1 ] . InsertionLength == baseOffset + insertionLength ;
808- }
809-
810- private bool ContainsFoldingStructuralCharacter ( ITextSource text )
811- {
812- return ContainsFoldingStructuralCharacter ( text , 0 , text . TextLength ) ;
813- }
814-
815- private bool ContainsFoldingStructuralCharacter ( ITextSource text , int offset , int length )
816- {
817- for ( var i = offset ; i < offset + length ; i ++ )
818- {
819- var ch = text . GetCharAt ( i ) ;
820-
821- if ( ch == _braceFoldingStrategy . OpeningBrace
822- || ch == _braceFoldingStrategy . ClosingBrace
823- || ch is '\r ' or '\n ' )
824- {
825- return true ;
826- }
827- }
828-
829- return false ;
830- }
831569}
0 commit comments