Skip to content

feat(shell): add fish-style Ctrl-L to clear screen preserving scrollback#1212

Open
jetjinser wants to merge 4 commits intoMoonshotAI:mainfrom
jetjinser:jinser/ctrl-l-scroll-up
Open

feat(shell): add fish-style Ctrl-L to clear screen preserving scrollback#1212
jetjinser wants to merge 4 commits intoMoonshotAI:mainfrom
jetjinser:jinser/ctrl-l-scroll-up

Conversation

@jetjinser
Copy link
Contributor

@jetjinser jetjinser commented Feb 23, 2026

Related Issue

N/A (Minor feature addition matching fish shell behavior)

Description

Pressing Ctrl+L now pushes the current prompt content into the terminal's scrollback buffer (like fish's scrollback-push)

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open with Devin

Signed-off-by: Jinser Kafka <aimer@purejs.icu>
Signed-off-by: Jinser Kafka <aimer@purejs.icu>
Signed-off-by: Jinser Kafka <aimer@purejs.icu>
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +718 to +722
height = output.get_size().rows
used_lines = window.render_info.content_height

# calculate scroll to push content to top; guard against negative
scroll = max(0, height - used_lines)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Incorrect scroll calculation under-pushes content into scrollback with multi-line input

The Ctrl+L handler computes scroll = max(0, height - used_lines) where used_lines is window.render_info.content_height — the line count of the input buffer content, not the total rendered height of the application. This means the number of newlines written decreases as the input grows, resulting in fewer rows being pushed into scrollback.

Detailed explanation and impact

content_height at prompt.py:719 returns ui_content.line_count, which is the number of lines in the text being edited in the input buffer. For a fish-style clear, the goal is to push the entire visible screen into scrollback by writing height newlines (one per terminal row).

With the current formula scroll = max(0, height - used_lines):

  • Terminal height 40, empty input (1 line): scroll = 39 — pushes 39 of 40 rows ✓ (close enough)
  • Terminal height 40, 10-line input: scroll = 30 — only pushes 30 rows, but the app renders ~12+ rows of content. The top ~10 rows of the old screen are not pushed into scrollback and are lost when renderer.clear() calls erase_screen().

The fix should be to write height newlines unconditionally (or at minimum, use the total rendered height of the application rather than just the input buffer content height):

scroll = output.get_size().rows
output.write("\n" * scroll)

Impact: With multi-line input, pressing Ctrl+L fails to preserve the top portion of the visible screen in scrollback history, contradicting the documented fish-style behavior.

Suggested change
height = output.get_size().rows
used_lines = window.render_info.content_height
# calculate scroll to push content to top; guard against negative
scroll = max(0, height - used_lines)
height = output.get_size().rows
output.write("\n" * height)
output.flush()
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is written intentionally.

Subtracting used_lines is to prevent the current prompt from scrolling up, thus preventing duplicate prompts (both the scrolled-up prompt and the refreshed prompt).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant