@@ -244,9 +244,9 @@ defmodule Mix.Tasks.Format do
244244 end
245245
246246 { formatter_opts_and_subs , _sources } =
247- eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , [ dot_formatter ] )
247+ eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , [ dot_formatter ] , opts )
248248
249- formatter_opts_and_subs = load_plugins ( formatter_opts_and_subs )
249+ formatter_opts_and_subs = load_plugins ( formatter_opts_and_subs , opts )
250250 files = expand_args ( args , cwd , dot_formatter , formatter_opts_and_subs , opts )
251251
252252 maybe_cache_timestamps ( all_args , files , fn files ->
@@ -290,20 +290,19 @@ defmodule Mix.Tasks.Format do
290290
291291 defp maybe_cache_timestamps ( [ _ | _ ] , files , fun ) , do: fun . ( files )
292292
293- defp load_plugins ( { formatter_opts , subs } ) do
293+ defp load_plugins ( { formatter_opts , subs } , opts ) do
294294 plugins = Keyword . get ( formatter_opts , :plugins , [ ] )
295295
296296 if not is_list ( plugins ) do
297297 Mix . raise ( "Expected :plugins to return a list of modules, got: #{ inspect ( plugins ) } " )
298298 end
299299
300- if plugins != [ ] do
301- Mix.Task . run ( "loadpaths" , [ ] )
302- end
303-
304- if not Enum . all? ( plugins , & Code . ensure_loaded? / 1 ) do
305- Mix.Task . run ( "compile" , [ ] )
306- end
300+ plugins =
301+ if plugins != [ ] do
302+ Keyword . get ( opts , :plugin_loader , & plugin_loader / 1 ) . ( plugins )
303+ else
304+ [ ]
305+ end
307306
308307 for plugin <- plugins do
309308 cond do
@@ -336,7 +335,21 @@ defmodule Mix.Tasks.Format do
336335 end )
337336
338337 { Keyword . put ( formatter_opts , :sigils , sigils ) ,
339- Enum . map ( subs , fn { path , opts } -> { path , load_plugins ( opts ) } end ) }
338+ Enum . map ( subs , fn { path , formatter_opts_and_subs } ->
339+ { path , load_plugins ( formatter_opts_and_subs , opts ) }
340+ end ) }
341+ end
342+
343+ defp plugin_loader ( plugins ) do
344+ if plugins != [ ] do
345+ Mix.Task . run ( "loadpaths" , [ ] )
346+ end
347+
348+ if not Enum . all? ( plugins , & Code . ensure_loaded? / 1 ) do
349+ Mix.Task . run ( "compile" , [ ] )
350+ end
351+
352+ plugins
340353 end
341354
342355 @ doc """
@@ -346,24 +359,41 @@ defmodule Mix.Tasks.Format do
346359 The function must be called with the contents of the file
347360 to be formatted. The options are returned for reflection
348361 purposes.
362+
363+ ## Options
364+
365+ * `:deps_paths` (since v1.18.0) - the dependencies path to be used to resolve
366+ `import_deps`. It defaults to `Mix.Project.deps_paths`.
367+
368+ * `:dot_formatter` - use the given file as the `dot_formatter`
369+ root. If this option is specified, it uses the default one.
370+ The default one is cached, so use this option only if necessary.
371+
372+ * `:plugin_loader` (since v1.18.0) - a function that receives a list of plugins,
373+ which may or may not yet be loaded, and ensures all of them are
374+ loaded. It must return a list of plugins, which is recommended
375+ to be the exact same list given as argument. You may choose to
376+ skip plugins, but then it means the code will be partially
377+ formatted (as in the plugins will be skipped). By default,
378+ this function calls `mix loadpaths` and then, if not enough,
379+ `mix compile`.
380+
381+ * `:root` - use the given root as the current working directory.
349382 """
350383 @ doc since: "1.13.0"
351384 def formatter_for_file ( file , opts \\ [ ] ) do
352385 cwd = Keyword . get_lazy ( opts , :root , & File . cwd! / 0 )
353386 { dot_formatter , formatter_opts } = eval_dot_formatter ( cwd , opts )
354387
355388 { formatter_opts_and_subs , _sources } =
356- eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , [ dot_formatter ] )
389+ eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , [ dot_formatter ] , opts )
357390
358- formatter_opts_and_subs = load_plugins ( formatter_opts_and_subs )
391+ formatter_opts_and_subs = load_plugins ( formatter_opts_and_subs , opts )
359392
360393 find_formatter_and_opts_for_file ( Path . expand ( file , cwd ) , formatter_opts_and_subs )
361394 end
362395
363- @ doc """
364- Returns formatter options to be used for the given file.
365- """
366- # TODO: Remove me Elixir v1.17
396+ @ doc false
367397 @ deprecated "Use formatter_for_file/2 instead"
368398 def formatter_opts_for_file ( file , opts \\ [ ] ) do
369399 { _ , formatter_opts } = formatter_for_file ( file , opts )
@@ -391,7 +421,7 @@ defmodule Mix.Tasks.Format do
391421 # This function reads exported configuration from the imported
392422 # dependencies and subdirectories and deals with caching the result
393423 # of reading such configuration in a manifest file.
394- defp eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , sources ) do
424+ defp eval_deps_and_subdirectories ( cwd , dot_formatter , formatter_opts , sources , opts ) do
395425 deps = Keyword . get ( formatter_opts , :import_deps , [ ] )
396426 subs = Keyword . get ( formatter_opts , :subdirectories , [ ] )
397427
@@ -410,8 +440,8 @@ defmodule Mix.Tasks.Format do
410440
411441 { { locals_without_parens , subdirectories } , sources } =
412442 maybe_cache_in_manifest ( dot_formatter , manifest , fn ->
413- { subdirectories , sources } = eval_subs_opts ( subs , cwd , sources )
414- { { eval_deps_opts ( deps ) , subdirectories } , sources }
443+ { subdirectories , sources } = eval_subs_opts ( subs , cwd , sources , opts )
444+ { { eval_deps_opts ( deps , opts ) , subdirectories } , sources }
415445 end )
416446
417447 formatter_opts =
@@ -457,12 +487,12 @@ defmodule Mix.Tasks.Format do
457487 { entry , sources }
458488 end
459489
460- defp eval_deps_opts ( [ ] ) do
490+ defp eval_deps_opts ( [ ] , _opts ) do
461491 [ ]
462492 end
463493
464- defp eval_deps_opts ( deps ) do
465- deps_paths = Mix.Project . deps_paths ( )
494+ defp eval_deps_opts ( deps , opts ) do
495+ deps_paths = opts [ :deps_paths ] || Mix.Project . deps_paths ( )
466496
467497 for dep <- deps ,
468498 dep_path = assert_valid_dep_and_fetch_path ( dep , deps_paths ) ,
@@ -474,7 +504,7 @@ defmodule Mix.Tasks.Format do
474504 do: parenless_call
475505 end
476506
477- defp eval_subs_opts ( subs , cwd , sources ) do
507+ defp eval_subs_opts ( subs , cwd , sources , opts ) do
478508 { subs , sources } =
479509 Enum . flat_map_reduce ( subs , sources , fn sub , sources ->
480510 cwd = Path . expand ( sub , cwd )
@@ -488,7 +518,7 @@ defmodule Mix.Tasks.Format do
488518 formatter_opts = eval_file_with_keyword_list ( sub_formatter )
489519
490520 { formatter_opts_and_subs , sources } =
491- eval_deps_and_subdirectories ( sub , :in_memory , formatter_opts , sources )
521+ eval_deps_and_subdirectories ( sub , :in_memory , formatter_opts , sources , opts )
492522
493523 { [ { sub , formatter_opts_and_subs } ] , sources }
494524 else
0 commit comments