ocaml-ppx / ocamlformat Goto Github PK
View Code? Open in Web Editor NEWAuto-formatter for OCaml code
License: MIT License
Auto-formatter for OCaml code
License: MIT License
There is a space missing before the constraint
keyword on output.
For example:
type 'a t = 'a list constraint 'a = [< `X]
gives:
$ ocamlformat test.ml -o test_formatted.ml
File "./test_formatted2055e4.ml", line 1, characters 30-31:
Error: Syntax error
with the following output:
type 'a t = 'a listconstraint 'a = [< `X]
$ jbuilder build --root=src -j 4 ocamlformat_reason.exe
File "ocamlformat_reason.ml", line 17, characters 27-51:
Error: Unbound value Migrate_ast.from_current
Hint: Did you mean to_current?
opam switch 4.03.0; make
fails:
(cd _build/opt && /Users/mroch/.opam/4.03.0/bin/ocamlc.opt -safe-string -strict-formats -strict-sequence -principal -w +a-4-6-9-40-41-42-44-45-48@50-21 -short-paths -bin-annot -keep-docs -keep-locs -unboxed-types -noassert -bin-annot -no-alias-deps -I format -open Format___ -o format/format_.cmi -c -intf format/format_.mli)
/Users/mroch/.opam/4.03.0/bin/ocamlc.opt: unknown option '-unboxed-types'.
For example:
let f (type v) (x: v) = x
formats as
let f = fun (type v) -> fun (x: v) -> x
Not sure if this is intentional.
The object language of OCaml is largely unimplemented. Designing the formatting of these constructs would be best done by someone with a lot of experience with them, who knows the readability pitfalls to avoid, etc.
Currently ocamlformat
reformats this to a single line:
let f x = function
| C -> 1
| D -> 2
becomes:
let f x = function C -> 1 | D -> 2
This is nice for aesthetic reasons, but if this code is checked into version control then it'll suddenly get all reformatted to multiple lines whenever one of the expressions becomes longer, making diffs harder to check for correctness. The programmer might've foreseen the expression becoming more complicated and separated each case on a line of its own in advance.
OTOH it could be that there are only ever 2 values there (like for 'a result
), in which case using the multiline pattern matching would be wasteful and harder to read.
Would be nice if there was a configuration field to keep the original singleline vs multiline choice, provided that it can still meet the column width limit.
The following:
let x = {a = 1; b = true}
is reformatted as:
let x = {a= 1; b= true}
One space on either side of the equals sign.
Using current latest version.
2 cases, not nice in both cases:
type (_, _, _, _, _) gadt =
| SomeLongName: ('a, 'b, long_name * long_name2, 't, 'u) gadt * ('b, 'c, 'v, 'u, 'k) gadt2 -> ( 'a
, 'c
, long_name
*
'k
, 't
, 'v
)
gadt
| AnEvenLongerName: ('a, 'b, long_name * long_name2, 't, 'u) gadt * ('b, 'c, 'v, 'u, 'k) gadt2 ->
( 'a
, 'c
, long_name * 'k
, 't
, 'v )
gadt
Expected: ( 'a, 'c, long_name * 'k, 't, 'v ) gadt
in one line
The following diff is also surprising:
let str = to_string t in
of_string_exn ~hostname:false (String.Ascii.lowercase str)
+
(*BISECT-IGNORE-BEGIN*)
let pp ppf xs = Fmt.string ppf (to_string xs)
+
(*BISECT-IGNORE-END*)
-module IntMap = Map.Make(struct
- type t = int
- let compare : int -> int -> int = compare
- end)
+module IntMap = Map.Make (struct
+ type t = int
+
+ let compare : int -> int -> int = compare
+end)
let compare_sub a b =
String.compare (String.Ascii.lowercase a) (String.Ascii.lowercase b)
+
it seems that after let
bindings there are two newlines, but an (interleaved) module
definition ends with a single newline... also a let
binding on a single line ends with only a single newline.
I personally prefer to have only a single newline after a let binding, but am open to use whatever is default, as long as the amount of newlines after each binding is consistent.
Classes are not implemented and when code using classes is formated, the tool crashes with an exception:
$ ocamlformat -m 140 -i test.ml
FAIL
Exp:
let a = r#incr in a
expression (test.ml[2,9+2]..[3,29+3])
Pexp_let Nonrec
[
<def>
pattern (test.ml[2,9+6]..[2,9+7])
Ppat_var "a" (test.ml[2,9+6]..[2,9+7])
expression (test.ml[2,9+10]..[2,9+16])
Pexp_send "incr"
expression (test.ml[2,9+10]..[2,9+11])
Pexp_ident "r" (test.ml[2,9+10]..[2,9+11])
]
expression (test.ml[3,29+2]..[3,29+3])
Pexp_ident "a" (test.ml[3,29+2]..[3,29+3])
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/error.ml" (inlined), line 9, characters 14-30
Called from file "src/error.ml", line 11, characters 19-40
Called from file "Fmt_ast.ml", line 1212, characters 6-49
Called from file "Fmt_ast.ml", line 1996, characters 22-68
Called from file "Fmt_ast.ml", line 2009, characters 8-22
Called from file "Fmt_ast.ml", line 1025, characters 20-122
Called from file "Fmt.ml", line 124, characters 2-6
Called from file "import/Import.ml", line 26, characters 18-21
Called from file "import/Import.ml", line 26, characters 18-21
Called from file "Fmt.ml", line 124, characters 2-6
Called from file "Fmt.ml", line 124, characters 2-6
Called from file "import/Import.ml", line 26, characters 18-21
Called from file "Fmt.ml", line 124, characters 2-6
Called from file "Fmt.ml", line 124, characters 2-6
Called from file "Fmt_ast.ml", line 27, characters 8-13
Fatal error: exception ("Internal Error: classes not implemented")
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
I think it should be added to the limitations paragraph of the readme until an eventual support is added.
In a list literal:
[ 1; (* one *)
2; (* two *) ]
reformats to
;; [(* two *) 1; (* one *) 2]
Note that the (* two *)
comment is now at the start of the list rather than the end.
These files fail with errors related to comments:
Fatal error: exception ("Internal Error: formatting lost comments"
(before
((ast_loc "([3624,167006+6]..[3624,167006+20])")
(cmt_loc "([3623,166896+50]..[3623,166896+109])")
(cmt_txt " used in constructor, destructor and explicit obj msgs ")))
(before
((ast_loc "([3533,162500+5]..[3533,162500+14])")
(cmt_loc "([3532,162419+25]..[3532,162419+80])")
(cmt_txt " list of (key_name,(writer_roles)) for a map field ")))
(before
((ast_loc "([3622,166807+27]..[3622,166807+47])")
(cmt_loc "([3621,166714+46]..[3621,166714+92])")
(cmt_txt " used in implicit obj msgs (get_all, etc) "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Fatal error: exception ("Internal Error: formatting changed comments"
(diff
((First
"\
\n * Copyright (C) Citrix Systems Inc.\
\n *\
\n * This program is free software; you can redistribute it and/or modify\
\n * it under the terms of the GNU Lesser General Public License as published\
\n * by the Free Software Foundation; version 2.1 only. with the special\
\n * exception on linking described in file LICENSE.\
\n *\
\n * This program is distributed in the hope that it will be useful,\
\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\
\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\
\n * GNU Lesser General Public License for more details.\
\n "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Fatal error: exception ("Internal Error: formatting changed comments" (diff ((First " "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Fatal error: exception ("Internal Error: formatting lost comments"
(before
((ast_loc "([2546,62326+6]..[2557,62636+30])")
(cmt_loc "([2545,62288+6]..[2545,62288+37])")
(cmt_txt " We do a DFS in the group. "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Fatal error: exception ("Internal Error: formatting changed comments" (diff ((First " "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Fatal error: exception ("Internal Error: formatting changed comments" (diff ((First " "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Taking an example from https://ocaml.org/learn/tutorials/guidelines.html
let universal_declaration =
"-1- Programs are born and remain free and equal under the law;\n\
distinctions can only be based on the common good."
gets converted to this and exceeds line length:
let universal_declaration =
"-1- Programs are born and remain free and equal under the law;\ndistinctions can only be based on the common good."
An alternative is to use {| |}
where newlines are preserved:
{| -1- Programs are born and remain free and equal under the law;
distinctions can only be based on the common good.|}
The following piece of code yields a syntax error:
let _ =
(function [@warning "-4"] None -> true | _ -> false) None
It seems to be because it duplicates the attribute in the output. Here is the saved temporary file:
let _ =
(function[@warning "-4"] None -> true | _ -> false) [@warning "-4"] None
Thanks!
ocamlformat master fails to format the following saying Internal Error: formatting changed ast
:
let f (`A x) = x
Sorry if this is not the right place for asking the questions. Feel free to close it if so.
I'd like to use ocamlformat
with OCaml v.4.02.3 because I also use it for ReasonML development. Is that possible somehow?
I've tried to install it under v4.05.0, switch back to v4.02.3 and configure my Emacs init.el
like this:
(require 'ocamlformat "~/.opam/4.05.0/packages.dev/ocamlformat/emacs/ocamlformat.el")
Didn't help at all. The ocamlformat
works fine from command line.
with ocamlformat v0.2, I get at the end of file:
in
- names, off
+ (names, off)
+
this extra newline is imho bad (and git diff complains about it by marking it red). it would be great if ocamlformat would avoid generating newlines at the end of file. :)
again, thank you for developing ocamlformat. I'm looking forward to use it and never have to care about formatting of my OCaml code.
Hello,
Thanks for this project. Having a default common style will be great.
While running it on our code base I found some errors. The following file cannot be formatted:
module type S = sig end
type t = (module S)
It just displays Error: Syntax error
, then exits.
I have tested ocamlformat on 5000+ OCaml files from https://github.com/xapi-project.
These files fail when running ocamlformat -i --no-warn-error
:
Fatal error: exception ("Internal Error: formatting changed ast" ("output file" api_server.ml))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "list.ml", line 85, characters 12-15
Called from file "src/list0.ml", line 28, characters 40-75
Tested under Ubuntu 16.04 64bit with OCaml 4.05.0 installed with opam after pinning with --dev-repo
:
#=== ERROR while installing ocamlformat.v0.2 ==================================#
# opam-version 1.2.2
# os linux
# command make
# path /home/hcarty/.opam/4.05.0/build/ocamlformat.v0.2
# compiler 4.05.0
# exit-code 2
# env-file /home/hcarty/.opam/4.05.0/build/ocamlformat.v0.2/ocamlformat-76215-a71bb4.env
# stdout-file /home/hcarty/.opam/4.05.0/build/ocamlformat.v0.2/ocamlformat-76215-a71bb4.out
# stderr-file /home/hcarty/.opam/4.05.0/build/ocamlformat.v0.2/ocamlformat-76215-a71bb4.err
### stdout ###
# sed -e "s|@OPAM_SWITCH[@]|$(opam switch show)|g" src/jbuild-workspace.in > src/jbuild-workspace
# patching file src/Version.ml
# jbuilder build --root=src -j 4 ocamlformat.exe
# Makefile:35: recipe for target 'exe' failed
### stderr ###
# Entering directory '/home/hcarty/.opam/4.05.0/build/ocamlformat.v0.2/src'
# [...]
# ocamlopt Ast.{cmx,o} [opt]
# ocamlopt Translation_unit.{cmx,o} [dbg] (exit 2)
# (cd _build/dbg && /home/hcarty/.opam/4.05.0/bin/ocamlopt.opt -w +a-4-6-9-40-41-42-44-45-48@50 -strict-formats -strict-sequence -principal -short-paths -bin-annot -keep-docs -unboxed-types -open Import -g -opaque -w -a -I /home/hcarty/.opam/4.05.0/lib/base -I /home/hcarty/.opam/4.05.0/lib/base/caml -I /home/hcarty/.opam/4.05.0/lib/base/shadow_stdlib -I /home/hcarty/.opam/4.05.0/lib/bytes -I /home/hcarty/.opam/4.05.0/lib/cmdliner -I /home/hcarty/.opam/4.05.0/lib/ocaml -I /home/hcarty/.opam/4.05.0/lib/ocaml-migrate-parsetree -I /home/hcarty/.opam/4.05.0/lib/ocaml/compiler-libs -I /home/hcarty/.opam/4.05.0/lib/ocamlformat_support -I /home/hcarty/.opam/4.05.0/lib/result -I /home/hcarty/.opam/4.05.0/lib/sexplib/0 -I /home/hcarty/.opam/4.05.0/lib/stdio -I import -no-alias-deps -I . -o Translation_unit.cmx -c -impl Translation_unit.ml)
# File "Translation_unit.ml", line 133, characters 4-19:
# Error: The constructor Warnings.Errors expects 1 argument(s),
# but is applied here to 0 argument(s)
#
# Waiting for 1 job to finish.
# make: *** [exe] Error 1
Files that contain only comments have no parsetree locations at all, which defeats the comment placement algorithm. It seems that comment-only files need to be specifically recognized and all the comments formatted even though they are not attached.
ocamlformat 0.2 from opam is unable to process this syntax:
val run :
unit -> (unit -> ('a, [> `Msg of string] as 'b) result) ->
('a, 'b) result
The error:
$ ocamlformat /tmp/x.mli -o /tmp/x2.mli
File "/tmp/x27d8987.mli", line 2, characters 44-45:
Error: Syntax error
The issue seems to be the as 'b
- if I remove that then ocamlformat processes the code without issues.
On Windows, I have some files with the Unix \n
line endings. However, when running them through ocamlformat, the line endings are changed to the Windows \r\n
line endings.
Ocamlformat version: 0.2
Sample file (any file should work):
let () =
let x = () in
x
Looking at this line:
| Pexp_constant _
|Pexp_extension _
[...]
Discussing this on Reddit, I thought this is intentional (to note the fact that multiple guards give the same result), but another user pointed out that this might be a bug where "| " accidentally got replaced by " |"...
ocamlformat/src/Translation_unit.mli
Lines 29 to 38 in f6b50d4
The migrate_ast
param doesn't seem to exist anymore
type t = A : t
is wrongly translated to type t = A -> t
(version 729c358, currently latest)
Simplified repro (test.mli):
module rec A : sig
type t =
| AA of B.t
end
and B : sig
type t =
| BB of A.t
end
Running ocamlformat test.mli
results in Error: Syntax error
.
The intermediate file looks like this:
module rec A : sig
type t = AA of B.t
end
and module rec B : sig
type t = BB of A.t
end
There are extra words module rec
after the and
keyword.
Version: 0.3
OCaml: 4.06.0
Hello,
I found a couple errors when running ocamlformat v0.2 on our code base.
module type S = sig end
type t = (module S)
module type S = sig val x : int end
module M = struct
let x = 0
end
let m = (module M : S)
let () =
let (module M : S) = m in (* error here *)
()
The pattern line gets rewritten as let module M : module S = m in
which is invalid syntax.
I think that it's the same issue but:
module type S = sig val x : int end
module M = struct
let x = 0
end
let m = (module M : S)
let f ((module M : S) as u) = (* error here *)
ignore u;
M.x
The error line gets rewritten as let f (module M: S as u) = ignore u ; M.x
module type S = sig
type a
val va : a
type b
val vb : b
end
let f (module M : S with type a = int and type b = int) = M.va + M.vb
The last line gets rewritten as let f (module M: S with type a = int and b = int) = M.va + M.vb
. (note the missing type
).
Thanks a lot!
ocamlformat is changing begin ... end
to (...)
It retains begin ... end
.
Note that I'm actually not sure if this is intentional. I just think it's a good idea to keep begin ... end
because it's often used to design a nice DSL-like syntax for code.
Bugs in the formatter can lead to a comment in the original source not being generated in the output. Often such a bug can be worked around by moving the comment slightly. Currently, dropping a comment is detected and an exception is raised. It would be better to issue an standard compiler error message identifying the dropped comment.
When ocamlformat detects that formatting changes the parsetree, check if it is only due to relocation of docstrings, and if so report the docstring and old vs new attachment point.
Edit:
Use a more accurate algorithm: get_docstrings would take both parsetrees and traverse them simultaneously, analogously to e.g. List.fold_left2 and at each point in the parsetrees where attributes might appear, compare the docstrings, collecting a list of the differences. Note that the structure of the parsetrees must match (after e.g. Normalize.impl), or else there are bigger problems than docstrings.
Currently building ocamlformat downloads and patches the standard library Format module. Once ocaml/ocaml#1229 is merged:
Format_
and Format
It would be nice to have documentation available describing how to use ocamlformat from within vim.
ocamlformat requires source code that:
--no-warn-error
flag can be passed to try to format even if warning 50 fires, but expect an exception indicating that formatting changed the AST.#use
). jbuild
files in ocaml syntax should work.- Term.(term_result (const Phases.phase1 $ arch $ hub_id $ build_dir $ logs_dir $ setup_logs)),
- Term.info "phase1" ~doc ~sdocs:Manpage.s_common_options ~exits ~man
+ ( (let open Term in
+ term_result
+ (const Phases.phase1 $ arch $ hub_id $ build_dir $ logs_dir $ setup_logs))
+ , Term.info "phase1" ~doc ~sdocs:Manpage.s_common_options ~exits ~man )
+
The following diff seems to be a case of succinct code being written to a longer form. Specifically, the Term.(term
now becomes a let open Term in
, which is very verbose. Is it possible to preserve the M.()
module open syntax?
Hi,
The following piece of code yields a syntax error:
let _ = Some (let open! List in 1)
Here is the saved temporary file:
let _ = Some let open! List in 1
Thanks!
Currently reformatting code such as [ (* this list is empty *) ]
yields [] (* this list is empty *)
. It would be better to detect and preserve this situation by comparing the location ranges of the list and the comment.
Code:
let x : unit = ()
Running ocamlformat foo.ml --inplace
results in Error: Syntax error
.
The intermediate file looks like this:
let x : . unit : unit = ()
Version: 0.2
OCaml: 4.06.0
OS: Reproduced on Windows and Ubuntu
These files fail to be reformatted with ocamlformat due to syntax errors.
ocamlformat
was compiled with 4.05.0
, these files correctly compile when using the build system from their respective repositories with 4.04.2, and at first glance I don't see anything particularly wrong that'd make them fail on 4.05.0
ocamlformat knows how to treat fun
or function
arguments specially if they are the last arg in an application. E.g.:
List.exists r1N ~f:(function
| Rtag (_, _, _, t1N) -> List.exists t1N ~f
| Rinherit t1 -> typ == t1 )
instead of:
List.exists
~f:(function
| Rtag (_, _, _, t1N) -> List.exists t1N ~f
| Rinherit t1 -> typ == t1)
r1N
It would be helpful if the formatter detected cases such as the second above and reordered a single labeled anonymous function argument to the last position.
The --help
text indicates that ocamlformat
should output to stdout by default, but if --inplace
and -o
are both left off of the command then the program fails with an error:
$ ocamlformat test.ml
ocamlformat: Must specify output file without --inplace
"\xff\xaa\x55"
gets converted to "\255\170U"
, and "A\xffB"
to "A\255B"
There should be a configuration field to specify whether this conversion is desired, and I'd prefer if ocamlformat
wouldn't change the choice of escape sequence when all bytes in the string use the same escape sequence.
OTOH if someone writes "\xff\170U" .... I wouldn't mind if ocamlformat chose one.
A simple file that yields an error:
module X (* : sig
val x : unit -> unit
end *) = struct
let x () = print_endline "coucou"
end
Fatal error: exception ("Internal Error: formatting lost comments"
(after
((ast_loc "([1,0+7]..[1,0+8])") (cmt_loc "([1,0+9]..[3,42+6])")
(cmt_txt " : sig \
\n val x : unit -> unit\
\nend "))))
Raised at file "src/import0.ml" (inlined), line 234, characters 22-32
Called from file "src/exn.ml", line 70, characters 6-15
Called from file "ocamlformat.ml", line 56, characters 7-170
Once #27 is merged there's probably not much left to document. One bit I do find useful is this binding to run ocamlformat
on the current file by pressing C-M-<tab>
. I think it's worth documenting how to do a keybinding like that easily (requires tuareg and merlin):
(add-hook
'tuareg-mode-hook
(lambda ()
(define-key merlin-mode-map (kbd "C-M-<tab>") 'ocamlformat)))
Prior to modifying any input file, ocamlformat checks that:
Follow up to Josh's comment here, ocamlformat currently desugars ppx syntax:
let _ =
let%lwt foo = Lwt.return 1 in
Lwt.return_unit
becomes
let _ =
[%lwt
let foo = Lwt.return 1 in
Lwt.return_unit]
Which becomes even weirder with multiple ppx usages in a row:
let _ =
let%lwt foo = Lwt.return 1 in
let%lwt bar = Lwt.return 1 in
let%lwt baz = Lwt.return 1 in
Lwt.return_unit
becomes
let _ =
[%lwt
let foo = Lwt.return 1 in
[%lwt
let bar = Lwt.return 1 in
[%lwt
let baz = Lwt.return 1 in
Lwt.return_unit]]]
(ocamlformat --version == v0.2
)
The expected behavior is that the syntactic sugar remains unchanged.
I use ocamlformat v0.2 and ocp-indent 1.6.1 (both without any custom configuration), both inside of emacs. My expectation is that they agree upon indentation in pattern matches. The following diff is a bit disappointing:
match Cstruct.get_uint8 buf off with
| 0 -> Ok ((`Z, off), offsets, succ off)
- | i when i >= ptr_tag -> (* 192 is 1100_0000 which is the pointer tag *)
- let ptr = (i - ptr_tag) lsl 8 + Cstruct.get_uint8 buf (succ off) in
- Ok ((`P ptr, off), offsets, off + 2)
- | i when i >= 64 -> Error (`BadTag i) (* bit patterns starting with 10 or 01 *)
- | i -> (* this is clearly < 64! *)
- let name = Cstruct.to_string (Cstruct.sub buf (succ off) i) in
- aux ((name, off) :: offsets) (succ off + i)
+ | i when i >= ptr_tag ->
+ (* 192 is 1100_0000 which is the pointer tag *)
+ let ptr = (i - ptr_tag) lsl 8 + Cstruct.get_uint8 buf (succ off) in
+ Ok ((`P ptr, off), offsets, off + 2)
+ | i when i >= 64 ->
+ Error (`BadTag i) (* bit patterns starting with 10 or 01 *)
+ | i ->
+ (* this is clearly < 64! *)
+ let name = Cstruct.to_string (Cstruct.sub buf (succ off) i) in
+ aux ((name, off) :: offsets) (succ off + i)
I'm not sure how other people use ocamlformat, but I thought of it as a pre-commit hook for my git repository. is there a way to use it instead of ocp-indent for writing code? if not, I can see two solutions for this: provide a .ocp-indent
which has the same behaviour of ocamlformat regarding indentations; or modify ocamlformat to match the default ocp-indent.
(* ... *)
(* ... *)
together
(* ...
... *)
(* ...
* ... *)
to
(* ...
... *)
thank you for developing ocamlformat. I ran it on some source of mine, and struggle with the diff below (esp. ocamlformat (v0.2) disagrees with ocp-indent (1.6.1):
let is_hostname t =
(* TLD should not be all-numeric! *)
- (if Array.length t > 0 then
- String.exists Char.Ascii.is_letter (Array.get t 0)
- else true) &&
- Array.for_all check_host_label t
+ ( if Array.length t > 0 then String.exists Char.Ascii.is_letter t.(0)
+ else true )
+ && Array.for_all check_host_label t
I'd expect the else
to be indented 4 spaces (instead of the 2).
Similar to #56 it would be nice to have keyword%ext
support for other keywords. Lwt's ppx, for example, benefits from match%lwt
, try%lwt
, if%lwt
, for%lwt
and while%lwt
.
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.