mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-11 22:16:10 +08:00
List module definitions in the sections side panel (#2760)
This commit is contained in:
parent
eca2dc1143
commit
ad0db1832b
15 changed files with 215 additions and 46 deletions
|
@ -373,7 +373,7 @@ const Session = {
|
||||||
}
|
}
|
||||||
} else if (keyBuffer.tryMatch(["e", "s"])) {
|
} else if (keyBuffer.tryMatch(["e", "s"])) {
|
||||||
this.queueFocusedSectionEvaluation();
|
this.queueFocusedSectionEvaluation();
|
||||||
} else if (keyBuffer.tryMatch(["s", "s"])) {
|
} else if (keyBuffer.tryMatch(["s", "o"])) {
|
||||||
this.toggleSectionsList();
|
this.toggleSectionsList();
|
||||||
} else if (keyBuffer.tryMatch(["s", "e"])) {
|
} else if (keyBuffer.tryMatch(["s", "e"])) {
|
||||||
this.toggleSecretsList();
|
this.toggleSecretsList();
|
||||||
|
@ -579,11 +579,23 @@ const Session = {
|
||||||
*/
|
*/
|
||||||
handleSectionsListClick(event) {
|
handleSectionsListClick(event) {
|
||||||
const sectionButton = event.target.closest(`[data-el-sections-list-item]`);
|
const sectionButton = event.target.closest(`[data-el-sections-list-item]`);
|
||||||
|
|
||||||
if (sectionButton) {
|
if (sectionButton) {
|
||||||
const sectionId = sectionButton.getAttribute("data-section-id");
|
const sectionId = sectionButton.getAttribute("data-section-id");
|
||||||
const section = this.getSectionById(sectionId);
|
const section = this.getSectionById(sectionId);
|
||||||
section.scrollIntoView({ behavior: "instant", block: "start" });
|
section.scrollIntoView({ behavior: "instant", block: "start" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sectionDefinitionButton = event.target.closest(
|
||||||
|
`[data-el-sections-list-definition-item]`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sectionDefinitionButton) {
|
||||||
|
const file = sectionDefinitionButton.getAttribute("data-file");
|
||||||
|
const line = sectionDefinitionButton.getAttribute("data-line");
|
||||||
|
|
||||||
|
this.jumpToLine(file, line);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -550,7 +550,7 @@ defmodule Livebook.Intellisense do
|
||||||
path = Path.join(context.ebin_path, "#{module}.beam")
|
path = Path.join(context.ebin_path, "#{module}.beam")
|
||||||
|
|
||||||
with true <- File.exists?(path),
|
with true <- File.exists?(path),
|
||||||
{:ok, line} <- Docs.locate_definition(path, identifier) do
|
{:ok, line} <- Docs.locate_definition(String.to_charlist(path), identifier) do
|
||||||
file = module.module_info(:compile)[:source]
|
file = module.module_info(:compile)[:source]
|
||||||
%{file: to_string(file), line: line}
|
%{file: to_string(file), line: line}
|
||||||
else
|
else
|
||||||
|
|
|
@ -185,7 +185,7 @@ defmodule Livebook.Intellisense.Docs do
|
||||||
|
|
||||||
The function returns the line where the identifier is located.
|
The function returns the line where the identifier is located.
|
||||||
"""
|
"""
|
||||||
@spec locate_definition(String.t(), definition()) :: {:ok, pos_integer()} | :error
|
@spec locate_definition(list() | binary(), definition()) :: {:ok, pos_integer()} | :error
|
||||||
def locate_definition(path, identifier)
|
def locate_definition(path, identifier)
|
||||||
|
|
||||||
def locate_definition(path, {:module, module}) do
|
def locate_definition(path, {:module, module}) do
|
||||||
|
@ -221,8 +221,6 @@ defmodule Livebook.Intellisense.Docs do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp beam_lib_chunks(path, key) do
|
defp beam_lib_chunks(path, key) do
|
||||||
path = String.to_charlist(path)
|
|
||||||
|
|
||||||
case :beam_lib.chunks(path, [key]) do
|
case :beam_lib.chunks(path, [key]) do
|
||||||
{:ok, {_, [{^key, value}]}} -> {:ok, value}
|
{:ok, {_, [{^key, value}]}} -> {:ok, value}
|
||||||
_ -> :error
|
_ -> :error
|
||||||
|
|
|
@ -470,12 +470,15 @@ defprotocol Livebook.Runtime do
|
||||||
dependencies between evaluations and avoids unnecessary reevaluations.
|
dependencies between evaluations and avoids unnecessary reevaluations.
|
||||||
"""
|
"""
|
||||||
@type evaluation_response_metadata :: %{
|
@type evaluation_response_metadata :: %{
|
||||||
|
interrupted: boolean(),
|
||||||
errored: boolean(),
|
errored: boolean(),
|
||||||
evaluation_time_ms: non_neg_integer(),
|
evaluation_time_ms: non_neg_integer(),
|
||||||
code_markers: list(code_marker()),
|
code_markers: list(code_marker()),
|
||||||
memory_usage: runtime_memory(),
|
memory_usage: runtime_memory(),
|
||||||
identifiers_used: list(identifier :: term()) | :unknown,
|
identifiers_used: list(identifier :: term()) | :unknown,
|
||||||
identifiers_defined: %{(identifier :: term()) => version :: term()}
|
identifiers_defined: %{(identifier :: term()) => version :: term()},
|
||||||
|
identifier_definitions:
|
||||||
|
list(%{label: String.t(), file: String.t(), line: pos_integer()})
|
||||||
}
|
}
|
||||||
|
|
||||||
@typedoc """
|
@typedoc """
|
||||||
|
|
|
@ -439,7 +439,7 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
|
|
||||||
%{tracer_info: tracer_info} = Evaluator.IOProxy.after_evaluation(state.io_proxy)
|
%{tracer_info: tracer_info} = Evaluator.IOProxy.after_evaluation(state.io_proxy)
|
||||||
|
|
||||||
{new_context, result, identifiers_used, identifiers_defined} =
|
{new_context, result, identifiers_used, identifiers_defined, identifier_definitions} =
|
||||||
case eval_result do
|
case eval_result do
|
||||||
{:ok, value, binding, env} ->
|
{:ok, value, binding, env} ->
|
||||||
context_id = random_long_id()
|
context_id = random_long_id()
|
||||||
|
@ -454,8 +454,10 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
{identifiers_used, identifiers_defined} =
|
{identifiers_used, identifiers_defined} =
|
||||||
identifier_dependencies(new_context, tracer_info, context)
|
identifier_dependencies(new_context, tracer_info, context)
|
||||||
|
|
||||||
|
identifier_definitions = definitions(new_context, tracer_info)
|
||||||
|
|
||||||
result = {:ok, value}
|
result = {:ok, value}
|
||||||
{new_context, result, identifiers_used, identifiers_defined}
|
{new_context, result, identifiers_used, identifiers_defined, identifier_definitions}
|
||||||
|
|
||||||
{:error, kind, error, stacktrace} ->
|
{:error, kind, error, stacktrace} ->
|
||||||
for {module, _} <- tracer_info.modules_defined do
|
for {module, _} <- tracer_info.modules_defined do
|
||||||
|
@ -465,9 +467,10 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
result = {:error, kind, error, stacktrace}
|
result = {:error, kind, error, stacktrace}
|
||||||
identifiers_used = :unknown
|
identifiers_used = :unknown
|
||||||
identifiers_defined = %{}
|
identifiers_defined = %{}
|
||||||
|
identifier_definitions = []
|
||||||
# Empty context
|
# Empty context
|
||||||
new_context = initial_context()
|
new_context = initial_context()
|
||||||
{new_context, result, identifiers_used, identifiers_defined}
|
{new_context, result, identifiers_used, identifiers_defined, identifier_definitions}
|
||||||
end
|
end
|
||||||
|
|
||||||
if ebin_path() do
|
if ebin_path() do
|
||||||
|
@ -475,7 +478,6 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
end
|
end
|
||||||
|
|
||||||
state = put_context(state, ref, new_context)
|
state = put_context(state, ref, new_context)
|
||||||
|
|
||||||
output = Evaluator.Formatter.format_result(result, language)
|
output = Evaluator.Formatter.format_result(result, language)
|
||||||
|
|
||||||
metadata = %{
|
metadata = %{
|
||||||
|
@ -485,7 +487,8 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
memory_usage: memory(),
|
memory_usage: memory(),
|
||||||
code_markers: code_markers,
|
code_markers: code_markers,
|
||||||
identifiers_used: identifiers_used,
|
identifiers_used: identifiers_used,
|
||||||
identifiers_defined: identifiers_defined
|
identifiers_defined: identifiers_defined,
|
||||||
|
identifier_definitions: identifier_definitions
|
||||||
}
|
}
|
||||||
|
|
||||||
send(state.send_to, {:runtime_evaluation_response, ref, output, metadata})
|
send(state.send_to, {:runtime_evaluation_response, ref, output, metadata})
|
||||||
|
@ -890,7 +893,7 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
into: identifiers_used
|
into: identifiers_used
|
||||||
|
|
||||||
identifiers_defined =
|
identifiers_defined =
|
||||||
for {module, _vars} <- tracer_info.modules_defined,
|
for {module, _line_vars} <- tracer_info.modules_defined,
|
||||||
version = module.__info__(:md5),
|
version = module.__info__(:md5),
|
||||||
do: {{:module, module}, version},
|
do: {{:module, module}, version},
|
||||||
into: identifiers_defined
|
into: identifiers_defined
|
||||||
|
@ -968,7 +971,7 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
# Note that :prune_binding removes variables used by modules
|
# Note that :prune_binding removes variables used by modules
|
||||||
# (unless used outside), so we get those from the tracer
|
# (unless used outside), so we get those from the tracer
|
||||||
module_used_vars =
|
module_used_vars =
|
||||||
for {_module, vars} <- tracer_info.modules_defined,
|
for {_module, {_line, vars}} <- tracer_info.modules_defined,
|
||||||
var <- vars,
|
var <- vars,
|
||||||
into: MapSet.new(),
|
into: MapSet.new(),
|
||||||
do: var
|
do: var
|
||||||
|
@ -1038,4 +1041,16 @@ defmodule Livebook.Runtime.Evaluator do
|
||||||
defp ebin_path() do
|
defp ebin_path() do
|
||||||
Process.get(@ebin_path_key)
|
Process.get(@ebin_path_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp definitions(context, tracer_info) do
|
||||||
|
for {module, {line, _vars}} <- tracer_info.modules_defined,
|
||||||
|
do: %{label: module_name(module), file: context.env.file, line: line}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp module_name(module) do
|
||||||
|
case Atom.to_string(module) do
|
||||||
|
"Elixir." <> name -> name
|
||||||
|
name -> name
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -146,7 +146,7 @@ defmodule Livebook.Runtime.Evaluator.IOProxy do
|
||||||
state = update_in(state.tracer_info, &Evaluator.Tracer.apply_updates(&1, updates))
|
state = update_in(state.tracer_info, &Evaluator.Tracer.apply_updates(&1, updates))
|
||||||
|
|
||||||
modules_defined =
|
modules_defined =
|
||||||
for {:module_defined, module, _vars} <- updates,
|
for {:module_defined, module, _vars, _line} <- updates,
|
||||||
into: state.modules_defined,
|
into: state.modules_defined,
|
||||||
do: module
|
do: module
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ defmodule Livebook.Runtime.Evaluator.Tracer do
|
||||||
module = env.module
|
module = env.module
|
||||||
vars = Map.keys(env.versioned_vars)
|
vars = Map.keys(env.versioned_vars)
|
||||||
Evaluator.write_module!(module, bytecode)
|
Evaluator.write_module!(module, bytecode)
|
||||||
[{:module_defined, module, vars}, {:alias_used, module}]
|
[{:module_defined, module, vars, env.line}, {:alias_used, module}]
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
|
@ -112,8 +112,8 @@ defmodule Livebook.Runtime.Evaluator.Tracer do
|
||||||
update_in(info.modules_used, &MapSet.put(&1, module))
|
update_in(info.modules_used, &MapSet.put(&1, module))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp apply_update(info, {:module_defined, module, vars}) do
|
defp apply_update(info, {:module_defined, module, vars, line}) do
|
||||||
put_in(info.modules_defined[module], vars)
|
put_in(info.modules_defined[module], {line, vars})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp apply_update(info, {:alias_used, alias}) do
|
defp apply_update(info, {:alias_used, alias}) do
|
||||||
|
|
|
@ -118,6 +118,8 @@ defmodule Livebook.Session.Data do
|
||||||
new_bound_to_inputs: %{input_id() => input_hash()},
|
new_bound_to_inputs: %{input_id() => input_hash()},
|
||||||
identifiers_used: list(identifier :: term()) | :unknown,
|
identifiers_used: list(identifier :: term()) | :unknown,
|
||||||
identifiers_defined: %{(identifier :: term()) => version :: term()},
|
identifiers_defined: %{(identifier :: term()) => version :: term()},
|
||||||
|
identifier_definitions:
|
||||||
|
list(%{label: String.t(), file: String.t(), line: pos_integer()}),
|
||||||
data: t()
|
data: t()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,7 +1403,8 @@ defmodule Livebook.Session.Data do
|
||||||
identifiers_defined: metadata.identifiers_defined,
|
identifiers_defined: metadata.identifiers_defined,
|
||||||
bound_to_inputs: eval_info.new_bound_to_inputs,
|
bound_to_inputs: eval_info.new_bound_to_inputs,
|
||||||
evaluation_end: DateTime.utc_now(),
|
evaluation_end: DateTime.utc_now(),
|
||||||
code_markers: metadata.code_markers
|
code_markers: metadata.code_markers,
|
||||||
|
identifier_definitions: metadata.identifier_definitions
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|> update_cell_evaluation_snapshot(cell, section)
|
|> update_cell_evaluation_snapshot(cell, section)
|
||||||
|
@ -2380,6 +2383,7 @@ defmodule Livebook.Session.Data do
|
||||||
data: nil,
|
data: nil,
|
||||||
code_markers: [],
|
code_markers: [],
|
||||||
doctest_reports: %{},
|
doctest_reports: %{},
|
||||||
|
identifier_definitions: [],
|
||||||
reevaluates_automatically: false
|
reevaluates_automatically: false
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1796,7 +1796,8 @@ defmodule LivebookWeb.SessionLive do
|
||||||
id: section.id,
|
id: section.id,
|
||||||
name: section.name,
|
name: section.name,
|
||||||
parent: parent_section_view(section.parent_id, data),
|
parent: parent_section_view(section.parent_id, data),
|
||||||
status: cells_status(section.cells, data)
|
status: cells_status(section.cells, data),
|
||||||
|
identifier_definitions: cells_identifier_definitions(section.cells, data)
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
clients:
|
clients:
|
||||||
|
@ -1853,6 +1854,14 @@ defmodule LivebookWeb.SessionLive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp cells_identifier_definitions(cells, data) do
|
||||||
|
for %Cell.Code{} = cell <- cells,
|
||||||
|
Cell.evaluable?(cell),
|
||||||
|
info = data.cell_infos[cell.id].eval,
|
||||||
|
definition <- info.identifier_definitions,
|
||||||
|
do: definition
|
||||||
|
end
|
||||||
|
|
||||||
defp global_status(data) do
|
defp global_status(data) do
|
||||||
cells =
|
cells =
|
||||||
data.notebook
|
data.notebook
|
||||||
|
|
|
@ -331,8 +331,8 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
<%!-- Local functionality --%>
|
<%!-- Local functionality --%>
|
||||||
|
|
||||||
<.button_item
|
<.button_item
|
||||||
icon="booklet-fill"
|
icon="node-tree"
|
||||||
label="Sections (ss)"
|
label="Outline (so)"
|
||||||
button_attrs={["data-el-sections-list-toggle": true]}
|
button_attrs={["data-el-sections-list-toggle": true]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -419,8 +419,8 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
class="flex flex-col h-full w-full max-w-xs absolute z-30 top-0 left-[64px] overflow-y-auto shadow-xl md:static md:shadow-none bg-gray-50 border-r border-gray-100 px-6 pt-16 md:py-8"
|
class="flex flex-col h-full w-full max-w-xs absolute z-30 top-0 left-[64px] overflow-y-auto shadow-xl md:static md:shadow-none bg-gray-50 border-r border-gray-100 px-6 pt-16 md:py-8"
|
||||||
data-el-side-panel
|
data-el-side-panel
|
||||||
>
|
>
|
||||||
<div class="flex grow" data-el-sections-list>
|
<div data-el-sections-list>
|
||||||
<.sections_list data_view={@data_view} />
|
<.outline_list data_view={@data_view} />
|
||||||
</div>
|
</div>
|
||||||
<div data-el-clients-list>
|
<div data-el-clients-list>
|
||||||
<.clients_list data_view={@data_view} client_id={@client_id} />
|
<.clients_list data_view={@data_view} client_id={@client_id} />
|
||||||
|
@ -497,25 +497,26 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp sections_list(assigns) do
|
defp outline_list(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex flex-col grow">
|
<div class="flex flex-col grow">
|
||||||
<h3 class="uppercase text-sm font-semibold text-gray-500">
|
<h3 class="uppercase text-sm font-semibold text-gray-500">
|
||||||
Sections
|
Outline
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex flex-col mt-4 space-y-4">
|
<div class="flex flex-col mt-4 space-y-4">
|
||||||
<div :for={section_item <- @data_view.sections_items} class="flex items-center">
|
<div :for={section_item <- @data_view.sections_items} class="flex flex-col">
|
||||||
<button
|
<div class="flex justify-between items-center">
|
||||||
class="grow flex items-center text-gray-500 hover:text-gray-900 text-left"
|
<button
|
||||||
data-el-sections-list-item
|
class="grow flex items-center gap-1 text-gray-500 hover:text-gray-900 text-left"
|
||||||
data-section-id={section_item.id}
|
data-el-sections-list-item
|
||||||
>
|
data-section-id={section_item.id}
|
||||||
<span class="flex items-center space-x-1">
|
>
|
||||||
|
<.remix_icon icon="font-size" class="text-lg font-normal leading-none" />
|
||||||
<span><%= section_item.name %></span>
|
<span><%= section_item.name %></span>
|
||||||
<%!--
|
<%!--
|
||||||
Note: the container has overflow-y auto, so we cannot set overflow-x visible,
|
Note: the container has overflow-y auto, so we cannot set overflow-x visible,
|
||||||
consequently we show the tooltip wrapped to a fixed number of characters
|
consequently we show the tooltip wrapped to a fixed number of characters
|
||||||
--%>
|
--%>
|
||||||
<span
|
<span
|
||||||
:if={section_item.parent}
|
:if={section_item.parent}
|
||||||
{branching_tooltip_attrs(section_item.name, section_item.parent.name)}
|
{branching_tooltip_attrs(section_item.name, section_item.parent.name)}
|
||||||
|
@ -525,12 +526,30 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
class="text-lg font-normal leading-none flip-horizontally"
|
class="text-lg font-normal leading-none flip-horizontally"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</button>
|
||||||
</button>
|
|
||||||
<.section_status
|
<.section_status
|
||||||
status={elem(section_item.status, 0)}
|
status={elem(section_item.status, 0)}
|
||||||
cell_id={elem(section_item.status, 1)}
|
cell_id={elem(section_item.status, 1)}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul :if={section_item.identifier_definitions != []} class="mt-2 ml-5 list-none items-center">
|
||||||
|
<li :for={definition <- section_item.identifier_definitions}>
|
||||||
|
<button
|
||||||
|
class="flex items-center max-w-full text-gray-500 hover:text-gray-900 text-sm gap-1"
|
||||||
|
data-el-sections-list-definition-item
|
||||||
|
data-file={definition.file}
|
||||||
|
data-line={definition.line}
|
||||||
|
title={definition.label}
|
||||||
|
>
|
||||||
|
<.remix_icon icon="braces-line" class="font-normal" />
|
||||||
|
<span class="font-mono truncate">
|
||||||
|
<%= definition.label %>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
@ -558,7 +577,7 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
wrapped_name = Livebook.Utils.wrap_line("”" <> parent_name <> "”", 16)
|
wrapped_name = Livebook.Utils.wrap_line("”" <> parent_name <> "”", 16)
|
||||||
label = "Branches from\n#{wrapped_name}"
|
label = "Branches from\n#{wrapped_name}"
|
||||||
|
|
||||||
[class: "tooltip #{direction}", data_tooltip: label]
|
[class: "tooltip #{direction}", "data-tooltip": label]
|
||||||
end
|
end
|
||||||
|
|
||||||
defp clients_list(assigns) do
|
defp clients_list(assigns) do
|
||||||
|
|
|
@ -259,9 +259,8 @@ defmodule Livebook.Runtime.EvaluatorTest do
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns additional metadata when there is a module compilation error", %{
|
test "returns additional metadata when there is a module compilation error",
|
||||||
evaluator: evaluator
|
%{evaluator: evaluator} do
|
||||||
} do
|
|
||||||
code = """
|
code = """
|
||||||
defmodule Livebook.Runtime.EvaluatorTest.Invalid do
|
defmodule Livebook.Runtime.EvaluatorTest.Invalid do
|
||||||
x
|
x
|
||||||
|
@ -504,6 +503,50 @@ defmodule Livebook.Runtime.EvaluatorTest do
|
||||||
|
|
||||||
refute Code.ensure_loaded?(Livebook.Runtime.EvaluatorTest.Exited)
|
refute Code.ensure_loaded?(Livebook.Runtime.EvaluatorTest.Exited)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag :with_ebin_path
|
||||||
|
test "returns identifier definitions", %{evaluator: evaluator} do
|
||||||
|
Code.put_compiler_option(:debug_info, true)
|
||||||
|
|
||||||
|
code = ~S'''
|
||||||
|
defmodule Livebook.Runtime.EvaluatorTest.ModuleDef1 do
|
||||||
|
def fun(), do: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defmodule Livebook.Runtime.EvaluatorTest.ModuleDef2 do
|
||||||
|
defmodule Foo do
|
||||||
|
defstruct [:name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
'''
|
||||||
|
|
||||||
|
file = "file.livemd#cell_id:123456789"
|
||||||
|
|
||||||
|
Evaluator.evaluate_code(evaluator, :elixir, code, :code_1, [], file: file)
|
||||||
|
|
||||||
|
assert_receive {:runtime_evaluation_response, :code_1, terminal_text(_),
|
||||||
|
metadata() = metadata}
|
||||||
|
|
||||||
|
assert metadata.identifier_definitions == [
|
||||||
|
%{
|
||||||
|
label: "Livebook.Runtime.EvaluatorTest.ModuleDef1",
|
||||||
|
line: 1,
|
||||||
|
file: file
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
label: "Livebook.Runtime.EvaluatorTest.ModuleDef2",
|
||||||
|
line: 5,
|
||||||
|
file: file
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
label: "Livebook.Runtime.EvaluatorTest.ModuleDef2.Foo",
|
||||||
|
line: 6,
|
||||||
|
file: file
|
||||||
|
}
|
||||||
|
]
|
||||||
|
after
|
||||||
|
Code.put_compiler_option(:debug_info, false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "doctests" do
|
describe "doctests" do
|
||||||
|
|
|
@ -25,6 +25,7 @@ defmodule Livebook.Session.DataTest do
|
||||||
defp eval_meta(opts \\ []) do
|
defp eval_meta(opts \\ []) do
|
||||||
uses = opts[:uses] || []
|
uses = opts[:uses] || []
|
||||||
defines = opts[:defines] || %{}
|
defines = opts[:defines] || %{}
|
||||||
|
identifier_definitions = opts[:identifier_definitions] || []
|
||||||
errored = Keyword.get(opts, :errored, false)
|
errored = Keyword.get(opts, :errored, false)
|
||||||
interrupted = Keyword.get(opts, :interrupted, false)
|
interrupted = Keyword.get(opts, :interrupted, false)
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ defmodule Livebook.Session.DataTest do
|
||||||
evaluation_time_ms: 10,
|
evaluation_time_ms: 10,
|
||||||
identifiers_used: uses,
|
identifiers_used: uses,
|
||||||
identifiers_defined: defines,
|
identifiers_defined: defines,
|
||||||
|
identifier_definitions: identifier_definitions,
|
||||||
code_markers: []
|
code_markers: []
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,7 @@ defmodule Livebook.SessionTest do
|
||||||
evaluation_time_ms: 10,
|
evaluation_time_ms: 10,
|
||||||
identifiers_used: [],
|
identifiers_used: [],
|
||||||
identifiers_defined: %{},
|
identifiers_defined: %{},
|
||||||
|
identifier_definitions: [],
|
||||||
code_markers: []
|
code_markers: []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,10 +246,11 @@ defmodule LivebookWeb.Integration.Hub.DeploymentGroupTest do
|
||||||
test "shows the app deployed count", %{conn: conn, hub: hub, tmp_dir: tmp_dir} do
|
test "shows the app deployed count", %{conn: conn, hub: hub, tmp_dir: tmp_dir} do
|
||||||
%{id: id} = insert_deployment_group(mode: :online, hub_id: hub.id)
|
%{id: id} = insert_deployment_group(mode: :online, hub_id: hub.id)
|
||||||
id = to_string(id)
|
id = to_string(id)
|
||||||
|
hub_id = hub.id
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}")
|
{:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}")
|
||||||
|
|
||||||
refute_received {:app_deployment_started, %{deployment_group_id: ^id}}
|
refute_received {:app_deployment_started, %{deployment_group_id: ^id, hub_id: ^hub_id}}
|
||||||
|
|
||||||
assert view
|
assert view
|
||||||
|> element("#hub-deployment-group-#{id} [aria-label=\"apps deployed\"]")
|
|> element("#hub-deployment-group-#{id} [aria-label=\"apps deployed\"]")
|
||||||
|
|
|
@ -2632,4 +2632,66 @@ defmodule LivebookWeb.SessionLiveTest do
|
||||||
assert File.read!(dockerfile_path) =~ "COPY notebook.livemd /apps"
|
assert File.read!(dockerfile_path) =~ "COPY notebook.livemd /apps"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "defined modules under sections", %{conn: conn, session: session} do
|
||||||
|
Code.put_compiler_option(:debug_info, true)
|
||||||
|
|
||||||
|
Session.subscribe(session.id)
|
||||||
|
|
||||||
|
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
|
||||||
|
refute render(view) =~ "LivebookWeb.SessionLiveTest.MyBigModuleName"
|
||||||
|
|
||||||
|
cell_id =
|
||||||
|
insert_text_cell(session.pid, insert_section(session.pid), :code, ~S'''
|
||||||
|
defmodule LivebookWeb.SessionLiveTest.MyBigModuleName do
|
||||||
|
def bar, do: :baz
|
||||||
|
end
|
||||||
|
''')
|
||||||
|
|
||||||
|
Session.queue_cell_evaluation(session.pid, cell_id)
|
||||||
|
assert_receive {:operation, {:add_cell_evaluation_response, _, ^cell_id, _, _}}
|
||||||
|
|
||||||
|
assert has_element?(
|
||||||
|
view,
|
||||||
|
"[data-el-sections-list-definition-item] span",
|
||||||
|
"LivebookWeb.SessionLiveTest.MyBigModuleName"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert render(view) =~
|
||||||
|
~s'data-file="#cell:#{cell_id}" data-line="1" title="LivebookWeb.SessionLiveTest.MyBigModuleName"'
|
||||||
|
|
||||||
|
second_cell_id =
|
||||||
|
insert_text_cell(session.pid, insert_section(session.pid), :code, ~S'''
|
||||||
|
defmodule LivebookWeb.SessionLiveTest.AnotherModule do
|
||||||
|
def bar, do: :baz
|
||||||
|
end
|
||||||
|
|
||||||
|
defmodule LivebookWeb.SessionLiveTest.Foo do
|
||||||
|
def bar, do: :baz
|
||||||
|
end
|
||||||
|
''')
|
||||||
|
|
||||||
|
Session.queue_cell_evaluation(session.pid, second_cell_id)
|
||||||
|
assert_receive {:operation, {:add_cell_evaluation_response, _, ^second_cell_id, _, _}}
|
||||||
|
|
||||||
|
assert has_element?(
|
||||||
|
view,
|
||||||
|
"[data-el-sections-list-definition-item] span",
|
||||||
|
"LivebookWeb.SessionLiveTest.AnotherModule"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert has_element?(
|
||||||
|
view,
|
||||||
|
"[data-el-sections-list-definition-item] span",
|
||||||
|
"LivebookWeb.SessionLiveTest.Foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert render(view) =~
|
||||||
|
~s'data-file="#cell:#{second_cell_id}" data-line="1" title="LivebookWeb.SessionLiveTest.AnotherModule"'
|
||||||
|
|
||||||
|
assert render(view) =~
|
||||||
|
~s'data-file="#cell:#{second_cell_id}" data-line="5" title="LivebookWeb.SessionLiveTest.Foo"'
|
||||||
|
after
|
||||||
|
Code.put_compiler_option(:debug_info, false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue