From 704ea9be702d326b09c4f5b06b085fa5aa01d62e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 7 May 2006 13:23:19 +0000 Subject: [PATCH] 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 --- .../CodeCompletion/BooAdvancedHighlighter.cs | 45 ++-- .../DefaultHighlightingStrategy.cs | 11 +- .../IHighlightingStrategy.cs | 2 +- .../Project/ICSharpCode.SharpDevelop.csproj | 3 +- .../Gui/Editor/AdvancedHighlighter.cs | 205 ++++++++++++++++++ .../Editor/AdvancedHighlightingStrategy.cs | 54 +++++ .../Gui/Editor/ParserHighlightingStrategy.cs | 101 --------- .../Gui/Editor/SharpDevelopTextAreaControl.cs | 2 +- 8 files changed, 290 insertions(+), 133 deletions(-) create mode 100644 src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlighter.cs create mode 100644 src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlightingStrategy.cs delete mode 100644 src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs index 386bda55cf..4561fe5ede 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs @@ -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> 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 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 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 words) + protected override void MarkWords(int lineNumber, LineSegment currentLine, List words) { Dictionary> decl = this.declarations; // volatile access! if (decl == null) return; int currentLineOffset = currentLine.Offset; - int lineNumber = document.GetLineNumberForOffset(currentLineOffset); List list; bool changedLine = false; if (decl.TryGetValue(lineNumber, out list)) { @@ -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 } } if (markingOutstanding && changedLine) { - textEditor.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber)); + this.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber)); } } } diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs index 9481c71d3f..b1050e3c58 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs @@ -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 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) diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/IHighlightingStrategy.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/IHighlightingStrategy.cs index 85f3ada610..e22b423a65 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/IHighlightingStrategy.cs +++ b/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) /// - /// Used internally, do not call + /// Gets the color of an Environment element. /// HighlightColor GetColorFor(string name); diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 03231ee6f9..8b3a8ce0ce 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -769,7 +769,8 @@ - + + diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlighter.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlighter.cs new file mode 100644 index 0000000000..ef279f6be3 --- /dev/null +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlighter.cs @@ -0,0 +1,205 @@ +// +// +// +// +// $Revision$ +// + +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 +{ + /// + /// Interface for advanced syntax highlighters. + /// + public interface IAdvancedHighlighter : IDisposable + { + /// + /// Is called once after creating the highlighter. Gives your highlighter a chance + /// to register events on the text editor. + /// + void Initialize(TextEditorControl textEditor); + + void BeginUpdate(IDocument document, IList inputLines); + void EndUpdate(); + + /// + /// Gives your highlighter the chance to change the highlighting of the words. + /// + void MarkLine(int lineNumber, LineSegment currentLine, List words); + } + + /// + /// Advanced syntax highlighter that stores a list of changed lines and can mark them + /// later by calling . + /// + public abstract class AsynchronousAdvancedHighlighter : IAdvancedHighlighter + { + protected abstract void MarkWords(int lineNumber, LineSegment currentLine, List words); + + readonly object lockObject = new object(); + Dictionary> outstanding = new Dictionary>(); + TextEditorControl textEditor; + IDocument document; + + #region Settings + public TextEditorControl TextEditor { + get { + return textEditor; + } + } + + public IDocument Document { + get { + return document; + } + } + + int immediateMarkLimit = 3; + + /// + /// Maximum number of changed lines to immediately mark the changes. + /// + protected int ImmediateMarkLimit { + get { + return immediateMarkLimit; + } + set { + if (value < 0) throw new ArgumentOutOfRangeException("value", value, "value must be >= 0"); + immediateMarkLimit = value; + } + } + + bool markVisibleOnly = true; + /// + /// Gets/Sets whether to only mark lines in the visible region of the text area. + /// + 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; + /// + /// Number of additional lines around the visible region that should be marked. + /// + 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 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 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>> oldOutstanding; + lock (lockObject) { + oldOutstanding = outstanding; + outstanding = new Dictionary>(); + } + // We cannot call MarkLine inside lock(lockObject) because then the main + // thread could deadlock with the highlighter thread. + foreach (KeyValuePair> 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); + } + } +} diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlightingStrategy.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlightingStrategy.cs new file mode 100644 index 0000000000..211ea877ec --- /dev/null +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/AdvancedHighlightingStrategy.cs @@ -0,0 +1,54 @@ +// +// +// +// +// $Revision$ +// + +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 +{ + /// + /// Modifies the TextEditor's IHighlightingStrategy to be able to plug in + /// an . + /// + 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 inputLines) + { + highlighter.BeginUpdate(document, inputLines); + base.MarkTokens(document, inputLines); + highlighter.EndUpdate(); + } + + protected override void OnParsedLine(IDocument document, LineSegment currentLine, List words) + { + highlighter.MarkLine(currentLineNumber, currentLine, words); + } + } +} diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs deleted file mode 100644 index 7005e50460..0000000000 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs +++ /dev/null @@ -1,101 +0,0 @@ -// -// -// -// -// $Revision$ -// - -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 - { - /// - /// Is called once after creating the highlighter. Gives your highlighter a chance - /// to register events on the text editor. - /// - void Initialize(TextEditorControl textEditor); - - /// - /// Gives your highlighter the chance to change the highlighting of the words. - /// - void MarkLine(IDocument document, LineSegment currentLine, List words); - - /// - /// 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. - /// - event EventHandler MarkOutstandingRequests; - } - - internal class ParserHighlightingStrategy : DefaultHighlightingStrategy - { - readonly object lockObject = new object(); - readonly IAdvancedHighlighter highlighter; - IDocument document; - Dictionary> outstanding = new Dictionary>(); - - 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 inputLines) - { - directMark = (inputLines.Count < 3) ? inputLines.Count : 0; - base.MarkTokens(document, inputLines); - directMark = 0; - } - - protected override void OnParsedLine(IDocument document, LineSegment currentLine, List 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> oldOutstanding; - lock (lockObject) { - oldOutstanding = outstanding; - outstanding = new Dictionary>(); - } - // We cannot call MarkLine inside lock(lockObject) because then the main - // thread could deadlock with the highlighter thread. - foreach (KeyValuePair> pair in oldOutstanding) { - highlighter.MarkLine(document, pair.Key, pair.Value); - } - } - } -} diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs index c99f90fe4a..e266f0b56d 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs @@ -406,8 +406,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor IList highlighter = AddInTree.BuildItems(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); } } }