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;
namespace Grunwald.BooBinding.CodeCompletion namespace Grunwald.BooBinding.CodeCompletion
{ {
public class BooAdvancedHighlighter : IAdvancedHighlighter public class BooAdvancedHighlighter : AsynchronousAdvancedHighlighter
{ {
public event EventHandler MarkOutstandingRequests;
TextEditorControl textEditor;
volatile Dictionary<int, List<int>> declarations; volatile Dictionary<int, List<int>> declarations;
public void Initialize(TextEditorControl textEditor) public override void Initialize(TextEditorControl textEditor)
{ {
LoggingService.Debug("AdvancedHighlighter created"); this.ImmediateMarkLimit = 0; // never immediately mark lines
this.textEditor = textEditor; base.Initialize(textEditor);
ParserService.ParserUpdateStepFinished += OnUpdateStep; ParserService.ParserUpdateStepFinished += OnUpdateStep;
} }
public void Dispose() public override void Dispose()
{ {
LoggingService.Debug("AdvancedHighlighter destroyed");
ParserService.ParserUpdateStepFinished -= OnUpdateStep; ParserService.ParserUpdateStepFinished -= OnUpdateStep;
base.Dispose();
} }
private class FindAssignmentsVisitor : DepthFirstVisitor private class FindAssignmentsVisitor : DepthFirstVisitor
@ -74,10 +71,10 @@ namespace Grunwald.BooBinding.CodeCompletion
void OnUpdateStep(object sender, ParserUpdateStepEventArgs e) 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; ParseInformation parseInfo = e.ParseInformation;
if (parseInfo == null && this.declarations == null) if (parseInfo == null && this.declarations == null)
parseInfo = ParserService.GetParseInformation(textEditor.FileName); parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName);
if (parseInfo != null) { if (parseInfo != null) {
ICompilationUnit cu = parseInfo.MostRecentCompilationUnit; ICompilationUnit cu = parseInfo.MostRecentCompilationUnit;
CompileUnit booCu = cu.Tag as CompileUnit; CompileUnit booCu = cu.Tag as CompileUnit;
@ -87,38 +84,36 @@ namespace Grunwald.BooBinding.CodeCompletion
this.declarations = visitor.declarations; // volatile access! this.declarations = visitor.declarations; // volatile access!
} }
} }
WorkbenchSingleton.SafeThreadAsyncCall(this, "RaiseMarkOutstandingRequests", e); WorkbenchSingleton.SafeThreadAsyncCall((System.Threading.ThreadStart)MarkOutstanding);
} }
} }
bool markingOutstanding; bool markingOutstanding;
int resolveCount; int resolveCount;
void RaiseMarkOutstandingRequests(EventArgs e) protected override void MarkOutstanding()
{ {
#if DEBUG #if DEBUG
int time = Environment.TickCount; int time = Environment.TickCount;
#endif #endif
markingOutstanding = true; markingOutstanding = true;
resolveCount = 0; resolveCount = 0;
if (MarkOutstandingRequests != null) { base.MarkOutstanding();
MarkOutstandingRequests(this, e);
}
markingOutstanding = false; markingOutstanding = false;
#if DEBUG #if DEBUG
if (resolveCount > 0) { time = Environment.TickCount - time;
LoggingService.Debug("AdvancedHighlighter took " + (Environment.TickCount - time) + " ms for " + resolveCount + " resolves"); if (time > 0) {
LoggingService.Info("BooHighlighter took " + time + "ms for " + resolveCount + " resolves");
} }
#endif #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! Dictionary<int, List<int>> decl = this.declarations; // volatile access!
if (decl == null) return; if (decl == null) return;
int currentLineOffset = currentLine.Offset; int currentLineOffset = currentLine.Offset;
int lineNumber = document.GetLineNumberForOffset(currentLineOffset);
List<int> list; List<int> list;
bool changedLine = false; bool changedLine = false;
if (decl.TryGetValue(lineNumber, out list)) { if (decl.TryGetValue(lineNumber, out list)) {
@ -130,15 +125,15 @@ namespace Grunwald.BooBinding.CodeCompletion
resolveCount++; resolveCount++;
rr = ParserService.Resolve(new ExpressionResult(word.Word), rr = ParserService.Resolve(new ExpressionResult(word.Word),
lineNumber + 1, word.Offset + 1, lineNumber + 1, word.Offset + 1,
textEditor.FileName, this.TextEditor.FileName,
textEditor.Document.TextContent this.Document.TextContent
) as LocalResolveResult; ) as LocalResolveResult;
if (rr != null if (rr != null
&& rr.Field.Region.BeginLine == lineNumber + 1 && rr.Field.Region.BeginLine == lineNumber + 1
&& rr.Field.Region.BeginColumn == word.Offset + 1) && rr.Field.Region.BeginColumn == word.Offset + 1)
{ {
changedLine = true; changedLine = true;
word.SyntaxColor = textEditor.Document.HighlightingStrategy.GetColorFor("LocalVariableCreation"); word.SyntaxColor = this.Document.HighlightingStrategy.GetColorFor("LocalVariableCreation");
} else { } else {
list.RemoveAt(i--); list.RemoveAt(i--);
} }
@ -148,7 +143,7 @@ namespace Grunwald.BooBinding.CodeCompletion
} }
} }
if (markingOutstanding && changedLine) { 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
protected void ImportSettingsFrom(DefaultHighlightingStrategy source) protected void ImportSettingsFrom(DefaultHighlightingStrategy source)
{ {
if (source == null)
throw new ArgumentNullException("source");
properties = source.properties; properties = source.properties;
extensions = source.extensions; extensions = source.extensions;
digitColor = source.digitColor; digitColor = source.digitColor;
@ -215,10 +217,11 @@ namespace ICSharpCode.TextEditor.Document
public HighlightColor GetColorFor(string name) public HighlightColor GetColorFor(string name)
{ {
if (! environmentColors.ContainsKey(name)) { HighlightColor color;
throw new Exception("Color : " + name + " not found!"); if (environmentColors.TryGetValue(name, out color))
} return color;
return (HighlightColor)environmentColors[name]; else
return defaultTextColor;
} }
public HighlightColor GetColor(IDocument document, LineSegment currentSegment, int currentOffset, int currentLength) 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
// returns special color. (BackGround Color, Cursor Color and so on) // returns special color. (BackGround Color, Cursor Color and so on)
/// <remarks> /// <remarks>
/// Used internally, do not call /// Gets the color of an Environment element.
/// </remarks> /// </remarks>
HighlightColor GetColorFor(string name); HighlightColor GetColorFor(string name);

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

@ -769,7 +769,8 @@
<Compile Include="Src\Services\RefactoringService\NRefactoryRefactoringProvider.cs" /> <Compile Include="Src\Services\RefactoringService\NRefactoryRefactoringProvider.cs" />
<Compile Include="Src\Services\RefactoringService\NamespaceRefactoringService.cs" /> <Compile Include="Src\Services\RefactoringService\NamespaceRefactoringService.cs" />
<Compile Include="Src\Services\RefactoringService\RefactorMenu.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>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\Libraries\DockPanel_Src\WinFormsUI\WinFormsUI.csproj"> <ProjectReference Include="..\..\..\Libraries\DockPanel_Src\WinFormsUI\WinFormsUI.csproj">

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

@ -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 @@
// <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 @@
// <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
IList<IAdvancedHighlighter> highlighter = AddInTree.BuildItems<IAdvancedHighlighter>(highlighterPath, this); IList<IAdvancedHighlighter> highlighter = AddInTree.BuildItems<IAdvancedHighlighter>(highlighterPath, this);
if (highlighter != null && highlighter.Count > 0) { if (highlighter != null && highlighter.Count > 0) {
advancedHighlighter = highlighter[0]; advancedHighlighter = highlighter[0];
Document.HighlightingStrategy = new ParserHighlightingStrategy((DefaultHighlightingStrategy)Document.HighlightingStrategy, advancedHighlighter);
advancedHighlighter.Initialize(this); advancedHighlighter.Initialize(this);
Document.HighlightingStrategy = new AdvancedHighlightingStrategy((DefaultHighlightingStrategy)Document.HighlightingStrategy, advancedHighlighter);
} }
} }
} }

Loading…
Cancel
Save