Giter Club home page Giter Club logo

ocamlformat's People

Contributors

avsm avatar bcc32 avatar craigfe avatar emiletrotignon avatar emillon avatar gpetiot avatar hcarty avatar hhugo avatar jberdine avatar jeremiedimino avatar julow avatar kevinji avatar khady avatar kit-ty-kate avatar mbarbin avatar mbouaziz avatar mroch avatar naartjie avatar nathanreb avatar nojb avatar panglesd avatar rgrinberg avatar ribeirotomas1904 avatar samoht avatar smondet avatar tdelvecchio-jsc avatar tmattio avatar trefis avatar wilfred avatar xvilka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ocamlformat's Issues

Fails on type with "constraint" applied

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]

`ocamlformat_reason` doesn't build

$ 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?

Doesn't support ocaml 4.03.0

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'.

Add support for the OCaml object language

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.

Add option to always break pattern match cases

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.

Ugly splitting of GADT return type parameters

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

more newlines: between top-level `let` bindings vs modules

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/objects are not supported

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.

Comment reordering in list literals

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.

Fatal error: formatting lost/changed comments

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

Automatically wrap long strings

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.|}

Syntax error with duplicated attribute in `function`

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!

Configure Emacs for v4.02.3

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.

trailing newline at end of file

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.

Syntax error with first class modules

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.

Fatal error: formatting changed ast

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

Latest master branch doesn't build against 4.05.0

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

Comments dropped from files consisting of only comments

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.

Failure to parse "as" in value's mli entry

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.

Line endings changed to \r\n on Windows.

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

Whitespace in pattern matching

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 " |"...

Translation_unit.parse docs incorrect

val parse :
(Lexing.lexbuf -> 'a) -> ?warn:bool -> string -> string -> In_channel.t
-> 'a * (string * Location.t) list
(** [parse migrate_ast parse_ast ~warn input_name input_file input_channel]
parses the contents of [input_channel] assuming it corresponds to
[input_name] for the purposes of error reporting and to the contents of
[input_file] for the purposes of comment placement. Actual parsing is
done by [parse_ast] and the resulting ast is migrated to the current
version using [migrate_ast]. If [warn] is set, then parse-time warnings
are fatal, otherwise only enabled. *)

The migrate_ast param doesn't seem to exist anymore

"Syntax error" on recursive signature definitions

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

Several small bugs with first class modules

Hello,
I found a couple errors when running ocamlformat v0.2 on our code base.

  • In an interface file (same as #29 which was fixed for implementations):
module type S = sig end
type t = (module S)
  • Patterns are rewritten without parens:
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 constraints are not rewritten correctly
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!

Changing begin...end to (...)

Observed

ocamlformat is changing begin ... end to (...)

Excpected

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.

Give informative error message when comment dropped

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.

Use a more accurate simultaneous traversal algorithm to detect when docstrings move

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.

Document vim setup

It would be nice to have documentation available describing how to use ocamlformat from within vim.

Document requirements on source files to format

ocamlformat requires source code that:

  • does not trigger warning 50. For code that triggers warning 50, it is unlikely that ocamlformat will happen to preserve the docstring attachment. The --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.
  • parses without any preprocessing, using the version of the ocaml standard (not camlp4) parser with which ocamlformat was itself built. Attributes and extension points should be correctly preserved, but other mechanisms such as camlp4, cppo, etc. will not work.
  • is either a module implementation (.ml) or interface (.mli) but not a sequence of toplevel phrases (that is, including toplevel directives such as #use). jbuild files in ocaml syntax should work.

Add option to use short local module open even when it costs indentation

-  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?

Preserve position of comments within empty lists

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.

Syntax failure on type annotation

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

ocamlformat: syntax error

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

Reorder labeled anonymous function arguments

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.

Does not output to stdout by default

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

Preserve original escape sequences in strings

"\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.

Internal Error: formatting lost comments

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

Document emacs installation

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)))

Document the sanity checking that is performed

Prior to modifying any input file, ocamlformat checks that:

  • the parsetrees obtained by parsing the original and formatted files are equal up to some minor normalization (see Normalize.equal_impl or equal_intf).
  • the docstrings, and their attachment, has been preserved (implicit in the parsetree check)
  • the set of comments in the original and formatted files is the same up to their location

Syntax sugar for ppx

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.

indentation in pattern matches

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.

Automatically format comments

  • combine multiple full-line comments
(* ... *)
(* ... *)

together

(* ...
   ... *)
  • remove leading '*' characters, converting e.g.
(* ...
 * ... *)

to

(* ...
   ... *)
  • wrap lines similar to strings in #11
  • preserve formatting within literal string delimiters such as {| |}

indentation quirks

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).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.