Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect: Entering a # character forces all preprocessor entries to be reindented #2487

Open
dotnet-bot opened this issue May 4, 2015 · 54 comments
Assignees
Labels
Area-IDE Bug help wanted The issue is "up for grabs" - add a comment if you are interested in working on it IDE-Formatter Code formatter and/or smart indent
Milestone

Comments

@dotnet-bot
Copy link
Collaborator

Ported from TFS WorkItem: 1160552


Repro Steps:

This item was filed by a customer. Please communicate and close the loop with your customer via the customer tab inside TFS.


Problem Description


Hi,

Entering a # character forces all preprocessor entries to be indented again, even when all formatting options have been disabled. It also displaces some "}"s

My setup is: automatical formatting fully disabled , tabs size=4, keep tabs, indenting=none

I'm supplying two images to ease the explanation.

  • Put your code like in image 1. Please note that there's a tabulation before "static void myfunc ()", so #if COND1 is not at the beginning of the line.
  • Put the cursor where the cursor is in the image 1
  • Type #
  • The #if COND1 is automatically indented, and the closing bracket is moved to the right (shown in image 2)

image1: https://dl.dropboxusercontent.com/u/49509038/img/vs2015_ctp6/img1.png

image2: https://dl.dropboxusercontent.com/u/49509038/img/vs2015_ctp6/img2.png


Revisions:

  1. Created By Microsoft Connect (4/21/2015 4:46:12 AM)

------------------------

Customer Information

------------------------

User ID: 10125130

Handle: KakCAT



---------------------------

Connect Site Information

---------------------------

Site Name: Visual Studio and .NET Framework

Site ID: 210

Feedback ID: 1266613

Feedback Form: 6049



----------------------

Problem Description

-----------------------

Hi,

Entering a # character forces all preprocessor entries to be indented again, even when all formatting options have been disabled. It also displaces some "}"s

My setup is: automatical formatting fully disabled , tabs size=4, keep tabs, indenting=none

I'm supplying two images to ease the explanation.

  • Put your code like in image 1. Please note that there's a tabulation before "static void myfunc ()", so #if COND1 is not at the beginning of the line.
  • Put the cursor where the cursor is in the image 1
  • Type #
  • The #if COND1 is automatically indented, and the closing bracket is moved to the right (shown in image 2)

image1: https://dl.dropboxusercontent.com/u/49509038/img/vs2015_ctp6/img1.png
image2: https://dl.dropboxusercontent.com/u/49509038/img/vs2015_ctp6/img2.png


  1. Edited By Macy Qu (Shang Hai Wei Chuang Ruan Jian) (4/21/2015 8:11:12 PM)

repro on Win8.1 with VS2015 CTP6


@KakCAT
Copy link

KakCAT commented May 5, 2015

Hello,

I'm the original bug reporter. I decided to create a self explaining CS file to ease the bug hunt:

http://online.ru-zero.com/files/test.cs

Thanks!

@basoundr
Copy link
Contributor

basoundr commented May 5, 2015

Thanks @KakCAT. Thank you for the feedback. We will be addressing the issue soon.

@Pilchie Pilchie assigned mattwar and unassigned basoundr May 8, 2015
@mattwar
Copy link
Contributor

mattwar commented May 15, 2015

The # key is a trigger character for formatting. It automatically formats the region before and after the #. This entails all trivia between the previous token and the next token after the #. All of the directives in the sample are part of the trivia between the # and the next token, so they all get formatted.

The sample has text that is not currently at the proper indentation level. All of the text in the format range gets indented to the proper level, this includes the directives, shifting all the way to the left and the method call, getting shifted to the right, but none of the surrounding type or method declarations get adjusted because they are outside of the auto formatted region.

AFAICT this is the expected and intended behavior of the formatter.

@Pilchie any thoughts?

@KakCAT
Copy link

KakCAT commented May 15, 2015

Hello,

I don't know if this is correct or not, but my opinion is that in case it is correct, there should be a way to disable it, as well as automatical format can be disabled on ; , on } and on paste.

