Repository: livebook-dev/kino (elixir)

Issue:
Adding kino as a dependency to project "breaks" dbg/2
I've been using livebook connected to a remote live app. In order to get access to kino I've added it as a dependency in `mix.exs`. After doing that, I've lost output from `dbg/2` calls, both in development and in test.

Is this expected behaviour? 
If so, should there be some warning about it?

UPDATE: 
I've figured this is due to kino doing this:

https://github.com/livebook-dev/kino/blob/2ef471de853ba2a8526a6e64fcb26c44ec2c0145/lib/kino/application.ex#L7

Pull request:
Fall back to default dbg when the call is outside Livebook context
Closes #228.

Patch:
diff --git a/lib/kino/bridge.ex b/lib/kino/bridge.ex
index 081e2d4..837f214 100644
--- a/lib/kino/bridge.ex
+++ b/lib/kino/bridge.ex
@@ -151,6 +151,16 @@ defmodule Kino.Bridge do
     end
   end
 
+  @doc """
+  Checks if the caller is running within Livebook context (group leader).
+  """
+  @spec within_livebook?() :: boolean()
+  def within_livebook?() do
+    # We make a Livebook-specific side-effect-free request and see if
+    # it is recognized
+    match?({:ok, _}, io_request(:livebook_get_evaluation_file))
+  end
+
   defp io_request(request) do
     gl = Process.group_leader()
     ref = Process.monitor(gl)
diff --git a/lib/kino/debug.ex b/lib/kino/debug.ex
index 6b342ec..77b2d52 100644
--- a/lib/kino/debug.ex
+++ b/lib/kino/debug.ex
@@ -11,15 +11,26 @@ defmodule Kino.Debug do
   falls back to the default backend otherwise.
   """
   @spec dbg(Macro.t(), Macro.t(), Macro.Env.t()) :: Macro.t()
-  def dbg(ast, _options, %Macro.Env{} = env) do
+  def dbg(ast, options, %Macro.Env{} = env) do
     dbg_id = System.unique_integer()
 
-    case ast do
-      {:|>, _meta, _args} ->
-        dbg_pipeline_ast(ast, dbg_id, env)
+    kino_ast =
+      case ast do
+        {:|>, _meta, _args} ->
+          dbg_pipeline_ast(ast, dbg_id, env)
 
-      _ ->
-        dbg_default_ast(ast, dbg_id, env)
+        _ ->
+          dbg_default_ast(ast, dbg_id, env)
+      end
+
+    fallback_ast = Macro.dbg(ast, options, env)
+
+    quote do
+      if Kino.Bridge.within_livebook?() do
+        unquote(kino_ast)
+      else
+        unquote(fallback_ast)
+      end
     end
   end
 


Test patch:
diff --git a/lib/kino/test/group_leader.ex b/lib/kino/test/group_leader.ex
index 6cc6257..5d30d12 100644
--- a/lib/kino/test/group_leader.ex
+++ b/lib/kino/test/group_leader.ex
@@ -43,6 +43,10 @@ defmodule Kino.Test.GroupLeader do
     {:ok, state.target}
   end
 
+  defp io_request(:livebook_get_evaluation_file, _state) do
+    {:ok, "#cell:xyz"}
+  end
+
   defp io_request(_request, _state) do
     # Forward everything else to the default group leader
     :forward
diff --git a/test/kino/debug_test.exs b/test/kino/debug_test.exs
index 1751f3f..436f2d6 100644
--- a/test/kino/debug_test.exs
+++ b/test/kino/debug_test.exs
@@ -190,4 +190,10 @@ defmodule Kino.Debug.Test do
       %{call_count: 5} = connect(kino)
     end
   end
+
+  test "falls back to the default dbg implementation when outside livebook context" do
+    # Capturing IO switches the group leader, so the function effectively
+    # runs outside the livebook context
+    assert ExUnit.CaptureIO.capture_io(fn -> call_dbg(:ok) end) =~ ":ok"
+  end
 end