diff --git a/lib/next_ls/extensions/credo_extension/code_action/remove_debugger.ex b/lib/next_ls/extensions/credo_extension/code_action/remove_debugger.ex index 78b9b731..fb9d6623 100644 --- a/lib/next_ls/extensions/credo_extension/code_action/remove_debugger.ex +++ b/lib/next_ls/extensions/credo_extension/code_action/remove_debugger.ex @@ -10,17 +10,24 @@ defmodule NextLS.CredoExtension.CodeAction.RemoveDebugger do alias NextLS.EditHelpers alias Sourceror.Zipper, as: Z - def new(diagnostic, text, uri) do - %Diagnostic{} = diagnostic - start = diagnostic.range.start + @line_length 121 - with {:ok, ast} <- parse(text), - {:ok, debugger_node} <- find_debugger(ast, start) do - indent = EditHelpers.get_indent(text, diagnostic.range.start.line) + def new(%Diagnostic{} = diagnostic, text, uri) do + range = diagnostic.range + with {:ok, ast, comments} <- parse(text), + {:ok, debugger_node} <- find_debugger(ast, range) do + indent = EditHelpers.get_indent(text, range.start.line) ast_without_debugger = remove_debugger(debugger_node) range = make_range(debugger_node) - formatted = Macro.to_string(ast_without_debugger) + comments = + Enum.filter(comments, fn comment -> + comment.line > range.start.line && comment.line <= range.end.line + end) + + to_algebra_opts = [comments: comments] + doc = Code.quoted_to_algebra(ast_without_debugger, to_algebra_opts) + formatted = doc |> Inspect.Algebra.format(@line_length) |> IO.iodata_to_binary() [ %CodeAction{ @@ -44,39 +51,53 @@ defmodule NextLS.CredoExtension.CodeAction.RemoveDebugger do end end - defp find_debugger(ast, position) do - pos = [line: position.line + 1, column: position.character + 1] + defp find_debugger(ast, range) do + pos = %{ + start: [line: range.start.line + 1, column: range.start.character + 1], + end: [line: range.end.line + 1, column: range.end.character + 1] + } - result = + {_, results} = ast |> Z.zip() - |> Z.traverse(nil, fn tree, acc -> + |> Z.traverse([], fn tree, acc -> node = Z.node(tree) range = Sourceror.get_range(node) - if !acc && - (matches_debug?(node, pos) || matches_pipe?(node, pos)) && - Sourceror.compare_positions(range.start, pos) in [:lt, :eq] && - Sourceror.compare_positions(range.end, pos) in [:gt, :eq] do - {tree, node} + # range.start <= diagnostic_pos.start <= diagnostic_pos.end <= range.end + if (matches_debug?(node) || matches_pipe?(node)) && range && + Sourceror.compare_positions(range.start, pos.start) in [:lt, :eq] && + Sourceror.compare_positions(range.end, pos.end) in [:gt, :eq] do + {tree, [node | acc]} else {tree, acc} end end) + result = Enum.min_by(results, fn node -> + range = Sourceror.get_range(node) + + pos.start[:column] - range.start[:column] + range.end[:column] - pos.end[:column] + end) + + result = Enum.find(results, result, fn + {:|>, _, [_first, ^result]} -> true + _ -> false + end) + case result do - {_, nil} -> {:error, "could find a debugger to remove"} - {_, node} -> {:ok, node} + nil -> {:error, "could find a debugger to remove"} + node -> {:ok, node} end end defp parse(lines) do lines |> Enum.join("\n") - |> Spitfire.parse(literal_encoder: &{:ok, {:__block__, &2, [&1]}}) + |> Spitfire.parse_with_comments(literal_encoder: &{:ok, {:__block__, &2, [&1]}}) |> case do - {:error, ast, _errors} -> - {:ok, ast} + {:error, ast, comments, _errors} -> + {:ok, ast, comments} other -> other @@ -92,18 +113,18 @@ defmodule NextLS.CredoExtension.CodeAction.RemoveDebugger do } end - defp matches_pipe?({:|>, ctx, [_, arg]}, pos), do: pos[:line] == ctx[:line] && matches_debug?(arg, pos) - defp matches_pipe?(_, _), do: false + defp matches_pipe?({:|>, _, [_, arg]}), do: matches_debug?(arg) + defp matches_pipe?(_), do: false - defp matches_debug?({:dbg, ctx, _}, pos), do: pos[:line] == ctx[:line] + defp matches_debug?({:dbg, _, _}), do: true - defp matches_debug?({{:., ctx, [{:__aliases__, _, [:IO]}, f]}, _, _}, pos) when f in [:puts, :inspect], - do: pos[:line] == ctx[:line] + defp matches_debug?({{:., _, [{:__aliases__, _, [:IO]}, f]}, _, _}) when f in [:puts, :inspect], + do: true - defp matches_debug?({{:., ctx, [{:__aliases__, _, [:IEx]}, :pry]}, _, _}, pos), do: pos[:line] == ctx[:line] - defp matches_debug?({{:., ctx, [{:__aliases__, _, [:Mix]}, :env]}, _, _}, pos), do: pos[:line] == ctx[:line] - defp matches_debug?({{:., ctx, [{:__aliases__, _, [:Kernel]}, :dbg]}, _, _}, pos), do: pos[:line] == ctx[:line] - defp matches_debug?(_, _), do: false + defp matches_debug?({{:., _, [{:__aliases__, _, [:IEx]}, :pry]}, _, _}), do: true + defp matches_debug?({{:., _, [{:__aliases__, _, [:Mix]}, :env]}, _, _}), do: true + defp matches_debug?({{:., _, [{:__aliases__, _, [:Kernel]}, :dbg]}, _, _}), do: true + defp matches_debug?(_), do: false defp remove_debugger({:|>, _, [arg, _function]}), do: arg defp remove_debugger({{:., _, [{:__aliases__, _, [:IO]}, :inspect]}, _, [arg | _]}), do: arg @@ -111,6 +132,9 @@ defmodule NextLS.CredoExtension.CodeAction.RemoveDebugger do defp remove_debugger({:dbg, _, [arg | _]}), do: arg defp remove_debugger(_node), do: {:__block__, [], []} + defp pipe?({:|>, _, _}), do: true + defp pipe?(_), do: false + defp make_title({_, ctx, _} = node), do: "Remove `#{format_node(node)}` #{ctx[:line]}:#{ctx[:column]}" defp format_node({:|>, _, [_arg, function]}), do: format_node(function) diff --git a/mix.exs b/mix.exs index 44d844eb..aaf5c607 100644 --- a/mix.exs +++ b/mix.exs @@ -76,7 +76,7 @@ defmodule NextLS.MixProject do {:burrito, "~> 1.0", only: [:dev, :prod]}, {:bypass, "~> 2.1", only: :test}, {:dialyxir, ">= 0.0.0", only: [:dev, :test], runtime: false}, - {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, + {:credo, github: "mhanberg/credo", branch: "fix-debugger-columns", only: [:dev, :test], runtime: false}, {:ex_doc, ">= 0.0.0", only: :dev}, {:styler, "~> 0.8", only: :dev} ] diff --git a/mix.lock b/mix.lock index b4c863cd..e02cefe4 100644 --- a/mix.lock +++ b/mix.lock @@ -9,7 +9,7 @@ "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"}, + "credo": {:git, "https://github.com/mhanberg/credo.git", "a227dfded9f19569efef410c5ba5817ff6c45f47", [branch: "fix-debugger-columns"]}, "ctx": {:hex, :ctx, "0.6.0", "8ff88b70e6400c4df90142e7f130625b82086077a45364a78d208ed3ed53c7fe", [:rebar3], [], "hexpm", "a14ed2d1b67723dbebbe423b28d7615eb0bdcba6ff28f2d1f1b0a7e1d4aa5fc2"}, "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, diff --git a/test/next_ls/extensions/credo_extension/remove_debugger_test.exs b/test/next_ls/extensions/credo_extension/remove_debugger_test.exs index 18ca14fa..64987012 100644 --- a/test/next_ls/extensions/credo_extension/remove_debugger_test.exs +++ b/test/next_ls/extensions/credo_extension/remove_debugger_test.exs @@ -339,7 +339,7 @@ defmodule NextLS.CredoExtension.CodeAction.RemoveDebuggerTest do source: "Elixir", range: %Range{ start: start, - end: %{start | character: 999} + end: start } } end