[RFC] Indent with tabs#920
Conversation
| // while loop which is much faster. The while loop below adds new | ||
| // cmds to the array instead of recursively calling `print`. | ||
| let cmds = [[0, MODE_BREAK, doc]]; | ||
| let cmds = [[newIndent(), MODE_BREAK, doc, 0]]; |
There was a problem hiding this comment.
Sorry, this part - , 0 - is a leftover from old code, and should be removed.
|
The approach that I think is a lot better is to do the conversion in the lower-level printer in In the low-level printer, it'll just replace the configured number of spaces with a tab when printing out the current indent level. |
|
@jlongster Yes, there is a provision for "manually indent a specific number of spaces" - it's called "indentCustom". Don't you think it's much more clean calling simply "indentLevel()" rather than "indent(options.tabWidth)" every time? 99% of the time, you want to indent by "tabWidth". And when you must use a custom value, it's much more explicit calling "indentCustom()". Also, there is no need to "change one place" - once this lands, it won't be changed anymore. But there's another point, and I think it's even more important - you're missing the point of Also, I bet tools like ESLint will complain when you mix tabs and spaces! Nobody does that! Also, take in consideration that over 500 people downloaded prettier-with-tabs on npmjs.org alone in the last month, and not a single one of them raised a issue on github, so I guess they're satisfied 😃 Also, you can see below that all tests pass - so it keeps the correct behaviour when using spaces. Also, I can't help but feel it is a 'hacky' way to convert spaces into tabs by using math. Why not let the commands specify exactly what the code should be indented by, rather than converting it afterwards? With this solution, you've got absolute control on the place where the indentation is actually printed - here: |
Last I asked many people said that yes, they indent with additional spaces sometimes to line things up. That's one thing I don't like about tabs: for certain scenarios it requires a specific spacing to line up with something above it because additional syntax moved it the line above. People definitely do it. But yes, I do think it would be a lot less work to just do it in the low-level printer. It requires a lot less code changes, and is more straight-forward: it always just indents |
|
@jlongster Is it not a lot less work calling simply "indentLevel()" rather than "indent(options.tabWidth)" 33 times? Why do you want to repeat "options.tabWidth" so much? Like I said, this will only change once, it's straightforward, simpler, more readable and specially, gives full control! You didn't answer to the fact that the purpose of tabs are to allow each user to have their own "tabWidth" in their editor - so you're defeating the purpose of tabs, it will be broken when a user changes their editor tab width! Like @JedWatson said:
|
|
@rhengles It's less work in the lower-level printer, and we should keep that as simple as possible. It's super straight-forward: just Let me give you an example of why people mix spaces and tabs. Take this code: type foo =
| {
prop1: string,
prop3: string,
prop3: string,
}
| { prop2: string }We indent the closing brace of the first object very carefully. It's specifically one indent level + 2 spaces. We need to do this because the opening one is not indented again, it's just bumped over because of syntax. Let's say you were using tabs, indented the closing brace twice, and used 4 spaces for tabs. This is what it would look like: type foo =
| {
prop1: string,
prop3: string,
prop3: string,
}
| { prop2: string }Which is wrong. If you all are OK with that, than sure, that's fine I guess. Just weird that some edge cases are going to look wrong! |
|
Of course most indentation is still done with tabs and the programmer can choose whatever. But in a few rare edge cases we can use spaces to align things like that. |
|
One thing that I commonly here from tabs people is:
That's called "smart tabs". I see nothing wrong with prettier outputting tabs for indentation, and sometimes 2 spaces or so on top of that for alignment. |
|
Then I guess it would be necessary an option: because honestly, an option that mixes tabs and spaces is useless to me. But is that feature being actively requested by tab users or only being mentioned by space users? I didn't introduce multiple commands, I introduce one single command and rename another one. If that's the issue, we can rename them with better names. Maybe Please also imagine for a moment that somewhere, you may "manually indent something a specific number of spaces" that is longer than |
97823bc to
65e6fc6
Compare
|
@jlongster There, with the rename should be much better now. Note that this would make it trivial to also support Haven't I said already that nobody complained about my handling of tabs on |
65e6fc6 to
660e771
Compare
|
@jlongster Please take another look, with the renaming i'm sure you will love it ❤️ Ah, just to mention it - I tried the project mentioned by @Alhadis on #34, and the only issue it gives with the formatting is because of code indented inside of ternaries, where the code is indented two tabs from one line to the next, but this is expected. Would you be more willing to accept it if I also add support for |
0d5eba6 to
c68bb11
Compare
c68bb11 to
3b293b5
Compare
|
I've been chatting in person with @jlongster at React Conf and we came up with a solution that we are both happy with:
This will have minimal impact on the printer code and provide reasonable support for tabs, even for the ternary case where we indent it by a fixed amount of spaces. Do you think it's reasonable and are you interested in implementing it? If yes, I'd love to review and merge it! |
|
Thank you, @vjeux . I do not think this solution is sufficient. As a tab user, it doesn't fill my needs, and I will have to continue using I realize that you guys have reached a final decision. Is there one main reason you can't change |
|
Arg, I can't re-open the pull request as you deleted your branch. I need to think more about it. Question to you, if you have nested ternaries and other indentation, you're going to have |
|
Actually I didn't delete it, I rebased it. Github should allow it to be reopened... |
|
It turns out my comment got scrambled by github.
|
Huh ? Yes, people do that. An indentation width dependent on the reader's preferences is a major argument in favor of tabs, but loses all its interest if there is only one width where everything is aligned correctly. Smart tabs gives you the best of both worlds. "Use tabs to indent, spaces to align" is a well-known maxim and smart-tabs is already supported in many linters. I'm a strong supporter of tabs for prettier but only if it is smart tabs, otherwise it would break alignement and we'd better rename this project "uglier".
That would break alignment in many cases, such as: |
|
(1): Space alignment only work when they're at the end of the indentation, which means there cannot be tabs after "alignment spaces". (2): In the entirety of Prettier today, there's only two places that use fixed alignment. They're (3): The example you provided is not implemented in Prettier (see #850). But how would you convert the following code to tabs? const x = 1,
y = 2, // **6 spaces are required to keep things aligned
myObject = {
prop1: {
x: 1
},
prop2: {
y: 2
}
}; |
If you put tabs behind spaces in sub-expressions of a space-aligned block, it will keep things aligned but only in the context of this specific block, which may or may not be what you are expecting. For example, the code you gave in (3) looks okay as it is, but if you had another block just after, the indentation starts to be confusing: in the example below, it is not obvious that both props have the same indentation level. So in general, whether it be tabs or spaces, I would recommend for optimal readability to avoid space-aligning a block with sub-expressions. Yet Prettier cannot refactor code, and you need an answer for (3). I guess tabs after spaces would be globally less surprising, especially for large tab-width (8 spaces for most user agents on the web). But I have no strong opinion about this, since I always respect the rule mentioned above. |

I know this isn't going to be merged any time soon, but as said by @jlongster on #908, support for tabs may be considered.
Then, I'd like you to consider this implementation.