Reformatting shouldn't be enforced on any case if the user doesn't want to use it.

@mattwar
Copy link
Contributor

mattwar commented May 15, 2015

This one doesn't look like its going to be easy to fix, not without a lot of rewrite of the command handlers or the formatter. The formatter only operates between tokens and since the # is part of trivia it doesn't count as a token. All special action keys other than ENTER are handled by the format command handler, which just formats. The ENTER key has its own command handler that possibly uses the smart indenter (but in some circumstances uses the formatter). It looks like this scenario would be better served by the smart indenter and not the formatter, but I'm not certain of all the ramifications of that change. Possibly the formatter needs an overhaul.

As for options, there currently only options to control formatting when ; or } are typed. All other keys that trigger formatting have no option, so they default to on.

@Pilchie Pilchie modified the milestones: 1.1, 1.0 (stable) May 18, 2015
@Pilchie
Copy link
Member

Pilchie commented May 18, 2015

Moving out to 1.1 based on Matt's assesement. Note that this only an issue around comments - if there are real tokens inside the preprocessor directives, this isn't as bad.

@KakCAT
Copy link

KakCAT commented May 18, 2015

Hi,

shouldn't there be a switch where all autoformatting is disabled?

I mean, this may or not may be important, but I'd really prefer to completely disable autoformatting if typing a '#' in my code is going to mess all my format. Right now my only option is keep using VS2013 and switch to VS2015 to compile when required.

@Pilchie
Copy link
Member

Pilchie commented May 19, 2015

@KakCAT You are right - this behavior should NOT occur when the Indent Style option is set to none or block. I filed #2907 to track that.

@Pilchie
Copy link
Member

Pilchie commented May 20, 2015

Note that connect bug http://connect.microsoft.com/VisualStudio/feedback/details/1247309/gets-wrong-indentation-for-region-and-endregion is related to this.

Once I wrap some text with #if false, we lose the indent of all the #regions when the #endif is typed.

@CyrusNajmabadi

This comment has been minimized.

@CyrusNajmabadi
Copy link
Member

