client/tf's telnet FSM had no handling for IAC GA (249) or IAC EOR (239)
anywhere. Both fell into the IAC state's `default` arm and were silently
discarded, so a prompt terminated by GA and no newline stayed in
line_buf_ until check_prompt()'s 250ms partial-line timer guessed at it.
TinyMUX's @program prompt is exactly that shape --
queue_write_LEN(d, T(">\377\371"), 3), i.e. ">" IAC GA -- so the
interactive flow where prompt responsiveness matters most was the one
paying the delay. The timer is the right safety net for servers that send
bare unterminated prompts; GA exists so a client that gets one does not
have to guess.
Both commands now set a flag that check_prompt() consumes, so the prompt
still reaches its single consumer (Terminal::set_prompt + Hook::PROMPT) by
exactly the path it did before -- just without the quarter second.
Three details worth stating:
- The flag is consumed unconditionally at the top of check_prompt(), even
when there is nothing to deliver. Left set, it would make some later
unrelated partial line fire instantly and attribute a prompt boundary to
a server that never claimed one.
- The GA path deliberately skips the last_prompt_ dedup. The timed path
needs it, because it is re-evaluated every main-loop pass while the same
partial line sits in the buffer. GA arrives once per prompt, and a
server that sends the same prompt text twice has genuinely prompted
twice.
- line_buf_ is not cleared, matching what the timed path already does, so
current_prompt() still works on a world switch.
EOR is handled alongside GA for correctness if it is ever negotiated;
today tf answers DONT to TELOPT_EOR, so servers use GA.
Measured with tf under a pty against a server that sends a prompt
terminated by IAC GA:
before: prompt displayed 251 ms after the server sent it
after: prompt displayed 0 ms after the server sent it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| src | ||
| tf-lib | ||
| CLAUDE.md | ||
| CMakeLists.txt | ||
| README.md | ||
TitanFugue
TitanFugue is the terminal MU* client shipped with TinyMUX — a modernized fork of Ken Keys' TinyFugue, the classic programmable MUD/MUSH client. It started from the TinyFugue 5.0 beta 8 "ICU" branch and was substantially extended for TinyMUX 2.14.
It keeps TinyFugue's programmability — macros, triggers, hooks, worlds, and the
tf scripting language — while adding:
- Full Unicode / UTF-8, grapheme-aware, via ICU.
- Modern networking with TLS/SSL (OpenSSL).
- 24-bit truecolor rendering.
- IPv6.
TitanFugue is one of a family of "Titan" MU* clients developed under
../ (the repo's client/ tree):
| Path | Client |
|---|---|
client/tf |
TitanFugue — terminal/ncurses client (this directory) |
client/console |
Win32 console client |
client/win32gui |
Win32 GUI client |
client/web |
Web client |
client/android |
Android ("Titan") app |
client/ios |
iOS / macOS ("Titan") app |
Lineage and license
Derived from TinyFugue 5.0b8 (ICU branch), originally by Ken Keys. Licensed under the GNU GPL v2, inherited from upstream TinyFugue.
Building
Prerequisites (Debian/Ubuntu): apt-get install libicu-dev libssl-dev
./configure # auto-detect, generate Makefiles
make all # compile
make install # compile + install (default prefix /usr/local or $HOME)
Useful configure options: --enable-ssl / --disable-ssl,
--disable-widechar (disable UTF-8/ICU), --enable-inet6 (IPv6),
--disable-termcap (hardcoded vt100). See CLAUDE.md for the full
architecture overview and developer notes.
Issue tracking
TitanFugue bugs and enhancements live in the main TinyMUX GitHub issue tracker,
titled TitanFugue: …. They were migrated there from this client's former
in-tree client/tf/ISSUES.md; the complete FIXED / FALSE-ALARM history is
preserved in git.