Skip to content

Commit

Permalink
implement string sigil rewrites
Browse files Browse the repository at this point in the history
  • Loading branch information
novaugust committed Mar 28, 2024
1 parent 817983e commit 211d561
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Disabling the rules means updating your `.credo.exs` depending on your configura
{Credo.Check.Readability.SinglePipe, false},
# **potentially breaks compilation** - see **Troubleshooting** section below
{Credo.Check.Readability.StrictModuleLayout, false},
{Credo.Check.Readability.StringSigils, false},
{Credo.Check.Readability.UnnecessaryAliasExpansion, false},
{Credo.Check.Readability.WithSingleClause, false},
{Credo.Check.Refactor.CaseTrivialMatches, false},
Expand Down
46 changes: 42 additions & 4 deletions lib/style/single_node.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ defmodule Styler.Style.SingleNode do
* Credo.Check.Readability.LargeNumbers
* Credo.Check.Readability.ParenthesesOnZeroArityDefs
* Credo.Check.Readability.PreferImplicitTry
* Credo.Check.Readability.StringSigils
* Credo.Check.Readability.WithSingleClause
* Credo.Check.Refactor.CaseTrivialMatches
* Credo.Check.Refactor.CondStatements
Expand All @@ -29,15 +30,52 @@ defmodule Styler.Style.SingleNode do

alias Styler.Zipper



def run({node, meta}, ctx), do: {:cont, {style(node), meta}, ctx}

# as of 1.15, elixir's formatter takes care of this for us.
if Version.match?(System.version(), "< 1.15.0-dev") do
# 'charlist' => ~c"charlist"
defp style({:__block__, meta, [chars]} = node) when is_list(chars) do
if meta[:delimiter] == "'",
do: {:sigil_c, Keyword.put(meta, :delimiter, "\""), [{:<<>>, [line: meta[:line]], [List.to_string(chars)]}, []]},
else: node
defp style({:__block__, [{:delimiter, ~s|"|} | meta], [chars]} = node) when is_list(chars),

Check warning on line 40 in lib/style/single_node.ex

View workflow job for this annotation

GitHub Actions / Ex1.14.2/OTP25.1.2

variable "node" is unused (if the variable is not meant to be used, prefix it with an underscore)
do: {:sigil_c, [{:delimiter, ~s|"|} | meta], [{:<<>>, [line: meta[:line]], [List.to_string(chars)]}, []]}
end

defp style({:__block__, [{:delimiter, ~s|"|} | meta], [string]} = node) when is_binary(string) do
# @TODO this'll run a regex against every double-quote delimited string in the codebase.
# is there a faster way to do this? is it too expensive vis-a-vis styler's goal of speed?
if string =~ ~r/".*".*".*"/ do
frequencies =
string
|> String.codepoints()
|> Stream.filter(& &1 in [")", "]", "}", "|", ">", ~s|"|])
|> Enum.frequencies()

# choose whichever delimiter has the least occurences, ties being broken by delimiter_priority
{closer, _} =
%{~s|"| => 0, ")" => 0, "]" => 0, "}" => 0, "|" => 0, ">" => 0}
|> Map.merge(frequencies)
|> Enum.min_by(fn
{~s|"|, count} -> {count, 0}
{")", count} -> {count, 1}
{"]", count} -> {count, 2}
{"}", count} -> {count, 3}
{"|", count} -> {count, 4}
{">", count} -> {count, 5}
end)

delimiter =
case closer do
")" -> "("
"]" -> "["
"}" -> "{"
">" -> "<"
x -> x
end

{:sigil_s, [{:delimiter, delimiter} | meta], [{:<<>>, [line: meta[:line]], [string]}, []]}
else
node
end
end

Expand Down

0 comments on commit 211d561

Please sign in to comment.