and this issue (#2487) is about the '#' character causing preprocessors to be re-indented.

I thought this was not supposed to happen if you had smart-indent off. If you change this:

image

To 'None' or 'Block' do you still see # automatically updating the indentation?

@jbienzms

This comment has been minimized.

@CyrusNajmabadi

This comment has been minimized.

@heejaechang

This comment has been minimized.

@heejaechang

This comment has been minimized.

@weltkante
Copy link
Contributor

weltkante commented Sep 6, 2018

@heejaechang see mattwars comment on May 3, 2017 for a summary of a few issues

my own another bug report #25973 which was resolved as duplicate of this one, was about interactively typing (or pasting) individual preprocessor directives which are part of a pair of directives. Typing or pasting a preprocessor directive was triggering auto-format of the whole document when seeing the initial # symbol, even though the document is in an incomplete state (I'm not done typing), so the auto-format gets indentation of e.g. #region directives wrong. This causes whitespace modifications on other (unrelated) preprocessor directives which are never repaired when you continue typing and the document eventually gets back into a valid state.

Workaround is to type ctrl+z (undo) whenever you are typing/pasting preprocessor directives.

[edit] actually this was not my bug report, got things mixed up, but great if it helps anyways

@heejaechang
Copy link
Contributor

@weltkante ah, thank you for the screencast. now I see exactly what the issue is. this looks like a bug. not sure what is the actual cause. but let me assign the issue to me and see whether I can fix it.

@sharwell
Copy link
Member

sharwell commented Sep 6, 2018

📝 I'm going to collapse all the comments not related to the original issue so the person interested in working on this has a good starting place. I might get some of the reasons wrong, but there is only a very limited selection to choose from.

@heejaechang
Copy link
Contributor

@sharwell thank you! didn't know one can do that.

@sharwell
Copy link
Member

@rjmholt
Copy link

rjmholt commented Jul 10, 2020

Brought over from https://developercommunity.visualstudio.com/content/problem/1094319/region-autoindent-dedents-herestring-lines-startin.html.

I've experienced this, plus erroneous formatting of #s inside a verbatim string:

string s = @"
    # A PowerShell comment
    Get-ChildItem
";

becomes:

string s = @"
# A PowerShell command
    Get-ChildItem
";

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Jul 10, 2020

@rjmholt I don't repro this at all. Can you supply your full file that demonstrates the issue? Thanks!

@rjmholt
Copy link

rjmholt commented Jul 10, 2020

The full file I experienced this with was this one

@CyrusNajmabadi
Copy link
Member

Still can't repro the issue. Which line were you on?

@rjmholt
Copy link

rjmholt commented Jul 10, 2020

So I was making edits here.

Based on the guidance in the original issue I opened, I just experimented with editing and it occurs when new ifdefs are being added. When #else is added from the wrong indentation level and the auto-indenter kicks in, it then proceeds to indent everything after it (I assume due to the lack of a closing token), including lines starting with # in verbatim strings.

Here's a gif:

regionindent

@CyrusNajmabadi
Copy link
Member

Ah thanks! that will def help narrow what to investigate. so it's not that editing in the string caused reindentation. Rather, editing of pp-directives outside of hte string affected indentation of code inside of it. Thanks! :)

@mattwar
Copy link
Contributor

mattwar commented Jul 10, 2020 via email

@mattwar
Copy link
Contributor

mattwar commented Jul 10, 2020

It might be interesting to explore changing the c# parser to keep parsing c# tokens inside of #if'd out blocks. This way we could also colorized them (albeit dimmed).

@rjmholt
Copy link

rjmholt commented Jul 10, 2020

Once a section of code is momentarily #if’d out, it is no longer parsed as c# tokens, and is no longer thought of as containing things like keywords or verbatim strings

I assume the issue here is that PP directives can nest, so it's not until the end of the file that the parser realises it has no production to follow, meaning it can't produce an error early and move on?

With that said, I would assume a tokeniser would emit the opening PP directive as a single token ending at the newline, allowing it to resume a normal state for later scanning of things like strings — I wouldn't have expected an opening PP token to affect the way the tokeniser sees strings (or really almost any preceding tokens to affect the tokeniser, especially in a language generally as well behaved as C#).

But I'm only making assumptions about how C# is parsed based on my experience elsewhere, especially that the pre-processor isn't really a pre-processor and instead that the tokeniser/parser are responsible for consuming PP directives.

@CyrusNajmabadi
Copy link
Member

I wouldn't have expected an opening PP token to affect the way the tokeniser sees strings

It def does. Consider something as simple as:

#if false
#else

The section inside the if is meaningless until we hit the #else or #endif. We don't interpret anthing in that block. i.e. you can have this:

#if false
        Console.WriteLine(@"foo
#else
        Console.WriteLine("");
#endif

We don't interpret the @"foo as starting a string there. And, as such #else is not consumed by that string literal.

Note: this behavior is mandated by the language and cannot be changed as we have found that there is actually code out there that depends on the behavior between preprocessor directives and strings. i.e. imagine a test file that has it's own ifdefs, and it contains strings that contain pp directives in the strings. changing the lang/behavior here will completely break that.

@rjmholt
Copy link

rjmholt commented Jul 10, 2020

Ah yes that makes sense -- an unfortunate consequence of needing to emulate an actual preprocessor, where unhygienic macro semantics are expected. I can feel myself wanting to pull on this thread more, since I'm thinking about how something like C++ handles its preprocessor pragmas, but I'm guessing we'd keep hitting reasons for the behaviour and don't want to waste anyone's time.

Thanks for the discussion!

@sharwell
Copy link
Member

The primary resolution to the above issue is avoiding re-indentation of the file if preprocessor directives are not complete.

@CyrusNajmabadi CyrusNajmabadi added the IDE-Formatter Code formatter and/or smart indent label Feb 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE Bug help wanted The issue is "up for grabs" - add a comment if you are interested in working on it IDE-Formatter Code formatter and/or smart indent
Projects
None yet
Development

No branches or pull requests