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

rpc: serialize user message styles #8516

Merged

Conversation

Alizter
Copy link
Collaborator

@Alizter Alizter commented Aug 26, 2023

We serialise user message styles in RPC allowing Ansi formatted error codes to be serialised faithfully. We also take the time to fix the differences between RPC messages and regular dune ones that were observed in #8411.

@@ -34,6 +34,468 @@ module Loc = struct
;;
end

let sexp_pp (conv_tag : 'a Conv.value) : 'a Pp.t Conv.value =
Copy link
Collaborator Author

@Alizter Alizter Aug 26, 2023

Choose a reason for hiding this comment

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

This generalises the previous sexp_pp function by allowing for the Conv of tags, and adds it to the API for use elsewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I actually had to introduce two versions of this function. The new version serialises tags as (Tag (pair tag pp)) which is different to how it was done previously as (Tag pp). Therefore I have included the old version too and made sure to version bump both diagnostics and the diagnostic poll.

@@ -189,17 +585,18 @@ module Diagnostic = struct

module Related = struct
type t =
{ message : unit Pp.t
{ message : User_message.Style.t Pp.t
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Jobs also have a unit Pp.t description, but I will not touch it in this PR.

Comment on lines +592 to +498
let message t = t.message |> Pp.map_tags ~f:(fun _ -> ())
let message_with_style t = t.message
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We add an extra function allowing for an opt in to the stylised message. This keeps our API version compatible. The old version is just the new version with the style tags removed.

@@ -256,35 +654,10 @@ module Diagnostic = struct
let to_dyn t = Sexp.to_dyn (Conv.to_sexp sexp t)

let to_user_message t =
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since we have a faithful reconstruction of the styles, we get rid of the ad-hoc message styling we had before and simply use Stdune.User_message.make to get more agreement. There are still some pain points however:

  • User_message concatenates hints etc. during construction which we cannot remove. However since the style is also serialised this doesn't appear different to the user. Only the pp, which in the tests can be inspected, is slightly different.

@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch 4 times, most recently from 1573151 to e5ccd20 Compare August 26, 2023 18:45
@Alizter Alizter marked this pull request as ready for review August 26, 2023 18:46
@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch 4 times, most recently from 2384740 to 906bf91 Compare August 27, 2023 15:07
@Alizter
Copy link
Collaborator Author

Alizter commented Aug 30, 2023

It's still possible for some messages to lose the Error: prefix. I have not yet been able to reproduce this in a test. I am not exactly sure what is causing this. I think it has something to do with how we use ocamlc-loc to parse error messages into compound user messages and then turn them into user messages. But I haven't been able to confirm.

@pmwhite
Copy link
Collaborator

pmwhite commented Sep 2, 2023

Sorry for the delay in starting to review this! I just started looking at it today. One thing that I don't understand is why we need to introduce new User_message and Ansi_color modules if Stdune already has sub-modules that look very similar to the ones introduced in this feature. Maybe this is related to what you mentioned about the compiler not letting you use polymorphic variants; I didn't follow that part - could you elaborate?

@Alizter
Copy link
Collaborator Author

Alizter commented Sep 2, 2023

@pmwhite That's related but not exactly why we have to mirror the types in the dune_rpc library. We need to keep the dependencies of that library small so exposing Stdune in the API would require consumers to also pull in the Stdune library. And this is not desirable IIUC. cc @rgrinberg

My hope with the poly variants was that we could mirror the API but share the implementation but that didn't work out so I ended up mirroring everything.

@pmwhite
Copy link
Collaborator

pmwhite commented Sep 2, 2023

I see, I wasn't aware of that constraint. The library does depend on stdune, but it doesn't mention it in the interface, which I assume is useful so that users of the API can more easily use their own standard library, like base or something. How come mirroring the API and sharing the implementation doesn't work? I would have expected that to work out just fine.

@Alizter
Copy link
Collaborator Author

Alizter commented Sep 2, 2023

@pmwhite When I tried it, I had to do something like this:

let to_user_message_style = function
  | `Fg_8_bit_color rgb -> RGB8.to_rgb8 rgb
...
  | x -> x

Now you would have thought that the final clause would go through since the type is the same structurally, however the compiler rejected this. This meant I had to write out each case anyway. Doing so meant there was little point keeping the poly variants around.

The reason we have poly variants in Stdune is because we add extra constructors when parsing escape codes. Here we do no such magic therefore we might as well use an ordinary variant.

@rgrinberg
Copy link
Member

Now you would have thought that the final clause would go through since the type is the same structurally, however the compiler rejected this.

I think you just needed to add a type annotation.

@rgrinberg
Copy link
Member

I see, I wasn't aware of that constraint. The library does depend on stdune, but it doesn't mention it in the interface, which I assume is useful so that users of the API can more easily use their own standard library, like base or something

That's right. In particular, stdune is completely unstable so depending on it in code is going to produce churn for users of this API. Although the dune rpc api isn't completely stable, we already have production users so we do our best to maintain backwards compatibility.

@pmwhite
Copy link
Collaborator

pmwhite commented Sep 2, 2023

@pmwhite When I tried it, I had to do something like this:

let to_user_message_style = function
  | `Fg_8_bit_color rgb -> RGB8.to_rgb8 rgb
...
  | x -> x

Is the function necessary? Could we instead expose the equality to Stdune.User_message.Style.t in private/exported_types.mli, since all we care about is not having Stdune show up in the public dune-rpc interface? Most of the value I've been imagining sharing the types would have is that then we wouldn't have to convert back and forth between the types. (maybe I'm missing a reason why we can't share the types?)

| Underline

let sexp =
let open Conv in
Copy link
Member

Choose a reason for hiding this comment

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

Could you introduce Conv.enum to make this all a bit more compact?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Conv.enum as it exists is not sufficient since I cannot handle constructor arguments.

@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch from cf1dbf5 to 82c190d Compare September 7, 2023 12:48
@Alizter
Copy link
Collaborator Author

Alizter commented Sep 7, 2023

@pmwhite I thought a bit harder about this and you are totally right, we can share much of the implementation. I've gone ahead and removed all the conversion functions and it has simplified things considerably.

@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch 2 times, most recently from b65e5cc to 9099bff Compare September 7, 2023 13:13
@Alizter
Copy link
Collaborator Author

Alizter commented Sep 7, 2023

I've added more functions to RGB8 and RGB24 in the dune_rpc API, allowing consumers to produce and consume those values easily.

@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch from 9099bff to 6c5860b Compare September 7, 2023 16:13
val of_int : int -> t

(** [to_int t] returns the 8-bit color as an integer in the range [0, 255]. *)
val to_int : t -> int
Copy link
Member

Choose a reason for hiding this comment

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

I don't think these functions are very useful. What about accessors like red, green, blue?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not possible to do split into red, green and blue like we do for 24-bit color since not every terminal encodes 8-bit colors in the same manner. The only thing that doesn't change is that there are 256 colors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The only time this can happen is if Dune runs a program with 8-bit color output and we wish to preserve that color. At that point we are at the mercy of the client on how we quantize those values.


(** [to_int t] returns the 24-bit color as an integer in the range [0, 0xFFFFFF].
Each color components consists of 8 bits. *)
val to_int : t -> int
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I'm making a web client for viewing RPC messages, this might be a useful value to have since colors are hex values usually. (As an example of how this might be useful).

@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch from 6c5860b to e6cb55b Compare September 8, 2023 21:11
Copy link
Member

@rgrinberg rgrinberg left a comment

Choose a reason for hiding this comment

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

Okay, this looks ready to me. I'll give @pmwhite another chance to comment.

cc @ddickstein who was interested in this.

@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch 2 times, most recently from 14637d5 to 18f80d1 Compare September 8, 2023 21:31
Signed-off-by: Ali Caglayan <alizter@gmail.com>
@Alizter Alizter force-pushed the ps/branch/rpc__serialize_user_message_styles branch from 18f80d1 to 0aa397b Compare September 9, 2023 14:56
@pmwhite
Copy link
Collaborator

pmwhite commented Sep 10, 2023

Yeah, looks good to me, too.

@rgrinberg rgrinberg merged commit 8783a59 into ocaml:main Sep 10, 2023
20 of 21 checks passed
emillon added a commit to emillon/opam-repository that referenced this pull request Sep 14, 2023
CHANGES:

- Modules that were declared in `(modules_without_implementation)`,
  `(private_modules)` or `(virtual_modules)` but not declared in `(modules)`
  will raise an error. (ocaml/dune#7674, @Alizter)

- `enabled_if` now supports `arch_sixtyfour` variable (ocaml/dune#8023, fixes ocaml/dune#7997,
  @Alizter)- Use `posix_spawn` instead of `fork` on MacOS. This gives us a
  performance boost and allows us to re-enable thread. (ocaml/dune#8090, @rgrinberg)

- Experimental: Added a `$ dune monitor` command that can connect to a running
  `dune build` in watch mode and display the errors and progress. (ocaml/dune#8152,
  @Alizter)

- No longer emit linkopts(javascript) in META files (ocaml/dune#8168, @hhugo)

- The `progress` RPC procedure now has an extra field for the `In_progress`
  constructor for the number of failed jobs. (ocaml/dune#8212, @Alizter)

- Add a `--preview` flag to `dune fmt` which causes it to print out the changes
  it would make without applying them (ocaml/dune#8289, @gridbugs)

- Introduce `(source_trees ..)` to the install stanza to allow installing
  entire source trees. (ocaml/dune#8349, @rgrinberg)

- Deprecate install destination paths beginning with ".." to prevent packages
  escaping their designated installation directories. (ocaml/dune#8350, @gridbugs)

- Stop signing source files with substitutions. Sign only binaries instead
  (ocaml/dune#8361, fixes ocaml/dune#8360, @anmonteiro)

- Add `--stop-on-first-error` option to `dune build` which will terminate the
  build when the first error is encountered. (ocaml/dune#8400, @pmwhite and @Alizter)-
  Dune now displays the number of errors when waiting for changes in watch
  mode. (ocaml/dune#8408, fixes ocaml/dune#6889, @Alizter)

- Add `with_prefix` keyword for changing the prefix of the destination of
  installed files matched by globs. (ocaml/dune#8416, @gridbugs)

- Added experimental `--display tui` option for Dune that opens an interactive
  Terminal User Interface (TUI) when Dune is running. Press '?' to open up a
  help screen when running for more information. (ocaml/dune#8429, @Alizter and
  @rgrinberg)

- Add a `warnings` field to `dune-project` files as a unified mechanism to
  enable or disable dune warnings (@rgrinberg, 8448)

- `dune exec`: support syntax like `%{bin:program}`. This can appear anywhere
  in the command line, so things like `dune exec time %{bin:program}` now work.
  (ocaml/dune#6035, ocaml/dune#8474, fixes ocaml/dune#2691, @emillon, @Leonidas-from-XIV)

- RPC message styles are now serialised meaning that RPC diagnostics keep their
  Ansi styling. (ocaml/dune#8516, fixes ocaml/dune#6921, @Alizter)- Ignore internal promote rules
  when `--ignore-promoted-rules` is set (ocaml/dune#8518, fix ocaml/dune#8417, @rgrinberg)

- Truncate output from actions that produce too much output (@tov, ocaml/dune#8351)

- Allow libraries to shadow OCaml builtin libraries. Previously, builtin
  libraries would always take precedence. (@rgrinberg, ocaml/dune#8558)

- Remove warning against `.dune` files generated by pre dune 2.0 (ocaml/dune#8611,
  @rgrinberg)

- `dune utop` no longer links `utop` in "custom" mode, which should make this
  command considerably faster. (ocaml/dune#8631, fixes ocaml/dune#6894, @nojb)

- Ensure that package names in `dune-project` are valid opam package
  names. (ocaml/dune#8331, @emillon)

- dune init: parse `--public` as a public name (ocaml/dune#8603, fixes ocaml/dune#7108, @emillon)

- Remove versions 0.1 and 0.2 of the experimental ctypes extension. (ocaml/dune#8293,
  @emillon)
emillon added a commit to emillon/opam-repository that referenced this pull request Sep 22, 2023
CHANGES:

- `enabled_if` now supports `arch_sixtyfour` variable (ocaml/dune#8023, fixes ocaml/dune#7997,
  @Alizter)

- Use `posix_spawn` instead of `fork` on MacOS. This gives us a performance
  boost and allows us to re-enable thread. (ocaml/dune#8090, @rgrinberg)

- Experimental: Added a `$ dune monitor` command that can connect to a running
  `dune build` in watch mode and display the errors and progress. (ocaml/dune#8152,
  @Alizter)

- The `progress` RPC procedure now has an extra field for the `In_progress`
  constructor for the number of failed jobs. (ocaml/dune#8212, @Alizter)

- Add a `--preview` flag to `dune fmt` which causes it to print out the changes
  it would make without applying them (ocaml/dune#8289, @gridbugs)

- Introduce `(source_trees ..)` to the install stanza to allow installing
  entire source trees. (ocaml/dune#8349, @rgrinberg)

- Add `--stop-on-first-error` option to `dune build` which will terminate the
  build when the first error is encountered. (ocaml/dune#8400, @pmwhite and @Alizter)

- Dune now displays the number of errors when waiting for changes in watch
  mode. (ocaml/dune#8408, fixes ocaml/dune#6889, @Alizter)

- Add `with_prefix` keyword for changing the prefix of the destination of
  installed files matched by globs. (ocaml/dune#8416, @gridbugs)

- Added experimental `--display tui` option for Dune that opens an interactive
  Terminal User Interface (TUI) when Dune is running. Press '?' to open up a
  help screen when running for more information. (ocaml/dune#8429, @Alizter and
  @rgrinberg)

- Add a `warnings` field to `dune-project` files as a unified mechanism to
  enable or disable dune warnings (@rgrinberg, 8448)

- `dune exec`: support syntax like `%{bin:program}`. This can appear anywhere
  in the command line, so things like `dune exec time %{bin:program}` now work.
  (ocaml/dune#6035, ocaml/dune#8474, fixes ocaml/dune#2691, @emillon, @Leonidas-from-XIV)

- Make copy sandbox support directory targets. (ocaml/dune#8705, fixes ocaml/dune#7724, @emillon)

- Add a new alias `@doc-json` to build odoc documentation in JSON format. This
  output can be consumed by external tools. (ocaml/dune#8178, @emillon)

- Modules that were declared in `(modules_without_implementation)`,
  `(private_modules)` or `(virtual_modules)` but not declared in `(modules)`
  will raise an error. (ocaml/dune#7674, @Alizter)

- No longer emit linkopts(javascript) in META files (ocaml/dune#8168, @hhugo)

- Deprecate install destination paths beginning with ".." to prevent packages
  escaping their designated installation directories. (ocaml/dune#8350, @gridbugs)

- RPC message styles are now serialised meaning that RPC diagnostics keep their
  Ansi styling. (ocaml/dune#8516, fixes ocaml/dune#6921, @Alizter)

- Truncate output from actions that produce too much output (@tov, ocaml/dune#8351)

- Allow libraries to shadow OCaml builtin libraries. Previously, builtin
  libraries would always take precedence. (@rgrinberg, ocaml/dune#8558)

- Remove warning against `.dune` files generated by pre dune 2.0 (ocaml/dune#8611,
  @rgrinberg)

- `dune utop` no longer links `utop` in "custom" mode, which should make this
  command considerably faster. (ocaml/dune#8631, fixes ocaml/dune#6894, @nojb)

- Ensure that package names in `dune-project` are valid opam package names.
  (ocaml/dune#8331, @emillon)

- init: check that module names are valid (ocaml/dune#8644, fixes ocaml/dune#8252, @emillon)

- dune init: parse `--public` as a public name (ocaml/dune#8603, fixes ocaml/dune#7108, @emillon)

- Stop signing source files with substitutions. Sign only binaries instead
  (ocaml/dune#8361, fixes ocaml/dune#8360, @anmonteiro)

- Remove versions 0.1 and 0.2 of the experimental ctypes extension. (ocaml/dune#8293,
  @emillon)
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.

Extend diagnostics RPC with display markup
3 participants