elixir-editors / emacs-elixir

Emacs major mode for Elixir
446 stars 94 forks source link

elixir-format does not respect locals_without_parens in .formatter.exs #428

Open lambdadog opened 5 years ago

lambdadog commented 5 years ago

With the following .formatter.exs and files, mix format $file respects locals_without_parens, whereas elixir-format does not

.formatter.exs

# Used by "mix format"
[
  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
  locals_without_parens: [
    defroute: 2
  ]
]

lib/pea_bb/bbs/router.ex

defmodule PeaBB.BBS.Router do
  import PeaBB.Macro.Route

  defroute "/", PeaBB.BBS.Menu
  defroute "/board", PeaBB.BBS.Board
  defroute "/blog", PeaBB.BBS.Blog

  # 404 route not found
  def route(_), do: {:error, "Route does not exist."}
end

lib/pea_bb/macro/route.ex

defmodule PeaBB.Macro.Route do
  defmacro defroute(path, module) do
    with path <- String.split(path, "/", [:trim]) do
      quote do
        def route(unquote(gen_match_statement(path))),
          do:
            {unquote(module),
             unquote(
               case path do
                 [] -> quote do: []
                 _ -> quote do: t
               end
             )}
      end
    end
  end

  defp gen_match_statement([head | tail]) do
    quote do
      [unquote(head) | unquote(gen_match_statement(tail))]
    end
  end

  defp gen_match_statement([]),
    do: quote(do: t)
end

(I doubt the last file is important, but I included it for completeness sake given that these files have no external dependencies other than the existence of the modules being routed to)

when elixir-format is run, lib/pea_bb/bbs/router.ex is changed to

defmodule PeaBB.BBS.Router do
  import PeaBB.Macro.Route

  defroute("/", PeaBB.BBS.Menu)
  defroute("/board", PeaBB.BBS.Board)
  defroute("/blog", PeaBB.BBS.Blog)

  # 404 route not found
  def route(_), do: {:error, "Route does not exist."}
end

this is not the case for when mix format is run

victorolinasc commented 3 years ago

I know this is not the kind of answer that you expect but a way to make it work is not using the format functionality here... this is how I use format with the reformatter.el package:

(use-package reformatter
  :config
  (reformatter-define +elixir-format
    :program "mix"
    :args '("format" "-"))

  (defun +set-default-directory-to-mix-project-root (original-fun &rest args)
    (if-let* ((mix-project-root (and buffer-file-name
                                     (locate-dominating-file buffer-file-name
                                                             ".formatter.exs"))))
        (let ((default-directory mix-project-root))
          (apply original-fun args))
      (apply original-fun args)))
  (advice-add '+elixir-format-region :around #'+set-default-directory-to-mix-project-root)

  (add-hook 'elixir-mode-hook #'+elixir-format-on-save-mode))
lambdadog commented 3 years ago

Thanks, @victorolinasc!

It may not be the answer that I was looking for but it's definitely a useful workaround for those who come across this issue in the future.

I personally don't use Elixir much anymore so the issue is no longer important to me personally, but regardless I still feel this is an important issue with regards to emacs-elixir functionality so I'm going to go ahead and leave it open unless someone objects.