alt+tab is grabbed by desktop WMs and alt+arrows are re-encoded or swallowed by several terminals, leaking plain arrow keys into the focused window. Primary defaults are now letter chords which every terminal delivers via ESC-prefix: alt+w (switcher), alt+h/alt+l (snap), alt+m (maximize). The alt+tab/arrow variants stay as extra bindings, and standalone/client now enable the kitty keyboard protocol (DISAMBIGUATE_ESCAPE_CODES) when the terminal supports it so even those are delivered unambiguously (Konsole 23.08+, kitty, foot, wezterm, ghostty). 34/34 integration checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
299 lines
9.5 KiB
Markdown
299 lines
9.5 KiB
Markdown
# TUI-WM
|
||
|
||
En terminal-baserad fönsterhanterare med flytande fönster, full mussuport och SSH-kompatibilitet — inspirerad av tmux men med ett modernt UX.
|
||
|
||
## Funktioner
|
||
|
||
- Flytande terminaler med fri positionering och storleksändring
|
||
- Full mussuport: vänster/höger/mitten-klick, scroll, drag, ANSI-muse-protokoll vidarebefordras till appar
|
||
- Scrollback-historik med scrollbar + copy-mode med sökning (`alt+c`)
|
||
- Fönsterväxlare i MRU-ordning (`alt+w`, även `alt+tab` där den inte fångas av skrivbordet)
|
||
- Snap till halvskärm (`alt+h`/`alt+l` eller dra mot kanten) och maximera (`alt+m`/dubbelklick på titelraden) — alt+pilar fungerar också i terminaler med kitty keyboard-protokoll
|
||
- Teman i egna TOML-filer (`themes/`) + inbyggd inställningsdialog (kugghjulet `≡` i panelen)
|
||
- Hot-reload: config.toml, panel- och temafiler laddas om live när de ändras
|
||
- Panel (topp/botten) med klickbara knappar och dynamiska status-widgets
|
||
- Dropdown-menyer med undermenyer
|
||
- Körbar kommandodialog (`ctrl+space`)
|
||
- SSH-kompatibel: daemon + display-klienter med full mus-forwarding
|
||
- Kompilerar till fristående binärer för Linux och Windows
|
||
|
||
## Teknikstack
|
||
|
||
| Komponent | Bibliotek |
|
||
|---|---|
|
||
| Terminal I/O, mus, resize | `crossterm` |
|
||
| TUI-rendering, buffersystem | `ratatui` |
|
||
| Pseudoterminal (PTY/ConPTY) | `portable-pty` |
|
||
| VT100-emulering | `vt100` |
|
||
| Konfiguration | `toml` + `serde` |
|
||
| Språk | Rust |
|
||
|
||
## Bygga projektet
|
||
|
||
### Förutsättningar
|
||
|
||
- [Rust toolchain](https://rustup.rs/) (`rustup`, `cargo`)
|
||
- För Windows-cross-kompilering från Linux: `mingw-w64`
|
||
|
||
### Bygga för Linux
|
||
|
||
```bash
|
||
cargo build --release --target x86_64-unknown-linux-gnu
|
||
```
|
||
|
||
### Bygga för Windows
|
||
|
||
```bash
|
||
cargo build --release --target x86_64-pc-windows-gnu
|
||
```
|
||
|
||
Binärerna hamnar i `target/<target>/release/`.
|
||
|
||
### Via VS Code
|
||
|
||
Använd `Terminal > Run Task` och välj:
|
||
- **Build Linux** — bygger för `x86_64-unknown-linux-gnu`
|
||
- **Build Windows** — bygger för `x86_64-pc-windows-gnu`
|
||
- **Build (native)** — bygger för det platform du sitter på
|
||
- **Run** — kör appen direkt
|
||
|
||
## Projektstruktur
|
||
|
||
```
|
||
TUI-WM/
|
||
├── src/
|
||
│ ├── main.rs — Startpunkt, event-loop
|
||
│ ├── app.rs — All logik: fönsterhantering, mus, event-routing
|
||
│ ├── config.rs — TOML-konfiguration och dess datatyper
|
||
│ ├── pty.rs — PTY-instans (startar och kommunicerar med shell/app)
|
||
│ └── render.rs — Ratatui-rendering av paneler och fönster
|
||
├── config.toml — Huvud-konfigfil (panels, keybinds)
|
||
├── panels/
|
||
│ └── topbar.toml — Panel-definition (knappar, status-widgets)
|
||
├── .vscode/
|
||
│ └── tasks.json
|
||
└── Cargo.toml
|
||
```
|
||
|
||
---
|
||
|
||
## Konfiguration
|
||
|
||
Toppnivå-nycklar i `config.toml`:
|
||
|
||
| Nyckel | Default | Beskrivning |
|
||
|---|---|---|
|
||
| `default_shell` | `$SHELL` | Skal för nya terminaler |
|
||
| `default_window_size` | `[82, 26]` | `[bredd, höjd]` för nya terminalfönster |
|
||
| `scrollback_lines` | `1000` | Historikrader per virtuell terminal |
|
||
| `show_scrollbar` | `true` | Scrollbar på terminalfönstrens högerkant |
|
||
| `background_image` | – | Bakgrundsbild via Kitty graphics |
|
||
| `terminal_bg_color` | genomskinlig | Terminalfönstrens bakgrundsfärg |
|
||
| `theme` | inbyggt | Temafil, t.ex. `"themes/dark.toml"` — se `themes/` för exempel |
|
||
| `shadow` | `true` | Skugga under/till höger om fönster |
|
||
|
||
Alla dessa (plus panel- och temafiler) **hot-reloadas** — spara filen så
|
||
uppdateras TUI-WM inom en sekund, utan omstart. Kugghjulet `≡` i panelen
|
||
öppnar den inbyggda inställningsdialogen som ändrar tema/panel/skugga/
|
||
scrollbar och sparar till config.toml.
|
||
|
||
Konfigurationen delas upp i två nivåer:
|
||
|
||
1. **`config.toml`** — huvud-konfigfil, definierar paneler och keybinds
|
||
2. **`panels/<fil>.toml`** — extern panel-fil, definierar knapparna och status-widgets för en specifik panel
|
||
|
||
---
|
||
|
||
### Paneler
|
||
|
||
En panel är en topbar eller bottombar med knappar och status-widgets.
|
||
|
||
```toml
|
||
# config.toml
|
||
[[panel]]
|
||
position = "top" # "top" | "bottom"
|
||
file = "panels/topbar.toml" # länk till extern panel-definition (valfri)
|
||
```
|
||
|
||
Eller inline utan extern fil:
|
||
|
||
```toml
|
||
[[panel]]
|
||
position = "bottom"
|
||
|
||
[[panel.item]]
|
||
label = "Terminal"
|
||
action = { type = "spawn_terminal" }
|
||
```
|
||
|
||
---
|
||
|
||
### Knappar (items)
|
||
|
||
Varje knapp i en panel kopplas till en `action`:
|
||
|
||
```toml
|
||
# panels/topbar.toml
|
||
[[item]]
|
||
label = "Terminal"
|
||
action = { type = "spawn_terminal" }
|
||
|
||
[[item]]
|
||
label = "Exit"
|
||
action = { type = "exit" }
|
||
```
|
||
|
||
#### Tillgängliga actions
|
||
|
||
| Action | Beskrivning |
|
||
|---|---|
|
||
| `{ type = "exit" }` | Avslutar TUI-WM |
|
||
| `{ type = "spawn_terminal" }` | Startar nytt terminalfönster med systemets standard-shell |
|
||
| `{ type = "spawn_terminal", shell = "/bin/bash" }` | Startar terminal med specifikt shell/program |
|
||
| `{ type = "spawn_run_dialog" }` | Öppnar körbar kommandodialog |
|
||
| `{ type = "run_program", command = "htop" }` | Kör ett program i terminalfönster |
|
||
| `{ type = "run_script", path = "/path/to/script.sh" }` | Kör ett skript i terminalfönster |
|
||
| `{ type = "submenu", item = [...] }` | Öppnar en dropdown-undermeny |
|
||
|
||
#### Dropdown-undermeny
|
||
|
||
```toml
|
||
[[item]]
|
||
label = "Apps"
|
||
action = { type = "submenu", item = [
|
||
{ label = "htop", action = { type = "run_program", command = "htop" } },
|
||
{ label = "vim", action = { type = "run_program", command = "vim" } },
|
||
] }
|
||
```
|
||
|
||
---
|
||
|
||
### Status-widgets
|
||
|
||
Status-widgets är dynamiska textblock i panelen som kör ett kommando periodiskt.
|
||
|
||
```toml
|
||
# panels/topbar.toml
|
||
[[status]]
|
||
command = "date '+%H:%M:%S'" # shell-kommando vars stdout visas
|
||
interval = 1 # uppdateringsintervall i sekunder (default: 10)
|
||
width = 10 # teckenbredd i panelen
|
||
align = "right" # "right" (default) | "left"
|
||
```
|
||
|
||
Flera status-widgets kan definieras. Höger-dockade renderas från höger kant inåt.
|
||
|
||
---
|
||
|
||
### Keybinds
|
||
|
||
Keybinds definieras i `config.toml` och kopplas till samme `action`-typ som knappar.
|
||
|
||
```toml
|
||
[[keybind]]
|
||
key = "ctrl+space"
|
||
scope = "global" # "global" | "wm" (default)
|
||
action = { type = "spawn_run_dialog" }
|
||
|
||
[[keybind]]
|
||
key = "alt+enter"
|
||
scope = "global"
|
||
action = { type = "spawn_terminal" }
|
||
|
||
[[keybind]]
|
||
key = "ctrl+q"
|
||
scope = "wm"
|
||
action = { type = "exit" }
|
||
```
|
||
|
||
#### Scope
|
||
|
||
| Scope | Beskrivning |
|
||
|---|---|
|
||
| `global` | Aktiveras alltid, även när ett terminalfönster har fokus |
|
||
| `wm` | Aktiveras bara när inget terminalfönster är fokuserat (default) |
|
||
|
||
#### Tangenter
|
||
|
||
Format: `"modifier+modifier+key"`. Tillgängliga modifiers: `ctrl`, `alt`, `shift`.
|
||
Exempelnycklar: `a`–`z`, `0`–`9`, `space`, `enter`, `esc`, `tab`, `backspace`, `delete`, `up`, `down`, `left`, `right`, `home`, `end`, `pageup`, `pagedown`, `f1`–`f12`.
|
||
|
||
---
|
||
|
||
## Mushantering
|
||
|
||
| Åtgärd | Effekt |
|
||
|---|---|
|
||
| Vänsterklick på titel-rad | Fokuserar och börjar flytta fönstret |
|
||
| Vänsterklick på `[x]` | Stänger fönstret |
|
||
| Vänsterklick på kant/hörn | Börjar storleksändra fönstret |
|
||
| Klick i innehållsyta | Fokuserar fönstret och skickar musklick till appen i terminalen |
|
||
| Scroll inuti terminal | Vidarebefordras till appen om den fångar musen; annars scrollas terminalens egen historik (`scrollback_lines`, scrollbar på högerkanten). På alternativskärm utan mus-stöd skickas pilar |
|
||
| Höger/mitten-klick i terminal | Vidarebefordras direkt till appen |
|
||
|
||
Möss-tracking fungerar automatiskt — om appen i terminalen aktiverar ANSI mus-protokoll (t.ex. vim, htop, ncurses-appar) vidarebefordras alla mus-events korrekt med rätt encoding (SGR, UTF-8 eller default X10).
|
||
|
||
---
|
||
|
||
## Startlägen
|
||
|
||
Kör `tui-wm --help` för en komplett flagg- och tangentöversikt.
|
||
|
||
TUI-WM kan startas i tre lägen:
|
||
|
||
### Standalone (standard)
|
||
|
||
```bash
|
||
tui-wm
|
||
```
|
||
|
||
Kör fönsterhanteraren i den aktuella terminalen och startar samtidigt en Unix-socket-server. Andra program kan ansluta till socketen medan TUI-WM kör.
|
||
|
||
### Daemon (`-d`)
|
||
|
||
```bash
|
||
tui-wm -d
|
||
```
|
||
|
||
Kör headless — ingen lokal terminal-rendering. State hanteras enbart via socketen. Frames renderas internt och skickas till anslutna display-klienter. Passar för att köra TUI-WM som bakgrundstjänst.
|
||
|
||
Daemonen stängs INTE av att en klient kopplar ner eller trycker `ctrl+q` — det kopplar bara ner den klienten. Stoppa daemonen med `pkill tui-wm` eller via systemd.
|
||
|
||
### Klient (`-c`)
|
||
|
||
```bash
|
||
tui-wm -c [socket-sökväg]
|
||
```
|
||
|
||
Ansluter till en befintlig TUI-WM-server (standalone eller daemon) som display-klient. Renderar mottagna frames och vidarebefordrar tangentbords-, **mus**- och resize-events — klick, drag, scroll och hover fungerar precis som lokalt, även över SSH. Om `socket-sökväg` utelämnas används standard-sökvägen. Koppla ned med **Ctrl+Shift+Q**.
|
||
|
||
#### Tester
|
||
|
||
```bash
|
||
cargo test # enhetstester (IPC-protokollet)
|
||
python3 tests/integration.py # end-to-end: daemon + frames + musforwarding
|
||
```
|
||
|
||
---
|
||
|
||
## Socket-API
|
||
|
||
Appar som körs inne i TUI-WM får miljövariablerna `TUI_WM_SOCKET` (sökväg till socketen) och `TUI_WM_WINDOW_ID` (fönstrets ID) satta automatiskt. Via socketen kan de:
|
||
|
||
- Spawna nya terminalfönster
|
||
- Visa popup-dialoger med knappar och vänta på svar
|
||
- Lista eller stänga fönster
|
||
- Ta emot renderade frames (ANSI) för att visa TUI-WM:s skärm
|
||
|
||
Se [SOCKET_API.md](SOCKET_API.md) för fullständig protokolldokumentation med JSON-exempel och kodexempel i Bash och Python.
|
||
|
||
---
|
||
|
||
## Standardtangenter
|
||
|
||
| Tangent | Funktion |
|
||
|---|---|
|
||
| `ctrl+space` | Öppna körbar kommandodialog |
|
||
| `alt+enter` | Nytt terminalfönster |
|
||
| `ctrl+q` | Avsluta (bara när inget terminalfönster fokuseras) |
|