Skip to content

Conversation

@ryoppippi
Copy link
Owner

@ryoppippi ryoppippi commented Jun 22, 2025

Summary

  • Implement alternate screen buffer for live monitoring display to eliminate screen flickering
  • Remove redundant screen clearing operations in the render loop
  • Add proper cleanup to restore terminal state on exit

Problem

The current implementation clears the entire screen on every refresh cycle, which causes visible flickering on slower terminals or when refresh rates are high. This creates a poor user experience, especially during extended monitoring sessions.

Solution

This PR introduces alternate screen buffer support (similar to how `vim` or `less` work):

  • Uses ANSI escape sequences to switch to an alternate screen buffer when monitoring starts
  • The alternate buffer handles screen updates more efficiently, reducing flicker
  • Automatically restores the original terminal content when monitoring ends

Changes

  1. TerminalManager enhancements:

    • Added `enterAlternateScreen()` method to switch to alternate buffer
    • Added `exitAlternateScreen()` method to restore original screen
    • Updated `cleanup()` to properly exit alternate screen
  2. Live monitoring improvements:

    • Enter alternate screen when starting live monitoring
    • Removed redundant `clearScreen()` call before each render
    • The alternate buffer handles clearing automatically

Test Plan

  • Tested live monitoring with `bun run start blocks --active`
  • Verified no flickering on terminal refresh
  • Confirmed terminal properly restores on exit (Ctrl+C)
  • Ensured all tests pass (`bun run test`)
  • Code formatting and linting pass (`bun run format` and ESLint)
  • TypeScript checks pass (`bun typecheck`)

Impact

This change significantly improves the user experience for live monitoring features without affecting any other functionality. The alternate screen buffer is a standard terminal feature supported by all modern terminal emulators.

Summary by CodeRabbit

  • New Features

    • Introduced support for alternate screen buffer mode in the terminal, enhancing the live display experience with reduced flicker and improved screen management.
  • Improvements

    • Terminal now automatically exits alternate screen buffer mode during cleanup, ensuring a smoother return to the original terminal state after live monitoring sessions.

- Add enterAlternateScreen() and exitAlternateScreen() methods to TerminalManager

- Use ANSI escape sequences for alternate screen buffer control

- Ensure alternate screen is exited during cleanup to restore terminal state
…ffer

- Enter alternate screen buffer when starting live monitoring

- Remove redundant clearScreen() call in render loop

- Alternate screen buffer handles clearing automatically on updates

- This significantly reduces flickering on slower terminals
@coderabbitai
Copy link

coderabbitai bot commented Jun 22, 2025

Walkthrough

The changes introduce methods to manage the terminal's alternate screen buffer in the TerminalManager class, updating cleanup logic to restore the original screen. The live monitoring command now uses the alternate screen buffer for rendering, removing manual screen clearing and relying on the new buffer management for smoother updates.

Changes

File(s) Change Summary
src/_terminal-utils.ts Added enterAlternateScreen() and exitAlternateScreen() methods to TerminalManager; updated cleanup() to exit alternate screen.
src/commands/_blocks.live.ts Updated live monitoring to use alternate screen buffer and removed explicit screen clearing.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TerminalManager
    participant Terminal

    User->>TerminalManager: start live monitoring
    TerminalManager->>Terminal: enterAlternateScreen()
    TerminalManager->>Terminal: hideCursor()
    loop live updates
        TerminalManager->>Terminal: render updates
    end
    User->>TerminalManager: stop monitoring/cleanup
    TerminalManager->>Terminal: exitAlternateScreen()
Loading

Poem

In a warren of code, the screens now swap,
Flicker fades as the rabbits hop—
Alternate buffers, a hidden delight,
Cursor concealed, the updates are bright.
When all is done and cleanup’s in sight,
The old screen returns—
Everything’s right!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d862da and 0f2ef94.

📒 Files selected for processing (2)
  • src/_terminal-utils.ts (2 hunks)
  • src/commands/_blocks.live.ts (2 hunks)
🧰 Additional context used
🪛 ESLint
src/_terminal-utils.ts

[error] 46-46: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 46-46: Unsafe member access .isTTY on an error typed value.

(ts/no-unsafe-member-access)


[error] 47-47: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 47-47: Unsafe member access .write on an error typed value.

(ts/no-unsafe-member-access)


[error] 55-55: Unexpected any value in conditional. An explicit comparison or type conversion is required.

(ts/strict-boolean-expressions)


[error] 55-55: Unsafe member access .isTTY on an error typed value.

(ts/no-unsafe-member-access)


[error] 56-56: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 56-56: Unsafe member access .write on an error typed value.

(ts/no-unsafe-member-access)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Workers Builds: ccusage-guide
🔇 Additional comments (5)
src/_terminal-utils.ts (3)

42-58: Excellent implementation of alternate screen buffer support!

The ANSI escape sequences used (\u001B[?1049h and \u001B[?1049l) are the correct standard sequences for alternate screen buffer management. The TTY checks prevent issues with non-interactive streams, and the implementation follows the same pattern as existing methods.


110-110: Good integration with cleanup process.

Adding exitAlternateScreen() to the cleanup method ensures proper terminal restoration when the application exits, preventing users from being left in the alternate screen buffer.


46-47: I’ll locate and inspect the src/_terminal-utils.ts file to confirm how stream is declared and typed:

#!/bin/bash
# Find the terminal utils file
file=$(rg --files --glob "*_terminal-utils.ts")
echo "=== File detected: $file ==="

# Show the first 200 lines (class declaration, imports, etc.)
echo; echo "=== Top of file ==="
sed -n '1,200p' "$file"

# Show how `stream` is declared on the class
echo; echo "=== `stream` field declaration ==="
rg -n "stream:" -C3 "$file"

# Check for WriteStream imports
echo; echo "=== WriteStream imports ==="
rg -n "import.*WriteStream" "$file"

# Show all uses of `this.stream` in context
echo; echo "=== `this.stream` usage sites ==="
rg -n "this.stream" -C3 "$file"
src/commands/_blocks.live.ts (2)

83-85: Perfect integration of alternate screen buffer.

The placement of enterAlternateScreen() before hideCursor() is correct, ensuring the terminal is properly set up for flicker-free updates. This will significantly improve the user experience during live monitoring sessions.


115-116: Accurate documentation of the rendering optimization.

The updated comment correctly explains that the alternate screen buffer reduces flicker, making the code self-documenting about this performance improvement.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @ryoppippi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a significant user experience issue in live monitoring by implementing an alternate screen buffer. This change eliminates visible screen flickering caused by repeated screen clearing, making extended monitoring sessions much more pleasant. It also refines the terminal management by ensuring the original terminal state is always restored upon application exit.

Highlights

  • User Experience Improvement: Introduced the use of an alternate screen buffer for live monitoring displays to significantly reduce screen flickering, providing a smoother user experience.
  • Performance Optimization: Eliminated redundant clearScreen() calls within the live monitoring render loop, as the alternate buffer handles screen updates more efficiently.
  • Robust Cleanup: Ensured proper restoration of the terminal's original state upon exiting the application by adding a call to exit the alternate screen buffer during cleanup.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jun 22, 2025

Open in StackBlitz

npm i https://pkg.pr.new/ryoppippi/ccusage@166

commit: 0f2ef94

@cloudflare-workers-and-pages
Copy link

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide 0f2ef94 Jun 22 2025, 07:25 PM

@ryoppippi ryoppippi requested a review from Copilot June 22, 2025 19:25
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an alternate screen buffer to reduce flickering in live monitoring. The changes include adding methods to enter and exit the alternate buffer in TerminalManager and using them in the live monitoring command. A potential issue with the clearScreen() call inside renderLiveDisplay has been identified, along with suggestions to use constants from the ansi-escapes library and adjust the order of calls in the cleanup function.


// Clear screen and render
terminal.clearScreen();
// Render display - alternate screen buffer reduces flicker
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The renderLiveDisplay function still calls terminal.clearScreen() which may cause flickering. Consider removing this call to fully eliminate flickering.

*/
enterAlternateScreen(): void {
if (this.stream.isTTY) {
this.stream.write('\u001B[?1049h');
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Consider using the ansiEscapes.alternateScreen constant from the already imported ansi-escapes library for consistency and readability.

Suggested change
this.stream.write('\u001B[?1049h');
this.stream.write(ansiEscapes.alternateScreen);

*/
exitAlternateScreen(): void {
if (this.stream.isTTY) {
this.stream.write('\u001B[?1049l');
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Use the ansiEscapes.mainScreen constant from the ansi-escapes library for exiting the alternate screen for consistency.

Suggested change
this.stream.write('\u001B[?1049l');
this.stream.write(ansiEscapes.mainScreen);

*/
cleanup(): void {
this.showCursor();
this.exitAlternateScreen();
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Consider calling exitAlternateScreen() before showCursor() in cleanup() to ensure the cursor is visible in the main screen.

this.exitAlternateScreen();
		this.showCursor();

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR reduces flickering in live monitoring by leveraging the terminal’s alternate screen buffer, removing redundant full-screen clears, and ensuring the original screen is restored on exit.

  • Enter alternate screen and hide cursor at start
  • Remove per-frame clearScreen() call
  • Add enterAlternateScreen/exitAlternateScreen methods and update cleanup()

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/commands/_blocks.live.ts Switch to alternate buffer, update cursor handling, remove clearScreen
src/_terminal-utils.ts Implement enterAlternateScreen/exitAlternateScreen, restore buffer in cleanup
Comments suppressed due to low confidence (1)

src/_terminal-utils.ts:45

  • Add unit tests to verify that enterAlternateScreen and exitAlternateScreen write the correct escape sequences when stream.isTTY is true, and that cleanup() restores the screen.
	enterAlternateScreen(): void {

process.on('SIGTERM', cleanup);

// Hide cursor for cleaner display
// Setup terminal for live updates
Copy link

Copilot AI Jun 22, 2025

Choose a reason for hiding this comment

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

[nitpick] Change 'Setup terminal for live updates' to 'Set up terminal for live updates' to use the correct verb form.

Suggested change
// Setup terminal for live updates
// Set up terminal for live updates

Copilot uses AI. Check for mistakes.
*/
enterAlternateScreen(): void {
if (this.stream.isTTY) {
this.stream.write('\u001B[?1049h');
Copy link

Copilot AI Jun 22, 2025

Choose a reason for hiding this comment

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

Extract the ANSI escape code '\u001B[?1049h' into a named constant (e.g., ALT_SCREEN_ON) to improve readability and avoid magic values.

Suggested change
this.stream.write('\u001B[?1049h');
this.stream.write(ALT_SCREEN_ON);

Copilot uses AI. Check for mistakes.
*/
exitAlternateScreen(): void {
if (this.stream.isTTY) {
this.stream.write('\u001B[?1049l');
Copy link

Copilot AI Jun 22, 2025

Choose a reason for hiding this comment

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

Consider extracting '\u001B[?1049l' into a constant (e.g., ALT_SCREEN_OFF) for consistency with the enter sequence.

Suggested change
this.stream.write('\u001B[?1049l');
this.stream.write(ALT_SCREEN_OFF);

Copilot uses AI. Check for mistakes.
@ryoppippi
Copy link
Owner Author

#167
167 is way better

@ryoppippi ryoppippi closed this Jun 22, 2025
@ryoppippi ryoppippi deleted the fix-screen-flickering branch September 17, 2025 23:02
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.

2 participants