Browse Source

BooAdvancedHighlighter: only resolve references that in the visible part of the document

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1394 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
704ea9be70
  1. 45
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs
  2. 11
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs
  3. 2
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/IHighlightingStrategy.cs
  4. 3
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  5. 205
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlighter.cs
  6. 54
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlightingStrategy.cs
  7. 101
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs
  8. 2
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs

45
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs

@ -18,24 +18,21 @@ using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; @@ -18,24 +18,21 @@ using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
namespace Grunwald.BooBinding.CodeCompletion
{
public class BooAdvancedHighlighter : IAdvancedHighlighter
public class BooAdvancedHighlighter : AsynchronousAdvancedHighlighter
{
public event EventHandler MarkOutstandingRequests;
TextEditorControl textEditor;
volatile Dictionary<int, List<int>> declarations;
public void Initialize(TextEditorControl textEditor)
public override void Initialize(TextEditorControl textEditor)
{
LoggingService.Debug("AdvancedHighlighter created");
this.textEditor = textEditor;
this.ImmediateMarkLimit = 0; // never immediately mark lines
base.Initialize(textEditor);
ParserService.ParserUpdateStepFinished += OnUpdateStep;
}
public void Dispose()
public override void Dispose()
{
LoggingService.Debug("AdvancedHighlighter destroyed");
ParserService.ParserUpdateStepFinished -= OnUpdateStep;
base.Dispose();
}
private class FindAssignmentsVisitor : DepthFirstVisitor
@ -74,10 +71,10 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -74,10 +71,10 @@ namespace Grunwald.BooBinding.CodeCompletion
void OnUpdateStep(object sender, ParserUpdateStepEventArgs e)
{
if (FileUtility.IsEqualFileName(e.FileName, textEditor.FileName)) {
if (FileUtility.IsEqualFileName(e.FileName, this.TextEditor.FileName)) {
ParseInformation parseInfo = e.ParseInformation;
if (parseInfo == null && this.declarations == null)
parseInfo = ParserService.GetParseInformation(textEditor.FileName);
parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName);
if (parseInfo != null) {
ICompilationUnit cu = parseInfo.MostRecentCompilationUnit;
CompileUnit booCu = cu.Tag as CompileUnit;
@ -87,38 +84,36 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -87,38 +84,36 @@ namespace Grunwald.BooBinding.CodeCompletion
this.declarations = visitor.declarations; // volatile access!
}
}
WorkbenchSingleton.SafeThreadAsyncCall(this, "RaiseMarkOutstandingRequests", e);
WorkbenchSingleton.SafeThreadAsyncCall((System.Threading.ThreadStart)MarkOutstanding);
}
}
bool markingOutstanding;
int resolveCount;
void RaiseMarkOutstandingRequests(EventArgs e)
protected override void MarkOutstanding()
{
#if DEBUG
int time = Environment.TickCount;
#endif
markingOutstanding = true;
resolveCount = 0;
if (MarkOutstandingRequests != null) {
MarkOutstandingRequests(this, e);
}
base.MarkOutstanding();
markingOutstanding = false;
#if DEBUG
if (resolveCount > 0) {
LoggingService.Debug("AdvancedHighlighter took " + (Environment.TickCount - time) + " ms for " + resolveCount + " resolves");
time = Environment.TickCount - time;
if (time > 0) {
LoggingService.Info("BooHighlighter took " + time + "ms for " + resolveCount + " resolves");
}
#endif
textEditor.Document.CommitUpdate();
this.Document.CommitUpdate();
}
public void MarkLine(IDocument document, LineSegment currentLine, List<TextWord> words)
protected override void MarkWords(int lineNumber, LineSegment currentLine, List<TextWord> words)
{
Dictionary<int, List<int>> decl = this.declarations; // volatile access!
if (decl == null) return;
int currentLineOffset = currentLine.Offset;
int lineNumber = document.GetLineNumberForOffset(currentLineOffset);
List<int> list;
bool changedLine = false;
if (decl.TryGetValue(lineNumber, out list)) {
@ -130,15 +125,15 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -130,15 +125,15 @@ namespace Grunwald.BooBinding.CodeCompletion
resolveCount++;
rr = ParserService.Resolve(new ExpressionResult(word.Word),
lineNumber + 1, word.Offset + 1,
textEditor.FileName,
textEditor.Document.TextContent
this.TextEditor.FileName,
this.Document.TextContent
) as LocalResolveResult;
if (rr != null
&& rr.Field.Region.BeginLine == lineNumber + 1
&& rr.Field.Region.BeginColumn == word.Offset + 1)
{
changedLine = true;
word.SyntaxColor = textEditor.Document.HighlightingStrategy.GetColorFor("LocalVariableCreation");
word.SyntaxColor = this.Document.HighlightingStrategy.GetColorFor("LocalVariableCreation");
} else {
list.RemoveAt(i--);
}
@ -148,7 +143,7 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -148,7 +143,7 @@ namespace Grunwald.BooBinding.CodeCompletion
}
}
if (markingOutstanding && changedLine) {
textEditor.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber));
this.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber));
}
}
}

