Skip to content

chore: get changes from longbridge gpui components. - #2

Merged
BumpyClock merged 12 commits into
mainfrom
upstream-merge
Feb 23, 2026
Merged

chore: get changes from longbridge gpui components.#2
BumpyClock merged 12 commits into
mainfrom
upstream-merge

Conversation

@BumpyClock

Copy link
Copy Markdown
Owner

This pull request introduces several new example fixture files for syntax highlighting, updates the theme selection logic to support theme sets and system mode, and documents the latest upstream sync status in the README.md. It also adds and closes a series of tasks in the project management event log to track the upstream porting and validation process.

Theme selection and menu improvements:

  • Updated the menu logic in crates/story/src/app_menus.rs to use ThemeModePreference (with "System", "Light", and "Dark" options) instead of the previous ThemeMode, and to support selecting theme sets rather than individual themes. The menu now reflects the user's theme mode preference and the current theme set. [1] [2] [3] [4]

New syntax highlighting fixtures:

  • Added example fixture files for Astro (test.astro), Kotlin (test.kt), Lua (test.lua), and Svelte (test.svelte) in crates/story/examples/fixtures/ to demonstrate and test syntax highlighting for these languages. [1] [2] [3] [4]

Documentation updates:

  • Updated README.md to include a new "Upstream sync status" section, listing the exact upstream commits that were manually ported and the categories of imported fixes/features.

Project management and task tracking:

  • Added a batch of task creation, dependency, claiming, and completion events to .tasque/events.jsonl to document the manual porting of upstream changes, validation, and documentation updates for the sync batch.

BumpyClock and others added 6 commits February 22, 2026 15:12
selection/docs

- Add syntax highlighting for Astro, Kotlin, Lua, and Svelte (fixtures
  and highlight queries)
- Update Table to support cell selection and document selection modes
- Sync upstream fixes: editor perf, table selection, bugfixes (see
  README)
- Update theme docs for ThemeSet and ThemeModePreference
- Misc: update dependencies, menu separator rendering, input
  keybindings, and minor code cleanup
- Replace "Dark Mode" and "Auto Switch Theme" with dropdowns for color
  theme and mode
- Update theme switching logic to use ThemeRegistry and
  ThemeModePreference
- Show theme set name in title bar
- Rename Ayu theme to "Ayu" for consistency
error logging

- Use `_` instead of `i` in Lua fixture loop for idiomatic style
- Adjust menu
- Make resolve_theme return Option instead of panicking on empty
  ThemeSetEntry; apply_theme_set now warns and returns early
- Extract create_default_set helper to remove duplicated
  ThemeSetEntry construction in init_default_themes and reload
- Clear stale selected_row/col/cell in table selection setters
  so internal state is consistent when switching selection mode
- Log parser.set_language/set_included_ranges errors at debug
  level instead of silently continuing in highlighter
- Fix leading separator in menu story (i > 0 && i % 5 == 0)
- Change Lua nil capture from @boolean to @constant.builtin
- Replace unused loop variable i with _ in test.lua fixture

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Matches the Lua nil fix — null is not a boolean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@BumpyClock
BumpyClock requested a review from Copilot February 23, 2026 00:18
@coderabbitai

coderabbitai Bot commented Feb 23, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary by CodeRabbit

  • New Features

    • Theme system: theme sets with System/Light/Dark preference
    • Table: cell-level selection, right-click, double-click, and clear-selection events
    • Floating Sidebar: resizable, collapsible component and demo story
    • Syntax highlighting: Kotlin & Lua support and added parsers
  • Documentation

    • Expanded theme and table docs; added Floating Sidebar / SidebarShell guides
  • Improvements

    • Optional SidebarShell layout and page-header action in settings
    • Various UI polish, input/keybinding updates, and highlighter injection/cache optimizations

Walkthrough

Adds theme sets with mode preference, cell-level table selection/events, per-language highlighter injection layers plus Kotlin/Lua support, a new resizable FloatingSidebar component and story, example fixtures, docs updates, UI refinements, and appended task events.

Changes

Cohort / File(s) Summary
Theme system & registry
crates/ui/src/theme/mod.rs, crates/ui/src/theme/registry.rs, crates/story/src/themes.rs, crates/story/src/stories/settings_story.rs, crates/story/src/app_menus.rs, crates/story/src/title_bar.rs, docs/docs/theme.md
Introduce ThemeSet/ThemeSetEntry and ThemeModePreference (System/Light/Dark). Add Theme::apply_theme_set and ThemeRegistry theme_sets APIs; persist theme_set_name and mode_preference; update settings, menus, title bar and story theming to use theme sets. Public API additions and behavior changes present.
Table selection & events
crates/ui/src/table/state.rs, docs/docs/components/table.md
Add SelectionMode { Column, Row, Cell }, cell_selectable, selected_cell, set_selected_cell, selected_cell() accessor, and new TableEvent variants (SelectCell, DoubleClickedCell, RightClickedCell, ClearSelection). Update rendering signatures and event wiring for per-cell interactions. Public API expanded.
Floating sidebar component & story
crates/ui/src/floating_sidebar/mod.rs, crates/ui/src/lib.rs, crates/story/src/stories/floating_sidebar_story.rs, crates/story/src/main.rs, crates/story/src/stories/mod.rs
Add public FloatingSidebar component with builder API, internal resize tracker, keyed state and on_resize_end callback; re-export from UI crate. Add FloatingSidebarStory, integrate floating/resizable sidebar into gallery and add Gallery.sidebar_width with resize handling. Significant new public API and behavior to review.
Syntax highlighter & languages
crates/ui/src/highlighter/highlighter.rs, crates/ui/src/highlighter/languages.rs, crates/ui/src/highlighter/languages/kotlin/highlights.scm, crates/ui/src/highlighter/languages/lua/highlights.scm, crates/ui/Cargo.toml
Add per-language injection_layers with incremental parsing and range-aware feeding; add Kotlin and Lua language variants and highlight grammars; add optional tree-sitter parser deps (astro-next, kotlin-sg, lua, svelte-next). Large parsing changes and new assets—validate queries and parser wiring.
Examples / fixtures
crates/story/examples/fixtures/test.astro, crates/story/examples/fixtures/test.kt, crates/story/examples/fixtures/test.lua, crates/story/examples/fixtures/test.svelte
Add example fixtures demonstrating Astro, Kotlin, Lua, and Svelte usage (new example files).
Settings UI & SettingPage signature
crates/ui/src/setting/page.rs, crates/ui/src/setting/settings.rs, docs/docs/components/settings.md
Add page_header_action: Option<AnyElement> parameter to SettingPage::render. Add configurable left SidebarShell for Settings plus builder methods (use_sidebar_shell, safe_area_top, sidebar_shell_inset, sidebar_title, page_header_action). Signature change requires call-site updates.
Sidebar & animation adjustments
crates/ui/src/sidebar/mod.rs, crates/ui/src/sidebar/menu.rs, crates/ui/src/accordion.rs, crates/ui/src/animation.rs
Expose DEFAULT_WIDTH/COLLAPSED_WIDTH as pub(crate); add Sidebar::animate_width field and builder; gate width animations on animate_width; change menu separator rendering and remove one clone in accordion; add clippy allow on keyed_presence.
Highlighter language data
crates/ui/src/highlighter/languages/kotlin/highlights.scm, crates/ui/src/highlighter/languages/lua/highlights.scm
Large new highlight grammar files for Kotlin and Lua added. Validate scopes/queries and performance impact.
UI minor tweaks & formatting
crates/ui/src/input/*, crates/ui/src/dialog.rs, crates/ui/src/menu/popup_menu.rs, crates/ui/src/notification.rs, crates/ui/src/plot/shape/line.rs, crates/ui/src/popover.rs, crates/ui/src/radio.rs, crates/ui/src/sheet.rs, crates/ui/src/sidebar/menu.rs, crates/ui/src/tab/tab.rs
Mostly formatting and small refactors: keybindings added, consolidated imports, collapsed builder calls, popup separator style changed, and removal of overflow_hidden() on Radio label container (affects clipping).
Tree & menu small changes
crates/story/src/stories/menu_story.rs, crates/ui/src/tree.rs
Insert separators into long dropdown menus; add TreeState::focus(&self, window, cx) public method.
Highlighter architecture
crates/ui/src/highlighter/highlighter.rs, crates/ui/src/highlighter/languages.rs
Add injection_layers: HashMap<SharedString, InjectionLayer> to SyntaxHighlighter, per-language reuse of parsed injection trees, and new ByteChunks fields for node-aware parsing. Significant internal parsing flow changes.
Events, docs & misc
.tasque/events.jsonl, README.md, docs/docs/components/table.md, docs/docs/components/sidebar.md, themes/ayu.json
Append multiple task events to .tasque/events.jsonl; add "Upstream sync status" to README; expand table and sidebar docs; rename Ayu theme top-level name to "Ayu".

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant FloatingSidebar
participant ResizeTracker
participant WindowApp as Window/App
User->>FloatingSidebar: pointer down on resizer (on_resize_start)
FloatingSidebar->>ResizeTracker: start tracking (capture origin, width)
User->>ResizeTracker: drag -> move events
ResizeTracker->>FloatingSidebar: update expanded_width
FloatingSidebar->>WindowApp: clamp/apply width, re-render
User->>ResizeTracker: release (on_resize_end)
ResizeTracker->>FloatingSidebar: finalize width
FloatingSidebar->>WindowApp: invoke on_resize_end callback (persist/update)

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'chore: get changes from longbridge gpui components' directly describes the main objective of the changeset: importing/porting upstream changes from longbridge's GPUI components.
Description check ✅ Passed The PR description comprehensively covers the major changes (theme system updates, syntax highlighting fixtures, documentation, and task tracking) and aligns well with the changeset details provided in the raw summary.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch upstream-merge

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 syncs a batch of upstream gpui-component changes into this fork by expanding syntax highlighting support/fixtures, adding theme-set + system appearance preference selection, and enhancing table selection capabilities (including cell selection), along with related docs and housekeeping updates.

Changes:

  • Introduces theme sets + ThemeModePreference (“System/Light/Dark”) across the UI theme registry and story app menus/settings.
  • Adds Kotlin/Lua syntax highlighting queries and example fixtures (plus new fixtures for Astro/Svelte).
  • Extends table interactions with cell selection events/handling and expands component documentation.

Reviewed changes

Copilot reviewed 39 out of 40 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
themes/ayu.json Renames the theme-set display name to “Ayu” for grouping.
docs/docs/theme.md Documents theme sets and ThemeModePreference usage.
docs/docs/components/table.md Expands Table docs (selection modes, events, keyboard shortcuts, API reference).
crates/ui/src/tree.rs Adds a focus() helper on TreeState.
crates/ui/src/theme/registry.rs Adds ThemeSetEntry storage + theme-set rebuild logic on reload.
crates/ui/src/theme/mod.rs Adds ThemeModePreference + active theme-set name to global Theme, plus apply-by-set APIs.
crates/ui/src/table/state.rs Adds cell selection mode, cell events, selection tracking, rendering + navigation support.
crates/ui/src/tab/tab.rs Import formatting cleanup.
crates/ui/src/sidebar/mod.rs Refactors header/footer builder closures formatting.
crates/ui/src/sidebar/menu.rs Minor formatting + avoids unnecessary clone in collapsed submenu builder.
crates/ui/src/sheet.rs Refactors slide animation closure formatting.
crates/ui/src/radio.rs Removes overflow_hidden() in radio indicator content.
crates/ui/src/popover.rs Minor formatting for motion duration calculation.
crates/ui/src/plot/shape/line.rs Import formatting cleanup.
crates/ui/src/notification.rs Import formatting cleanup.
crates/ui/src/menu/popup_menu.rs Changes separator rendering from 1px background to bottom border styling.
crates/ui/src/input/state.rs Adds additional keybindings (shift variants, ctrl-backspace on macOS) + formatting tweaks.
crates/ui/src/input/search.rs Minor formatting simplification.
crates/ui/src/input/element.rs Minor formatting simplification.
crates/ui/src/highlighter/languages/lua/highlights.scm Adds Lua highlight query file.
crates/ui/src/highlighter/languages/kotlin/highlights.scm Adds Kotlin highlight query file.
crates/ui/src/highlighter/languages.rs Registers Kotlin/Lua in language enum/name parsing/config selection.
crates/ui/src/highlighter/highlighter.rs Refactors combined injection highlighting to parse once in update() and reuse during matching.
crates/ui/src/dialog.rs Minor import formatting + wraps soft-dismiss animation fallback formatting.
crates/ui/src/animation.rs Adds clippy allow for keyed_presence argument count.
crates/ui/src/accordion.rs Removes an unnecessary clone of layout_anim.
crates/ui/Cargo.toml Adds optional tree-sitter deps (Astro-next, Kotlin, Lua, Svelte-next) to the highlighting feature set.
crates/story/src/title_bar.rs Displays theme set name in title bar instead of variant name.
crates/story/src/themes.rs Persists theme set + mode preference in story state and applies via theme set API.
crates/story/src/stories/table_story.rs Logs new table cell-selection events.
crates/story/src/stories/settings_story.rs Replaces dark-mode toggle with theme-set + mode preference dropdowns.
crates/story/src/stories/menu_story.rs Inserts separators periodically in an example popup menu.
crates/story/src/app_menus.rs Updates menu theme selection to use theme sets + system/light/dark preference.
crates/story/examples/fixtures/test.svelte Adds a Svelte fixture file for highlighting demos.
crates/story/examples/fixtures/test.lua Adds a Lua fixture file for highlighting demos.
crates/story/examples/fixtures/test.kt Adds a Kotlin fixture file for highlighting demos.
crates/story/examples/fixtures/test.astro Adds an Astro fixture file for highlighting demos.
README.md Adds upstream sync status section with referenced commits.
Cargo.lock Updates lockfile for new/updated dependencies.
.tasque/events.jsonl Logs planning/claiming/completion events for this upstream port batch.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +275 to +280
cx.stop_propagation();
self.selection_mode = SelectionMode::Row;
self.right_clicked_row = None;
self.selected_row = Some(row_ix);
self.selected_col = None;
self.selected_cell = None;

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

set_selected_row clears right_clicked_row but leaves right_clicked_cell untouched. After a cell right-click, switching to row selection can leave a stale right-click border rendered on an unrelated cell. Clear right_clicked_cell (and/or unify selection state resets) when changing selection modes.

Copilot uses AI. Check for mistakes.
Comment on lines 307 to 312
pub fn set_selected_col(&mut self, col_ix: usize, cx: &mut Context<Self>) {
self.selection_state = SelectionState::Column;
self.selection_mode = SelectionMode::Column;
self.selected_col = Some(col_ix);
self.selected_row = None;
self.selected_cell = None;
if let Some(col_ix) = self.selected_col {

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

set_selected_col switches to column selection but does not clear right_clicked_cell/right_clicked_row. This can leave stale right-click styling even though the active selection mode changed. Consider clearing the right-click state when a new selection mode is set.

Copilot uses AI. Check for mistakes.
Comment thread crates/ui/Cargo.toml
Comment on lines 21 to 53
@@ -35,6 +36,8 @@ tree-sitter-languages = [
"dep:tree-sitter-java",
"dep:tree-sitter-javascript",
"dep:tree-sitter-jsdoc",
"dep:tree-sitter-kotlin-sg",
"dep:tree-sitter-lua",
"dep:tree-sitter-make",
"dep:tree-sitter-md",
"dep:tree-sitter-php",
@@ -46,6 +49,7 @@ tree-sitter-languages = [
"dep:tree-sitter-sequel",
"dep:tree-sitter-swift",
"dep:tree-sitter-toml-ng",
"dep:tree-sitter-svelte-next",
"dep:tree-sitter-typescript",

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

The tree-sitter-languages feature now enables tree-sitter-astro-next and tree-sitter-svelte-next, but there are no corresponding Language variants / parser wiring / highlight queries for Astro or Svelte (and these crates appear unused in the code). Either add full highlighter integration for Astro/Svelte or remove these deps from the feature set to avoid unnecessary build time and binary size.

Copilot uses AI. Check for mistakes.
Comment on lines 11 to 16
#[derive(Debug, Clone, Serialize, Deserialize)]
struct State {
theme: SharedString,
theme_set: SharedString,
mode_preference: ThemeModePreference,
scrollbar_show: Option<ScrollbarShow>,
}

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

The persisted State format changed from theme to theme_set + mode_preference, but Deserialize will now fail on existing target/state.json files (missing fields) and silently reset users to defaults via unwrap_or_default(). If you want to preserve prior selections, add #[serde(default)] plus #[serde(alias = "theme")]/migration logic so older state files can still load.

Copilot uses AI. Check for mistakes.
/// Parse all combined injections after main tree is updated.
/// pattern: parse once in update, query many times in render.
fn parse_combined_injections(&mut self, tree: &Tree) {
let Some(combined_query) = &self.combined_injections_query else {

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

parse_combined_injections returns early when there is no combined_injections_query, but it never clears injection_layers. If the highlighter previously parsed combined injections (or the language changes), stale injection trees can remain and match_styles will keep applying injection highlights that no longer exist. Consider clearing injection_layers when combined_injections_query is None, and otherwise retaining/removing layers based on the languages found in the current combined_ranges before inserting updated trees.

Suggested change
let Some(combined_query) = &self.combined_injections_query else {
let Some(combined_query) = &self.combined_injections_query else {
// If combined injections are disabled or unavailable, clear any stale injection layers.
self.injection_layers.clear();

Copilot uses AI. Check for mistakes.
Comment on lines 153 to 156
pub mode: ThemeMode,
pub mode_preference: ThemeModePreference,
pub theme_set_name: SharedString,
/// The font family for the application, default is `.SystemUIFont`.

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

Theme derives Serialize/Deserialize, and this PR adds new non-optional fields (mode_preference, theme_set_name) without #[serde(default)]. Any persisted Theme JSON produced by older versions will fail to deserialize due to missing fields. Add serde defaults for the new fields (or mark the whole struct with #[serde(default)] and ensure sensible defaults) to avoid a breaking change for consumers.

Copilot uses AI. Check for mistakes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (2)
crates/ui/src/table/state.rs (1)

269-317: ⚠️ Potential issue | 🟡 Minor

Clear stale right-click cell state when selection changes.

right_clicked_cell persists across left-click selection and clear_selection, so the old right-click highlight can linger after selecting another cell or pressing Esc. Clear it (and the row right-click state) whenever selection changes.

🧹 Suggested fix
 pub fn set_selected_row(&mut self, row_ix: usize, cx: &mut Context<Self>) {
@@
-        self.right_clicked_row = None;
+        self.right_clicked_row = None;
+        self.right_clicked_cell = None;
@@
 }
 
 pub fn set_selected_col(&mut self, col_ix: usize, cx: &mut Context<Self>) {
         self.selection_mode = SelectionMode::Column;
         self.selected_col = Some(col_ix);
         self.selected_row = None;
         self.selected_cell = None;
+        self.right_clicked_row = None;
+        self.right_clicked_cell = None;
@@
 }
 
 pub fn set_selected_cell(&mut self, row_ix: usize, col_ix: usize, cx: &mut Context<Self>) {
         self.selection_mode = SelectionMode::Cell;
         self.selected_cell = Some((row_ix, col_ix));
         self.selected_row = None;
         self.selected_col = None;
+        self.right_clicked_row = None;
+        self.right_clicked_cell = None;
@@
 }
 
 pub fn clear_selection(&mut self, cx: &mut Context<Self>) {
         self.selection_mode = SelectionMode::Row;
         self.selected_row = None;
         self.selected_col = None;
         self.selected_cell = None;
+        self.right_clicked_row = None;
+        self.right_clicked_cell = None;
         cx.emit(TableEvent::ClearSelection);
         cx.notify();
 }

Also applies to: 324-347

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

In `@crates/ui/src/table/state.rs` around lines 269 - 317, Clear any stale
right-click state when changing selection: in set_selected_row and
set_selected_col (and in clear_selection), reset both self.right_clicked_cell =
None and self.right_clicked_row = None whenever you change selection
mode/selected items so the old right-click highlight is removed; update the
methods set_selected_row, set_selected_col, and clear_selection to explicitly
clear these fields before emitting events/notifications.
crates/ui/src/highlighter/languages.rs (1)

32-133: 🧹 Nitpick | 🔵 Trivial

Add test coverage for the new Language variants.

Extending test_language_name to include the newly added variants guards name() regressions and keeps mappings exercised.

🔧 Suggested test additions
@@
         assert_eq!(Language::JavaScript.name(), "javascript");
         assert_eq!(Language::Zig.name(), "zig");
         assert_eq!(Language::CSharp.name(), "csharp");
         assert_eq!(Language::TypeScript.name(), "typescript");
         assert_eq!(Language::Tsx.name(), "tsx");
         assert_eq!(Language::Diff.name(), "diff");
         assert_eq!(Language::Elixir.name(), "elixir");
         assert_eq!(Language::Erb.name(), "erb");
         assert_eq!(Language::Ejs.name(), "ejs");
+        assert_eq!(Language::Kotlin.name(), "kotlin");
+        assert_eq!(Language::Lua.name(), "lua");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/ui/src/highlighter/languages.rs` around lines 32 - 133, The test suite
is missing coverage for the newly added Language variants; update the existing
test (e.g., test_language_name) to assert that Language::Kotlin, ::Lua, ::Make,
::Markdown, ::MarkdownInline, ::Php, ::Proto, ::Python, ::Ruby, ::Rust, ::Scala,
::Sql, ::Swift, ::Toml, ::Tsx, ::TypeScript, ::Yaml, and ::Zig map to their
expected name() outputs; add each variant to the test assertions so
Language::name() is exercised for all enum variants and future regressions are
caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/story/examples/fixtures/test.astro`:
- Around line 83-88: The template uses a React-style key prop inside items.map
(the <li key={index}> in the map callback) which is unnecessary in Astro; remove
the key attribute from the <li> elements (or if this JSX-like usage is
intentional for demonstration, add an inline comment near the items.map block
indicating it’s illustrative) so the template emits clean Astro/HTML output;
locate the map invocation (items.map((item, index) => ( ... ))) and either
delete key={index} from the <li> or add a clarifying comment above it.
- Line 6: Remove the unused import GetStaticPaths from the top of the file (the
import statement referencing GetStaticPaths) unless you intend it for
demonstration; if it is meant as an example, replace it with a brief inline
comment clarifying that the import is present only for syntax highlighting/demo,
otherwise delete the import line to eliminate the unused symbol.

In `@crates/story/examples/fixtures/test.kt`:
- Around line 63-67: The function safely currently catches a generic Exception
which triggers the TooGenericExceptionCaught detekt rule; either add
`@Suppress`("TooGenericExceptionCaught") above the safely declaration to silence
the rule, or refactor safely to use Kotlin's runCatching in the safely(block: ()
-> T): Result<T> function (call runCatching { block() } and map success to
Result.Success and failure to Result.Error using the exception.message ?:
"unknown error") so you avoid an explicit catch of Exception.

In `@crates/story/examples/fixtures/test.lua`:
- Line 59: The function declaration HelloWorld:processNames currently defines an
implicit self parameter but doesn't use it, triggering Luacheck W212; either (a)
change the declaration to a dot-style function HelloWorld.processNames(names) if
no instance is needed, or (b) keep the colon and reference self inside the body
or add a Luacheck suppression comment (-- luacheck: ignore 212) directly above
the function to silence the warning; locate the HelloWorld:processNames
definition and apply one of these fixes to remove the unused implicit self
warning.
- Around line 8-112: The Config, LogLevel and describe symbols are unused and
causing Luacheck W211; update HelloWorld.new and/or HelloWorld:generateReport to
reference Config and LogLevel (for example include Config values in self.config
or append LogLevel.DEFAULT to the report) and add a small main/test block that
constructs HelloWorld, calls :generateReport() and calls describe(...) on a
Success/Error and a string to exercise the describe function (use Success/Error
or safely to produce values). Ensure the modifications reference the exact
symbols Config, LogLevel, and describe so they are no longer unused.

In `@crates/story/examples/fixtures/test.svelte`:
- Line 100: The each block using "{`#each` state.items as item, i (item)}" risks
key collisions when duplicate strings exist; change the key to a stable unique
value such as the index or a composite key to guarantee uniqueness (e.g., use
"i" or combine "item" and "i") in the each block that iterates state.items
(references: state.items, item, i, the each block) so Svelte can reliably track
list items.

In `@crates/ui/src/highlighter/highlighter.rs`:
- Around line 41-50: The injection_layers cache is only appended to and can
retain trees for languages whose combined_ranges have been removed; update the
logic in update() to prune injection_layers before parsing new trees: iterate
over the keys in injection_layers and remove any language (key) that is not
present in the current combined_ranges or whose combined_ranges entry is empty,
so InjectionLayer entries are dropped when there are no combined injection
ranges left; keep match_styles() unchanged but rely on the pruned
injection_layers to avoid emitting highlights for non-existent ranges.

In `@crates/ui/src/tree.rs`:
- Around line 396-398: The method signature for focus currently takes &mut self
though it doesn't mutate TreeState; change pub fn focus(&mut self, window: &mut
Window, cx: &mut App) to pub fn focus(&self, window: &mut Window, cx: &mut App)
so callers can use shared refs. Update the impl where focus is defined (the
method named focus that calls self.focus_handle.focus(...)) and ensure
focus_handle.focus accepts &self (no other internal mutability changes
required); then run/adjust any call sites that passed &mut to use & if needed.

In `@docs/docs/components/table.md`:
- Around line 658-669: The events list is missing the ClearSelection event
referenced elsewhere; update the Events section to include the ClearSelection
variant (no payload) alongside the other enum variants (e.g., add
`ClearSelection` to the list) so the API summary and examples match; ensure any
example snippets and references to ClearSelection now point to this documented
event name (ClearSelection) and keep the same formatting as the other entries
like `SelectRow(usize)` and `MoveColumn(usize, usize)`.

---

Outside diff comments:
In `@crates/ui/src/highlighter/languages.rs`:
- Around line 32-133: The test suite is missing coverage for the newly added
Language variants; update the existing test (e.g., test_language_name) to assert
that Language::Kotlin, ::Lua, ::Make, ::Markdown, ::MarkdownInline, ::Php,
::Proto, ::Python, ::Ruby, ::Rust, ::Scala, ::Sql, ::Swift, ::Toml, ::Tsx,
::TypeScript, ::Yaml, and ::Zig map to their expected name() outputs; add each
variant to the test assertions so Language::name() is exercised for all enum
variants and future regressions are caught.

In `@crates/ui/src/table/state.rs`:
- Around line 269-317: Clear any stale right-click state when changing
selection: in set_selected_row and set_selected_col (and in clear_selection),
reset both self.right_clicked_cell = None and self.right_clicked_row = None
whenever you change selection mode/selected items so the old right-click
highlight is removed; update the methods set_selected_row, set_selected_col, and
clear_selection to explicitly clear these fields before emitting
events/notifications.

// This file demonstrates Astro 5 syntax highlighting features.
// Frontmatter: TypeScript/JavaScript code that runs at build time

import type { GetStaticPaths } from 'astro';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Unused import.

GetStaticPaths is imported but never used in this file. If it's intended to demonstrate import syntax for highlighting purposes, consider adding a comment clarifying this. Otherwise, it can be removed.

Remove unused import
-import type { GetStaticPaths } from 'astro';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { GetStaticPaths } from 'astro';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/story/examples/fixtures/test.astro` at line 6, Remove the unused
import GetStaticPaths from the top of the file (the import statement referencing
GetStaticPaths) unless you intend it for demonstration; if it is meant as an
example, replace it with a brief inline comment clarifying that the import is
present only for syntax highlighting/demo, otherwise delete the import line to
eliminate the unused symbol.

Comment on lines +83 to +88
items.map((item, index) => (
<li key={index}>
<a href={`/${item.toLowerCase()}`}>{item}</a>
</li>
))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

key attribute is not used in Astro templates.

Unlike React, Astro compiles templates at build time to static HTML, so the key prop has no effect here. If this is intentional to demonstrate JSX-like syntax for highlighting, consider adding a comment. Otherwise, it can be removed.

Remove unnecessary key attribute
 				items.map((item, index) => (
-					<li key={index}>
+					<li>
 						<a href={`/${item.toLowerCase()}`}>{item}</a>
 					</li>
 				))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
items.map((item, index) => (
<li key={index}>
<a href={`/${item.toLowerCase()}`}>{item}</a>
</li>
))
}
items.map((item, index) => (
<li>
<a href={`/${item.toLowerCase()}`}>{item}</a>
</li>
))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/story/examples/fixtures/test.astro` around lines 83 - 88, The template
uses a React-style key prop inside items.map (the <li key={index}> in the map
callback) which is unnecessary in Astro; remove the key attribute from the <li>
elements (or if this JSX-like usage is intentional for demonstration, add an
inline comment near the items.map block indicating it’s illustrative) so the
template emits clean Astro/HTML output; locate the map invocation
(items.map((item, index) => ( ... ))) and either delete key={index} from the
<li> or add a clarifying comment above it.

Comment on lines +63 to +67
fun <T> safely(block: () -> T): Result<T> = try {
Result.Success(block())
} catch (e: Exception) {
Result.Error(e.message ?: "unknown error")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the test.kt file
find . -name "test.kt" -type f | head -20

Repository: BumpyClock/gpui-component

Length of output: 109


🏁 Script executed:

# Look for detekt configuration files
find . -name "detekt*" -type f | head -20

Repository: BumpyClock/gpui-component

Length of output: 89


🏁 Script executed:

# Check for gradle/maven files that might reference detekt
find . \( -name "build.gradle*" -o -name "pom.xml" -o -name "*.gradle" \) -type f | head -20

Repository: BumpyClock/gpui-component

Length of output: 51


🏁 Script executed:

cat -n ./crates/story/examples/fixtures/test.kt | sed -n '55,75p'

Repository: BumpyClock/gpui-component

Length of output: 842


🏁 Script executed:

cat ./detekt-config.yaml

Repository: BumpyClock/gpui-component

Length of output: 10224


🏁 Script executed:

# Check if there's any `@Suppress` annotation in the test.kt file
grep -n "@Suppress" ./crates/story/examples/fixtures/test.kt

Repository: BumpyClock/gpui-component

Length of output: 51


🏁 Script executed:

# Check the complete context around the safely function to see if there's any suppression
cat -n ./crates/story/examples/fixtures/test.kt | sed -n '60,70p'

Repository: BumpyClock/gpui-component

Length of output: 430


🏁 Script executed:

# Verify if examples/fixtures matches any detekt exclusion patterns
# by checking the exact path structure
ls -la ./crates/story/examples/fixtures/

Repository: BumpyClock/gpui-component

Length of output: 1313


Add an explicit suppression or refactor to avoid catching generic Exception.

The TooGenericExceptionCaught detekt rule is active and applies to this file (it's not excluded from linting). Line 65 will be flagged. Either add @Suppress("TooGenericExceptionCaught") or refactor using runCatching:

Refactor using runCatching
-fun <T> safely(block: () -> T): Result<T> = try {
-    Result.Success(block())
-} catch (e: Exception) {
-    Result.Error(e.message ?: "unknown error")
-}
+fun <T> safely(block: () -> T): Result<T> =
+    kotlin.runCatching(block).fold(
+        onSuccess = { Result.Success(it) },
+        onFailure = { Result.Error(it.message ?: "unknown error") }
+    )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun <T> safely(block: () -> T): Result<T> = try {
Result.Success(block())
} catch (e: Exception) {
Result.Error(e.message ?: "unknown error")
}
fun <T> safely(block: () -> T): Result<T> =
kotlin.runCatching(block).fold(
onSuccess = { Result.Success(it) },
onFailure = { Result.Error(it.message ?: "unknown error") }
)
🧰 Tools
🪛 detekt (1.23.8)

[warning] 65-65: The caught exception is too generic. Prefer catching specific exceptions to the case that is currently handled.

(detekt.exceptions.TooGenericExceptionCaught)

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

In `@crates/story/examples/fixtures/test.kt` around lines 63 - 67, The function
safely currently catches a generic Exception which triggers the
TooGenericExceptionCaught detekt rule; either add
`@Suppress`("TooGenericExceptionCaught") above the safely declaration to silence
the rule, or refactor safely to use Kotlin's runCatching in the safely(block: ()
-> T): Result<T> function (call runCatching { block() } and map success to
Result.Success and failure to Result.Error using the exception.message ?:
"unknown error") so you avoid an explicit catch of Exception.

Comment on lines +8 to +112
-- Module configuration with default values
local Config = {
timeout = 5000,
retries = 3,
debug = false
}

-- Enum-like table for log levels
local LogLevel = {
INFO = "INFO",
WARN = "WARN",
ERROR = "ERROR"
}

-- Create a class using metatables
local HelloWorld = {}
HelloWorld.__index = HelloWorld

function HelloWorld.new(name)
local self = setmetatable({}, HelloWorld)
self.name = name or "World"
self.config = {timeout = 5000, retries = 3, debug = false}
self.createdAt = os.time()
self._greetCount = 0 -- private-like field
return self
end

-- Method using colon syntax (implicit self)
function HelloWorld:greet(...)
local names = {...}
local results = {}

for _, name in ipairs(names) do
local greeting = string.format("Hello, %s!", name)
table.insert(results, greeting)
self._greetCount = self._greetCount + 1

if self.config.debug then
print(string.format(" [debug] %s", greeting))
end
end

return results
end

function HelloWorld:configure(newConfig)
for k, v in pairs(newConfig) do
self.config[k] = v
end
end

function HelloWorld:processNames(names)
local processed = {}

for _, name in ipairs(names or {}) do
if name ~= "" and name:match("%S") then
table.insert(processed, name:upper())
end
end

table.sort(processed)
return processed
end

function HelloWorld:generateReport()
local elapsed = os.time() - self.createdAt
local lines = {
"HelloWorld Report",
"=================",
string.format("Name: %s", self.name),
string.format("Elapsed: %ds", elapsed),
string.format("Greetings: %d", self._greetCount),
string.format("Config: timeout=%d, retries=%d",
self.config.timeout, self.config.retries)
}
return table.concat(lines, "\n")
end

-- Metatable for Result type (Success/Error)
local function Success(data)
return {success = true, data = data}
end

local function Error(message)
return {success = false, message = message}
end

-- Protected call wrapper
local function safely(fn)
local status, result = pcall(fn)
return status and Success(result) or Error(tostring(result))
end

-- Pattern matching-like function
local function describe(obj)
if obj == nil then return "nil"
elseif type(obj) == "string" then
return string.format('String(%d): "%s"', #obj, obj:sub(1, 20))
elseif type(obj) == "table" and obj.success ~= nil then
return obj.success and ("ok: " .. tostring(obj.data))
or ("err: " .. obj.message)
else
return type(obj)
end
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Luacheck W211: unused Config, LogLevel, and describe.

If luacheck runs on fixtures, these will fail linting. Consider using them in the constructor/report and in the main block (mirroring the Kotlin fixture).

🧩 Example usage to satisfy luacheck
 function HelloWorld.new(name)
     local self = setmetatable({}, HelloWorld)
     self.name = name or "World"
-    self.config = {timeout = 5000, retries = 3, debug = false}
+    self.config = {
+        timeout = Config.timeout,
+        retries = Config.retries,
+        debug = Config.debug,
+        level = LogLevel.INFO
+    }
@@
-        string.format("Config: timeout=%d, retries=%d",
-            self.config.timeout, self.config.retries)
+        string.format("Config: timeout=%d, retries=%d, level=%s",
+            self.config.timeout, self.config.retries, self.config.level)
     }
     return table.concat(lines, "\n")
 end
@@
 print("Processed: " .. table.concat(processed, ", "))
@@
 if result.success then
     print(result.data)
 else
     print("Failed: " .. result.message)
 end
+
+-- Describe samples (mirrors Kotlin fixture intent)
+print("  " .. describe("hello"))
+print("  " .. describe(42))
+print("  " .. describe(nil))
+print("  " .. describe(result))
🧰 Tools
🪛 Luacheck (1.2.0)

[warning] 9-9: unused variable 'Config'

(W211)


[warning] 16-16: unused variable 'LogLevel'

(W211)


[warning] 59-59: unused argument 'self'

(W212)


[warning] 102-102: unused function 'describe'

(W211)

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

In `@crates/story/examples/fixtures/test.lua` around lines 8 - 112, The Config,
LogLevel and describe symbols are unused and causing Luacheck W211; update
HelloWorld.new and/or HelloWorld:generateReport to reference Config and LogLevel
(for example include Config values in self.config or append LogLevel.DEFAULT to
the report) and add a small main/test block that constructs HelloWorld, calls
:generateReport() and calls describe(...) on a Success/Error and a string to
exercise the describe function (use Success/Error or safely to produce values).
Ensure the modifications reference the exact symbols Config, LogLevel, and
describe so they are no longer unused.

Comment thread crates/story/examples/fixtures/test.lua
Comment thread crates/story/examples/fixtures/test.svelte Outdated
Comment thread crates/ui/src/highlighter/highlighter.rs
Comment thread crates/ui/src/tree.rs Outdated
Comment thread docs/docs/components/table.md
BumpyClock and others added 2 commits February 22, 2026 17:00
Fix TreeState::focus to take &self, not &mut self

Document ClearSelection event in Table delegate
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/story/src/stories/floating_sidebar_story.rs`:
- Around line 43-49: Replace the hardcoded collapsed width px(48.0) with the
existing COLLAPSED_WIDTH constant from the sidebar module: update the local
collapsed_width (and any usages like content_offset) to use COLLAPSED_WIDTH so
the code reads collapsed_width = COLLAPSED_WIDTH (or remove the local var and
substitute COLLAPSED_WIDTH directly), and ensure render_example continues to
reference the same constant for consistency.

In `@crates/ui/src/floating_sidebar/mod.rs`:
- Around line 41-59: FloatingSidebar lacks the Sizable trait required for UI
components; implement impl<E: SidebarItem> Sizable for FloatingSidebar<E> and
add a with_size(self, size: impl Into<Size>) -> Self that forwards the requested
size to the inner Sidebar (or stores it on FloatingSidebar and applies to
Sidebar before layout), ensuring you handle the generic bound E: SidebarItem and
preserve other fields (collapsed, width, min_width, etc.); update any calls that
construct Sidebar inside FloatingSidebar to consume or apply the stored size so
xs/sm/md/lg sizing is respected.

In `@crates/ui/src/highlighter/highlighter.rs`:
- Around line 393-396: Avoid cloning the tree by storing new_tree directly into
self.tree and passing a reference to that stored value to
parse_combined_injections instead of calling new_tree.clone(); specifically,
replace self.tree = Some(new_tree.clone()) with assigning the owned new_tree
into self.tree (self.tree = Some(new_tree)) and then call
parse_combined_injections with a reference obtained from self.tree (e.g.,
self.tree.as_ref().unwrap() or matching on self.tree) so
parse_combined_injections(&...) receives a shared reference to the stored tree.
- Around line 467-486: The injection trees are being reused without applying the
document edit, breaking incremental parsing; in parse_combined_injections (where
you access injection_layers and layer.tree for language_name) stop passing the
stale old_tree into parser.parse_with_options — instead pass None for the old
tree so injections are parsed from scratch (simpler short-term fix), or if you
prefer to preserve incremental parsing, propagate the InputEdit from update()
into parse_combined_injections and call edit() on each old injection tree before
passing it to parser.parse_with_options.

Comment thread crates/story/src/stories/floating_sidebar_story.rs
Comment thread crates/ui/src/floating_sidebar/mod.rs
Comment thread crates/ui/src/highlighter/highlighter.rs Outdated
Comment thread crates/ui/src/highlighter/highlighter.rs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/story/src/main.rs`:
- Around line 164-171: Replace the hardcoded px(48.0) used to compute
collapsed_width in the render logic with the existing COLLAPSED_WIDTH constant
from the sidebar module to ensure consistency; update the expression that sets
collapsed_width (used when self.collapsed is true) to reference
sidebar::COLLAPSED_WIDTH (or the appropriate module path) so that sidebar_width
and content_offset derive from that constant instead of a literal.

In `@crates/ui/src/setting/settings.rs`:
- Around line 349-352: The SidebarShell currently calls
SidebarShell::left(...).resizer_width(px(0.0)) which disables the resize handle;
either remove the .resizer_width(px(0.0)) call to restore a default/visible
resizer, or (if the sidebar is intentionally non-resizable) add a one-line
inline comment next to the SidebarShell::left(...) chain explaining that the
resizer is deliberately disabled for the settings sidebar (reference:
SidebarShell::left and resizer_width(px(0.0)) in settings.rs).
- Around line 73-106: Add a unit test named test_settings_builder that
instantiates the Settings builder, chains the methods use_sidebar_shell(true),
safe_area_top(<Pixels value>), sidebar_shell_inset(<Pixels value>),
sidebar_title("title"), and page_header_action(|_, _| /* closure */), then
assert the backing fields were set: assert_eq!(settings.use_sidebar_shell,
true), assert_eq!(settings.safe_area_top, <expected Pixels>),
assert_eq!(settings.sidebar_shell_inset, <expected Pixels>),
assert_eq!(settings.sidebar_title.as_deref(), Some("title")), and
assert!(settings.page_header_action.is_some()); place this test in a
#[cfg(test)] mod tests in the same file and import any required types (Pixels,
SharedString, Rc) so the test verifies chaining and field assignment for the
methods use_sidebar_shell, safe_area_top, sidebar_shell_inset, sidebar_title,
and page_header_action.

In `@docs/docs/components/settings.md`:
- Line 95: The documentation example uses a raw integer for the inset which may
not compile because sidebar_shell_inset expects something implementing
Into<Pixels>; update the example to pass a Pixels value by calling px(8.0) (or
equivalent constructor) instead of raw 8 so sidebar_shell_inset(...) receives
the correct type; reference the sidebar_shell_inset helper and the px
constructor/Into<Pixels> conversion in the docs.

In `@docs/docs/components/sidebar.md`:
- Line 104: The documentation example uses inset(8) but inset expects an
Into<Pixels>, so update the example to call inset with a Pixels value using the
px helper (e.g., inset(px(8.0)) or inset(px(8))) and mention px/import if
needed; reference the inset method and the Pixels type to locate the example and
ensure it matches the function signature pub fn inset(mut self, inset: impl
Into<Pixels>) -> Self.

---

Duplicate comments:
In `@crates/story/src/stories/floating_sidebar_story.rs`:
- Around line 43-49: The local variable collapsed_width is hardcoded to
px(48.0); replace its usage with the existing COLLAPSED_WIDTH constant from the
sidebar module to ensure consistency. Update the code in
floating_sidebar_story.rs by removing or replacing the collapsed_width variable
and use COLLAPSED_WIDTH in the content_offset calculation (keeping sidebar_width
and inset as-is), and add the appropriate use/import if needed so
COLLAPSED_WIDTH is in scope.

In `@crates/ui/src/floating_sidebar/mod.rs`:
- Around line 41-59: FloatingSidebar lacks the Sizable trait implementation
required by project UI conventions; implement impl<E: SidebarItem + 'static>
Sizable for FloatingSidebar<E> and have its required methods (e.g., current size
getter, set_size/resize, and min/max size accessors as defined by the Sizable
trait in the codebase) read from and update the struct's fields (width,
min_width, max_width, inset, top_inset and resizer_width where applicable), and
ensure any resize callbacks (on_resize_end) are invoked when size changes so the
component behaves consistently with other sizable UI components.

Comment thread crates/story/src/main.rs
Comment thread crates/ui/src/setting/settings.rs
Comment thread crates/ui/src/setting/settings.rs
Comment thread docs/docs/components/settings.md
Comment thread docs/docs/components/sidebar.md
Add logic to ensure width is always within [min_width, max_width] range.
Update min_width and max_width setters to maintain valid constraints.
Add tests for width clamping and constraint behavior.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@crates/ui/src/floating_sidebar/mod.rs`:
- Around line 224-229: FloatingSidebar lacks Sizable support so callers can't
choose xs/sm/md/lg; add an impl and propagate the chosen size. Add a Size field
to FloatingSidebar (default Size::Md), implement impl<E: SidebarItem> Sizable
for FloatingSidebar<E> with getter and setter (e.g., size(&self) -> Size and
set_size(&mut self, s: Size) -> &mut Self), and ensure this stored size is
applied wherever the component composes children or builds styles: forward the
size to inner components (call their .size(self.size) / set_size) and apply to
the StyleRefinement/state used in render (use the size when computing
classes/styles). Update any builders/constructors to set default Size::Md if
missing.

- Use index as key in Svelte {#each} block to avoid duplicate key issues
- Refine syntax highlighter debug logs for better error context
@BumpyClock
BumpyClock merged commit 10f5867 into main Feb 23, 2026
1 check was pending

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
crates/ui/src/highlighter/highlighter.rs (1)

517-579: 🧹 Nitpick | 🔵 Trivial

Make injection layer iteration deterministic.

HashMap iteration order is nondeterministic; this can change highlight precedence across runs/edits. Consider iterating in a stable key order.

♻️ Deterministic iteration order
-        for (language_name, layer) in &self.injection_layers {
+        let mut languages: Vec<_> = self.injection_layers.keys().collect();
+        languages.sort_by(|a, b| a.as_ref().cmp(b.as_ref()));
+        for language_name in languages {
+            let Some(layer) = self.injection_layers.get(language_name) else {
+                continue;
+            };
             let Some(query) = self.injection_queries.get(language_name) else {
                 continue;
             };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/ui/src/highlighter/highlighter.rs` around lines 517 - 579, The loop
over self.injection_layers is nondeterministic because it iterates a HashMap;
make iteration deterministic by collecting the keys (language_name) into a Vec,
sort them (e.g., ascending string order), and then iterate the sorted keys to
lookup layer and query from self.injection_layers and self.injection_queries
instead of iterating the map directly; update the block that currently says "for
(language_name, layer) in &self.injection_layers" to first build and sort the
keys and then use those keys to obtain layer and query so highlight precedence
is stable across runs (references: self.injection_layers,
self.injection_queries, the injection layer loop in highlighter.rs).
♻️ Duplicate comments (1)
crates/ui/src/highlighter/highlighter.rs (1)

476-492: ⚠️ Potential issue | 🟠 Major

Don’t reuse injection trees without applying edit() first.

Tree‑sitter requires edits on old trees before incremental reuse; otherwise positions are stale and parsing can be incorrect. Easiest safe fix is to disable reuse for injections (or propagate InputEdit into this function and call edit() on each cached tree).

🛠️ Safer short‑term fix: disable incremental reuse for injections
-            // Try to reuse old tree for incremental parsing
-            let old_tree = self
-                .injection_layers
-                .get(&language_name)
-                .map(|layer| &layer.tree);
+            let old_tree = None; // full re-parse; incremental requires edit() on old tree
tree-sitter incremental parsing requirement edit() old tree parse_with_options
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/ui/src/highlighter/highlighter.rs` around lines 476 - 492, The code is
reusing cached injection trees from self.injection_layers when calling
parser.parse_with_options without applying Tree‑sitter edits, which can lead to
stale positions; either stop passing old_tree for injections (disable
incremental reuse) or accept and propagate an InputEdit into this routine and
call layer.tree.edit(&input_edit) on each cached tree before passing them to
parser.parse_with_options; update the logic around injection_layers, old_tree,
and the parse_with_options call to ensure edit() is invoked on every cached
layer.tree (or set old_tree to None) before incremental parsing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/ui/src/highlighter/highlighter.rs`:
- Around line 517-579: The loop over self.injection_layers is nondeterministic
because it iterates a HashMap; make iteration deterministic by collecting the
keys (language_name) into a Vec, sort them (e.g., ascending string order), and
then iterate the sorted keys to lookup layer and query from
self.injection_layers and self.injection_queries instead of iterating the map
directly; update the block that currently says "for (language_name, layer) in
&self.injection_layers" to first build and sort the keys and then use those keys
to obtain layer and query so highlight precedence is stable across runs
(references: self.injection_layers, self.injection_queries, the injection layer
loop in highlighter.rs).

---

Duplicate comments:
In `@crates/ui/src/highlighter/highlighter.rs`:
- Around line 476-492: The code is reusing cached injection trees from
self.injection_layers when calling parser.parse_with_options without applying
Tree‑sitter edits, which can lead to stale positions; either stop passing
old_tree for injections (disable incremental reuse) or accept and propagate an
InputEdit into this routine and call layer.tree.edit(&input_edit) on each cached
tree before passing them to parser.parse_with_options; update the logic around
injection_layers, old_tree, and the parse_with_options call to ensure edit() is
invoked on every cached layer.tree (or set old_tree to None) before incremental
parsing.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e09681 and 7a6f694.

📒 Files selected for processing (3)
  • AGENTS.md
  • crates/story/examples/fixtures/test.svelte
  • crates/ui/src/highlighter/highlighter.rs

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