Multiple terminals per tab, rearrangeable by drag or keyboard
A tab is now a view holding an ordered list of panes rather than a single terminal. New panes open side by side; moving one against a top or bottom edge restacks the view, and against a side edge returns it to a row. Layout is a flat list with one orientation per view rather than a split tree. That covers a shell beside an agent without the structure a tree needs, and it can be replaced once mixed layouts actually matter. Panes live in a GtkBox and are reordered in place, so rearranging never unparents a terminal and running processes and scrollback survive the move. Dragging a pane uses its header as the handle so it never competes with the terminal's own mouse handling, and drops go through the same moveRelative path as the Ctrl+Shift+arrow shortcuts. Also fixes an ordering bug this surfaced: View.create used to add its first pane immediately, firing the title callback into a Tab that had not been initialized yet. The view is now created empty and the caller adds the pane once it has finished wiring itself up.
This commit is contained in:
@@ -77,7 +77,9 @@ just the VT core.
|
||||
|
||||
```
|
||||
main.zig AdwApplication, CSS loading
|
||||
Window.zig sidebar + GtkStack of terminals, tab management, shortcuts
|
||||
Window.zig sidebar + GtkStack of views, tab management, shortcuts
|
||||
View.zig one tab's content: an ordered list of panes + their layout
|
||||
Pane.zig a terminal plus its header, drag source, and drop target
|
||||
Terminal.zig GtkDrawingArea: Cairo/Pango renderer + input handling
|
||||
Session.zig libghostty-vt Terminal + parser, fed by the PTY
|
||||
Pty.zig openpt/fork/exec, controlling terminal setup
|
||||
@@ -85,6 +87,20 @@ key.zig GDK keyval -> libghostty-vt key mapping
|
||||
theme.zig colors libghostty-vt has no opinion about
|
||||
```
|
||||
|
||||
A tab is a **view**, and a view holds one or more terminal **panes**. New panes
|
||||
open side by side; moving a pane to a top or bottom edge restacks the view, and
|
||||
moving it to a side edge puts it back in a row.
|
||||
|
||||
**Layout is a flat list, not a split tree.** A view has one orientation shared
|
||||
by all its panes, so it can express "three side by side" or "three stacked" but
|
||||
not "two beside a stack of three". A tree would handle the general case and is
|
||||
where this goes if mixed layouts turn out to matter; it just brings a lot of
|
||||
structure that a shell-next-to-an-agent view doesn't need yet.
|
||||
|
||||
Panes are held in a `GtkBox`, which can reorder its children in place. Nothing
|
||||
is ever unparented, so rearranging a view never disturbs the running
|
||||
terminals — their scrollback and processes carry straight through the move.
|
||||
|
||||
Two design choices worth calling out:
|
||||
|
||||
**No IO thread.** The PTY is read on the GLib main loop through a unix fd
|
||||
@@ -108,20 +124,29 @@ in principle, but a terminal grid is small.
|
||||
- Block / bar / underline / hollow cursor styles
|
||||
- Scrollback via mouse wheel; typing snaps back to the prompt
|
||||
- Resize reflows the grid and notifies the child
|
||||
- Window title (OSC 0/2) becomes the tab label
|
||||
- Tabs: create, close, switch; closing the last one closes the window;
|
||||
a child exiting closes its own tab
|
||||
- Window title (OSC 0/2) becomes the pane header and tab label; the tab shows
|
||||
its pane count once a view holds more than one
|
||||
- Tabs: create, close, switch; closing the last one closes the window
|
||||
- Multiple terminals per tab, rearranged by keyboard or by dragging a pane's
|
||||
header; closing the last pane in a view closes its tab
|
||||
|
||||
### Shortcuts
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `Ctrl+Shift+T` | new tab |
|
||||
| `Ctrl+Shift+W` | close tab |
|
||||
| `Ctrl+Shift+E` | new terminal in the current tab |
|
||||
| `Ctrl+Shift+W` | close the focused terminal (closes the tab with its last one) |
|
||||
| `Ctrl+Shift+←/→/↑/↓` | move the focused terminal within its view |
|
||||
| `Ctrl+Shift+V` | paste (bracketed-paste aware, refuses unsafe pastes) |
|
||||
| `Ctrl+PageUp/PageDown` | previous / next tab |
|
||||
| `Alt+1`..`Alt+8` | jump to tab N, `Alt+9` jumps to the last |
|
||||
|
||||
Dragging a pane by its header does the same thing as the arrow shortcuts: the
|
||||
edge you drop against decides both the order and the view's orientation. The
|
||||
header is the drag handle rather than the whole pane so that dragging never
|
||||
competes with the terminal's own mouse handling.
|
||||
|
||||
## Not implemented
|
||||
|
||||
This is a proof of concept, and the following are deliberately absent:
|
||||
@@ -132,7 +157,11 @@ This is a proof of concept, and the following are deliberately absent:
|
||||
- **Ligatures and complex shaping.** Each run is drawn independently at a
|
||||
fixed grid offset, so text that needs shaping across cell boundaries won't
|
||||
look right.
|
||||
- **Kitty graphics, hyperlinks, tab reordering, split panes, config file.**
|
||||
- **Resizable splits.** Panes in a view divide the space evenly; there are no
|
||||
draggable dividers. Moving to `GtkPaned` would add them.
|
||||
- **Mixed layouts and moving panes between tabs.** See the flat-list note
|
||||
above; panes can only be rearranged within their own view.
|
||||
- **Kitty graphics, hyperlinks, tab reordering, config file.**
|
||||
- **Custom terminfo.** `TERM` is reported as `xterm-256color` rather than
|
||||
`ghostty`, since we don't install a terminfo entry.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user