Roslyn: Need to be able to disable smart semicolon positioning

Created on 9 Aug 2019  路  16Comments  路  Source: dotnet/roslyn

Version Used:
16.1.3

Steps to Reproduce:

  1. Create a new C# console app
  2. Inside a method body, type Console.WriteLine() (without a semicolon)
  3. Place the caret inside () and type ;

Expected Behavior:
Should insert the caret where typed

Actual Behavior:
Inserts the caret after ()

Reported by @jfrijters

As far as I can tell this must be a relatively new feature - one needs to be able to turn it off

Area-IDE Blocked Concept-Continuous Improvement Need Design Review

Most helpful comment

When I'm editing, the code is often in an intermediate state (i.e. not valid C#), so the editor cannot safely reason about it. It is incredibly annoying that the editor thinks it knows better. It frankly boggles the mind that anyone would introduce a feature this intrusive without an off switch.

All 16 comments

cc @sharwell

The feature will not move a semicolon placed in any location where the language allows it. We are planning to implement undo support for the feature (https://github.com/dotnet/roslyn/issues/36945#issuecomment-516164241), specifically to handle cases where a user unintentionally types a semicolon.

When I'm editing, the code is often in an intermediate state (i.e. not valid C#), so the editor cannot safely reason about it. It is incredibly annoying that the editor thinks it knows better. It frankly boggles the mind that anyone would introduce a feature this intrusive without an off switch.

@jfrijters The algorithm accounts for intermediate states. There are only two known cases where it moves the semicolon and a user really wouldn't have wanted it:

  1. The user is typing in reverse (as in literally typing a statement from end to beginning, starting with the semicolon)
  2. The user accidentally hit ; when trying to type something else

There are also a handful of users that don't want _any_ IDE assistance when typing. We may tie this feature to a global "disable all IntelliSense" option in the future to account for these users.

The algorithm obviously doesn't account for my way of working, because it has been annoying me ever since I switched to 2019. TBH, it is very annoying because I cannot even imagine any scenario were I would ever want this behavior.

We absolutely need a switch to turn it off. When an editor doesn't let you edit your text with full control over each character, it stops being a text editor.

That said, @jfrijters it would help immensely if you documented a couple of scenarios in which it gets in your way (initial code and set of keystrokes, your expected behavior vs. actual behavior). Maybe it will help the feature designers understand your flow and think of usage scenarios they haven't considered.

Here's my personal concern. Even ignoring all the above relevant point, I haven't yet encountered a case where i want this behavior or have found myself adapting to this behavior. Contrast that with may other features (auto-formatting, auto-braces, etc.) where i can see the value and gently adjust my typing to take advantage of it.

With the semicolon-insertion... i'm not actually sure what the value is. Like how am i expected to use it? If i was explainin it to a new user, how would i pitch this to them as to why they would want this?

@chborl ?

Thanks!

@CyrusNajmabadi If you are not using this feature, then you are always doing more work than is required to insert the semicolon at the end of a statement that ends with one or more closing parentheses followed by a semicolon. There are many ways to relocate the caret, but this is the only one that doesn't require you to take explicit action.

The value of the feature will be substantially increased when argument inference is added. Once the user is happy with the remaining arguments of the current call, pressing semicolon will move past all subsequent arguments to the end of the call, and add the semicolon.

Ok. So the intent of hte feature is this: I write out something call-like. Because of brace-completion, my caret will be in the argument-list of the call-like thing. I then write out my arguments. I then hit semicolon to indicate completion?

In that case, should it be the case that the feature should only trigger in the following cases:

  1. you're in the arg list.
  2. you're between an arg and the following comma, or an arg and the following close brace.

Right now, i feel like i've experienced the semicolon triggering behavior not in those cases. However, i will have to experiment to see if that's the case.

Thanks!

Design review conclusion: This feature had some bugs that negatively impacted the experience for early adopters. We believe that a combination of fixes for those bugs (already done) and proper support for the undo stack (to match what we do in other implicitly trigger cases) will address the concerns of a majority of users. Once both of these are addressed, if users are still concerned we are particularly interested in understanding _specific_ workflows that are problematic. So this is temporarily deferred in favor of #37577, and we can review it again in the future if necessary.

What are the other cases? I can't think of a single situation where I want VS to start moving the caret around of it's own accord, and ignore what I just typed and think that it knows better. I filed this issue under VS Feedback and was directed here. See https://developercommunity.visualstudio.com/content/problem/795161/text-editor-issue-cant-insert-semicolon.html

I came across it when writing mathematical expressions. It doesn't matter what the expression is really. Semicolons can be used to cut into the line, redefining the EOL. Really simple example ..

float u = (float) (x / delta);

.. oops that's not working. I'll have to try something else ..

float u = (float) (x ; // / delta);

A temporary semicolon is used to cut off the end of the line, I actually intend the compiler error now because I know this line is incorrect. But I'll keep the '/ delta);' around because I thought that should have worked. Not sure what the denominator should be. Let me try this ..

float u = (float) (x / gamma); // / delta);

See how I'm free to cut up the text how I please. It shouldn't matter what text i use. If I type a semicolon in the middle of the line, don't you think that is exactly what I intended? I could use

; //
//
* this doesn't work *
WTF

It shouldn't matter what I type, that's what i intended. I honestly cannot see how auto-correction / auto-grammar / auto-syntax or whatever this is, is going to work in programming.

"Once the user is happy with the remaining arguments of the current call, pressing semicolon will move past all subsequent arguments to the end of the call, and add the semicolon." - Maybe TAB will be a better choice.

float u = (float) (x / delta);

.. oops that's not working. I'll have to try something else ..

float u = (float) (x ; // / delta);

For this particular case, if you type );//, the editor will not interfere with your typing. The additional ) character relative to the text you were already typing is something you already needed to type in order to end up with your final example.

Note that this particular case falls into two special cases:

  1. You are typing in reverse (starting with ; at the end of a statement, then moving backward to type the ) in front of it).
  2. We need to make Undo work properly with this feature (i.e. after typing ; and having it move to insert the ;, pressing Ctrl+Z will move the ; back to the location where it was originally typed).