11
src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs

@ -47,6 +47,8 @@ namespace ICSharpCode.TextEditor.Document @@ -47,6 +47,8 @@ namespace ICSharpCode.TextEditor.Document
protected void ImportSettingsFrom(DefaultHighlightingStrategy source)
{
if (source == null)
throw new ArgumentNullException("source");
properties = source.properties;
extensions = source.extensions;
digitColor = source.digitColor;
@ -215,10 +217,11 @@ namespace ICSharpCode.TextEditor.Document @@ -215,10 +217,11 @@ namespace ICSharpCode.TextEditor.Document
public HighlightColor GetColorFor(string name)
{
if (! environmentColors.ContainsKey(name)) {
throw new Exception("Color : " + name + " not found!");
}
return (HighlightColor)environmentColors[name];
HighlightColor color;
if (environmentColors.TryGetValue(name, out color))
return color;
else
return defaultTextColor;
}
public HighlightColor GetColor(IDocument document, LineSegment currentSegment, int currentOffset, int currentLength)

2
src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/IHighlightingStrategy.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.TextEditor.Document @@ -41,7 +41,7 @@ namespace ICSharpCode.TextEditor.Document
// returns special color. (BackGround Color, Cursor Color and so on)
/// <remarks>
/// Used internally, do not call
/// Gets the color of an Environment element.
/// </remarks>
HighlightColor GetColorFor(string name);

3
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -769,7 +769,8 @@ @@ -769,7 +769,8 @@
<Compile Include="Src\Services\RefactoringService\NRefactoryRefactoringProvider.cs" />
<Compile Include="Src\Services\RefactoringService\NamespaceRefactoringService.cs" />
<Compile Include="Src\Services\RefactoringService\RefactorMenu.cs" />
<Compile Include="Src\TextEditor\Gui\Editor\ParserHighlightingStrategy.cs" />
<Compile Include="Src\TextEditor\Gui\Editor\AdvancedHighlightingStrategy.cs" />
<Compile Include="Src\TextEditor\Gui\Editor\AdvancedHighlighter.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Libraries\DockPanel_Src\WinFormsUI\WinFormsUI.csproj">

205
src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlighter.cs

@ -0,0 +1,205 @@ @@ -0,0 +1,205 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{
/// <summary>
/// Interface for advanced syntax highlighters.
/// </summary>
public interface IAdvancedHighlighter : IDisposable
{
/// <summary>
/// Is called once after creating the highlighter. Gives your highlighter a chance
/// to register events on the text editor.
/// </summary>
void Initialize(TextEditorControl textEditor);
void BeginUpdate(IDocument document, IList<LineSegment> inputLines);
void EndUpdate();
/// <summary>
/// Gives your highlighter the chance to change the highlighting of the words.
/// </summary>
void MarkLine(int lineNumber, LineSegment currentLine, List<TextWord> words);
}
/// <summary>
/// Advanced syntax highlighter that stores a list of changed lines and can mark them
/// later by calling <see cref="MarkOutstanding"/>.
/// </summary>
public abstract class AsynchronousAdvancedHighlighter : IAdvancedHighlighter
{
protected abstract void MarkWords(int lineNumber, LineSegment currentLine, List<TextWord> words);
readonly object lockObject = new object();
Dictionary<LineSegment, List<TextWord>> outstanding = new Dictionary<LineSegment, List<TextWord>>();
TextEditorControl textEditor;
IDocument document;
#region Settings
public TextEditorControl TextEditor {
get {
return textEditor;
}
}
public IDocument Document {
get {
return document;
}
}
int immediateMarkLimit = 3;
/// <summary>
/// Maximum number of changed lines to immediately mark the changes.
/// </summary>
protected int ImmediateMarkLimit {
get {
return immediateMarkLimit;
}
set {
if (value < 0) throw new ArgumentOutOfRangeException("value", value, "value must be >= 0");
immediateMarkLimit = value;
}
}
bool markVisibleOnly = true;
/// <summary>
/// Gets/Sets whether to only mark lines in the visible region of the text area.
/// </summary>
protected bool MarkVisibleOnly {
get {
return markVisibleOnly;
}
set {
if (markVisibleOnly != value) {
if (textEditor != null)
throw new InvalidOperationException("Cannot change value after initialization");
markVisibleOnly = value;
}
}
}
int markVisibleAdditional = 5;
/// <summary>
/// Number of additional lines around the visible region that should be marked.
/// </summary>
public int MarkVisibleAdditional {
get {
return markVisibleAdditional;
}
set {
if (value < 0) throw new ArgumentOutOfRangeException("value", value, "value must be >= 0");
markVisibleAdditional = value;
}
}
#endregion
public virtual void Initialize(TextEditorControl textEditor)
{
if (textEditor == null)
throw new ArgumentNullException("textEditor");
if (this.textEditor != null)
throw new InvalidOperationException("Already initialized");
this.textEditor = textEditor;
this.document = textEditor.Document;
}
public virtual void Dispose()
{
textEditor = null;
document = null;
}
int directMark;
public virtual void BeginUpdate(IDocument document, IList<LineSegment> inputLines)
{
if (this.document == null)
throw new InvalidOperationException("Not initialized");
if (document != this.document)
throw new InvalidOperationException("document != this.document");
if (inputLines == null) {
lock (lockObject) {
outstanding.Clear();
}
} else {
directMark = inputLines.Count > immediateMarkLimit ? 0 : inputLines.Count;
}
}
public virtual void EndUpdate()
{
}
void IAdvancedHighlighter.MarkLine(int lineNumber, LineSegment currentLine, List<TextWord> words)
{
if (directMark > 0) {
directMark--;
MarkWords(lineNumber, currentLine, words);
} else {
lock (lockObject) {
outstanding[currentLine] = words;
}
}
}
protected virtual void MarkOutstanding()
{
if (WorkbenchSingleton.InvokeRequired) {
// TODO: allow calling MarkOutstanding in separate threads
throw new InvalidOperationException("Invoke required");
}
IEnumerable<KeyValuePair<LineSegment, List<TextWord>>> oldOutstanding;
lock (lockObject) {
oldOutstanding = outstanding;
outstanding = new Dictionary<LineSegment, List<TextWord>>();
}
// We cannot call MarkLine inside lock(lockObject) because then the main
// thread could deadlock with the highlighter thread.
foreach (KeyValuePair<LineSegment, List<TextWord>> pair in oldOutstanding) {
int offset = pair.Key.Offset;
if (offset < 0 || offset >= document.TextLength)
continue;
int lineNumber = document.GetLineNumberForOffset(offset);
if (markVisibleOnly && IsVisible(lineNumber) == false) {
lock (lockObject) {
outstanding[pair.Key] = pair.Value;
}
} else {
MarkWords(lineNumber, pair.Key, pair.Value);
}
}
}
bool IsVisible(int lineNumber)
{
TextView textView = textEditor.ActiveTextAreaControl.TextArea.TextView;
int firstLine = textView.FirstVisibleLine;
if (lineNumber < firstLine - markVisibleAdditional) {
return false;
}
int lastLine = document.GetFirstLogicalLine(textView.FirstPhysicalLine + textView.VisibleLineCount);
if (lineNumber > lastLine + markVisibleAdditional) {
return false;
}
// line is visible if it is not folded away
return document.GetVisibleLine(lineNumber) != document.GetVisibleLine(lineNumber - 1);
}
}
}

54
src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlightingStrategy.cs

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{
/// <summary>
/// Modifies the TextEditor's IHighlightingStrategy to be able to plug in
/// an <see cref="IAdvancedHighlighter"/>.
/// </summary>
internal class AdvancedHighlightingStrategy : DefaultHighlightingStrategy
{
readonly IAdvancedHighlighter highlighter;
public AdvancedHighlightingStrategy(DefaultHighlightingStrategy baseStrategy, IAdvancedHighlighter highlighter)
{
if (highlighter == null)
throw new ArgumentNullException("highlighter");
ImportSettingsFrom(baseStrategy);
this.highlighter = highlighter;
}
public override void MarkTokens(IDocument document)
{
highlighter.BeginUpdate(document, null);
base.MarkTokens(document);
highlighter.EndUpdate();
}
public override void MarkTokens(IDocument document, List<LineSegment> inputLines)
{
highlighter.BeginUpdate(document, inputLines);
base.MarkTokens(document, inputLines);
highlighter.EndUpdate();
}
protected override void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words)
{
highlighter.MarkLine(currentLineNumber, currentLine, words);
}
}
}

