mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
* feat(web-shell): show more slash commands with category headers The slash-command menu capped its visible height at exactly four rows, so with 40+ merged commands users had to scroll a thin list to find anything, and the built-in custom/skill/system grouping was only a faint 1px divider with no label. Raise the cap to min(12 rows, 40vh) and render the category name as a visible header at each group boundary (custom / skill / system), keeping the divider between groups. Sub-command menus are ungrouped and unchanged. * feat(web-shell): fuzzy-match slash commands and show per-group counts Typing in the slash menu now fuzzy-ranks commands with the same fzf engine the TUI uses, so abbreviated input like "mdl" finds "model" and "arf" finds "agent-reproduce-feature" — substring matching alone could not. An empty query still browses the category-ordered list; a non-empty query switches to a flat relevance-ranked list (headers are dropped since results interleave categories). Each category header also shows how many commands the group holds (e.g. "Skill commands 28"), so the volume hidden below the fold is visible at a glance. The fzf index is built once per command set (keyed on the array identity) and falls back to substring filtering if construction fails. * refactor(web-shell): address slash menu review feedback - Extract the section header/divider boundary logic into a pure `planSlashSectionRows` helper and unit-test it (headers at group boundaries, first row header without a divider, no repeated headers for adjacent duplicate sections, per-group counts). This also moves the section-count computation past the `!anchorRect` early return so it no longer runs on first render. - Simplify `--slash-panel-max-height` to a round `min(460px, 45vh)` instead of a `12 * rowHeight` formula that ignored header/divider overhead and so showed only ~9-10 rows; the panel now shows ~12-13 rows. - Log a warning when fzf fuzzy search throws before falling back to substring matching, so a silent failure is diagnosable. - Add a completion test for the zero-match case returning null.
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Qwen Team
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/** Per-row rendering plan for the slash command panel's section grouping. */
|
|
export interface SlashSectionRowPlan {
|
|
/** Render the category header above this row (group boundary). */
|
|
showHeader: boolean;
|
|
/** Render the divider above the header (every boundary except the first row). */
|
|
showDivider: boolean;
|
|
/** Number of rows in this row's section; 0 when no header is shown. */
|
|
count: number;
|
|
}
|
|
|
|
/**
|
|
* Decide, for each item, whether it starts a new section (and so needs a header,
|
|
* a divider, and the group count). Extracted as a pure function so the section
|
|
* boundary logic — headers at group boundaries, a header but no divider on the
|
|
* first row, and no redundant headers for adjacent duplicate sections — is unit
|
|
* testable without rendering the panel.
|
|
*
|
|
* Only 'command' menus are grouped; subcommand menus render flat (no headers).
|
|
*/
|
|
export function planSlashSectionRows(
|
|
items: ReadonlyArray<{ section?: string }>,
|
|
kind: 'command' | 'subcommand',
|
|
): SlashSectionRowPlan[] {
|
|
const counts = new Map<string, number>();
|
|
if (kind === 'command') {
|
|
for (const item of items) {
|
|
if (item.section) {
|
|
counts.set(item.section, (counts.get(item.section) ?? 0) + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
let lastSection: string | undefined;
|
|
return items.map((item, index) => {
|
|
const section = item.section;
|
|
const showHeader =
|
|
kind === 'command' && section !== undefined && section !== lastSection;
|
|
const showDivider = showHeader && index > 0;
|
|
lastSection = section ?? lastSection;
|
|
return {
|
|
showHeader,
|
|
showDivider,
|
|
count: showHeader && section ? (counts.get(section) ?? 0) : 0,
|
|
};
|
|
});
|
|
}
|