Skip to content

Move indentation services down to Workspace layer.#33978

Merged
heejaechang merged 18 commits intodotnet:masterfrom
CyrusNajmabadi:moveIndentationDown
May 28, 2019
Merged

Move indentation services down to Workspace layer.#33978
heejaechang merged 18 commits intodotnet:masterfrom
CyrusNajmabadi:moveIndentationDown

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

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).

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner March 8, 2019 23:45
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tagging @dpoeschl @sharwell

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@dotnet/roslyn-infrastructure @jasonmalinowski @jaredpar

Do you know what causes this error on pipelines:

 IlAsmDeploy -> F:\vsagent\1\s\artifacts\bin\IlAsmDeploy\Debug\netcoreapp2.1\win-x64\IlAsmDeploy.dll
F:\vsagent\1\s\src\Tools\ILAsm\IlAsmDeploy.csproj(46,11): error MSB4006: There is a circular dependency in the target dependency graph involving target "_PublishILAsm".

?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

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?

@heejaechang
Copy link
Copy Markdown
Contributor

we have 3 different scenario.

  1. format - people issue format command
  2. indentation - people ask where caret should go on blank line
  3. auto formatting - this do bunch stuff
    a. if it is one of certain token like ";" or "}", it finds starting point (which is heuristic on what considered as starting point) and format those span.
    b. if it is enter, then it sees whether caret was before certain token like { or whether it is at the start location of token, and whether it is enter on a whitespace, and do things differently. here it is full case by case people added as people get feedbacks.

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.

@heejaechang
Copy link
Copy Markdown
Contributor

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.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

CyrusNajmabadi commented Mar 9, 2019

Could you clarify what the intended split is across all three indentation systems today? To help, i asked this question:

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?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

we have 3 different scenario.

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?"

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Let me try to ask teh question as simply as possible:

We have:

internal partial class SmartIndent : ISmartIndent

And

internal class SmartTokenFormatterCommandHandler

Both are responsible for figuring out where to place the care after enter is hit. My questions are these:

  1. Why do we have both of these?
  2. What determines which logic each is responsible for?
  3. Why can't we just merge the logic of these into the other?

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!

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

I guess it is time to clean things up here.

Alright, i'll see what i can do.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

I guess it is time to clean things up here.

@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.

Copy link
Copy Markdown
Contributor

@sharwell sharwell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensuring this gets a design review to determine the approach we want for two specific items:

  1. Are type forwarders preferred to redefining types?
  2. We have active plans to eliminate external code depending on these interfaces, and need to determine which we want to pursue first.

@sharwell sharwell added Blocked Need Design Review The end user experience design needs to be reviewed and approved. Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee. labels Mar 9, 2019
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Ensuring this gets a design review to determine the approach we want for two specific items:

Are type forwarders preferred to redefining types?

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.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

We have active plans to eliminate external code depending on these interfaces, and need to determine which we want to pursue first.

Can you explain these plans? What's the recommended way for a 3rd party language to participate in indentation?

@sharwell
Copy link
Copy Markdown
Contributor

sharwell commented Mar 11, 2019

Can you explain these plans?

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.

#31393

What's the recommended way for a 3rd party language to participate in indentation?

Through the public API.

@sharwell
Copy link
Copy Markdown
Contributor

sharwell commented Mar 11, 2019

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.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

What public API are you referring to?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@CyrusNajmabadi Can you file an issue tracking removal of the newly obsolete API and link it from the code?

@tmat Done!

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@tmat feel free to merge when you havea chance.

@tmat
Copy link
Copy Markdown
Member

tmat commented May 23, 2019

@heejaechang @sharwell OK to merge?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@heejaechang @sharwell OK to merge?

Ping. Thanks!

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@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.

@jinujoseph
Copy link
Copy Markdown
Contributor

spoke to @heejaechang , he will take a look at it soon.

@sharwell sharwell removed the Blocked label May 24, 2019

namespace Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral
{
using Microsoft.CodeAnalysis.Indentation;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to where other using is?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't. if we move it, then diffrent symbols will be found in Microsoft.CodeAnalysis.Editor.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is tracked with: #35872


namespace Microsoft.CodeAnalysis.Editor.Implementation.Formatting.Indentation
{
using Microsoft.CodeAnalysis.Indentation;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this for things like typescript or F#?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup!

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>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where it go?


namespace Microsoft.CodeAnalysis.Editor.Wrapping.BinaryExpression
{
using Microsoft.CodeAnalysis.Indentation;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@heejaechang heejaechang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me!

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@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.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@heejaechang can you please merge in?

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

ping @heejaechang

@heejaechang heejaechang merged commit 5e10660 into dotnet:master May 28, 2019
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Thanks!

@CyrusNajmabadi CyrusNajmabadi deleted the moveIndentationDown branch May 28, 2019 21:23
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@heejaechang Did you squash this PR? I've having a heck of a time trying to merge it into all my other branches :-/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants