Skip to content

Commit 3e98981

Browse files
authored
feat(tty): support DEC auto wrap mode (#18)
1 parent 4adb9a8 commit 3e98981

10 files changed

Lines changed: 142 additions & 2 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ Use `Tty` when an operation needs a real terminal handle:
3636
- terminal events: `Tty::read_event`
3737
- output commands: cursor movement/visibility, line erase, scroll margins,
3838
reverse index, alternate screen, bracketed paste mode, SGR mouse tracking,
39-
focus tracking, foreground/background colors, text attributes, and style
40-
reset
39+
focus tracking, DEC auto wrap mode, foreground/background colors, text
40+
attributes, and style reset
4141

4242
Raw file and stdio byte I/O should use `moonbitlang/async/fs` and
4343
`moonbitlang/async/stdio` directly. The root package does not wrap them as

docs/architecture.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ operations:
4343
through `Tty`
4444
- bracketed paste mode helpers through `Tty`
4545
- focus tracking mode helpers through `Tty`
46+
- DEC auto wrap mode helpers through `Tty`
4647
- terminal state operations such as `Tty::get_state`, `Tty::set_state`, and raw
4748
mode helpers through `Tty`
4849

@@ -70,6 +71,7 @@ It should:
7071
- construct screen mode sequences such as alternate-screen enter/leave
7172
- construct bracketed paste enable/disable sequences
7273
- construct focus tracking enable/disable sequences
74+
- construct DEC auto wrap enable/disable sequences
7375
- construct scrolling-margin and reverse-index sequences
7476
- construct low-level SGR sequences and fixed SGR attribute bytes
7577
- document the standard or terminal family each sequence comes from

docs/plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ This board tracks implementation direction for `moonbit-community/tty`. Use
5353
| TTY-17 | done | Windows controlling console open | `docs/plans/2026-05-26-windows-tty-open.md`, root package | `Tty::open` uses Windows console devices instead of `/dev/tty` while keeping the public API unchanged | `moon fmt`, `moon check`, `moon test .`, `moon test`, `moon info`, `moon run tests/open` |
5454
| TTY-18 | done | Windows output VT mode during raw sessions | `docs/plans/2026-05-27-windows-output-vt-mode.md`, root package | Windows raw sessions enable and restore output VT processing plus delayed wrap while keeping public API unchanged | `moon fmt`, `moon check`, `moon test .`, `moon test`, `moon info`, Windows manual examples |
5555
| TTY-19 | done | OSC dynamic color queries | `docs/plans/2026-05-27-osc-dynamic-colors.md`, `color/`, `internal/vt/`, `internal/input/`, root package | root `Tty` can query default foreground, default background, and cursor colors while preserving interleaved input | `moon fmt`, `moon test color`, `moon test internal/vt`, `moon test internal/input`, `moon test .`, `moon test`, `moon check`, `moon info`, `git diff --check` |
56+
| TTY-20 | done | DEC auto wrap mode commands | `docs/plans/2026-05-29-decawm-auto-wrap.md`, `internal/vt/`, root package | root `Tty` can enable and disable DECAWM without adding terminal state or a capability query | `moon fmt`, `moon test internal/vt`, `moon test .`, `moon check`, `moon info`, `git diff --check` |
5657
| MVP-2 | done | queued input and shell commands in agent demo | `docs/plans/2026-05-21-agent-queued-shell.md`, `examples/agent` | `Tab` queues input for delayed submission and `!cmd` runs through `moonbitlang/async/process` without background tasks writing directly to tty | `moon fmt`, `moon check examples/agent`, `moon test examples/agent`, `moon check`, `moon test`, `moon info`, `git diff --check` |
5758

5859
## Current Rules
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# DECAWM Auto Wrap Mode
2+
3+
## Goal
4+
5+
Expose DEC auto wrap mode (DECAWM, private mode 7) through the root `Tty`
6+
command surface, without adding terminal-emulator state or capability probing.
7+
8+
## Status
9+
10+
Done.
11+
12+
## Context And Decisions
13+
14+
- DECAWM is controlled with DEC private mode 7:
15+
- enable: `CSI ? 7 h`
16+
- disable: `CSI ? 7 l`
17+
- This is an output-side terminal mode switch. It does not affect the input
18+
event model.
19+
- Do not add a scoped `with_auto_wrap` helper. The package does not track the
20+
previous terminal mode state, and forcing a fixed restore value could undo a
21+
caller or terminal preference.
22+
- Unsupported terminals can ignore the mode switch; no support query is added.
23+
24+
## References Or Standards
25+
26+
- DEC private mode 7, commonly named DECAWM.
27+
28+
## Target Files
29+
30+
- `internal/vt/screen.mbt`
31+
- `internal/vt/screen_test.mbt`
32+
- `style.mbt`
33+
- `tty_wbtest.mbt`
34+
- `README.md`
35+
- `docs/architecture.md`
36+
- `docs/plan.md`
37+
- generated `.mbti` files from `moon info`
38+
39+
## Public API Changes
40+
41+
Root package additions:
42+
43+
- `Tty::enable_auto_wrap(Self) -> Unit`
44+
- `Tty::disable_auto_wrap(Self) -> Unit`
45+
46+
Internal VT package additions:
47+
48+
- `enable_auto_wrap : Bytes`
49+
- `disable_auto_wrap : Bytes`
50+
51+
No new public type, parser state, input event, platform backend, or capability
52+
query is proposed.
53+
54+
## Invariants
55+
56+
- `Tty` remains the public output-command surface.
57+
- `internal/vt` remains byte-sequence-only and does not own output streams.
58+
- The package does not remember or infer terminal auto-wrap state.
59+
- DECAWM support does not add a screen model, renderer, layout layer, or
60+
terminal-emulator state.
61+
62+
## Acceptance Criteria
63+
64+
- Internal VT helpers emit `CSI ? 7 h` and `CSI ? 7 l`.
65+
- Root command helpers write the same bytes through `Tty`.
66+
- Generated `.mbti` diffs contain only the intended API additions.
67+
68+
## Validation Commands
69+
70+
- `moon fmt` passed.
71+
- `moon test internal/vt` passed: 17 tests.
72+
- `moon test .` passed: 24 tests.
73+
- `moon check` passed.
74+
- `moon info` passed and regenerated intended `.mbti` entries.
75+
- `git diff --check` passed.
76+
77+
## Public API Audit
78+
79+
- Root `Tty` now exposes `enable_auto_wrap` and `disable_auto_wrap` for callers
80+
that need to control DECAWM directly.
81+
- Internal VT exposes `enable_auto_wrap` and `disable_auto_wrap` byte constants
82+
for root command methods.
83+
- No public parser state, platform handle, input event, wrapper type, mutable
84+
field, or terminal state model was added.
85+
- The generated `.mbti` diff was reviewed and contains only the intended root
86+
and internal VT additions.
87+
88+
## Result Notes
89+
90+
- Added fixed DECAWM byte constants and root write-through helpers.
91+
- Added internal VT sequence tests and root pipe-backed command tests.
92+
- Updated README, architecture notes, and the execution board.
93+
94+
## Open Questions
95+
96+
- None.

internal/vt/pkg.generated.mbti

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub fn cursor_prev_line(Int) -> Bytes
2020

2121
pub fn cursor_up(Int) -> Bytes
2222

23+
pub let disable_auto_wrap : Bytes
24+
2325
pub let disable_bracketed_paste : Bytes
2426

2527
pub let disable_focus_tracking : Bytes
@@ -32,6 +34,8 @@ pub let disable_mouse_motion : Bytes
3234

3335
pub let disable_sgr_mouse : Bytes
3436

37+
pub let enable_auto_wrap : Bytes
38+
3539
pub let enable_bracketed_paste : Bytes
3640

3741
pub let enable_focus_tracking : Bytes

internal/vt/screen.mbt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ pub let enable_focus_tracking : Bytes = b"\x1b[?1004h"
2222
/// Disable focus tracking, xterm private mode 1004.
2323
pub let disable_focus_tracking : Bytes = b"\x1b[?1004l"
2424

25+
///|
26+
/// Enable DEC auto wrap mode (DECAWM), DEC private mode 7.
27+
pub let enable_auto_wrap : Bytes = b"\x1b[?7h"
28+
29+
///|
30+
/// Disable DEC auto wrap mode (DECAWM), DEC private mode 7.
31+
pub let disable_auto_wrap : Bytes = b"\x1b[?7l"
32+
2533
///|
2634
/// Query kitty keyboard protocol progressive enhancement flags.
2735
pub let query_keyboard_enhancement_flags : Bytes = b"\x1b[?u"

internal/vt/screen_test.mbt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ test "focus tracking sequences" {
1616
@debug.assert_eq(@vt.disable_focus_tracking, b"\x1b[?1004l")
1717
}
1818

19+
///|
20+
test "auto wrap mode sequences" {
21+
@debug.assert_eq(@vt.enable_auto_wrap, b"\x1b[?7h")
22+
@debug.assert_eq(@vt.disable_auto_wrap, b"\x1b[?7l")
23+
}
24+
1925
///|
2026
test "terminal response query sequences" {
2127
@debug.assert_eq(@vt.query_keyboard_enhancement_flags, b"\x1b[?u")

pkg.generated.mbti

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ pub fn Tty::close(Self) -> Unit
5353
pub async fn Tty::cursor_back(Self, Int) -> Unit
5454
pub async fn Tty::cursor_forward(Self, Int) -> Unit
5555
pub async fn Tty::cursor_up(Self, Int) -> Unit
56+
pub async fn Tty::disable_auto_wrap(Self) -> Unit
5657
pub async fn Tty::disable_bracketed_paste(Self) -> Unit
5758
pub async fn Tty::disable_focus_tracking(Self) -> Unit
5859
pub async fn Tty::disable_mouse(Self) -> Unit
60+
pub async fn Tty::enable_auto_wrap(Self) -> Unit
5961
pub async fn Tty::enable_bracketed_paste(Self) -> Unit
6062
pub async fn Tty::enable_focus_tracking(Self) -> Unit
6163
pub async fn Tty::enable_mouse(Self, MouseTrackingMode) -> Unit

style.mbt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,18 @@ pub async fn Tty::disable_focus_tracking(self : Self) -> Unit {
166166
self.write(@vt.disable_focus_tracking)
167167
}
168168

169+
///|
170+
/// Enable DEC auto wrap mode (DECAWM).
171+
pub async fn Tty::enable_auto_wrap(self : Self) -> Unit {
172+
self.write(@vt.enable_auto_wrap)
173+
}
174+
175+
///|
176+
/// Disable DEC auto wrap mode (DECAWM).
177+
pub async fn Tty::disable_auto_wrap(self : Self) -> Unit {
178+
self.write(@vt.disable_auto_wrap)
179+
}
180+
169181
///|
170182
/// Run `f` with focus tracking enabled.
171183
pub async fn[T] Tty::with_focus_tracking(self : Self, f : async () -> T) -> T {

tty_wbtest.mbt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ async test "pipe tty focus tracking commands write sequences" {
114114
inspect(output, content="\u{1B}[?1004h\u{1B}[?1004l")
115115
}
116116

117+
///|
118+
async test "pipe tty auto wrap commands write sequences" {
119+
let output = with_pipe_tty(b"", tty => {
120+
tty.enable_auto_wrap()
121+
tty.disable_auto_wrap()
122+
})
123+
inspect(output, content="\u{1B}[?7h\u{1B}[?7l")
124+
}
125+
117126
///|
118127
async test "pipe tty with focus tracking restores on success" {
119128
let output = with_pipe_tty(b"", tty => {

0 commit comments

Comments
 (0)