Move indentation services down to Workspace layer.#33978
Move indentation services down to Workspace layer.#33978heejaechang merged 18 commits intodotnet:masterfrom
Conversation
|
@dotnet/roslyn-infrastructure @jasonmalinowski @jaredpar Do you know what causes this error on pipelines: ? |
|
Oh, the formatting stuff is even weirder than i first though. It looks like we actually run SmartTokenCommandHandler and FormatCommandHandler in the same chain. Though there's nothing that indicates that these should be ordered in any particular fashion. This is definitely a bit strange as that means you could hand Format handle enter first, followed by SmartToken, or vice versa. In my current debug-session, SmartTokenCommandHandler called into FormatCommandHandler. There FormatCommandHandler bailed out very quickly (it looks like it only tries to handle close-parens and using-statements??). We then got back to SmartTokenCommandHandler, which did a bunch of checks, and then bailed out because it thought the editor handled things... It's all pretty confusing about who/what/where and when is responsible for handling thse things. @heejaechang can you shed some light on the design here and the separation of responsibilities? One good thin to know would be: say we had a bug in hitting 'enter'. How would you determine which of these three systems was responsible for handling fixing it? |
|
we have 3 different scenario.
also, for 2 and 3, since formatting doesn't touch any expression level construct except certain cases like query expression, for 2 and 3 to handle "enter" or "indentation" of expression level, it adds some extra rules for things like argument list, parameter list and etc to format engine. also for us to not re-implementation logic to determine where to put caret based on various formatting options for indentation, it uses formatting rules to determine indentation if there is new line indentation rule. otherwise, it uses heuristic to find indentation since there is no option to change its behavior. and there are bunch of case by case for indentation from feedbacks. can't remember all those special cases. |
|
ah, and we also has special case for razor and venus through some formatting rule provider and etc. we can't get rid of that due to venus. but hopefully for new razor, we don't need to use it. |
|
Could you clarify what the intended split is across all three indentation systems today? To help, i asked this question:
|
Ok. But hte only scenario i'm really asking about is 'indentation/enter-handling'. My question is about why we've separated the logic out for that into mulitple different locations, with each location needing to know about and poke into the other locations to figure out what's going on. That's the part that seems very confusing, and makes it very difficult for, say, a feature to ask "where should i indent here?" |
|
Let me try to ask teh question as simply as possible: We have: internal partial class SmartIndent : ISmartIndentAnd internal class SmartTokenFormatterCommandHandlerBoth are responsible for figuring out where to place the care after
I can't figure out any rhyme or reasons on these guys. -- Note: if gitter would be better to discuss things, i'm happy to take it there. It might be easier to ask questions and build understanding versus trying to do this back and forth over github. Which would you prefer? Thanks! |
Alright, i'll see what i can do. |
@heejaechang i have cleaned up a lot here: #33989 This removes unnecessary separation of services for handling indentation. -- THe end result gets rid of a lot. but it still ends up being complex. That's because the indentation service itself has all these different codepaths trying to decide what behavior to perform with all sorts of complex assumptions. I have no idea how to make that better, but at least it's all contained in this one service now. |
sharwell
left a comment
There was a problem hiding this comment.
Ensuring this gets a design review to determine the approach we want for two specific items:
- Are type forwarders preferred to redefining types?
- We have active plans to eliminate external code depending on these interfaces, and need to determine which we want to pursue first.
I would prefer not here. There are changes i want to make to the interfaces in other PRs (for example, making the return types non-nullable). So this will be more than just a move. |
Can you explain these plans? What's the recommended way for a 3rd party language to participate in indentation? |
All components not in dotnet/roslyn (except for VS for Mac) must now go through an adapter assembly rather than directly access internal Roslyn APIs. New IVTs are not getting added, and ones already in place are being phased out.
Through the public API. |
|
I would prefer to migrate existing external components off of the internal indentation APIs before making changes that go beyond the abilities of type forwarders. Will need to review with F# and TypeScript to determine the complexity of these changes. Otherwise this change is vastly more complex to account for a situation that we can avoid from the start. |
|
What public API are you referring to? |
@tmat Done! |
|
@tmat feel free to merge when you havea chance. |
|
@heejaechang @sharwell OK to merge? |
Ping. Thanks! |
|
@tmat, @sharwell says he's not blocking this, but he's not moving it forward. Would it be possible to directly pull in @heejaechang as i find pings don't reach him very well. |
|
spoke to @heejaechang , he will take a look at it soon. |
|
|
||
| namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral | ||
| { | ||
| using Microsoft.CodeAnalysis.Indentation; |
There was a problem hiding this comment.
move to where other using is?
There was a problem hiding this comment.
can't. if we move it, then diffrent symbols will be found in Microsoft.CodeAnalysis.Editor.
There was a problem hiding this comment.
so, we have a plan to move at some point then? or it has to be here until typescript/F# is moving to new API as well?
|
|
||
| namespace Microsoft.CodeAnalysis.Editor.Implementation.Formatting.Indentation | ||
| { | ||
| using Microsoft.CodeAnalysis.Indentation; |
There was a problem hiding this comment.
can't. if we move it, then diffrent symbols will be found in Microsoft.CodeAnalysis.Editor.
| if (asyncService != null) | ||
| // If we don't have a feature-layer service, try to fall back to the legacy | ||
| // editor-feature-layer interfaces. | ||
|
|
There was a problem hiding this comment.
is this for things like typescript or F#?
| nameof(FeatureOnOffOptions), nameof(AutoFormattingOnTyping), defaultValue: true, | ||
| storageLocations: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Typing")); | ||
|
|
||
| public static readonly PerLanguageOption<bool> AutoFormattingOnReturn = new PerLanguageOption<bool>( |
|
|
||
| namespace Microsoft.CodeAnalysis.Editor.Wrapping.BinaryExpression | ||
| { | ||
| using Microsoft.CodeAnalysis.Indentation; |
There was a problem hiding this comment.
can't. if we move it, then different symbols will be found in Microsoft.CodeAnalysis.Editor.
|
|
||
| namespace Microsoft.CodeAnalysis.Editor.Wrapping.SeparatedSyntaxList | ||
| { | ||
| using Microsoft.CodeAnalysis.Indentation; |
There was a problem hiding this comment.
can't. if we move it, then different symbols will be found in Microsoft.CodeAnalysis.Editor.
|
|
||
| internal static Option<bool> AllowDisjointSpanMerging { get; } = CreateOption(OptionGroup.Default, nameof(AllowDisjointSpanMerging), defaultValue: false); | ||
|
|
||
| internal static readonly PerLanguageOption<bool> AutoFormattingOnReturn = CreatePerLanguageOption(OptionGroup.Default, nameof(AutoFormattingOnReturn), defaultValue: true, |
There was a problem hiding this comment.
ah. I see. it moved to here.
| internal static Option<bool> AllowDisjointSpanMerging { get; } = CreateOption(OptionGroup.Default, nameof(AllowDisjointSpanMerging), defaultValue: false); | ||
|
|
||
| internal static readonly PerLanguageOption<bool> AutoFormattingOnReturn = CreatePerLanguageOption(OptionGroup.Default, nameof(AutoFormattingOnReturn), defaultValue: true, | ||
| storageLocations: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Auto Formatting On Return")); |
There was a problem hiding this comment.
this option location is very specific to VS. so I am not sure what it means that Workspace layer saving option to place where it is specific to VS.
There was a problem hiding this comment.
the option itself is a bit strange. it's used in one place:
public static bool ShouldUseSmartTokenFormatterInsteadOfIndenter(
IEnumerable<AbstractFormattingRule> formattingRules,
CompilationUnitSyntax root,
TextLine line,
OptionSet optionSet,
CancellationToken cancellationToken)
{
Contract.ThrowIfNull(formattingRules);
Contract.ThrowIfNull(root);
if (!optionSet.GetOption(FormattingOptions.AutoFormattingOnReturn, LanguageNames.CSharp))
{
return false;
}Which is in the indentation service itself. I think it's a way to allow us (potentially for manual testing purposes) to opt out of smart-indent. It's a bit wonky, but i'm not sure to do about it. We could try to figure something else out once the following two PRs go in here.
|
@heejaechang if you want, feel free to merge in. I'll move ahead with teh followup PRs and we can then decide how best to structure the options here. |
|
@heejaechang can you please merge in? |
|
ping @heejaechang |
|
Thanks! |
|
@heejaechang Did you squash this PR? I've having a heck of a time trying to merge it into all my other branches :-/ |
For reasons that have never been quite clear to me, our indentation services were defined at the EditorFeatures layer (maybe because they thought it was an editor concept?). This was especially odd as similar features (like Formatting) are defined at the Workspaces layer.
This change simply moves things down to the Workspace layer (while also keeping around and obsoleting the existing editor-interfaces since they are consumed by F#/TS/JS).
This makes thigns much cleaner, and makes it possible to push other features down (like the wrapping-code-actions).