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

Formatting: recognize tab and multiple spaces as whitespace for custom alignment #16088

Open
Thaina opened this Issue Dec 23, 2016 · 18 comments

Comments

10 participants
@Thaina
Copy link

Thaina commented Dec 23, 2016

roslyn formatter will format
int i=0;
into
int i = 0;

Something like this

But then I always use

int i	= 0;
long l	= 0;
//smart tab aligning

When format document it became

int i = 0;
long l = 0;

So I wish that formatter about spacing will just see that tab, tabs, and spaces is also whitespace and ignore it if it is there, else will insert a space into it

@Thaina Thaina changed the title Is it possible to have code formatter accept tab and many spaces as whitespace Is it possible to have code formatter accept tab and multiple spaces as whitespace Dec 23, 2016

@tamlin-mike

This comment has been minimized.

Copy link

tamlin-mike commented Dec 26, 2016

This is something that has disturbed me for decades (I'm not joking) with Visual Studio. It completely lacks any way to state "Don't reformat this section of code!" - no matter the source code language.

IntelliJ IDEA has it (since many years) using comment tags, and I'd be surprised if Rider didn't also inherit it. Just mentioning this to light a fire under the chair of the ones responsible at Microsoft. :-)

@jnm2

This comment has been minimized.

Copy link
Contributor

jnm2 commented Dec 27, 2016

In general IDE reformatting is useful because it saves keypresses, but once in a while it's irritating. Especially around case scoped blocks.

Also, whitespace like this is huge for maintainability, and this is only a simple example:

static ulong BigEndianToUInt64(byte[] bigEndianBinary)
{
    return ((ulong)bigEndianBinary[0] << 56) |
           ((ulong)bigEndianBinary[1] << 48) |
           ((ulong)bigEndianBinary[2] << 40) |
           ((ulong)bigEndianBinary[3] << 32) |
           ((ulong)bigEndianBinary[4] << 24) |
           ((ulong)bigEndianBinary[5] << 16) |
           ((ulong)bigEndianBinary[6] <<  8) |
                   bigEndianBinary[7];
}

I find blocks like that reformatted at strange times when I didn't even touch it.

@Pilchie

This comment has been minimized.

Copy link
Member

Pilchie commented Dec 31, 2016

For the first case - while we don't have alignment like that built in, you can change the option at Tools\Options\Text Editor\C#\Code Style\Formatting\Spacing to ignore the spaces around operators to allow you to control it manually:

image

@Pilchie

This comment has been minimized.

Copy link
Member

Pilchie commented Dec 31, 2016

Also see these issues:

Formatting: Add option to not perform any auto-formatting (#8263)
Add an option to apply code formatting to collection initializers (#8269)

@Pilchie Pilchie added this to the Unknown milestone Dec 31, 2016

@Pilchie Pilchie changed the title Is it possible to have code formatter accept tab and multiple spaces as whitespace Formatting: Support aligning multiple assignments based on their = Dec 31, 2016

@Pilchie Pilchie referenced this issue Dec 31, 2016

Closed

Support enforcing "Code Style" in the IDE #7071

8 of 42 tasks complete
@tamlin-mike

This comment has been minimized.

Copy link

tamlin-mike commented Jan 3, 2017

Another issue but very related to this, is that the editor still think alignment == indentation (this problem is also decades old in the VS series of editors).
Snipping from jnm2's example:

I   static ulong BigEndianToUInt64(byte[] bigEndianBinary)
I   {
I   I   return ((ulong)bigEndianBinary[0] << 56) |
I   I   AAAAAAA((ulong)bigEndianBinary[1] << 48);
I   }

I = Indentation
A = Alignment.

I is the indentation level selected by the user. TAB works best, since it saves on code size and allows the users to read the code at whatever indentation size they prefer.

But when we come to the alignment part, VS insist on using tab's there too, as if indenting, when it should really only use tab up to the indentation level, and then spaces for the alignment.

I came across an extension called Elastic Tabstops that at first blush looked like pure brilliance, since it would replace all space characters used for alignment with a single tab character, but it faces the problem that such a feature would have to be supported on all possible editors (incl. vi) for it to be truly viable, but its heart seems to be in the right place. Perhaps that could provide some ideas to the editor team?

@Thaina

This comment has been minimized.

Copy link

Thaina commented Jan 3, 2017

Well, by there are various convention and familiarity of each person. I still think the best solution is to let formatter accept tab and multiple spaces as whitespace

The point is whenever people do their custom spacing. Using tab or space or anything to make whitespace. Should be satisfied that insert space formatting rules to

So @Pilchie I think I would like my request title to be the same

@Pilchie

This comment has been minimized.

Copy link
Member

Pilchie commented Jan 3, 2017

@Thaina In that case I don't understand what your proposal is. How is allowing any arbitrary set of tabs and spaces at any point where the formatter currently expects a single space any different from just disabling formatting altogether?

@Thaina

This comment has been minimized.

Copy link

Thaina commented Jan 3, 2017

@Pilchie My point is each person might have their own custom convention of spacing. One may use tab somewhere but other points should be under standard rule. That is the most used case in my opinion

In my case I like 1tab+=+1space for alignment only at declaration. But every other operator should always be 1space+op+1space. However it must not ignore when there are no space. I wish it must enforce space but when I

And I don't always need to align declaration in the same line. I only want 1tab for aligning

Such this is OK

int i	= 0;
long l	= 0;
Dictionary<string,int> D	= new Dictionary<string,int>;
Dictionary<string,Dictionary<string,int>> DD	= null;

for me this below is not cute

int i						= 0;
long l						= 0;
Dictionary<string,int> D			= new Dictionary<string,int>;
Dictionary<string,Dictionary<string,int>> DD	= null;

Well, I think formatter should give us just some freedom under the rules. Ignore what already satisfied the rules is better than make a rules to always cover every specific things. It's too harsh to have only option to obey or being ignored

@Esidar

This comment has been minimized.

Copy link

Esidar commented Feb 2, 2017

While we're on the subject, I don't mind to align multiple assignments manually, however what really irritate me is that auto-formatting removes those spaces when option "Ignore spaces in declaration statements" is unchecked, which is fine, but with option checked it removes Tabs and replaces them with spaces.

So currently those spaces are either removed, or tabs are replaced with spaces. Ideally "Ignore spaces in declaration statement" would keep spaces when "C#->Tabs->Keep Tabs" is checked.

@Thaina Thaina changed the title Formatting: Support aligning multiple assignments based on their = Formatting: recognize tab and multiple spaces as whitespace for custom alignment Feb 4, 2017

@ulln

This comment has been minimized.

Copy link

ulln commented Sep 28, 2017

If we could use a special whitespace character for alignment, VS could ignore this character completely when auto-formatting.

There are several unicode characters we could use:
https://en.wikipedia.org/wiki/Whitespace_character

For example:
U+00A0 (NO-BREAK SPACE) or U+2007 (FIGURE SPACE)

I think it would solve the alignment and formatting problems since VS should display it as normal space but ignore it otherwise. Does this make sense?

Currently in VS 2017 it seems those characters can't be used at all...

@nickgravgaard

This comment has been minimized.

Copy link

nickgravgaard commented Oct 24, 2017

Could I suggest using my elastic tabstops invention? You can try it by downloading this demo app, and running it with java -jar ElasticNotepad.jar. The code for the reference implementation of elastic tabstops this uses is here: elasticTabstops.scala

Elastic tabstops is already used by a growing number of editors and tools, including the gofmt tool developed by Google for use by Go programmers, and I have just open sourced my old extension for Visual Studio and updated it for VS 2017 (it's written in C#, but I think the Scala code I linked to above is definitely the better implementation, and it should be relatively straight-forward to port it to C#).

Elastic tabstops can be used in the following ways:

  1. In a text editor/IDE to move tabstops to keep text aligned as the user types code. Files are saved exactly how they are in the buffer.
  2. As an optional variant of 1, but files are converted to use spaces or traditional mod-N tabs on saving, and to elastic tabstops when loading. Since many tools do not understand elastic tabstops' way of interpreting tab characters yet, it may make sense for this option to be enabled by default.
  3. To "pretty print" files (this is what gofmt does). gofmt parses the code specified by the user, creates intermediate code with a tab character before each piece of text that needs to be aligned (as per elastic tabstops), and then converts the intermediate code to generate space or traditional mod-N tab indented final code. Someone at Google made a nice slideshow which includes an explanation of how and why they use elastic tabstops.

I think elastic tabstops fits your requirements very well, and I made sure it is unencumbered by any patent or other intellectual property issues. It is a popular idea (if you search for it you'll see when it's mentioned it's usually considered the best solution to any text alignment issues), but it suffers from a bit of a chicken and egg problem. I think being adopted by .NET would help solve that problem, and any problems can be mitigated by always allowing users to save in traditional formats (or by just using it as an intermediate format like gofmt).

Finally, for a long time, Apple has claimed to be the platform for people who care about typography. Since elastic tabstops makes it possible to use proportional fonts, this might be a way of beating them on this front. Programmers spend 7 or 8 hours a day staring at code. Wouldn't it be nice if we didn't have to use ugly monospaced fonts? And wouldn't it be great if everyone on a project could have different display settings (fonts and indent sizes) while sharing exactly the same code? What about code that stays aligned even if you rename a variable in a large code base, without reformatting adjacent lines? Elastic tabstops gives you all of this.

@Esidar

This comment has been minimized.

Copy link

Esidar commented Oct 25, 2017

"Wouldn't it be nice if we didn't have to use ugly monospaced fonts?". No. Code formatting is all about order and structure. Proportional font is anything but order. Proportional is good for reading 1D stream of characters, row by row. Code is about 2D view where rows and columns matter.
Just an opinion and personal preference.

@nickgravgaard

This comment has been minimized.

Copy link

nickgravgaard commented Oct 25, 2017

@Esidar Elastic tabstops is all about structure, just one based on tab separated columns rather than a 2D monospaced character grid. When you think about it, tab separated columns is arguably a better fit for what we're dealing with a lot of the time in code files - variable names and values, or code and comments, or nested blocks. And if you want to use monospaced fonts you still can - it's just not forced on everyone in the team.

But that's all if you use elastic tabstops to keep code aligned as you type in your editor/IDE. If you go the pretty-printer route (like gofmt), the elastic tabstops format is just used as an intermediate format and the output is the traditional 2D monospaced character grid you're used to.

@Esidar

This comment has been minimized.

Copy link

Esidar commented Oct 26, 2017

@nickgravgaard I was referring to "proportional fonts" not "elastic tabstops". I don't care if VS will incorporate elastic tabstops :)

... of course as long as there will be option to disable it. People fight on internet over spaces vs tabs :) That's because it changes keyboard navigation (how various key combinations work, the way the cursor moves, etc). I'm assuming your solution is using spaces to format text. Converting all files to spaces only is rather a big deal and not "fits all solution".

@farteryhr

This comment has been minimized.

Copy link

farteryhr commented Jan 3, 2018

@nickgravgaard i'm for elastic tabstops too!
i came up with this idea independently and implemented my own version (in VB6 lolol) several years ago, before i could find your work with the keyword "elastic". no word can describe how satisfying it is when i found yours.

for this issue, this is the solution, both conceptually and practically, also backward compatible.

it's hard to decide whether a slice of whitespace is for alignment or not if they are just \x20's (even worse, a mixture of several \t's and \x20's). if it's easy, it won't need much discussion here.

@nickgravgaard

This comment has been minimized.

Copy link

nickgravgaard commented Jan 3, 2018

@farteryhr I'm not on a Windows machine right now, so I can't try your program. Is the source code anywhere for me to look at?

In well formed code, single spaces are usually used to separate tokens. So when converting from elastic tabstops to spaces, tab characters must always be replaced by at least 2 spaces. Then, when converting back to use elastic tabstops, single space characters are left alone and runs of multiple spaces are replaced by tabs. The best thing is to try my demo app (in particular, try changing the code and then toggling Elastic mode on and off) and look at the code.

@farteryhr

This comment has been minimized.

Copy link

farteryhr commented Jan 6, 2018

@nickgravgaard i open-sourced it just now (didn't do it before because the i know code is actually too shitty...)
it is slow on every other operations especially rendering, but it loads big files faster than yours~ (slap)
it has some other features such as rendering empty lines (those with only brackets and semicolons) with less space, and maybe more to be added.

btw you may try to setup wine with vb6run or something in order to run it on *nix.

@sharwell

This comment has been minimized.

Copy link
Member

sharwell commented Oct 2, 2018

For the purpose of the design review outcome, this is a duplicate of #28729. I will follow up there with next steps.

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