diff --git a/apps/elixir_ls_debugger/lib/debugger/server.ex b/apps/elixir_ls_debugger/lib/debugger/server.ex index 827f35cc9..edc78008c 100644 --- a/apps/elixir_ls_debugger/lib/debugger/server.ex +++ b/apps/elixir_ls_debugger/lib/debugger/server.ex @@ -509,6 +509,9 @@ defmodule ElixirLS.Debugger.Server do {pid, %Frame{} = frame} -> {state, args_id} = ensure_var_id(state, pid, frame.args) {state, bindings_id} = ensure_var_id(state, pid, frame.bindings) + {state, messages_id} = ensure_var_id(state, pid, frame.messages) + process_info = Process.info(pid) + {state, process_info_id} = ensure_var_id(state, pid, process_info) vars_scope = %{ "name" => "variables", @@ -526,7 +529,27 @@ defmodule ElixirLS.Debugger.Server do "expensive" => false } - scopes = if Enum.count(frame.args) > 0, do: [vars_scope, args_scope], else: [vars_scope] + messages_scope = %{ + "name" => "messages", + "variablesReference" => messages_id, + "namedVariables" => 0, + "indexedVariables" => Enum.count(frame.messages), + "expensive" => false + } + + process_info_scope = %{ + "name" => "process info", + "variablesReference" => process_info_id, + "namedVariables" => length(process_info), + "indexedVariables" => 0, + "expensive" => false + } + + scopes = + [vars_scope, process_info_scope] + |> Kernel.++(if Enum.count(frame.args) > 0, do: [args_scope], else: []) + |> Kernel.++(if Enum.count(frame.messages) > 0, do: [messages_scope], else: []) + {state, scopes} nil -> @@ -1006,7 +1029,6 @@ defmodule ElixirLS.Debugger.Server do "supportsConditionalBreakpoints" => true, "supportsHitConditionalBreakpoints" => true, "supportsLogPoints" => true, - "supportsEvaluateForHovers" => false, "exceptionBreakpointFilters" => [], "supportsStepBack" => false, "supportsSetVariable" => false, diff --git a/apps/elixir_ls_debugger/lib/debugger/stacktrace.ex b/apps/elixir_ls_debugger/lib/debugger/stacktrace.ex index 677301614..efbf20299 100644 --- a/apps/elixir_ls_debugger/lib/debugger/stacktrace.ex +++ b/apps/elixir_ls_debugger/lib/debugger/stacktrace.ex @@ -4,7 +4,7 @@ defmodule ElixirLS.Debugger.Stacktrace do """ defmodule Frame do - defstruct [:level, :file, :module, :function, :args, :line, :bindings] + defstruct [:level, :file, :module, :function, :args, :line, :bindings, :messages] def name(%__MODULE__{} = frame) do "#{inspect(frame.module)}.#{frame.function}/#{Enum.count(frame.args)}" @@ -17,6 +17,8 @@ defmodule ElixirLS.Debugger.Stacktrace do [{level, {module, function, args}} | backtrace_rest] = :int.meta(meta_pid, :backtrace, :all) + messages = :int.meta(meta_pid, :messages) + first_frame = %Frame{ level: level, module: module, @@ -24,7 +26,8 @@ defmodule ElixirLS.Debugger.Stacktrace do args: args, file: get_file(module), line: break_line(pid), - bindings: get_bindings(meta_pid, level) + bindings: get_bindings(meta_pid, level), + messages: messages } # If backtrace_rest is empty, calling stack_frames causes an exception @@ -44,7 +47,8 @@ defmodule ElixirLS.Debugger.Stacktrace do args: args, file: get_file(mod), line: line, - bindings: Enum.into(bindings, %{}) + bindings: Enum.into(bindings, %{}), + messages: messages } end end diff --git a/apps/elixir_ls_debugger/lib/debugger/variables.ex b/apps/elixir_ls_debugger/lib/debugger/variables.ex index e55614b31..360f93e80 100644 --- a/apps/elixir_ls_debugger/lib/debugger/variables.ex +++ b/apps/elixir_ls_debugger/lib/debugger/variables.ex @@ -7,16 +7,31 @@ defmodule ElixirLS.Debugger.Variables do def child_type(var) when is_map(var), do: :named def child_type(var) when is_bitstring(var), do: :indexed def child_type(var) when is_tuple(var), do: :indexed - def child_type(var) when is_list(var), do: :indexed + + def child_type(var) when is_list(var) do + if Keyword.keyword?(var) do + :named + else + :indexed + end + end + def child_type(_var), do: nil def children(var, start, count) when is_list(var) do start = start || 0 count = count || Enum.count(var) - var - |> Enum.slice(start, count) - |> with_index_as_name(start) + sliced = + var + |> Enum.slice(start, count) + + if Keyword.keyword?(var) do + sliced + else + sliced + |> with_index_as_name(start) + end end def children(var, start, count) when is_tuple(var) do @@ -90,7 +105,14 @@ defmodule ElixirLS.Debugger.Variables do def type(var) when is_float(var), do: "float" def type(var) when is_function(var), do: "function" def type(var) when is_integer(var), do: "integer" - def type(var) when is_list(var), do: "list" + + def type(var) when is_list(var) do + if Keyword.keyword?(var) and var != [] do + "keyword" + else + "list" + end + end def type(%name{}), do: "%#{inspect(name)}{}" diff --git a/apps/elixir_ls_debugger/test/debugger_test.exs b/apps/elixir_ls_debugger/test/debugger_test.exs index e6fd317e5..0f83e5df6 100644 --- a/apps/elixir_ls_debugger/test/debugger_test.exs +++ b/apps/elixir_ls_debugger/test/debugger_test.exs @@ -171,6 +171,13 @@ defmodule ElixirLS.Debugger.ServerTest do "namedVariables" => 1, "variablesReference" => vars_id }, + %{ + "expensive" => false, + "indexedVariables" => 0, + "name" => "process info", + "namedVariables" => _, + "variablesReference" => _ + }, %{ "expensive" => false, "indexedVariables" => 1, diff --git a/apps/elixir_ls_debugger/test/variables_test.exs b/apps/elixir_ls_debugger/test/variables_test.exs index f0b0b4a18..27b385b7c 100644 --- a/apps/elixir_ls_debugger/test/variables_test.exs +++ b/apps/elixir_ls_debugger/test/variables_test.exs @@ -39,6 +39,8 @@ defmodule ElixirLS.Debugger.VariablesTest do assert Variables.type([1]) == "list" assert Variables.type('asd') == "list" + assert Variables.type(abc: 123) == "keyword" + assert Variables.type(%{}) == "map" assert Variables.type(%{asd: 123}) == "map" assert Variables.type(%{"asd" => 123}) == "map" @@ -87,6 +89,8 @@ defmodule ElixirLS.Debugger.VariablesTest do assert Variables.num_children([1]) == 1 assert Variables.num_children('asd') == 3 + assert Variables.num_children(abc: 123) == 1 + assert Variables.num_children(%{}) == 0 assert Variables.num_children(%{asd: 123}) == 1 assert Variables.num_children(%{"asd" => 123}) == 1 @@ -104,6 +108,20 @@ defmodule ElixirLS.Debugger.VariablesTest do assert Variables.children('asd', 0, 10) == [{"0", 97}, {"1", 115}, {"2", 100}] end + test "keyword" do + assert Variables.children([abc: 123], 0, 10) == [abc: 123] + + assert Variables.children([abc1: 121, abc2: 122, abc3: 123, abc4: 124], 0, 2) == [ + abc1: 121, + abc2: 122 + ] + + assert Variables.children([abc1: 121, abc2: 122, abc3: 123, abc4: 124], 1, 2) == [ + abc2: 122, + abc3: 123 + ] + end + test "tuple" do assert Variables.children({}, 0, 10) == [] assert Variables.children({1}, 0, 10) == [{"0", 1}]