Skip to content

Conversation

@KJ7LNW
Copy link
Contributor

@KJ7LNW KJ7LNW commented Mar 3, 2025

Overview

This is a port of cline/cline#1583 to RooCode, plus new features:

This PR has become pretty mature, please give it a try.

Summary of CodeBlock Features

  • Copy Button: Users can easily copy code snippets with a dedicated button that stays visible.
  • Word Wrap Toggle: Users can switch word wrapping on or off in code blocks.
  • Collapsible Code Blocks: Code blocks can be collapsed or expanded, with the collapse icon hidden for shorter blocks.
  • Language Display: Code blocks show a subtle, semi‑transparent label indicating the language.
  • Language Selection: The language name is a pull down to change the selected highlight language
  • Auto‑Scroll on Update: Code blocks automatically scroll to the bottom when their content changes.

Summary of Shiki Features

  • On-Demand Loading: Languages load only when needed, reducing initial wait times.
  • Singleton Highlighter: A single instance is used to optimize memory usage.
  • Language Aliasing & Fallback: Recognizes language abbreviations and defaults to plain text for unrecognized languages.
  • Refactored code block rendering to use a single component across the application, ensuring consistent styling and behavior.
  • Syntax highlight style is github-dark or github-light depending on whether the vscode theme contains the word "light" (close/reopen the Roo task if you change your VSCode theme).

Testing

Latest test build:

Here is a good test instruction:

show me a survey of sample language programs without language duplication display them directly in response to not create files. as soon as I reply, provide more examples always different without duplication. include a few invalid languages and md language tags like ```lang . one sample should be a long sample in a valid language.

How to Test

  1. Open any chat or conversation with code blocks
  2. Hover over a code block to see the copy button appear in the top-right corner
  3. Click the button to copy the code (you should see a checkmark icon briefly)
  4. Paste the code elsewhere to verify it was copied correctly

New Screenshots

  1. Feature widgets top-right corner w/ language pull down selector in case AI chose the wrong language
  2. Syntax highlight via shiki

image

image

Older Screenshots

These were taken earlier in development, before the expand/collapse and word-wrap widgets were added:

Code

Notice that the current syntax highlight Rehype (left) is not recognizing syntax like regular expression symbols or nested var = "${variables} in strings" --- but Shiki does this really well (right, this PR).

image

Shell

Shiki also provides beautiful shell markup:

image

More examples:

Current Rehype (left) - Shiki (right, this PR)
image

Get in Touch

If you have any questions or feedback, please reach out on the Roo Code Discord.

My Discord handle is KJ7LNW.


Important

Overhaul CodeBlock rendering with new features, Shiki integration for syntax highlighting, and build updates for WebAssembly support.

  • CodeBlock Features:
    • Added copy button, word wrap toggle, collapsible code blocks, language display, language selection, and auto-scroll on update in CodeBlock.tsx.
    • Refactored to use a single component for consistent styling and behavior.
  • Shiki Integration:
    • Implemented on-demand language loading and singleton highlighter in highlighter.ts.
    • Added language aliasing and fallback to plain text for unrecognized languages.
    • Syntax highlight style set to github-dark or github-light based on VSCode theme.
  • Build and Configuration:
    • Updated vite.config.ts to include a WebAssembly plugin for Shiki.
    • Excluded shiki and related dependencies from optimization in vite.config.ts.
  • Testing and Miscellaneous:
    • Added tests for CodeBlock in CodeBlock.test.tsx.
    • Updated package.json to include shiki and adjust dependencies.

This description was created by Ellipsis for 1117500926889242a2fc63f1d102b1b9cf78e864. It will automatically update as commits are pushed.

@KJ7LNW KJ7LNW requested review from cte and mrubens as code owners March 3, 2025 02:26
@changeset-bot
Copy link

changeset-bot bot commented Mar 3, 2025

🦋 Changeset detected

Latest commit: 535b37d

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. enhancement New feature or request labels Mar 3, 2025
@cte
Copy link
Collaborator

cte commented Mar 3, 2025

This is great! I did notice one small bug with the sticky-ness:
Screen Cast 2025-03-03 at 1 18 28 PM

@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 4, 2025

Thanks for the feedback, there are a couple of UI stay in the box changes for that icon that I will make when I have a few minutes to work on that

@hannesrudolph hannesrudolph moved this to To triage in Roo Code Roadmap Mar 5, 2025
@hannesrudolph hannesrudolph moved this from To triage to PR - In Progress in Roo Code Roadmap Mar 5, 2025
@hannesrudolph hannesrudolph moved this from PR - Approved to PR - Needs Approval in Roo Code Roadmap Mar 6, 2025
@mrubens mrubens moved this from PR [Unverified] to PR [Greenlit] in Roo Code Roadmap Mar 10, 2025
@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 11, 2025

I think this is ready please test.

@cte
Copy link
Collaborator

cte commented Mar 12, 2025

Sorry for the delay - will have some time to test later today.

@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 12, 2025

rebased and tested, ready to merge if you are

@cte
Copy link
Collaborator

cte commented Mar 12, 2025

Still seeing some weirdness while scrolling:
Screen Cast 2025-03-12 at 2 33 52 PM

I wonder if we should ditch the fixed position for now. What do you think?

@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 15, 2025

@cte, I think this is ready to test again

@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 18, 2025

Background

I was working on a fix for this PR related to problems with nested non-inline code blocks like this:

```
 contains tripple-ticks 
