Terminal: draw control characters as ^X; bound GUI config values
- C0 controls and DEL were passed to ncurses, which acted on them: a carriage return moved to column 0 and the line padding then erased the text, so every line of a CRLF file drew blank, and a backspace ate the previous character. They are now drawn in caret notation (^M, ^H, ^?) and counted as two cells. C1 controls (and stray bytes 0x80-0x9F, which decode to them; U+009B is CSI) are drawn as '?'. - The width rule lives in TermWidth.h and is shared by the renderer's drawing loop, its cursor placement and the command layer's horizontal scrolling and mouse mapping, which also disagreed on NUL and invalid bytes. - GUI config: columns/rows must be 1..1000 and the font size a finite 4..200 (TOML 'size = inf' and huge values were accepted, leading to UB in float-to-int conversion and int overflow downstream). Verified in tmux: a CRLF file now shows 'first line^M' where the baseline showed a blank line. Audit findings B9 (and the CR/BS case from the follow-up review). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
+40
@@ -0,0 +1,40 @@
|
||||
// TermWidth.h - terminal cell width of a decoded character
|
||||
//
|
||||
// Shared by TerminalRenderer (drawing and cursor placement) and the command
|
||||
// layer (horizontal scrolling, mouse column mapping) so they always agree.
|
||||
// Tabs are handled by the callers, which know the current column.
|
||||
#pragma once
|
||||
|
||||
#include <cwchar>
|
||||
|
||||
namespace kte {
|
||||
// C0 controls and DEL are drawn as caret notation ("^M", "^?"): two cells.
|
||||
// ncurses would otherwise act on them (carriage return, backspace) and
|
||||
// corrupt the line.
|
||||
inline bool
|
||||
IsCaretControl(wchar_t wch)
|
||||
{
|
||||
return (wch >= 0 && wch < 0x20) || wch == 0x7f;
|
||||
}
|
||||
|
||||
|
||||
// C1 controls (U+0080..U+009F, also what a stray byte in that range decodes
|
||||
// to) are drawn as '?': sent raw, U+009B is a terminal CSI.
|
||||
inline bool
|
||||
IsC1Control(wchar_t wch)
|
||||
{
|
||||
return wch >= 0x80 && wch <= 0x9f;
|
||||
}
|
||||
|
||||
|
||||
inline int
|
||||
CellWidth(wchar_t wch)
|
||||
{
|
||||
if (IsCaretControl(wch))
|
||||
return 2;
|
||||
if (IsC1Control(wch))
|
||||
return 1;
|
||||
const int w = wcwidth(wch);
|
||||
return w < 0 ? 1 : w;
|
||||
}
|
||||
} // namespace kte
|
||||
Reference in New Issue
Block a user