-
Notifications
You must be signed in to change notification settings - Fork 77
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
Switch from ANSITerminal to ocolor #474
Conversation
(and some cleanup of the remaining deps to ANSITerminal)
Closes #451 |
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.
Thanks! This is so cool!
if !Cli.disable_warnings_flag then Format.ifprintf Format.std_formatter format | ||
else Format.printf ("%a" ^^ format ^^ "\n%!") warning_marker () | ||
let get_ppf = function | ||
| Result -> Lazy.force std_ppf |
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.
Why Lazy
?
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.
Tere are a few reasons:
- we want to do the setup only once (
isatty
is not free ; and the Format setup uses side-effects) - we need the command-line to already have been parsed before we can do that setup¹
- also, we recreate a formatter at each call (for consistency among formatters for file output, etc.) and certainly don't want to use multiple concurrent formatters to stdout (that could be fixed by using
Ocolor_format.raw_std_formatter
instead though)
¹ I agree that this is a bit fragile if one were to use Messages
printing too early in the process; we could switch to hidden references and explicitely call setup functions upon parsing the command-line if that were a problem (but that would also be an issue with cli flags not consistently acknowledged).
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.
There should be this comment in messages.mli
that describes how we expect these side-effects to work I think :)
|
||
let of_message (s : string) : t = { message = s; positions = [] } | ||
let of_string (s : string) : t = | ||
{ message = (fun ppf -> Format.pp_print_string ppf s); positions = [] } |
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 think the codebase of the compiler uses fmt
instead of ppf
as the go-to variable names for formatters.
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.
Hm, I know (or at least it used to 😇)
The reason for my preference is that you often have functions that take a pretty-printing formatter and a format string as arguments, and fmt
is ambiguous in that regard
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.
indeed
compiler/catala_utils/messages.ml
Outdated
(match pos.message with None -> "" | Some msg -> msg ^ "\n") | ||
(Pos.retrieve_loc_text pos.position)) | ||
pos)) | ||
format target "@[<v>%t%a@]" message |
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.
Wouahou what's %t
?
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.
Sorry if it's a bit obscure, it's a function that just takes a ppf as argument. In the above "%t" message
is basically equivalent to "%a" (fun ppf () -> message ppf) ()
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.
Thanks, didn't know!
(Format.asprintf "\"%a\"" ScopeName.format_t scope_name) | ||
(Cli.format_with_style [ANSITerminal.yellow]) | ||
(Format.asprintf "\"%a\"" Ast.ScopeDef.format_t scope_def_key)) | ||
"In scope @{<yellow>\"%a\"@}, the variable @{<yellow>\"%a\"@} is \ |
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.
This is a big win!!!!
Thanks @denismerigoux for the review; I added to the PR the modified output of tests so you may want to double-check if there is no issue with that (tests were passing but that's because they tolerate whitespace diffs) |
@@ -32,7 +32,8 @@ scope B: | |||
```catala-test-inline | |||
$ catala Interpret -s A | |||
[RESULT] Computation successful! Results: | |||
[RESULT] x = | |||
[RESULT] | |||
x = |
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.
Not sure that we want this newline here between [RESULT]
and x
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.
Thing is, since we now ensure that pretty-printing is done consistently, the code below will be aligned with the x =
; so there is no clean/easy way to have neither the newline, nor the extra indentation as in the ERROR
examples below.
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.
Hum hum, the downside of doing things correctly :) Then we can leave it as it is in this PR right now.
@@ -29,8 +29,8 @@ scope Test1: | |||
```catala-test-inline | |||
$ catala Interpret -s Test1 | |||
[ERROR] Syntax error at token "scope" | |||
Message: expected either 'condition', or 'content' followed by the expected variable type | |||
Autosuggestion: did you mean "content", or maybe "condition"? | |||
Message: expected either 'condition', or 'content' followed by the expected variable type |
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.
Do we want that extra indent ? Also why are we keeping under CI something that has a syntax error?
@@ -13,8 +13,8 @@ scope Foo: | |||
```catala-test-inline | |||
$ catala Interpret -s Foo | |||
[ERROR] Error during typechecking, incompatible types: | |||
--> integer | |||
--> bool | |||
--> integer |
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.
Not sure we want this big indent
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.
In this case (comparing with the above RESULT
), we can probably tweak the printer for the specific error message to not have an outer box that creates this alignment.
[RESULT] Printing the tree of exceptions for the definitions of variable "x" of scope "Foo". | ||
[RESULT] Definitions with label "base": | ||
[RESULT] | ||
Printing the tree of exceptions for the definitions of variable "x" of scope "Foo". |
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.
Yeah I guess the newline here is a bit ugly
ocolor uses OCaml's
Format
module support for semantic tags; hence we can keepusing the usual formatting functions, but use format-string tags such as
@{<blue>some blue text@}
inside them. There are several benefits, includingreadability, correct formatting (the format characters are automatically skipped
from column calculations), and correct nesting of tags.
To properly leverage this, this PR also cleans up the whole printing pipeline,
ensuring we use
Format
ters all the way through (we used to have intermediatestring conversions in many places, which breaks the formatting paradigm).
In addition, this allows us to delay the decision to print color codes or not to
the backend printer, e.g. printing functions are not concerned wether color is
enabled, and it is done by detecting if the end output is a tty or a file (this
can still be forced by the
--color
option of course)Another small change is that errors, warnings and logs are now all printed to
stderr, reserving stdout to normal program output (e.g. a
.dcalc
file that youmay want to redirect)