This additionally gets rid of an extra whole buffer allocation in the ParserContext. The most complex bit of the change is around avoiding TextLineCollection.GetLocation.
Overall, I'm seeing a pretty big win here, about 35% less time spent in RazorSyntaxTree.Parse for the typing scenario I was doing in a very large file.
This method allocated multiple strings on every invocation when they were rarely needed. With this change, I see a reduction in memory allocated during RazorProjectEngine.ProcessDesignTime of 1.4%.
This is the last of the easy wins that I could find for typing in large razor files (minus the logged bug to move the divergence checker code off the UI thread). In the profile for the large document editing, these changes reduce allocated memory during RazorSyntaxTree.Parse by about 25%. CPU wise, the win isn't quite as dramatic, only a couple percent improvement under RazorSyntaxTree.Parse.
* Add mechanism where IR token generation can defer allocation of it's content.
It turns out that many IR tokens access their content, and thus allocating it is unnecessary. In particular, with this change against a large file, I've seen allocations under SyntaxNodeExtensions.GetContent reduced by about 33%. Performance wise, I've seen the number of CPU samples in the profile under GetContent reduce by about 40% (in my sample I typed 26 characters and there was about 600 ms less spent in GetContent)
* ContentGetter => ContentFactory
* Make tests happy with the switch from IntermediateToken to IntermediateTokenWithDeferreedContentAllocation
* IntermediateTokenWithDeferredContentAllocation => LazyIntermediateToken
* Previous optimization didn't help as much as intended.
By specifying a method group as the arguments to method like ReadWhile, an allocation was still occurring. Instead, cache the Func as a member in the class and use it instead of the method group.\n\nCommit migrated from 2e6aa150bc
* Improve CSharpLanguageCharacteristics.MapKeyword performance
The razor typing perf test profile I'm looking at has 156 ms of CPU cycles spent in this method, mostly in Enum.ToString()
\n\nCommit migrated from e821a4642e
In the razor perf typing test, Accept was showing 27 ms allocating enumerators. Additionally, modified ReadWhile to only allocate if it would return a non-empty collection (and to not use the complexity introduced by using yield enumerators)\n\nCommit migrated from 27a14af36a
The razor perf test shows about 70 ms CPU of WithSpanContext is in allocation. GetAnnotation similarly is showing about 60 ms in allocation (of which this only partly improves)\n\nCommit migrated from a060f129ff
Our razor typing test measured 153 CPU ms in this method. Optimized by fewer calls to CurrentCharacter, not checking '<' twice, and uswing a switch stmt.\n\nCommit migrated from c601c2f11e
* Several changes targeted to improving perf of RazorSyntaxTree.Parse
1) Modify ParserHelpers.IsNewLine to use a switch instead of Array.IndexOf
2) Modify Tokenizer.CreateToken to take in an array of RazorDiagnostics rather than an IReadOnlyList as that was causing a ToArray call on an empty diagnostics very often (during a SyntaxFactory.Token call)
3) Modify TokenizerBackedParser.Putback to allow an IReadOnlyList as a parameter to not require creation of a reverse enumerator.
4) Cut down allocations in HtmlMarkupParser.GetParserState by:
a) Using an IReadOnlyList instead of IEnumerable to get rid of the allocations from the .any calls
b) Don't allocate while reading initial spacing
c) Inline the IsSpacingToken code so cut down on code executed and need to allocate a separate Func
5) Modify CSharpCodeParser.IsSpacingToken to now be a set of methods instead of a single method that allocates a Func. This is a very high traffic method.
6) Implement a fairly rudimentary Whitespace token cache, as they can be reused. This was based off Roslyn's SyntaxNodeCache, but simplified significantly. It's probably worth investigating whether you should more fully embrance token caching outside of whitespace.
* PR feedback and added one more optimization in LocateOwner that's been bugging me for years. Assuming all chidlren are contained within a nodes span, we can short-circuit the DFS this code was doing significantly cutting time in this method which is important as it's exercised on the main thread during typing.
* missed a space
* StringTextToSnapshot's switch to IsNewLine needed to use start as the index to begin the search, not zero.\n\nCommit migrated from 45411f7526
I noticed several hundred ms spent in this method from a customer profile. Primarilly, the method was doing a linear scan of all lines trying to find one that contained the requested position. I changed this to a binary search, but kept/improved the optimization around checking next/previous lines before instigating the search.
Note, there was also a bug where the old code did:
else if (absoluteIndex > _currentLine.Index && _currentLine.Index + 1 < _lines.Count)
but it should have been coparing absoluteIndex with _currentLine.Start
\n\nCommit migrated from 32a0f28708
- This is a pre-requisite work item to run our language server in-process in Visual Studio. VS is a .NET framework application so we can't have a language server which targets netcoreapp be loaded. Therefore, in order to account for this I needed to re-target our language server library to netstandard2.0 so it can be referenced via a netcoreapp (rzls.exe) and a .NET framework app.
- Added a new `rzls` project to be the maintainer of our OOP language server
- Had to make adjustments to the existing language server project to be compatible with netstandard2.0.
- Created a new `RazorLanguageServer` type to initiate our Language Server but not start and initialize it. To enable a consumer to initialize the new language server I had to use private reflection to `Initialize` O#'s internal type. This is a temporary measure which I intend to expand the O# lib to make their Initialize method public.
dotnet/aspnetcoredotnet/aspnetcore-tooling#19185
\n\nCommit migrated from 79841b9371
LSP Razor formatting for Razor code block directives
- Support for @code/@functions block formatting
- Except when it contains Markup or other Razor constructs
- Added a RazorFormattingService which is invoked by the RazorFormattingEndpoint.
- Added a custom razor/rangeFormatting command that the server can use to ask the client to format a range of the projected C# or HTML document
- Added a CSharpFormatter and HTMLFormatter that invoke the above mentioned command
- Added FormattingSpan and its corresponding visitor to represent Razor understanding of indentation
- Moved the document mapping code to a separate RazorDocumentMappingService service for ease of use
- Added necessary extension methods for convenience. Some of them were copied from Roslyn
- Some cleanup
- Added a C# test formatter to enable unit testing. Right now it calls Roslyn APIs directly. As far as I've seen its behavior is the same as OmniSharp formatting except it doesn't remove trailing whitespace and empty lines. I am following up with people to understand why that is the case.
Added/updated tests
\n\nCommit migrated from 62051b9ad7
- The Blazor runtime doesn't support adding attributes prior to any sort of content frames being applied. This change ensures that `ComponentAttributes` (how preventDefault / stopPropagation are represented) are handled like other HTML attributes (applied first).
- Updated existing tests and their baselines.
aspnet/AspNetCoredotnet/aspnetcore-tooling#16611
\n\nCommit migrated from 1513cd2a5b
Fixes aspnet/AspNetCoredotnet/aspnetcore-tooling#13181
The big change here is that we have to allow an HtmlAttributeIRNode to have
a dynamically computed attribute name. This isn't something that exists
anywhere else in the system.
\n\nCommit migrated from 559f0f5e52
This change updates tag helper binding logic to allow directive
attributes (when they appear alone) to bind to any kind of tag
(start/end, void, self-closing).
Tag Helpers don't have a semantic that allows this level of flexibility
- using StartTagOnly as suggested in the issue means that this would
*only* work for void elements.
There's no change to any of the directive attribute implementations
because this is a global change in the tag helper infra.
\n\nCommit migrated from fd72afc1c6
- No longer mark declaration files as single file generators. Prior to this we relied on SingleFileGenerators to dynamically update the declaration files when .razor files changed. However, to make partial classes work we can no longer depend on declaration files being available because their existence causes us to have to mangle class names for opened documents; otherwise you get two files with same name and result in ambiguous definition errors.
- Stopped including declaration files as part of the users compilation. This was intended to make the design time experience operate more similar to how Blazor apps function at runtime (directly access each component instead of their declarations). We now rely on the background code generation effort built from the find all references work to supply users with strongly typed component names.
- Stop mangling class names for Visual Studio. Razor.VSCode has its own set of configurations which i'm not addressing as part of this changeset.
- Start generating components with the partial modifier to their class name to enable partial class support.
- Updated existing tests to expect partial modifier.
aspnet/AspNetCoredotnet/aspnetcore-tooling#5487\n\nCommit migrated from 73858cdd37
- Added tests for both the language server and the common language server projects.
- Updated publish MSBuild bits to publish to `artifacts/LanguageServer/$(Configuration)/TFM`
- Updated the language server to be netcoreapp3.0
aspnet/AspNetCoredotnet/aspnetcore-tooling#13494
\n\nCommit migrated from 984c638b37
This change updates the snapshot of components APIs used in compiler
tests and updates the tests to react tot hose changes.
\n\nCommit migrated from c8cc588bca
The code-generated TypeInference type resides in a custom namespace.
Any types that it refers to in user code must be qualified using the "global::" prefix
to avoid type \ namespace conflicts.
Fixes https://github.com/aspnet/AspNetCore/issues/12116\n\nCommit migrated from f0e09e4a97