101
src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs

@ -1,101 +0,0 @@ @@ -1,101 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{
public interface IAdvancedHighlighter : IDisposable
{
/// <summary>
/// Is called once after creating the highlighter. Gives your highlighter a chance
/// to register events on the text editor.
/// </summary>
void Initialize(TextEditorControl textEditor);
/// <summary>
/// Gives your highlighter the chance to change the highlighting of the words.
/// </summary>
void MarkLine(IDocument document, LineSegment currentLine, List<TextWord> words);
/// <summary>
/// When your class fires this event, MarkLine will be called for all waiting lines.
/// You can fire this event on any thread, but MarkLine will be called on that thread
/// - so if you use multithreading, you must invoke when accessing the document inside
/// MarkLine.
/// </summary>
event EventHandler MarkOutstandingRequests;
}
internal class ParserHighlightingStrategy : DefaultHighlightingStrategy
{
readonly object lockObject = new object();
readonly IAdvancedHighlighter highlighter;
IDocument document;
Dictionary<LineSegment, List<TextWord>> outstanding = new Dictionary<LineSegment, List<TextWord>>();
public ParserHighlightingStrategy(DefaultHighlightingStrategy baseStrategy, IAdvancedHighlighter highlighter)
{
ImportSettingsFrom(baseStrategy);
this.highlighter = highlighter;
highlighter.MarkOutstandingRequests += OnMarkOutstandingRequest;
}
int directMark; // counter for immediate marking when only few lines have changed
public override void MarkTokens(IDocument document)
{
lock (lockObject) {
outstanding.Clear();
}
base.MarkTokens(document);
}
public override void MarkTokens(IDocument document, List<LineSegment> inputLines)
{
directMark = (inputLines.Count < 3) ? inputLines.Count : 0;
base.MarkTokens(document, inputLines);
directMark = 0;
}
protected override void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words)
{
int ln = currentLineNumber;
if (directMark > 0) {
directMark--;
highlighter.MarkLine(document, currentLine, words);
} else {
this.document = document;
lock (lockObject) {
outstanding[currentLine] = words;
}
}
}
void OnMarkOutstandingRequest(object sender, EventArgs e)
{
Dictionary<LineSegment, List<TextWord>> oldOutstanding;
lock (lockObject) {
oldOutstanding = outstanding;
outstanding = new Dictionary<LineSegment, List<TextWord>>();
}
// We cannot call MarkLine inside lock(lockObject) because then the main
// thread could deadlock with the highlighter thread.
foreach (KeyValuePair<LineSegment, List<TextWord>> pair in oldOutstanding) {
highlighter.MarkLine(document, pair.Key, pair.Value);
}
}
}
}

2
src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs

@ -406,8 +406,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -406,8 +406,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
IList<IAdvancedHighlighter> highlighter = AddInTree.BuildItems<IAdvancedHighlighter>(highlighterPath, this);
if (highlighter != null && highlighter.Count > 0) {
advancedHighlighter = highlighter[0];
Document.HighlightingStrategy = new ParserHighlightingStrategy((DefaultHighlightingStrategy)Document.HighlightingStrategy, advancedHighlighter);
advancedHighlighter.Initialize(this);
Document.HighlightingStrategy = new AdvancedHighlightingStrategy((DefaultHighlightingStrategy)Document.HighlightingStrategy, advancedHighlighter);
}
}
}

Loading…
Cancel
Save