@@ -233,13 +233,64 @@ defmodule Mix.Tasks.Format do
233233 { formatter_opts_and_subs , _sources } =
234234 eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , [ dot_formatter ] )
235235
236+ formatter_opts_and_subs = load_plugins ( formatter_opts_and_subs )
237+
236238 args
237239 |> expand_args ( cwd , dot_formatter , formatter_opts_and_subs , opts )
238240 |> Task . async_stream ( & format_file ( & 1 , opts ) , ordered: false , timeout: :infinity )
239241 |> Enum . reduce ( { [ ] , [ ] } , & collect_status / 2 )
240242 |> check! ( opts )
241243 end
242244
245+ defp load_plugins ( { formatter_opts , subs } ) do
246+ plugins = Keyword . get ( formatter_opts , :plugins , [ ] )
247+
248+ if not is_list ( plugins ) do
249+ Mix . raise ( "Expected :plugins to return a list of directories, got: #{ inspect ( plugins ) } " )
250+ end
251+
252+ if plugins != [ ] do
253+ Mix.Task . run ( "loadpaths" , [ ] )
254+ end
255+
256+ if not Enum . all? ( plugins , & Code . ensure_loaded? / 1 ) do
257+ Mix.Task . run ( "compile" , [ ] )
258+ end
259+
260+ for plugin <- plugins do
261+ cond do
262+ not Code . ensure_loaded? ( plugin ) ->
263+ Mix . raise ( "Formatter plugin #{ inspect ( plugin ) } cannot be found" )
264+
265+ not function_exported? ( plugin , :features , 1 ) ->
266+ Mix . raise ( "Formatter plugin #{ inspect ( plugin ) } does not define features/1" )
267+
268+ true ->
269+ :ok
270+ end
271+ end
272+
273+ sigils =
274+ for plugin <- plugins ,
275+ sigil <- find_sigils_from_plugins ( plugin , formatter_opts ) ,
276+ do: { sigil , plugin }
277+
278+ sigils =
279+ sigils
280+ |> Enum . group_by ( & elem ( & 1 , 0 ) , & elem ( & 1 , 1 ) )
281+ |> Enum . map ( fn { sigil , plugins } ->
282+ { sigil ,
283+ fn input , opts ->
284+ Enum . reduce ( plugins , input , fn plugin , input ->
285+ plugin . format ( input , opts ++ formatter_opts )
286+ end )
287+ end }
288+ end )
289+
290+ { Keyword . put ( formatter_opts , :sigils , sigils ) ,
291+ Enum . map ( subs , fn { path , opts } -> { path , load_plugins ( opts ) } end ) }
292+ end
293+
243294 @ doc """
244295 Returns a formatter function and the formatter options to
245296 be used for the given file.
@@ -289,7 +340,6 @@ defmodule Mix.Tasks.Format do
289340 defp eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , sources ) do
290341 deps = Keyword . get ( formatter_opts , :import_deps , [ ] )
291342 subs = Keyword . get ( formatter_opts , :subdirectories , [ ] )
292- plugins = Keyword . get ( formatter_opts , :plugins , [ ] )
293343
294344 if not is_list ( deps ) do
295345 Mix . raise ( "Expected :import_deps to return a list of dependencies, got: #{ inspect ( deps ) } " )
@@ -299,65 +349,17 @@ defmodule Mix.Tasks.Format do
299349 Mix . raise ( "Expected :subdirectories to return a list of directories, got: #{ inspect ( subs ) } " )
300350 end
301351
302- if not is_list ( plugins ) do
303- Mix . raise ( "Expected :plugins to return a list of modules, got: #{ inspect ( plugins ) } " )
304- end
305-
306- maybe_load_and_compile_plugins ( plugins )
307-
308- for plugin <- plugins do
309- cond do
310- not Code . ensure_loaded? ( plugin ) ->
311- Mix . raise ( "Formatter plugin #{ inspect ( plugin ) } cannot be found" )
312-
313- not function_exported? ( plugin , :features , 1 ) ->
314- Mix . raise ( "Formatter plugin #{ inspect ( plugin ) } does not define features/1" )
315-
316- true ->
317- :ok
318- end
319- end
320-
321- sigils =
322- for plugin <- plugins ,
323- sigil <- find_sigils_from_plugins ( plugin , formatter_opts ) ,
324- do: { sigil , plugin }
325-
326- sigils =
327- sigils
328- |> Enum . group_by ( & elem ( & 1 , 0 ) , & elem ( & 1 , 1 ) )
329- |> Enum . map ( fn { sigil , plugins } ->
330- { sigil ,
331- fn input , opts ->
332- Enum . reduce ( plugins , input , fn plugin , input ->
333- plugin . format ( input , opts ++ formatter_opts )
334- end )
335- end }
336- end )
337-
338- formatter_opts =
339- formatter_opts
340- |> Keyword . put ( :plugins , plugins )
341- |> Keyword . put ( :sigils , sigils )
342-
343352 if deps == [ ] and subs == [ ] do
344353 { { formatter_opts , [ ] } , sources }
345354 else
346355 manifest = Path . join ( Mix.Project . manifest_path ( ) , @ manifest )
347356
348- { cached? , { { locals_without_parens , subdirectories } , sources } } =
357+ { { locals_without_parens , subdirectories } , sources } =
349358 maybe_cache_in_manifest ( dot_formatter , manifest , fn ->
350359 { subdirectories , sources } = eval_subs_opts ( subs , cwd , sources )
351360 { { eval_deps_opts ( deps ) , subdirectories } , sources }
352361 end )
353362
354- # If we read from cache, we may still need to load and compile plugins.
355- if cached? do
356- Enum . each ( subdirectories , fn { _path , { opts , _deps } } ->
357- maybe_load_and_compile_plugins ( Keyword . get ( opts , :plugins , [ ] ) )
358- end )
359- end
360-
361363 formatter_opts =
362364 Keyword . update (
363365 formatter_opts ,
@@ -370,21 +372,11 @@ defmodule Mix.Tasks.Format do
370372 end
371373 end
372374
373- defp maybe_load_and_compile_plugins ( plugins ) do
374- if plugins != [ ] do
375- Mix.Task . run ( "loadpaths" , [ ] )
376- end
377-
378- if not Enum . all? ( plugins , & Code . ensure_loaded? / 1 ) do
379- Mix.Task . run ( "compile" , [ ] )
380- end
381- end
382-
383375 defp maybe_cache_in_manifest ( dot_formatter , manifest , fun ) do
384376 cond do
385- is_nil ( Mix.Project . get ( ) ) or dot_formatter != ".formatter.exs" -> { false , fun . ( ) }
386- entry = read_manifest ( manifest ) -> { true , entry }
387- true -> { false , write_manifest! ( manifest , fun . ( ) ) }
377+ is_nil ( Mix.Project . get ( ) ) or dot_formatter != ".formatter.exs" -> fun . ( )
378+ entry = read_manifest ( manifest ) -> entry
379+ true -> write_manifest! ( manifest , fun . ( ) )
388380 end
389381 end
390382
0 commit comments