Fix graphical label alignment issues #202
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #87 and #97.
Turns out that reliably determining the width of a string when displayed in a terminal is impossible without using ANSI escapes to get the current cursor position. Relying on the ANSI escapes is an option, but won't work if your output isn't a TTY. Supporting non-TTY output is important for things like redirecting error messages to a file, so I implemented a mostly correct label alignment process that makes some specific tradeoffs. In the future, we could also add the escape-based option, and just fall back to this behavior on non-TTY output.
Back in #87 (comment), I had an idea for a hack to fix tab alignment while still respecting the terminal's tabstop setting. Unfortunately, I couldn't figure out a way to make this work for underlines, so the remaining option is to give up and replace tabs with spaces. This allows us to determine the visual width of the output reliably, but it does mean that we're ignoring the user's tabstop preferences. The original default behavior, where tabs were emitted verbatim and highlight alignment was broken, is pretty much never desirable, so I ended up just removing that option.
One of the issues with replacing tabs with a fixed number of spaces is that it will produce bad results if tabs are used for alignment in the middle of a line. To avoid this, we can emulate the behavior of the terminal, where tabs shift the cursor to the next tabstop rather than by a fixed width. Existing compilers that I checked seem to go both ways on this one. Gcc, clang, and rustc all emulate tabstops, while ghc uses a fixed width. I implemented the tabstop emulation option, which is a second breaking change, but this should be easy enough to swap out if we don't want it.
The other tradeoff here is that
unicode_width
isn't actually going to be able to predict the width of characters displayed on an arbitrary terminal. For example, 🏳️🌈 could show up as 1, 2, 3, or 4 columns. Predicting this is, in the general case, not possible.unicode_width
is still better than assuming every character is 1 column though, so yay for incremental improvement.Computers are a mess lol.