Skip to content

Prompt cursor misplaced: input text not appearing after prompt marker #221

Description

@xinhuagu

Problem

When launching AceClaw via ./dev.sh, the text input cursor does not appear immediately after the aceclaw> prompt marker. Typed text appears at a wrong position, making the console unusable.

Analysis

Likely Cause 1: SCP/RCP cursor save/restore conflicts with JLine

In renderStatusFrame() (line 1592-1596):

writer.print("\u001B[s");   // SCP — save cursor position
writer.flush();
promptStatus.update(rendered);  // JLine does its own cursor mgmt internally
writer.print("\u001B[u");   // RCP — restore cursor position
writer.flush();

JLine's Status.update() internally moves the cursor to the status area, renders lines, then repositions the cursor back to the prompt. Wrapping it with SCP/RCP (\u001B[s/\u001B[u) can corrupt the cursor position because:

  • The \u001B[s saves a stale position (before JLine moves the cursor)
  • Status.update() changes cursor position internally
  • \u001B[u] restores to the stale position, overriding JLine's correct repositioning

Likely Cause 2: Background thread updates during readLine()

renderStatusFrame() is called from the aceclaw-ui-renderer virtual thread (line 560), which runs every 100ms. The main thread is concurrently in reader.readLine(PROMPT_STR) (line 408). Even though renderStatusFrame() uses synchronized (uiRenderLock), the main readLine() doesn't participate in that lock, so JLine's internal cursor state can become inconsistent.

Likely Cause 3: ensureCursorVisible() doesn't fix position

After renderStatusFrame(), ensureCursorVisible() sends \u001B[?25h (DECTCEM — make cursor visible). This only toggles cursor visibility, not its position. If the cursor was misplaced by the status update, ensureCursorVisible() doesn't help.

Suggested Fix

  1. Remove SCP/RCP wrapping: JLine's Status.update() manages cursor position internally. The \u001B[s/\u001B[u wrapper is both unnecessary and harmful.

  2. Coordinate with JLine's threading model: Either:

    • Use JLine's Display.update() from the reader thread (triggered by a signal)
    • Or use reader.callWidget() to trigger status updates within JLine's event loop
  3. After status update, explicitly reposition cursor: If background updates must continue, send \u001B[H + row/col positioning to force the cursor back to the prompt line, rather than relying on JLine's internal state.

How to Reproduce

  1. ./dev.sh
  2. Wait for the status panel to render
  3. Start typing — cursor is not at the correct position after aceclaw>

Related

May share root cause with #219 (status panel width issues)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingquestionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions