Packages
livebook
0.8.2
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook/runtime/evaluator/default_formatter.ex
defmodule Livebook.Runtime.Evaluator.DefaultFormatter do
@moduledoc false
# The formatter used by Livebook for rendering the results.
#
# See `Livebook.Runtime.output/0` for available output formats.
@behaviour Livebook.Runtime.Evaluator.Formatter
require Logger
@impl true
def format_result({:ok, :"do not show this result in output"}) do
# Functions in the `IEx.Helpers` module return this specific value
# to indicate no result should be printed in the iex shell,
# so we respect that as well.
:ignored
end
def format_result({:ok, {:module, _, _, _} = value}) do
to_inspect_output(value, limit: 10)
end
def format_result({:ok, value}) do
to_output(value)
end
def format_result({:error, kind, error, stacktrace}) do
formatted = format_error(kind, error, stacktrace)
{:error, formatted, error_type(error)}
end
@compile {:no_warn_undefined, {Kino.Render, :to_livebook, 1}}
defp to_output(value) do
# Kino is a "client side" extension for Livebook that may be
# installed into the runtime node. If it is installed we use
# its more precise output rendering rules.
if Code.ensure_loaded?(Kino.Render) do
try do
Kino.Render.to_livebook(value)
catch
kind, error ->
formatted = format_error(kind, error, __STACKTRACE__)
Logger.error(formatted)
to_inspect_output(value)
end
else
to_inspect_output(value)
end
end
defp to_inspect_output(value, opts \\ []) do
try do
inspected = inspect(value, inspect_opts(opts))
{:text, inspected}
catch
kind, error ->
formatted = format_error(kind, error, __STACKTRACE__)
{:error, formatted}
end
end
def inspect_opts(opts \\ []) do
default_opts = [pretty: true, width: 100, syntax_colors: syntax_colors()]
Keyword.merge(default_opts, opts)
end
defp syntax_colors() do
# Note: we intentionally don't specify colors
# for `:binary`, `:list`, `:map` and `:tuple`
# and rely on these using the default text color.
# This way we avoid a bunch of HTML tags for coloring commas, etc.
[
atom: :blue,
# binary: :light_black,
boolean: :magenta,
# list: :light_black,
# map: :light_black,
number: :blue,
nil: :magenta,
regex: :red,
string: :green,
# tuple: :light_black,
reset: :reset
]
end
defp format_error(kind, error, stacktrace) do
{blamed, stacktrace} =
case error do
%CompileError{description: "cannot compile file (errors have been logged)" <> _, line: 0} ->
{%CompileError{description: "cannot compile cell (errors have been logged)"}, []}
_ ->
Exception.blame(kind, error, stacktrace)
end
banner =
case blamed do
%FunctionClauseError{} ->
banner = Exception.format_banner(kind, error, stacktrace)
blame = FunctionClauseError.blame(blamed, &inspect(&1, inspect_opts()), &blame_match/1)
[error_color(banner), pad(blame)]
_ ->
banner = Exception.format_banner(kind, blamed, stacktrace)
error_color(banner)
end
message =
if stacktrace == [] do
banner
else
stacktrace = Exception.format_stacktrace(stacktrace)
[banner, "\n", error_color(stacktrace)]
end
IO.iodata_to_binary(message)
end
defp blame_match(%{match?: true, node: node}), do: Macro.to_string(node)
defp blame_match(%{match?: false, node: node}) do
node
|> Macro.to_string()
|> error_color()
|> IO.iodata_to_binary()
end
defp pad(string) do
" " <> String.replace(string, "\n", "\n ")
end
defp error_color(string) do
IO.ANSI.format([:red, string], true)
end
defp error_type(%System.EnvError{env: "LB_" <> secret_name}),
do: {:missing_secret, secret_name}
defp error_type(_), do: :other
end