User:Furey/Box drawing problem
Contents
Introduction
When I watch other players on hardfought.org, and they are using curses, sometimes the boxes on screen are messed up. NetHack prints the top left corner, then one horizontal line segment character, then skips the rest of the horizontal line segment characters, then prints the upper right corner. Since most of the line segment chars are skipped, everything to the right is shifted and hard to read.
(Tryna get a screenshot here, TBD).
Other users have reported this problem with ttyrec readers.
The problem happens when Player A is playing a game, but Player B is watching it, either through dgl or a ttyrec player. Usually, Player A has a TERM
environment variable that works fine for whatever terminal emulator Player A is using. However, the raw bytestream that looks fine for Player A does not look fine for Player B. It usually works, but we have run into this issue where Player A has a TERM
that offers the ANSI repeat character capability, and Player B is using a slightly different terminal emulator that does not support this sequence.
ECMA-48 standard
https://ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf
8.3.103 REP - REPEAT
This standard defines the relevant escape sequences. I think the problem happens when Player A has a terminfo entry that supports char ESC [ digits b
, and Player B has a terminal emulator that does not support REP.
Places where we could fix this
NetHack source
In the TNNT source (based on vanilla 3.6.7), the window subsystems are in win/. The file for the curses window system makes standard curses calls, particularly initscr
to initialize the screen and box
to draw boxes around the sub-windows.
We cannot fix this by changing the call to box
to print individual line drawing chars. ncurses generates the REP sequence during normal curses optimization by noticing repeated chars, even if the application generated these chars one by one.
NetHack hack 1: hack the code around the call to initscr
to use a synthetic terminal type that has rep@
cancelled out. This is difficult because initscr
takes no parameters at all, so we have to manipulate the environment variables around it.
NetHack hack 2: after initscr(), add a line: SP->_rep_cost = 999999;
. This would dissuade ncurses runtime from using the terminfo capability for repeating characters. Need to use gdb on nethack to find out the actual name of SP, and need to finagle the headers to get the right private header file for the internal SP struct.
Advantages: we build NetHack from source already.
Disadvantages: hardfought has 21 versions of NetHack (as of this writing).
ncurses source
Internals of ncurses uses SP->_rep_cost to choose when to use repeated char capability. Just disable one block of code and rebuild ncurses from source.
Advantages: there is only one ncurses shared library per system.
Disadvantages: rebuilding system library from source is difficult and may not replicate vendor build exactly, breaking unknown things.
terminfo source
Edit all the terminal descriptions to cancel the rep
capability. Then rebuild the terminfo files. It's likely that most terminfo entries inherit rep
from a small number of base entries, so the actual editing would be small.
Advantages: easy to do.
Disadvantages: again, touching a system database.
dgl source
dgl is small, built from source (as opposed to coming as system software, which is harder to customize), and already modifies the data stream.
We could filter the data stream for the ansi sequence char ESC [ digits b
and replace it with b+1 copies of char
. Just add another state machine to the existing code.
Advantages: easy to do.
Disadvantages: works only for ansi based terminal types.
ttyrec players
Could do the hack described under dgl source.
Advantages: would work instantly on historical ttyrecs. is principled, because it makes the ttyrec player more compliant with ECMA-48.
Disadvantages: I have no idea how many ttyrec players there are.
hterm
Dunno how popular hterm is. Both NAO and hardfought offer it, though, and it's nice for playing nethack without installing any software.
I looked at some hterm source. They have an "unimplemented, TBD" for char ESC [ digits b
. Problem might be that in the context where the function handler for ESC [ digits b
gets called, the digits are available, but the previous char may not be. I would have to look harder at the hterm source.
Advantages: would fix the problem for everybody who uses hterm.
Disadvantages: may require more state than a 1-line fix (to store the previous char). Requires maintaining a local patch until if and when upstream maintainers accept it.