From 62a6e2cd990f4e3811ad94b5ea67ce4248c716ff Mon Sep 17 00:00:00 2001 From: mkonicek Date: Wed, 22 Dec 2010 23:37:55 +0100 Subject: [PATCH] Context actions optimization - removed one unnecessary call to EditorContext ctor. --- .../Src/CaretReferencesRenderer.cs | 34 ++++++++++++------- .../ContextActions/ContextActionsService.cs | 11 +++--- .../ContextActions/EditorContext.cs | 2 +- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs index 72bb3ac568..3f1ad478d8 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CaretReferencesRenderer.cs @@ -22,15 +22,22 @@ namespace ICSharpCode.AvalonEdit.AddIn public class CaretReferencesRenderer { /// - /// Delays the highlighting after the caret position changes, so that Find references does not get called too often. + /// Delays the Resolve check so that it does not get called too often when user holds an arrow. + /// + DispatcherTimer delayMoveTimer; + const int delayMoveMs = 100; + + /// + /// Delays the Find references (and highlight) after the caret stays at one point for a while. /// DispatcherTimer delayTimer; - const int delayMilliseconds = 800; + const int delayMs = 800; + /// - /// Delays the Resolve check so that it does not get called too often when user holds an arrow. + /// Maximum time for Find references. After this time it gets cancelled and no highlight is displayed. + /// Useful for very large files. /// - DispatcherTimer delayMoveTimer; - const int delayMoveMilliseconds = 100; + const int findReferencesTimeoutMs = 200; CodeEditorView editorView; ITextEditor Editor { get { return editorView.Adapter; } } @@ -53,10 +60,10 @@ namespace ICSharpCode.AvalonEdit.AddIn { this.editorView = editorView; this.highlightRenderer = new ExpressionHighlightRenderer(this.editorView.TextArea.TextView); - this.delayTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMilliseconds) }; + this.delayTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMs) }; this.delayTimer.Stop(); this.delayTimer.Tick += TimerTick; - this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) }; + this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMs) }; this.delayMoveTimer.Stop(); this.delayMoveTimer.Tick += TimerMoveTick; this.editorView.TextArea.Caret.PositionChanged += CaretPositionChanged; @@ -73,7 +80,7 @@ namespace ICSharpCode.AvalonEdit.AddIn if (!IsEnabled) return; - var referencesToBeHighlighted = GetReferencesInCurrentFile(this.lastResolveResult); + var referencesToBeHighlighted = FindReferencesInCurrentFile(this.lastResolveResult); this.highlightRenderer.SetHighlight(referencesToBeHighlighted); } @@ -85,7 +92,7 @@ namespace ICSharpCode.AvalonEdit.AddIn if (!IsEnabled) return; - var resolveResult = GetExpressionUnderCaret(); + var resolveResult = GetExpressionAtCaret(); if (resolveResult == null) { this.lastResolveResult = resolveResult; this.highlightRenderer.ClearHighlight(); @@ -115,7 +122,7 @@ namespace ICSharpCode.AvalonEdit.AddIn /// Resolves the current expression under caret. /// This gets called on every caret position change, so quite often. /// - ResolveResult GetExpressionUnderCaret() + ResolveResult GetExpressionAtCaret() { if (string.IsNullOrEmpty(Editor.FileName) || ParserService.LoadSolutionProjectsThreadRunning) return null; @@ -127,14 +134,14 @@ namespace ICSharpCode.AvalonEdit.AddIn /// /// Finds references to resolved expression in the current file. /// - List GetReferencesInCurrentFile(ResolveResult resolveResult) + List FindReferencesInCurrentFile(ResolveResult resolveResult) { var cancellationTokenSource = new CancellationTokenSource(); using (new Timer( delegate { - LoggingService.Debug("Aborting GetReferencesInCurrentFile due to timeout"); + LoggingService.Debug("Aborting FindReferencesInCurrentFile due to timeout"); cancellationTokenSource.Cancel(); - }, null, 200, Timeout.Infinite)) + }, null, findReferencesTimeoutMs, Timeout.Infinite)) { var progressMonitor = new DummyProgressMonitor(); progressMonitor.CancellationToken = cancellationTokenSource.Token; @@ -147,6 +154,7 @@ namespace ICSharpCode.AvalonEdit.AddIn /// /// Returns true if the 2 ResolveResults refer to the same symbol. + /// So that when caret moves but stays inside the same symbol, symbol stays highlighted. /// bool SameResolveResult(ResolveResult resolveResult, ResolveResult resolveResult2) { diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs index 9a4506d666..816ac8831f 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsService.cs @@ -59,7 +59,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring { ITextEditor editor { get; set; } IList providers { get; set; } - EditorContext context { get; set; } public EditorActionsProvider(ITextEditor editor, IList providers) { @@ -70,7 +69,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring this.editor = editor; this.providers = providers; ParserService.ParseCurrentViewContent(); - this.context = new EditorContext(editor); } public IEnumerable GetVisibleActions() @@ -104,11 +102,16 @@ namespace ICSharpCode.SharpDevelop.Refactoring { if (ParserService.LoadSolutionProjectsThreadRunning) yield break; + // Not necessary to reparse here because the ContextActionsRenderer timeout + // is large enough for the standard parser to finish first - not completely reliable, but saves one full reparse. + // In case the standard parser does not finish in time, the DOM is a little outdated but nothing bad happens + // (context action can just display an old class/method). + // DO NOT USE Wait on the main thread! // causes deadlocks! - //parseTask.Wait(); + // parseTask.Wait(); - var sw = new Stopwatch(); sw.Start(); + // var sw = new Stopwatch(); sw.Start(); var editorContext = new EditorContext(this.editor); long elapsedEditorContextMs = sw.ElapsedMilliseconds; diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs index 32e37b15ba..693791e5d2 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs @@ -200,7 +200,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring ExpressionResult GetExpressionAtCaret(ITextEditor editor) { ExpressionResult expr = ParserService.FindFullExpression(CaretLine, CaretColumn, editor.Document, editor.FileName); - // if no expression, look one character back (works better with method calls - Foo()(*caret*)) + // if no expression, look one character back (works better with method calls, e.g. Foo()(*caret*)) if (string.IsNullOrWhiteSpace(expr.Expression) && CaretColumn > 1) expr = ParserService.FindFullExpression(CaretLine, CaretColumn - 1, editor.Document, editor.FileName); return expr;