Browse Source

XML Parser: ParseAndLock method in the XamlParser

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4719 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
0b8bf974ef
  1. 11
      samples/XmlDOM/Window1.xaml.cs
  2. 41
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs
  3. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/ParserTests.cs
  4. 44
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlParser.cs

11
samples/XmlDOM/Window1.xaml.cs

@ -37,6 +37,7 @@ namespace XmlDOM
} }
TextMarkerService markerService; TextMarkerService markerService;
List<DocumentChangeEventArgs> changes = new List<DocumentChangeEventArgs>();
protected override void OnInitialized(EventArgs e) protected override void OnInitialized(EventArgs e)
{ {
@ -44,8 +45,11 @@ namespace XmlDOM
editor.TextArea.TextView.MouseMove += new MouseEventHandler(editor_TextArea_TextView_MouseMove); editor.TextArea.TextView.MouseMove += new MouseEventHandler(editor_TextArea_TextView_MouseMove);
editor.Document.Changed += delegate { textDirty = true; }; editor.Document.Changed += delegate(object sender, DocumentChangeEventArgs e2) {
parser = new AXmlParser(editor.Document); textDirty = true;
changes.Add(e2);
};
parser = new AXmlParser();
DispatcherTimer timer = new DispatcherTimer(); DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(0.5); timer.Interval = TimeSpan.FromSeconds(0.5);
@ -75,7 +79,8 @@ namespace XmlDOM
AXmlDocument doc; AXmlDocument doc;
parser.Lock.EnterWriteLock(); parser.Lock.EnterWriteLock();
try { try {
doc = parser.Parse(); doc = parser.Parse(editor.Document.Text, changes);
changes.Clear();
} finally { } finally {
parser.Lock.ExitWriteLock(); parser.Lock.ExitWriteLock();
} }

41
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs

@ -5,13 +5,16 @@
// <version>$Revision: 2568 $</version> // <version>$Revision: 2568 $</version>
// </file> // </file>
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.AvalonEdit.Document;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Xml; using System.Xml;
using ICSharpCode.AvalonEdit.Xml;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Project;
namespace ICSharpCode.XamlBinding namespace ICSharpCode.XamlBinding
{ {
@ -46,6 +49,42 @@ namespace ICSharpCode.XamlBinding
{ {
return false; return false;
} }
AXmlParser axmlParser;
ICSharpCode.SharpDevelop.ITextBuffer lastParsedContent;
/// <summary>
/// Parse the given text and enter read lock.
/// No parsing is done if the text is older than seen before.
/// </summary>
public IDisposable ParseAndLock(ICSharpCode.SharpDevelop.ITextBuffer fileContent)
{
// Is fileContent newer?
if (lastParsedContent == null || fileContent.Version.CompareAge(lastParsedContent.Version) > 0) {
axmlParser.Lock.EnterWriteLock();
// Dobuble check, now that we are thread-safe
if (lastParsedContent == null) {
// First parse
axmlParser = new AXmlParser();
axmlParser.Parse(fileContent.Text, null);
lastParsedContent = fileContent;
} else if (fileContent.Version.CompareAge(lastParsedContent.Version) > 0) {
// Incremental parse
var changes = lastParsedContent.Version.GetChangesTo(fileContent.Version).
Select(c => new DocumentChangeEventArgs(c.Offset, c.RemovedText, c.InsertedText));
axmlParser.Parse(fileContent.Text, changes);
lastParsedContent = fileContent;
} else {
// fileContent is older - no need to parse
}
axmlParser.Lock.EnterReadLock();
axmlParser.Lock.ExitWriteLock();
} else {
// fileContent is older - no need to parse
axmlParser.Lock.EnterReadLock();
}
return new CallbackOnDispose(() => axmlParser.Lock.ExitReadLock());
}
public ICompilationUnit Parse(IProjectContent projectContent, string fileName, ICSharpCode.SharpDevelop.ITextBuffer fileContent) public ICompilationUnit Parse(IProjectContent projectContent, string fileName, ICSharpCode.SharpDevelop.ITextBuffer fileContent)
{ {

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/ParserTests.cs

@ -154,7 +154,7 @@ namespace ICSharpCode.AvalonEdit.Xml.Tests
string content = testFile.Content; string content = testFile.Content;
Debug.WriteLine("Testing " + testFile.Name + "..."); Debug.WriteLine("Testing " + testFile.Name + "...");
AXmlParser parser = new AXmlParser(content); AXmlParser parser = new AXmlParser();
bool usingDTD = content.Contains("<!DOCTYPE") && (content.Contains("<!ENTITY") || content.Contains(" SYSTEM ")); bool usingDTD = content.Contains("<!DOCTYPE") && (content.Contains("<!ENTITY") || content.Contains(" SYSTEM "));
if (usingDTD) if (usingDTD)
@ -164,7 +164,7 @@ namespace ICSharpCode.AvalonEdit.Xml.Tests
parser.Lock.EnterWriteLock(); parser.Lock.EnterWriteLock();
try { try {
document = parser.Parse(); document = parser.Parse(content, null);
} finally { } finally {
parser.Lock.ExitWriteLock(); parser.Lock.ExitWriteLock();
} }

44
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlParser.cs

@ -88,13 +88,9 @@ namespace ICSharpCode.AvalonEdit.Xml
/// </remarks> /// </remarks>
public class AXmlParser public class AXmlParser
{ {
string input;
AXmlDocument userDocument; AXmlDocument userDocument;
TextDocument textDocument;
internal TrackedSegmentCollection TrackedSegments { get; private set; } internal TrackedSegmentCollection TrackedSegments { get; private set; }
ChangeTrackingCheckpoint lastCheckpoint;
ReaderWriterLockSlim lockObject;
/// <summary> /// <summary>
/// Generate syntax error when seeing enity reference other then the build-in ones /// Generate syntax error when seeing enity reference other then the build-in ones
@ -102,12 +98,11 @@ namespace ICSharpCode.AvalonEdit.Xml
public bool UknonwEntityReferenceIsError { get; set; } public bool UknonwEntityReferenceIsError { get; set; }
/// <summary> Create new parser </summary> /// <summary> Create new parser </summary>
public AXmlParser(string input) public AXmlParser()
{ {
this.input = input;
this.UknonwEntityReferenceIsError = true; this.UknonwEntityReferenceIsError = true;
this.TrackedSegments = new TrackedSegmentCollection(); this.TrackedSegments = new TrackedSegmentCollection();
this.lockObject = new ReaderWriterLockSlim(); this.Lock = new ReaderWriterLockSlim();
this.userDocument = new AXmlDocument() { Parser = this }; this.userDocument = new AXmlDocument() { Parser = this };
this.userDocument.Document = this.userDocument; this.userDocument.Document = this.userDocument;
@ -116,15 +111,6 @@ namespace ICSharpCode.AvalonEdit.Xml
this.userDocument.IsCached = false; this.userDocument.IsCached = false;
} }
/// <summary>
/// Create new parser, but do not parse the text yet.
/// </summary>
public AXmlParser(TextDocument textDocument)
: this(textDocument.Text)
{
this.textDocument = textDocument;
}
/// <summary> Throws exception if condition is false </summary> /// <summary> Throws exception if condition is false </summary>
internal static void Assert(bool condition, string message) internal static void Assert(bool condition, string message)
{ {
@ -147,23 +133,19 @@ namespace ICSharpCode.AvalonEdit.Xml
System.Diagnostics.Debug.WriteLine(string.Format("XML: " + text, pars)); System.Diagnostics.Debug.WriteLine(string.Format("XML: " + text, pars));
} }
public AXmlDocument Parse() /// <summary>
/// Incrementaly parse the given text.
/// You have to hold the write lock.
/// 'changesSinceLastParse' can be null on the first call.
/// </summary>
public AXmlDocument Parse(string input, IEnumerable<DocumentChangeEventArgs> changesSinceLastParse)
{ {
if (!Lock.IsWriteLockHeld) if (!Lock.IsWriteLockHeld)
throw new InvalidOperationException("Lock needed!"); throw new InvalidOperationException("Lock needed!");
if (textDocument != null) { // incremental parse // Use changes to invalidate cache
ChangeTrackingCheckpoint checkpoint; if (changesSinceLastParse != null) {
input = textDocument.CreateSnapshot(out checkpoint).Text; this.TrackedSegments.UpdateOffsetsAndInvalidate(changesSinceLastParse);
// Use changes to invalidate cache
if (lastCheckpoint != null) {
var changes = lastCheckpoint.GetChangesTo(checkpoint);
if (!changes.Any())
return userDocument;
this.TrackedSegments.UpdateOffsetsAndInvalidate(changes);
}
lastCheckpoint = checkpoint;
} }
TagReader tagReader = new TagReader(this, input); TagReader tagReader = new TagReader(this, input);
@ -180,8 +162,6 @@ namespace ICSharpCode.AvalonEdit.Xml
/// <summary> /// <summary>
/// Makes calls to Parse() thread-safe. Use Lock everywhere Parse() is called. /// Makes calls to Parse() thread-safe. Use Lock everywhere Parse() is called.
/// </summary> /// </summary>
public ReaderWriterLockSlim Lock { public ReaderWriterLockSlim Lock { get; private set; }
get { return this.lockObject; }
}
} }
} }

Loading…
Cancel
Save