Browse Source

XML Parser: Using only one copy of raw DOM again. All DOM object offsets will be always relative to the last parsed text. The user can use list of changes since last parse to translate between the old offsets and new ones.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4581 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
4c6945b8bb
  1. 144
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs
  2. 63
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs

144
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs

@ -39,26 +39,24 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -39,26 +39,24 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public RawObject Parent { get; set; }
public RawDocument Document {
get {
if (this.Parent != null) {
return this.Parent.Document;
} else if (this is RawDocument) {
return (RawDocument)this;
} else {
return null;
}
}
}
// public RawDocument Document {
// get {
// if (this.Parent != null) {
// return this.Parent.Document;
// } else if (this is RawDocument) {
// return (RawDocument)this;
// } else {
// return null;
// }
// }
// }
/// <summary> Occurs when the value of any local properties changes. Nested changes do not cause the event to occur </summary>
public event EventHandler LocalDataChanged;
protected void OnLocalDataChanged()
{
if (!inCloning) {
Log("XML DOM: Local data changed for {0}", this);
}
LogDom("Local data changed for {0}", this);
if (LocalDataChanged != null) {
LocalDataChanged(this, EventArgs.Empty);
}
@ -78,26 +76,11 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -78,26 +76,11 @@ namespace ICSharpCode.AvalonEdit.XmlParser
this.ReadCallID = new object();
}
// Disable some log messages during cloning
static bool inCloning = false;
public RawObject Clone()
{
RawObject clone = (RawObject)System.Activator.CreateInstance(this.GetType());
inCloning = true;
clone.UpdateDataFrom(this);
inCloning = false;
return clone;
}
public virtual IEnumerable<RawObject> GetSeftAndAllNestedObjects()
{
yield return this;
}
public virtual void UpdateDataFrom(RawObject source)
{
this.ReadCallID = source.ReadCallID;
// In some cases we are just updating objects of that same
// type and sequential position hoping to be luckily right
this.StartOffset = source.StartOffset;
this.EndOffset = source.EndOffset;
}
@ -107,42 +90,36 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -107,42 +90,36 @@ namespace ICSharpCode.AvalonEdit.XmlParser
return string.Format("{0}({1}-{2})", this.GetType().Name.Remove(0, 3), this.StartOffset, this.EndOffset);
}
public static bool LoggingEnabled = true;
public static void Log(string format, params object[] args)
public static void LogDom(string format, params object[] args)
{
if (LoggingEnabled) {
System.Diagnostics.Debug.WriteLine(format, args);
}
System.Diagnostics.Debug.WriteLine("XML DOM: " + format, args);
}
public static void LogLinq(string format, params object[] args)
{
if (LoggingEnabled) {
System.Diagnostics.Debug.WriteLine("XML Linq: " + format, args);
}
System.Diagnostics.Debug.WriteLine("XML Linq: " + format, args);
}
internal void OnInserting(RawObject parent, int index)
{
Log("XML DOM: Inserting {0} at index {1}", this, index);
LogDom("Inserting {0} at index {1}", this, index);
this.Parent = parent;
if (this.Document != null) {
foreach(RawObject obj in GetSeftAndAllNestedObjects()) {
this.Document.OnObjectAttached(new RawObjectEventArgs() { Object = obj });
}
}
// if (this.Document != null) {
// foreach(RawObject obj in GetSeftAndAllNestedObjects()) {
// this.Document.OnObjectAttached(new RawObjectEventArgs() { Object = obj });
// }
// }
}
internal void OnRemoving(RawObject parent, int index)
{
Log("XML DOM: Removing {0} at index {1}", this, index);
LogDom("Removing {0} at index {1}", this, index);
this.Parent = null;
if (this.Document != null) {
foreach(RawObject obj in GetSeftAndAllNestedObjects()) {
this.Document.OnObjectDettached(new RawObjectEventArgs() { Object = obj });
}
}
// if (this.Document != null) {
// foreach(RawObject obj in GetSeftAndAllNestedObjects()) {
// this.Document.OnObjectDettached(new RawObjectEventArgs() { Object = obj });
// }
// }
}
protected XName EncodeXName(string name, string ns)
@ -161,8 +138,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -161,8 +138,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser
{
public ObservableCollection<RawObject> Children { get; set; }
public event EventHandler<RawObjectEventArgs> ObjectAttached;
public event EventHandler<RawObjectEventArgs> ObjectDettached;
// public event EventHandler<RawObjectEventArgs> ObjectAttached;
// public event EventHandler<RawObjectEventArgs> ObjectDettached;
public ObservableCollection<RawObject> Helper_Elements {
get {
@ -170,29 +147,21 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -170,29 +147,21 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
}
internal void OnObjectAttached(RawObjectEventArgs e)
{
if (ObjectAttached != null) ObjectAttached(this, e);
}
internal void OnObjectDettached(RawObjectEventArgs e)
{
if (ObjectDettached != null) ObjectDettached(this, e);
}
// internal void OnObjectAttached(RawObjectEventArgs e)
// {
// if (ObjectAttached != null) ObjectAttached(this, e);
// }
//
// internal void OnObjectDettached(RawObjectEventArgs e)
// {
// if (ObjectDettached != null) ObjectDettached(this, e);
// }
public RawDocument()
{
this.Children = new ObservableCollection<RawObject>();
}
public override IEnumerable<RawObject> GetSeftAndAllNestedObjects()
{
return Enumerable.Union(
new RawObject[] { this },
this.Children.SelectMany(x => x.GetSeftAndAllNestedObjects())
);
}
public override void UpdateDataFrom(RawObject source)
{
if (this.ReadCallID == source.ReadCallID) return;
@ -242,14 +211,6 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -242,14 +211,6 @@ namespace ICSharpCode.AvalonEdit.XmlParser
this.Attributes = new ObservableCollection<RawObject>();
}
public override IEnumerable<RawObject> GetSeftAndAllNestedObjects()
{
return Enumerable.Union(
new RawObject[] { this },
this.Attributes // Have no nested objects
);
}
public override void UpdateDataFrom(RawObject source)
{
if (this.ReadCallID == source.ReadCallID) return;
@ -298,16 +259,6 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -298,16 +259,6 @@ namespace ICSharpCode.AvalonEdit.XmlParser
this.EndTag = new RawTag() { Parent = this };
}
public override IEnumerable<RawObject> GetSeftAndAllNestedObjects()
{
return new IEnumerable<RawObject>[] {
new RawObject[] { this },
this.StartTag.GetSeftAndAllNestedObjects(),
this.Children.SelectMany(x => x.GetSeftAndAllNestedObjects()),
this.EndTag.GetSeftAndAllNestedObjects()
}.SelectMany(x => x);
}
public override void UpdateDataFrom(RawObject source)
{
if (this.ReadCallID == source.ReadCallID) return;
@ -477,9 +428,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -477,9 +428,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser
for(int i = 0; i < srcList.Count;) {
// Item is missing - 'i' is invalid index
if (i >= dstList.Count) {
RawObject clone = srcList[i].Clone();
clone.OnInserting(dstListOwner, i);
dstList.Insert(i, clone);
srcList[i].OnInserting(dstListOwner, i);
dstList.Insert(i, srcList[i]);
i++; continue;
}
RawObject srcItem = srcList[i];
@ -501,9 +451,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -501,9 +451,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser
RawObject src = srcList[srcItemIndex];
if (src.StartOffset == dstItem.StartOffset && src.GetType() == dstItem.GetType()) {
for(int j = i; j < srcItemIndex; j++) {
RawObject clone = srcList[j].Clone();
clone.OnInserting(dstListOwner, j);
dstList.Insert(j, clone);
srcList[j].OnInserting(dstListOwner, j);
dstList.Insert(j, srcList[j]);
}
i = srcItemIndex;
goto continue2;
@ -533,9 +482,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -533,9 +482,8 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
// Otherwise just add the item
{
RawObject clone = srcList[i].Clone();
clone.OnInserting(dstListOwner, i);
dstList.Insert(i, clone);
srcList[i].OnInserting(dstListOwner, i);
dstList.Insert(i, srcList[i]);
i++; continue;
}
}

63
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
@ -19,26 +20,19 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -19,26 +20,19 @@ namespace ICSharpCode.AvalonEdit.XmlParser
{
public class XmlParser
{
RawDocument userDocument;
RawDocument userDocument = new RawDocument();
XDocument userLinqDocument;
TextDocument textDocument;
TextSegmentCollection<RawObject> userDom;
TextSegmentCollection<RawObject> parsedDom;
TextSegmentCollection<RawObject> parsedItems = new TextSegmentCollection<RawObject>();
List<DocumentChangeEventArgs> changesSinceLastParse = new List<DocumentChangeEventArgs>();
public XmlParser(TextDocument textDocument)
{
this.userDocument = new RawDocument();
this.userLinqDocument = userDocument.CreateXDocument(true);
this.textDocument = textDocument;
this.userDom = new TextSegmentCollection<RawObject>(textDocument);
this.parsedDom = new TextSegmentCollection<RawObject>(textDocument);
this.textDocument.Changed += TextDocument_Changed;
this.userDocument.ObjectAttached += delegate(object sender, RawObjectEventArgs e) {
this.userDom.Add(e.Object);
this.textDocument.Changed += delegate(object sender, DocumentChangeEventArgs e) {
changesSinceLastParse.Add(e);
};
this.userDocument.ObjectDettached += delegate(object sender, RawObjectEventArgs e) {
this.userDom.Remove(e.Object);
};
this.userLinqDocument = this.userDocument.CreateXDocument(true);
}
public RawDocument Parse()
@ -46,32 +40,35 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -46,32 +40,35 @@ namespace ICSharpCode.AvalonEdit.XmlParser
currentLocation = 0;
input = textDocument.Text;
foreach(DocumentChangeEventArgs change in changesSinceLastParse) {
// Update offsets of all items
parsedItems.UpdateOffsets(change);
// Remove any items affected by the change
int start = change.Offset - 2;
int end = change.Offset + change.InsertionLength + 2;
start = Math.Max(Math.Min(start, textDocument.TextLength - 1), 0);
end = Math.Max(Math.Min(end, textDocument.TextLength - 1), 0);
foreach(RawObject obj in parsedItems.FindOverlappingSegments(start, end - start)) {
parsedItems.Remove(obj);
Log("Removed cached item: {0}", obj);
}
}
changesSinceLastParse.Clear();
RawDocument parsedDocument = ReadDocument();
userDocument.UpdateDataFrom(parsedDocument);
return userDocument;
}
void TextDocument_Changed(object sender, DocumentChangeEventArgs e)
{
int start = e.Offset - 2;
int end = e.Offset + e.InsertionLength + 2;
start = Math.Max(Math.Min(start, textDocument.TextLength - 1), 0);
end = Math.Max(Math.Min(end, textDocument.TextLength - 1), 0);
foreach(RawObject obj in parsedDom.FindOverlappingSegments(start, end - start)) {
parsedDom.Remove(obj);
Log("Removed cached item: {0}", obj);
}
}
T ReadFromCache<T>(int location) where T: RawObject
{
RawObject obj = parsedDom.FindFirstSegmentWithStartAfter(location);
RawObject obj = parsedItems.FindFirstSegmentWithStartAfter(location);
while(obj != null && obj.StartOffset == location) {
if (obj is T) {
currentLocation += obj.Length;
return (T)obj;
}
obj = parsedDom.GetNextSegment(obj);
obj = parsedItems.GetNextSegment(obj);
}
return null;
}
@ -203,7 +200,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -203,7 +200,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
doc.EndOffset = currentLocation;
LogParsed(doc);
parsedDom.Add(doc);
parsedItems.Add(doc);
return doc;
}
@ -243,7 +240,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -243,7 +240,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
element.EndOffset = currentLocation;
LogParsed(element);
parsedDom.Add(element);
parsedItems.Add(element);
return element;
}
@ -307,7 +304,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -307,7 +304,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
tag.EndOffset = currentLocation;
LogParsed(tag);
parsedDom.Add(tag);
parsedItems.Add(tag);
return tag;
}
@ -326,7 +323,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -326,7 +323,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
ws.Value = GetText(start, currentLocation);
ws.EndOffset = currentLocation;
parsedDom.Add(ws);
parsedItems.Add(ws);
return ws;
}
@ -374,7 +371,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -374,7 +371,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
attr.EndOffset = currentLocation;
parsedDom.Add(attr);
parsedItems.Add(attr);
return attr;
}
@ -393,7 +390,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -393,7 +390,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
charData.Value = GetText(start, currentLocation);
charData.EndOffset = currentLocation;
parsedDom.Add(charData);
parsedItems.Add(charData);
return charData;
}
}

Loading…
Cancel
Save