Browse Source

Add simple XmlReader-based XmlFoldingStrategy to AvalonEdit.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4912 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
5dae574aec
  1. 32
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/BraceFoldingStrategy.cs
  2. 17
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/NewFolding.cs
  3. 216
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/XmlFoldingStrategy.cs
  4. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

32
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/BraceFoldingStrategy.cs

@ -11,10 +11,31 @@ using System.Collections.Generic; @@ -11,10 +11,31 @@ using System.Collections.Generic;
namespace ICSharpCode.AvalonEdit.Folding
{
/// <summary>
/// Base class for folding strategies.
/// </summary>
public abstract class AbstractFoldingStrategy
{
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document and updates the folding manager with them.
/// </summary>
public void UpdateFoldings(FoldingManager manager, TextDocument document)
{
int firstErrorOffset;
IEnumerable<NewFolding> foldings = CreateNewFoldings(document, out firstErrorOffset);
manager.UpdateFoldings(foldings, firstErrorOffset);
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public abstract IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset);
}
/// <summary>
/// Allows producing foldings from a document based on braces.
/// </summary>
public class BraceFoldingStrategy
public class BraceFoldingStrategy : AbstractFoldingStrategy
{
/// <summary>
/// Gets/Sets the opening brace. The default value is '{'.
@ -35,6 +56,15 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -35,6 +56,15 @@ namespace ICSharpCode.AvalonEdit.Folding
this.ClosingBrace = '}';
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
{
firstErrorOffset = -1;
return CreateNewFoldings(document);
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>

17
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/NewFolding.cs

@ -21,17 +21,17 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -21,17 +21,17 @@ namespace ICSharpCode.AvalonEdit.Folding
/// <summary>
/// Helper class used for <see cref="FoldingManager.UpdateFoldings"/>.
/// </summary>
public sealed class NewFolding : ISegment
public class NewFolding : ISegment
{
/// <summary>
/// Gets the start offset.
/// Gets/Sets the start offset.
/// </summary>
public int StartOffset { get; private set; }
public int StartOffset { get; set; }
/// <summary>
/// Gets the end offset.
/// Gets/Sets the end offset.
/// </summary>
public int EndOffset { get; private set; }
public int EndOffset { get; set; }
/// <summary>
/// Gets/Sets the name displayed for the folding.
@ -43,6 +43,13 @@ namespace ICSharpCode.AvalonEdit.Folding @@ -43,6 +43,13 @@ namespace ICSharpCode.AvalonEdit.Folding
/// </summary>
public bool DefaultClosed { get; set; }
/// <summary>
/// Creates a new NewFolding instance.
/// </summary>
public NewFolding()
{
}
/// <summary>
/// Creates a new NewFolding instance.
/// </summary>

216
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/XmlFoldingStrategy.cs

@ -0,0 +1,216 @@ @@ -0,0 +1,216 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Folding
{
/// <summary>
/// Holds information about the start of a fold in an xml string.
/// </summary>
sealed class XmlFoldStart : NewFolding
{
internal int StartLine;
}
/// <summary>
/// Determines folds for an xml string in the editor.
/// </summary>
public class XmlFoldingStrategy : AbstractFoldingStrategy
{
/// <summary>
/// Flag indicating whether attributes should be displayed on folded
/// elements.
/// </summary>
public bool ShowAttributesWhenFolded { get; set; }
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
{
try {
XmlTextReader reader = new XmlTextReader(document.CreateReader());
reader.XmlResolver = null; // don't resolve DTDs
return CreateNewFoldings(document, reader, out firstErrorOffset);
} catch (XmlException) {
firstErrorOffset = 0;
return Enumerable.Empty<NewFolding>();
}
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, XmlReader reader, out int firstErrorOffset)
{
Stack<XmlFoldStart> stack = new Stack<XmlFoldStart>();
List<NewFolding> foldMarkers = new List<NewFolding>();
try {
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.Element:
if (!reader.IsEmptyElement) {
XmlFoldStart newFoldStart = CreateElementFoldStart(document, reader);
stack.Push(newFoldStart);
}
break;
case XmlNodeType.EndElement:
XmlFoldStart foldStart = stack.Pop();
CreateElementFold(document, foldMarkers, reader, foldStart);
break;
case XmlNodeType.Comment:
CreateCommentFold(document, foldMarkers, reader);
break;
}
}
firstErrorOffset = -1;
} catch (XmlException ex) {
// ignore errors
firstErrorOffset = document.GetOffset(ex.LineNumber, ex.LinePosition);
}
foldMarkers.Sort((a,b) => a.StartOffset.CompareTo(b.StartOffset));
return foldMarkers;
}
int GetOffset(TextDocument document, XmlReader reader)
{
IXmlLineInfo info = reader as IXmlLineInfo;
if (info != null && info.HasLineInfo()) {
return document.GetOffset(info.LineNumber, info.LinePosition);
} else {
throw new ArgumentException("XmlReader does not have positioning information.");
}
}
/// <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(TextDocument document, List<NewFolding> foldMarkers, XmlReader reader)
{
string comment = reader.Value;
if (comment != null) {
int firstNewLine = comment.IndexOf('\n');
if (firstNewLine >= 0) {
// Take off 4 chars to get the actual comment start (takes
// into account the <!-- chars.
int startOffset = GetOffset(document, reader) - 4;
int endOffset = startOffset + comment.Length + 3;
string foldText = String.Concat("<!--", comment.Substring(0, firstNewLine).TrimEnd('\r') , "-->");
foldMarkers.Add(new NewFolding(startOffset, endOffset) { Name = foldText } );
}
}
}
/// <summary>
/// Creates an XmlFoldStart for the start tag of an element.
/// </summary>
XmlFoldStart CreateElementFoldStart(TextDocument document, XmlReader reader)
{
// Take off 1 from the offset returned
// from the xml since it points to the start
// of the element name and not the beginning
// tag.
//XmlFoldStart newFoldStart = new XmlFoldStart(reader.Prefix, reader.LocalName, reader.LineNumber - 1, reader.LinePosition - 2);
XmlFoldStart newFoldStart = new XmlFoldStart();
IXmlLineInfo lineInfo = (IXmlLineInfo)reader;
newFoldStart.StartLine = lineInfo.LineNumber;
newFoldStart.StartOffset = document.GetOffset(newFoldStart.StartLine, lineInfo.LinePosition - 1);
if (this.ShowAttributesWhenFolded && reader.HasAttributes) {
newFoldStart.Name = String.Concat("<", reader.Name, " ", GetAttributeFoldText(reader), ">");
} else {
newFoldStart.Name = String.Concat("<", reader.Name, ">");
}
return newFoldStart;
}
/// <summary>
/// Create an element fold if the start and end tag are on
/// different lines.
/// </summary>
void CreateElementFold(TextDocument document, List<NewFolding> foldMarkers, XmlReader reader, XmlFoldStart foldStart)
{
IXmlLineInfo lineInfo = (IXmlLineInfo)reader;
int endLine = lineInfo.LineNumber;
if (endLine > foldStart.StartLine) {
int endCol = lineInfo.LinePosition + reader.Name.Length + 1;
foldStart.EndOffset = document.GetOffset(endLine, endCol);
foldMarkers.Add(foldStart);
}
}
/// <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(XmlReader reader)
{
StringBuilder 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());
text.Append(XmlEncodeAttributeValue(reader.Value, reader.QuoteChar));
text.Append(reader.QuoteChar.ToString());
// Append a space if this is not the
// last attribute.
if (i < reader.AttributeCount - 1) {
text.Append(" ");
}
}
return text.ToString();
}
/// <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)
{
StringBuilder encodedValue = new StringBuilder(attributeValue);
encodedValue.Replace("&", "&amp;");
encodedValue.Replace("<", "&lt;");
encodedValue.Replace(">", "&gt;");
if (quoteChar == '"') {
encodedValue.Replace("\"", "&quot;");
} else {
encodedValue.Replace("'", "&apos;");
}
return encodedValue.ToString();
}
}
}

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

@ -172,6 +172,7 @@ @@ -172,6 +172,7 @@
<DependentUpon>IReadOnlySectionProvider.cs</DependentUpon>
</Compile>
<Compile Include="Folding\NewFolding.cs" />
<Compile Include="Folding\XmlFoldingStrategy.cs" />
<Compile Include="Highlighting\DocumentHighlighter.cs" />
<Compile Include="Highlighting\HighlightedInlineBuilder.cs" />
<Compile Include="Highlighting\HighlightedLine.cs" />

Loading…
Cancel
Save