# libtmux for Erlang

Source: https://libtmux.org/en/erlang/latest/

> libtmux for Erlang, version latest.

![](https://libtmux.org/en/brand/erlang/library/logo.svg)

Erlang-based tmux client

tmux client library for Erlang. Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, capture pane contents

```erlang
-module(readme_demo).
-moduledoc "Create a workspace, query its graph and preserve captured values.".
-export([run/1]).
-import_record(tmux_model, [pane]).


-spec run(binary()) -> map().
run(Executable) ->
    {ok, Server, Ownership} =
        tmux_server:start_owned(#{executable => Executable}),
    try
        {ok, Session} = tmux_session:create(Server, #{name => <<"workspace">>,
            window_name => <<"editor">>, width => 120, height => 30,
            launch => #{argv => [<<"/bin/cat">>]}}),
        {ok, Worker} = tmux_window:create(Session,
            #{name => <<"workers">>,
              launch => #{argv => [<<"/bin/cat">>]}}),
        {ok, Right} = tmux_pane:split(Worker, #{direction => horizontal,
            launch => #{argv => [<<"/bin/cat">>]}}),
        {ok, _} = tmux_window:select_layout(Worker, even_horizontal),
        {ok, _} = tmux_pane:resize(Right, #{width => 40}),
        {ok, Snapshot} = tmux_server:snapshot(Server),
        Windows = tmux_select:windows(Snapshot),
        Workers = #{name => <<"workers">>, panes => #{count => 2,
            every => #{current_command => <<"cat">>}}},
        {ok, Captured} = tmux_select:one(Workers, Windows),
        {ok, Children} = tmux_snapshot:related(panes, Captured, Snapshot),
        Ids = [Id || #pane{id = Id} <:- Children],
        2 = length(Ids),
        Criteria = #{width => #{gte => 20},
            window => #{is => #{name => <<"workers">>}}},
        Query = tmux_query:where(Criteria, tmux_query:panes(Server)),
        {ok, Fetched} = tmux_query:fetch(Query),
        2 = tmux_select:size(Fetched),
        {ok, _} = tmux_window:rename(Worker, <<"finished">>),
        <<"workers">> = tmux_model:get(name, Captured),
        {ok, Fresh} = tmux_query:fetch(tmux_query:where(
            #{name => <<"finished">>}, tmux_query:windows(Server))),
        {ok, Renamed} = tmux_select:one(Fresh),
        <<"finished">> = tmux_model:get(name, Renamed),
        1 = length(tmux_snapshot:sessions(Snapshot)),
        2 = length(tmux_snapshot:windows(Snapshot)),
        3 = length(tmux_snapshot:panes(Snapshot)),
        #{sessions => 1, windows => 2, panes => 3, matched_panes => 2,
          captured_name => <<"workers">>, immutable => true}
    after
        ok = tmux_server:stop_owned(Ownership)
    end.
```

```erlang
-module(readme_demo).
-moduledoc "Create a workspace, query its graph and preserve captured values.".
-export([run/1]).
-import_record(tmux_model, [pane]).


-spec run(binary()) -> map().
run(Executable) ->
    {ok, Server, Ownership} =
        tmux_server:start_owned(#{executable => Executable}),
    try
        {ok, Session} = tmux_session:create(Server, #{name => <<"workspace">>,
            window_name => <<"editor">>, width => 120, height => 30,
            launch => #{argv => [<<"/bin/cat">>]}}),
        {ok, Worker} = tmux_window:create(Session,
            #{name => <<"workers">>,
              launch => #{argv => [<<"/bin/cat">>]}}),
        {ok, Right} = tmux_pane:split(Worker, #{direction => horizontal,
            launch => #{argv => [<<"/bin/cat">>]}}),
        {ok, _} = tmux_window:select_layout(Worker, even_horizontal),
        {ok, _} = tmux_pane:resize(Right, #{width => 40}),
        {ok, Snapshot} = tmux_server:snapshot(Server),
        Windows = tmux_select:windows(Snapshot),
        Workers = #{name => <<"workers">>, panes => #{count => 2,
            every => #{current_command => <<"cat">>}}},
        {ok, Captured} = tmux_select:one(Workers, Windows),
        {ok, Children} = tmux_snapshot:related(panes, Captured, Snapshot),
        Ids = [Id || #pane{id = Id} <:- Children],
        2 = length(Ids),
        Criteria = #{width => #{gte => 20},
            window => #{is => #{name => <<"workers">>}}},
        Query = tmux_query:where(Criteria, tmux_query:panes(Server)),
        {ok, Fetched} = tmux_query:fetch(Query),
        2 = tmux_select:size(Fetched),
        {ok, _} = tmux_window:rename(Worker, <<"finished">>),
        <<"workers">> = tmux_model:get(name, Captured),
        {ok, Fresh} = tmux_query:fetch(tmux_query:where(
            #{name => <<"finished">>}, tmux_query:windows(Server))),
        {ok, Renamed} = tmux_select:one(Fresh),
        <<"finished">> = tmux_model:get(name, Renamed),
        1 = length(tmux_snapshot:sessions(Snapshot)),
        2 = length(tmux_snapshot:windows(Snapshot)),
        3 = length(tmux_snapshot:panes(Snapshot)),
        #{sessions => 1, windows => 2, panes => 3, matched_panes => 2,
          captured_name => <<"workers">>, immutable => true}
    after
        ok = tmux_server:stop_owned(Ownership)
    end.
```

```erlang
-module(readme_demo).
-moduledoc "Create a workspace, query its graph and preserve captured values.".
-export([run/1]).
-import_record(tmux_model, [pane]).


-spec run(binary()) -> map().
run(Executable) ->
    {ok, Server, Ownership} =
        tmux_server:start_owned(#{executable => Executable}),
    try
        {ok, Session} = tmux_session:create(Server, #{name => <<"workspace">>,
            window_name => <<"editor">>, width => 120, height => 30,
            launch => #{argv => [<<"/bin/cat">>]}}),
        try
            {ok, Worker} = tmux_window:create(Session,
                #{name => <<"workers">>,
                  launch => #{argv => [<<"/bin/cat">>]}}),
            {ok, Right} = tmux_pane:split(Worker, #{direction => horizontal,
                launch => #{argv => [<<"/bin/cat">>]}}),
            {ok, _} = tmux_window:select_layout(Worker, even_horizontal),
            {ok, _} = tmux_pane:resize(Right, #{width => 40}),
            {ok, Snapshot} = tmux_server:snapshot(Server),
            Windows = tmux_select:windows(Snapshot),
            Workers = #{name => <<"workers">>, panes => #{count => 2,
                every => #{current_command => <<"cat">>}}},
            {ok, Captured} = tmux_select:one(Workers, Windows),
            {ok, Children} = tmux_snapshot:related(panes, Captured, Snapshot),
            Ids = [Id || #pane{id = Id} <:- Children],
            2 = length(Ids),
            Criteria = #{width => #{gte => 20},
                window => #{is => #{name => <<"workers">>}}},
            Query = tmux_query:where(Criteria, tmux_query:panes(Server)),
            {ok, Fetched} = tmux_query:fetch(Query),
            2 = tmux_select:size(Fetched),
            {ok, _} = tmux_window:rename(Worker, <<"finished">>),
            <<"workers">> = tmux_model:get(name, Captured),
            {ok, Fresh} = tmux_query:fetch(tmux_query:where(
                #{name => <<"finished">>}, tmux_query:windows(Server))),
            {ok, Renamed} = tmux_select:one(Fresh),
            <<"finished">> = tmux_model:get(name, Renamed),
            1 = length(tmux_snapshot:sessions(Snapshot)),
            2 = length(tmux_snapshot:windows(Snapshot)),
            3 = length(tmux_snapshot:panes(Snapshot)),
            #{sessions => 1, windows => 2, panes => 3, matched_panes => 2,
              captured_name => <<"workers">>, immutable => true}
        after
            {ok, _} = tmux_session:kill(Session)
        end
    after
        ok = tmux_server:stop_owned(Ownership)
    end.
```

```erlang
-module(readme_demo).
-moduledoc "Create a workspace, query its graph and preserve captured values.".
-export([run/1]).
-import_record(tmux_model, [pane]).


-spec run(binary()) -> map().
run(Executable) ->
    {ok, Server, Ownership} =
        tmux_server:start_owned(#{executable => Executable}),
    try
        {ok, Session} = tmux_session:create(Server, #{name => <<"workspace">>,
            window_name => <<"editor">>, width => 120, height => 30,
            launch => #{argv => [<<"/bin/cat">>]}}),
        try
            {ok, Worker} = tmux_window:create(Session,
                #{name => <<"workers">>,
                  launch => #{argv => [<<"/bin/cat">>]}}),
            {ok, Right} = tmux_pane:split(Worker, #{direction => horizontal,
                launch => #{argv => [<<"/bin/cat">>]}}),
            {ok, _} = tmux_window:select_layout(Worker, even_horizontal),
            {ok, _} = tmux_pane:resize(Right, #{width => 40}),
            {ok, Snapshot} = tmux_server:snapshot(Server),
            Windows = tmux_select:windows(Snapshot),
            Workers = #{name => <<"workers">>, panes => #{count => 2,
                every => #{current_command => <<"cat">>}}},
            {ok, Captured} = tmux_select:one(Workers, Windows),
            {ok, Children} = tmux_snapshot:related(panes, Captured, Snapshot),
            Ids = [Id || #pane{id = Id} <:- Children],
            2 = length(Ids),
            Criteria = #{width => #{gte => 20},
                window => #{is => #{name => <<"workers">>}}},
            Query = tmux_query:where(Criteria, tmux_query:panes(Server)),
            {ok, Fetched} = tmux_query:fetch(Query),
            2 = tmux_select:size(Fetched),
            {ok, _} = tmux_window:rename(Worker, <<"finished">>),
            <<"workers">> = tmux_model:get(name, Captured),
            {ok, Fresh} = tmux_query:fetch(tmux_query:where(
                #{name => <<"finished">>}, tmux_query:windows(Server))),
            {ok, Renamed} = tmux_select:one(Fresh),
            <<"finished">> = tmux_model:get(name, Renamed),
            1 = length(tmux_snapshot:sessions(Snapshot)),
            2 = length(tmux_snapshot:windows(Snapshot)),
            3 = length(tmux_snapshot:panes(Snapshot)),
            #{sessions => 1, windows => 2, panes => 3, matched_panes => 2,
              captured_name => <<"workers">>, immutable => true}
        after
            {ok, _} = tmux_session:kill(Session)
        end
    after
        ok = tmux_server:stop_owned(Ownership)
    end.
```

Example details

\+ Error handling + Cleanup

Run this example

Linux, tmux 3.3a–3.8, Erlang/OTP 29.1.2, Rebar3 3.28.0, Git, make and a C11 compiler. Save the displayed files in an empty project directory.

Save the program above as `src/readme_demo.erl` in a new directory, along with the files below.

Every version retires its owned server in try/after. Cleanup also removes the created session explicitly. The program stops its private tmux server and removes any temporary files it created when it finishes. Unmatched tagged results raise with a stack trace. The program propagates failures through try/after cleanup.

rebar.config

```erlang
{minimum_otp_vsn, "29.1.2"}.
{erl_opts, [debug_info, warnings_as_errors]}.
{deps, [
    {libtmux_erlang, {git_subdir,
        "https://github.com/libtmux/libtmux-erlang.git",
        {ref, "9a1ca749f7bf6f082c910c99f961bb586781ab0b"}, "apps/libtmux_erlang"}}
]}.
```

src/tmux_example.app.src

```erlang
{application, tmux_example, [
    {vsn, "0.1.0"},
    {applications, [kernel, stdlib, libtmux_erlang]},
    {modules, []}
]}.
```

### Setup and run

```bash
rebar3 compile
```

```bash
env \
    -u TMUX \
    -u TMUX_PANE \
    erl \
    -noshell \
    -pa _build/default/lib/tmux_example/ebin \
    -pa _build/default/lib/libtmux_erlang/apps/libtmux_erlang/ebin \
    -eval '
        {ok, _} = application:ensure_all_started(libtmux_erlang),
        Tmux = unicode:characters_to_binary(os:find_executable("tmux")),
        Stats = readme_demo:run(Tmux),
        io:format("~B session, ~B windows, ~B panes; ~B matches~n", [
            maps:get(sessions, Stats), maps:get(windows, Stats),
            maps:get(panes, Stats), maps:get(matched_panes, Stats)]),
        halt().'
```

### Expected output

```text
1 session, 2 windows, 3 panes; 2 matches
```

[Core Library documentation →](https://libtmux.org/en/erlang/latest/core/)[More Erlang examples →](https://libtmux.org/en/erlang/latest/examples/)

### Install `libtmux_erlang`

**rebar.config**

```erlang
{deps, [
    {libtmux_erlang, {git_subdir,
        "https://github.com/libtmux/libtmux-erlang.git",
        {ref, "d1b6308440cf9eb8f6647e7ae434bce60e849368"}, "apps/libtmux_erlang"}}
]}.
```

```console
rebar3 compile
```

Merge this deps entry into rebar.config. Requires Erlang/OTP 29.1.2, Rebar3 3.28.0, Linux, tmux 3.3a–3.8, make and a C11 compiler. Commit rebar.lock to retain the resolved Git revision. The application is unreleased; no Hex package is advertised.

### [Topics](https://libtmux.org/en/erlang/latest/topics/)

[Subject-by-subject, with Erlang in every code block.](https://libtmux.org/en/erlang/latest/topics/)

### [Guides](https://libtmux.org/en/erlang/latest/guides/)

[Task guides for Erlang.](https://libtmux.org/en/erlang/latest/guides/)

### [Examples](https://libtmux.org/en/erlang/latest/examples/)

[Complete programs, sourced from the code each port tests.](https://libtmux.org/en/erlang/latest/examples/)

### [Concepts](https://libtmux.org/en/erlang/latest/concepts/)

[The domain model every port shares.](https://libtmux.org/en/erlang/latest/concepts/)

## API references

### [Official reference](https://libtmux.org/en/erlang/latest/reference/)

[Erlang API signatures and documentation, with links to related guides and APIs in other languages.](https://libtmux.org/en/erlang/latest/reference/)

[All Erlang versions and install instructions](https://libtmux.org/en/erlang/)