Maybe TAB will be a better choice.

Tab is already incorporated into the brace matching feature, but there are a few key differences:

  1. Tab moves outside one matching brace pair, but ; moves outside multiples if necessary.
  2. Tab does not insert a missing ; character.
  3. Tab will move outside matching } characters at the end of a code block, but ; will only move outside the closing delimiters of the current statement.

The semicolon insertion feature is a very efficient way to end the current statement when typing new code. We're still working to make sure it works well for cases where users editing existing code, and while most such cases have already been addressed there are a couple outstanding edge cases still under consideration.

Here's another repro:

            var quietMeasure = new MeasurementHolder(
                new StressUtilOptions()
                    {
                                await Task.Yield()
                    }
                );

Can't type ";" after the Yield(). This is very confusing and seems to the user that it's a bug. Syntactically, it may make sense with the current text, but it's text that is currently being edited, which means the user is in the middle of editing text and expecting Typed chars to be inserted like notepad

Putting this simply - editor effectively prevents you from typing the character where you intend to put it. How is this a feature?

@sharwell There are only two ways of triggering it if you write new code. I'm hitting this problem several times a day when I rewrite existing one. When you need to refactor something do you remove everything and start fresh? Do you keep your code to be ALWAYS syntactically correct? I start in the middle of a method call if I feel like it and don't care about it compiling until I'm done.

Even in case of typo - how does moving me out of context and inserting unnecessary character in random place help me fix it?

I don't understand the opposition against fixing this behavior (by providing a switch to turn it off). Far less intrusive and more reasonable features have their switches. And not bundled under "disable all the useful features and the single annoying one" option.

@calvinhsia The case you mention in https://github.com/dotnet/roslyn/issues/37874#issuecomment-580844443 was intended to work, so we should fix it.

@dstarkowski The case you mention in https://github.com/dotnet/roslyn/issues/37874#issuecomment-743228136 is really another example of this feature needing to support Undo operations (which puts the ; back where it was originally typed).

The opposition to making this an option boils down to two things:

... editor effectively prevents you from typing the character where you intend to put it ...

Even if the editor doesn't prevent you from typing the character, the language will. The feature does not trigger in cases where the language might allow a semicolon at that location. All current cases of faulty triggering (where Undo is needed) are cases where ; was typed accidentally (typically instead of ,). For some syntaxes, this is unfortunately quite easy to do.

Second, this feature is needed for the ongoing work on #12363.

In other words, rather than make the feature an option, we need to fix the edge cases where the feature causes pain. At that point, whether or not the feature is used it will not be a problem to have it enabled.

Was this page helpful?
0 / 5 - 0 ratings