Browse Source
Please provide feedback (usefulness, performance, highlight color, ...) It should have no effect on editor performance - when moving caret by holding an arrow in the editor, nothing gets executed. After the caret stops for 100ms at one place, expression under caret is resolved to e.g. hide current highlight if no expression is under caret. Then, if the caret stays in place for 1000ms, "Find references in current document" is executed (on the main thread, but it's quite fast, maybe could be moved to background thread). The timeouts are done using two DispatcherTimers. Added "Find references in given document" (RefactoringService.FindReferencesLocal) to RefactoringService. Refactored RefactoringService a bit, but public API and its behavior stays unchanged. Fixed comment of DebuggerService.HandleToolTipRequest. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5725 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61pull/1/head
11 changed files with 302 additions and 51 deletions
@ -0,0 +1,123 @@
@@ -0,0 +1,123 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Martin Konicek" email="martin.konicek@gmail.com"/>
|
||||
// <version>$Revision: $</version>
|
||||
// </file>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Windows.Threading; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Refactoring; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// Description of CaretReferencesRenderer.
|
||||
/// </summary>
|
||||
public class CaretReferencesRenderer |
||||
{ |
||||
/// <summary>
|
||||
/// Delays the highlighting after the caret position changes, so that Find references does not get called too often.
|
||||
/// </summary>
|
||||
DispatcherTimer delayTimer; |
||||
const int delayMilliseconds = 1000; |
||||
DispatcherTimer delayMoveTimer; |
||||
const int delayMoveMilliseconds = 100; |
||||
|
||||
CodeEditorView editorView; |
||||
ITextEditor Editor { get { return editorView.Adapter; } } |
||||
|
||||
ExpressionHighlightRenderer highlightRenderer; |
||||
ResolveResult lastResolveResult; |
||||
|
||||
public CaretReferencesRenderer(CodeEditorView editorView) |
||||
{ |
||||
this.editorView = editorView; |
||||
this.highlightRenderer = new ExpressionHighlightRenderer(this.editorView.TextArea.TextView); |
||||
this.delayTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMilliseconds) }; |
||||
this.delayTimer.Stop(); |
||||
this.delayTimer.Tick += TimerTick; |
||||
this.delayMoveTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(delayMoveMilliseconds) }; |
||||
this.delayMoveTimer.Stop(); |
||||
this.delayMoveTimer.Tick += TimerMoveTick; |
||||
this.editorView.TextArea.Caret.PositionChanged += CaretPositionChanged; |
||||
} |
||||
|
||||
void TimerTick(object sender, EventArgs e) |
||||
{ |
||||
this.delayTimer.Stop(); |
||||
LoggingService.Info("tick"); |
||||
// almost the same as DebuggerService.HandleToolTipRequest
|
||||
var referencesToBeHighlighted = GetReferencesInCurrentFile(this.lastResolveResult); |
||||
this.highlightRenderer.SetHighlight(referencesToBeHighlighted); |
||||
} |
||||
|
||||
void TimerMoveTick(object sender, EventArgs e) |
||||
{ |
||||
LoggingService.Debug("move"); |
||||
this.delayMoveTimer.Stop(); |
||||
this.delayTimer.Stop(); |
||||
var resolveResult = GetExpressionUnderCaret(); |
||||
if (resolveResult == null) { |
||||
this.lastResolveResult = resolveResult; |
||||
this.highlightRenderer.ClearHighlight(); |
||||
return; |
||||
} |
||||
// caret is over symbol and that symbol is different from the last time
|
||||
if (!SameResolveResult(resolveResult, lastResolveResult)) |
||||
{ |
||||
this.lastResolveResult = resolveResult; |
||||
this.highlightRenderer.ClearHighlight(); |
||||
this.delayTimer.Start(); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// In the current document, highlights all references to the expression
|
||||
/// which is currently under the caret (local variable, class, property).
|
||||
/// This gets called on every caret position change, so quite often.
|
||||
/// </summary>
|
||||
void CaretPositionChanged(object sender, EventArgs e) |
||||
{ |
||||
this.delayMoveTimer.Stop(); |
||||
this.delayMoveTimer.Start(); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Resolves the current expression under caret.
|
||||
/// This gets called on every caret position change, so quite often.
|
||||
/// </summary>
|
||||
ResolveResult GetExpressionUnderCaret() |
||||
{ |
||||
if (string.IsNullOrEmpty(Editor.FileName) || ParserService.LoadSolutionProjectsThreadRunning) |
||||
return null; |
||||
int line = Editor.Caret.Position.Line; |
||||
int column = Editor.Caret.Position.Column; |
||||
return ParserService.Resolve(line, column, Editor.Document, Editor.FileName); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Finds references to resolved expression in the current file.
|
||||
/// </summary>
|
||||
List<Reference> GetReferencesInCurrentFile(ResolveResult resolveResult) |
||||
{ |
||||
var references = RefactoringService.FindReferencesLocal(resolveResult, Editor.FileName, null); |
||||
if (references == null || references.Count == 0) |
||||
return null; |
||||
return references; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Returns true if the 2 ResolveResults refer to the same symbol.
|
||||
/// </summary>
|
||||
bool SameResolveResult(ResolveResult resolveResult, ResolveResult resolveResult2) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Martin Konicek" email="martin.konicek@gmail.com"/>
|
||||
// <version>$Revision: $</version>
|
||||
// </file>
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Windows.Media; |
||||
using System.Collections.Generic; |
||||
|
||||
using ICSharpCode.AvalonEdit.Document; |
||||
using ICSharpCode.AvalonEdit.Rendering; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Refactoring; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// Highlights expressions (references to expression under current caret).
|
||||
/// </summary>
|
||||
public class ExpressionHighlightRenderer : IBackgroundRenderer |
||||
{ |
||||
List<Reference> renderedReferences; |
||||
Pen borderPen; |
||||
Brush backgroundBrush; |
||||
TextView textView; |
||||
|
||||
public void SetHighlight(List<Reference> renderedReferences) |
||||
{ |
||||
if (this.renderedReferences != renderedReferences) { |
||||
this.renderedReferences = renderedReferences; |
||||
textView.InvalidateLayer(this.Layer); |
||||
} |
||||
} |
||||
|
||||
public void ClearHighlight() |
||||
{ |
||||
this.SetHighlight(null); |
||||
} |
||||
|
||||
public ExpressionHighlightRenderer(TextView textView) |
||||
{ |
||||
if (textView == null) |
||||
throw new ArgumentNullException("textView"); |
||||
//this.borderPen = new Pen(new SolidColorBrush(Color.FromRgb(70, 230, 70)), 1);
|
||||
this.borderPen = new Pen(Brushes.Transparent, 1); |
||||
this.borderPen.Freeze(); |
||||
this.backgroundBrush = new SolidColorBrush(Color.FromArgb(120, 60, 255, 60)); |
||||
this.backgroundBrush.Freeze(); |
||||
this.textView = textView; |
||||
this.textView.BackgroundRenderers.Add(this); |
||||
} |
||||
|
||||
public KnownLayer Layer { |
||||
get { |
||||
return KnownLayer.Selection; |
||||
} |
||||
} |
||||
|
||||
public void Draw(TextView textView, DrawingContext drawingContext) |
||||
{ |
||||
if (this.renderedReferences == null) |
||||
return; |
||||
BackgroundGeometryBuilder builder = new BackgroundGeometryBuilder(); |
||||
builder.CornerRadius = 1; |
||||
builder.AlignToMiddleOfPixels = true; |
||||
foreach (var reference in this.renderedReferences) { |
||||
builder.AddSegment(textView, new TextSegment() { |
||||
StartOffset = reference.Offset, |
||||
Length = reference.Length }); |
||||
builder.CloseFigure(); |
||||
} |
||||
Geometry geometry = builder.CreateGeometry(); |
||||
if (geometry != null) { |
||||
drawingContext.DrawGeometry(backgroundBrush, borderPen, geometry); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue