Skip to content

fix terminal scrolling bug#257

Closed
AviPeltz wants to merge 4 commits intomainfrom
golden-sunset-50
Closed

fix terminal scrolling bug#257
AviPeltz wants to merge 4 commits intomainfrom
golden-sunset-50

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Dec 4, 2025

Description

Related Issues

Type of Change

  • [x ] Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • Bug Fixes
    • Fixed terminal scroll behavior to maintain bottom alignment when new content arrives while the viewport is at the bottom.
    • Ensured terminal scrolls to the latest content after initialization and after processing pending events.
    • Deferred automatic scroll after resizes so content reflows before jumping to bottom.
    • Preserved manual scroll position when users scroll away from the bottom.
    • Improved handling of partial/fragmented terminal control sequences at data boundaries so incomplete fragments are buffered and reassembled, preventing spurious or garbled output.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 4, 2025

Walkthrough

Preserve terminal bottom alignment by detecting whether the viewport is at the bottom before writes and scrolling to bottom after writes; defer scroll-to-bottom after resize/fitting; buffer incomplete escape-sequence prefixes at chunk boundaries and preserve them on flush, with updated tests for cross-chunk reassembly.

Changes

Cohort / File(s) Summary
Terminal scroll position management
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
Detects whether viewport is at bottom before writing terminal data and only scrolls-to-bottom after writes when appropriate; scrolls-to-bottom after flushing pending events and after applying initial scrollback.
Resize / fit handling
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
After fitting the xterm addon, defers xterm.scrollToBottom() via requestAnimationFrame to allow buffer reflow before scrolling.
Escape filtering and tests
apps/desktop/src/main/lib/terminal-escape-filter.ts, apps/desktop/src/main/lib/terminal-escape-filter.test.ts
Buffer trailing/incomplete escape-sequence prefixes at chunk boundaries (e.g., ESC, ESC[, ESC], ESC P), avoid emitting partial query responses, preserve standalone prefixes on flush(), and add/adjust tests for cross-chunk reassembly and flush semantics.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect Terminal.tsx for race conditions around viewport detection, pending-event flush ordering, and writes that may occur during initialization.
  • Validate requestAnimationFrame deferral in helpers.ts across resize sequences and on different platforms.
  • Review terminal-escape-filter.ts buffering logic for correctness on boundary cases (CPR/OSC/DCS reassembly), memory growth on prolonged partial streams, and correct behavior of flush().
  • Run and verify updated tests in terminal-escape-filter.test.ts for cross-chunk scenarios.

Possibly related PRs

  • filter terminal  #157 — modifies terminal escape filtering logic and tests; closely related to cross-chunk buffering and reassembly changes.
  • Fix terminal scrollback #150 — alters Terminal.tsx initial scrollback handling; related to scroll-to-bottom after applying initial scrollback.
  • fix terminal token filtering #246 — touches terminal escape handling and buffering semantics; likely overlaps with the new preservation and flush behavior.

Poem

🐇 I hopped through bytes and buffered a clue,

Saved lonely ESCs till the rest came through.
I twitched my whiskers at resizes and frames,
And nudged the cursor back where the story remains.
🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description uses the template structure but lacks substantive content—no description of changes, no related issues, no testing details, no screenshots, and no additional notes. Add a detailed description of the scrolling bug, explain the fix approach, link any related issues, describe testing performed, and provide any relevant context about the changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix terminal scrolling bug' directly matches the changes which address terminal scrolling issues through viewport detection, bottom alignment preservation, and deferred scrolling.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch golden-sunset-50

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 4, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
website Ready Ready Preview Comment Dec 4, 2025 10:22pm

