Multiple select is imo even harder, because it’s not just that it’s not customizable, but also that multiple select is plain old bad UI in the first place. And while there are alternatives I personally don’t consider any of those universally good.
OpenUI however does truely seem to be able to make progress happen looking at the things they proposed that turned into standards.
I have only one such problem that’s scalable to the universe size! Just think that for years you have written macros that generates some functions/macros and documented the generated code inside quote do … end block and then you realize that you can simply use @callback attribute for documentation purposes (like for example Ecto.Repo is doing).
This was because the behaviours I remembered were pigeonholed for 3rd-party modules and not for the code you generate. I’m still in a process of rewriting all related projects.
That’s said the best topic is of course the never ending story:
I still use IO.inspect after pipes because the majority of the time I only want to see the final output. I wish there was a way to configure dbg to default to not doing this with an inline option to turn it on. Maybe there is? I have not found it.
EDIT: And speaking of things that took me way too long to figure out, not only did I just learn about dbg(binding()) while taking another look through the docs for anything related to my problem stated above, I learned that it is “very common” to do so! Oh boy! It hurts extra because I have used binding() several times, just never thought to use it in every day debugging.
There isn’t one I guess — Macro.dbg/3 matches on the |> AST node and always expands it, and the options only control printing. But you can flip the default yourself: dbg resolves its backend at compile time from config :elixir, :dbg_callback, {Mod, :fun, []}, and Macro.dbg/3 is public precisely so custom backends can fall back to it. So: match {:|>, _, _}, emit a plain IO.inspect with Macro.to_string(code) as label, and delegate everything else to Macro.dbg/3 — with a steps: true option to opt back into the full expansion. Two gotchas: the options come in as AST, not values, and the backend module must already be compiled when the dbg call sites are, so it’s cleanest as a separate dep. Also, since 1.17 the IEx pry backend is opt-in via --dbg pry, so a custom callback survives a plain iex -S mix.
Oh that’s a neat trick, not not really any easier to type than IO.inspect. It’s more of a muscle memory issue, though. I also have my own little plugin to add auto-add debug statements and of course it adds complexity when I have to change what the actual output is.
Because of my (stupid?) aversion to certain kinds of spacing in code, I was using an obnoxious \ with with:
with \
{:ok, thing} <- get_thing(x),
{:ok, modified_thing} <- modify_thing(thing)
do
# ...
else
# ...
end
instead of the more typical:
with {:ok, thing} <- get_thing(x),
{:ok, modified_thing} <- modify_thing(thing) do
# ...
But then I happened across the fact in the documentation that you can simply use brackets (which is honoured by auto-formatting, with line breaks when the line with clauses doesn’t fit in one line):
As with any other function or macro call in Elixir, explicit parens can also be used around the arguments before the do-end block
– Kernel.SpecialForms — Elixir v1.20.3