Skip to content

Commit

Permalink
improvement: better UX around large files
Browse files Browse the repository at this point in the history
  • Loading branch information
zachdaniel committed Feb 10, 2025
1 parent 34b7e37 commit 39686bf
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 61 deletions.
210 changes: 151 additions & 59 deletions lib/igniter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,11 @@ defmodule Igniter do
if opts[:dry_run] || !opts[:yes] do
Mix.shell().info("\n#{IO.ANSI.green()}#{title}#{IO.ANSI.reset()}:")

display_diff(Rewrite.sources(igniter.rewrite), opts)
if !opts[:yes] && too_long_to_display?(igniter) do
handle_long_diff(igniter, opts)
else
display_diff(Rewrite.sources(igniter.rewrite), opts)
end
end

:dry_run_with_changes
Expand Down Expand Up @@ -1174,6 +1178,90 @@ defmodule Igniter do
end
end

@line_limit 1000

defp too_long_to_display?(igniter) do
if igniter.assigns[:test_mode?] do
false
else
Enum.reduce_while(igniter.rewrite, {0, false}, fn source, {count, res} ->
count = count + Enum.count(String.split(source_diff(source, false), "\n"))

if count > @line_limit do
{:halt, {count, true}}
else
{:cont, {count, res}}
end
end)
|> elem(1)
end
end

defp handle_long_diff(igniter, opts) do
files_changed =
igniter.rewrite
|> Enum.filter(&changed?/1)
|> Enum.group_by(&Rewrite.Source.from?(&1, :string))
|> Enum.sort_by(&elem(&1, 0))
|> Enum.map_join("\n\n", fn
{true, sources} ->
"Creating: \n\n" <>
Enum.map_join(sources, "\n", &" * #{Rewrite.Source.get(&1, :path)}")

{false, sources} ->
"Updating: \n\n" <>
Enum.map_join(sources, "\n", &" * #{Rewrite.Source.get(&1, :path)}")
end)

files_changed =
if Enum.empty?(igniter.moves) do
files_changed
else
("Moving: \n\n" <>
igniter.moves)
|> Enum.sort_by(&elem(&1, 0))
|> Enum.map(fn {from, to} ->
"#{IO.ANSI.red()} #{from}#{IO.ANSI.reset()}: #{IO.ANSI.green()}#{to}#{IO.ANSI.reset()}"
end)
end

options = [
write: "Proceed *without* viewing changes. (default)",
display: "Display the diff inline anyway.",
patch_file:
"Write to `.igniter` so you can preview all of the changes, and wait to proceed."
]

Igniter.Util.IO.select(
"Too many changes to automatically display a full diff (>= #{@line_limit} lines changed).\n" <>
"The following files will be changed:\n\n" <>
files_changed <> "\n\nHow would you like to proceed?",
options,
display: &elem(&1, 1),
default: :write
)
|> elem(0)
|> case do
:display ->
display_diff(Rewrite.sources(igniter.rewrite), opts)

:patch_file ->
File.write!(
".igniter",
diff(Rewrite.sources(igniter.rewrite), Keyword.put(opts, :color?, false))
)

Mix.shell().info(
"Diff:\n\n#{IO.ANSI.yellow()}View the diff by opening `#{Path.expand(".igniter")}`.#{IO.ANSI.reset()}"
)

:write ->
Mix.shell().info("#{IO.ANSI.yellow()}Not shown due to line count.#{IO.ANSI.reset()}")

:ok
end
end

defp display_diff(sources, opts) do
if !opts[:yes] do
Mix.shell().info(diff(sources))
Expand All @@ -1191,74 +1279,78 @@ defmodule Igniter do
source -> source
end

cond do
Rewrite.Source.from?(source, :string) &&
String.valid?(Rewrite.Source.get(source, :content)) ->
content_lines =
source
|> Rewrite.Source.get(:content)
|> String.split("\n")

space_padding =
content_lines
|> length()
|> to_string()
|> String.length()

diffish_looking_text =
content_lines
|> Enum.with_index(1)
|> Enum.map_join(fn {line, line_number} ->
IO.ANSI.format(
[
String.pad_trailing(to_string(line_number), space_padding),
" ",
:yellow,
"|",
:green,
line,
"\n"
],
color?
)
end)
source_diff(source, color?)
end)
end

if String.trim(diffish_looking_text) != "" do
"""
defp source_diff(source, color?) do
cond do
Rewrite.Source.from?(source, :string) &&
String.valid?(Rewrite.Source.get(source, :content)) ->
content_lines =
source
|> Rewrite.Source.get(:content)
|> String.split("\n")

space_padding =
content_lines
|> length()
|> to_string()
|> String.length()

diffish_looking_text =
content_lines
|> Enum.with_index(1)
|> Enum.map_join(fn {line, line_number} ->
IO.ANSI.format(
[
String.pad_trailing(to_string(line_number), space_padding),
" ",
:yellow,
"|",
:green,
line,
"\n"
],
color?
)
end)

Create: #{Rewrite.Source.get(source, :path)}
if String.trim(diffish_looking_text) != "" do
"""
#{diffish_looking_text}
"""
else
""
end
Create: #{Rewrite.Source.get(source, :path)}
String.valid?(Rewrite.Source.get(source, :content)) ->
diff = Rewrite.Source.diff(source, color: color?) |> IO.iodata_to_binary()
#{diffish_looking_text}
"""
else
""
end

if String.trim(diff) != "" do
"""
String.valid?(Rewrite.Source.get(source, :content)) ->
diff = Rewrite.Source.diff(source, color: color?) |> IO.iodata_to_binary()

Update: #{Rewrite.Source.get(source, :path)}
if String.trim(diff) != "" do
"""
#{diff}
"""
else
""
end
Update: #{Rewrite.Source.get(source, :path)}
!String.valid?(Rewrite.Source.get(source, :content)) ->
#{diff}
"""
Create: #{Rewrite.Source.get(source, :path)}
else
""
end

(content diff can't be displayed)
"""
!String.valid?(Rewrite.Source.get(source, :content)) ->
"""
Create: #{Rewrite.Source.get(source, :path)}
:else ->
""
end
end)
(content diff can't be displayed)
"""

true ->
""
end
end

@doc false
Expand Down Expand Up @@ -1642,7 +1734,7 @@ defmodule Igniter do
igniter.moves
|> Enum.sort_by(&elem(&1, 0))
|> Enum.map(fn {from, to} ->
[:red, Path.relative_to_cwd(from), :reset, ": ", :green, to]
[:red, from, :reset, ": ", :green, to]
end)
|> display_list("These files will be moved:")
end
Expand Down
14 changes: 12 additions & 2 deletions lib/igniter/util/io.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,22 @@ defmodule Igniter.Util.IO do
items
|> Enum.with_index()
|> Enum.map_join("\n", fn {item, index} ->
"#{index}. #{display.(item)}"
if Keyword.has_key?(opts, :default) && item == opts[:default] do
"#{IO.ANSI.green()}#{index}.#{IO.ANSI.reset()} #{display.(item)} (Default)"
else
"#{index}. #{display.(item)}"
end
end)

case String.trim(Mix.shell().prompt(prompt <> "\n" <> item_numbers <> "\nInput number ❯ ")) do
"" ->
select(prompt, items, opts)
case Keyword.fetch(opts, :default) do
{:ok, value} ->
value

:error ->
select(prompt, items, opts)
end

item ->
case Integer.parse(item) do
Expand Down

0 comments on commit 39686bf

Please sign in to comment.