Skip to content

Add support for setting tabs/spaces preference in Tools->Options#3317

Merged
25 commits merged into
mainfrom
allichou/TabsSpacesSettings
Mar 29, 2021
Merged

Add support for setting tabs/spaces preference in Tools->Options#3317
25 commits merged into
mainfrom
allichou/TabsSpacesSettings

Conversation

@allisonchou
Copy link
Copy Markdown

@allisonchou allisonchou commented Mar 24, 2021

Summary of the changes

image

A couple of notes about what currently doesn't work:

  • UPDATE: This seems to be working now. In the lower right-hand corner of the editor, the correct current TABS/SPC option is displayed. However, switching between tabs and spaces by clicking on a different option is still not currently supported, and the current option isn't "checked" like it should be. I'm not sure why, but this will probably take more time digging into the VS side to investigate. I don't think this is is a major blocker since users can just set their preference in Tools->Options, but it's something we should look into in the future. https://github.com/dotnet/aspnetcore/issues/28003 has already been created for this.
    image
  • In the Tabs page of Tools->Options there's an "Indenting" section (see first screenshot). None of these options actually do anything, since Razor uses language-configuration.json to power indenting. All three radio buttons should probably be disabled, but current VS infrastructure seems to only support disabling "Smart" indent specifically, so I left all three for now. Created follow-up issue here: https://github.com/dotnet/aspnetcore/issues/31184

Fixes:
https://github.com/dotnet/aspnetcore/issues/30254
https://github.com/dotnet/aspnetcore/issues/27101
https://github.com/dotnet/aspnetcore/issues/28003

Copy link
Copy Markdown

@ryanbrandenburg ryanbrandenburg 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 overall, some questions about tests but if you're confident in the answers no need to block on it.

{
[PackageRegistration(UseManagedResourcesOnly = true)]
[AboutDialogInfo(PackageGuidString, "ASP.NET Core Razor Language Services", "#110", "#112", IconResourceID = "#400")]
[AboutDialogInfo(PackageGuidString, "Razor (ASP.NET Core)", "#110", "#112", IconResourceID = "#400")]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I assume this name is #PMApproved?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yep. There was an email thread a few weeks back and this was the decided upon name.

{
// Arrange
var expectedOptions = new RazorLSPOptions(Trace.Messages, enableFormatting: false, autoClosingTags: true);
var expectedOptions = new RazorLSPOptions(Trace.Messages, enableFormatting: false, autoClosingTags: true, insertSpaces: true, tabSize: 4);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I expected some settings other than insertSpaces:true, tabSize: 4 to be tested here, is the actual value of the properties just not doing anything interesting at this layer?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good point! I added some other tests in my latest push.

Copy link
Copy Markdown

@NTaylorMullen NTaylorMullen left a comment

Choose a reason for hiding this comment

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

Oh man this is exciting, really awesome to see this flow through! 👏

Copy link
Copy Markdown

@TanayParikh TanayParikh left a comment

Choose a reason for hiding this comment

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

👏 👏 👏

Just a couple nits;

{
// JToken.ToObject could potentially throw here if the user provides malformed options.
// If this occurs, catch the exception and return the default value.
return token.ToObject<T>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I forget if it's possible for this to return null. If so, would:

Suggested change
return token.ToObject<T>();
return token.ToObject<T>() ?? defaultValue;

be preferable?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hmm, the docs don't specify whether it can return null - I guess it wouldn't hurt to include just in case.

Copy link
Copy Markdown

@NTaylorMullen NTaylorMullen left a comment

Choose a reason for hiding this comment

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

90% there and looking awesome! One last blocking comment would be how you manage the attaching/unattaching from the ITextView state

{
// JToken.ToObject could potentially throw here if the user provides malformed options.
// If this occurs, catch the exception and return the default value.
return token.ToObject<T>();
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hmm, the docs don't specify whether it can return null - I guess it wouldn't hurt to include just in case.

@allisonchou
Copy link
Copy Markdown
Author

@dotnet/razor-tooling @NTaylorMullen I've pushed some changes that update the behavior in the TextViewConnectionListener. Would appreciate any feedback!

Also, I mentioned in the PR description that the active spaces/tabs option (https://github.com/dotnet/aspnetcore/issues/28003) wasn't working, but it seems I was mistaken. The user just has to type a bit in the document before being able to freely toggle between tabs/spaces. (The same behavior is observed in C#.) I've updated the PR description accordingly.

Copy link
Copy Markdown

@NTaylorMullen NTaylorMullen left a comment

Choose a reason for hiding this comment

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

Overall looks great wooohooo!! I just had some suggestions for cleanup that might be valuable / reduce the amount of work going on in the textviewconnection listener.

// All TextViews share the same options, so we only need to listen to changes for one.
_textBuffer.Properties[RazorEditorTrackedView] = textView;

var razorEditorTextViewOptions = _editorOptionsFactory.GetOptions(textView);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could you elaborate on why we need both the textview options here and the buffer ones above? Also, given that you only track one textview at a time, and assuming it's needed, it'll be important to have a good comment explaining why we only ever update options on one and not all

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added these comments to the code:

// We need to keep track of and update both the TextView and TextBuffer options. Updating
// the TextView's options is necessary so 'SPC'/'TABS' in the bottom right corner of the
// view displays the right setting. Updating the TextBuffer is necessary since it's where
// LSP pulls settings from when sending us requests.
// A change in Tools->Options settings only kicks off an options changed event in the view
// and not the buffer, i.e. even if we listened for TextBuffer option changes, we would never
// be notified. As a workaround, we listen purely for TextView changes, and update the
// TextBuffer options in the TextView listener as well.

^this latter issue was discovered via testing. I'm not sure why a Tools->Options change doesn't kick off a TextBuffer option changed event even if we listen for it, but I think this workaround works.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@gundermanc lol VS' details make me sad

var updatedTextView = _activeTextViews[0];
_textBuffer.Properties[RazorEditorTrackedView] = updatedTextView;

var updatedRazorEditorTextViewOptions = _editorOptionsFactory.GetOptions(updatedTextView);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Very interesting, so it definitely seems like the TextView option tracking is important. Will be curious to understand what this piece does. I'm sure this was a fun one to optimize against 😆

@allisonchou allisonchou added the auto-merge Squash merge once all PR checks are complete and reviewers have approved label Mar 29, 2021
@ghost
Copy link
Copy Markdown

ghost commented Mar 29, 2021

Hello @allisonchou!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merge Squash merge once all PR checks are complete and reviewers have approved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants