[Pre-RFC] Alignment token for column formatting of code


#1

Summary

Make formatting code in columns easy by introduction of alignment token β€˜β€™. The token will be used by rustfmt for automatic columns alignment and ignored by rustc.

//Regular style before rustfmt
let x\ = 1;
let x_multiplied_by_two\ = 2;
let x_times_3\ = 3;

//Column formatted after rustfmt
let x                  \ = 1;
let x_multiplied_by_two\ = 2;
let x_times_3          \ = 3;

#Motivation There is a timeless discussion whether some parts of code should be formatted in shape of columns. The gain of wisely used column formatting is readability, but the cost is hard maintenance. Creation and every modification of such code is slow and tedious.

The creators of official Rust coding style guidelines decided to explicitly forbid this technique. Another reason to do this could be impossibility to detect and handle such formatting by rustfmt.

Token driven automation of formatting will bring the best of both worlds: no need for whitespace management, elegant code and fine control over its shape, all in cooperation with rustfmt.

#Detailed design The backslash has currently no meaning outside of text literals, so introduction of β€˜β€™ token won’t break any syntax, but it has to be ignored by rustc.

The columns will be managed uniformly across blocks of code. A block of code will be a series of neighboring lines with the same number of β€˜β€™ tokens in each of them.

let a  \ = fun1(     \"block 1");
       \ //          \ block 1
let bbb\ = function2(\"block 1");
let c\ = "block 2";
let d\ = "block 2";

let eee\ = "block 3";

Rustfmt will do the following:

  1. Identify the first block
  2. In each line of block find the first β€˜β€™ and remove all spaces right before it
  3. Get position of the first β€˜β€™ in each line of block and find the highest value
  4. In each line of block insert spaces right before the first β€˜β€™ so that its position equals the highest value found in point 3
  5. Repeat steps 2-4 for the second β€˜β€™ in lines of block, then third and so on
  6. Identify the second block and repeat steps 2-5 for it, then for the third and so on

#Drawbacks

  1. It will add another element to already complicated Rust grammar.
  2. It will take over backslash, which might be needed for a more important syntax extension.
  3. It will give programmers some freedom of choice of formatting, which always leads to argues.

#Alternatives Things can stay the way they are.

#Unresolved questions

  1. Should there be inserted at least one space before β€˜β€™ to separate it from the longest line of previous column?
  2. Should there be inserted exactly one space after β€˜β€™ to separate it from the next column?
  3. Should the β€˜β€™ token be replaced with '\ ’ (backslash and space)? This will complicate the syntax, but will open the possibility of creation of whole family of autoformatting tokens. For example there could be β€˜>’ or β€˜~’. I have no idea, what they could be used for.

#2

I think the complexity and odd look of this proposal outweigh the benefits. It makes Rust weirder to people coming from other languages and we have more impactful things to spend our language strangeness budget on.


#3

I believe this makes much more sense as a formatting tool itself, rather than patching rustc just for code formatting purposes. Note that this would require a change in the parser/lexer and the addition of a new keyword/symbol, and we have a history of keeping the syntax relatively stable after 1.0. The proposal as it stands is heavily stacked against implementing this change - I don’t see much value in making drastic changes to the compiler just because we want to avoid/prevent arguments over code styling.


#4

The best solution would probably be to stay with the current style, but have your editor render it as if the =>, :, … are aligned. This way the diffs stay clean and it is easily readable.

elastic-spaces > elastic-tabs, if only because tabs are not idiomatic in Rust


#5

Another solution that would not involve changing the language would be that rustfmt perform alignment if there is more than just one space before the β€˜=’ sign.


#6

Another solution would be to use elastic-tabs in your editor.

the separator in the source code will be a single tab character instead of the space character and you’d rely on your editor’s capabilities to align this properly for display purposes. Same thing can be also implemented for rustdoc as well.