diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index dbe11efa3e..9b8b82d568 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -61,7 +61,6 @@ - diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd b/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd index ca2c3f407a..e17dae7ade 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Resources/CSharp-Semantic.xshd @@ -31,7 +31,7 @@ - + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs deleted file mode 100644 index dba086bf89..0000000000 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpAdvancedHighlighter.cs +++ /dev/null @@ -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 words) - { - if (IsInMultilineCommentOrStringLiteral(currentLine)) { - return; - } - ParseInformation parseInfo = ParserService.GetParseInformation(this.TextEditor.FileName); - if (parseInfo == null) return; - - CSharpExpressionFinder finder = new CSharpExpressionFinder(parseInfo); - Func 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(); - } - } -} -*/ diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 7bf746c3dc..31f8e1536a 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -34,7 +34,7 @@ namespace CSharpBinding 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 @@ namespace CSharpBinding ISyntaxHighlighter highlighter = editor.GetService(typeof(ISyntaxHighlighter)) as ISyntaxHighlighter; if (highlighter != null) { highlighter.RemoveAdditionalHighlighter(semanticHighlighter); + semanticHighlighter.Dispose(); semanticHighlighter = null; } this.editor = null; diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs index 5cbf975504..080676edbf 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpSemanticHighlighter.cs +++ b/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 /// /// Semantic highlighting for C#. /// - public class CSharpSemanticHighlighter : DepthFirstAstVisitor, IHighlighter, IResolveVisitorNavigator + public class CSharpSemanticHighlighter : DepthFirstAstVisitor, IHighlighter, IResolveVisitorNavigator, IDisposable { readonly ITextEditor textEditor; + readonly ISyntaxHighlighter syntaxHighlighter; readonly HighlightingColor typeReferenceColor; readonly HighlightingColor methodCallColor; readonly HighlightingColor fieldAccessColor; readonly HighlightingColor valueKeywordColor; + HashSet invalidLines = new HashSet(); + 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 @@ namespace CSharpBinding public HighlightedLine HighlightLine(int lineNumber) { - Task 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(); - 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 @@ namespace CSharpBinding 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 @@ namespace CSharpBinding 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; + } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs index b9c7616a9a..618890f04e 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs @@ -6,13 +6,13 @@ using System.Collections.Generic; 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 @@ namespace ICSharpCode.AvalonEdit.AddIn 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 customizations; readonly IHighlightingDefinition highlightingDefinition; readonly IHighlighter baseHighlighter; List additionalHighlighters = new List(); - public CustomizingHighlighter(IEnumerable customizations, IHighlightingDefinition highlightingDefinition, IHighlighter baseHighlighter) + public CustomizingHighlighter(TextView textView, IEnumerable 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 @@ namespace ICSharpCode.AvalonEdit.AddIn return line; } + #region MergeHighlighting /// /// Merges the highlighting sections from additionalLine into line. /// @@ -297,6 +306,7 @@ namespace ICSharpCode.AvalonEdit.AddIn } } } + #endregion HighlightingColor CustomizeColor(HighlightingColor color) { @@ -323,6 +333,16 @@ namespace ICSharpCode.AvalonEdit.AddIn 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 diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs index 5d30dccfac..2f4160c2ad 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs @@ -32,14 +32,27 @@ namespace ICSharpCode.AvalonEdit.Highlighting void textView_DocumentChanged(object sender, EventArgs e) { - OnDocumentChanged((TextView)sender); + TextView textView = (TextView)sender; + DeregisterServices(textView); + RegisterServices(textView); } - protected virtual void OnDocumentChanged(TextView textView) + /// + /// This method is called when a text view is removed from this HighlightingColorizer, + /// and also when the TextDocument on any associated text view changes. + /// + protected virtual void DeregisterServices(TextView textView) { // remove existing highlighter, if any exists textView.Services.RemoveService(typeof(IHighlighter)); - + } + + /// + /// 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. + /// + protected virtual void RegisterServices(TextView textView) + { TextDocument document = textView.Document; if (document != null) { IHighlighter highlighter = CreateHighlighter(textView, document); @@ -61,17 +74,16 @@ namespace ICSharpCode.AvalonEdit.Highlighting base.OnAddToTextView(textView); textView.DocumentChanged += textView_DocumentChanged; textView.VisualLineConstructionStarting += textView_VisualLineConstructionStarting; - OnDocumentChanged(textView); + RegisterServices(textView); } /// 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) diff --git a/src/Main/Base/Project/Src/Editor/ISyntaxHighlighter.cs b/src/Main/Base/Project/Src/Editor/ISyntaxHighlighter.cs index b4e6a5acf3..402e191f58 100644 --- a/src/Main/Base/Project/Src/Editor/ISyntaxHighlighter.cs +++ b/src/Main/Base/Project/Src/Editor/ISyntaxHighlighter.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.NRefactory.Editor; namespace ICSharpCode.SharpDevelop.Editor { @@ -33,6 +34,24 @@ namespace ICSharpCode.SharpDevelop.Editor /// Removes an additional highlighting engine. /// void RemoveAdditionalHighlighter(IHighlighter highlighter); + + /// + /// Invalidates a line, causing it to be re-highlighted. + /// + /// + /// This method is intended to be called by additional highlighters that process external information + /// (e.g. semantic highlighting). + /// + void InvalidateLine(IDocumentLine line); + + /// + /// Invalidates all lines, causing-them to be re-highlighted. + /// + /// + /// This method is intended to be called by additional highlighters that process external information + /// (e.g. semantic highlighting). + /// + void InvalidateAll(); } public static class SyntaxHighligherKnownSpanNames diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index 80be29268b..b8b89921f4 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -5,8 +5,8 @@ using System; 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 @@ namespace ICSharpCode.SharpDevelop.Parser 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()); diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index 8aa4ba69e5..4dbb97094e 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -10,6 +10,7 @@ using System.Text; 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 @@ namespace ICSharpCode.SharpDevelop.Parser 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) { @@ -821,6 +835,26 @@ namespace ICSharpCode.SharpDevelop.Parser return null; } + /// + /// Gets full parse information for the specified file, if it is available and at least as recent as the specified version. + /// + /// + /// If only the IParsedFile is available (non-full parse information), this method + /// returns null. + /// If parse information is avaiable but potentially outdated (older than , + /// or belonging to a different document), this method returns null. + /// + 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; + } + /// /// Gets parse information for the specified file. ///