-
-
Notifications
You must be signed in to change notification settings - Fork 135
Use fmt precision if specified in graphical report handler #448
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
base: main
Are you sure you want to change the base?
Conversation
|
Wouldn't precision support exactly this, while being technically correct? For integral types, this is ignored. For floating-point types, this indicates how many digits after the decimal point should be printed. |
src/handlers/graphical.rs
Outdated
| } | ||
|
|
||
| self.render_report(f, diagnostic) | ||
| if let Some(width) = f.width() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe .precision() is treated as maximum width for stringy / non-numeric types, would that make more sense?
https://doc.rust-lang.org/std/fmt/struct.Formatter.html#method.precision
|
Ah didn't know that! Will change 😁 |
|
Neither did I, fwiw 😄. I just went "there has to be some way that that's supported, surely" and had better luck stumbling onto the right method documentation apparently |
|
Alright, did the change! Working as expected. |
|
To be clear - this is just a musing from another fellow user of the library, not something you necessarily need to address. It seems reasonable enough to me. But that .clone() might get expensive. I feel like there's another issue we're kinda circling around, that I've ran into in tests too - which is that given a ReportHandler, and a Diagnostic, there's no obvious way (such as a macro) documented on how to put them together. Most of the time, setting a hook early in startup is what a user wants to do. |
I considered that too, but the current struct doesn't look too bad.
There is a way to print a diagnostic without using the hook I guess: https://docs.rs/miette/latest/miette/struct.GraphicalReportHandler.html#method.render_report I'm only now thinking I could use this instead of this PR. |
|
Perhaps another way to solve for this scenario would be to have: impl Report
{
pub fn with_handler(self, new_handler: Box<dyn ReportHandler> -> Self
{
let inner = unsafe { self.inner.boxed() }.into_inner();
unsafe { Report::construct(inner.vtable, Some(new_handler), inner.object) }
}Then you could do report = Report::from(my_diagnostic).with_handler(my_overridden_handler)
println!("{report}");But even that seems wasteful unless the ReportHandler being cloned for every error is expected / reasonable. Or, alternatively, one could add a bunch of methods to Report that would take the handler up front. It also looks likely to me that you could install a HOOK that say, looks at thread local instead of always returning the same handler. Which might make sense in some scenarios. Might be another way to solve your use case. But yeah, I have no idea what's better either, and don't have a strong opinion. I just thought this PR was interesting and thought I'd share some ideas, which may or may not be any good. Kat's opinion on this is obviously massively more informed than my own, and I look forward to seeing their much more informed thoughts. |
Yeah, definitely doable. like the comment on GraphicalReportHandler::render_report (and the other render_report methods too) says: /// Render a [`Diagnostic`]. This function is mostly internal and meant to
/// be called by the toplevel [`ReportHandler`] handler, but is made public
/// to make it easier (possible) to test in isolation from global state.
Something like this does the trick and I think works in your scenario. fn get_formatted_diagnostic(diagnostic: &dyn miette::Diagnostic) -> String
{
let handler = miette::GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor());
let mut result = String::new();
handler.render_report(&mut result, diagnostic).expect("Should render");
result
}This is very useful to my tests, glad I commented on this issue, because I didn't quite get what that comment meant before. Which I guess would be another way to solve this - you could basically create your own version of Report (potentially less optimal) that does the same sort of trick of implementing Debug and Display to call into your ReportHandler, ignoring the one contained inside the Report. |
|
As a general thought on performance: I don't consider extreme performance to be super important for the graphical renderer. It's kind of already assumed this is a "one and done" kinda situation, not something you're going to be doing in a tight loop or printing a literal ton of. Even if people printed a lot of diagnostics, most folks get cut off at 1-10k lines in their terminal. These extra clone allocations wouldn't even be a blip at that scale. |
Fair point. Most compilers and similar tools I've worked with have some error count limit where they stop, like msvc's C1003 for example (if they're kind enough to go beyond "the first error") - even if we're talking about a thousand errors, we're talking about under a megabyte of ReportHandlers themselves. And the actual span contents may dwarf the ReportHandlers in a lot of cases anyway. Edit: I also think at some point I was thinking "what if ReportHandler is very large, it could be expensive". But the logic in question is specific to GraphicalReportHandler, not |
|
Ok, I think this is blocked on #451 |
#451 perhaps isn't the optimal solution (I couldn't get any combination of --locked and package versions to play nice without raising the MSRV a lot - from its current 1.70 to 1.82 - and I don't understand why not), but it is the best I could come up with in a few hours of trying to fix it. If you can find a way to do so without raising the MSRV, that'd presumably be better than what I did - I don't personally have any need for more than a few versions back (e.g. even a MSRV of like, 1.86 or 1.88 wouldn't bother me), so I don't really have a strong personal opinion, but there may well be people out there to whom it does matter. I'm not clear what the project's policy is on raising the MSRV, or whether @zkat has plans to address the downlevel issues themself in a better way - I just thought I'd raise #451 in case it was helpful, as I believe in contributing back to libraries I'm using wherever I can. |
|
Just in case you missed it, #451 merged |
I'm displaying diagnostics on a web page.
Currently the only way I know of to change the width with which the diagnostics get printed is in setting the hook.
But the hook can only be set once, so that won't work sadly.
So this PR adds the option to print the diagnostics with the fmt width that overrides the existing configured width.
Strictly speaking this not exactly correct. fmt width is supposed to be a minimum while we're using it as a maximum here.
If there's another better way to do dynamic width support, I'm all ears. But I think this is a decent solution :)