@AviPeltz AviPeltz marked this pull request as ready for review December 4, 2025 21:35
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fe2672 and 8a4e740.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
**/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/components/**/*.tsx: Create one folder per component with structure: ComponentName/ComponentName.tsx + index.ts for barrel export
Co-locate tests next to the component file they test (e.g., ComponentName.test.tsx)
Co-locate dependencies (utils, hooks, constants, config, stories) next to the file using them
Use nested components/ subdirectory within a parent component only if a sub-component is used 2+ times within that parent; otherwise keep it in the parent's components/ folder
One component per file - avoid multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net, etc.) in renderer process code - browser environment only

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Call IPC methods using window.ipcRenderer.invoke() with object parameters - TypeScript will infer the exact response type automatically

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
🔇 Additional comments (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (2)

173-174: LGTM!

Scrolling to bottom after flushing pending events ensures the latest content is visible after initialization.


183-184: LGTM!

Scrolling to bottom after applying scrollback ensures the user sees the most recent terminal output.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/desktop/src/main/lib/terminal-escape-filter.ts (1)

120-142: Consider consolidating repetitive prefix checks.

The logic is correct, but the four similar if-blocks could be simplified using an array of prefixes to reduce duplication and improve maintainability.

-		// Pre-check: Buffer trailing prefix fragments at chunk boundaries
-		// These could be the start of query responses split across chunks
-		// Covers: ESC (any), ESC[ (CSI), ESC] (OSC), ESC P (DCS)
-		if (combined.endsWith(ESC)) {
-			this.buffer = ESC;
-			const toFilter = combined.slice(0, -1);
-			return toFilter.replace(COMBINED_PATTERN, "");
-		}
-		if (combined.endsWith(`${ESC}[`)) {
-			this.buffer = `${ESC}[`;
-			const toFilter = combined.slice(0, -2);
-			return toFilter.replace(COMBINED_PATTERN, "");
-		}
-		if (combined.endsWith(`${ESC}]`)) {
-			this.buffer = `${ESC}]`;
-			const toFilter = combined.slice(0, -2);
-			return toFilter.replace(COMBINED_PATTERN, "");
-		}
-		if (combined.endsWith(`${ESC}P`)) {
-			this.buffer = `${ESC}P`;
-			const toFilter = combined.slice(0, -2);
-			return toFilter.replace(COMBINED_PATTERN, "");
-		}
+		// Pre-check: Buffer trailing prefix fragments at chunk boundaries
+		// These could be the start of query responses split across chunks
+		// Covers: ESC (any), ESC[ (CSI), ESC] (OSC), ESC P (DCS)
+		const prefixFragments = [`${ESC}P`, `${ESC}[`, `${ESC}]`, ESC];
+		for (const prefix of prefixFragments) {
+			if (combined.endsWith(prefix)) {
+				this.buffer = prefix;
+				const toFilter = combined.slice(0, -prefix.length);
+				return toFilter.replace(COMBINED_PATTERN, "");
+			}
+		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a29aa9c and 69f51c7.

📒 Files selected for processing (2)
  • apps/desktop/src/main/lib/terminal-escape-filter.test.ts (3 hunks)
  • apps/desktop/src/main/lib/terminal-escape-filter.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/main/lib/terminal-escape-filter.test.ts
  • apps/desktop/src/main/lib/terminal-escape-filter.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/main/lib/terminal-escape-filter.test.ts
  • apps/desktop/src/main/lib/terminal-escape-filter.ts
apps/desktop/**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.test.{ts,tsx,js,jsx}: Tests should have one assert per test
Tests should be readable
Tests should be fast
Tests should be independent
Tests should be repeatable

Files:

  • apps/desktop/src/main/lib/terminal-escape-filter.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/main/lib/terminal-escape-filter.test.ts
  • apps/desktop/src/main/lib/terminal-escape-filter.ts
apps/desktop/src/main/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Node.js modules (fs, path, os, net, etc.) can be used in main process code only

Files:

  • apps/desktop/src/main/lib/terminal-escape-filter.test.ts
  • apps/desktop/src/main/lib/terminal-escape-filter.ts
🧠 Learnings (1)
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/*.{ts,tsx} : Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications

Applied to files:

  • apps/desktop/src/main/lib/terminal-escape-filter.ts
🧬 Code graph analysis (1)
apps/desktop/src/main/lib/terminal-escape-filter.test.ts (1)
apps/desktop/src/main/lib/terminal-escape-filter.ts (2)
  • filter (115-165)
  • TerminalEscapeFilter (108-271)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (4)
apps/desktop/src/main/lib/terminal-escape-filter.ts (1)

256-261: LGTM!

The flush logic correctly preserves standalone prefix fragments that never formed a query response. This ensures genuine ESC bytes aren't incorrectly filtered when the terminal session ends.

apps/desktop/src/main/lib/terminal-escape-filter.test.ts (3)

420-482: Comprehensive test coverage for chunk boundary buffering.

The new tests thoroughly cover all prefix fragment cases (ESC, ESC[, ESC], ESC P) and their reassembly scenarios. The test naming and comments clearly explain the expected behavior.


541-576: LGTM!

The flush behavior tests correctly verify that standalone prefix fragments (ESC, ESC[, ESC], ESC P) are preserved rather than filtered when the session ends. Each test is focused and independent.


595-606: LGTM!

The updated test correctly reflects the new buffering behavior where trailing ESC is buffered and reassembled with the next chunk. The combined output remains correct.

@AviPeltz AviPeltz closed this Dec 12, 2025
@Kitenite Kitenite deleted the golden-sunset-50 branch December 18, 2025 01:32
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