• ANSI cursor tracking: clear-to-end-of-screen (CSI J) is tracked as hom

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Fri Oct 30 15:08:51 2026
    open https://gitlab.synchro.net/main/sbbs/-/work_items/1314

    `ANSI_Terminal::handle_control_sequence()` (`src/sbbs3/ansi_terminal.cpp`) treats every ED (Erase in Display, `CSI Ps J`) as if it homed the cursor:

    ```cpp
    case 'J': // Clear screen
    // TODO: ANSI does not move cursor, ANSI-BBS does.
    set_row();
    set_column();
    break;
    ```

    Only `CSI 2J` homes the cursor, and only on ANSI-BBS terminals such as SyncTERM (cterm's `cterm_handle_ed()`). `CSI J` / `CSI 0J` (erase to end of screen) and `CSI 1J` (erase to start of screen) leave it where it is. Synchronet sends `CSI J` itself, via `ANSI_Terminal::cleartoeos()`, which is reached from:

    - the Ctrl-A `J` attribute code (`con_out.cpp`)
    - the `@CLR2EOS@` @-code (`atcodes.cpp`)
    - JS `console.cleartoeos()` (`js_console.cpp`)

    After any of these, the tracked cursor position (`row`/`column`) is wrong: it says top-left while the real cursor hasn't moved. `set_row()` also zeroes the line counter (`lncntr`), so:

    - **Auto-pause comes late.** The next "[Hit a key]" prompt is postponed until a full screen of further output, so lines scroll off unseen.
    - **Cursor movement is skipped** when `console.optimize_gotoxy` is enabled (`xtrn/utopia/utopia.js` enables it). For example, `gotoxy(1,1)` right after `cleartoeos()` sends nothing, because the tracker thinks the cursor is already there.
    - Anything else that consults the tracked row/column (pause-line hotspot, `putmsg()`'s top-of-screen checks, etc.) works from a wrong position.

    ### Fix

    Only home the tracked cursor for `Ps == 2` (keeping the existing ANSI-BBS assumption there), and leave the position and line counter alone for `Ps` 0 and 1.

    ### Related cursor-tracking gaps in the same function

    Smaller, mainly relevant to raw ANSI passed through from messages and display files:

    - `CSI E` (CNL) and `CSI F` (CPL) are tracked like `CSI B`/`CSI A`, but they also move to column 1.
    - `CSI r` (DECSTBM, set scroll region) homes the cursor in cterm, but isn't tracked (`// TODO`).
    - `ESC c` (RIS) resets the tracked position in `handle_control_code()` but not the tracked attribute (`curatr`).
    - `ESC 7` / `ESC 8` (DECSC/DECRC save/restore cursor) and `ESC D` (IND, index) aren't tracked at all.

    *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.38-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Fri Oct 30 19:20:43 2026
    close https://gitlab.synchro.net/main/sbbs/-/work_items/1314
    --- SBBSecho 3.38-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)