```

The best way to fix that problem was to stop double-nesting markdown when rendering code blocks, and directly pass "code" nodes from Remark (the markdown engine) into Rehype (the syntax highlight engine)---which is a better development practice anyway. Interestingly, Rehype uses Shiki under the hood, but Shiki without Rehype seems to do a much better job with syntax highlight of language features, as we can see below.

Proposal: Replace Rehype with Shiki

I propose that we drop Rehype in favor of Shiki. Syntax highlight style is github-dark or github-light depending on whether the vscode theme contains the word "light" (close/reopen the Roo task if you change your theme). This PR contains the syntax highlight change if you would like to try it out:

Code

Notice that the current syntax highlight Rehype (left) is not recognizing syntax like regular expression symbols or nested var = "${variables} in strings" --- but Shiki does this really well (right). IMHO, the color contrast is better, too:

image

Shell

Shiki also provides beautiful shell markup:

image

More examples:

Current Rehype (left) - Shiki (right)
image

@cte
Copy link
Collaborator

cte commented Mar 18, 2025

I had the same thought. I even went as far as re-implementing our CodeBlock component using Shiki:

See:

I haven't tried dropping this in as a replacement to the existing component yet though.

@KJ7LNW KJ7LNW marked this pull request as draft March 18, 2025 06:07
@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 19, 2025

Shiki seems to work great from a development F5 build, but I have spent a couple hours today trying to get it to package and it just will not go...

the code runs and shiki executes, but it is missing all of it's language definition so there is no highlight.

@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 23, 2025

This PR has become pretty mature, please give it a try.

Here is a good test instruction:

show me a survey of sample language programs without language duplication display them directly in response to not create files. as soon as I reply, provide more examples always different without duplication. include a few invalid languages and md language tags like ```lang . one sample should be a long sample in a valid language.

Summary of Features

  • Copy Button: Users can easily copy code snippets with a dedicated button that stays visible.
  • Word Wrap Toggle: Users can switch word wrapping on or off in code blocks.
  • Collapsible Code Blocks: Code blocks can be collapsed or expanded, with the collapse icon hidden for shorter blocks.
  • Language Display: Code blocks show a subtle, semi‑transparent label indicating the language.
  • Auto‑Scroll on Update: Code blocks automatically scroll to the bottom when their content changes.

Summary of Shiki Features

  • On-Demand Loading: Languages load only when needed, reducing initial wait times.
  • Singleton Highlighter: A single instance is used to optimize memory usage.
  • Language Aliasing & Fallback: Recognizes language abbreviations and defaults to plain text for unrecognized languages.

@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 23, 2025

@KJ7LNW KJ7LNW self-assigned this Mar 23, 2025
@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Mar 23, 2025

feature widgets top-right corner:

image

@KJ7LNW KJ7LNW marked this pull request as ready for review March 23, 2025 07:23
@dosubot dosubot bot removed the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 23, 2025
Eric Wheeler added 26 commits April 26, 2025 20:21
- Add word wrap toggle button with ⟼/⤸ symbols
- Initialize word wrap state with prop defaulting to true
- Style buttons consistently with same width
- Add separator between adjacent code blocks
- Show controls on hover when block is visible

Signed-off-by: Eric Wheeler <[email protected]>
- Add window shade toggle with ⌄/⌃ symbols
- Define constant collapsed height 500px
- Maintain scroll position when toggling

Signed-off-by: Eric Wheeler <[email protected]>
- Add semi-transparent wrapper with hover effect

Signed-off-by: Eric Wheeler <[email protected]>
- Add StyledPre ref for scroll control
- Use requestAnimationFrame and setTimeout for reliable content rendering
- Implement immediate scrolling behavior without animation

Signed-off-by: Eric Wheeler <[email protected]>
Moves the code block height check into its own useEffect hook that runs whenever
highlightedCode changes, ensuring the collapse button visibility is updated whenever
the rendered content changes.

Signed-off-by: Eric Wheeler <[email protected]>
Replace manual scroll position tracking with scrollIntoView for more reliable visibility when toggling code blocks. This ensures collapsed/expanded blocks remain visible in the viewport regardless of surrounding content changes.

- Remove lastScrollPosition state
- Use scrollIntoView with smooth behavior
- Simplify toggle handler code

Signed-off-by: Eric Wheeler <[email protected]>
Renamed components for better semantic clarity:
- CopyButton -> CodeBlockButton
- CopyButtonWrapper -> CodeBlockButtonWrapper
- updateCopyButtonPosition -> updateCodeBlockButtonPosition

Signed-off-by: Eric Wheeler <[email protected]>
Transform static language indicator into interactive dropdown with all Shiki languages so users can change the highlighting if the default language selected by the AI is not accurate. Current language remains bold for identification. Standardize button heights and alignment for visual consistency.

Signed-off-by: Eric Wheeler <[email protected]>
Check for officially supported languages before checking aliases and enable support for single character language identifiers.

Signed-off-by: Eric Wheeler <[email protected]>
Add mock for shiki bundledLanguages to handle ES module imports in Jest

Signed-off-by: Eric Wheeler <[email protected]>
Add minimal required CSP directives for Shiki syntax highlighting:
- wasm-unsafe-eval: Required for WebAssembly compilation
- strict-dynamic: Ensures script loading security

These CSP changes are scoped to VSCode webview context where
the code execution environment is already sandboxed.

Signed-off-by: Eric Wheeler <[email protected]>
Dynamic imports of .wasm files return a module object where the binary data is under the default export.

This change ensures the actual ArrayBuffer is passed to new WebAssembly.Module() rather than the module wrapper object, which is necessary for correct loading of WebAssembly modules per Vite/ESModule conventions.

Appeases ellipsis-dev linter/validator.

Signed-off-by: Eric Wheeler <[email protected]>
When text is parsed character by character, the detected language could be partial
or incorrect (e.g., 'type' instead of 'typescript'). This change:

- Prevents incorrect language display in button wrapper
- Exports ExtendedLanguage type for better type safety
- Uses proper state management with normalized language values
- Implements React best practices with controlled state

Signed-off-by: Eric Wheeler <[email protected]>
Test was failing because CSP structure changed with additional
directives before the nonce. Extract script-src section with regex
to verify nonce presence regardless of its position in the directive.

