first commit
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file is part of CodingEditor.
|
||||
// Note: This project is derived from Peter Project
|
||||
// (hosted on sourceforge and codeplex)
|
||||
//
|
||||
// Copyright (c) 2008-2009, CE Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
using System.Collections.Generic;
|
||||
using ICSharpCode.TextEditor.Document;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Src.Document.FoldingStrategy
|
||||
{
|
||||
public class CSharpFoldingStrategy : IFoldingStrategy
|
||||
{
|
||||
#region Methods
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var list = new List<FoldMarker>();
|
||||
var startLines = new Stack<int>();
|
||||
|
||||
// Create foldmarkers for the whole document, enumerate through every line.
|
||||
for (int i = 0; i < document.TotalNumberOfLines; i++)
|
||||
{
|
||||
var seg = document.GetLineSegment(i);
|
||||
int offs, end = document.TextLength;
|
||||
char c;
|
||||
for (offs = seg.Offset; offs < end && ((c = document.GetCharAt(offs)) == ' ' || c == '\t'); offs++)
|
||||
{
|
||||
}
|
||||
if (offs == end)
|
||||
break;
|
||||
int spaceCount = offs - seg.Offset;
|
||||
|
||||
// now offs points to the first non-whitespace char on the line
|
||||
if (document.GetCharAt(offs) == '#')
|
||||
{
|
||||
string text = document.GetText(offs, seg.Length - spaceCount);
|
||||
if (text.StartsWith("#region"))
|
||||
startLines.Push(i);
|
||||
if (text.StartsWith("#endregion") && startLines.Count > 0)
|
||||
{
|
||||
// Add a new FoldMarker to the list.
|
||||
int start = startLines.Pop();
|
||||
list.Add(new FoldMarker(document, start,
|
||||
document.GetLineSegment(start).Length,
|
||||
i, spaceCount + "#endregion".Length, FoldType.Region, "{...}"));
|
||||
}
|
||||
}
|
||||
|
||||
// { }
|
||||
if (document.GetCharAt(offs) == '{')
|
||||
{
|
||||
int offsetOfClosingBracket = document.FormattingStrategy.SearchBracketForward(document, offs + 1, '{', '}');
|
||||
if (offsetOfClosingBracket > 0)
|
||||
{
|
||||
int length = offsetOfClosingBracket - offs + 1;
|
||||
list.Add(new FoldMarker(document, offs, length, "{...}", false));
|
||||
}
|
||||
}
|
||||
|
||||
if (document.GetCharAt(offs) == '/')
|
||||
{
|
||||
string text = document.GetText(offs, seg.Length - spaceCount);
|
||||
if (text.StartsWith("/// <summary>"))
|
||||
startLines.Push(i);
|
||||
if ((text.StartsWith("/// <param") || text.StartsWith("/// <returns>") || text.StartsWith("/// </summary>"))
|
||||
&& startLines.Count > 0)
|
||||
{
|
||||
// Add a new FoldMarker to the list.
|
||||
int start = startLines.Pop();
|
||||
list.Add(new FoldMarker(document, start,
|
||||
document.GetLineSegment(start).Length,
|
||||
i, spaceCount + "/// </summary>".Length, FoldType.TypeBody, "/// <summary>..."));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
public enum FoldType {
|
||||
Unspecified,
|
||||
MemberBody,
|
||||
Region,
|
||||
TypeBody
|
||||
}
|
||||
|
||||
public class FoldMarker : AbstractSegment, IComparable
|
||||
{
|
||||
bool isFolded = false;
|
||||
string foldText = "...";
|
||||
FoldType foldType = FoldType.Unspecified;
|
||||
IDocument document = null;
|
||||
int startLine = -1, startColumn, endLine = -1, endColumn;
|
||||
|
||||
static void GetPointForOffset(IDocument document, int offset, out int line, out int column)
|
||||
{
|
||||
if (offset > document.TextLength) {
|
||||
line = document.TotalNumberOfLines + 1;
|
||||
column = 1;
|
||||
} else if (offset < 0) {
|
||||
line = -1;
|
||||
column = -1;
|
||||
} else {
|
||||
line = document.GetLineNumberForOffset(offset);
|
||||
column = offset - document.GetLineSegment(line).Offset;
|
||||
}
|
||||
}
|
||||
|
||||
public FoldType FoldType {
|
||||
get { return foldType; }
|
||||
set { foldType = value; }
|
||||
}
|
||||
|
||||
public int StartLine {
|
||||
get {
|
||||
if (startLine < 0) {
|
||||
GetPointForOffset(document, offset, out startLine, out startColumn);
|
||||
}
|
||||
return startLine;
|
||||
}
|
||||
}
|
||||
|
||||
public int StartColumn {
|
||||
get {
|
||||
if (startLine < 0) {
|
||||
GetPointForOffset(document, offset, out startLine, out startColumn);
|
||||
}
|
||||
return startColumn;
|
||||
}
|
||||
}
|
||||
|
||||
public int EndLine {
|
||||
get {
|
||||
if (endLine < 0) {
|
||||
GetPointForOffset(document, offset + length, out endLine, out endColumn);
|
||||
}
|
||||
return endLine;
|
||||
}
|
||||
}
|
||||
|
||||
public int EndColumn {
|
||||
get {
|
||||
if (endLine < 0) {
|
||||
GetPointForOffset(document, offset + length, out endLine, out endColumn);
|
||||
}
|
||||
return endColumn;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Offset {
|
||||
get { return base.Offset; }
|
||||
set {
|
||||
base.Offset = value;
|
||||
startLine = -1; endLine = -1;
|
||||
}
|
||||
}
|
||||
public override int Length {
|
||||
get { return base.Length; }
|
||||
set {
|
||||
base.Length = value;
|
||||
endLine = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFolded {
|
||||
get {
|
||||
return isFolded;
|
||||
}
|
||||
set {
|
||||
isFolded = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string FoldText {
|
||||
get {
|
||||
return foldText;
|
||||
}
|
||||
}
|
||||
|
||||
public string InnerText {
|
||||
get {
|
||||
return document.GetText(offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
public FoldMarker(IDocument document, int offset, int length, string foldText, bool isFolded)
|
||||
{
|
||||
this.document = document;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.foldText = foldText;
|
||||
this.isFolded = isFolded;
|
||||
}
|
||||
|
||||
public FoldMarker(IDocument document, int startLine, int startColumn, int endLine, int endColumn) : this(document, startLine, startColumn, endLine, endColumn, FoldType.Unspecified)
|
||||
{
|
||||
}
|
||||
|
||||
public FoldMarker(IDocument document, int startLine, int startColumn, int endLine, int endColumn, FoldType foldType) : this(document, startLine, startColumn, endLine, endColumn, foldType, "...")
|
||||
{
|
||||
}
|
||||
|
||||
public FoldMarker(IDocument document, int startLine, int startColumn, int endLine, int endColumn, FoldType foldType, string foldText) : this(document, startLine, startColumn, endLine, endColumn, foldType, foldText, false)
|
||||
{
|
||||
}
|
||||
|
||||
public FoldMarker(IDocument document, int startLine, int startColumn, int endLine, int endColumn, FoldType foldType, string foldText, bool isFolded)
|
||||
{
|
||||
this.document = document;
|
||||
|
||||
startLine = Math.Min(document.TotalNumberOfLines - 1, Math.Max(startLine, 0));
|
||||
ISegment startLineSegment = document.GetLineSegment(startLine);
|
||||
|
||||
endLine = Math.Min(document.TotalNumberOfLines - 1, Math.Max(endLine, 0));
|
||||
ISegment endLineSegment = document.GetLineSegment(endLine);
|
||||
|
||||
// Prevent the region from completely disappearing
|
||||
if (string.IsNullOrEmpty(foldText)) {
|
||||
foldText = "...";
|
||||
}
|
||||
|
||||
this.FoldType = foldType;
|
||||
this.foldText = foldText;
|
||||
this.offset = startLineSegment.Offset + Math.Min(startColumn, startLineSegment.Length);
|
||||
this.length = (endLineSegment.Offset + Math.Min(endColumn, endLineSegment.Length)) - this.offset;
|
||||
this.isFolded = isFolded;
|
||||
}
|
||||
|
||||
public int CompareTo(object o)
|
||||
{
|
||||
if (!(o is FoldMarker)) {
|
||||
throw new ArgumentException();
|
||||
}
|
||||
FoldMarker f = (FoldMarker)o;
|
||||
if (offset != f.offset) {
|
||||
return offset.CompareTo(f.offset);
|
||||
}
|
||||
|
||||
return length.CompareTo(f.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
public class FoldingManager
|
||||
{
|
||||
List<FoldMarker> foldMarker = new List<FoldMarker>();
|
||||
List<FoldMarker> foldMarkerByEnd = new List<FoldMarker>();
|
||||
IDocument document;
|
||||
|
||||
public IList<FoldMarker> FoldMarker => foldMarker.AsReadOnly();
|
||||
|
||||
public IFoldingStrategy? FoldingStrategy { get; set; }
|
||||
|
||||
internal FoldingManager(IDocument document, LineManager lineTracker)
|
||||
{
|
||||
this.document = document;
|
||||
document.DocumentChanged += new DocumentEventHandler(DocumentChanged);
|
||||
|
||||
// lineTracker.LineCountChanged += new LineManagerEventHandler(LineManagerLineCountChanged);
|
||||
// lineTracker.LineLengthChanged += new LineLengthEventHandler(LineManagerLineLengthChanged);
|
||||
// foldMarker.Add(new FoldMarker(0, 5, 3, 5));
|
||||
//
|
||||
// foldMarker.Add(new FoldMarker(5, 5, 10, 3));
|
||||
// foldMarker.Add(new FoldMarker(6, 0, 8, 2));
|
||||
//
|
||||
// FoldMarker fm1 = new FoldMarker(10, 4, 10, 7);
|
||||
// FoldMarker fm2 = new FoldMarker(10, 10, 10, 14);
|
||||
//
|
||||
// fm1.IsFolded = true;
|
||||
// fm2.IsFolded = true;
|
||||
//
|
||||
// foldMarker.Add(fm1);
|
||||
// foldMarker.Add(fm2);
|
||||
// foldMarker.Sort();
|
||||
}
|
||||
|
||||
void DocumentChanged(object sender, DocumentEventArgs e)
|
||||
{
|
||||
int oldCount = foldMarker.Count;
|
||||
document.UpdateSegmentListOnDocumentChange(foldMarker, e);
|
||||
if (oldCount != foldMarker.Count)
|
||||
{
|
||||
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
|
||||
}
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldingsFromPosition(int line, int column)
|
||||
{
|
||||
List<FoldMarker> foldings = new List<FoldMarker>();
|
||||
if (foldMarker != null)
|
||||
{
|
||||
for (int i = 0; i < foldMarker.Count; ++i)
|
||||
{
|
||||
FoldMarker fm = foldMarker[i];
|
||||
if ((fm.StartLine == line && column > fm.StartColumn && !(fm.EndLine == line && column >= fm.EndColumn)) ||
|
||||
(fm.EndLine == line && column < fm.EndColumn && !(fm.StartLine == line && column <= fm.StartColumn)) ||
|
||||
(line > fm.StartLine && line < fm.EndLine))
|
||||
{
|
||||
foldings.Add(fm);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foldings;
|
||||
}
|
||||
|
||||
class StartComparer : IComparer<FoldMarker>
|
||||
{
|
||||
public readonly static StartComparer Instance = new StartComparer();
|
||||
|
||||
public int Compare(FoldMarker x, FoldMarker y)
|
||||
{
|
||||
if (x.StartLine < y.StartLine)
|
||||
return -1;
|
||||
else if (x.StartLine == y.StartLine)
|
||||
return x.StartColumn.CompareTo(y.StartColumn);
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
class EndComparer : IComparer<FoldMarker>
|
||||
{
|
||||
public readonly static EndComparer Instance = new EndComparer();
|
||||
|
||||
public int Compare(FoldMarker x, FoldMarker y)
|
||||
{
|
||||
if (x.EndLine < y.EndLine)
|
||||
return -1;
|
||||
else if (x.EndLine == y.EndLine)
|
||||
return x.EndColumn.CompareTo(y.EndColumn);
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
List<FoldMarker> GetFoldingsByStartAfterColumn(int lineNumber, int column, bool forceFolded)
|
||||
{
|
||||
List<FoldMarker> foldings = new List<FoldMarker>();
|
||||
|
||||
if (foldMarker != null)
|
||||
{
|
||||
int index = foldMarker.BinarySearch(
|
||||
new FoldMarker(document, lineNumber, column, lineNumber, column),
|
||||
StartComparer.Instance);
|
||||
if (index < 0) index = ~index;
|
||||
|
||||
for (; index < foldMarker.Count; index++)
|
||||
{
|
||||
FoldMarker fm = foldMarker[index];
|
||||
if (fm.StartLine > lineNumber)
|
||||
break;
|
||||
if (fm.StartColumn <= column)
|
||||
continue;
|
||||
if (!forceFolded || fm.IsFolded)
|
||||
foldings.Add(fm);
|
||||
}
|
||||
}
|
||||
return foldings;
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldingsWithStart(int lineNumber)
|
||||
{
|
||||
return GetFoldingsByStartAfterColumn(lineNumber, -1, false);
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldedFoldingsWithStart(int lineNumber)
|
||||
{
|
||||
return GetFoldingsByStartAfterColumn(lineNumber, -1, true);
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldedFoldingsWithStartAfterColumn(int lineNumber, int column)
|
||||
{
|
||||
return GetFoldingsByStartAfterColumn(lineNumber, column, true);
|
||||
}
|
||||
|
||||
List<FoldMarker> GetFoldingsByEndAfterColumn(int lineNumber, int column, bool forceFolded)
|
||||
{
|
||||
List<FoldMarker> foldings = new List<FoldMarker>();
|
||||
|
||||
if (foldMarker != null)
|
||||
{
|
||||
int index = foldMarkerByEnd.BinarySearch(
|
||||
new FoldMarker(document, lineNumber, column, lineNumber, column),
|
||||
EndComparer.Instance);
|
||||
if (index < 0) index = ~index;
|
||||
|
||||
for (; index < foldMarkerByEnd.Count; index++)
|
||||
{
|
||||
FoldMarker fm = foldMarkerByEnd[index];
|
||||
if (fm.EndLine > lineNumber)
|
||||
break;
|
||||
if (fm.EndColumn <= column)
|
||||
continue;
|
||||
if (!forceFolded || fm.IsFolded)
|
||||
foldings.Add(fm);
|
||||
}
|
||||
}
|
||||
return foldings;
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldingsWithEnd(int lineNumber)
|
||||
{
|
||||
return GetFoldingsByEndAfterColumn(lineNumber, -1, false);
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldedFoldingsWithEnd(int lineNumber)
|
||||
{
|
||||
return GetFoldingsByEndAfterColumn(lineNumber, -1, true);
|
||||
}
|
||||
|
||||
public bool IsFoldStart(int lineNumber)
|
||||
{
|
||||
return GetFoldingsWithStart(lineNumber).Count > 0;
|
||||
}
|
||||
|
||||
public bool IsFoldEnd(int lineNumber)
|
||||
{
|
||||
return GetFoldingsWithEnd(lineNumber).Count > 0;
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetFoldingsContainsLineNumber(int lineNumber)
|
||||
{
|
||||
List<FoldMarker> foldings = new List<FoldMarker>();
|
||||
if (foldMarker != null)
|
||||
{
|
||||
foreach (FoldMarker fm in foldMarker)
|
||||
{
|
||||
if (fm.StartLine < lineNumber && lineNumber < fm.EndLine)
|
||||
{
|
||||
foldings.Add(fm);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foldings;
|
||||
}
|
||||
|
||||
public bool IsBetweenFolding(int lineNumber)
|
||||
{
|
||||
return GetFoldingsContainsLineNumber(lineNumber).Count > 0;
|
||||
}
|
||||
|
||||
public bool IsLineVisible(int lineNumber)
|
||||
{
|
||||
foreach (FoldMarker fm in GetFoldingsContainsLineNumber(lineNumber))
|
||||
{
|
||||
if (fm.IsFolded)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<FoldMarker> GetTopLevelFoldedFoldings()
|
||||
{
|
||||
List<FoldMarker> foldings = new List<FoldMarker>();
|
||||
if (foldMarker != null)
|
||||
{
|
||||
Point end = new Point(0, 0);
|
||||
foreach (FoldMarker fm in foldMarker)
|
||||
{
|
||||
if (fm.IsFolded && (fm.StartLine > end.Y || fm.StartLine == end.Y && fm.StartColumn >= end.X))
|
||||
{
|
||||
foldings.Add(fm);
|
||||
end = new Point(fm.EndColumn, fm.EndLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foldings;
|
||||
}
|
||||
|
||||
public void UpdateFoldings(string fileName, object parseInfo)
|
||||
{
|
||||
UpdateFoldings(FoldingStrategy?.GenerateFoldMarkers(document, fileName, parseInfo));
|
||||
}
|
||||
|
||||
public void UpdateFoldings(List<FoldMarker> newFoldings)
|
||||
{
|
||||
int oldFoldingsCount = foldMarker.Count;
|
||||
lock (this)
|
||||
{
|
||||
if (newFoldings != null && newFoldings.Count != 0)
|
||||
{
|
||||
newFoldings.Sort();
|
||||
if (foldMarker.Count == newFoldings.Count)
|
||||
{
|
||||
for (int i = 0; i < foldMarker.Count; ++i)
|
||||
{
|
||||
newFoldings[i].IsFolded = foldMarker[i].IsFolded;
|
||||
}
|
||||
foldMarker = newFoldings;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0, j = 0; i < foldMarker.Count && j < newFoldings.Count;)
|
||||
{
|
||||
int n = newFoldings[j].CompareTo(foldMarker[i]);
|
||||
if (n > 0)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n == 0)
|
||||
{
|
||||
newFoldings[j].IsFolded = foldMarker[i].IsFolded;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newFoldings != null)
|
||||
{
|
||||
foldMarker = newFoldings;
|
||||
foldMarkerByEnd = new List<FoldMarker>(newFoldings);
|
||||
foldMarkerByEnd.Sort(EndComparer.Instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
foldMarker.Clear();
|
||||
foldMarkerByEnd.Clear();
|
||||
}
|
||||
}
|
||||
if (oldFoldingsCount != foldMarker.Count)
|
||||
{
|
||||
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
|
||||
document.CommitUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public string SerializeToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (FoldMarker marker in this.foldMarker)
|
||||
{
|
||||
sb.Append(marker.Offset); sb.Append("\n");
|
||||
sb.Append(marker.Length); sb.Append("\n");
|
||||
sb.Append(marker.FoldText); sb.Append("\n");
|
||||
sb.Append(marker.IsFolded); sb.Append("\n");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void DeserializeFromString(string str)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] lines = str.Split('\n');
|
||||
for (int i = 0; i < lines.Length && lines[i].Length > 0; i += 4)
|
||||
{
|
||||
int offset = int.Parse(lines[i]);
|
||||
int length = int.Parse(lines[i + 1]);
|
||||
string text = lines[i + 2];
|
||||
bool isFolded = bool.Parse(lines[i + 3]);
|
||||
bool found = false;
|
||||
foreach (FoldMarker marker in foldMarker)
|
||||
{
|
||||
if (marker.Offset == offset && marker.Length == length)
|
||||
{
|
||||
marker.IsFolded = isFolded;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
foldMarker.Add(new FoldMarker(document, offset, length, text, isFolded));
|
||||
}
|
||||
}
|
||||
if (lines.Length > 0)
|
||||
{
|
||||
NotifyFoldingsChanged(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Empty catch
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyFoldingsChanged(EventArgs e)
|
||||
{
|
||||
if (FoldingsChanged != null)
|
||||
{
|
||||
FoldingsChanged(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public event EventHandler FoldingsChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface is used for the folding capabilities
|
||||
/// of the textarea.
|
||||
/// </summary>
|
||||
public interface IFoldingStrategy
|
||||
{
|
||||
/// <remarks>
|
||||
/// Calculates the fold level of a specific line.
|
||||
/// </remarks>
|
||||
List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using ICSharpCode.TextEditor.Document;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Src.Document.FoldingStrategy
|
||||
{
|
||||
public interface IFoldingStrategyEx : IFoldingStrategy
|
||||
{
|
||||
List<string> GetFoldingErrors();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple folding strategy which calculates the folding level
|
||||
/// using the indent level of the line.
|
||||
/// </summary>
|
||||
public class IndentFoldingStrategy : IFoldingStrategy
|
||||
{
|
||||
public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
|
||||
{
|
||||
List<FoldMarker> l = new List<FoldMarker>();
|
||||
Stack<int> offsetStack = new Stack<int>();
|
||||
Stack<string> textStack = new Stack<string>();
|
||||
//int level = 0;
|
||||
//foreach (LineSegment segment in document.LineSegmentCollection) {
|
||||
//
|
||||
//}
|
||||
return l;
|
||||
}
|
||||
|
||||
int GetLevel(IDocument document, int offset)
|
||||
{
|
||||
int level = 0;
|
||||
int spaces = 0;
|
||||
for (int i = offset; i < document.TextLength; ++i) {
|
||||
char c = document.GetCharAt(i);
|
||||
if (c == '\t' || (c == ' ' && ++spaces == 4)) {
|
||||
spaces = 0;
|
||||
++level;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// This file is part of CodingEditor.
|
||||
// Note: This project is derived from Peter Project
|
||||
// (hosted on sourceforge and codeplex)
|
||||
//
|
||||
// Copyright (c) 2008-2009, CE Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICSharpCode.TextEditor.Document;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Src.Document.FoldingStrategy
|
||||
{
|
||||
public class JSONFoldingStrategy : IFoldingStrategy
|
||||
{
|
||||
#region Methods
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var list = new List<FoldMarker>();
|
||||
var startLines = new Stack<int>();
|
||||
|
||||
// Create foldmarkers for the whole document, enumerate through every line.
|
||||
for (int i = 0; i < document.TotalNumberOfLines; i++)
|
||||
{
|
||||
var seg = document.GetLineSegment(i);
|
||||
int offs, end = seg.Length + seg.Offset;
|
||||
char c;
|
||||
for (
|
||||
offs = seg.Offset;
|
||||
offs < end;
|
||||
offs++)
|
||||
{
|
||||
|
||||
c = document.GetCharAt(offs);
|
||||
if (seg.Words.Any(w => w.IsDelimiter && w.Offset == offs - seg.Offset && w.Word == c.ToString()))
|
||||
{
|
||||
if (c == '{')
|
||||
{
|
||||
int offsetOfClosingBracket = SearchBracketForward(document, i, offs, '{', '}');
|
||||
if (offsetOfClosingBracket > 0)
|
||||
{
|
||||
int length = offsetOfClosingBracket - offs + 1;
|
||||
list.Add(new FoldMarker(document, offs, length, "{...}", false));
|
||||
}
|
||||
}
|
||||
if (c == '[')
|
||||
{
|
||||
int offsetOfClosingBracket = SearchBracketForward(document, i, offs, '[', ']');
|
||||
if (offsetOfClosingBracket > 0)
|
||||
{
|
||||
int length = offsetOfClosingBracket - offs + 1;
|
||||
list.Add(new FoldMarker(document, offs, length, "[...]", false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
private int SearchBracketForward(IDocument document, int currLine, int currOffset, char openBracket, char closingBracket)
|
||||
{
|
||||
// Create foldmarkers for the whole document, enumerate through every line.
|
||||
|
||||
int brackets = 1, spaceCount = 0;
|
||||
for (int i = currLine; i < document.TotalNumberOfLines; i++)
|
||||
{
|
||||
var seg = document.GetLineSegment(i);
|
||||
int offs, end = seg.Length + seg.Offset;
|
||||
char c;
|
||||
for (
|
||||
offs = i == currLine ? currOffset + 1 : seg.Offset;
|
||||
offs < end;
|
||||
offs++)
|
||||
{
|
||||
|
||||
c = document.GetCharAt(offs);
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') spaceCount++;
|
||||
if (seg.Words.Any(w => w.IsDelimiter && w.Offset == offs - seg.Offset && w.Word == c.ToString()))
|
||||
{
|
||||
if (c == openBracket)
|
||||
{
|
||||
++brackets;
|
||||
}
|
||||
else if (c == closingBracket)
|
||||
{
|
||||
--brackets;
|
||||
if (brackets == 0)
|
||||
{
|
||||
if (offs - spaceCount - 1 == currOffset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return offs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
// Copied from http://codingeditor.googlecode.com/svn/trunk/libs/ICSharpCode.TextEditor/Project/Src/Document/FoldingStrategy/
|
||||
#region Header
|
||||
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
|
||||
// <version>$Revision: 1971 $</version>
|
||||
// </file>
|
||||
|
||||
#endregion Header
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using ICSharpCode.TextEditor.Document;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Src.Document.FoldingStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds information about the start of a fold in an xml string.
|
||||
/// </summary>
|
||||
class XmlFoldStart
|
||||
{
|
||||
#region Fields
|
||||
|
||||
readonly int _col;
|
||||
string _foldText = string.Empty;
|
||||
readonly int _line;
|
||||
readonly string _name = string.Empty;
|
||||
readonly string _prefix = string.Empty;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Constructors
|
||||
|
||||
public XmlFoldStart(string prefix, string name, int line, int col)
|
||||
{
|
||||
_line = line;
|
||||
_col = col;
|
||||
_prefix = prefix;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// The column where the fold should start. Columns start from 0.
|
||||
/// </summary>
|
||||
public int Column
|
||||
{
|
||||
get
|
||||
{
|
||||
return _col;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The text to be displayed when the item is folded.
|
||||
/// </summary>
|
||||
public string FoldText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _foldText;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_foldText = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The line where the fold should start. Lines start from 0.
|
||||
/// </summary>
|
||||
public int Line
|
||||
{
|
||||
get
|
||||
{
|
||||
return _line;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of the xml item with its prefix if it has one.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _prefix.Length > 0 ? string.Concat(_prefix, ":", _name) : _name;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines folds for an xml string in the editor.
|
||||
/// </summary>
|
||||
public class XmlFoldingStrategy : IFoldingStrategyEx
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating whether attributes should be displayed on folded elements.
|
||||
/// </summary>
|
||||
public bool ShowAttributesWhenFolded = false;
|
||||
|
||||
private List<string> _foldingErrors = new List<string>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Methods
|
||||
|
||||
public List<string> GetFoldingErrors()
|
||||
{
|
||||
return _foldingErrors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds folds to the text editor around each start-end element pair.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If the xml is not well formed then no folds are created.</para>
|
||||
/// <para>Note that the xml text reader lines and positions start
|
||||
/// from 1 and the SharpDevelop text editor line information starts from 0.</para>
|
||||
/// </remarks>
|
||||
public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
|
||||
{
|
||||
_foldingErrors = new List<string>();
|
||||
//showAttributesWhenFolded = XmlEditorAddInOptions.ShowAttributesWhenFolded;
|
||||
|
||||
var foldMarkers = new List<FoldMarker>();
|
||||
var stack = new Stack();
|
||||
|
||||
try
|
||||
{
|
||||
string xml = document.TextContent;
|
||||
var reader = new XmlTextReader(new StringReader(xml));
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element:
|
||||
if (!reader.IsEmptyElement)
|
||||
{
|
||||
XmlFoldStart newFoldStart = CreateElementFoldStart(reader);
|
||||
stack.Push(newFoldStart);
|
||||
}
|
||||
break;
|
||||
|
||||
case XmlNodeType.EndElement:
|
||||
var foldStart = (XmlFoldStart)stack.Pop();
|
||||
CreateElementFold(document, foldMarkers, reader, foldStart);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Comment:
|
||||
CreateCommentFold(document, foldMarkers, reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_foldingErrors.Add(ex.Message);
|
||||
|
||||
// If the xml is not well formed keep the foldings that already exist in the document.
|
||||
return new List<FoldMarker>(document.FoldingManager.FoldMarker);
|
||||
}
|
||||
|
||||
return foldMarkers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml encode the attribute string since the string returned from
|
||||
/// the XmlTextReader is the plain unencoded string and .NET
|
||||
/// does not provide us with an xml encode method.
|
||||
/// </summary>
|
||||
static string XmlEncodeAttributeValue(string attributeValue, char quoteChar)
|
||||
{
|
||||
var encodedValue = new StringBuilder(attributeValue);
|
||||
|
||||
encodedValue.Replace("&", "&");
|
||||
encodedValue.Replace("<", "<");
|
||||
encodedValue.Replace(">", ">");
|
||||
|
||||
if (quoteChar == '"')
|
||||
{
|
||||
encodedValue.Replace("\"", """);
|
||||
}
|
||||
else
|
||||
{
|
||||
encodedValue.Replace("'", "'");
|
||||
}
|
||||
|
||||
return encodedValue.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a comment fold if the comment spans more than one line.
|
||||
/// </summary>
|
||||
/// <remarks>The text displayed when the comment is folded is the first
|
||||
/// line of the comment.</remarks>
|
||||
void CreateCommentFold(IDocument document, List<FoldMarker> foldMarkers, XmlTextReader reader)
|
||||
{
|
||||
if (reader.Value != null)
|
||||
{
|
||||
string comment = reader.Value.Replace("\r\n", "\n");
|
||||
string[] lines = comment.Split('\n');
|
||||
if (lines.Length > 1)
|
||||
{
|
||||
|
||||
// Take off 5 chars to get the actual comment start (takes
|
||||
// into account the <!-- chars.
|
||||
int startCol = reader.LinePosition - 5;
|
||||
int startLine = reader.LineNumber - 1;
|
||||
|
||||
// Add 3 to the end col value to take into account the '-->'
|
||||
int endCol = lines[lines.Length - 1].Length + startCol + 3;
|
||||
int endLine = startLine + lines.Length - 1;
|
||||
string foldText = string.Concat("<!--", lines[0], "-->");
|
||||
var foldMarker = new FoldMarker(document, startLine, startCol, endLine, endCol, FoldType.TypeBody, foldText);
|
||||
foldMarkers.Add(foldMarker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an element fold if the start and end tag are on
|
||||
/// different lines.
|
||||
/// </summary>
|
||||
void CreateElementFold(IDocument document, List<FoldMarker> foldMarkers, XmlTextReader reader, XmlFoldStart foldStart)
|
||||
{
|
||||
int endLine = reader.LineNumber - 1;
|
||||
if (endLine > foldStart.Line)
|
||||
{
|
||||
int endCol = reader.LinePosition + foldStart.Name.Length;
|
||||
var foldMarker = new FoldMarker(document, foldStart.Line, foldStart.Column, endLine, endCol, FoldType.TypeBody, foldStart.FoldText);
|
||||
foldMarkers.Add(foldMarker);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an XmlFoldStart for the start tag of an element.
|
||||
/// </summary>
|
||||
XmlFoldStart CreateElementFoldStart(XmlTextReader reader)
|
||||
{
|
||||
// Take off 2 from the line position returned
|
||||
// from the xml since it points to the start
|
||||
// of the element name and not the beginning
|
||||
// tag.
|
||||
var newFoldStart = new XmlFoldStart(reader.Prefix, reader.LocalName, reader.LineNumber - 1, reader.LinePosition - 2);
|
||||
|
||||
if (ShowAttributesWhenFolded && reader.HasAttributes)
|
||||
{
|
||||
newFoldStart.FoldText = string.Concat("<", newFoldStart.Name, " ", GetAttributeFoldText(reader), ">");
|
||||
}
|
||||
else
|
||||
{
|
||||
newFoldStart.FoldText = string.Concat("<", newFoldStart.Name, ">");
|
||||
}
|
||||
|
||||
return newFoldStart;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the element's attributes as a string on one line that will
|
||||
/// be displayed when the element is folded.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this puts all attributes from an element on the same
|
||||
/// line of the start tag. It does not cater for elements where attributes
|
||||
/// are not on the same line as the start tag.
|
||||
/// </remarks>
|
||||
string GetAttributeFoldText(XmlTextReader reader)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < reader.AttributeCount; ++i)
|
||||
{
|
||||
reader.MoveToAttribute(i);
|
||||
|
||||
text.Append(reader.Name);
|
||||
text.Append("=");
|
||||
text.Append(reader.QuoteChar.ToString(CultureInfo.InvariantCulture));
|
||||
text.Append(XmlEncodeAttributeValue(reader.Value, reader.QuoteChar));
|
||||
text.Append(reader.QuoteChar.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
// Append a space if this is not the
|
||||
// last attribute.
|
||||
if (i < reader.AttributeCount - 1)
|
||||
{
|
||||
text.Append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user