- Rust 96.4%
- Shell 2.8%
- Meson 0.8%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| build-aux | ||
| crates | ||
| data | ||
| docs/spec | ||
| ui | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| meson.build | ||
| meson.format | ||
| meson.options | ||
| mprocs.yaml | ||
| NOTICE | ||
| README.md | ||
Terminalko
A terminal emulator organised around sessions instead of tabs: a vertical session sidebar with folders, sessions you configure once and start automatically, per-session colour highlighting, and sessions that keep running when their window closes.
Built on VTE with GTK 4 and libadwaita.
Status
M2 landed. Sessions in a vertical sidebar with folders, accent colours, saved layout, plus a working terminal underneath: four colour palettes with day/night schemes following the desktop preference, zoom, link recognition with a context menu, per-session output search, a paste guard, and drag-and-drop of files and text.
M3 in progress. terminalko-agent works: it owns the pseudo-terminals,
speaks a framed CBOR protocol over a unix socket, passes pty descriptors with
SCM_RIGHTS, replays output buffered while nothing was attached, restarts
sessions with backoff, autostarts those configured for it, allows only one agent
per user, and exits by itself once it has no windows and no sessions. Ten
end-to-end tests drive the real binary, including a session that survives its
window disconnecting entirely.
The window uses it. Opening a session asks the agent to start it and hands the terminal the pty that comes back; closing a page detaches a persistent session and stops one that is not. Sessions marked persistent keep running when their window closes, and reattaching replays the output produced in between.
terminalkoctl looks at and steers sessions from a shell, so M3 is complete.
M4 in progress. Sessions can be local, ssh, container (podman, docker, toolbox or distrobox) or root (sudo, run0 or pkexec). The New menu is filled from the user's ssh configuration and the containers the installed runtimes know about. Misconfigured sessions fail with a reason instead of a dead terminal.
Each session has a settings dialog (Ctrl+Shift+,) showing only what its type
needs, and application preferences live behind Ctrl+,.
M5 in progress. Sessions show what they are running and whether that is root,
the window says where the shell is, sessions that ring while you are elsewhere are
marked, sessions can carry their own font and palette, closing something still
running asks first, a session that ends unwatched raises a notification, and
Ctrl+Shift+P / Ctrl+Shift+O find a session and show them all.
An rpm can be built (see below). Remaining work is tracked as issues: drag-reorder in the sidebar, export/import of the session tree, i18n, and a Flatpak manifest.
Specified and implemented, see docs/spec/: colour palettes, font and zoom,
hyperlinks, search/paste/drop, the session model, the session sidebar, the
session agent, session types, preferences.
| Keys | |
|---|---|
Ctrl+Shift+C / V / A |
copy, paste, select all |
Ctrl+Shift+F |
find in output (Ctrl+Shift+G / H for next / previous) |
Ctrl + / - / 0 |
zoom in, out, reset |
Ctrl+Shift+N / W |
new window, close window |
Ctrl+Shift+T / D |
new session, new folder |
Ctrl+Shift+Alt+T |
new session, asking for a name |
F2 |
rename the selected session |
Ctrl+Shift+, / Ctrl+, |
session settings, application preferences |
Ctrl+1…Ctrl+9 |
jump to a session by position |
Alt+Up / Alt+Down |
previous / next session |
F9 |
show or hide the sidebar |
Ctrl+Shift+P / O |
find a session, show all sessions |
F11 |
fullscreen |
Ctrl+Shift+? |
keyboard shortcuts |
Ctrl-click |
open the link under the pointer |
Build dependencies (Fedora 44)
sudo dnf install cargo rust rustfmt clippy rust-analyzer \
gtk4-devel libadwaita-devel vte291-gtk4-devel glib2-devel \
blueprint-compiler meson ninja-build \
desktop-file-utils libappstream-glib
Minimum versions, enforced by meson.build: GTK 4.20, libadwaita 1.9,
VTE 0.78, GLib 2.84, Rust 1.85 (edition 2024).
Running from a checkout
cargo run -p terminalko
No install step is needed. build.rs compiles the blueprint UI, embeds the
resource bundle, and compiles the GSettings schema into OUT_DIR; a debug build
points GSETTINGS_SCHEMA_DIR at it. A checkout build uses the application ID
me.dusansimic.terminalko.Devel, so it never activates an installed copy — but
it shares preferences with it, since the schema ID is deliberately profile
independent.
mprocs starts the app alongside lint and test processes:
mprocs
build-aux/smoke.sh runs the app on a private D-Bus session with a throwaway
settings backend and a session agent of its own, drives its actions over
org.gtk.Actions, and fails if anything warns. It needs a display, so it is
separate from ci.sh:
./build-aux/smoke.sh
Installing
meson setup build --prefix=/usr/local
meson compile -C build
meson install -C build
-Dprofile=development builds a debug binary with the .Devel application ID.
Repository layout
| Path | What it is |
|---|---|
crates/terminalko |
GUI binary — application, window, terminal widget |
crates/terminalko-config |
GSettings access and the session model, shared by every binary |
crates/terminalko-agent |
Owns the pseudo-terminals so sessions outlive windows |
crates/terminalko-proto |
The messages the two speak, and their framing |
crates/terminalko-ctl |
terminalkoctl, for looking at and steering sessions |
ui/*.blp |
Blueprint templates, compiled by build.rs |
data/ |
GSettings schema, desktop entry, AppStream metainfo, icons |
docs/spec/ |
Behaviour specs written before implementation (see CONTRIBUTING.md) |
build-aux/ |
cargo-build.sh (meson glue), ci.sh, smoke.sh |
Packaging
An rpm can be built from a distribution tarball:
meson setup build
meson dist -C build --no-tests # tarball from git HEAD
rpmdev-setuptree
cp build/meson-dist/terminalko-*.tar.xz ~/rpmbuild/SOURCES/
rpmbuild -ba build-aux/terminalko.spec
Note that meson dist archives git HEAD, so uncommitted changes are not in
the tarball, and that %build runs cargo, which fetches dependencies — fine
locally, not acceptable in an offline build such as Fedora's koji. The spec says
what to do about that.
A Flatpak manifest does not exist yet: the agent has to reach the host to spawn podman, toolbox and ssh, which is a design decision rather than a packaging detail.
Controlling sessions from a shell
terminalkoctl list # every session, and what it is doing
terminalkoctl start api # by id, name, or an unambiguous prefix
terminalkoctl stop api
terminalkoctl signal api 2 # to the session's process group
Runtime operations only: creating, renaming and deleting sessions belong to the
window, which is the only writer of the configuration. list still works with no
agent running — it says so and shows what is configured.
Configuration
There is no configuration file. Preferences and, from M2, the session tree live
in GSettings under /me/dusansimic/terminalko/, and the GUI is the only writer.
dconf dump /me/dusansimic/terminalko/ # inspect or back up
Folders and sessions are relocatable schema instances keyed by UUID, so they are scriptable too:
gsettings get me.dusansimic.terminalko sessions
gsettings get me.dusansimic.terminalko.session:/me/dusansimic/terminalko/sessions/UUID/ name
Licence
BSD-2-Clause. See LICENSE.
Terminalko links GTK, libadwaita and VTE, which are LGPL: they are linked
dynamically so that users can replace them, and no code from any GPL/LGPL
project is copied into this tree. CONTRIBUTING.md explains the rule and the
process for features other terminals also have; NOTICE records every
permissively licensed snippet that was adapted.