Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Put #140 / #153 behind a flag #172

Merged
merged 5 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ The plugin supports the following configuration options in the `format` section
+ `inline_simple_funs` (`boolean()`):
* Specifies if anonymous function bodies should be placed in the same line as the function clause head in case for anonymous functions with just one clause if `paper` and `ribbon` allows it or if these simple funs should be indented as all the others.
* The default value is `true`.
+ `inline_qualified_function_composition` (`boolean()`):
* Specifies if composed qualified function calls (e.g. `module1:function1(module2:function2(...`) should stay in the same line if they fit or if the formatter should always put the internal function call in the next line.
* Because of how OTP's `prettypr` is built (which is the tool we're using to finally print the formatted code) we can't indent these function calls _only if it doesn't fit in a line_, at least not without adding an extra space to the right of `(` for _all_ function applications. That's why this switch is all-or-none.
* The non-inlining only applies when both functions that are composed are fully qualified (we're using _fully-qualified_ as a _proxy_ for _has a long name_); e.g. in this case `d(f:f(g:g(h(…))))` the formatter will always write `g:g(...)` in the next row, but not `h(...)` nor `f:f(...)` will be moved to a new row.
* The default value is `false`.
+ `inline_clause_bodies` (`boolean()`):
* Specifies if clause bodies (for `case`, `function`, etc. statements) should be placed in the same line as the clause heads if `paper` and `ribbon` allows it or if all bodies should be placed in the next line after their clause heads.
* The default value is `false`.
Expand Down
7 changes: 6 additions & 1 deletion src/formatters/default_formatter.erl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
force_arity_qualifiers = false :: boolean(),
inline_simple_funs = true :: boolean(),
inline_clause_bodies = false :: boolean(),
inline_qualified_function_composition = false :: boolean(),
inline_expressions = false :: boolean(),
unquote_atoms = true :: boolean(),
empty_lines = [] :: [pos_integer()],
Expand Down Expand Up @@ -138,6 +139,8 @@ layout(Node, EmptyLines, Options) ->
break_indent = maps:get(break_indent, Options, ?BREAK_INDENT),
inline_simple_funs = maps:get(inline_simple_funs, Options, true),
inline_clause_bodies = maps:get(inline_clause_bodies, Options, false),
inline_qualified_function_composition =
maps:get(inline_qualified_function_composition, Options, false),
inline_expressions = maps:get(inline_expressions, Options, false),
inline_items = maps:get(inline_items, Options, {when_over, 25}),
inline_attributes = maps:get(inline_attributes, Options, all),
Expand Down Expand Up @@ -1158,7 +1161,9 @@ lay_application(Name, Arguments, Ctxt) ->
DName = beside(lay(Name, set_prec(Ctxt, PrecL)), text("(")),
DArgs = beside(lay_items(Arguments, reset_prec(Ctxt), fun lay/2), lay_text_float(")")),
D =
case is_qualified_function_composition(Name, Arguments) of
case not Ctxt#ctxt.inline_qualified_function_composition andalso
is_qualified_function_composition(Name, Arguments)
of
true ->
vertical([DName, nest(Ctxt#ctxt.break_indent, DArgs)]);
_ ->
Expand Down
25 changes: 25 additions & 0 deletions test_app/after/src/function_composition_inline.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-module(function_composition_inline).

-export([local_calls/3, external_calls/0]).

-format #{inline_qualified_function_composition => true}.

-type t() :: only:function(application:is(affected(by:this(change)))) | not_types.

local_calls(should, be, unaffected) ->
g(f(b, h(a), w(x(y)))).

external_calls() ->
shouldnt:be(indented:every(singe:time([{even, "when", inlcuding}]),
local_calls(?AND_MACROS, #{}, undefined)),
local_calls(?MACROS(should), be, unaffected)),
the_idea_is_not_to_force:long_module_and_function_names(to_be_put:in_the_next_row([{even,
'when'},
"their",
<<"parameters">>,
can:be(),
read,
more,
easily])),
this_one(will:be(more(complex:since(it:combines(), local:and_remote(calls))),
hopefully:it(is(a, rare, thing)))).
16 changes: 16 additions & 0 deletions test_app/src/function_composition_inline.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-module(function_composition_inline).

-export([local_calls/3, external_calls/0]).

-format #{inline_qualified_function_composition => true}.

-type t() :: only:function(application:is(affected(by:this(change)))) | not_types.

local_calls(should, be, unaffected) ->
g(f(b, h(a), w(x(y)))).

external_calls() ->
shouldnt:be(indented:every(singe:time([{even, "when", inlcuding}]), local_calls(?AND_MACROS, #{}, undefined)),
local_calls(?MACROS(should), be, unaffected)),
the_idea_is_not_to_force:long_module_and_function_names(to_be_put:in_the_next_row([{even, 'when'}, "their", <<"parameters">>, can:be(), read, more, easily])),
this_one(will:be(more(complex:since(it:combines(), local:and_remote(calls))), hopefully:it(is(a, rare, thing)))).