Skip to content

VT emulator: LF incorrectly resets cursor column to 0 #362

Description

@Bahtya

Summary

TerminalScreen::linefeed() resets cursor.col = 0 in addition to advancing the row. Per VT100/ECMA-48 spec, LF (line feed, 0x0A) should only move the cursor down one row — it must NOT reset the column position. The column reset is the responsibility of CR (carriage return, 0x0D).

Impact

Programs that rely on LF-only cursor movement (without CR) will have incorrect cursor positioning. This affects:

  • ncurses-based TUI applications that position the cursor then use LF to move down
  • Any program that emits standalone LF characters for vertical cursor movement
  • cmd.exe/PowerShell output that uses LF without CR in certain modes

Most Unix shells pair CR+LF (\r\n), so this bug is masked for basic command output. However, TUI programs and some Windows console applications may emit standalone LF.

Affected Code

crates/kestrel-tools/src/builtins/terminal/screen.rs:854-861:

fn linefeed(&mut self) {
    self.cursor.col = 0;  // BUG: should NOT reset column
    if self.cursor.row == self.scroll_bottom {
        self.scroll_up(1);
    } else if self.cursor.row < self.active_buf().rows - 1 {
        self.cursor.row += 1;
    }
}

Expected Behavior

fn linefeed(&mut self) {
    // Do NOT reset cursor.col
    if self.cursor.row == self.scroll_bottom {
        self.scroll_up(1);
    } else if self.cursor.row < self.active_buf().rows - 1 {
        self.cursor.row += 1;
    }
}

Note

Some terminal emulators implement an "automatic newline" mode (LNM, DECSET 20) where LF does imply CR. However, this mode is rarely enabled and should be opt-in, not the default behavior. The default should be LF-only (no column reset).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions