Conversation
…g created via `AsTextContainer` If MonoDevelop creates new instance of `SourceTextContainer`(`MonoDevelopSourceTextContainer`) and adds this one to workspace the one used by Roslyn services via `AsTextContainer` is disconnected and most services don't work... Change in `IMonoDevelopHostDocument.cs` is to fix exception(before was never called because `SourceTextContainer` was not connected)
…ighting fixes Issue #3770 This improves typing performance a lot in some cases when `GetSemanticModelAsync` takes long time(sometimes it can take multiple seconds)... This uses advanced `AbstractAsynchronousTaggerProvider` from Roslyn that takes care of snapshot `TranslateTo` so if new classification is not ready yet, it translates old spans to requested snapshot and notifies editor when semantic classification is updated for specific span so it re-renders line containing updated classification. There are two hacks in this commit: - Translations from `ClassificationTypes` to `ScopeStack` are hardcoded and so is order(same as in existing Roslyn classifier) - On `classifier.ClassificationChanged` event is ignored if span is whole file, reason for this is that it seems to me like SyntaxHighligher is doing this(probably can't figure out exact spans), Kirill debugged this on VS2017 and saw same behaviour, I suspect VS2017 doesn't re-render if classifications are same as in previous pass, hence it doesn't hurt them as much as it does MonoDevelop
Now it's inserting lines in correct order so FormattedSpan can return First().Start,Last.End and also fixed issue with 1st and last line having different snapshot, this is not ideal solution.
|
Forgot to mention this fixes #3770 |
| if (this.Count == 0) | ||
| return new SnapshotSpan (textEditor.TextSnapshot, 0, 0); | ||
| var start = this [0].Start; | ||
| var end = this.Last ().EndIncludingLineBreak; |
There was a problem hiding this comment.
Please avoid linq. It usually does not work well perf-wise.
There was a problem hiding this comment.
If you never use linq you don't do anything wrong.
There was a problem hiding this comment.
Nice - we can really need that.
However this breaks span updates. /* & @". VS.NET taggers need to do that somehow.
ATM we've a more or less dirty work around for making it work with the roslyn classification highlighting.
And how are ISemanticChangeNotificationService notifications handled ? They seem to be missing here.
In roslyn there are some event sources that raise state change events:
(The old roslyn classification highlighting had that)
I'm not really sure how the span updates work according to
TaggerEventSources.TextChangedEventSource.cs they should always reclassify the whole buffer on text change which is something I try to avoid.
| return document; | ||
| } | ||
| var monoDevelopSourceTextContainer = new MonoDevelopSourceTextContainer (this, documentId, editor); | ||
| var monoDevelopSourceTextContainer = editor.TextView.TextBuffer.AsTextContainer (); |
There was a problem hiding this comment.
Now we're starting to benefit from the vs.net editor work - nice :)
| var styleName = GetStyleNameFromClassificationName (baseType.Classification); | ||
| if (styleName == null) | ||
| continue; | ||
| scope = new ScopeStack (styleName); |
There was a problem hiding this comment.
This doesn't look right the classification map already contains the scope and then you're using GetStyleNameFromClassificationName to produce a new scope ?
GetStyleNameFromClassificationName has to go and the missing entries need to be added to the classificationMap.
Maybe make a default classificationMap and make classificationMap an immutable dictionary.
If an entry is missing add the default case from GetStyleNameFromClassificationName to the ClassificationMap. So the ScopeStack objects get re-used instead of re-created every time.
There was a problem hiding this comment.
I fixed this now by returning of mapping one is found, also, all of this is cached so it shouldn't be a problem.
| continue; | ||
| scope = new ScopeStack (styleName); | ||
| } | ||
| return classificationTypeToScopeCache [classificationType] = scope ?? new ScopeStack (EditorThemeColors.Foreground); |
There was a problem hiding this comment.
Do not create a new ScopeStack (EditorThemeColors.Foreground) more than once. But it's not a big issue because of the cache.
| if (classificationTypeToScopeCache.TryGetValue (classificationType, out var cachedScope)) | ||
| return cachedScope; | ||
| ScopeStack scope = null; | ||
| foreach (var baseType in classificationType.BaseTypes.Concat (classificationType)) { |
There was a problem hiding this comment.
Wouldn't it be more performant to start with the classificationType and then check the base types ?
And in which order are the base types ? And what's with the BaseTypes of the BaseTypes ?
But in general it doesn't make much sense to me - in which cases no classification for a classification type is done - we should always have a color for a classification and if not we should log it. Then we can go to the base types.
There was a problem hiding this comment.
About performance, we are caching this so it's not really problem, plus we have to check all anyway.
Base types are in alphabetic order, priorty is handled differently in VSEditor, see https://github.com/dotnet/roslyn/blob/88d1bd1/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs
I'm now handling BaseTypes of BaseTypes...
Logging non-found classifcaiton is imo not an option because some classifications are created on the fly when merging multiple classifications...
|
|
||
| private ScopeStack GetScopeNameFromClassificationType (IClassificationType classificationType) | ||
| { | ||
| if (classificationTypeToScopeCache.TryGetValue (classificationType, out var cachedScope)) |
There was a problem hiding this comment.
classificationTypeToScopeCache is an immutable dictionary. Let's say you've a vb.net and c# file open.
Is the IClassificationType keyword the same for vb.net and c# ? If so it would return a wrong value for one of these files.
There was a problem hiding this comment.
This object and cache is created per ITextView so I don't expect this to be an issue.
…changes e.g. `/*`
|
I updated PR with |
|
Tell me more, what is that huge performance improvement? |
|
Often times when I see laggy typing I profile it and it turns out to be problem like seen at #3770. The way new logic work is same as in VS Windows, it uses SnapshotSpan.TranslateTo to translate older classification to latest textbuffer so it's "instantly" renders best approximation and later calls |
|
Still missing the ISemanticChangeNotificationService usage. However testing semantic updates seem to work for some reason. I think that the code analysis may do the updates since it takes a while for highlighting to correct. But it works so I approve. One thing: remove the tests for the span updater I already did that. And we should consider this for d15-7 because it's a better fix to my span updater move. The tag based highlighter needs to work anyways. |
|
Tnx for heads ups about Unit tests, I noticed locally few minutes ago that it doesn't compile... I removed them now. |
This PR introduces 2 big changes:
TextBuffer.AsTextContainer()which enables some roslyn functionalities(Tagger among others)I will need to figure out how to optimize rendering logic, to not redraw lines if nothing changed, like VS2017 does...