9e0a98ed07
Validate(root): optional startup/test check for tree authoring faults — >1 slot child per node, empty word, duplicate sibling words, dead-end node — traversing circular slots without looping (#3). keypress subpackage: WaitForKey(ctx, cancel) cancels a context on any keystroke for watch-style streaming commands, with per-GOOS cbreak (linux TCGETS/TCSETS, BSD TIOCGETA/TIOCSETA) and a non-tty/unsupported fallback that just waits on ctx. Lifts the last OpenBSD-specific bit out of evpnc/maglevc's watch.go (#6). docs: replace PROPOSAL.md with an RFC-2119 design.md (FR/NFR for the library). Example now dogfoods Validate (a unit test) and keypress (a bounded `watch` command). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
1.1 KiB
Go
33 lines
1.1 KiB
Go
// SPDX-FileCopyrightText: (C) Copyright 2026 Pim van Pelt <pim@ipng.ch>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//go:build openbsd || freebsd || netbsd || dragonfly || darwin
|
|
|
|
package keypress
|
|
|
|
import "golang.org/x/sys/unix"
|
|
|
|
// cbreak puts the terminal into cbreak mode (no canonical input/echo) so a
|
|
// single keystroke is available, leaving output post-processing intact. The
|
|
// BSDs use the TIOCGETA/TIOCSETA termios ioctls (Linux uses TCGETS/TCSETS). It
|
|
// returns the previous termios for restore, or an error if fd is not a tty.
|
|
func cbreak(fd int) (*unix.Termios, error) {
|
|
old, err := unix.IoctlGetTermios(fd, unix.TIOCGETA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t := *old
|
|
t.Lflag &^= unix.ICANON | unix.ECHO | unix.ECHOE | unix.ECHOK | unix.ECHONL
|
|
t.Cc[unix.VMIN] = 1
|
|
t.Cc[unix.VTIME] = 0
|
|
if err := unix.IoctlSetTermios(fd, unix.TIOCSETA, &t); err != nil {
|
|
return nil, err
|
|
}
|
|
return old, nil
|
|
}
|
|
|
|
// restore reverts the terminal to the settings captured by cbreak.
|
|
func restore(fd int, old *unix.Termios) error {
|
|
return unix.IoctlSetTermios(fd, unix.TIOCSETAF, old)
|
|
}
|