From 01b7b3bebde025f2132e28a9f72acba7b247c104 Mon Sep 17 00:00:00 2001 From: Andrey Popp <8mayday@gmail.com> Date: Wed, 6 Sep 2023 18:53:11 +0400 Subject: [PATCH 1/3] ocamlformat-mlx --- .github/workflows/build-linux.yml | 129 +++++++------- .github/workflows/build-mingw64.yml | 14 +- .github/workflows/build-others.yml | 4 +- .github/workflows/changelog-check.yml | 5 +- Makefile | 2 +- bin/dune | 1 + bin/ocamlformat/dune | 14 +- dune | 2 +- dune-project | 102 ++++++----- lib/Ast.ml | 7 +- lib/Ast.mli | 2 +- lib/Fmt_ast.ml | 64 +++++++ lib/bin_conf/Bin_conf.ml | 2 +- lib/bin_conf/dune | 4 +- lib/dune | 2 +- ocamlformat-bench.opam | 44 ----- ...ormat-lib.opam => ocamlformat-mlx-lib.opam | 20 +-- ...plate => ocamlformat-mlx-lib.opam.template | 0 ocamlformat.opam => ocamlformat-mlx.opam | 20 +-- ....template => ocamlformat-mlx.opam.template | 0 ocamlformat-rpc-lib.opam | 41 ----- test/dune | 1 + test/mlx/dune | 3 + test/mlx/mlx.t | 164 ++++++++++++++++++ vendor/ocaml-common/dune | 2 +- vendor/ocamlformat-stdlib/dune | 2 +- vendor/ocamlformat_support/dune | 2 +- vendor/odoc-parser/dune | 2 +- vendor/parser-extended/dune | 2 +- vendor/parser-extended/jsx_helper.ml | 82 +++++++++ vendor/parser-extended/lexer.mll | 26 ++- vendor/parser-extended/parser.mly | 44 +++++ vendor/parser-shims/dune | 2 +- vendor/parser-shims/stdlib_shims/dune | 2 +- vendor/parser-standard/dune | 2 +- vendor/parser-standard/jsx_helper.ml | 82 +++++++++ vendor/parser-standard/lexer.mll | 26 ++- vendor/parser-standard/parser.mly | 50 ++++++ 38 files changed, 709 insertions(+), 264 deletions(-) create mode 100644 bin/dune delete mode 100644 ocamlformat-bench.opam rename ocamlformat-lib.opam => ocamlformat-mlx-lib.opam (70%) rename ocamlformat-lib.opam.template => ocamlformat-mlx-lib.opam.template (100%) rename ocamlformat.opam => ocamlformat-mlx.opam (76%) rename ocamlformat.opam.template => ocamlformat-mlx.opam.template (100%) delete mode 100644 ocamlformat-rpc-lib.opam create mode 100644 test/dune create mode 100644 test/mlx/dune create mode 100644 test/mlx/mlx.t create mode 100644 vendor/parser-extended/jsx_helper.ml create mode 100644 vendor/parser-standard/jsx_helper.ml diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 4bf1be4ed1..8b097ca6ca 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -36,81 +36,82 @@ jobs: - name: Opam dependencies run: opam install --deps-only -t . - - name: Format - run: opam exec -- dune fmt +# - name: Format +# run: opam exec -- dune fmt - name: Build run: | opam exec -- dune subst - opam exec -- dune build -p ocamlformat-lib,ocamlformat + opam exec -- dune build -p ocamlformat-mlx-lib,ocamlformat-mlx - name: Runtest run: opam exec -- dune runtest - - name: Check manpages - run: opam exec -- dune build @gen_manpage --auto-promote +# - name: Check manpages +# run: opam exec -- dune build @gen_manpage --auto-promote - name: Upload binary # Using a specific version because of https://github.com/actions/upload-artifact/issues/590 uses: actions/upload-artifact@v4.3.4 with: name: ocamlformat-${{ runner.os }}-${{ runner.arch }} - path: _build/install/default/bin/ocamlformat - - test-branch: - if: ${{ github.ref != 'refs/heads/main' }} - needs: build-linux - runs-on: ubuntu-latest - strategy: - matrix: - profile: - - conventional - - ocamlformat - - janestreet - # To enable comparing with ocp-indent: - # include: - # - ocp_indent: true - # ocp_indent_config: JaneStreet - # profile: janestreet - - steps: - - name: Install ocp-indent - if: ${{ matrix.ocp_indent }} - run: | - sudo apt install -y ocp-indent - sudo touch /etc/ocamlfind.conf - - # Clone the project - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - uses: actions/cache@v3 - with: - path: test-extra/code - key: test-extra-code - - - name: Fetch main build of ocamlformat - uses: dawidd6/action-download-artifact@v6 - with: - workflow: build-linux.yml - workflow_conclusion: "" - check_artifacts: true - branch: main - name: ocamlformat-${{ runner.os }}-${{ runner.arch }} - path: ocamlformat-a - - - name: Fetch new build of ocamlformat - uses: actions/download-artifact@v4.1.7 - with: - name: ocamlformat-${{ runner.os }}-${{ runner.arch }} - path: ocamlformat-b - - - name: Test ${{ matrix.profile }} profile - run: | - chmod +x ocamlformat-a/ocamlformat ocamlformat-b/ocamlformat - ./tools/test_branch.sh $TEST_BRANCH_ARGS -n -a ocamlformat-a/ocamlformat -b ocamlformat-b/ocamlformat 'profile=${{ matrix.profile }}' - shell: bash - env: - OCP_INDENT_CONFIG: ${{ matrix.ocp_indent_config }} - TEST_BRANCH_ARGS: ${{ matrix.ocp_indent && '-o -s' || '' }} + path: _build/install/default/bin/ocamlformat-mlx + +# test-branch: +# if: ${{ github.ref != 'refs/heads/main' }} +# needs: build-linux +# runs-on: ubuntu-latest +# strategy: +# matrix: +# profile: +# - conventional +# - ocamlformat +# - janestreet +# # To enable comparing with ocp-indent: +# # include: +# # - ocp_indent: true +# # ocp_indent_config: JaneStreet +# # profile: janestreet +# +# steps: +# - name: Install ocp-indent +# if: ${{ matrix.ocp_indent }} +# run: | +# sudo apt install -y ocp-indent +# sudo touch /etc/ocamlfind.conf +# +# # Clone the project +# - uses: actions/checkout@v3 +# with: +# fetch-depth: 0 +# +# - uses: actions/cache@v3 +# with: +# path: test-extra/code +# key: test-extra-code +# +# - name: Fetch main build of ocamlformat +# uses: dawidd6/action-download-artifact@v6 +# with: +# workflow: build-linux.yml +# workflow_conclusion: "" +# check_artifacts: true +# branch: main +# name: ocamlformat-${{ runner.os }}-${{ runner.arch }} +# path: ocamlformat-a +# allow_forks: true +# +# - name: Fetch new build of ocamlformat +# uses: actions/download-artifact@v4.1.7 +# with: +# name: ocamlformat-${{ runner.os }}-${{ runner.arch }} +# path: ocamlformat-b +# +# - name: Test ${{ matrix.profile }} profile +# run: | +# chmod +x ocamlformat-a/ocamlformat ocamlformat-b/ocamlformat + #./tools/test_branch.sh $TEST_BRANCH_ARGS -n -a ocamlformat-a/ocamlformat -b ocamlformat-b/ocamlformat 'profile=${{ matrix.profile }}' +# shell: bash +# env: +# OCP_INDENT_CONFIG: ${{ matrix.ocp_indent_config }} +# TEST_BRANCH_ARGS: ${{ matrix.ocp_indent && '-o -s' || '' }} diff --git a/.github/workflows/build-mingw64.yml b/.github/workflows/build-mingw64.yml index 92aeae965a..88c1bdcebb 100644 --- a/.github/workflows/build-mingw64.yml +++ b/.github/workflows/build-mingw64.yml @@ -46,21 +46,21 @@ jobs: - name: Install dependencies run: | - opam pin add -yn ocamlformat-lib.dev . - opam pin add -yn ocamlformat.dev . - opam install -y --deps-only ocamlformat + opam pin add -yn ocamlformat-mlx-lib.dev . + opam pin add -yn ocamlformat-mlx.dev . + opam install -y --deps-only ocamlformat-mlx - name: Build run: | opam exec -- dune subst - opam exec -- dune build -p ocamlformat-lib,ocamlformat @install - opam exec -- dune install --prefix=install ocamlformat - Copy-Item ${{ github.workspace }}\\install\\bin\\ocamlformat.exe -Destination .\${{ env.artifact_name }} + opam exec -- dune build -p ocamlformat-mlx-lib,ocamlformat-mlx @install + opam exec -- dune install --prefix=install ocamlformat-mlx + Copy-Item ${{ github.workspace }}\\install\\bin\\ocamlformat-mlx.exe -Destination .\${{ env.artifact_name }} - name: Version check run: | echo "Version check:" - install/bin/ocamlformat.exe --version + install/bin/ocamlformat-mlx.exe --version - name: Upload Artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/build-others.yml b/.github/workflows/build-others.yml index a51c201838..853d65fddf 100644 --- a/.github/workflows/build-others.yml +++ b/.github/workflows/build-others.yml @@ -40,8 +40,8 @@ jobs: - name: Opam dependencies run: opam install --deps-only -t . - - name: Format - run: opam exec -- dune fmt +# - name: Format +# run: opam exec -- dune fmt - name: Runtest run: opam exec -- dune runtest diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index 3d12e892f9..422f7941ce 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -8,6 +8,9 @@ on: jobs: Changelog-Entry-Check: name: Check Changelog Action - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: tarides/changelog-check-action@v1 + # We don't push changelog entries + # steps: + # - uses: tarides/changelog-check-action@v1 diff --git a/Makefile b/Makefile index 5e690620d8..5694c59479 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ default: exe .PHONY: exe exe: - @dune build bin/ocamlformat/main.exe bin/ocamlformat-rpc/main.exe + @dune build bin/ocamlformat/main.exe .PHONY: clean clean: diff --git a/bin/dune b/bin/dune new file mode 100644 index 0000000000..4d21c8d55c --- /dev/null +++ b/bin/dune @@ -0,0 +1 @@ +(data_only_dirs ocamlformat-rpc) diff --git a/bin/ocamlformat/dune b/bin/ocamlformat/dune index 86de53edca..b54d238867 100644 --- a/bin/ocamlformat/dune +++ b/bin/ocamlformat/dune @@ -11,21 +11,21 @@ (executable (name main) - (public_name ocamlformat) - (package ocamlformat) + (public_name ocamlformat-mlx) + (package ocamlformat-mlx) (modules main) (flags (:standard -open Ocamlformat_stdlib)) (instrumentation (backend bisect_ppx)) - (libraries ocamlformat-lib bin_conf)) + (libraries ocamlformat-mlx-lib bin_conf)) (rule (with-stdout-to ocamlformat.1 (run ./main.exe --help=groff))) -(install - (section man) - (files ocamlformat.1) - (package ocamlformat)) +; (install +; (section man) +; (files ocamlformat.1) +; (package ocamlformat)) diff --git a/dune b/dune index a30a8353e4..5d63e0858d 100644 --- a/dune +++ b/dune @@ -14,7 +14,7 @@ (flags (:standard -noassert)))) -(data_only_dirs test-extra) +(data_only_dirs test-extra mlx lib-rpc lib-rpc-server emacs doc bench tools) (rule (with-stdout-to diff --git a/dune-project b/dune-project index 10c2b76a74..55f58df968 100644 --- a/dune-project +++ b/dune-project @@ -11,7 +11,7 @@ ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(name ocamlformat) +(name ocamlformat-mlx) (using menhir 2.1) @@ -20,28 +20,28 @@ (generate_opam_files true) (authors + "Andrey Popp " "Josh Berdine " "Hugo Heuzard " "Etienne Millon " "Guillaume Petiot " "Jules Aguillon ") -(maintainers - "Guillaume Petiot " - "Jules Aguillon " - "Emile Trotignon ") +(maintainers "Andrey Popp ") (source - (github ocaml-ppx/ocamlformat)) + (github ocaml-mlx/ocamlformat-mlx)) (package - (name ocamlformat-lib) - (synopsis "OCaml Code Formatter") + (name ocamlformat-mlx-lib) + (synopsis "OCaml .mlx Code Formatter") (description - "OCamlFormat is a tool to automatically format OCaml code in a uniform style.") + "OCamlFormat is a tool to automatically format OCaml .mlx code in a uniform style.") (depends (ocaml - (>= 4.08)) + (and + (>= 4.08) + (< 5.3))) (alcotest (and :with-test @@ -64,10 +64,6 @@ (>= 20201216)) (ocaml-version (>= 3.5.0)) - (ocamlformat-rpc-lib - (and - :with-test - (= :version))) (ocp-indent (or (and @@ -88,13 +84,15 @@ camlp-streams)) (package - (name ocamlformat) - (synopsis "Auto-formatter for OCaml code") + (name ocamlformat-mlx) + (synopsis "Auto-formatter for OCaml .mlx code") (description "**ocamlformat** is a code formatter for OCaml. It comes with opinionated default settings but is also fully customizable to suit your coding style.\n\n- **Profiles:** ocamlformat offers profiles we predefined formatting configurations. Profiles include `default`, `ocamlformat`, `janestreet`.\n- **Configurable:** Users can change the formatting profile and configure every option in their `.ocamlformat` configuration file.\n- **Format Comments:** ocamlformat can format comments, docstrings, and even code blocks in your comments.\n- **RPC:** ocamlformat provides an RPC server that can be used by other tools to easily format OCaml Code.") (depends (ocaml - (>= 4.08)) + (and + (>= 4.08) + (< 5.3))) (cmdliner (or (and @@ -106,43 +104,43 @@ (csexp (>= 1.4.0)) dune - (ocamlformat-lib + (ocamlformat-mlx-lib (= :version)) - (ocamlformat-rpc-lib - (and - :with-test - (= :version))) + ; (ocamlformat-rpc-lib + ; (and + ; :with-test + ; (= :version))) (re (>= 1.10.3)))) -(package - (name ocamlformat-bench) - (synopsis "Auto-formatter for OCaml code") - (description - "OCamlFormat is a tool to automatically format OCaml code in a uniform style.") - (depends - (ocaml - (>= 4.08)) - (alcotest - (and - :with-test - (>= 1.3.0))) - (bechamel - (>= 0.2.0)) - (ocamlformat-lib - (= :version)) - stdio - (yojson - (>= 1.6.0)))) +; (package +; (name ocamlformat-bench) +; (synopsis "Auto-formatter for OCaml code") +; (description +; "OCamlFormat is a tool to automatically format OCaml code in a uniform style.") +; (depends +; (ocaml +; (>= 4.08)) +; (alcotest +; (and +; :with-test +; (>= 1.3.0))) +; (bechamel +; (>= 0.2.0)) +; (ocamlformat-lib +; (= :version)) +; stdio +; (yojson +; (>= 1.6.0)))) -(package - (name ocamlformat-rpc-lib) - (synopsis "Auto-formatter for OCaml code (RPC mode)") - (description - "OCamlFormat is a tool to automatically format OCaml code in a uniform style. This package defines a RPC interface to OCamlFormat") - (license MIT) - (depends - (ocaml - (>= 4.08)) - (csexp - (>= 1.4.0)))) +; (package +; (name ocamlformat-rpc-lib) +; (synopsis "Auto-formatter for OCaml code (RPC mode)") +; (description +; "OCamlFormat is a tool to automatically format OCaml code in a uniform style. This package defines a RPC interface to OCamlFormat") +; (license MIT) +; (depends +; (ocaml +; (>= 4.08)) +; (csexp +; (>= 1.4.0)))) diff --git a/lib/Ast.ml b/lib/Ast.ml index 98f9bcff8c..1b4dd1ec04 100644 --- a/lib/Ast.ml +++ b/lib/Ast.ml @@ -781,7 +781,7 @@ let break_between s cc (i1, c1) (i2, c2) = immediate sub-term of [ctx] as assumed by the operations in [Requires_sub_terms]. *) module rec In_ctx : sig - type 'a xt = private {ctx: T.t; ast: 'a} + type 'a xt = {ctx: T.t; ast: 'a} val sub_ast : ctx:T.t -> T.t -> T.t xt @@ -1403,9 +1403,10 @@ end = struct || Option.value_map pia_rhs ~default:false ~f ) | Pexp_prefix (_, e) -> assert (f e) | Pexp_infix (_, e1, e2) -> assert (f e1 || f e2) - | Pexp_apply (e0, e1N) -> + | Pexp_apply (_e0, _e1N) -> + () (* FAIL *) - assert (e0 == exp || List.exists e1N ~f:snd_f) + (* assert (e0 == exp || List.exists e1N ~f:snd_f) *) | Pexp_tuple e1N | Pexp_array e1N | Pexp_list e1N | Pexp_cons e1N -> assert (List.exists e1N ~f) | Pexp_construct (_, e) | Pexp_variant (_, e) -> diff --git a/lib/Ast.mli b/lib/Ast.mli index 64ec25d218..9dfe826b01 100644 --- a/lib/Ast.mli +++ b/lib/Ast.mli @@ -144,7 +144,7 @@ val dump : Format.formatter -> t -> unit (** Term-in-context [{ctx; ast}] records that [ast] is (considered to be) an immediate sub-term of [ctx]. *) -type 'a xt = private {ctx: t; ast: 'a} +type 'a xt = {ctx: t; ast: 'a} val sub_typ : ctx:t -> core_type -> core_type xt (** Construct a core_type-in-context. *) diff --git a/lib/Fmt_ast.ml b/lib/Fmt_ast.ml index 32d28a9688..5182b34f41 100644 --- a/lib/Fmt_ast.ml +++ b/lib/Fmt_ast.ml @@ -2168,6 +2168,70 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens $ fmt_expression c ~box (sub_exp ~ctx e) $ fmt_atrs ) ) | Pexp_apply (e0, e1N1) -> ( + match pexp_attributes with + | [{attr_name={txt="JSX";loc=_}; attr_payload=PStr []; _}] -> + let children = ref None in + let props = List.filter_map e1N1 ~f:(function + | Labelled {txt="children";_}, {pexp_desc=Pexp_list es;pexp_loc;_} -> + children := Some (pexp_loc, es); + None + | Nolabel, {pexp_desc=Pexp_construct ({txt=Lident "()";_}, _); _} -> None + | arg -> Some arg) + in + let start_tag, end_tag = + let name, name_loc, id = + match e0.pexp_desc with + | Pexp_ident {txt=Lident name;loc} -> name, loc, None + | Pexp_ident {txt=Ldot (id, name);loc} -> name, loc, Some id + | _ -> failwith "JSX element tag is not Longident.t" + in + let make tag = + (fun () -> + str (Printf.sprintf "<%s" tag) $ Cmts.fmt_after c name_loc), + (fun () -> str (Printf.sprintf "" tag)) + in + match id with + | None -> make name + | Some id -> + let path = Ocamlformat_ocaml_common.Longident.flatten id in + match name with + | "createElement" -> make (String.concat ~sep:"." path) + | name -> make (Printf.sprintf "%s.%s" (String.concat ~sep:"." path) name) + in + let props = + match props with + | [] -> str "" + | props -> + let fmt_labelled ?(prefix="") label e = + let flabel = str (Printf.sprintf "%s%s" prefix label.txt) in + match e.pexp_desc with + | Pexp_ident {txt=Lident id; loc=_} when String.equal id label.txt -> + flabel + | _ -> + flabel $ str "=" $ fmt_expression c {ctx;ast=e} + in + let fmt_prop = function + | Nolabel, e -> fmt_expression c {ctx;ast=e} + | Labelled label, e -> fmt_labelled label e + | Optional label, e -> fmt_labelled ~prefix:"?" label e + in + space_break $ hvbox 0 (list props (break 1 0) fmt_prop) + in + begin match !children with + | None -> hvbox 2 (start_tag () $ props) $ space_break $ str "/>" + | Some (children_loc, []) when not (Cmts.has_after c.cmts children_loc) -> + hvbox 2 (start_tag () $ props) $ space_break $ str "/>" + | Some (children_loc, children) -> + let head = hvbox 2 (start_tag () $ props $ str ">") in + let children = + hvbox 0 ( + list children (break 1 0) + (fun e -> fmt_expression c {ctx;ast=e}) + $ Cmts.fmt_after c children_loc) + in + hvbox 2 (head $ break 0 0 $ children $ break 0 (-2) $ end_tag ()) + end + | _ -> let wrap = if c.conf.fmt_opts.wrap_fun_args.v then hovbox 2 else hvbox 2 in diff --git a/lib/bin_conf/Bin_conf.ml b/lib/bin_conf/Bin_conf.ml index 26b15c6f7c..543b367fca 100644 --- a/lib/bin_conf/Bin_conf.ml +++ b/lib/bin_conf/Bin_conf.ml @@ -102,7 +102,7 @@ let info = "Unless mentioned otherwise non-formatting options cannot be set in \ attributes or $(b,.ocamlformat) files." ] in - Cmd.info "ocamlformat" ~version:Version.current ~doc ~man + Cmd.info "ocamlformat-mlx" ~version:Version.current ~doc ~man let kind = Decl.Operational diff --git a/lib/bin_conf/dune b/lib/bin_conf/dune index adb7cb12c1..5ed0febb7e 100644 --- a/lib/bin_conf/dune +++ b/lib/bin_conf/dune @@ -1,8 +1,8 @@ (library - (public_name ocamlformat.bin_conf) + (public_name ocamlformat-mlx.bin_conf) (name bin_conf) (flags (:standard -open Ocamlformat_ocaml_common -open Ocamlformat_stdlib)) (instrumentation (backend bisect_ppx)) - (libraries ocamlformat-lib re)) + (libraries ocamlformat-mlx-lib re)) diff --git a/lib/dune b/lib/dune index 1281db301d..15e8d6b159 100644 --- a/lib/dune +++ b/lib/dune @@ -15,7 +15,7 @@ (library (name ocamlformat_lib) - (public_name ocamlformat-lib) + (public_name ocamlformat-mlx-lib) (flags (:standard -open diff --git a/ocamlformat-bench.opam b/ocamlformat-bench.opam deleted file mode 100644 index 4ef1dee209..0000000000 --- a/ocamlformat-bench.opam +++ /dev/null @@ -1,44 +0,0 @@ -# This file is generated by dune, edit dune-project instead -opam-version: "2.0" -synopsis: "Auto-formatter for OCaml code" -description: - "OCamlFormat is a tool to automatically format OCaml code in a uniform style." -maintainer: [ - "Guillaume Petiot " - "Jules Aguillon " - "Emile Trotignon " -] -authors: [ - "Josh Berdine " - "Hugo Heuzard " - "Etienne Millon " - "Guillaume Petiot " - "Jules Aguillon " -] -homepage: "https://github.com/ocaml-ppx/ocamlformat" -bug-reports: "https://github.com/ocaml-ppx/ocamlformat/issues" -depends: [ - "dune" {>= "2.8"} - "ocaml" {>= "4.08"} - "alcotest" {with-test & >= "1.3.0"} - "bechamel" {>= "0.2.0"} - "ocamlformat-lib" {= version} - "stdio" - "yojson" {>= "1.6.0"} - "odoc" {with-doc} -] -build: [ - ["dune" "subst"] {dev} - [ - "dune" - "build" - "-p" - name - "-j" - jobs - "@install" - "@runtest" {with-test} - "@doc" {with-doc} - ] -] -dev-repo: "git+https://github.com/ocaml-ppx/ocamlformat.git" diff --git a/ocamlformat-lib.opam b/ocamlformat-mlx-lib.opam similarity index 70% rename from ocamlformat-lib.opam rename to ocamlformat-mlx-lib.opam index e72e99be38..3c23b5e832 100644 --- a/ocamlformat-lib.opam +++ b/ocamlformat-mlx-lib.opam @@ -1,24 +1,21 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "OCaml Code Formatter" +synopsis: "OCaml .mlx Code Formatter" description: - "OCamlFormat is a tool to automatically format OCaml code in a uniform style." -maintainer: [ - "Guillaume Petiot " - "Jules Aguillon " - "Emile Trotignon " -] + "OCamlFormat is a tool to automatically format OCaml .mlx code in a uniform style." +maintainer: ["Andrey Popp "] authors: [ + "Andrey Popp " "Josh Berdine " "Hugo Heuzard " "Etienne Millon " "Guillaume Petiot " "Jules Aguillon " ] -homepage: "https://github.com/ocaml-ppx/ocamlformat" -bug-reports: "https://github.com/ocaml-ppx/ocamlformat/issues" +homepage: "https://github.com/ocaml-mlx/ocamlformat-mlx" +bug-reports: "https://github.com/ocaml-mlx/ocamlformat-mlx/issues" depends: [ - "ocaml" {>= "4.08"} + "ocaml" {>= "4.08" & < "5.3"} "alcotest" {with-test & >= "1.3.0"} "base" {>= "v0.12.0"} "cmdliner" {>= "1.1.0"} @@ -31,7 +28,6 @@ depends: [ "menhirLib" {>= "20201216"} "menhirSdk" {>= "20201216"} "ocaml-version" {>= "3.5.0"} - "ocamlformat-rpc-lib" {with-test & = version} "ocp-indent" {with-test = "false" & >= "1.8.0" | with-test & >= "1.8.1"} "stdio" "uuseg" {>= "10.0.0"} @@ -55,6 +51,6 @@ build: [ "@doc" {with-doc} ] ] -dev-repo: "git+https://github.com/ocaml-ppx/ocamlformat.git" +dev-repo: "git+https://github.com/ocaml-mlx/ocamlformat-mlx.git" # OCamlFormat is distributed under the MIT license. Parts of the OCaml library are vendored for OCamlFormat and distributed under their original LGPL 2.1 license license: ["MIT" "LGPL-2.1-only WITH OCaml-LGPL-linking-exception"] diff --git a/ocamlformat-lib.opam.template b/ocamlformat-mlx-lib.opam.template similarity index 100% rename from ocamlformat-lib.opam.template rename to ocamlformat-mlx-lib.opam.template diff --git a/ocamlformat.opam b/ocamlformat-mlx.opam similarity index 76% rename from ocamlformat.opam rename to ocamlformat-mlx.opam index 24bd11c530..5e59c51c16 100644 --- a/ocamlformat.opam +++ b/ocamlformat-mlx.opam @@ -1,6 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "Auto-formatter for OCaml code" +synopsis: "Auto-formatter for OCaml .mlx code" description: """ **ocamlformat** is a code formatter for OCaml. It comes with opinionated default settings but is also fully customizable to suit your coding style. @@ -8,27 +8,23 @@ description: """ - **Configurable:** Users can change the formatting profile and configure every option in their `.ocamlformat` configuration file. - **Format Comments:** ocamlformat can format comments, docstrings, and even code blocks in your comments. - **RPC:** ocamlformat provides an RPC server that can be used by other tools to easily format OCaml Code.""" -maintainer: [ - "Guillaume Petiot " - "Jules Aguillon " - "Emile Trotignon " -] +maintainer: ["Andrey Popp "] authors: [ + "Andrey Popp " "Josh Berdine " "Hugo Heuzard " "Etienne Millon " "Guillaume Petiot " "Jules Aguillon " ] -homepage: "https://github.com/ocaml-ppx/ocamlformat" -bug-reports: "https://github.com/ocaml-ppx/ocamlformat/issues" +homepage: "https://github.com/ocaml-mlx/ocamlformat-mlx" +bug-reports: "https://github.com/ocaml-mlx/ocamlformat-mlx/issues" depends: [ - "ocaml" {>= "4.08"} + "ocaml" {>= "4.08" & < "5.3"} "cmdliner" {with-test = "false" & >= "1.1.0" | with-test & >= "1.2.0"} "csexp" {>= "1.4.0"} "dune" {>= "2.8"} - "ocamlformat-lib" {= version} - "ocamlformat-rpc-lib" {with-test & = version} + "ocamlformat-mlx-lib" {= version} "re" {>= "1.10.3"} "odoc" {with-doc} ] @@ -46,6 +42,6 @@ build: [ "@doc" {with-doc} ] ] -dev-repo: "git+https://github.com/ocaml-ppx/ocamlformat.git" +dev-repo: "git+https://github.com/ocaml-mlx/ocamlformat-mlx.git" # OCamlFormat is distributed under the MIT license. Parts of the OCaml library are vendored for OCamlFormat and distributed under their original LGPL 2.1 license license: ["MIT" "LGPL-2.1-only WITH OCaml-LGPL-linking-exception"] diff --git a/ocamlformat.opam.template b/ocamlformat-mlx.opam.template similarity index 100% rename from ocamlformat.opam.template rename to ocamlformat-mlx.opam.template diff --git a/ocamlformat-rpc-lib.opam b/ocamlformat-rpc-lib.opam deleted file mode 100644 index 66cee8b9fd..0000000000 --- a/ocamlformat-rpc-lib.opam +++ /dev/null @@ -1,41 +0,0 @@ -# This file is generated by dune, edit dune-project instead -opam-version: "2.0" -synopsis: "Auto-formatter for OCaml code (RPC mode)" -description: - "OCamlFormat is a tool to automatically format OCaml code in a uniform style. This package defines a RPC interface to OCamlFormat" -maintainer: [ - "Guillaume Petiot " - "Jules Aguillon " - "Emile Trotignon " -] -authors: [ - "Josh Berdine " - "Hugo Heuzard " - "Etienne Millon " - "Guillaume Petiot " - "Jules Aguillon " -] -license: "MIT" -homepage: "https://github.com/ocaml-ppx/ocamlformat" -bug-reports: "https://github.com/ocaml-ppx/ocamlformat/issues" -depends: [ - "dune" {>= "2.8"} - "ocaml" {>= "4.08"} - "csexp" {>= "1.4.0"} - "odoc" {with-doc} -] -build: [ - ["dune" "subst"] {dev} - [ - "dune" - "build" - "-p" - name - "-j" - jobs - "@install" - "@runtest" {with-test} - "@doc" {with-doc} - ] -] -dev-repo: "git+https://github.com/ocaml-ppx/ocamlformat.git" diff --git a/test/dune b/test/dune new file mode 100644 index 0000000000..fb5d5de09b --- /dev/null +++ b/test/dune @@ -0,0 +1 @@ +(data_only_dirs rpc cli passing failing disabled projects unit) diff --git a/test/mlx/dune b/test/mlx/dune new file mode 100644 index 0000000000..901c99d7cd --- /dev/null +++ b/test/mlx/dune @@ -0,0 +1,3 @@ +(cram + (package ocamlformat-mlx) + (deps %{bin:ocamlformat-mlx})) diff --git a/test/mlx/mlx.t b/test/mlx/mlx.t new file mode 100644 index 0000000000..a61a7b3e94 --- /dev/null +++ b/test/mlx/mlx.t @@ -0,0 +1,164 @@ +Setup: + $ alias fmt="ocamlformat-mlx - --impl --enable-outside-detected-project" + +Basics: + $ echo '
' | fmt +
+ + $ echo '
' | fmt +
+ + $ echo '
child
' | fmt +
child
+ + $ echo '
child1 child2
' | fmt +
child1 child2
+ +Prop wrapping: + $ echo '
' | fmt --margin=50 +
+ + $ echo '
' | fmt --margin=50 +
+
+
+ + $ echo '
' | fmt --margin=50 +
+
+
+ +Prop wrapping with comments: + $ echo '
' | fmt --margin=50 + +
+ + +Children wrapping: + $ echo '
some child
' | fmt --margin=60 +
+
some child +
+ +Prop punning: + $ echo '
' | fmt --margin=50 +
+ + $ echo '
' | fmt --margin=50 +
+ +Children wrapping: + $ echo '
some child
' | fmt --margin=50 +
+
+ some + child +
+ +Children wrapping: + $ echo '
some child
' | fmt --margin=60 +
+
some child +
+ +Optional props: + $ echo '
' | fmt --margin=50 +
+ + $ echo '
' | fmt --margin=50 +
+ +Props expressions: + $ echo '
' | fmt --margin=50 +
+ $ echo '
' | fmt --margin=50 +
+ $ echo '
' | fmt --margin=50 +
+ $ echo '
' | fmt --margin=50 +
+ +Uident: + $ echo '' | fmt + + +Uident: + $ echo '' | fmt + + +Modident: + $ echo '' | fmt + + +Comments: + $ echo '
a (* 1 *)
' | fmt +
a (* 1 *)
+ $ echo ' a (* 1 *) ' | fmt + a (* 1 *) + $ echo ' a (* 1 *) ' | fmt + a (* 1 *) + + $ echo '
(* 1 *) b
' | fmt +
(* 1 *) b
+ $ echo ' (* 1 *) b ' | fmt + (* 1 *) b + $ echo ' (* 1 *) b ' | fmt + (* 1 *) b + + $ echo '
a (* 1 *) b
' | fmt +
a (* 1 *) b
+ $ echo ' a (* 1 *) b ' | fmt + a (* 1 *) b + $ echo ' a (* 1 *) b ' | fmt + a (* 1 *) b + + $ echo '
(* 1 *)
' | fmt +
(* 1 *)
+ $ echo ' (* 1 *) ' | fmt + (* 1 *) + $ echo ' (* 1 *) ' | fmt + (* 1 *) + + $ echo '
' | fmt +
+ $ echo '
' | fmt +
+ $ echo '
' | fmt +
+ $ echo '
' | fmt +
+ + $ echo '
' | fmt +
+ $ echo '' | fmt + + $ echo '' | fmt + + + $ echo '
' | fmt +
+ $ echo '' | fmt + + $ echo '' | fmt + diff --git a/vendor/ocaml-common/dune b/vendor/ocaml-common/dune index 3b05cf2c4a..1b4d2bc721 100644 --- a/vendor/ocaml-common/dune +++ b/vendor/ocaml-common/dune @@ -1,6 +1,6 @@ (library (name ocamlformat_ocaml_common) - (public_name ocamlformat-lib.ocaml_common) + (public_name ocamlformat-mlx-lib.ocaml_common) (flags (:standard -w -9 -open Ocamlformat_parser_shims)) (libraries ocamlformat_parser_shims)) diff --git a/vendor/ocamlformat-stdlib/dune b/vendor/ocamlformat-stdlib/dune index ff5ab41a14..cb211f5efb 100644 --- a/vendor/ocamlformat-stdlib/dune +++ b/vendor/ocamlformat-stdlib/dune @@ -1,6 +1,6 @@ (library (name ocamlformat_stdlib) - (public_name ocamlformat-lib.ocamlformat_stdlib) + (public_name ocamlformat-mlx-lib.ocamlformat_stdlib) (flags (:standard -open Ocamlformat_ocaml_common)) (libraries base cmdliner ocamlformat_ocaml_common fpath stdio)) diff --git a/vendor/ocamlformat_support/dune b/vendor/ocamlformat_support/dune index 078dc7e575..c47eb60cd6 100644 --- a/vendor/ocamlformat_support/dune +++ b/vendor/ocamlformat_support/dune @@ -1,6 +1,6 @@ (library (name ocamlformat_format) - (public_name ocamlformat-lib.format_) + (public_name ocamlformat-mlx-lib.format_) (flags (:standard -open Ocamlformat_parser_shims)) (libraries either ocamlformat_parser_shims)) diff --git a/vendor/odoc-parser/dune b/vendor/odoc-parser/dune index fafcd25f7e..64a5bdd509 100644 --- a/vendor/odoc-parser/dune +++ b/vendor/odoc-parser/dune @@ -2,7 +2,7 @@ (library (name ocamlformat_odoc_parser) - (public_name ocamlformat-lib.odoc_parser) + (public_name ocamlformat-mlx-lib.odoc_parser) (instrumentation (backend bisect_ppx)) (flags diff --git a/vendor/parser-extended/dune b/vendor/parser-extended/dune index 629a6d0886..5ffb0dd0e4 100644 --- a/vendor/parser-extended/dune +++ b/vendor/parser-extended/dune @@ -1,6 +1,6 @@ (library (name ocamlformat_parser_extended) - (public_name ocamlformat-lib.parser_extended) + (public_name ocamlformat-mlx-lib.parser_extended) (flags (:standard -w diff --git a/vendor/parser-extended/jsx_helper.ml b/vendor/parser-extended/jsx_helper.ml new file mode 100644 index 0000000000..3442b03f0c --- /dev/null +++ b/vendor/parser-extended/jsx_helper.ml @@ -0,0 +1,82 @@ +open Printf +open Asttypes +open Longident +open Parsetree +open Ast_helper + +let make_loc (startpos, endpos) = + { + Location.loc_start = startpos; + Location.loc_end = endpos; + Location.loc_ghost = false; + } + +let mkloc = Location.mkloc +let mkexp ~loc d = Exp.mk ~loc:(make_loc loc) d + +let mkjsxexp ~loc:loc' e = + let e = mkexp ~loc:loc' e in + let loc = make_loc loc' in + let pexp_attributes = [ Attr.mk ~loc { txt = "JSX"; loc } (PStr []) ] in + { e with pexp_attributes } + +let rec equal_longindent a b = + match a, b with + | Longident.Lident a, Longident.Lident b -> String.equal a b + | Ldot (pa, a), Ldot (pb, b) -> + String.equal a b && equal_longindent pa pb + | Lapply _, _ | _, Lapply _ -> assert false + | _ -> false + +let make_jsx_element ~raise ~loc:_ ~tag ~end_tag ~props ~children () = + let () = + match end_tag with + | None -> () + | Some (end_tag, (_, end_loc_e)) -> + let eq = + match tag, end_tag with + | (`Module, _, s), (`Module, _, e) -> equal_longindent s e + | (`Value, _, s), (`Value, _, e) -> equal_longindent s e + | _ -> false + in + if not eq then + let _, (end_loc_s, _), _ = end_tag in + let end_loc = end_loc_s, end_loc_e in + let _, start_loc, tag = tag in + let tag = Longident.flatten tag |> String.concat "." in + raise + Syntaxerr.( + Error + (Unclosed + ( make_loc start_loc, + sprintf "<%s>" tag, + make_loc end_loc, + sprintf "" tag ))) + in + let tag = + match tag with + | `Value, loc, txt -> + mkexp ~loc (Pexp_ident { loc = make_loc loc; txt }) + | `Module, loc, txt -> + let txt = Longident.Ldot (txt, "createElement") in + mkexp ~loc (Pexp_ident { loc = make_loc loc; txt }) + in + let props = + let prop_exp ~loc name = + let id = mkloc (Lident name.txt) (make_loc loc) in + mkexp ~loc (Pexp_ident id) + in + List.map + (function + | loc, `Prop_punned name -> Labelled {txt=name.txt;loc = make_loc loc}, prop_exp ~loc name + | loc, `Prop_opt_punned name -> Optional {txt=name.txt;loc = make_loc loc}, prop_exp ~loc name + | _loc, `Prop (name, expr) -> Labelled name, expr + | _loc, `Prop_opt (name, expr) -> Optional name, expr) + props + in + let unit = + Exp.mk ~loc:Location.none + (Pexp_construct ({ txt = Lident "()"; loc = Location.none }, None)) + in + let props = (Labelled {txt="children"; loc=children.pexp_loc}, children) :: props in + Pexp_apply (tag, (Nolabel, unit) :: props) diff --git a/vendor/parser-extended/lexer.mll b/vendor/parser-extended/lexer.mll index 8d36620dfd..a26ddf1e44 100644 --- a/vendor/parser-extended/lexer.mll +++ b/vendor/parser-extended/lexer.mll @@ -500,6 +500,12 @@ let delim_ext = (lowercase | uppercase | utf8)* let symbolchar = ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>' '?' '@' '^' '|' '~'] +let symbolchar_no_prefix = + ['$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>' '?' '@' '^' '|' '~'] +let symbolchar_no_greater = + ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '?' '@' '^' '|' '~'] +let symbolchar_no_less = + ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '=' '>' '?' '@' '^' '|' '~'] let dotsymbolchar = ['!' '$' '%' '&' '*' '+' '-' '/' ':' '=' '>' '?' '@' '^' '|'] let symbolchar_or_hash = @@ -571,6 +577,10 @@ rule token = parse } | lowercase identchar * as name { find_keyword lexbuf name } + | "<" (lowercase identchar * as name) + { JSX_LIDENT name } + | "<" "/" (lowercase identchar * as name) + { JSX_LIDENT_E name } | uppercase identchar * as name { UIDENT name } (* No capitalized keywords *) | (raw_ident_escape? as escape) (ident_ext as raw_name) @@ -585,6 +595,10 @@ rule token = parse (* Compared to upstream, the raw_ident_escape is part of the lident. *) LIDENT (escape ^ name) } (* No non-ascii keywords *) + | "<" (uppercase identchar * as name) + { JSX_UIDENT name } + | "<" "/" (uppercase identchar * as name) + { JSX_UIDENT_E name } | int_literal as lit { INT (lit, None) } | (int_literal as lit) (literal_modifier as modif) { INT (lit, Some modif) } @@ -709,6 +723,7 @@ rule token = parse | ";" { SEMI } | ";;" { SEMISEMI } | "<" { LESS } + | "" { GREATER } + | "/>" { SLASHGREATER } | ">]" { GREATERRBRACKET } | "}" { RBRACE } | ">}" { GREATERRBRACE } @@ -742,7 +758,11 @@ rule token = parse { PREFIXOP op } | ['~' '?'] symbolchar_or_hash + as op { PREFIXOP op } - | ['=' '<' '>' '|' '&' '$'] symbolchar * as op + | ['<' '|' '&' '$'] symbolchar * as op + { INFIXOP0 op } + | '=' symbolchar_no_prefix * as op + { INFIXOP0 op } + | ">" symbolchar_no_less * as op { INFIXOP0 op } | ['@' '^'] symbolchar * as op { INFIXOP1 op } @@ -752,7 +772,9 @@ rule token = parse { INFIXOP4 op } | '%' { PERCENT } | '/' { SLASH } - | ['*' '/' '%'] symbolchar * as op + | ['*' '%'] symbolchar * as op + { INFIXOP3 op } + | "/" symbolchar_no_greater * as op { INFIXOP3 op } | '#' symbolchar_or_hash + as op { HASHOP op } diff --git a/vendor/parser-extended/parser.mly b/vendor/parser-extended/parser.mly index 718cba274e..4186c7c946 100644 --- a/vendor/parser-extended/parser.mly +++ b/vendor/parser-extended/parser.mly @@ -672,6 +672,7 @@ let mk_directive ~loc name arg = %token FUNCTION "function" %token FUNCTOR "functor" %token GREATER ">" +%token SLASHGREATER "/>" %token GREATERRBRACE ">}" %token GREATERRBRACKET ">]" %token IF "if" @@ -699,9 +700,12 @@ let mk_directive ~loc name arg = %token LBRACKETPERCENT "[%" %token LBRACKETPERCENTPERCENT "[%%" %token LESS "<" +%token LESSSLASH " LIDENT "lident" (* just an example *) +%token JSX_LIDENT " JSX_LIDENT_E " UIDENT "UIdent" (* just an example *) +%token JSX_UIDENT " JSX_UIDENT_E " Ldot (Lident prefix, id) + | Ldot (prefix', id) -> Ldot (rebase prefix', id) + | Lapply _ -> assert false + in + `Module, $sloc, rebase id } + | prefix = uident DOT id = val_longident { + let rec rebase = function + | Lident id -> Ldot (Lident prefix, id) + | Ldot (prefix', id) -> Ldot (rebase prefix', id) + | Lapply _ -> assert false + in + `Value, $sloc, rebase id } +; val_longident: mk_longident(mod_longident, val_ident) { $1 } ; diff --git a/vendor/parser-shims/dune b/vendor/parser-shims/dune index ff2677543a..0d7be9b333 100644 --- a/vendor/parser-shims/dune +++ b/vendor/parser-shims/dune @@ -1,6 +1,6 @@ (library (name ocamlformat_parser_shims) - (public_name ocamlformat-lib.parser_shims) + (public_name ocamlformat-mlx-lib.parser_shims) (flags (:standard -w -37 -w -38 -open Ocamlformat_stdlib_shims)) (libraries compiler-libs.common ocamlformat_stdlib_shims)) diff --git a/vendor/parser-shims/stdlib_shims/dune b/vendor/parser-shims/stdlib_shims/dune index ca4b376618..d86836cbc9 100644 --- a/vendor/parser-shims/stdlib_shims/dune +++ b/vendor/parser-shims/stdlib_shims/dune @@ -1,3 +1,3 @@ (library (name ocamlformat_stdlib_shims) - (public_name ocamlformat-lib.stdlib_shims)) + (public_name ocamlformat-mlx-lib.stdlib_shims)) diff --git a/vendor/parser-standard/dune b/vendor/parser-standard/dune index bdfba81205..67979f5b34 100644 --- a/vendor/parser-standard/dune +++ b/vendor/parser-standard/dune @@ -1,6 +1,6 @@ (library (name ocamlformat_parser_standard) - (public_name ocamlformat-lib.parser_standard) + (public_name ocamlformat-mlx-lib.parser_standard) (flags (:standard -w diff --git a/vendor/parser-standard/jsx_helper.ml b/vendor/parser-standard/jsx_helper.ml new file mode 100644 index 0000000000..b83d1106c8 --- /dev/null +++ b/vendor/parser-standard/jsx_helper.ml @@ -0,0 +1,82 @@ +open Printf +open Asttypes +open Longident +open Parsetree +open Ast_helper + +let make_loc (startpos, endpos) = + { + Location.loc_start = startpos; + Location.loc_end = endpos; + Location.loc_ghost = false; + } + +let mkloc = Location.mkloc +let mkexp ~loc d = Exp.mk ~loc:(make_loc loc) d + +let mkjsxexp ~loc:loc' e = + let e = mkexp ~loc:loc' e in + let loc = make_loc loc' in + let pexp_attributes = [ Attr.mk ~loc { txt = "JSX"; loc } (PStr []) ] in + { e with pexp_attributes } + +let rec equal_longindent a b = + match a, b with + | Longident.Lident a, Longident.Lident b -> String.equal a b + | Ldot (pa, a), Ldot (pb, b) -> + String.equal a b && equal_longindent pa pb + | Lapply _, _ | _, Lapply _ -> assert false + | _ -> false + +let make_jsx_element ~raise ~loc:_ ~tag ~end_tag ~props ~children () = + let () = + match end_tag with + | None -> () + | Some (end_tag, (_, end_loc_e)) -> + let eq = + match tag, end_tag with + | (`Module, _, s), (`Module, _, e) -> equal_longindent s e + | (`Value, _, s), (`Value, _, e) -> equal_longindent s e + | _ -> false + in + if not eq then + let _, (end_loc_s, _), _ = end_tag in + let end_loc = end_loc_s, end_loc_e in + let _, start_loc, tag = tag in + let tag = Longident.flatten tag |> String.concat "." in + raise + Syntaxerr.( + Error + (Unclosed + ( make_loc start_loc, + sprintf "<%s>" tag, + make_loc end_loc, + sprintf "" tag ))) + in + let tag = + match tag with + | `Value, loc, txt -> + mkexp ~loc (Pexp_ident { loc = make_loc loc; txt }) + | `Module, loc, txt -> + let txt = Longident.Ldot (txt, "createElement") in + mkexp ~loc (Pexp_ident { loc = make_loc loc; txt }) + in + let props = + let prop_exp ~loc name = + let id = mkloc (Lident name) (make_loc loc) in + mkexp ~loc (Pexp_ident id) + in + List.map + (function + | loc, `Prop_punned name -> Labelled name, prop_exp ~loc name + | loc, `Prop_opt_punned name -> Optional name, prop_exp ~loc name + | _loc, `Prop (name, expr) -> Labelled name, expr + | _loc, `Prop_opt (name, expr) -> Optional name, expr) + props + in + let unit = + Exp.mk ~loc:Location.none + (Pexp_construct ({ txt = Lident "()"; loc = Location.none }, None)) + in + let props = (Labelled "children", children) :: props in + Pexp_apply (tag, (Nolabel, unit) :: props) diff --git a/vendor/parser-standard/lexer.mll b/vendor/parser-standard/lexer.mll index 47c039314d..97b7e13afb 100644 --- a/vendor/parser-standard/lexer.mll +++ b/vendor/parser-standard/lexer.mll @@ -494,6 +494,12 @@ let delim_ext = (lowercase | uppercase | utf8)* let symbolchar = ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>' '?' '@' '^' '|' '~'] +let symbolchar_no_prefix = + ['$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>' '?' '@' '^' '|' '~'] +let symbolchar_no_greater = + ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '?' '@' '^' '|' '~'] +let symbolchar_no_less = + ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '=' '>' '?' '@' '^' '|' '~'] let dotsymbolchar = ['!' '$' '%' '&' '*' '+' '-' '/' ':' '=' '>' '?' '@' '^' '|'] let symbolchar_or_hash = @@ -565,6 +571,10 @@ rule token = parse } | lowercase identchar * as name { find_keyword lexbuf name } + | "<" (lowercase identchar * as name) + { JSX_LIDENT name } + | "<" "/" (lowercase identchar * as name) + { JSX_LIDENT_E name } | uppercase identchar * as name { UIDENT name } (* No capitalized keywords *) | (raw_ident_escape? as escape) (ident_ext as raw_name) @@ -578,6 +588,10 @@ rule token = parse end else LIDENT name } (* No non-ascii keywords *) + | "<" (uppercase identchar * as name) + { JSX_UIDENT name } + | "<" "/" (uppercase identchar * as name) + { JSX_UIDENT_E name } | int_literal as lit { INT (lit, None) } | (int_literal as lit) (literal_modifier as modif) { INT (lit, Some modif) } @@ -702,6 +716,7 @@ rule token = parse | ";" { SEMI } | ";;" { SEMISEMI } | "<" { LESS } + | "" { GREATER } + | "/>" { SLASHGREATER } | ">]" { GREATERRBRACKET } | "}" { RBRACE } | ">}" { GREATERRBRACE } @@ -735,7 +751,11 @@ rule token = parse { PREFIXOP op } | ['~' '?'] symbolchar_or_hash + as op { PREFIXOP op } - | ['=' '<' '>' '|' '&' '$'] symbolchar * as op + | ['<' '|' '&' '$'] symbolchar * as op + { INFIXOP0 op } + | '=' symbolchar_no_prefix * as op + { INFIXOP0 op } + | ">" symbolchar_no_less * as op { INFIXOP0 op } | ['@' '^'] symbolchar * as op { INFIXOP1 op } @@ -745,7 +765,9 @@ rule token = parse { INFIXOP4 op } | '%' { PERCENT } | '/' { SLASH } - | ['*' '/' '%'] symbolchar * as op + | ['*' '%'] symbolchar * as op + { INFIXOP3 op } + | "/" symbolchar_no_greater * as op { INFIXOP3 op } | '#' symbolchar_or_hash + as op { HASHOP op } diff --git a/vendor/parser-standard/parser.mly b/vendor/parser-standard/parser.mly index 1c8317c710..a12b0965f7 100644 --- a/vendor/parser-standard/parser.mly +++ b/vendor/parser-standard/parser.mly @@ -768,6 +768,7 @@ let mk_directive ~loc name arg = %token FUNCTION "function" %token FUNCTOR "functor" %token GREATER ">" +%token SLASHGREATER "/>" %token GREATERRBRACE ">}" %token GREATERRBRACKET ">]" %token IF "if" @@ -795,9 +796,12 @@ let mk_directive ~loc name arg = %token LBRACKETPERCENT "[%" %token LBRACKETPERCENTPERCENT "[%%" %token LESS "<" +%token LESSSLASH " LIDENT "lident" (* just an example *) +%token JSX_LIDENT " JSX_LIDENT_E " UIDENT "UIdent" (* just an example *) +%token JSX_UIDENT " JSX_UIDENT_E " Ldot (Lident prefix, id) + | Ldot (prefix', id) -> Ldot (rebase prefix', id) + | Lapply _ -> assert false + in + `Module, $sloc, rebase id } + | prefix = uident DOT id = val_longident { + let rec rebase = function + | Lident id -> Ldot (Lident prefix, id) + | Ldot (prefix', id) -> Ldot (rebase prefix', id) + | Lapply _ -> assert false + in + `Value, $sloc, rebase id } +; label_longident: mk_longident(mod_longident, LIDENT) { $1 } ; From 5d76c3dee30f9397a6f01339a6b64079ea4c3240 Mon Sep 17 00:00:00 2001 From: Andrey Popp <8mayday@gmail.com> Date: Wed, 6 Sep 2023 18:53:11 +0400 Subject: [PATCH 2/3] ocamlformat-mlx --- dune-project | 2 +- lib/Fmt_ast.ml | 228 ++++++++++++++++++++++++++----------------------- test/mlx/mlx.t | 2 +- 3 files changed, 121 insertions(+), 111 deletions(-) diff --git a/dune-project b/dune-project index 55f58df968..741c6b60e8 100644 --- a/dune-project +++ b/dune-project @@ -92,7 +92,7 @@ (ocaml (and (>= 4.08) - (< 5.3))) + (<= 5.3))) (cmdliner (or (and diff --git a/lib/Fmt_ast.ml b/lib/Fmt_ast.ml index 5182b34f41..6d0586a2c4 100644 --- a/lib/Fmt_ast.ml +++ b/lib/Fmt_ast.ml @@ -2168,141 +2168,151 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens $ fmt_expression c ~box (sub_exp ~ctx e) $ fmt_atrs ) ) | Pexp_apply (e0, e1N1) -> ( - match pexp_attributes with - | [{attr_name={txt="JSX";loc=_}; attr_payload=PStr []; _}] -> + match pexp_attributes with + | [{attr_name= {txt= "JSX"; loc= _}; attr_payload= PStr []; _}] -> ( let children = ref None in - let props = List.filter_map e1N1 ~f:(function - | Labelled {txt="children";_}, {pexp_desc=Pexp_list es;pexp_loc;_} -> - children := Some (pexp_loc, es); - None - | Nolabel, {pexp_desc=Pexp_construct ({txt=Lident "()";_}, _); _} -> None - | arg -> Some arg) + let props = + List.filter_map e1N1 ~f:(function + | ( Labelled {txt= "children"; _} + , {pexp_desc= Pexp_list es; pexp_loc; _} ) -> + children := Some (pexp_loc, es) ; + None + | ( Nolabel + , {pexp_desc= Pexp_construct ({txt= Lident "()"; _}, _); _} ) + -> + None + | arg -> Some arg ) in let start_tag, end_tag = let name, name_loc, id = match e0.pexp_desc with - | Pexp_ident {txt=Lident name;loc} -> name, loc, None - | Pexp_ident {txt=Ldot (id, name);loc} -> name, loc, Some id + | Pexp_ident {txt= Lident name; loc} -> (name, loc, None) + | Pexp_ident {txt= Ldot (id, name); loc} -> (name, loc, Some id) | _ -> failwith "JSX element tag is not Longident.t" in let make tag = - (fun () -> - str (Printf.sprintf "<%s" tag) $ Cmts.fmt_after c name_loc), - (fun () -> str (Printf.sprintf "" tag)) + ( (fun () -> + str (Printf.sprintf "<%s" tag) $ Cmts.fmt_after c name_loc ) + , fun () -> str (Printf.sprintf "" tag) ) in match id with | None -> make name - | Some id -> - let path = Ocamlformat_ocaml_common.Longident.flatten id in - match name with - | "createElement" -> make (String.concat ~sep:"." path) - | name -> make (Printf.sprintf "%s.%s" (String.concat ~sep:"." path) name) + | Some id -> ( + let path = Ocamlformat_ocaml_common.Longident.flatten id in + match name with + | "createElement" -> make (String.concat ~sep:"." path) + | name -> + make + (Printf.sprintf "%s.%s" + (String.concat ~sep:"." path) + name ) ) in let props = match props with | [] -> str "" | props -> - let fmt_labelled ?(prefix="") label e = - let flabel = str (Printf.sprintf "%s%s" prefix label.txt) in - match e.pexp_desc with - | Pexp_ident {txt=Lident id; loc=_} when String.equal id label.txt -> - flabel - | _ -> - flabel $ str "=" $ fmt_expression c {ctx;ast=e} - in - let fmt_prop = function - | Nolabel, e -> fmt_expression c {ctx;ast=e} - | Labelled label, e -> fmt_labelled label e - | Optional label, e -> fmt_labelled ~prefix:"?" label e - in - space_break $ hvbox 0 (list props (break 1 0) fmt_prop) + let fmt_labelled ?(prefix = "") label e = + let flabel = str (Printf.sprintf "%s%s" prefix label.txt) in + match e.pexp_desc with + | Pexp_ident {txt= Lident id; loc= _} + when String.equal id label.txt -> + flabel + | _ -> flabel $ str "=" $ fmt_expression c {ctx; ast= e} + in + let fmt_prop = function + | Nolabel, e -> fmt_expression c {ctx; ast= e} + | Labelled label, e -> fmt_labelled label e + | Optional label, e -> fmt_labelled ~prefix:"?" label e + in + space_break $ hvbox 0 (list props (break 1 0) fmt_prop) in - begin match !children with + match !children with | None -> hvbox 2 (start_tag () $ props) $ space_break $ str "/>" - | Some (children_loc, []) when not (Cmts.has_after c.cmts children_loc) -> - hvbox 2 (start_tag () $ props) $ space_break $ str "/>" + | Some (children_loc, []) + when not (Cmts.has_after c.cmts children_loc) -> + hvbox 2 (start_tag () $ props) $ space_break $ str "/>" | Some (children_loc, children) -> - let head = hvbox 2 (start_tag () $ props $ str ">") in - let children = - hvbox 0 ( - list children (break 1 0) - (fun e -> fmt_expression c {ctx;ast=e}) - $ Cmts.fmt_after c children_loc) - in - hvbox 2 (head $ break 0 0 $ children $ break 0 (-2) $ end_tag ()) - end - | _ -> - let wrap = - if c.conf.fmt_opts.wrap_fun_args.v then hovbox 2 else hvbox 2 - in - let (lbl, last_arg), args_before = - match List.rev e1N1 with - | [] -> assert false - | hd :: tl -> (hd, List.rev tl) - in - let intro_epi, expr_epi = - (* [intro_epi] should be placed inside the inner most box but before - anything. [expr_epi] is placed in the outermost box, outside of - parenthesis. *) - let dock_fun_arg = - (* Do not dock the arguments when there's more than one. *) - (not c.conf.fmt_opts.ocp_indent_compat.v) - || Location.line_difference e0.pexp_loc last_arg.pexp_loc = 0 + let head = hvbox 2 (start_tag () $ props $ str ">") in + let children = + hvbox 0 + ( list children (break 1 0) (fun e -> + fmt_expression c {ctx; ast= e} ) + $ Cmts.fmt_after c children_loc ) + in + hvbox 2 (head $ break 0 0 $ children $ break 0 (-2) $ end_tag ()) + ) + | _ -> ( + let wrap = + if c.conf.fmt_opts.wrap_fun_args.v then hovbox 2 else hvbox 2 in - if parens || not dock_fun_arg then (noop, pro) else (pro, noop) - in - match last_arg.pexp_desc with - | Pexp_function (largs, ltyp, lbody) - when List.for_all args_before ~f:(fun (_, eI) -> - is_simple c.conf (fun _ -> 0) (sub_exp ~ctx eI) ) -> - let inner_ctx = Exp last_arg in - let inner_parens, outer_parens = - (* Don't disambiguate parentheses in some cases, also affect - indentation. *) - match lbody with - | Pfunction_cases _ when not c.conf.fmt_opts.ocp_indent_compat.v - -> - (parens, false) - | _ -> (false, parens) + let (lbl, last_arg), args_before = + match List.rev e1N1 with + | [] -> assert false + | hd :: tl -> (hd, List.rev tl) + in + let intro_epi, expr_epi = + (* [intro_epi] should be placed inside the inner most box but + before anything. [expr_epi] is placed in the outermost box, + outside of parenthesis. *) + let dock_fun_arg = + (* Do not dock the arguments when there's more than one. *) + (not c.conf.fmt_opts.ocp_indent_compat.v) + || Location.line_difference e0.pexp_loc last_arg.pexp_loc = 0 in - let args = - let wrap_intro x = - fmt_if inner_parens (str "(") - $ hvbox 0 - ( intro_epi - $ wrap - ( fmt_args_grouped e0 args_before - $ break 1 0 $ hvbox 0 x ) ) - $ break 1 0 + if parens || not dock_fun_arg then (noop, pro) else (pro, noop) + in + match last_arg.pexp_desc with + | Pexp_function (largs, ltyp, lbody) + when List.for_all args_before ~f:(fun (_, eI) -> + is_simple c.conf (fun _ -> 0) (sub_exp ~ctx eI) ) -> + let inner_ctx = Exp last_arg in + let inner_parens, outer_parens = + (* Don't disambiguate parentheses in some cases, also affect + indentation. *) + match lbody with + | Pfunction_cases _ + when not c.conf.fmt_opts.ocp_indent_compat.v -> + (parens, false) + | _ -> (false, parens) in - let force_closing_paren = + let args = + let wrap_intro x = + fmt_if inner_parens (str "(") + $ hvbox 0 + ( intro_epi + $ wrap + ( fmt_args_grouped e0 args_before + $ break 1 0 $ hvbox 0 x ) ) + $ break 1 0 + in + let force_closing_paren = + if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v + then Fit + else Break + in + fmt_function ~last_arg:true ~force_closing_paren ~ctx:inner_ctx + ~ctx0:ctx ~wrap_intro ~label:lbl ~parens:true + ~attrs:last_arg.pexp_attributes ~loc:last_arg.pexp_loc c + (largs, ltyp, lbody) + in + hvbox_if has_attr 0 + ( expr_epi + $ Params.parens_if outer_parens c.conf + (args $ fmt_atrs $ fmt_if inner_parens (str ")")) ) + | _ -> + let fmt_atrs = + fmt_attributes c ~pre:(Break (1, -2)) pexp_attributes + in + let force = if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v then Fit else Break in - fmt_function ~last_arg:true ~force_closing_paren ~ctx:inner_ctx - ~ctx0:ctx ~wrap_intro ~label:lbl ~parens:true - ~attrs:last_arg.pexp_attributes ~loc:last_arg.pexp_loc c - (largs, ltyp, lbody) - in - hvbox_if has_attr 0 - ( expr_epi - $ Params.parens_if outer_parens c.conf - (args $ fmt_atrs $ fmt_if inner_parens (str ")")) ) - | _ -> - let fmt_atrs = - fmt_attributes c ~pre:(Break (1, -2)) pexp_attributes - in - let force = - if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v then - Fit - else Break - in - pro - $ fmt_if parens (str "(") - $ hvbox 2 - ( fmt_args_grouped ~epi:fmt_atrs e0 e1N1 - $ fmt_if parens (closing_paren c ~force ~offset:(-3)) ) ) + pro + $ fmt_if parens (str "(") + $ hvbox 2 + ( fmt_args_grouped ~epi:fmt_atrs e0 e1N1 + $ fmt_if parens (closing_paren c ~force ~offset:(-3)) ) ) ) | Pexp_array [] -> pro $ hvbox 0 diff --git a/test/mlx/mlx.t b/test/mlx/mlx.t index a61a7b3e94..821812c6f5 100644 --- a/test/mlx/mlx.t +++ b/test/mlx/mlx.t @@ -160,5 +160,5 @@ Comments:
$ echo '' | fmt - $ echo '' | fmt + $ echo '' | fmtMore actions From 721b22c1f98742ef297e7094205aae2fc50df72d Mon Sep 17 00:00:00 2001 From: ed-baker Date: Sat, 22 Mar 2025 18:15:41 +0000 Subject: [PATCH 3/3] upgrade to 5.3 --- dune-project | 10 +- lib/Fmt_ast.ml | 228 +++++++++++++++++++-------------------- ocamlformat-mlx-lib.opam | 2 +- ocamlformat-mlx.opam | 2 +- test/mlx/mlx.t | 2 +- 5 files changed, 115 insertions(+), 129 deletions(-) diff --git a/dune-project b/dune-project index 741c6b60e8..a1529a0e24 100644 --- a/dune-project +++ b/dune-project @@ -39,9 +39,7 @@ "OCamlFormat is a tool to automatically format OCaml .mlx code in a uniform style.") (depends (ocaml - (and - (>= 4.08) - (< 5.3))) + (>= 4.08)) (alcotest (and :with-test @@ -89,10 +87,8 @@ (description "**ocamlformat** is a code formatter for OCaml. It comes with opinionated default settings but is also fully customizable to suit your coding style.\n\n- **Profiles:** ocamlformat offers profiles we predefined formatting configurations. Profiles include `default`, `ocamlformat`, `janestreet`.\n- **Configurable:** Users can change the formatting profile and configure every option in their `.ocamlformat` configuration file.\n- **Format Comments:** ocamlformat can format comments, docstrings, and even code blocks in your comments.\n- **RPC:** ocamlformat provides an RPC server that can be used by other tools to easily format OCaml Code.") (depends - (ocaml - (and - (>= 4.08) - (<= 5.3))) + (ocaml + (>= 4.08)) (cmdliner (or (and diff --git a/lib/Fmt_ast.ml b/lib/Fmt_ast.ml index 6d0586a2c4..5182b34f41 100644 --- a/lib/Fmt_ast.ml +++ b/lib/Fmt_ast.ml @@ -2168,151 +2168,141 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens $ fmt_expression c ~box (sub_exp ~ctx e) $ fmt_atrs ) ) | Pexp_apply (e0, e1N1) -> ( - match pexp_attributes with - | [{attr_name= {txt= "JSX"; loc= _}; attr_payload= PStr []; _}] -> ( + match pexp_attributes with + | [{attr_name={txt="JSX";loc=_}; attr_payload=PStr []; _}] -> let children = ref None in - let props = - List.filter_map e1N1 ~f:(function - | ( Labelled {txt= "children"; _} - , {pexp_desc= Pexp_list es; pexp_loc; _} ) -> - children := Some (pexp_loc, es) ; - None - | ( Nolabel - , {pexp_desc= Pexp_construct ({txt= Lident "()"; _}, _); _} ) - -> - None - | arg -> Some arg ) + let props = List.filter_map e1N1 ~f:(function + | Labelled {txt="children";_}, {pexp_desc=Pexp_list es;pexp_loc;_} -> + children := Some (pexp_loc, es); + None + | Nolabel, {pexp_desc=Pexp_construct ({txt=Lident "()";_}, _); _} -> None + | arg -> Some arg) in let start_tag, end_tag = let name, name_loc, id = match e0.pexp_desc with - | Pexp_ident {txt= Lident name; loc} -> (name, loc, None) - | Pexp_ident {txt= Ldot (id, name); loc} -> (name, loc, Some id) + | Pexp_ident {txt=Lident name;loc} -> name, loc, None + | Pexp_ident {txt=Ldot (id, name);loc} -> name, loc, Some id | _ -> failwith "JSX element tag is not Longident.t" in let make tag = - ( (fun () -> - str (Printf.sprintf "<%s" tag) $ Cmts.fmt_after c name_loc ) - , fun () -> str (Printf.sprintf "" tag) ) + (fun () -> + str (Printf.sprintf "<%s" tag) $ Cmts.fmt_after c name_loc), + (fun () -> str (Printf.sprintf "" tag)) in match id with | None -> make name - | Some id -> ( - let path = Ocamlformat_ocaml_common.Longident.flatten id in - match name with - | "createElement" -> make (String.concat ~sep:"." path) - | name -> - make - (Printf.sprintf "%s.%s" - (String.concat ~sep:"." path) - name ) ) + | Some id -> + let path = Ocamlformat_ocaml_common.Longident.flatten id in + match name with + | "createElement" -> make (String.concat ~sep:"." path) + | name -> make (Printf.sprintf "%s.%s" (String.concat ~sep:"." path) name) in let props = match props with | [] -> str "" | props -> - let fmt_labelled ?(prefix = "") label e = - let flabel = str (Printf.sprintf "%s%s" prefix label.txt) in - match e.pexp_desc with - | Pexp_ident {txt= Lident id; loc= _} - when String.equal id label.txt -> - flabel - | _ -> flabel $ str "=" $ fmt_expression c {ctx; ast= e} - in - let fmt_prop = function - | Nolabel, e -> fmt_expression c {ctx; ast= e} - | Labelled label, e -> fmt_labelled label e - | Optional label, e -> fmt_labelled ~prefix:"?" label e - in - space_break $ hvbox 0 (list props (break 1 0) fmt_prop) + let fmt_labelled ?(prefix="") label e = + let flabel = str (Printf.sprintf "%s%s" prefix label.txt) in + match e.pexp_desc with + | Pexp_ident {txt=Lident id; loc=_} when String.equal id label.txt -> + flabel + | _ -> + flabel $ str "=" $ fmt_expression c {ctx;ast=e} + in + let fmt_prop = function + | Nolabel, e -> fmt_expression c {ctx;ast=e} + | Labelled label, e -> fmt_labelled label e + | Optional label, e -> fmt_labelled ~prefix:"?" label e + in + space_break $ hvbox 0 (list props (break 1 0) fmt_prop) in - match !children with + begin match !children with | None -> hvbox 2 (start_tag () $ props) $ space_break $ str "/>" - | Some (children_loc, []) - when not (Cmts.has_after c.cmts children_loc) -> - hvbox 2 (start_tag () $ props) $ space_break $ str "/>" + | Some (children_loc, []) when not (Cmts.has_after c.cmts children_loc) -> + hvbox 2 (start_tag () $ props) $ space_break $ str "/>" | Some (children_loc, children) -> - let head = hvbox 2 (start_tag () $ props $ str ">") in - let children = - hvbox 0 - ( list children (break 1 0) (fun e -> - fmt_expression c {ctx; ast= e} ) - $ Cmts.fmt_after c children_loc ) - in - hvbox 2 (head $ break 0 0 $ children $ break 0 (-2) $ end_tag ()) - ) - | _ -> ( - let wrap = - if c.conf.fmt_opts.wrap_fun_args.v then hovbox 2 else hvbox 2 - in - let (lbl, last_arg), args_before = - match List.rev e1N1 with - | [] -> assert false - | hd :: tl -> (hd, List.rev tl) - in - let intro_epi, expr_epi = - (* [intro_epi] should be placed inside the inner most box but - before anything. [expr_epi] is placed in the outermost box, - outside of parenthesis. *) - let dock_fun_arg = - (* Do not dock the arguments when there's more than one. *) - (not c.conf.fmt_opts.ocp_indent_compat.v) - || Location.line_difference e0.pexp_loc last_arg.pexp_loc = 0 + let head = hvbox 2 (start_tag () $ props $ str ">") in + let children = + hvbox 0 ( + list children (break 1 0) + (fun e -> fmt_expression c {ctx;ast=e}) + $ Cmts.fmt_after c children_loc) in - if parens || not dock_fun_arg then (noop, pro) else (pro, noop) + hvbox 2 (head $ break 0 0 $ children $ break 0 (-2) $ end_tag ()) + end + | _ -> + let wrap = + if c.conf.fmt_opts.wrap_fun_args.v then hovbox 2 else hvbox 2 + in + let (lbl, last_arg), args_before = + match List.rev e1N1 with + | [] -> assert false + | hd :: tl -> (hd, List.rev tl) + in + let intro_epi, expr_epi = + (* [intro_epi] should be placed inside the inner most box but before + anything. [expr_epi] is placed in the outermost box, outside of + parenthesis. *) + let dock_fun_arg = + (* Do not dock the arguments when there's more than one. *) + (not c.conf.fmt_opts.ocp_indent_compat.v) + || Location.line_difference e0.pexp_loc last_arg.pexp_loc = 0 in - match last_arg.pexp_desc with - | Pexp_function (largs, ltyp, lbody) - when List.for_all args_before ~f:(fun (_, eI) -> - is_simple c.conf (fun _ -> 0) (sub_exp ~ctx eI) ) -> - let inner_ctx = Exp last_arg in - let inner_parens, outer_parens = - (* Don't disambiguate parentheses in some cases, also affect - indentation. *) - match lbody with - | Pfunction_cases _ - when not c.conf.fmt_opts.ocp_indent_compat.v -> - (parens, false) - | _ -> (false, parens) - in - let args = - let wrap_intro x = - fmt_if inner_parens (str "(") - $ hvbox 0 - ( intro_epi - $ wrap - ( fmt_args_grouped e0 args_before - $ break 1 0 $ hvbox 0 x ) ) - $ break 1 0 - in - let force_closing_paren = - if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v - then Fit - else Break - in - fmt_function ~last_arg:true ~force_closing_paren ~ctx:inner_ctx - ~ctx0:ctx ~wrap_intro ~label:lbl ~parens:true - ~attrs:last_arg.pexp_attributes ~loc:last_arg.pexp_loc c - (largs, ltyp, lbody) - in - hvbox_if has_attr 0 - ( expr_epi - $ Params.parens_if outer_parens c.conf - (args $ fmt_atrs $ fmt_if inner_parens (str ")")) ) - | _ -> - let fmt_atrs = - fmt_attributes c ~pre:(Break (1, -2)) pexp_attributes + if parens || not dock_fun_arg then (noop, pro) else (pro, noop) + in + match last_arg.pexp_desc with + | Pexp_function (largs, ltyp, lbody) + when List.for_all args_before ~f:(fun (_, eI) -> + is_simple c.conf (fun _ -> 0) (sub_exp ~ctx eI) ) -> + let inner_ctx = Exp last_arg in + let inner_parens, outer_parens = + (* Don't disambiguate parentheses in some cases, also affect + indentation. *) + match lbody with + | Pfunction_cases _ when not c.conf.fmt_opts.ocp_indent_compat.v + -> + (parens, false) + | _ -> (false, parens) + in + let args = + let wrap_intro x = + fmt_if inner_parens (str "(") + $ hvbox 0 + ( intro_epi + $ wrap + ( fmt_args_grouped e0 args_before + $ break 1 0 $ hvbox 0 x ) ) + $ break 1 0 in - let force = + let force_closing_paren = if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v then Fit else Break in - pro - $ fmt_if parens (str "(") - $ hvbox 2 - ( fmt_args_grouped ~epi:fmt_atrs e0 e1N1 - $ fmt_if parens (closing_paren c ~force ~offset:(-3)) ) ) ) + fmt_function ~last_arg:true ~force_closing_paren ~ctx:inner_ctx + ~ctx0:ctx ~wrap_intro ~label:lbl ~parens:true + ~attrs:last_arg.pexp_attributes ~loc:last_arg.pexp_loc c + (largs, ltyp, lbody) + in + hvbox_if has_attr 0 + ( expr_epi + $ Params.parens_if outer_parens c.conf + (args $ fmt_atrs $ fmt_if inner_parens (str ")")) ) + | _ -> + let fmt_atrs = + fmt_attributes c ~pre:(Break (1, -2)) pexp_attributes + in + let force = + if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v then + Fit + else Break + in + pro + $ fmt_if parens (str "(") + $ hvbox 2 + ( fmt_args_grouped ~epi:fmt_atrs e0 e1N1 + $ fmt_if parens (closing_paren c ~force ~offset:(-3)) ) ) | Pexp_array [] -> pro $ hvbox 0 diff --git a/ocamlformat-mlx-lib.opam b/ocamlformat-mlx-lib.opam index 3c23b5e832..35fc331353 100644 --- a/ocamlformat-mlx-lib.opam +++ b/ocamlformat-mlx-lib.opam @@ -15,7 +15,7 @@ authors: [ homepage: "https://github.com/ocaml-mlx/ocamlformat-mlx" bug-reports: "https://github.com/ocaml-mlx/ocamlformat-mlx/issues" depends: [ - "ocaml" {>= "4.08" & < "5.3"} + "ocaml" {>= "4.08"} "alcotest" {with-test & >= "1.3.0"} "base" {>= "v0.12.0"} "cmdliner" {>= "1.1.0"} diff --git a/ocamlformat-mlx.opam b/ocamlformat-mlx.opam index 5e59c51c16..b6cc7098cf 100644 --- a/ocamlformat-mlx.opam +++ b/ocamlformat-mlx.opam @@ -20,7 +20,7 @@ authors: [ homepage: "https://github.com/ocaml-mlx/ocamlformat-mlx" bug-reports: "https://github.com/ocaml-mlx/ocamlformat-mlx/issues" depends: [ - "ocaml" {>= "4.08" & < "5.3"} + "ocaml" {>= "4.08"} "cmdliner" {with-test = "false" & >= "1.1.0" | with-test & >= "1.2.0"} "csexp" {>= "1.4.0"} "dune" {>= "2.8"} diff --git a/test/mlx/mlx.t b/test/mlx/mlx.t index 821812c6f5..a61a7b3e94 100644 --- a/test/mlx/mlx.t +++ b/test/mlx/mlx.t @@ -160,5 +160,5 @@ Comments:
$ echo '' | fmt - $ echo '' | fmtMore actions + $ echo '' | fmt