Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Update semantic highlighting when new parse information arrives.

  • Loading branch information...
commit 269597e6192d01ba80d06a1c92cbc58fc09a7e89 1 parent 04d88d5
@dgrunwald dgrunwald authored
View
1  src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
@@ -61,7 +61,6 @@
<Compile Include="Configuration\AssemblyInfo.cs" />
<EmbeddedResource Include="Resources\BuildOptions.xfrm" />
<EmbeddedResource Include="Resources\MyNamespaceSupportForCSharp.cs" />
- <Compile Include="Src\CSharpAdvancedHighlighter.cs" />
<Compile Include="Src\CSharpBracketSearcher.cs" />
<Compile Include="Src\CSharpLanguageBinding.cs" />
<Compile Include="Src\CSharpProjectBinding.cs" />
View
2  src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd
@@ -31,7 +31,7 @@
<Color name="TypeKeywords" fontWeight="bold" foreground="DarkCyan" exampleText="if (x is int) { a = x as int; type = typeof(int); size = sizeof(int); c = new object(); }"/>
<!-- Colors used for semantic highlighting -->
- <Color name="TypeReferences" foreground="DarkCyan" exampleText="System.Uri uri;"/>
+ <Color name="TypeReferences" foreground="#004085" exampleText="System.Uri uri;"/>
<Color name="MethodCall" foreground="MidnightBlue" fontWeight="bold" exampleText="o.ToString();"/>
<Color name="FieldAccess" fontStyle="italic" exampleText="return this.name;"/>
View
145 src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs
@@ -1,145 +0,0 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
-// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
-
-/*
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Diagnostics;
-using ICSharpCode.SharpDevelop.Dom.CSharp;
-using ICSharpCode.Core;
-using ICSharpCode.SharpDevelop;
-using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
-using ICSharpCode.SharpDevelop.Dom;
-using ICSharpCode.SharpDevelop.Gui;
-using ICSharpCode.TextEditor;
-using ICSharpCode.TextEditor.Document;
-
-namespace CSharpBinding
-{
- public class CSharpAdvancedHighlighter : AsynchronousAdvancedHighlighter
- {
- public override void Initialize(TextEditorControl textEditor)
- {
- base.Initialize(textEditor);
- ParserService.ParserUpdateStepFinished += OnUpdateStep;
- }
-
- public override void Dispose()
- {
- ParserService.ParserUpdateStepFinished -= OnUpdateStep;
- base.Dispose();
- }
-
- void OnUpdateStep(object sender, ParserUpdateStepEventArgs e)
- {
- if (FileUtility.IsEqualFileName(e.FileName, this.TextEditor.FileName)) {
- ParseInformation parseInfo = e.ParseInformation;
-// if (parseInfo == null && this.storedParseInformation)
-// parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName);
-// if (parseInfo != null) {
-// ICompilationUnit cu = parseInfo.MostRecentCompilationUnit;
-// }
- WorkbenchSingleton.SafeThreadAsyncCall(MarkOutstanding);
- }
- }
-
- static bool IsInMultilineCommentOrStringLiteral(LineSegment line)
- {
- if (line.HighlightSpanStack == null || line.HighlightSpanStack.IsEmpty) {
- return false;
- }
- return !line.HighlightSpanStack.Peek().StopEOL;
- }
-
- protected override void MarkWords(int lineNumber, LineSegment currentLine, List<TextWord> words)
- {
- if (IsInMultilineCommentOrStringLiteral(currentLine)) {
- return;
- }
- ParseInformation parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName);
- if (parseInfo == null) return;
-
- CSharpExpressionFinder finder = new CSharpExpressionFinder(parseInfo);
- Func<string, int, ExpressionResult> findExpressionMethod;
- IClass callingClass = parseInfo.MostRecentCompilationUnit.GetInnermostClass(lineNumber, 0);
- if (callingClass != null) {
- if (GetCurrentMember(callingClass, lineNumber, 0) != null) {
- findExpressionMethod = finder.FindFullExpressionInMethod;
- } else {
- findExpressionMethod = finder.FindFullExpressionInTypeDeclaration;
- }
- } else {
- findExpressionMethod = finder.FindFullExpression;
- }
-
- string lineText = this.Document.GetText(currentLine.Offset, currentLine.Length);
- bool changedLine = false;
- // now go through the word list:
- foreach (TextWord word in words) {
- if (word.IsWhiteSpace) continue;
- if (char.IsLetter(lineText[word.Offset]) || lineText[word.Offset] == '_') {
- ExpressionResult result = findExpressionMethod(lineText, word.Offset);
- if (result.Expression != null) {
- // result.Expression
- if (ICSharpCode.NRefactory.Parser.CSharp.Keywords.IsNonIdentifierKeyword(result.Expression))
- continue;
- // convert text editor to DOM coordinates:
- resolveCount++;
- ResolveResult rr = ParserService.Resolve(result, lineNumber + 1, word.Offset + 1, this.TextEditor.FileName, this.TextEditor.Text);
- if (rr is MixedResolveResult || rr is TypeResolveResult) {
- changedLine = true;
- word.SyntaxColor = this.Document.HighlightingStrategy.GetColorFor("TypeReference");
- } else if (rr == null) {
- changedLine = true;
- word.SyntaxColor = this.Document.HighlightingStrategy.GetColorFor("UnknownEntity");
- }
- }
- }
- }
-
- if (markingOutstanding && changedLine) {
- this.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber));
- }
- }
-
- static IMember GetCurrentMember(IClass callingClass, int caretLine, int caretColumn)
- {
- if (callingClass == null)
- return null;
- foreach (IMethod method in callingClass.Methods) {
- if (method.Region.IsInside(caretLine, caretColumn) || method.BodyRegion.IsInside(caretLine, caretColumn)) {
- return method;
- }
- }
- foreach (IProperty property in callingClass.Properties) {
- if (property.Region.IsInside(caretLine, caretColumn) || property.BodyRegion.IsInside(caretLine, caretColumn)) {
- return property;
- }
- }
- return null;
- }
-
- bool markingOutstanding;
- int resolveCount;
-
- protected override void MarkOutstanding()
- {
- #if DEBUG
- int time = Environment.TickCount;
- #endif
- markingOutstanding = true;
- resolveCount = 0;
- base.MarkOutstanding();
- markingOutstanding = false;
- #if DEBUG
- time = Environment.TickCount - time;
- if (time > 0) {
- LoggingService.Info("CSharpHighlighter took " + time + "ms for " + resolveCount + " resolves");
- }
- #endif
- this.Document.CommitUpdate();
- }
- }
-}
-*/
View
3  src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs
@@ -34,7 +34,7 @@ public override void Attach(ITextEditor editor)
this.editor = editor;
ISyntaxHighlighter highlighter = editor.GetService(typeof(ISyntaxHighlighter)) as ISyntaxHighlighter;
if (highlighter != null) {
- semanticHighlighter = new CSharpSemanticHighlighter(editor, highlighter.HighlightingDefinition);
+ semanticHighlighter = new CSharpSemanticHighlighter(editor, highlighter);
highlighter.AddAdditionalHighlighter(semanticHighlighter);
}
}
@@ -44,6 +44,7 @@ public override void Detach()
ISyntaxHighlighter highlighter = editor.GetService(typeof(ISyntaxHighlighter)) as ISyntaxHighlighter;
if (highlighter != null) {
highlighter.RemoveAdditionalHighlighter(semanticHighlighter);
+ semanticHighlighter.Dispose();
semanticHighlighter = null;
}
this.editor = null;
View
68 src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs
@@ -4,8 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
-using System.Threading.Tasks;
+
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
@@ -21,34 +20,66 @@ namespace CSharpBinding
/// <summary>
/// Semantic highlighting for C#.
/// </summary>
- public class CSharpSemanticHighlighter : DepthFirstAstVisitor<object, object>, IHighlighter, IResolveVisitorNavigator
+ public class CSharpSemanticHighlighter : DepthFirstAstVisitor<object, object>, IHighlighter, IResolveVisitorNavigator, IDisposable
{
readonly ITextEditor textEditor;
+ readonly ISyntaxHighlighter syntaxHighlighter;
readonly HighlightingColor typeReferenceColor;
readonly HighlightingColor methodCallColor;
readonly HighlightingColor fieldAccessColor;
readonly HighlightingColor valueKeywordColor;
+ HashSet<IDocumentLine> invalidLines = new HashSet<IDocumentLine>();
+
int lineNumber;
HighlightedLine line;
ResolveVisitor resolveVisitor;
bool isInAccessor;
- public CSharpSemanticHighlighter(ITextEditor textEditor, IHighlightingDefinition highlightingDefinition)
+ public CSharpSemanticHighlighter(ITextEditor textEditor, ISyntaxHighlighter syntaxHighlighter)
{
if (textEditor == null)
throw new ArgumentNullException("textEditor");
- if (highlightingDefinition == null)
- throw new ArgumentNullException("highlightingDefinition");
+ if (syntaxHighlighter == null)
+ throw new ArgumentNullException("syntaxHighlighter");
this.textEditor = textEditor;
+ this.syntaxHighlighter = syntaxHighlighter;
+
+ IHighlightingDefinition highlightingDefinition = syntaxHighlighter.HighlightingDefinition;
this.typeReferenceColor = highlightingDefinition.GetNamedColor("TypeReferences");
this.methodCallColor = highlightingDefinition.GetNamedColor("MethodCall");
this.fieldAccessColor = highlightingDefinition.GetNamedColor("FieldAccess");
this.valueKeywordColor = highlightingDefinition.GetNamedColor("NullOrValueKeywords");
+
+ ParserService.ParserUpdateStepFinished += ParserService_ParserUpdateStepFinished;
+ ParserService.LoadSolutionProjectsThreadEnded += ParserService_LoadSolutionProjectsThreadEnded;
}
- public IDocument Document {
+ public void Dispose()
+ {
+ ParserService.ParserUpdateStepFinished -= ParserService_ParserUpdateStepFinished;
+ ParserService.LoadSolutionProjectsThreadEnded -= ParserService_LoadSolutionProjectsThreadEnded;
+ }
+
+ void ParserService_LoadSolutionProjectsThreadEnded(object sender, EventArgs e)
+ {
+ syntaxHighlighter.InvalidateAll();
+ }
+
+ void ParserService_ParserUpdateStepFinished(object sender, ParserUpdateStepEventArgs e)
+ {
+ if (e.FileName == textEditor.FileName && invalidLines.Count > 0) {
+ foreach (IDocumentLine line in invalidLines) {
+ if (!line.IsDeleted) {
+ syntaxHighlighter.InvalidateLine(line);
+ }
+ }
+ invalidLines.Clear();
+ }
+ }
+
+ IDocument IHighlighter.Document {
get { return textEditor.Document; }
}
@@ -59,16 +90,18 @@ IEnumerable<HighlightingColor> IHighlighter.GetColorStack(int lineNumber)
public HighlightedLine HighlightLine(int lineNumber)
{
- Task<ParseInformation> parseInfoTask = ParserService.ParseAsync(textEditor.FileName, textEditor.Document);
- if (!parseInfoTask.IsCompleted) {
- Debug.WriteLine("Semantic highlighting for line {0} - parser not completed", lineNumber);
+ ParseInformation parseInfo = ParserService.GetCachedParseInformation(textEditor.FileName, textEditor.Document.Version);
+ if (parseInfo == null) {
+ invalidLines.Add(textEditor.Document.GetLineByNumber(lineNumber));
+ Debug.WriteLine("Semantic highlighting for line {0} - marking as invalid", lineNumber);
return null;
}
- ParseInformation parseInfo = parseInfoTask.Result;
CSharpParsedFile parsedFile = parseInfo.ParsedFile as CSharpParsedFile;
CompilationUnit cu = parseInfo.Annotation<CompilationUnit>();
- if (cu == null || parsedFile == null)
+ if (cu == null || parsedFile == null) {
+ Debug.WriteLine("Semantic highlighting for line {0} - not a C# file?", lineNumber);
return null;
+ }
using (var ctx = ParserService.GetTypeResolveContext(parseInfo.ProjectContent).Synchronize()) {
CSharpResolver resolver = new CSharpResolver(ctx);
@@ -246,7 +279,7 @@ public override object VisitMethodDeclaration(MethodDeclaration methodDeclaratio
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
- Colorize(typeDeclaration, typeReferenceColor);
+ Colorize(typeDeclaration.NameToken, typeReferenceColor);
foreach (var node in typeDeclaration.TypeParameters)
node.AcceptVisitor(this);
foreach (var node in typeDeclaration.BaseTypes)
@@ -257,5 +290,14 @@ public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, obj
node.AcceptVisitor(this);
return null;
}
+
+ public override object VisitVariableInitializer(VariableInitializer variableInitializer, object data)
+ {
+ if (variableInitializer.Parent is FieldDeclaration) {
+ Colorize(variableInitializer.NameToken, fieldAccessColor);
+ }
+ variableInitializer.Initializer.AcceptVisitor(this);
+ return null;
+ }
}
}
View
32 src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs
@@ -6,13 +6,13 @@
using System.Diagnostics;
using System.Linq;
using System.Windows;
-using System.Windows.Controls;
using System.Windows.Media;
+using System.Windows.Threading;
+
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
-using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop.Editor;
@@ -109,31 +109,39 @@ public CustomizableHighlightingColorizer(IHighlightingDefinition highlightingDef
this.customizations = customizations;
}
- protected override void OnDocumentChanged(TextView textView)
+ protected override void DeregisterServices(TextView textView)
{
textView.Services.RemoveService(typeof(ISyntaxHighlighter));
- base.OnDocumentChanged(textView);
+ base.DeregisterServices(textView);
+ }
+
+ protected override void RegisterServices(TextView textView)
+ {
+ base.RegisterServices(textView);
textView.Services.AddService(typeof(ISyntaxHighlighter), (CustomizingHighlighter)textView.GetService(typeof(IHighlighter)));
}
protected override IHighlighter CreateHighlighter(TextView textView, TextDocument document)
{
- return new CustomizingHighlighter(customizations, highlightingDefinition, base.CreateHighlighter(textView, document));
+ return new CustomizingHighlighter(textView, customizations, highlightingDefinition, base.CreateHighlighter(textView, document));
}
sealed class CustomizingHighlighter : IHighlighter, ISyntaxHighlighter
{
+ readonly TextView textView;
readonly IEnumerable<CustomizedHighlightingColor> customizations;
readonly IHighlightingDefinition highlightingDefinition;
readonly IHighlighter baseHighlighter;
List<IHighlighter> additionalHighlighters = new List<IHighlighter>();
- public CustomizingHighlighter(IEnumerable<CustomizedHighlightingColor> customizations, IHighlightingDefinition highlightingDefinition, IHighlighter baseHighlighter)
+ public CustomizingHighlighter(TextView textView, IEnumerable<CustomizedHighlightingColor> customizations, IHighlightingDefinition highlightingDefinition, IHighlighter baseHighlighter)
{
+ Debug.Assert(textView != null);
Debug.Assert(customizations != null);
Debug.Assert(highlightingDefinition != null);
Debug.Assert(baseHighlighter != null);
+ this.textView = textView;
this.customizations = customizations;
this.highlightingDefinition = highlightingDefinition;
this.baseHighlighter = baseHighlighter;
@@ -195,6 +203,7 @@ public HighlightedLine HighlightLine(int lineNumber)
return line;
}
+ #region MergeHighlighting
/// <summary>
/// Merges the highlighting sections from additionalLine into line.
/// </summary>
@@ -297,6 +306,7 @@ void ValidateInvariants(HighlightedLine line)
}
}
}
+ #endregion
HighlightingColor CustomizeColor(HighlightingColor color)
{
@@ -323,6 +333,16 @@ static HighlightingBrush CreateBrush(Color? color)
else
return new CustomizedBrush(color.Value);
}
+
+ public void InvalidateLine(IDocumentLine line)
+ {
+ textView.Redraw(line, DispatcherPriority.Background);
+ }
+
+ public void InvalidateAll()
+ {
+ textView.Redraw(DispatcherPriority.Background);
+ }
}
sealed class CustomizedBrush : HighlightingBrush
View
26 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs
@@ -32,14 +32,27 @@ public HighlightingColorizer(HighlightingRuleSet ruleSet)
void textView_DocumentChanged(object sender, EventArgs e)
{
- OnDocumentChanged((TextView)sender);
+ TextView textView = (TextView)sender;
+ DeregisterServices(textView);
+ RegisterServices(textView);
}
- protected virtual void OnDocumentChanged(TextView textView)
+ /// <summary>
+ /// This method is called when a text view is removed from this HighlightingColorizer,
+ /// and also when the TextDocument on any associated text view changes.
+ /// </summary>
+ protected virtual void DeregisterServices(TextView textView)
{
// remove existing highlighter, if any exists
textView.Services.RemoveService(typeof(IHighlighter));
-
+ }
+
+ /// <summary>
+ /// This method is called when a new text view is added to this HighlightingColorizer,
+ /// and also when the TextDocument on any associated text view changes.
+ /// </summary>
+ protected virtual void RegisterServices(TextView textView)
+ {
TextDocument document = textView.Document;
if (document != null) {
IHighlighter highlighter = CreateHighlighter(textView, document);
@@ -61,17 +74,16 @@ protected override void OnAddToTextView(TextView textView)
base.OnAddToTextView(textView);
textView.DocumentChanged += textView_DocumentChanged;
textView.VisualLineConstructionStarting += textView_VisualLineConstructionStarting;
- OnDocumentChanged(textView);
+ RegisterServices(textView);
}
/// <inheritdoc/>
protected override void OnRemoveFromTextView(TextView textView)
{
- base.OnRemoveFromTextView(textView);
- textView.Services.RemoveService(typeof(IHighlighter));
- textView.Services.RemoveService(typeof(DocumentHighlighter));
+ DeregisterServices(textView);
textView.DocumentChanged -= textView_DocumentChanged;
textView.VisualLineConstructionStarting -= textView_VisualLineConstructionStarting;
+ base.OnRemoveFromTextView(textView);
}
void textView_VisualLineConstructionStarting(object sender, VisualLineConstructionStartEventArgs e)
View
19 src/Main/Base/Project/Src/Editor/ISyntaxHighlighter.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.AvalonEdit.Highlighting;
+using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.SharpDevelop.Editor
{
@@ -33,6 +34,24 @@ public interface ISyntaxHighlighter
/// Removes an additional highlighting engine.
/// </summary>
void RemoveAdditionalHighlighter(IHighlighter highlighter);
+
+ /// <summary>
+ /// Invalidates a line, causing it to be re-highlighted.
+ /// </summary>
+ /// <remarks>
+ /// This method is intended to be called by additional highlighters that process external information
+ /// (e.g. semantic highlighting).
+ /// </remarks>
+ void InvalidateLine(IDocumentLine line);
+
+ /// <summary>
+ /// Invalidates all lines, causing-them to be re-highlighted.
+ /// </summary>
+ /// <remarks>
+ /// This method is intended to be called by additional highlighters that process external information
+ /// (e.g. semantic highlighting).
+ /// </remarks>
+ void InvalidateAll();
}
public static class SyntaxHighligherKnownSpanNames
View
4 src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
@@ -5,8 +5,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Threading;
using System.Threading.Tasks;
+
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
@@ -29,7 +29,7 @@ public ParseProjectContent(MSBuildBasedProject project)
if (project == null)
throw new ArgumentNullException("project");
this.project = project;
- this.typeResolveContext = MinimalResolveContext.Instance;
+ this.typeResolveContext = new CompositeTypeResolveContext(new ITypeResolveContext[] { this, MinimalResolveContext.Instance });
this.initializing = true;
LoadSolutionProjects.AddJob(Initialize, "Loading " + project.Name + "...", GetInitializationWorkAmount());
View
34 src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
@@ -10,6 +10,7 @@
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
+
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
@@ -412,6 +413,19 @@ public ParseInformation GetCachedParseInformation()
return cachedParseInformation; // read volatile
}
+ public ParseInformation GetCachedParseInformation(ITextSourceVersion version)
+ {
+ if (version == null)
+ return GetCachedParseInformation();
+ lock (this) {
+ if (bufferVersion != null && bufferVersion.BelongsToSameDocumentAs(version)) {
+ if (bufferVersion.CompareAge(version) >= 0)
+ return cachedParseInformation;
+ }
+ }
+ return null;
+ }
+
public IParsedFile GetExistingParsedFile(IProjectContent content)
{
if (content == null) {
@@ -822,6 +836,26 @@ public static ParseInformation GetCachedParseInformation(FileName fileName)
}
/// <summary>
+ /// Gets full parse information for the specified file, if it is available and at least as recent as the specified version.
+ /// </summary>
+ /// <returns>
+ /// If only the IParsedFile is available (non-full parse information), this method
+ /// returns null.
+ /// If parse information is avaiable but potentially outdated (older than <paramref name="version"/>,
+ /// or belonging to a different document), this method returns null.
+ /// </returns>
+ public static ParseInformation GetCachedParseInformation(FileName fileName, ITextSourceVersion version)
+ {
+ if (string.IsNullOrEmpty(fileName))
+ return null;
+ FileEntry entry = GetFileEntry(fileName, false);
+ if (entry != null)
+ return entry.GetCachedParseInformation(version);
+ else
+ return null;
+ }
+
+ /// <summary>
/// Gets parse information for the specified file.
/// </summary>
/// <returns>

0 comments on commit 269597e

Please sign in to comment.
Something went wrong with that request. Please try again.