Skip to content

cocoa-xu/ExPTY

Repository files navigation

(Warning: this project is still WIP, there are a lot of things (like proper cleanups) not done yet, and right now it shows a minimal working product (without proper cleanups yet!) with Kino. Use at your own risk.

Any help/PR is welcome!

ExPTY

ExPTY fills the gap where executables spawned by Port do not have a tty available to them.

Module Example
ExPTY
iex> pty = ExPTY.spawn("tty", [], on_data: fn _, _, data -> IO.write(data) end)
#PID<0.229.0>
/dev/ttys001
Port
iex> Port.open({:spawn, "tty"}, [:binary])
#Port<0.5>
iex> flush()
{#Port<0.5>, {:data, "not a tty\n"}}
:ok

Most importantly, and as a consequence of the point above, we can now forward all data to somewhere else (e.g., via WebSocket to LiveBook) have a full terminal experience.

Example

defmodule Example do  
  def run do
    {:ok, pty} =
      ExPTY.spawn("tty", [],
        name: "xterm-color",
        cols: 80,
        rows: 24,
        on_data: __MODULE__,
        on_exit: __MODULE__
      )

    pty
  end

  def on_data(ExPTY, _erl_pid, data) do
    IO.write(data)
  end

  def on_exit(ExPTY, _erl_pid, exit_code, signal_code) do
    IO.puts("exit_code=#{exit_code}, signal_code=#{signal_code}")
  end
end

Installation

Unix

For Unix systems it's pretty much what you would expect, a working C/C++ toolchain, CMake, Make.

Windows

For Windows users, if you're not using Livebook, it's also the same as installing any other NIF libraries.

However, if you're trying to install it on a Livebook, you need to set up some environment variables.

Normally, these environment variables would be set by vcvarsall.bat in your cmd (or powershell, or any other shell), but here we have to do it manually:

  • Open the x64 Native Tools Command Prompt (on 64-bit system) or x86 Native Tools Command Prompt (on 32-bit system)
  • In the command prompt window, type set, and you will see all the environment variables
  • Copy the output printed by set command, and store them in a variable (say env) in the setup cell in your livebook
  • export these environment variables before Mix.install using the following code
Enum.each(String.split(env, "\n"), fn env_var ->
  case String.split(env_var, "=", parts: 2) do
    [name, value] ->
      System.put_env(name, value)
    _ -> :ok
  end
end)

If available in Hex, the package can be installed by adding ExPTY to your list of dependencies in mix.exs:

def deps do
  [
    {:expty, "~> 0.1.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/expty.

Acknowledgements

This project is largely based on microsoft/node-pty. Many thanks to all developers and maintainers, without them this wouldn't be possible.