Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Code folding

mrward edited this page · 6 revisions

Introduction

In this section I will describe how to create a simple code folding.

For this purpose I have created a small sample application. It creates code folding for a small programming language I made up myself, called VariX. But it is just sample code and will not work and you even don't need to know anything about that language. For this "code" we will make a code folding:

def function FuncName(val Name : Type) : Type
    return value;
enddef;

def procedure ProcName(val Name : Type)
    ; This is a comment
enddef;

That is enough for introduction. Now I will describe how this works.

Overview over the folding system

To create your own folding, you have to implement the IFoldingStrategy interface. It is located at the ICSharpCode.TextEditor.Document-namespace. This interface has one method called GenerateFoldMarkers it creates a list of FoldMarkers.

The IDocument interface has a property called FoldingStrategy. There you can attach your created folding strategy.

// Folding strategy
public class MyFolding : IFoldingStrategy
{
    public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
    {
        // TODO : Create your FoldMarkers here
    }
}

To initialize folding use this code:

// Initialize folding, attach your strategy.
this.textEditorControl1.Document.FoldingManager.FoldingStrategy = new MyFolding();
// Update folding markers, call whenever you need to update the folding markers.
// Especially when the text in the texteditor has been changed.
this.textEditorControl1.Document.FoldingManager.UpdateFoldings(null, null);

The UpdateFoldings method used above calls our GenerateFoldMarkers method.

That is all you need to know to create your own foldings.

Conclusion

I hope this little information helped you to create your own folding. See the full sample code below.

If you have any further questions, please ask in the forum and I will try to improve this little tutorial. I would really like to know what you think about this tutorial, because I'm not good at writing tutorials, I want to improve my writing.

Code

Here is my full sample code.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

using ICSharpCode.TextEditor.Document;

namespace TextEditorTest
{
    /// <summary>
    /// This is the main class for testing the folding example.
    /// It is a form which simply contains a ICSharpCode.TextEditor.TextEditorControl
    /// </summary>
    public class MainForm : Form
    {
        /// <summary>
        /// Program entry point.
        /// </summary>
        [STAThread]
        private static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }

        public MainForm()
        {
            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();

            // Initialize folding
            this.textEditorControl1.Document.FoldingManager.FoldingStrategy = new VariXFolding();
            // Update folding markers, call whenever you need to update the folding markers.
            // Especially when the text in the texteditor has been changed.
            this.textEditorControl1.Document.FoldingManager.UpdateFoldings(null, null);
        }

        #region FormsDesignerCode
        /// <summary>
        /// Designer variable used to keep track of non-visual components.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Disposes resources used by the form.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing) {
                if (components != null) {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// This method is required for Windows Forms designer support.
        /// Do not change the method contents inside the source code editor. The Forms designer might
        /// not be able to load this method if it was changed manually.
        /// </summary>
        private void InitializeComponent()
        {
            this.textEditorControl1 = new ICSharpCode.TextEditor.TextEditorControl();
            this.SuspendLayout();
            // 
            // textEditorControl1
            // 
            this.textEditorControl1.Anchor = ((System.Windows.Forms.AnchorStyles)&#0040;&#0040;&#0040;&#0040;System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
                                    | System.Windows.Forms.AnchorStyles.Left) 
                                    | System.Windows.Forms.AnchorStyles.Right)));
            this.textEditorControl1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
            this.textEditorControl1.IsReadOnly = false;
            this.textEditorControl1.Location = new System.Drawing.Point(12, 12);
            this.textEditorControl1.Name = "textEditorControl1";
            this.textEditorControl1.Size = new System.Drawing.Size(268, 249);
            this.textEditorControl1.TabIndex = 0;
            this.textEditorControl1.Text = "def function FuncName(val Name : Type) : Type\r\n\treturn value;\r\nenddef;\r\n" +
            "\r\ndef procedure ProcName(val Name : Type)\r\n\t; More lines ...\r\nenddef;";
            // 
            // MainForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Controls.Add(this.textEditorControl1);
            this.Name = "MainForm";
            this.Text = "TextEditorTest";
            this.ResumeLayout(false);
        }
        private ICSharpCode.TextEditor.TextEditorControl textEditorControl1;
        #endregion

    }

    /// <summary>
    /// The class to generate the foldings, it implements ICSharpCode.TextEditor.Document.IFoldingStrategy
    /// </summary>
    public class VariXFolding : IFoldingStrategy
    {
        /// <summary>
        /// Generates the foldings for our document.
        /// </summary>
        /// <param name="document">The current document.</param>
        /// <param name="fileName">The filename of the document.</param>
        /// <param name="parseInformation">Extra parse information, not used in this sample.</param>
        /// <returns>A list of FoldMarkers.</returns>
        public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
        {
            List<FoldMarker> list = new List<FoldMarker>();

            int start = 0;

            // Create foldmarkers for the whole document, enumerate through every line.
            for (int i = 0; i < document.TotalNumberOfLines; i++)
            {
                // Get the text of current line.
                string text = document.GetText(document.GetLineSegment(i));

                if (text.StartsWith("def")) // Look for method starts
                    start = i;
                if (text.StartsWith("enddef;")) // Look for method endings
                    // Add a new FoldMarker to the list.
                    // document = the current document
                    // start = the start line for the FoldMarker
                    // document.GetLineSegment(start).Length = the ending of the current line = the start column of our foldmarker.
                    // i = The current line = end line of the FoldMarker.
                    // 7 = The end column
                    list.Add(new FoldMarker(document, start, document.GetLineSegment(start).Length, i, 7));
            }

            return list;
        }
    }
}
Something went wrong with that request. Please try again.