Skip to content

Commit

Permalink
Use the API of ocp-indent to parse the .ocp-indent files (#2103)
Browse files Browse the repository at this point in the history
  • Loading branch information
gpetiot committed Jun 10, 2022
1 parent 3b59f18 commit 42fceb5
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 112 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -12,6 +12,7 @@
### Changes

- `bench` binary renamed to `ocamlformat-bench` to avoid conflicts (#2101, @gpetiot)
- Use the API of ocp-indent to parse the `.ocp-indent` files (#2103, @gpetiot)
- JaneStreet profile: set `max-indent = 2` (#2099, @gpetiot)

### New features
Expand Down
169 changes: 67 additions & 102 deletions lib/Conf.ml
Expand Up @@ -1327,22 +1327,16 @@ let numeric =
let default = false in
mk ~default Arg.(value & flag & info ["numeric"] ~doc ~docs)

let ocp_indent_options =
let unsupported ocp_indent = (ocp_indent, ([], "")) in
let ocp_indent_options_doc =
let alias ocp_indent ocamlformat =
( ocp_indent
, ( [ocamlformat]
, Printf.sprintf "$(b,%s) is an alias for $(b,%s)." ocp_indent
ocamlformat ) )
Printf.sprintf "$(b,%s) is an alias for $(b,%s)." ocp_indent ocamlformat
in
let multi_alias ocp_indent l_ocamlformat =
( ocp_indent
, ( l_ocamlformat
, Format.asprintf "$(b,%s) sets %a." ocp_indent
(Format.pp_print_list
~pp_sep:(fun fs () -> Format.fprintf fs " and ")
(fun fs x -> Format.fprintf fs "$(b,%s)" x) )
l_ocamlformat ) )
Format.asprintf "$(b,%s) sets %a." ocp_indent
(Format.pp_print_list
~pp_sep:(fun fs () -> Format.fprintf fs " and ")
(fun fs x -> Format.fprintf fs "$(b,%s)" x) )
l_ocamlformat
in
[ alias "base" "let-binding-indent"
; alias "type" "type-decl-indent"
Expand All @@ -1352,27 +1346,20 @@ let ocp_indent_options =
; alias "ppx_stritem_ext" "stritem-extension-indent"
; alias "max_indent" "max-indent"
; multi_alias "strict_with"
["function-indent-nested"; "match-indent-nested"]
; unsupported "strict_else"
; unsupported "strict_comments"
; unsupported "align_ops"
; unsupported "align_params" ]
["function-indent-nested"; "match-indent-nested"] ]

let ocp_indent_config =
let doc =
let open Format in
let supported =
let only_doc (_, (_, doc)) =
Option.some_if (not (String.is_empty doc)) doc
in
let l = List.filter_map ocp_indent_options ~f:only_doc in
if List.is_empty l then ""
else
asprintf " %a"
(pp_print_list
~pp_sep:(fun fs () -> fprintf fs "@ ")
(fun fs s -> fprintf fs "%s" s) )
l
match ocp_indent_options_doc with
| [] -> ""
| docs ->
asprintf " %a"
(pp_print_list
~pp_sep:(fun fs () -> fprintf fs "@ ")
(fun fs s -> fprintf fs "%s" s) )
docs
in
asprintf "Read .ocp-indent configuration files.%s" supported
in
Expand Down Expand Up @@ -1662,47 +1649,6 @@ let (_profile : fmt_opts option C.t) =
{conf with fmt_opts= new_fmt_opts} )
(fun _ -> !selected_profile_ref)

let ocp_indent_normal_profile =
[ ("base", "2")
; ("type", "2")
; ("in", "0")
; ("with", "0")
; ("match_clause", "2")
; ("ppx_stritem_ext", "2")
; ("max_indent", "4")
; ("strict_with", "never")
; ("strict_else", "always")
; ("strict_comments", "false")
; ("align_ops", "true")
; ("align_params", "auto") ]

let ocp_indent_apprentice_profile =
[ ("base", "2")
; ("type", "4")
; ("in", "2")
; ("with", "2")
; ("match_clause", "4")
; ("ppx_stritem_ext", "2")
; ("strict_with", "never")
; ("strict_else", "always")
; ("strict_comments", "false")
; ("align_ops", "true")
; ("align_params", "always") ]

let ocp_indent_janestreet_profile =
[ ("base", "2")
; ("type", "2")
; ("in", "0")
; ("with", "0")
; ("match_clause", "2")
; ("ppx_stritem_ext", "2")
; ("max_indent", "2")
; ("strict_with", "auto")
; ("strict_else", "always")
; ("strict_comments", "true")
; ("align_ops", "true")
; ("align_params", "always") ]

let parse_line config ~from s =
let update ~config ~from ~name ~value =
let name = String.strip name in
Expand All @@ -1725,21 +1671,6 @@ let parse_line config ~from s =
C.update ~config ~from:(`Parsed `Attribute) ~name ~value
~inline:true
in
let update_ocp_indent_option ~config ~from ~name ~value =
let equal = String.equal in
match List.Assoc.find ocp_indent_options ~equal name with
| None -> Ok config
| Some (l, _doc) ->
let update_one config name = update ~config ~from ~name ~value in
List.fold_result l ~init:config ~f:update_one
in
let rec update_many ~config ~from = function
| [] -> Ok config
| (name, value) :: t -> (
match update_ocp_indent_option ~config ~from ~name ~value with
| Ok c -> update_many ~config:c ~from t
| Error e -> Error e )
in
let s =
match String.index s '#' with
| Some i -> String.sub s ~pos:0 ~len:i
Expand All @@ -1751,21 +1682,12 @@ let parse_line config ~from s =
| [name; value] ->
let name = String.strip name in
let value = String.strip value in
if List.Assoc.mem ocp_indent_options ~equal:String.equal name then
update_ocp_indent_option ~config ~from ~name ~value
else update ~config ~from ~name ~value
update ~config ~from ~name ~value
| [s] -> (
match String.strip s with
| "" -> impossible "previous match"
(* special case for disable/enable *)
| "enable" -> update ~config ~from ~name:"disable" ~value:"false"
| "normal" -> update_many ~config ~from ocp_indent_normal_profile
| "apprentice" -> update_many ~config ~from ocp_indent_apprentice_profile
| "JaneStreet" ->
Result.( >>= )
(update ~config ~from ~name:"profile" ~value:"janestreet")
(fun config ->
update_many ~config ~from ocp_indent_janestreet_profile )
| name -> update ~config ~from ~name ~value:"true" )
| _ -> Error (Config_option.Error.Malformed s)

Expand All @@ -1779,9 +1701,53 @@ let failwith_user_errors ~from errors =
let msg = asprintf "Error while parsing %s:@ %a" from pp_errors errors in
raise (Conf_error msg)

let update_from_ocp_indent c (oic : IndentConfig.t) =
let convert_threechoices = function
| IndentConfig.Always -> `Always
| Never -> `Never
| Auto -> `Auto
in
{ c with
fmt_opts=
{ c.fmt_opts with
let_binding_indent= oic.i_base
; type_decl_indent= oic.i_type
; indent_after_in= oic.i_in
; function_indent= oic.i_with
; match_indent= oic.i_with
; cases_exp_indent= oic.i_match_clause
; stritem_extension_indent= oic.i_ppx_stritem_ext
; max_indent= oic.i_max_indent
; function_indent_nested= convert_threechoices oic.i_strict_with
; match_indent_nested= convert_threechoices oic.i_strict_with } }

let read_config_file conf = function
| File_system.Ocp_indent _ when not !ocp_indent_config -> conf
| File_system.Ocp_indent file | File_system.Ocamlformat file -> (
| File_system.Ocp_indent file -> (
let filename = Fpath.to_string file in
try
let ocp_indent_conf = IndentConfig.default in
In_channel.with_file filename ~f:(fun ic ->
let ocp_indent_conf, errors, _ =
In_channel.fold_lines ic ~init:(ocp_indent_conf, [], 1)
~f:(fun (conf, errors, lnum) line ->
try
( IndentConfig.update_from_string ocp_indent_conf line
, errors
, lnum + 1 )
with
| Invalid_argument e when !ignore_invalid_options ->
warn ~filename:file ~lnum "%s" e ;
(conf, errors, lnum + 1)
| Invalid_argument e ->
( conf
, Config_option.Error.Unknown (e, None) :: errors
, lnum + 1 ) )
in
match List.rev errors with
| [] -> update_from_ocp_indent conf ocp_indent_conf
| l -> failwith_user_errors ~from:filename l )
with Sys_error _ -> conf )
| File_system.Ocamlformat file -> (
let filename = Fpath.to_string file in
try
In_channel.with_file filename ~f:(fun ic ->
Expand Down Expand Up @@ -1869,17 +1835,16 @@ let build_config ~enable_outside_detected_project ~root ~file ~is_stdin =
let file_abs = Fpath.(vfile |> to_absolute |> normalize) in
let fs =
File_system.make ~enable_outside_detected_project
~disable_conf_files:!disable_conf_files ~root ~file:file_abs
~disable_conf_files:!disable_conf_files
~ocp_indent_config:!ocp_indent_config ~root ~file:file_abs
in
let conf =
List.fold fs.configuration_files ~init:default ~f:read_config_file
|> update_using_env |> C.update_using_cmdline
in
let no_ocamlformat_files =
List.for_all fs.configuration_files ~f:File_system.is_ocp_indent_file
in
if
(not is_stdin) && no_ocamlformat_files
(not is_stdin)
&& (not (File_system.has_ocamlformat_file fs))
&& not enable_outside_detected_project
then (
(let why =
Expand Down
19 changes: 11 additions & 8 deletions lib/File_system.ml
Expand Up @@ -28,10 +28,6 @@ let dot_ocamlformat_enable = ".ocamlformat-enable"

type configuration_file = Ocamlformat of Fpath.t | Ocp_indent of Fpath.t

let is_ocp_indent_file = function
| Ocamlformat _ -> false
| Ocp_indent _ -> true

let root_ocamlformat_file ~root =
let root = Option.value root ~default:(Fpath.cwd ()) in
Fpath.(root / dot_ocamlformat)
Expand All @@ -57,7 +53,8 @@ type t =
; configuration_files: configuration_file list
; project_root: Fpath.t option }

let make ~enable_outside_detected_project ~disable_conf_files ~root ~file =
let make ~enable_outside_detected_project ~disable_conf_files
~ocp_indent_config ~root ~file =
let dir = Fpath.(file |> split_base |> fst) in
let volume, dir = Fpath.split_volume dir in
let segs = Fpath.segs dir |> List.rev in
Expand Down Expand Up @@ -99,9 +96,10 @@ let make ~enable_outside_detected_project ~disable_conf_files ~root ~file =
Ocamlformat f_1 :: fs.configuration_files
else fs.configuration_files
in
let f_2 = Fpath.(dir / dot_ocp_indent) in
if Fpath.exists f_2 then Ocp_indent f_2 :: files else files
) }
if ocp_indent_config then
let f_2 = Fpath.(dir / dot_ocp_indent) in
if Fpath.exists f_2 then Ocp_indent f_2 :: files else files
else files ) }
in
(* Inside a detected project, configs are applied in top-down
starting from the project root (i.e. excluding the global config
Expand All @@ -114,3 +112,8 @@ let make ~enable_outside_detected_project ~disable_conf_files ~root ~file =
; enable_files= []
; configuration_files= []
; project_root= None }

let has_ocamlformat_file fs =
List.exists fs.configuration_files ~f:(function
| Ocamlformat _ -> true
| Ocp_indent _ -> false )
5 changes: 3 additions & 2 deletions lib/File_system.mli
Expand Up @@ -13,8 +13,6 @@ val project_root_witness : string list

type configuration_file = Ocamlformat of Fpath.t | Ocp_indent of Fpath.t

val is_ocp_indent_file : configuration_file -> bool

val root_ocamlformat_file : root:Fpath.t option -> Fpath.t

type t =
Expand All @@ -26,6 +24,9 @@ type t =
val make :
enable_outside_detected_project:bool
-> disable_conf_files:bool
-> ocp_indent_config:bool
-> root:Fpath.t option
-> file:Fpath.t (** Absolute path of the file to format. *)
-> t

val has_ocamlformat_file : t -> bool

0 comments on commit 42fceb5

Please sign in to comment.