Signed-off-by: Eric Wheeler <[email protected]>
Add test to ensure CSP includes 'wasm-unsafe-eval' directive required
for Shiki syntax highlighting to function.

Signed-off-by: Eric Wheeler <[email protected]>
Previously, scrolling between stacked code blocks was jarring - when reaching
the bottom of one block, continued scrolling would get stuck on the outer
container instead of smoothly transitioning to the next block.

Implements physics-based smooth scrolling that naturally chains between nested
code blocks and their container. When reaching a block's boundary, scrolling
transitions to the outer container with momentum and gradual deceleration,
allowing seamless flow to the next block.

Signed-off-by: Eric Wheeler <[email protected]>
When selecting text in a code block, the button wrapper would remain visible and interfere with text selection, making it difficult to select text accurately. This fix adds mouseDown/mouseUp handlers to hide/show the wrapper during selection.
Fixes issue introduced in dc8a892fef8630cc0d2ccf9019463ce95b7d3fc0 where
language dropdown selection would immediately revert after changing.

The problem was caused by the useEffect overriding user selections when
the language prop changed. This solution uses a ref to track whether
the user has made a manual selection, preventing the effect from
overriding user choices while still keeping the component reactive
to model-streamed language updates.

Signed-off-by: Eric Wheeler <[email protected]>
Prevents the CodeBlock component from automatically scrolling to the
bottom when new content arrives if the user has manually scrolled away
from the bottom.

Uses a ref updated by a scroll listener to track the scroll state
before content updates, ensuring the user's scroll position is
respected.

Signed-off-by: Eric Wheeler <[email protected]>
The custom wheel event handler in the CodeBlock component
intercepted all wheel events, preventing the default browser
behavior for horizontal scrolling when the Shift key was held.

This change adds a check for `e.shiftKey` at the beginning
of the `handleWheel` function. If Shift is pressed, the
handler returns early, allowing the browser to handle the
horizontal scroll as expected.

Signed-off-by: Eric Wheeler <[email protected]>
Improve scrolling behavior for code blocks by:
- Adding a consistent SCROLL_SNAP_TOLERANCE constant (20px)
- Tracking outer container scroll position
- Moving scrolling logic to happen immediately after Shiki highlighting completes
- Ensuring both inner and outer containers scroll to bottom simultaneously when appropriate

This creates a more responsive and consistent scrolling experience without relying on arbitrary timeouts.

Signed-off-by: Eric Wheeler <[email protected]>
Fixes issue where language selection dropdown would display truncated language names and not properly update UI state after selection.

Signed-off-by: Eric Wheeler <[email protected]>
The forceWrap prop was being passed to CodeBlock but was not defined in CodeBlockProps interface or used in the component. Removing it resolves the type error without changing behavior.

Signed-off-by: Eric Wheeler <[email protected]>
- Update CodeAccordian.tsx to use @src/utils/getLanguageFromPath and @roo/shared/ExtensionMessage
- Update MarkdownBlock.tsx to use @src/context/ExtensionStateContext

Signed-off-by: Eric Wheeler <[email protected]>
Only apply special wheel event handling when the pre element actually has a scrollbar.
Otherwise, let the browser handle default scrolling behavior. This ensures proper
event bubbling when content is too small to need scrolling.

Signed-off-by: Eric Wheeler <[email protected]>
@KJ7LNW
Copy link
Contributor Author

KJ7LNW commented Apr 27, 2025

rebased on 3.14.3

@cte
Copy link
Collaborator

cte commented Apr 29, 2025

@KJ7LNW - I merged this change in a separate branch (#3019) since I don't have access to push to your branches (I think your fork predates when I got admin access to the Roo Code repository). I still have a little bit of cleanup to do related to the CommandExecution stuff (I kept that component for now b/c it uses Virtuoso).

Thanks so much for this PR - it's really big improvement IMO.

@cte cte closed this Apr 29, 2025
@github-project-automation github-project-automation bot moved this from PR [Greenlit] to Done in Roo Code Roadmap Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants