Skip to content

feat: add BashToolViewer, collapsible output, and expanded syntax highlighting#90

Closed
Psypeal wants to merge 1 commit intomatt1398:mainfrom
Psypeal:feat/bash-viewer-collapsible-output
Closed

feat: add BashToolViewer, collapsible output, and expanded syntax highlighting#90
Psypeal wants to merge 1 commit intomatt1398:mainfrom
Psypeal:feat/bash-viewer-collapsible-output

Conversation

@Psypeal
Copy link
Contributor

@Psypeal Psypeal commented Feb 27, 2026

Summary

  • Add BashToolViewer with syntax-highlighted command input via CodeBlockViewer
  • Add CollapsibleOutputSection (collapsed by default) for tool output sections
  • Add keyword sets for bash/zsh/fish, c, cpp, java, kotlin, swift, lua, html, yaml
  • Fix markdown/html false type-coloring on capitalized words
  • Add markdown preview toggle to ReadToolViewer, default to preview for .md files

Test plan

  • pnpm typecheck — no type errors
  • pnpm lint:fix — no lint errors
  • pnpm test — all 654 tests pass
  • pnpm build && npx electron-builder --linux deb — builds successfully
  • Manual: verify Bash tool calls show syntax-highlighted command input
  • Manual: verify tool output sections are collapsed by default
  • Manual: verify .md files default to rendered markdown preview in Read/Write viewers
  • Manual: verify other tool types (Read, Edit, Write) still render correctly

Summary by CodeRabbit

  • New Features

    • Added Bash tool rendering with syntax-highlighted command display and copy button
    • Output sections are collapsible and default to collapsed for cleaner chats
    • Markdown files (.md/.mdx) can toggle between code and preview modes
  • Improvements

    • Expanded syntax highlighting coverage (Bash, C/C++, Java, Kotlin, Swift, Lua, HTML, YAML)
    • Output styling now reflects result status and supports copyable output content

@gemini-code-assist
Copy link

Summary of Changes

Hello, 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 introduces significant enhancements to the tool viewing experience within the application. It adds dedicated support for Bash tools with syntax-highlighted commands and standardizes tool output sections to be collapsible, improving overall UI organization. Furthermore, it greatly expands the range of languages supported by the syntax highlighter and refines markdown file viewing with a new preview toggle, making tool interactions more intuitive and visually appealing.

Highlights

  • Bash Tool Viewer: Introduced a new BashToolViewer component to display Bash tool calls with syntax-highlighted command input, enhancing readability for shell commands.
  • Collapsible Output Sections: Implemented a reusable CollapsibleOutputSection component, now used for tool output sections (including Bash and Default tool viewers), which are collapsed by default to improve UI cleanliness.
  • Expanded Syntax Highlighting: Significantly expanded syntax highlighting capabilities by adding keyword sets for numerous languages including Bash/Zsh/Fish, C, C++, Java, Kotlin, Swift, Lua, HTML, and YAML.
  • Markdown Preview Toggle: Added a toggle for ReadToolViewer and WriteToolViewer to switch between code and rendered markdown preview for .md files, with markdown files defaulting to the preview mode.
  • Syntax Highlighting Fixes: Corrected an issue where markdown/HTML syntax highlighting incorrectly colored capitalized words as types.
Changelog
  • src/renderer/components/chat/items/LinkedToolItem.tsx
    • Imported hasBashContent utility and BashToolViewer component.
    • Added logic to determine useBashViewer for 'Bash' tools.
    • Updated useDefaultViewer condition to exclude 'Bash' tools.
    • Passed toolVariant prop to BaseItem for consistent styling.
    • Rendered BashToolViewer when useBashViewer is true.
  • src/renderer/components/chat/items/linkedTool/BashToolViewer.tsx
    • Added new component BashToolViewer to render Bash tool commands with syntax highlighting.
    • Integrated CodeBlockViewer for command input and CollapsibleOutputSection for tool output.
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
    • Added new reusable component CollapsibleOutputSection to wrap content in a collapsed-by-default section with a toggle.
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
    • Removed manual output section rendering.
    • Refactored to use the new CollapsibleOutputSection for displaying tool output.
  • src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx
    • Imported MarkdownViewer component.
    • Implemented state for viewMode (code/preview) for markdown files, defaulting to 'preview'.
    • Added a toggle UI to switch between code and markdown preview for .md files.
    • Conditionally rendered MarkdownViewer or CodeBlockViewer based on viewMode.
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
    • Modified the initial viewMode state to default to 'preview' for markdown files.
  • src/renderer/components/chat/items/linkedTool/index.ts
    • Exported BashToolViewer and CollapsibleOutputSection for broader use.
  • src/renderer/components/chat/viewers/syntaxHighlighter.ts
    • Expanded the KEYWORDS object with new keyword sets for bash, c, java, kotlin, swift, lua, html, and yaml.
    • Extended KEYWORDS.zsh and KEYWORDS.fish to use KEYWORDS.bash.
    • Extended KEYWORDS.cpp and KEYWORDS.hpp to include KEYWORDS.c and additional C++ specific keywords.
    • Adjusted the highlightLine function to correctly handle comment styles for zsh, fish, yaml, and lua.
    • Updated the condition for returning plain text in highlightLine to reflect new highlighting support.
  • src/renderer/utils/toolRendering/index.ts
    • Exported the new hasBashContent utility function.
  • src/renderer/utils/toolRendering/toolContentChecks.ts
    • Added a new function hasBashContent to check if a Bash tool has a command to display.
Activity
  • Type-checking completed with no errors.
  • Linting fixed with no errors.
  • All 654 tests passed successfully.
  • Build process and Electron builder for Linux debian package completed successfully.
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 by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request 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 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. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

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.

@coderabbitai coderabbitai bot added the feature request New feature or request label Feb 27, 2026
Copy link

@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 a new BashToolViewer component, a reusable CollapsibleOutputSection, and significantly expands syntax highlighting capabilities for various programming languages. The changes enhance the user experience by providing syntax-highlighted command inputs for Bash tools and collapsing tool outputs by default, improving readability. Additionally, markdown files in ReadToolViewer and WriteToolViewer now default to a preview mode with a toggle to switch to code view, which is a great usability improvement. The expanded keyword sets for syntax highlighting are a valuable addition, making the code viewer more robust.

}

export const BashToolViewer: React.FC<BashToolViewerProps> = ({ linkedTool, status }) => {
const command = linkedTool.input.command as string;

Choose a reason for hiding this comment

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

medium

Using as string here performs a type assertion without a runtime check. If linkedTool.input.command is undefined or null, this could lead to unexpected behavior or runtime errors when command is later treated as a string. Consider adding a fallback or a more robust check.

Suggested change
const command = linkedTool.input.command as string;
const command = (linkedTool.input.command as string) || '';

Comment on lines +29 to +33
const fileName = description
? description.length > 60
? description.slice(0, 57) + '...'
: description
: 'bash';

Choose a reason for hiding this comment

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

medium

The numbers 60 and 57 used for truncating the description are 'magic numbers'. It would improve readability and maintainability to define these as named constants, perhaps at the top of the file or in a shared constants file, to make their purpose clear and allow for easier modification if the truncation logic needs to change in the future.

  const MAX_DESCRIPTION_LENGTH = 60;
  const TRUNCATED_LENGTH = 57;
  const fileName = description
    ? description.length > MAX_DESCRIPTION_LENGTH
      ? description.slice(0, TRUNCATED_LENGTH) + '...'
      : description
    : 'bash';

Comment on lines +30 to +34
<button
type="button"
className="mb-1 flex items-center gap-2 text-xs"
style={{ color: 'var(--tool-item-muted)', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }}
onClick={() => setIsExpanded((prev) => !prev)}

Choose a reason for hiding this comment

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

medium

The inline styles for the button (e.g., color, background, border, padding, cursor) are static and could be moved to a CSS class. This would improve maintainability, promote consistency across components, and separate concerns between structure and styling. Consider defining these styles in a dedicated CSS module or using a utility-first CSS framework if available.

Comment on lines +42 to +50
className="max-h-96 overflow-auto rounded p-3 font-mono text-xs"
style={{
backgroundColor: 'var(--code-bg)',
border: '1px solid var(--code-border)',
color:
status === 'error'
? 'var(--tool-result-error-text)'
: 'var(--color-text-secondary)',
}}

Choose a reason for hiding this comment

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

medium

Similar to the button, the inline styles for this div (e.g., backgroundColor, border, color) are static and could be extracted into a CSS class. This practice enhances maintainability and ensures a more consistent visual language across the application.

Comment on lines +68 to +71
style={{
backgroundColor: viewMode === 'code' ? 'var(--tag-bg)' : 'transparent',
color: viewMode === 'code' ? 'var(--tag-text)' : 'var(--color-text-muted)',
border: '1px solid var(--tag-border)',

Choose a reason for hiding this comment

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

medium

The inline styles for the 'Code' button are static and could be extracted into a CSS class. This would improve maintainability and consistency with other UI elements.

Comment on lines +81 to +84
backgroundColor: viewMode === 'preview' ? 'var(--tag-bg)' : 'transparent',
color: viewMode === 'preview' ? 'var(--tag-text)' : 'var(--color-text-muted)',
border: '1px solid var(--tag-border)',
}}

Choose a reason for hiding this comment

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

medium

The inline styles for the 'Preview' button are static and could be extracted into a CSS class. This would improve maintainability and consistency with other UI elements.

@Psypeal Psypeal force-pushed the feat/bash-viewer-collapsible-output branch from 6a80a45 to 4a830f0 Compare February 27, 2026 12:24
@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

📝 Walkthrough

Walkthrough

Adds Bash tool support with a new BashToolViewer and exports; introduces a reusable CollapsibleOutputSection for collapsible tool outputs; enhances linked tool viewers with Markdown preview toggles; expands syntax highlighting keyword sets and comment handling; and exports a hasBashContent utility.

Changes

Cohort / File(s) Summary
Bash tool & viewers
src/renderer/components/chat/items/LinkedToolItem.tsx, src/renderer/components/chat/items/linkedTool/BashToolViewer.tsx, src/renderer/components/chat/items/linkedTool/index.ts
Detects Bash linked tools, adds BashToolViewer, and re-exports it from the linkedTool index. LinkedToolItem integrates the Bash viewer into existing viewer selection and passes status.
Collapsible output wrapper & default viewer integration
src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx, src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
Adds CollapsibleOutputSection component (collapsible header, StatusDot, copy support) and refactors DefaultToolViewer to render tool outputs via this collapsible wrapper.
Markdown preview toggles
src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx, src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
Adds Markdown detection (.md/.mdx) and a Code/Preview toggle; ReadToolViewer and WriteToolViewer conditionally render MarkdownViewer or CodeBlockViewer and sync view mode for Markdown files.
Syntax highlighting expansion
src/renderer/components/chat/viewers/syntaxHighlighter.ts
Extends exported KEYWORDS with bash, c, java, kotlin, swift, lua, html, yaml; adds aliases (zsh, fishbash; hppcpp) and augments cpp; updates comment recognition and early-return logic to include new languages.
Tool rendering utilities
src/renderer/utils/toolRendering/toolContentChecks.ts, src/renderer/utils/toolRendering/index.ts
Adds and exports hasBashContent(linkedTool) to detect Bash commands in linked tools; re-exports it from the toolRendering index for viewer usage.

Possibly related PRs


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

Copy link

@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: 2

🧹 Nitpick comments (5)
src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx (1)

62-88: Consider extracting a shared MarkdownToggle component.

The toggle button UI is duplicated between ReadToolViewer and WriteToolViewer. Extracting a small reusable component would reduce duplication and ensure consistent styling.

♻️ Example extraction
// MarkdownToggle.tsx
interface MarkdownToggleProps {
  viewMode: 'code' | 'preview';
  onModeChange: (mode: 'code' | 'preview') => void;
}

export const MarkdownToggle: React.FC<MarkdownToggleProps> = ({ viewMode, onModeChange }) => (
  <div className="flex items-center justify-end gap-1">
    <button
      type="button"
      onClick={() => onModeChange('code')}
      className="rounded px-2 py-1 text-xs transition-colors"
      style={{
        backgroundColor: viewMode === 'code' ? 'var(--tag-bg)' : 'transparent',
        color: viewMode === 'code' ? 'var(--tag-text)' : 'var(--color-text-muted)',
        border: '1px solid var(--tag-border)',
      }}
    >
      Code
    </button>
    <button
      type="button"
      onClick={() => onModeChange('preview')}
      className="rounded px-2 py-1 text-xs transition-colors"
      style={{
        backgroundColor: viewMode === 'preview' ? 'var(--tag-bg)' : 'transparent',
        color: viewMode === 'preview' ? 'var(--tag-text)' : 'var(--color-text-muted)',
        border: '1px solid var(--tag-border)',
      }}
    >
      Preview
    </button>
  </div>
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx` around
lines 62 - 88, The duplicated markdown view toggle UI in ReadToolViewer (and its
sibling WriteToolViewer) should be extracted into a small reusable component
(e.g., MarkdownToggle) that accepts props like viewMode: 'code' | 'preview' and
onModeChange: (mode) => void; replace the duplicated JSX in ReadToolViewer and
WriteToolViewer with <MarkdownToggle viewMode={viewMode}
onModeChange={setViewMode} /> (or equivalent) to centralize styling/behavior and
avoid duplication while preserving current props/state (viewMode and
setViewMode).
src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx (1)

23-24: Consider syncing viewMode when filePath changes.

The useState initializer only runs on mount. If linkedTool changes to a different file type after mount, viewMode won't update accordingly. If the component is always unmounted/remounted for different tools, this is fine—otherwise, consider using useEffect to reset viewMode when isMarkdownFile changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx` around
lines 23 - 24, The viewMode state in WriteToolViewer is initialized from
isMarkdownFile but never updates when filePath (or isMarkdownFile) changes; add
a useEffect in the WriteToolViewer component that watches filePath or
isMarkdownFile and calls setViewMode(isMarkdownFile ? 'preview' : 'code') to
reset the mode whenever the file type changes so viewMode stays in sync with the
current file.
src/renderer/components/chat/viewers/syntaxHighlighter.ts (1)

807-840: Minor: auto is duplicated in C++ keyword extension.

auto is already in KEYWORDS.c (line 471) and is included again in the C++ extension array (line 838). The Set constructor handles this gracefully, but you could remove it from the extension array for clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts` around lines 807 -
840, The C++ keyword extension block (KEYWORDS.cpp and KEYWORDS.hpp) redundantly
includes 'auto' which already exists in KEYWORDS.c; remove 'auto' from the array
passed into new Set([...KEYWORDS.c, ...[ ... ]]) so KEYWORDS.cpp is a clean
superset without duplicate literals while keeping KEYWORDS.hpp assigned to
KEYWORDS.cpp.
src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx (1)

30-39: Expose toggle state for assistive technologies.

Add aria-expanded on the button so screen readers can announce whether the section is open.

♿ Suggested diff
       <button
         type="button"
         className="mb-1 flex items-center gap-2 text-xs"
         style={{ color: 'var(--tool-item-muted)', background: 'none', border: 'none', padding: 0, cursor: 'pointer' }}
+        aria-expanded={isExpanded}
         onClick={() => setIsExpanded((prev) => !prev)}
       >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx`
around lines 30 - 39, The button in the CollapsibleOutputSection component
doesn't expose its toggle state to assistive tech; update the button element
(the one using setIsExpanded and isExpanded) to include an aria-expanded
attribute bound to the isExpanded boolean so screen readers can announce
open/closed state (optionally also add an aria-controls referencing the
collapsible region id if present to improve accessibility).
src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx (1)

7-14: Reorder imports to match repository convention.

Place the @renderer/... import before relative imports to align with the project import ordering rule.

♻️ Suggested diff
 import React from 'react';
+import type { LinkedToolItem } from '@renderer/types/groups';
 
 import { type ItemStatus } from '../BaseItem';
-
 import { CollapsibleOutputSection } from './CollapsibleOutputSection';
 import { renderInput, renderOutput } from './renderHelpers';
-
-import type { LinkedToolItem } from '@renderer/types/groups';

As per coding guidelines: "Organize imports in order: external packages, path aliases (@main, @renderer, @shared, @preload), then relative imports".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx` around
lines 7 - 14, Reorder the imports in DefaultToolViewer.tsx to follow the repo
convention: keep external package imports (React) first, then move the
path-alias import "import type { LinkedToolItem } from
'@renderer/types/groups';" before any relative imports, and finally list the
relative imports (ItemStatus from '../BaseItem', CollapsibleOutputSection from
'./CollapsibleOutputSection', and renderInput/renderOutput from
'./renderHelpers') so the file imports are ordered: external, `@renderer`, then
relative; update import order around the symbols LinkedToolItem, ItemStatus,
CollapsibleOutputSection, renderInput, and renderOutput.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/renderer/components/chat/items/LinkedToolItem.tsx`:
- Line 175: The LinkedToolItem component is passing variant={toolVariant} to
BaseItem but BaseItemProps doesn't declare a variant prop; either remove the
variant prop from the BaseItem usage in LinkedToolItem (remove the
variant={toolVariant} attribute) or add a variant?: <type> entry to the
BaseItemProps interface (and handle it inside the BaseItem component
rendering/styling) so BaseItem accepts toolVariant; locate the call in
LinkedToolItem.tsx (where BaseItem is rendered) and adjust accordingly, or
update the BaseItemProps/interface and the BaseItem component to consume the new
variant property.
- Line 44: Remove the unused/nonexistent StepVariant import and the erroneous
variant prop usage: delete the import "StepVariant" from LinkedToolItem.tsx and
remove the prop variant={toolVariant} from the BaseItem JSX call (BaseItem does
not accept a variant prop and toolVariant is not defined/typed), leaving
BaseItem with only its supported props.

---

Nitpick comments:
In `@src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx`:
- Around line 30-39: The button in the CollapsibleOutputSection component
doesn't expose its toggle state to assistive tech; update the button element
(the one using setIsExpanded and isExpanded) to include an aria-expanded
attribute bound to the isExpanded boolean so screen readers can announce
open/closed state (optionally also add an aria-controls referencing the
collapsible region id if present to improve accessibility).

In `@src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx`:
- Around line 7-14: Reorder the imports in DefaultToolViewer.tsx to follow the
repo convention: keep external package imports (React) first, then move the
path-alias import "import type { LinkedToolItem } from
'@renderer/types/groups';" before any relative imports, and finally list the
relative imports (ItemStatus from '../BaseItem', CollapsibleOutputSection from
'./CollapsibleOutputSection', and renderInput/renderOutput from
'./renderHelpers') so the file imports are ordered: external, `@renderer`, then
relative; update import order around the symbols LinkedToolItem, ItemStatus,
CollapsibleOutputSection, renderInput, and renderOutput.

In `@src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx`:
- Around line 62-88: The duplicated markdown view toggle UI in ReadToolViewer
(and its sibling WriteToolViewer) should be extracted into a small reusable
component (e.g., MarkdownToggle) that accepts props like viewMode: 'code' |
'preview' and onModeChange: (mode) => void; replace the duplicated JSX in
ReadToolViewer and WriteToolViewer with <MarkdownToggle viewMode={viewMode}
onModeChange={setViewMode} /> (or equivalent) to centralize styling/behavior and
avoid duplication while preserving current props/state (viewMode and
setViewMode).

In `@src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx`:
- Around line 23-24: The viewMode state in WriteToolViewer is initialized from
isMarkdownFile but never updates when filePath (or isMarkdownFile) changes; add
a useEffect in the WriteToolViewer component that watches filePath or
isMarkdownFile and calls setViewMode(isMarkdownFile ? 'preview' : 'code') to
reset the mode whenever the file type changes so viewMode stays in sync with the
current file.

In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts`:
- Around line 807-840: The C++ keyword extension block (KEYWORDS.cpp and
KEYWORDS.hpp) redundantly includes 'auto' which already exists in KEYWORDS.c;
remove 'auto' from the array passed into new Set([...KEYWORDS.c, ...[ ... ]]) so
KEYWORDS.cpp is a clean superset without duplicate literals while keeping
KEYWORDS.hpp assigned to KEYWORDS.cpp.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ac7977 and 6a80a45.

📒 Files selected for processing (10)
  • src/renderer/components/chat/items/LinkedToolItem.tsx
  • src/renderer/components/chat/items/linkedTool/BashToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/index.ts
  • src/renderer/components/chat/viewers/syntaxHighlighter.ts
  • src/renderer/utils/toolRendering/index.ts
  • src/renderer/utils/toolRendering/toolContentChecks.ts

WriteToolViewer,
} from './linkedTool';

import type { StepVariant } from '@renderer/constants/stepVariants';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for StepVariant definition and exports
echo "=== Searching for StepVariant definitions ==="
rg -n "export.*StepVariant" --type=ts --type=tsx

echo -e "\n=== Searching for stepVariants module ==="
fd -e ts -e tsx stepVariants

echo -e "\n=== Checking if stepVariants directory exists ==="
fd -d stepVariants

Repository: matt1398/claude-devtools

Length of output: 380


🏁 Script executed:

#!/bin/bash
# Search for StepVariant type anywhere in the codebase
echo "=== Searching for any StepVariant references ==="
rg "StepVariant" --type=ts

echo -e "\n=== Checking LinkedToolItem.tsx file ==="
fd "LinkedToolItem.tsx" -x cat {}

echo -e "\n=== Searching for variant prop type in BaseItem ==="
rg -B5 -A10 "interface BaseItemProps|type BaseItemProps" --type=ts

echo -e "\n=== Checking if constants/stepVariants exists ==="
fd "stepVariants" --type=f

Repository: matt1398/claude-devtools

Length of output: 9608


🏁 Script executed:

#!/bin/bash
# Get the full BaseItemProps interface
echo "=== Full BaseItemProps interface ==="
sed -n '/^interface BaseItemProps/,/^}/p' src/renderer/components/chat/items/BaseItem.tsx

echo -e "\n=== Search for variant in BaseItem ==="
rg "variant" src/renderer/components/chat/items/BaseItem.tsx -B2 -A2

echo -e "\n=== Check if constants directory exists ==="
ls -la src/renderer/constants/

echo -e "\n=== Search for StepVariant definition anywhere ==="
rg "type StepVariant|interface StepVariant" --type=ts

echo -e "\n=== Check what's in linkedTool directory ==="
ls -la src/renderer/components/chat/items/linkedTool/
</parameter>

Repository: matt1398/claude-devtools

Length of output: 2571


Remove unused variant prop and non-existent import from LinkedToolItem.

BaseItem component does not accept a variant prop. The import on line 44 references a non-existent module @renderer/constants/stepVariants (which is not defined anywhere in the codebase), and the toolVariant variable passed to BaseItem on line 175 will cause a type error.

Delete the import statement on line 44 and remove variant={toolVariant} from the BaseItem component call.

🧰 Tools
🪛 GitHub Check: validate

[failure] 44-44:
Cannot find module '@renderer/constants/stepVariants' or its corresponding type declarations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/items/LinkedToolItem.tsx` at line 44, Remove the
unused/nonexistent StepVariant import and the erroneous variant prop usage:
delete the import "StepVariant" from LinkedToolItem.tsx and remove the prop
variant={toolVariant} from the BaseItem JSX call (BaseItem does not accept a
variant prop and toolVariant is not defined/typed), leaving BaseItem with only
its supported props.

highlightClasses={highlightClasses}
highlightStyle={highlightStyle}
notificationDotColor={notificationDotColor}
variant={toolVariant}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find BaseItem component and its props definition
rg -n "BaseItemProps|interface BaseItemProps" --type=ts --type=tsx -A 10

Repository: matt1398/claude-devtools

Length of output: 95


🏁 Script executed:

# Check the LinkedToolItem.tsx file context around line 175
fd -e tsx -e ts | xargs rg -l "LinkedToolItem" | head -5

Repository: matt1398/claude-devtools

Length of output: 286


🏁 Script executed:

# Find BaseItem component file
fd -e tsx -e ts -name "*BaseItem*"

Repository: matt1398/claude-devtools

Length of output: 298


🏁 Script executed:

# Search for BaseItemProps definition
rg "interface BaseItemProps|BaseItemProps" -t ts -A 10

Repository: matt1398/claude-devtools

Length of output: 1679


🏁 Script executed:

# Find BaseItem component file more carefully
fd "BaseItem" -e tsx -e ts

Repository: matt1398/claude-devtools

Length of output: 115


🏁 Script executed:

# Check LinkedToolItem.tsx directly
cat src/renderer/components/chat/items/LinkedToolItem.tsx

Repository: matt1398/claude-devtools

Length of output: 7877


🏁 Script executed:

# Get the full BaseItem.tsx file
cat src/renderer/components/chat/items/BaseItem.tsx

Repository: matt1398/claude-devtools

Length of output: 6054


Remove variant prop from BaseItem call or add it to BaseItemProps.

The variant={toolVariant} prop being passed at line 175 is not accepted by BaseItemProps. The BaseItem component does not include a variant property in its interface definition. Either remove this prop from the call or update BaseItemProps to include it if the variant styling is needed.

🧰 Tools
🪛 GitHub Check: validate

[failure] 175-175:
Type '{ children: (false | Element | undefined)[]; icon: Element; label: string; summary: string; tokenCount: number; status: ItemStatus; durationMs: number | undefined; ... 5 more ...; variant: StepVariant; }' is not assignable to type 'IntrinsicAttributes & BaseItemProps'.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/items/LinkedToolItem.tsx` at line 175, The
LinkedToolItem component is passing variant={toolVariant} to BaseItem but
BaseItemProps doesn't declare a variant prop; either remove the variant prop
from the BaseItem usage in LinkedToolItem (remove the variant={toolVariant}
attribute) or add a variant?: <type> entry to the BaseItemProps interface (and
handle it inside the BaseItem component rendering/styling) so BaseItem accepts
toolVariant; locate the call in LinkedToolItem.tsx (where BaseItem is rendered)
and adjust accordingly, or update the BaseItemProps/interface and the BaseItem
component to consume the new variant property.

Copy link

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/components/chat/viewers/syntaxHighlighter.ts (1)

924-942: ⚠️ Potential issue | 🟠 Major

Guard // comments by language to prevent false positives in shell/URL lines.

The // comment check at line ~913 currently applies to all languages without guards. This causes URLs like curl https://example.com in bash to be incorrectly highlighted as comments, truncating output before the properly language-gated # and -- checks can run. The issue is critical because the unguarded // check executes first and breaks out of the loop, preventing language-specific comment detection from working correctly.

Recommended fix
+const SLASH_COMMENT_LANGUAGES = new Set([
+  'typescript', 'tsx', 'javascript', 'jsx',
+  'java', 'kotlin', 'swift', 'c', 'cpp', 'hpp', 'go', 'rust', 'php'
+]);
+
 // Check for comment (// style)
-    if (remaining.startsWith('//')) {
+    if (SLASH_COMMENT_LANGUAGES.has(language) && remaining.startsWith('//')) {
       segments.push(
         React.createElement(
           'span',
           { key: currentPos, style: { color: 'var(--syntax-comment)', fontStyle: 'italic' } },
           remaining
         )
       );
       break;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts` around lines 924 -
942, The unguarded // comment branch is matching URLs in shell/URL lines; update
the // comment check (the branch that tests remaining.startsWith('//') and
pushes into segments) to only run for languages that actually use // comments
(e.g., javascript/typescript, java, c, cpp, csharp, go, rust, swift, kotlin) by
adding a language whitelist check (e.g., (language === 'javascript' || language
=== 'typescript' || ... ) && remaining.startsWith('//')), and ensure this
guarded check remains after or does not preempt the existing '#' and '--' checks
so shell (bash/zsh/fish/ruby/php/yaml) and sql/lua comment detection still runs
first.
🧹 Nitpick comments (1)
src/renderer/components/chat/viewers/syntaxHighlighter.ts (1)

850-851: Optional cleanup: remove redundant bash from the no-keyword bypass list.

Since KEYWORDS.bash is now defined, this exception is effectively dead and may confuse future edits.

♻️ Suggested simplification
-  if (keywords.size === 0 && !['json', 'css', 'bash'].includes(language)) {
+  if (keywords.size === 0 && !['json', 'css'].includes(language)) {
     return [line];
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts` around lines 850 -
851, The conditional in syntaxHighlighter.ts that bypasses highlighting when
keywords.size === 0 currently includes a redundant 'bash' check; since
KEYWORDS.bash is now defined, remove 'bash' from the array (i.e., change the
array passed to includes so it no longer lists 'bash') and keep the rest of the
logic intact; update any related comments and run unit/visual checks for the
highlight function that uses the keywords and language variables to ensure bash
now falls through to normal highlighting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx`:
- Around line 64-88: Add accessible state to the toggle buttons by adding an
aria-pressed attribute that reflects the current viewMode; update the Code
button (uses setViewMode and viewMode) to include aria-pressed={viewMode ===
'code'} and the Preview button to include aria-pressed={viewMode === 'preview'}
so screen readers can announce which mode is active.
- Line 58: The viewMode state in ReadToolViewer is initialized once and can
become out-of-sync when isMarkdownFile (or filePath) changes; add an effect in
the ReadToolViewer component that watches isMarkdownFile (and/or filePath) and
calls setViewMode(isMarkdownFile ? 'preview' : 'code') so the UI toggles to the
correct default when the detected file type changes, referencing the viewMode
and setViewMode state pair and the isMarkdownFile detection.

In `@src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx`:
- Line 24: The component WriteToolViewer initializes viewMode from
isMarkdownFile only once, so when isMarkdownFile (derived from filePath) changes
while the component is reused, viewMode can be stale; add an effect in
WriteToolViewer that watches isMarkdownFile and calls setViewMode(isMarkdownFile
? 'preview' : 'code') to reset the mode whenever isMarkdownFile changes (keeping
the existing state when unchanged).

In `@src/renderer/utils/toolRendering/toolContentChecks.ts`:
- Around line 63-65: The current hasBashContent(linkedTool: LinkedToolItem)
check is too permissive; update it to ensure linkedTool.input?.command is a
string and not empty/whitespace-only by verifying typeof
linkedTool.input.command === 'string' and linkedTool.input.command.trim().length
> 0 before returning true; keep the function name hasBashContent and the
LinkedToolItem references to locate and replace the existing boolean coercion.

---

Outside diff comments:
In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts`:
- Around line 924-942: The unguarded // comment branch is matching URLs in
shell/URL lines; update the // comment check (the branch that tests
remaining.startsWith('//') and pushes into segments) to only run for languages
that actually use // comments (e.g., javascript/typescript, java, c, cpp,
csharp, go, rust, swift, kotlin) by adding a language whitelist check (e.g.,
(language === 'javascript' || language === 'typescript' || ... ) &&
remaining.startsWith('//')), and ensure this guarded check remains after or does
not preempt the existing '#' and '--' checks so shell
(bash/zsh/fish/ruby/php/yaml) and sql/lua comment detection still runs first.

---

Nitpick comments:
In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts`:
- Around line 850-851: The conditional in syntaxHighlighter.ts that bypasses
highlighting when keywords.size === 0 currently includes a redundant 'bash'
check; since KEYWORDS.bash is now defined, remove 'bash' from the array (i.e.,
change the array passed to includes so it no longer lists 'bash') and keep the
rest of the logic intact; update any related comments and run unit/visual checks
for the highlight function that uses the keywords and language variables to
ensure bash now falls through to normal highlighting.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6a80a45 and 4a830f0.

📒 Files selected for processing (10)
  • src/renderer/components/chat/items/LinkedToolItem.tsx
  • src/renderer/components/chat/items/linkedTool/BashToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/index.ts
  • src/renderer/components/chat/viewers/syntaxHighlighter.ts
  • src/renderer/utils/toolRendering/index.ts
  • src/renderer/utils/toolRendering/toolContentChecks.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/renderer/utils/toolRendering/index.ts
  • src/renderer/components/chat/items/LinkedToolItem.tsx
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx

@cesarafonseca
Copy link
Contributor

Hey @Psypeal, thank you for the contribution.

The markdown preview is a valuable addition and clearly improves the readability of the output, good improvement there.

However, the syntax-highlighted command for Bash tool inputs seems to introduce more noise than benefit. The Bash tool already expects a bash instruction as input, so wrapping it with a CodeBlockViewer makes the information redundant rather than clearer (as shown in the screenshot).

IMO, a more practical improvement would be to add a copy button to both the Bash input and its output. That would make it easier to reuse commands in other tools or run them directly in a terminal, providing tangible usability gains without increasing visual complexity.

image

@Psypeal
Copy link
Contributor Author

Psypeal commented Feb 27, 2026

Hey @Psypeal, thank you for the contribution.

The markdown preview is a valuable addition and clearly improves the readability of the output, good improvement there.

However, the syntax-highlighted command for Bash tool inputs seems to introduce more noise than benefit. The Bash tool already expects a bash instruction as input, so wrapping it with a CodeBlockViewer makes the information redundant rather than clearer (as shown in the screenshot).

IMO, a more practical improvement would be to add a copy button to both the Bash input and its output. That would make it easier to reuse commands in other tools or run them directly in a terminal, providing tangible usability gains without increasing visual complexity.
image

that's good insight @cesarafonseca I am trying to find a better way to make the current bash command and output visualization better. I will improve it later.

…hlighting

- Add BashToolViewer with syntax-highlighted command input via CodeBlockViewer
- Add CollapsibleOutputSection (collapsed by default) for tool output
- Apply collapsible output to DefaultToolViewer and BashToolViewer
- Add bash/zsh/fish keyword sets for syntax highlighting
- Add keyword sets for c, cpp, java, kotlin, swift, lua, html, yaml
- Fix markdown/html false type-coloring on capitalized words
- Add markdown preview toggle to ReadToolViewer (defaults to preview)
- Default WriteToolViewer to preview mode for markdown files
- Extend comment detection for zsh, fish, yaml (#) and lua (--)
@Psypeal Psypeal force-pushed the feat/bash-viewer-collapsible-output branch from 4a830f0 to a6035d4 Compare February 28, 2026 03:25
Copy link

@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

🧹 Nitpick comments (1)
src/renderer/components/chat/viewers/syntaxHighlighter.ts (1)

405-469: Bash keyword set includes shell utilities — verify this is intentional.

The bash keyword set includes common shell utilities (ls, cat, grep, sed, awk, find, git, docker, curl, etc.) alongside actual bash keywords. While practical for command highlighting, this may over-highlight common words that appear in other contexts (e.g., variable names, comments).

If this is intentional for the Bash tool viewer use case, LGTM. Otherwise, consider separating true keywords from common commands.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts` around lines 405 -
469, The bash keyword Set (the "bash" entry created with new Set([...])) mixes
core shell keywords with common utilities/commands which can over-highlight;
split this into two named Sets (e.g., bashKeywords and bashCommands) and update
the highlighting logic (where the "bash" set is used — search for the "bash" key
and any highlightToken/highlightWord functions in syntaxHighlighter.ts) to only
treat bashKeywords as language keywords by default and use bashCommands
optionally (or only in command-context tokens) to avoid matching commands inside
variables/comments; ensure callers that need the broader command list opt into
using bashCommands.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts`:
- Around line 727-787: The type-coloring logic in highlightLine erroneously
colors capitalized words in HTML content because 'html' is not included in the
early-return bypass; update the early-return condition (the bypass list checked
at the start of highlightLine) to include 'html' or add a language-specific
guard so when language === 'html' the type-coloring block (the capitalized-word
check `(word[0]?.toUpperCase() ?? '') === word[0] && word.length > 1`) is
skipped; target the highlightLine function and the early-return bypass array to
implement this change.

---

Nitpick comments:
In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts`:
- Around line 405-469: The bash keyword Set (the "bash" entry created with new
Set([...])) mixes core shell keywords with common utilities/commands which can
over-highlight; split this into two named Sets (e.g., bashKeywords and
bashCommands) and update the highlighting logic (where the "bash" set is used —
search for the "bash" key and any highlightToken/highlightWord functions in
syntaxHighlighter.ts) to only treat bashKeywords as language keywords by default
and use bashCommands optionally (or only in command-context tokens) to avoid
matching commands inside variables/comments; ensure callers that need the
broader command list opt into using bashCommands.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a830f0 and a6035d4.

📒 Files selected for processing (10)
  • src/renderer/components/chat/items/LinkedToolItem.tsx
  • src/renderer/components/chat/items/linkedTool/BashToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/index.ts
  • src/renderer/components/chat/viewers/syntaxHighlighter.ts
  • src/renderer/utils/toolRendering/index.ts
  • src/renderer/utils/toolRendering/toolContentChecks.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/index.ts
  • src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx
  • src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx
  • src/renderer/components/chat/items/LinkedToolItem.tsx

Comment on lines +727 to +787
html: new Set([
'div',
'span',
'html',
'head',
'body',
'title',
'meta',
'link',
'script',
'style',
'section',
'article',
'header',
'footer',
'nav',
'main',
'aside',
'form',
'input',
'button',
'select',
'option',
'textarea',
'label',
'table',
'thead',
'tbody',
'tr',
'th',
'td',
'ul',
'ol',
'li',
'a',
'p',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'img',
'video',
'audio',
'canvas',
'svg',
'class',
'id',
'src',
'href',
'type',
'name',
'value',
'placeholder',
'alt',
'width',
'height',
'true',
'false',
]),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the syntaxHighlighter.ts file
find . -name "syntaxHighlighter.ts" -type f

Repository: matt1398/claude-devtools

Length of output: 127


🏁 Script executed:

# Read the relevant sections of the file to verify the claims
sed -n '725,790p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 877


🏁 Script executed:

# Check the early-return condition around line 850
sed -n '845,855p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 446


🏁 Script executed:

# Check the type-coloring logic around line 979
sed -n '975,985p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 482


🏁 Script executed:

# Search for where HTML language is used in the codebase
rg -n "language.*['\"]html['\"]" --type=ts -C2

Repository: matt1398/claude-devtools

Length of output: 50


🏁 Script executed:

# Search for calls to highlightLine function
rg -n "highlightLine" --type=ts -B2 -A2

Repository: matt1398/claude-devtools

Length of output: 2570


🏁 Script executed:

# Search for any HTML language specification in the codebase
rg -n "html" --type=ts -i | grep -i "language\|lang" | head -20

Repository: matt1398/claude-devtools

Length of output: 50


🏁 Script executed:

# Check if there's any language mapping or detection
rg -n "getLanguage\|detectLanguage\|language.*=" --type=ts | head -20

Repository: matt1398/claude-devtools

Length of output: 50


🏁 Script executed:

# Read more context around the syntaxHighlighter file to understand the full picture
wc -l src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 130


🏁 Script executed:

# Check MarkdownViewer to see where 'lang' comes from
sed -n '140,180p' src/renderer/components/chat/viewers/MarkdownViewer.tsx

Repository: matt1398/claude-devtools

Length of output: 1500


🏁 Script executed:

# Check CodeBlockViewer to see how detectedLanguage is determined
sed -n '1,50p' src/renderer/components/chat/viewers/CodeBlockViewer.tsx

Repository: matt1398/claude-devtools

Length of output: 1561


🏁 Script executed:

# Get more context around detectedLanguage in CodeBlockViewer
sed -n '200,240p' src/renderer/components/chat/viewers/CodeBlockViewer.tsx

Repository: matt1398/claude-devtools

Length of output: 1605


🏁 Script executed:

# Look for where detectedLanguage is set
rg -n "detectedLanguage" src/renderer/components/chat/viewers/CodeBlockViewer.tsx -B5 -A5

Repository: matt1398/claude-devtools

Length of output: 1202


🏁 Script executed:

# Check if there's any git history or comments about HTML being added to or removed from the bypass list
git log --oneline -n 20 -- src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 154


🏁 Script executed:

# Let's examine the entire KEYWORDS object and the early-return logic together
sed -n '200,250p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 732


🏁 Script executed:

# Get the full early-return condition and surrounding context
sed -n '840,870p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 1076


🏁 Script executed:

# Check what languages have empty keyword sets
rg -n "new Set\(\[\]" src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 50


🏁 Script executed:

# Let's see the full KEYWORDS object structure to understand which languages are defined
sed -n '200,850p' src/renderer/components/chat/viewers/syntaxHighlighter.ts | grep -E "^\s+[a-z]+:\s+new Set|^\s+[a-z]+:\s+KEYWORDS"

Repository: matt1398/claude-devtools

Length of output: 277


🏁 Script executed:

# Let's check the exact commit that added HTML keywords
git show a6035d4 --stat

Repository: matt1398/claude-devtools

Length of output: 28523


🏁 Script executed:

# Get more details about what changed in that commit regarding HTML
git show a6035d4 -- src/renderer/components/chat/viewers/syntaxHighlighter.ts | head -200

Repository: matt1398/claude-devtools

Length of output: 3881


🏁 Script executed:

# Check if there's any documentation or issues mentioning the type-coloring problem
rg -n "type-coloring\|false.*keyword\|capitalize" --type=ts --type=md

Repository: matt1398/claude-devtools

Length of output: 50


🏁 Script executed:

# Let's verify the exact HTML keyword set to see if capitalized words are included
sed -n '727,787p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 808


🏁 Script executed:

# Let me check if there's any special handling for HTML in the type-coloring logic
sed -n '970,1000p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 1023


🏁 Script executed:

# Check the complete context around type-coloring to see if HTML is handled specially
sed -n '960,1015p' src/renderer/components/chat/viewers/syntaxHighlighter.ts

Repository: matt1398/claude-devtools

Length of output: 1553


HTML type-coloring will cause false positives on capitalized content.

The HTML keyword set (50+ tag and attribute names) won't prevent capitalized words in HTML content from being colored as types. When highlightLine is called with language='html', any word starting with uppercase like "My Company" or "Click Here" will match the type-coloring rule at line 979 ((word[0]?.toUpperCase() ?? '') === word[0] && word.length > 1) since HTML is not in the early-return bypass list (line 850).

The commit objective to "fix markdown/html false type-coloring on capitalized words" is only partially addressed—adding HTML keywords helps with recognized tag names, but doesn't resolve the broader issue for arbitrary capitalized content.

Consider adding 'html' to the early-return bypass condition at line 850 to prevent this, or implement language-specific logic to skip type-coloring for HTML.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/chat/viewers/syntaxHighlighter.ts` around lines 727 -
787, The type-coloring logic in highlightLine erroneously colors capitalized
words in HTML content because 'html' is not included in the early-return bypass;
update the early-return condition (the bypass list checked at the start of
highlightLine) to include 'html' or add a language-specific guard so when
language === 'html' the type-coloring block (the capitalized-word check
`(word[0]?.toUpperCase() ?? '') === word[0] && word.length > 1`) is skipped;
target the highlightLine function and the early-return bypass array to implement
this change.

@matt1398
Copy link
Owner

@Psypeal — appreciate the PR.

I want to keep the CollapsibleOutputSection refactor and the markdown preview toggle — both solid. But the 437 lines of keyword sets for languages like C, Java, Swift, Lua etc. aren't something we need. CONTRIBUTING.md is pretty clear about not committing large static data blobs. Also agree with @cesarafonseca re: Bash highlighting being more noise than help.

Can you split out just the collapsible output + markdown preview into its own PR? Happy to merge that. The rest should start as an Issue so we can scope it properly.

Going to close this if there's no update soon.

@Psypeal
Copy link
Contributor Author

Psypeal commented Mar 11, 2026

@Psypeal — appreciate the PR.

I want to keep the CollapsibleOutputSection refactor and the markdown preview toggle — both solid. But the 437 lines of keyword sets for languages like C, Java, Swift, Lua etc. aren't something we need. CONTRIBUTING.md is pretty clear about not committing large static data blobs. Also agree with @cesarafonseca re: Bash highlighting being more noise than help.

Can you split out just the collapsible output + markdown preview into its own PR? Happy to merge that. The rest should start as an Issue so we can scope it properly.

Going to close this if there's no update soon.

okay, matt. I will do it later.

Psypeal added a commit to Psypeal/claude-devtools that referenced this pull request Mar 11, 2026
- Add reusable CollapsibleOutputSection component for tool outputs
  (collapsed by default, with status dot and copy support)
- Refactor DefaultToolViewer to use CollapsibleOutputSection
- Add Code/Preview toggle for .md/.mdx files in ReadToolViewer
- Default to preview mode for markdown files in WriteToolViewer
- Export CollapsibleOutputSection from linkedTool barrel

Split from matt1398#90 per maintainer feedback — drops BashToolViewer and
keyword expansions, keeps the collapsible output refactor and
markdown preview improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Psypeal
Copy link
Contributor Author

Psypeal commented Mar 11, 2026

Closing in favor of #112, which splits out just the CollapsibleOutputSection + markdown preview toggle as requested.

@Psypeal Psypeal closed this Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants