1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
id: 15
title: windows support for terminal windows
state: closed
author:
name: k33g
email: ph.charriere@gmail.com
createdAt: 2026-08-31T04:40:00.000Z
updatedAt: 2026-09-02T03:51:59.496Z
labels:
- priority::medium
body: |
Terminal windows (#7) ship for Linux and macOS only. On Windows, `F8` opens a
message saying they are not supported yet and changes nothing else.
Everything above the pseudo-terminal is already portable. `Parser`, `Screen`,
`Encode` and `View` are pure Go with no platform assumptions, and the whole
VT/ANSI emulator is tested without a process behind it. What is missing is one
file.
## The platform surface
`internal/terminal` isolates the whole of it in three build-tagged files, each
implementing the same three functions:
func openPTY() (master, slave *os.File, err error)
func setWinsize(f *os.File, width, height int) error
func childAttributes() *syscall.SysProcAttr
| File | Platform |
| --- | --- |
| `pty_linux.go` | `TIOCSPTLCK`, `TIOCGPTN` -> `/dev/pts/N` |
| `pty_darwin.go` | `TIOCPTYGRANT`, `TIOCPTYUNLK`, `TIOCPTYGNAME` |
| `pty_other.go` | returns `ErrUnsupported` |
Windows means adding `pty_windows.go` and narrowing `pty_other.go`'s build tag.
No other file should need to change.
## Why it is not a fourth ioctl
Windows has no `/dev/ptmx`. The equivalent is **ConPTY**, available from
Windows 10 1809, and it does not fit the same shape:
- `CreatePseudoConsole` takes two pipe handles and returns an `HPCON`, rather
than handing back a master and a slave file.
- The child is started with `CreateProcess` and an attribute list carrying
`PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE_HANDLE` — not `os/exec`'s
`SysProcAttr{Setsid, Setctty}`. `exec.Cmd` may not be usable directly.
- Resizing is `ResizePseudoConsole(hpcon, COORD)`, not an ioctl.
- There is no controlling terminal and no `SIGWINCH`: job control has no
equivalent, and `Ctrl-C` reaches the child through the console rather than
through a process group.
So the contract above may need widening — most likely `Session` gaining a
platform-provided `resize` and `close` rather than `setWinsize` alone. Keep
the change inside `internal/terminal`; `internal/app` should not learn that
Windows exists.
## Which shell
`shellOrDefault` falls back to `/bin/sh`, which is meaningless there. Windows
needs its own default — `%COMSPEC%`, or PowerShell — decided before the port,
because it is the first thing a user notices.
## Notes
- `golang.org/x/sys/windows` carries the ConPTY bindings, and is already in
the module graph as `golang.org/x/sys`. No new dependency.
- The emulator sends `TERM=xterm-256color`; ConPTY emits VT sequences, so the
existing parser should be close to sufficient. Expect differences in how
the alternate screen and the cursor-visibility modes are used.
- This cannot be developed or tested in the current sandbox: it is Linux, and
no Windows machine is reachable from it. Whoever takes it needs Windows.
## Checklist
- [ ] decide the default shell on Windows (%COMSPEC% or PowerShell)
- [ ] add `pty_windows.go` using `CreatePseudoConsole` / `ResizePseudoConsole`
- [ ] narrow the build tag on `pty_other.go`
- [ ] widen the platform contract if `exec.Cmd` cannot carry the HPCON
- [ ] run the `internal/terminal` suite on Windows and unskip what passes
- [ ] update `docs/*/reference/terminal.md`, which currently says Windows is unsupported
tasks: []
comments: []
|