dbuenzli / fmt Goto Github PK
View Code? Open in Web Editor NEWOCaml Format pretty-printer combinators
Home Page: http://erratique.ch/software/fmt
License: ISC License
OCaml Format pretty-printer combinators
Home Page: http://erratique.ch/software/fmt
License: ISC License
Not sure if that's intended.
L291 : /brackets/braces/
L426 : /provide/provides/
L437 : /were/where/
As far as I can see, Fmt
only depends on unix for its isatty
feature.
The ocaml runtime has caml_sys_isatty
which is what you want. It is used in the compiler but not exported in the Stdlib
. Maybe it should.
# Omod.load "fmt";;
[INC] /Users/dbuenzli/.opam/4.03.0/lib/ocaml
[INC] /Users/dbuenzli/.opam/4.03.0/lib/result
[INC] /Users/dbuenzli/.opam/4.03.0/lib/fmt
[OBJ] /Users/dbuenzli/.opam/4.03.0/lib/fmt/fmt.cma
[SRC] /Users/dbuenzli/.opam/4.03.0/lib/fmt/fmt_top_init.ml
[ERROR] load /Users/dbuenzli/.opam/4.03.0/lib/fmt/fmt_top_init.ml:
File "/Users/dbuenzli/.opam/4.03.0/lib/fmt/fmt_top_init.ml", line 1:
Error: Reference to undefined global `Fmt_tty'
Hi,
I remarked some of my code breaks due to the generalization of const
's type as writing something such as:
let t = const string "t"
will yield a weak type variable in t
's type.
Granted, in the case of my code, I should anyway have created an interface to fix the type of my functions (and this is what I'm gonna do) but I thought you may be interested in this piece of information. I'm not sure what outcome you expect of generalizing const
's type compared to keeping unit
in it?
I get the following error log when I try to build fmt
with 4.14.0+trunk
and dune.2.9.0
#=== ERROR while compiling fmt.0.8.9 ==========================================#
# context 2.0.8 | linux/x86_64 | ocaml-variants.4.14.0+trunk | https://opam.ocaml.org#1fc79772
# path ~/.opam/4.14.0+trunk/.opam-switch/build/fmt.0.8.9
# command ~/.opam/opam-init/hooks/sandbox.sh build ocaml pkg/pkg.ml build --dev-pkg false --with-base-unix true --with-cmdliner false
# exit-code 1
# env-file ~/.opam/log/fmt-2323173-d2c37b.env
# output-file ~/.opam/log/fmt-2323173-d2c37b.out
### output ###
# [...]
# 7 | let () = ignore (Toploop.use_file Format.err_formatter "fmt_tty_top_init.ml")
# ^^^^^^^^^^^^^^^^
# Error: Unbound value Toploop.use_file
# Command exited with code 2.
# pkg.ml: [ERROR] cmd ['ocamlbuild' '-use-ocamlfind' '-classic-display' '-j' '4' '-tag' 'debug'
# '-build-dir' '_build' 'opam' 'pkg/META' 'CHANGES.md' 'LICENSE.md'
# 'README.md' 'src/fmt.a' 'src/fmt.cmxs' 'src/fmt.cmxa' 'src/fmt.cma'
# 'src/fmt.cmx' 'src/fmt.cmi' 'src/fmt.mli' 'src/fmt_tty.a'
# 'src/fmt_tty.cmxs' 'src/fmt_tty.cmxa' 'src/fmt_tty.cma'
# 'src/fmt_tty.cmx' 'src/fmt_tty.cmi' 'src/fmt_tty.mli' 'src/fmt_top.a'
# 'src/fmt_top.cmxs' 'src/fmt_top.cmxa' 'src/fmt_top.cma'
# 'src/fmt_top.cmx' 'src/fmt_tty_top_init.ml']: exited with 10
$ opam install fmt
The following actions will be performed:
∗ install fmt 0.8.2
=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[fmt] Archive in cache
=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[ERROR] The compilation of fmt failed at "ocaml pkg/pkg.ml build --dev-pkg false --with-base-unix true --with-cmdliner true".
#=== ERROR while installing fmt.0.8.2 =========================================#
# opam-version 1.2.2
# os linux
# command ocaml pkg/pkg.ml build --dev-pkg false --with-base-unix true --with-cmdliner true
# path /home/guest/.opam/system/build/fmt.0.8.2
# compiler system (4.02.3)
# exit-code 1
# env-file /home/guest/.opam/system/build/fmt.0.8.2/fmt-17344-6d07ae.env
# stdout-file /home/guest/.opam/system/build/fmt.0.8.2/fmt-17344-6d07ae.out
# stderr-file /home/guest/.opam/system/build/fmt.0.8.2/fmt-17344-6d07ae.err
### stderr ###
# pkg.ml: [ERROR] key --dev-pkg: Unknown key.
=-=- Error report -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The following actions failed
∗ install fmt 0.8.2
No changes have been performed
$ opam install base-unix cmdliner fmt
[NOTE] Package base-unix is already installed (current version is base).
[NOTE] Package cmdliner is already installed (current version is 1.0.0).
The following actions will be performed:
∗ install fmt 0.8.2
Do you want to continue ? [Y/n] y
=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[fmt] Archive in cache
=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[ERROR] The compilation of fmt failed at "ocaml pkg/pkg.ml build --dev-pkg false --with-base-unix true --with-cmdliner true".
#=== ERROR while installing fmt.0.8.2 =========================================#
# opam-version 1.2.2
# os linux
# command ocaml pkg/pkg.ml build --dev-pkg false --with-base-unix true --with-cmdliner true
# path /home/guest/.opam/system/build/fmt.0.8.2
# compiler system (4.02.3)
# exit-code 1
# env-file /home/guest/.opam/system/build/fmt.0.8.2/fmt-17402-6d07ae.env
# stdout-file /home/guest/.opam/system/build/fmt.0.8.2/fmt-17402-6d07ae.out
# stderr-file /home/guest/.opam/system/build/fmt.0.8.2/fmt-17402-6d07ae.err
### stderr ###
# pkg.ml: [ERROR] key --dev-pkg: Unknown key.
=-=- Error report -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The following actions failed
∗ install fmt 0.8.2
No changes have been performed
how fix ?
There is no v0.8.9
tag in either this git repository or https://erratique.ch/repos/fmt/ and CHANGES.md
does not list this release
Printexc.to_string
and Printexc.raw_backtrace_to_string
in combination with Fmt.lines
can already be used to perform this, but may be convenient if Fmt
already provided this.
The exception message could also be optionally highlighted with a Fmt.style
(e.g. bold).
(I'm a ocaml newbie)
I try to test the "fmt" module and ran into a problem. While "pam install fmt" seems to succeed, I cannot load it open Fmt;;
: Error: Unbound module Fmt
.
I tried to run the test/test.ml example but I dont really know howto compile it.
$ocamlc test.ml
File "test.ml", line 23, characters 34-48:
Error: Unbound module Fmt
E.g. option
is using 1 space, we should use 2.
What do you think about this small newline format combinator?
let nl = Format.pp_print_newline
Which can be used like this:
# Fmt.(pr "%a" (list ~sep:nl int) [1; 2; 3])
1
2
3
When you have a recursive datastructure and you want to define a pretty printer for it (that you naturally call 'pp'), you end up with code like that:
let rec pp : t Fmt.t = fun fmt -> function
| Mod d -> Fmt.string fmt d#module_name
| List (f, args) ->
Fmt.pp fmt "%s%a"
f#module_name
Fmt.(parens @@ list pp) args
and then the last line is wrong, because of the local open.
I'm afraid the situation is going to be quite frequent. A name different than pp
would probably be better ...
fmt <- opam <- opam-installer <- opam-format <- opam-0installer-cudf <- fmt
maybe adding dune build could be fine
Fmt.unit ",@ "
Before I start let me thank you for maintaining fmt
. Just as a lot of other OCaml developers, I use it quite extensively!
fmt.0.9.0
has been released but it seems the corresponding git tag was not pushed either here or upstream at https://erratique.ch/repos/fmt.git
. Could you please push the tag or eventually let me know the hash of the commit used to produce the release tarball?
To give you a bit of context, the reason why I'm asking for this is because we maintain dune ports of opam packages at https://github.com/dune-universe/opam-overlays to make them compatible with opam-monorepo. We want to make sure the dune ports are as close as possible to released version they correspond to.
Please let me know if I can help in any way with this.
Should I just paste the example in this issue? Or send you a PR? It's small, and my motivation is mostly that there aren't any examples that come with Fmt, and that seems to be the biggest impediment to using it.
I want to try out Lucas Pluvinags’s mirage port to ESP32.
(https://www.lortex.org/posts/mirage/esp32/2018/06/22/build-your-own-mirage.html)
After creating and changing to a opam switch 4.06.0+32bit I want to do a
opam install mirage
which fails with:
>
> <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><> <><><><>
> [ERROR] The compilation of fmt failed at
> "/home/florian/.opam/opam-init/hooks/sandbox.sh build ocaml pkg/pkg.ml
> build --dev-pkg false --with-base-unix true --with-cmdliner true".
>
> #=== ERROR while compiling fmt.0.8.7 ==========================================#
> # context 2.0.4 | linux/x86_64 | ocaml-variants.4.06.0+32bit | https://opam.ocaml.org#3389beb3
> # path ~/.opam/4.06.0+32bit/.opam-switch/build/fmt.0.8.7
> # command ~/.opam/opam-init/hooks/sandbox.sh build ocaml pkg/pkg.ml build --dev-pkg false --with-base-unix true --with-cmdliner true
> # exit-code 1
> # env-file ~/.opam/log/fmt-24744-6ef1df.env
> # output-file ~/.opam/log/fmt-24744-6ef1df.out
> ### output ###
> # [...]
> # Error: Integer literal exceeds the range of representable integers of type int
> # Command exited with code 2.
> # pkg.ml: [ERROR] cmd ['ocamlbuild' '-use-ocamlfind' '-classic-display' '-j' '4' '-tag' 'debug'
> # '-build-dir' '_build' 'opam' 'pkg/META' 'CHANGES.md' 'LICENSE.md'
> # 'README.md' 'src/fmt.a' 'src/fmt.cmxs' 'src/fmt.cmxa' 'src/fmt.cma'
> # 'src/fmt.cmx' 'src/fmt.cmi' 'src/fmt.mli' 'src/fmt_tty.a'
> # 'src/fmt_tty.cmxs' 'src/fmt_tty.cmxa' 'src/fmt_tty.cma'
> # 'src/fmt_tty.cmx' 'src/fmt_tty.cmi' 'src/fmt_tty.mli' 'src/fmt_cli.a'
> # 'src/fmt_cli.cmxs' 'src/fmt_cli.cmxa' 'src/fmt_cli.cma'
> # 'src/fmt_cli.cmx' 'src/fmt_cli.cmi' 'src/fmt_cli.mli' 'src/fmt_top.a'
> # 'src/fmt_top.cmxs' 'src/fmt_top.cmxa' 'src/fmt_top.cma'
> # 'src/fmt_top.cmx' 'src/fmt_tty_top_init.ml']: exited with 10
> <><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
> ┌─ The following actions failed
> │ λ build fmt 0.8.7
> └─
> ╶─ No changes have been performed
>
I've been investigating a problem with my programs slowing down over time, but only when logging is configured. The problem seems to be with fmt (0.8.10)!
With this test program:
let n = 10000
let () =
while true do
let t0 = Unix.gettimeofday () in
for _i = 1 to n do
ignore @@ Fmt.str "Hello %a" Fmt.(styled `Blue string) "world"
done;
let t1 = Unix.gettimeofday () in
Printf.printf "Formatted %.0f messages/second\n%!" (float n /. (t1 -. t0))
done
I get:
$ dune exec -- ./test.exe
Formatted 522518 messages/second
Formatted 411017 messages/second
Formatted 298257 messages/second
Formatted 215499 messages/second
Formatted 155861 messages/second
Formatted 110564 messages/second
Formatted 77171 messages/second
Formatted 54181 messages/second
Formatted 37493 messages/second
Formatted 25499 messages/second
Formatted 17254 messages/second
Replacing Fmt.(styled `Blue string)
with Fmt.string
shows no slow-down.
According to the documentation, applying Fmt.styled
to a formatter returns one of the same type :
val styled : style -> 'a t -> 'a t
styled s pp formats like pp but styled with s.
but in practice, the 'a
is replaced by unit :
Format.formatter ->
('a, Format.formatter, unit, unit, unit, unit) format6 -> 'a
becomes
Format.formatter ->
(unit, Format.formatter, unit, unit, unit, unit) format6 -> unit
and is thus only usable with simple strings.
Here is an example I would expect to work but doesn't :
Fmt.set_style_renderer Fmt.stdout `Ansi_tty;
let pf = Fmt.pf in
pf Fmt.stdout "Hello, %s\n" "World";
let pf = Fmt.styled `Red pf in
pf Fmt.stdout "Hello, %s\n" "World"
I had the same behaviour on OCaml 4.08.1 & 4.14.0
Perhaps I should ask before creating an in-house solution... I wonder if there's any plan to support OSC 8 in fmt
?
ocaml-fmt-0.8.7, broken build on i586:
ocamlfind ocamldep -modules src/fmt.ml > src/fmt.ml.depends
ocamlfind ocamldep -modules src/fmt.mli > src/fmt.mli.depends
ocamlfind ocamlc -c -g -bin-annot -safe-string -I src -I test -o src/fmt.cmi src/fmt.mli
ocamlfind ocamlopt -c -g -bin-annot -safe-string -I src -I test -o src/fmt.cmx src/fmt.ml
It is:
val unit : (unit, Format.formatter, unit) Pervasives.format -> unit t
Which prevents for example to write:
Fmt.(option (prefix (unit " ") pp_type))
It should be
val unit : string -> unit t
to cater for the future removal of Uchar.dump
and the lack of support by the dev team for such a formatter in the stdlib.
See discussion in ocaml/ocaml#1081
On US-ASCII.
for OCaml signal numbers.
The implementation is not (thankfully).
Raising the corresponding exceptions.
val Fmt.failwith : ('a, Format.formatter, unit, unit) format4 -> 'a
val Fmt.invalid_arg : ('a, Format.formatter, unit, unit) format4 -> 'a
This does not cause a type error:
Fmt.invalid_arg "hello" 1
Is this expected? Fmt.pr
shows a type error as I would expect:
# Fmt.pr "hello" 1;;
Error: This expression has type
('a -> 'b, Format.formatter, unit, unit, unit, 'a -> 'b)
CamlinternalFormatBasics.fmt
but an expression was expected of type
('a -> 'b, Format.formatter, unit, unit, unit, unit)
CamlinternalFormatBasics.fmt
Type 'a -> 'b is not compatible with type unit
The following program gives an assert failure:
let parse fmt = Fmt.kstrf (fun x -> x) fmt
let check f = assert (f "X" = f "X")
let () = check (parse "%s")
This is fixed if you replace Fmt.kstrf
by Format.ksprintf
. This is fixed if you eta-expand (parse "%s")
into (fun x -> parse "%s" x)
. Not sure exactly what is happening there ...
If compiled without debug symbols or run without OCAMLRUNPARAM=b
, Printexc.raw_backtrace_to_string
returns the empty string. Fmt.exn_backtrace
then crashes with exception Invalid_argument("index out of bounds")
.
Also, if backtraces are on then it loses the last character of the error message. e.g.
let test_bt () =
try failwith "Test"
with ex ->
let bt = Printexc.get_raw_backtrace () in
Fmt.pr "[%s]@." (Printexc.raw_backtrace_to_string bt);
let msg = Fmt.strf "%a" Fmt.exn_backtrace (ex, bt) in
print_endline msg
prints
[Raised at file "pervasives.ml", line 32, characters 17-33
Called from file "test/test.ml", line 36, characters 6-21
]
Exception: Failure("Test")
Raised at file "pervasives.ml", line 32, characters 17-33
Called from file "test/test.ml", line 36, characters 6-2
(tested with OCaml 4.04.0)
In a separate package fmt.unix package.
See also dbuenzli/rresult#17
L088 : /int32/uint32/
L106 : /pp_float_dsig/float_dsig/
L209 : /botttom/bottom/
L241 : /brackets/braces/
L246 : /pp_text/text/
L250 : /pp_lines/lines/
L277 : /pp_byte_size/byte_size/
L282 : /pp_bi_byte_size/bi_byte_size/
Currently, styled formatting is done by (conditionally) outputting terminal escape sequences. This means that there are two choices currently:
However, using Format.tag
, it is possible to have customizable interpretation depending on the output formatter (one being escape sequence).
The upside is that it could output styled things on various outputs (html, lambda_term, etc), given the correct interpretation of tags (which doesn't need to be provided in fmt
).
The downside is that enabling styling must be done for each output formatter.
It's something I did for lambda_term once. The implementation was a bit awkward but the interface ended up being rather simple (one pp
function, like you have currently).
What do you think of adding
val Fmt.print_endline : ('a, Format.formatter, unit, unit) format4 -> 'a
val Fmt.print_endline : ('a, Format.formatter, unit, unit) format4 -> 'a
implemented as
let print_endline fmt = kstrf print_endline fmt
let prerr_endline fmt = kstrf prerr_endline fmt
potentially with better names.
I end up using these often in toplevel sessions and small throw-away scripts/programs when setting up Logs may be more code than it's worth.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.