Skip to content
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

very minimalistic support for colors (warnings and errors) #207

Closed
wants to merge 6 commits into from

Conversation

c-cube
Copy link
Contributor

@c-cube c-cube commented Jun 25, 2015

The point of this PR is to poll maintainers and users, do NOT merge (yet) :-)

The idea is simple: print warnings in yellow and errors in red, as other compilers (gcc, clang for instance) do. I didn't spend a lot of time on this (no tests, a problem with Format which indents weirdly because of escape codes). I could use ANSITerminal but I'm not sure about adding dependencies to the compiler.

@Drup
Copy link
Contributor

Drup commented Jun 25, 2015

You should really use Format.tag for this. It would simplify the enabling/disabling and solve the weird indentation.

Respecting GCC_COLORS (iirc) might be a good idea.

@gasche
Copy link
Member

gasche commented Jun 25, 2015

My personal opinion is that while I don't personally care about colors (Emacs and Merlin do that for me), I have heard enough demand from enough people to believe that integrating it in the compiler is worthwhile. I find it rather silly to say that a compiler is "massively more usable" when it adds colors (not saying that's what @c-cube claims, but I have heard this argument around the Clang debates), but if enough people hold that irrational belief it becomes an important aspect of usability to please them -- and also they might be right, who knows?

Cc: @ppedrot which asked me privately about doing such things in the toplevel (but I think there utop may be the ultimate answer).

@c-cube
Copy link
Contributor Author

c-cube commented Jun 25, 2015

@gasche I think many people use OCaml without emacs, those days, including me. Colors do not have a "massive" effects, but they do help spot where important messages lie.
I'll follow @Drup's advice on Format tags, although it requires a bit more refactoring to ensure all messages are built using Format.

@dbuenzli
Copy link
Contributor

dbuenzli commented Jun 25, 2015

One of the problem with tags is that they are not compositional (though it may not be a problem in that case, it is if you try to provide styling as a library). You can also simply use "@<0>" to solve the weird identation, this is the way this API is implemented.

@objmagic
Copy link
Contributor

objmagic commented Jun 25, 2015

I like this idea, personally. Colored warnings and errors are definitely helpful, especially for beginners.

@c-cube
Copy link
Contributor Author

c-cube commented Jun 25, 2015

The code is better now (using Format tags). It prints warnings in magenta, locations in bold, errors in red.

@c-cube
Copy link
Contributor Author

c-cube commented Jun 26, 2015

I should probably add some support into ocamlbuild (with a tag?)

@gasche
Copy link
Member

gasche commented Jun 26, 2015

Yes, I was thinking of that yesterday. If you don't mind, an ocamlbuild tag would be nice -- it's rather easy to add by imitating what is already present, eg -opaque for example. You should also adapt the OCAMLPARAM parsing, I suppose.

@damiendoligez
Copy link
Member

damiendoligez commented Jun 26, 2015

Three questions:

  1. Any thoughts (from anyone) about whether colors should be enabled by default?
  2. Does Emacs deal with them, or do they have to be disabled when compiling under Emacs?
  3. Should the new code be in a new file?

Also, you definitely need to add this option to the OCAMLPARAM code.

@Drup
Copy link
Contributor

Drup commented Jun 26, 2015

for 2. there is always the possibility to check terminfo ... which should be done anyway. Emacs users can enable ansicolor.

@c-cube
Copy link
Contributor Author

c-cube commented Jun 29, 2015

There seems to be some Terminfo handling in the compiler, but I have no idea how that works. Also, a lot of printing is made into buffers rather than directly into stdout/stderr.

@whitequark
Copy link
Member

whitequark commented Jul 12, 2015

"Massively more usable" is a silly claim, but "massively more readable" isn't one. For that matter, even OCaml agrees and uses some formatting for the toplevel.

(* color output *)
| "color" ->
begin try
let b = bool_of_string v in
Copy link
Member

@gasche gasche Aug 2, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There already is a standardized interface for boolean parameters, which is to use 0/1 (see Compenv.setter) rather than bool_of_string. You should feel free to generalize Compenv.setter to support calling an arbitrary function (as an auxiliary function).

@gasche
Copy link
Member

gasche commented Aug 2, 2015

I think the current codebase is reasonable and could be mergeable after having been made a bit less Location-centric. (Once we open the colored box, I am sure that plenty of people will have ideas for even better color output, so it makes sense to put it in a central place from the start.)

Re. default setting: I would enable it by default on TERM values that are not empty or dumb. (I just checked: it seems that the toplevel started by Emacs modes is set with dumb, so that would disable it there by default.). There seem to be terminfo settings to retrive color support information (eg. maximal number of colors), but I would wait for a PR of someone willing to implement this.

On the other hand, checking how other projects handle this question (eg. clang?) may suffice to have a good/consensual answer.

@whitequark
Copy link
Member

whitequark commented Aug 2, 2015

@gasche Usually, you check the TERM and also look at the result of isatty(fileno(stdout)). This is what clang does.

@c-cube
Copy link
Contributor Author

c-cube commented Aug 3, 2015

I'm working on @gasche 's recommendations. I moved Color to Misc.Color (for fear of module conflicts) with some one-shot initialization code. I put a flag Clflags.color (but it's not a boolean, it's a ternary value On | Off | Auto). The value Auto enables colors depending on Sys.getenv "TERM" (isatty is only available in Unix, which is not currently linked, right?).

let mk_no_color f =
"-no-color", Arg.Unit f,
" <bool> Disable ANSI color codes for warning/error messages"

Copy link
Member

@gasche gasche Aug 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if there was a way to explicitly ask on the command line the "auto" mode -- you had a good idea in separating these three options. You could have -color-auto as a third flag, or maybe accept -color {on,off,auto} (or {always,never,auto}, these are the option names in git and grep). This would mean that the OCAMLPARAM handling code would have to be changed again...

@c-cube
Copy link
Contributor Author

c-cube commented Aug 3, 2015

Indeed, forgot about the ocamlbuild tag (which should become several tags: color, no_color and color_auto, I guess). The past has shown it was good to provide an explicit option for each possible value of a parameter (including the default one), so I agree we need -color-auto and the corresponding OCAMLPARAM flag (maybe a 'a').

@gasche
Copy link
Member

gasche commented Aug 3, 2015

I'm not sure why the testsuite fails, but it may be the case that some tests in the testsuite do not run with TERM=dumb while they should (I have had issues with this in the past because the location-printing code in the toplevel depends on TERM, and some tests run a toplevel: e2b6629 ).

@c-cube
Copy link
Contributor Author

c-cube commented Aug 3, 2015

The errors were because the output was slightly changed by this branch; the last commit should fix this.

@c-cube
Copy link
Contributor Author

c-cube commented Aug 3, 2015

yay!

print ppf loc;
fprintf ppf "Warning %a@." Warnings.print w
pp_open_tag ppf "warning";
Copy link
Member

@gasche gasche Aug 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a particular reason for not using a format string here?

@xavierleroy
Copy link
Contributor

xavierleroy commented Aug 3, 2015

For what it's worth, keep in mind that the Windows terminal does not support ANSI escapes, despite MSDOS's famous ANSI.SYS extension that made them ubiquitous:
http://stackoverflow.com/questions/16755142/how-to-make-win32-console-recognize-ansi-vt100-escape-sequences
So, one way or another, make sure that color support is turned off in a Windows terminal.


let print_error_prefix ppf () =
setup_colors ();
pp_open_tag ppf "error";
Copy link
Member

@gasche gasche Aug 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason for not using a format here? (I don't mind either the format or plain-pp styles, but mixing both is a bit surprising)

@c-cube
Copy link
Contributor Author

c-cube commented Aug 3, 2015

@gasche I'm moving to format strings, right.
@xavierleroy I don't have access to a windows machine, sadly. Do you know whether the TERM environment variable is set on windows? If it's not set (or equal to "dumb"), then colors will be disabled by default.

@gasche
Copy link
Member

gasche commented Aug 8, 2015

Fun fact: because your rebased the bootstrap that was done on the old patch state, applying this patch series makes the compiler print warning in yellow, while the code specifies purple -- with no mention of yellow in the code or its history. On trusting trust, tastes and colors.

@gasche
Copy link
Member

gasche commented Aug 8, 2015

Sorry to nitpick, but the current patch series isn't really usable as is -- for example, this commit is not at all what it says. Would it be possible to have another rebase? I will do it myself otherwise, but probably not today.

Other points I noticed when trying to rebase myself this morning:

  • the code says caml_sys_is_interactive, the commit message says caml_sys_isatty, you should pick one
  • I think there is a useless let color = ref false definition in one commit

@gasche
Copy link
Member

gasche commented Aug 9, 2015

Also, I noticed during my testing that, when printing a location, the characters are not highlighted with the rest of the location (this corresponds to a small bug in print_loc).

@c-cube
Copy link
Contributor Author

c-cube commented Aug 10, 2015

I will do the rebase and change the bad commit/commit messages. What do you mean by non-highlighted 'characters'?

@gasche
Copy link
Member

gasche commented Aug 10, 2015

Only the line numbers are highlighted, not the character range.

@c-cube
Copy link
Contributor Author

c-cube commented Aug 10, 2015

Right, fixed. About the bootstrap, I admit it's funny to have yellow colors (it illustrates the idea of the compiler hidden backdoor perfectly imho); I can change the bootstrap again if you want, either using the latest version or the one just after caml_sys_is_interactive was added.

@gasche
Copy link
Member

gasche commented Aug 10, 2015

I think it's nice to bootstrap with the color-enabled compiler, as it ensures that other maintainers will see the effect of the change -- early adopters! But then you should use the right colors. (Bootstrapping before is fine as well.)

You should also merge "add option handling" and "add color handling in OCAMLPARAM and ocamlbuild". Thanks for the changelog message. Would it be possible to also have a test in the testsuite that checks that the behavior is as expected for -color and -no-color?

(I'm thinking of adding two changes on top of this PR in the future: change the option handling to use -color {always,never,auto} instead, and add a color for hints. I might also experiment with having locations underlined instead of bold, or maybe not emphasized at all, because right now they are a bit invasive visually.)

@c-cube
Copy link
Contributor Author

c-cube commented Aug 10, 2015

Ok, will do. About the bold locations, I followed what clang and gcc do, and I don't find it too invasive. It will be easy to change later anyway.

Is there something that would help me write tests that set specific options to the compiler before compiling the sample?

c-cube added 6 commits Aug 10, 2015
use bold magenta for warnings (works on white background)
use -color, -no-color, -color-auto in the compiler
use "0", "1" or "a" for the "color" option in OCAMLPARAM
add tags 'color', 'color_auto', 'no_color' to ocamlbuild
@gasche
Copy link
Member

gasche commented Aug 10, 2015

Now that I think of it, testsuite would be a pain because you'd have to disable them under Windows and other unsupported environment. I think it's not worth it, so feel free to skip these. (If color get broken, people will complain anyway, hopefully...).

An example of test controlling the command-line parameters of the compiler is lib-dynlink-bytecode.

@c-cube
Copy link
Contributor Author

c-cube commented Aug 10, 2015

Ok. Then I think the current set of commits is ready (I re-bootstraped and fixed the location bug, please check!).

@gasche
Copy link
Member

gasche commented Aug 15, 2015

Merged in trunk. Thanks for the patch!

@gasche gasche closed this Aug 15, 2015
@c-cube
Copy link
Contributor Author

c-cube commented Aug 22, 2015

apologies for the bad rebasing (I did rebase a lot tbh, it must have gone wrong at some iteration).

@gasche
Copy link
Member

gasche commented Sep 23, 2015

Based on this caml-list discussion, it seems that the current patch breaks the ability to define a custom margin for toplevel messages. We should fix that, and add a regression test to the testsuite.

@c-cube
Copy link
Contributor Author

c-cube commented Sep 23, 2015

I don't think it breaks this feature, I think it was already broken. Formatting was done using ksprintf and buffers. I can try to fix it nonetheless.

@gasche
Copy link
Member

gasche commented Sep 23, 2015

Indeed, it seems you were right and the change happened between 4.01 and 4.02. Sorry for jumping to the wrong conclusions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants