/// <summary> /// Updates the foldings in this <see cref="FoldingManager"/> using the given new foldings. /// This method will try to correlate new foldings with existing foldings and will attempt /// to keep the state (<see cref="FoldingSection.IsFolded"/>) of existing foldings. /// </summary> /// <remarks> /// Based on original code from: https://github.com/icsharpcode/AvalonEdit/blob/master/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs /// This custom version was created in order to fix an issue where only the first collapsed folding was preserved. /// See: https://github.com/icsharpcode/AvalonEdit/issues/86 /// </remarks> public static void UpdateFoldings(this FoldingManager manager, IEnumerable <NewFolding> newFoldings) { if (newFoldings == null) { throw new ArgumentNullException(nameof(newFoldings)); } var oldFoldings = manager.AllFoldings.ToArray(); int oldFoldingIndex = 0; int previousStartOffset = 0; // Merge new foldings into old foldings so that sections keep being collapsed. // Both oldFoldings and newFoldings are sorted by start offset. foreach (var newFolding in newFoldings) { // ensure newFoldings are sorted correctly if (newFolding.StartOffset < previousStartOffset) { throw new ArgumentException(nameof(newFoldings) + " must be sorted by start offset"); } previousStartOffset = newFolding.StartOffset; if (newFolding.StartOffset == newFolding.EndOffset) { continue; // ignore zero-length foldings } // Remove old foldings that were skipped. while (oldFoldingIndex < oldFoldings.Length && newFolding.StartOffset > oldFoldings[oldFoldingIndex].StartOffset) { manager.RemoveFolding(oldFoldings[oldFoldingIndex++]); } // Reuse current folding if its matching. FoldingSection section; if (oldFoldingIndex < oldFoldings.Length && newFolding.StartOffset == oldFoldings[oldFoldingIndex].StartOffset) { section = oldFoldings[oldFoldingIndex++]; section.Length = newFolding.EndOffset - newFolding.StartOffset; } else { // No matching current folding; create a new one. section = manager.CreateFolding(newFolding.StartOffset, newFolding.EndOffset); section.IsFolded = newFolding.DefaultClosed; section.Tag = newFolding; } section.Title = newFolding.Name; } // Remove all outstanding old foldings. while (oldFoldingIndex < oldFoldings.Length) { var oldSection = oldFoldings[oldFoldingIndex++]; manager.RemoveFolding(oldSection); } }