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

refactor: factor out text handling as new modules Text and Loctext #159

Merged
merged 1 commit into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src-lsp/LspServer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ struct
let msg = Broadcast.to_jsonrpc notif in
send (RPC.Packet.Notification msg)

let render_lsp_related_info (uri : L.DocumentUri.t) (message : Asai.Diagnostic.loctext) : L.DiagnosticRelatedInformation.t =
let render_lsp_related_info (uri : L.DocumentUri.t) (message : Asai.Loctext.t) : L.DiagnosticRelatedInformation.t =
let range = LspShims.Loc.lsp_range_of_range message.loc in
let location = L.Location.create ~uri ~range in
let message = Asai.Diagnostic.string_of_text message.value in
let message = Asai.Text.to_string message.value in
L.DiagnosticRelatedInformation.create ~location ~message

let render_lsp_diagnostic (uri : L.DocumentUri.t) (diag : diagnostic) : Lsp_Diagnostic.t =
let range = LspShims.Loc.lsp_range_of_range diag.explanation.loc in
let severity = LspShims.Diagnostic.lsp_severity_of_severity @@ diag.severity in
let code = `String (Message.short_code diag.message) in
let source = (State.get ()).source in
let message = Asai.Diagnostic.string_of_text diag.explanation.value in
let message = Asai.Text.to_string diag.explanation.value in
let relatedInformation = Bwd.to_list @@ Bwd.map (render_lsp_related_info uri) diag.extra_remarks in
Lsp_Diagnostic.create
~range
Expand Down
2 changes: 2 additions & 0 deletions src/Asai.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
module Range = Range
module Text = Text
module Loctext = Loctext
module Diagnostic = Diagnostic
module Reporter = Reporter
module StructuredReporter = StructuredReporter
Expand Down
10 changes: 10 additions & 0 deletions src/Asai.mli
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@
(** Locations and ranges. *)
module Range = Range

(** Texts that preserve pretty-printing structures.

@since 0.3.2 *)
module Text = Text

(** Located texts. "Loctext" is a portmanteau of "locate" and "text".

@since 0.3.2 *)
module Loctext = Loctext

(** The definition of diagnostics and some utility functions. *)
module Diagnostic = Diagnostic

Expand Down
30 changes: 13 additions & 17 deletions src/Diagnostic.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,6 @@ open Bwd

include DiagnosticData

let text s fmt =
Format.(pp_print_list ~pp_sep:pp_force_newline pp_print_string) fmt @@
String.split_on_char '\n' s

let textf = Format.dprintf

let ktextf = Format.kdprintf

let loctext ?loc s = Range.{ loc; value = text s }

let kloctextf ?loc k = ktextf @@ fun loctext -> k Range.{ loc; value = loctext }

let loctextf ?loc = kloctextf Fun.id ?loc

let of_loctext ?(backtrace=Bwd.Emp) ?(extra_remarks=[]) severity message explanation : _ t =
{ severity
; message
Expand All @@ -28,14 +14,14 @@ let of_text ?loc ?backtrace ?extra_remarks severity message text : _ t =
of_loctext ?backtrace ?extra_remarks severity message {loc; value = text}

let make ?loc ?backtrace ?extra_remarks severity message explanation =
of_text ?loc ?backtrace ?extra_remarks severity message @@ text explanation
of_text ?loc ?backtrace ?extra_remarks severity message @@ Text.make explanation

let kmakef ?loc ?backtrace ?extra_remarks k severity message =
ktextf @@ fun text ->
Text.kmakef @@ fun text ->
k @@ of_text ?loc ?backtrace ?extra_remarks severity message text

let makef ?loc ?backtrace ?extra_remarks severity message =
ktextf @@ of_text ?loc ?backtrace ?extra_remarks severity message
Text.kmakef @@ of_text ?loc ?backtrace ?extra_remarks severity message

let map f d = {d with message = f d.message}

Expand All @@ -47,3 +33,13 @@ let string_of_text text : string =
Format.pp_print_flush fmt ();
Str.global_replace (Str.regexp "\\([\r\n]+ *\\)+") " " @@
Buffer.contents buf

type text = Text.t
let text = Text.make
let textf = Text.makef
let ktextf = Text.kmakef

type loctext = Loctext.t
let loctext = Loctext.make
let loctextf = Loctext.makef
let kloctextf = Loctext.kmakef
83 changes: 45 additions & 38 deletions src/Diagnostic.mli
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,9 @@
(* @include *)
include module type of DiagnosticData

(** {1 Constructing Messages} *)

(** [text str] converts the string [str] into a text, converting each ['\n'] into a call to {!val:Format.pp_force_newline}. *)
val text : string -> text

(** [textf format ...] formats a text. It is an alias of {!val:Format.dprintf}. Note that there should not be any literal control characters (e.g., literal newline characters). *)
val textf : ('a, Format.formatter, unit, text) format4 -> 'a

(** [ktextf kont format ...] is [kont (textf format ...)]. It is an alias of {!val:Format.kdprintf}. *)
val ktextf : (text -> 'b) -> ('a, Format.formatter, unit, 'b) format4 -> 'a

(** [loctext str] converts the string [str] into a loctext.

@param loc The location of the loctext (usually the code) to highlight. *)
val loctext : ?loc:Range.t -> string -> loctext

(** [loctextf format ...] constructs a loctext. Note that there should not be any literal control characters (e.g., literal newline characters).

@param loc The location of the loctext (usually the code) to highlight.
*)
val loctextf : ?loc:Range.t -> ('a, Format.formatter, unit, loctext) format4 -> 'a

(** [kloctextf kont format ...] is [kont (loctextf format ...)].

@param loc The location of the loctext (usually the code) to highlight.
*)
val kloctextf : ?loc:Range.t -> (loctext -> 'b) -> ('a, Format.formatter, unit, 'b) format4 -> 'a

(** {1 Constructing Diagnostics} *)

(** [of_text severity message text] constructs a diagnostic from a {!type:text}.
(** [of_text severity message text] constructs a diagnostic from a {!type:Text.t}.

Example:
{[
Expand All @@ -45,9 +17,9 @@ val kloctextf : ?loc:Range.t -> (loctext -> 'b) -> ('a, Format.formatter, unit,

@since 0.2.0
*)
val of_text : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:loctext list -> severity -> 'message -> text -> 'message t
val of_text : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:Loctext.t list -> severity -> 'message -> Text.t -> 'message t

(** [of_loctext severity message loctext] constructs a diagnostic from a {!type:loctext}.
(** [of_loctext severity message loctext] constructs a diagnostic from a {!type:Loctext.t}.

Example:
{[
Expand All @@ -57,7 +29,7 @@ val of_text : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:loctext lis
@param backtrace The backtrace (to overwrite the accumulative frames up to this point).
@param extra_remarks Additional remarks that are not part of the backtrace.
*)
val of_loctext : ?backtrace:backtrace -> ?extra_remarks:loctext list -> severity -> 'message -> loctext -> 'message t
val of_loctext : ?backtrace:backtrace -> ?extra_remarks:Loctext.t list -> severity -> 'message -> Loctext.t -> 'message t

(** [make severity message loctext] constructs a diagnostic with the [loctext].

Expand All @@ -69,9 +41,9 @@ val of_loctext : ?backtrace:backtrace -> ?extra_remarks:loctext list -> severity
@param backtrace The backtrace (to overwrite the accumulative frames up to this point).
@param extra_remarks Additional remarks that are not part of the backtrace.
*)
val make : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:loctext list -> severity -> 'message -> string -> 'message t
val make : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:Loctext.t list -> severity -> 'message -> string -> 'message t

(** [makef severity message format ...] is [of_loctext severity message (loctextf format ...)]. It formats the message and constructs a diagnostic out of it.
(** [makef severity message format ...] is [of_loctext severity message (Loctext.makef format ...)]. It formats the message and constructs a diagnostic out of it.

Example:
{[
Expand All @@ -82,20 +54,55 @@ val make : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:loctext list -
@param backtrace The backtrace (to overwrite the accumulative frames up to this point).
@param extra_remarks Additional remarks that are not part of the backtrace.
*)
val makef : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:loctext list -> severity -> 'message -> ('a, Format.formatter, unit, 'message t) format4 -> 'a
val makef : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:Loctext.t list -> severity -> 'message -> ('a, Format.formatter, unit, 'message t) format4 -> 'a

(** [kmakef kont severity message format ...] is [kont (makef severity message format ...)].

@param loc The location of the text (usually the code) to highlight.
@param backtrace The backtrace (to overwrite the accumulative frames up to this point).
@param extra_remarks Additional remarks that are not part of the backtrace.
*)
val kmakef : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:loctext list -> ('message t -> 'b) -> severity -> 'message -> ('a, Format.formatter, unit, 'b) format4 -> 'a
val kmakef : ?loc:Range.t -> ?backtrace:backtrace -> ?extra_remarks:Loctext.t list -> ('message t -> 'b) -> severity -> 'message -> ('a, Format.formatter, unit, 'b) format4 -> 'a

(** {1 Other Helper Functions} *)

(** A convenience function that maps the message of a diagnostic. This is helpful when using {!val:Reporter.S.adopt}. *)
val map : ('message1 -> 'message2) -> 'message1 t -> 'message2 t

(** A convenience function that converts a {!type:text} into a string by formatting it with the maximum admissible margin and then replacing newlines and indentation with a space character. *)
val string_of_text : text -> string
(** {1 Deprecated Types and Functions} *)

(** An alias of [Text.t] for backward compatibility. *)
type text = Text.t
[@@ocaml.alert deprecated "Use Text.t instead"]

(** An alias of [Loctext.t] for backward compatibility. *)
type loctext = Loctext.t
[@@ocaml.alert deprecated "Use Loctext.t instead"]

(** An alias of [Text.make] for backward compatibility. *)
val text : string -> Text.t
[@@ocaml.alert deprecated "Use Text.make instead"]

(** An alias of [Text.makef] for backward compatibility. *)
val textf : ('a, Format.formatter, unit, Text.t) format4 -> 'a
[@@ocaml.alert deprecated "Use Text.makef instead"]

(** An alias of [Text.kmakef] for backward compatibility. *)
val ktextf : (Text.t -> 'b) -> ('a, Format.formatter, unit, 'b) format4 -> 'a
[@@ocaml.alert deprecated "Use Text.kmakef instead"]

(** An alias of [Loctext.make] for backward compatibility. *)
val loctext : ?loc:Range.t -> string -> Loctext.t
[@@ocaml.alert deprecated "Use Loctext.make instead"]

(** An alias of [Loctext.makef] for backward compatibility. *)
val loctextf : ?loc:Range.t -> ('a, Format.formatter, unit, Loctext.t) format4 -> 'a
[@@ocaml.alert deprecated "Use Loctext.makef instead"]

(** An alias of [Loctext.kmakef] for backward compatibility. *)
val kloctextf : ?loc:Range.t -> (Loctext.t -> 'b) -> ('a, Format.formatter, unit, 'b) format4 -> 'a
[@@ocaml.alert deprecated "Use Loctext.kmakef instead"]

(** An alias of [Text.to_string] for backward compatibility. *)
val string_of_text : Text.t -> string
[@@ocaml.alert deprecated "Use Text.to_string instead"]
22 changes: 3 additions & 19 deletions src/DiagnosticData.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,19 @@ type severity =
| Error (** A serious error caused by the end user (the user of your proof assistant or compiler) or other external factors (e.g., internet not working). *)
| Bug (** A serious error likely caused by a bug in the proof assistant. You would want the end user to report the bug back to you. This is useful for indicating that certain branches in a pattern matching should be "impossible", while printing out debugging information in case the program logic is flawed. *)

(** The type of texts.

When we render a diagnostic, the layout engine of the diagnostic handler should be the one making layout choices. Therefore, we cannot pass already formatted strings. Instead, a text is defined to be a function that takes a formatter and uses it to render the content. A valid text must satisfy the following two conditions:
+ {b All string (and character) literals must be encoded using UTF-8.}
+ {b All string (and character) literals must not contain control characters (such as the newline character [\n]).} It is okay to have break hints (such as [@,] and [@ ]) but not literal control characters. This means you should avoid pre-formatted strings, and if you must use them, use {!val:text} to convert newline characters. Control characters include `U+0000-001F` (C0 controls), `U+007F` (backspace) and `U+0080-009F` (C1 controls). These characters are banned because they would mess up the cursor position.

{i Pro-tip:} to format a text in another text, use [%t]:
{[
let t = textf "@[<2>this is what the master said:@ @[%t@]@]" inner_text
]}
*)
type text = Format.formatter -> unit

(** A loctext is a {!type:text} with location information. "loctext" is a portmanteau of "locate" and "text". *)
type loctext = text Range.located

(** A backtrace is a (backward) list of loctexts. *)
type backtrace = loctext bwd
type backtrace = Loctext.t bwd

(** The type of diagnostics. *)
type 'message t = {
severity : severity;
(** Severity of the diagnostic. *)
message : 'message;
(** The (structured) message. *)
explanation : loctext;
explanation : Loctext.t;
(** The free-form explanation. *)
backtrace : backtrace;
(** The backtrace leading to this diagnostic. *)
extra_remarks : loctext bwd;
extra_remarks : Loctext.t bwd;
(** Additional remarks that are relevant to the main message but not part of the backtrace. It is a backward list so that new remarks can be added to its end easily. *)
}
4 changes: 2 additions & 2 deletions src/GitHub.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module Make (Message : Reporter.Message) = struct
Format.printf "::%s title=%s::%s@."
(command_of_severity severity)
(Message.short_code msg)
(Diagnostic.string_of_text text)
(Text.to_string text)

let print_with_loc severity msg loc text =
match Range.source loc with
Expand All @@ -26,7 +26,7 @@ module Make (Message : Reporter.Message) = struct
(Range.begin_line_num loc)
(Range.end_line_num loc)
(Message.short_code msg)
(Diagnostic.string_of_text text)
(Text.to_string text)

let print Diagnostic.{severity; message; explanation = {loc; value = text}; _} =
match loc with
Expand Down
7 changes: 7 additions & 0 deletions src/Loctext.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type t = Text.t Range.located

let make ?loc s : t = Range.locate_opt loc @@ Text.make s

let kmakef ?loc k = Text.kmakef @@ fun t -> k @@ Range.locate_opt loc t

let makef ?loc = Text.kmakef @@ Range.locate_opt loc
23 changes: 23 additions & 0 deletions src/Loctext.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
(** {1 Types} *)

(** A located text *)
type t = Text.t Range.located

(** {1 Builders} *)

(** [make str] converts the string [str] into a located text.

@param loc The location of the text (usually the code) to highlight. *)
val make : ?loc:Range.t -> string -> t

(** [makef format ...] constructs a located text. Note that there should not be any literal control characters (e.g., literal newline characters).

@param loc The location of the text (usually the code) to highlight.
*)
val makef : ?loc:Range.t -> ('a, Format.formatter, unit, t) format4 -> 'a

(** [kmakef kont format ...] is [kont (makef format ...)].

@param loc The location of the text (usually the code) to highlight.
*)
val kmakef : ?loc:Range.t -> (t -> 'b) -> ('a, Format.formatter, unit, 'b) format4 -> 'a
6 changes: 3 additions & 3 deletions src/Reporter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ struct
(match loc with None -> l | Some _ -> loc),
bt <: {loc; value = text}

let trace_loctext (t : Diagnostic.loctext) =
let trace_loctext (t : Loctext.t) =
trace_text ?loc:t.loc t.value

let trace ?loc str = trace_text ?loc @@ Diagnostic.text str
let trace ?loc str = trace_text ?loc @@ Text.make str

let tracef ?loc = Diagnostic.kloctextf trace_loctext ?loc
let tracef ?loc = Loctext.kmakef trace_loctext ?loc

(* Constructing diagnostics *)

Expand Down
Loading