Closed epage closed 9 months ago
@joshtriplett
I found the requirement to call .render() and .render_reset() rather verbose, particularly when trying to render several color styles in one line. I started thinking about ways to make that more convenient, and this idea occurred to me.
Directly implementing Display
is the more obvious API design choice. Explicit render
was something I intentionally did. That doesn't mean it can't change.
Background: anstyle
s primary purpose is to exist in APIs, like clap
or env_logger
. To avoid major version bumps, the API tries to be as minimal as possible. We are not trying to "compete" with crates like owo-colors on usability as that would be scope creep and could run into regrets we can't undo. Already, it was a bit of a stretch to include the rendering of ANSI escape code (even more so for Style::reset
to exist). I went ahead with it because "its all already there" and was a reasonable minimal interpretation of the values.
Its been a while that I forgot (and I don't feel like digging through PRs if I even noted it) as to why I made render
explicit. So an off-the-cuff, unprioritized list are
The more unusual part of this PR: if you set the alternate format flag, a Style will print its reset code, instead.
Clever idea. My concerns are
{:#?}
is "pretty debug mode" and I worry that that flavors people's interpretation of #
(rather than the literal name of "alternate")#
(e.g. should a styled str be styled or not based on #
? is per-api #
ok or too confusing?)To be explicit about something: I do agree with the rationale for anstyle not having a "rendered/styled string" or "rendered/styled arbitrary Display
" type. I think that's a much more complex API that would be more likely to result in churn as new needs arise; also, such an API makes it more difficult to handle any non-trivial formatting of the string/Display
type. That's why I didn't add any kind of API that accepts an impl Display
and displays it wrapped in the style.
With that in mind, I think the fact that anstyle doesn't have or plan to add such an API avoids the most obvious source of potential concerns here.
One of my rationales for this is that with an explicit .render()
, you can't put the result in a const
, because render()
returns impl Display
. You can have a const
Style
, and use it directly in rendering in a variety of functions.
To be explicit on what the user is wanting rendered. This is a style definition first, and ansi codes second. A form of string rendering is also reasonable, if not out of scope due to too many styles (thats what some of the other crates are for).
I do appreciate this. But I personally think Debug
covers this case perfectly: Debug
of a Style
tells you the definition of the style, Display
of a Style
renders it.
People refer to
{:#?}
is "pretty debug mode" and I worry that that flavors people's interpretation of#
(rather than the literal name of "alternate")
Personally, my most common use of :#
is as part of :#x
for "please print the 0x in front of this hex number". :)
I personally suspect that most people don't think about :#
much except in the context of a specific type or rendering like this, and I think this is likely to just be one more of those: "here's what it means for this type". I don't think people are likely to port their knowledge of "this is a weird debug thing", particularly in the absence of the ?
to use Debug
.
With our goal of API stability, what is the likelihood of us regretting it. For example, if other conventions develop around # (e.g. should a styled str be styled or not based on #? is per-api # ok or too confusing?)
This is where I think it's important that anstyle doesn't have and doesn't plan to have a "styled string" or "styled arbitrary Display
" API. Because of that, I don't think there's going to be any ambiguity or question about how #
should behave.
All that said, I would like to treat these as separable possibilities: making Style
/Reset
support Display
directly, and using the alternate mode for Style
's reset. I don't think either one adds API stability risks, and I think the combination of both would provide a particularly convenient solution. But I also think the baseline of just implementing Display
would already be a substantial boost to usability.
btw another approach to const
is #160.
I do appreciate this. But I personally think Debug covers this case perfectly: Debug of a Style tells you the definition of the style, Display of a Style renders it.
To be more clear, this crate was originally not going to have any ANSI escape code support. Its been a slow slope in adding some. When I did add it, I siloed it.
The question is, with where this is going, if siloing is still needed. I'm suspecting it isn't and we should go ahead with this.
Looking at #165 is reminding me that this was also designed from the ground up and that colors can't do the same because they are context dependent and so Style
just followed the pattern of the items it built on top of. Extending past that is fine.
Personally, my most common use of :# is as part of :#x for "please print the 0x in front of this hex number". :)
I think with that precedence we can likely go forward with this.
One last question is what should Style::render
do
render
and render_reset
.We can always decouple this and add alternate support later. I've made corresponding updates to the PR.
Closed with #165
Moved from #165
This is an unusual suggestion, but I've tried it out in practice and it feels really comfortable to use. I wanted to run it by you to see if it seemed reasonable.
I found the requirement to call
.render()
and.render_reset()
rather verbose, particularly when trying to render several color styles in one line. I started thinking about ways to make that more convenient, and this idea occurred to me.With this PR applied,
Style
andReset
implementDisplay
directly, rendering the ANSI code, without having to call.render()
. That part I'm hoping will be relatively uncontroversial; that's in the first two commits.The more unusual part of this PR: if you set the alternate format flag, a
Style
will print its reset code, instead.The combination of the two makes it easy to use inline formats to render styles. Here's an example of how this looks:
I'm hoping this seems reasonable. If you find the use of the alternate flag too much, though, then as an alternative, you could drop the last two commits, and that would still let people render codes and resets using inline styles:
(This would get even easier if anstyle had a
pub const RESET: Reset = Reset;
, which I'd be happy to send in a patch for.)