using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Folding; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor { public class CustomFoldingManager : FoldingManager { public CustomFoldingManager(TextDocument document) : base(document) { } #region Install /// <summary> /// Adds Folding support to the specified text area. /// Warning: The folding manager is only valid for the text area's current document. The folding manager /// must be uninstalled before the text area is bound to a different document. /// </summary> /// <returns>The <see cref="FoldingManager"/> that manages the list of foldings inside the text area.</returns> public new static CustomFoldingManager Install(TextArea textArea) { if (textArea == null) throw new ArgumentNullException("textArea"); return new CustomFoldingManagerInstallation(textArea) as CustomFoldingManager; } #endregion /// <summary> /// Uninstalls the folding manager. /// </summary> /// <exception cref="ArgumentException">The specified manager was not created using <see cref="Install"/>.</exception> public new static void Uninstall(FoldingManager manager) { if (manager == null) throw new ArgumentNullException("manager"); CustomFoldingManagerInstallation installation = manager as CustomFoldingManagerInstallation; if (installation != null) { installation.Uninstall(); } else { throw new ArgumentException("FoldingManager was not created using FoldingManager.Install"); } } private bool foldSpecialFoldings = false; /// <summary> /// 只应该在打开文件时临时将此属性值设置为 true。 /// 用以在UpdateFoldings()时自动折叠某些被指定为应该自动折叠的块。 /// </summary> public bool FoldSpecialFoldings { get { return foldSpecialFoldings; } set { foldSpecialFoldings = value; } } public new void UpdateFoldings(IEnumerable<NewFolding> newFoldings, int firstErrorOffset) { base.UpdateFoldings(newFoldings, firstErrorOffset); //折叠所有单行的图像链接文本、二维文字表、自定义折叠区等。 //这个只应该折叠一次,否则可能造成无法顺利展开折叠块并编辑——因为会总是被自动折叠起来。 if (FoldSpecialFoldings) { foreach (var i in this.AllFoldings) { var folding = i.Tag as ICSharpCode.AvalonEdit.Folding.NewFolding; if (folding != null && folding.IsSpecial) { i.IsFolded = true; } } } } } sealed class CustomFoldingManagerInstallation : CustomFoldingManager { TextArea textArea; FoldingMargin margin; FoldingElementGenerator generator; public CustomFoldingManagerInstallation(TextArea textArea) : base(textArea.Document) { this.textArea = textArea; margin = new FoldingMargin() { FoldingManager = this }; generator = new FoldingElementGenerator() { FoldingManager = this }; textArea.LeftMargins.Add(margin); textArea.TextView.Services.AddService(typeof(FoldingManager), this); // HACK: folding only works correctly when it has highest priority textArea.TextView.ElementGenerators.Insert(0, generator); textArea.Caret.PositionChanged += textArea_Caret_PositionChanged; } public void Uninstall() { Clear(); if (textArea != null) { textArea.Caret.PositionChanged -= textArea_Caret_PositionChanged; textArea.LeftMargins.Remove(margin); textArea.TextView.ElementGenerators.Remove(generator); textArea.TextView.Services.RemoveService(typeof(FoldingManager)); margin = null; generator = null; textArea = null; } } void textArea_Caret_PositionChanged(object sender, EventArgs e) { // Expand Foldings when Caret is moved into them. int caretOffset = textArea.Caret.Offset; foreach (FoldingSection s in GetFoldingsContaining(caretOffset)) { if (s.IsFolded && s.StartOffset < caretOffset && caretOffset < s.EndOffset) { s.IsFolded = false; } } } } }