Skip to content

feat: 支持模糊搜索指令 - #573

Open
gdm257 wants to merge 1 commit into
ZToolsCenter:mainfrom
gdm257:pr/token-search
Open

feat: 支持模糊搜索指令#573
gdm257 wants to merge 1 commit into
ZToolsCenter:mainfrom
gdm257:pr/token-search

Conversation

@gdm257

@gdm257 gdm257 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Issues

Closes #495
Related #462 #352

Changed

  • 启用后,支持更多以词首为主搜索模式,例如 tas ma 可以匹配 Task Manager
  • 新设置项 通用设置->搜索->分词模式:默认禁用。是否聚合模式使用分词搜索、列表模式二次排序使用分词算法。禁用则回退原算法
  • 新设置项 通用设置->搜索->匹配单词内部:默认禁用,避免噪音。仅在 分词算法 启用时才显示。是否允许从非词首匹配,例如 psshop 命中 Photoshop
Before After
聚合模式 命令搜索使用 Fuse.js 模糊搜索 命令搜索使用分词搜索
列表模式 命令搜索结果为主的 commands 去重并二次排序(基于 name/是否为系统应用/使用频率/动态分数 二次排序基于分词搜索分数(更细化的静态挡位与动态加权)、使用频率

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a new word token search feature (分词搜索) that supports cross-word abbreviation matching. It includes a new tokenizer, a token search engine, a setting toggle in the general settings UI, and updated highlighting and sorting logic. The review feedback highlights several critical improvements: ensuring Vue's reactivity tracks the search setting correctly, resolving a highlighting misalignment bug for mixed pinyin/number queries by including digits in character position mapping, preventing a potential infinite loop in pinyin segmentation when encountering empty syllables, and adding defensive checks in the character classification function to handle undefined inputs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

// 合并去重后仍居前,无需在此重复处理),然后按 token 档位排序。
// 同档位内 tiebreaker:系统应用软加权 → 频率。
// 开关 OFF: 旧比较器(完全匹配 → 前缀 → 系统应用 → 频率)
if (wordTokenEnabled) {

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.

high

Issue: Access commandDataStore.wordTokenEnabled directly here to ensure Vue's reactivity system tracks the dependency correctly and re-evaluates the computed property when the setting changes.

Suggested change
if (wordTokenEnabled) {
if (commandDataStore.wordTokenEnabled) {

Comment thread src/renderer/src/utils/highlight.ts Outdated
Comment on lines +186 to +199
function getChineseCharPositions(text: string): number[] {
const positions: number[] = []
for (let i = 0; i < text.length; i++) {
const code = text.charCodeAt(i)
if (
(code >= 0x4e00 && code <= 0x9fff) ||
(code >= 0x3400 && code <= 0x4dbf) ||
(code >= 0xf900 && code <= 0xfaff)
) {
positions.push(i)
}
}
return positions
}

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.

high

🔴 Critical Highlighting Alignment Bug\n\nIssue:\nThe getChineseCharPositions function only extracts the indices of Chinese characters. However, buildPinyinFields in commandDataStore.ts includes digits 0-9 in pinyinTokens to support mixed pinyin/number queries (e.g., "360极速" -> ['3', '6', '0', 'ji', 'su']).\n\nBecause digits are omitted from getChineseCharPositions, the mapped indices for pinyin matches containing numbers will be completely misaligned, leading to incorrect characters being highlighted (e.g., searching "360" on "360极速" highlights "极速" instead of "360").\n\nResolution:\nUpdate getChineseCharPositions to also include digits 0-9 (ASCII range 0x30 to 0x39) so that it aligns perfectly with the characters processed in pinyinTokens.

Suggested change
function getChineseCharPositions(text: string): number[] {
const positions: number[] = []
for (let i = 0; i < text.length; i++) {
const code = text.charCodeAt(i)
if (
(code >= 0x4e00 && code <= 0x9fff) ||
(code >= 0x3400 && code <= 0x4dbf) ||
(code >= 0xf900 && code <= 0xfaff)
) {
positions.push(i)
}
}
return positions
}
function getChineseCharPositions(text: string): number[] {
const positions: number[] = []
for (let i = 0; i < text.length; i++) {
const code = text.charCodeAt(i)
if (
(code >= 0x4e00 && code <= 0x9fff) ||
(code >= 0x3400 && code <= 0x4dbf) ||
(code >= 0xf900 && code <= 0xfaff) ||
(code >= 0x30 && code <= 0x39)
) {
positions.push(i)
}
}
return positions
}

Comment thread src/shared/tokenSearch.ts Outdated
Comment on lines +332 to +333
for (let i = cursor; i < syllables.length; i++) {
const syl = syllables[i]

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.

high

⚠️ Potential App-Freezing Infinite Loop\n\nIssue:\nIn segmentPinyin, if any element in syllables is empty or falsy, rest.startsWith(syl) will evaluate to true (since any string starts with ""), and qStart will be incremented by syl.length (which is 0). This results in an infinite loop that freezes the entire Electron application.\n\nResolution:\nAdd a defensive check if (!syl) continue at the beginning of the loop to skip empty syllables.

Suggested change
for (let i = cursor; i < syllables.length; i++) {
const syl = syllables[i]
for (let i = cursor; i < syllables.length; i++) {
const syl = syllables[i]
if (!syl) continue

Comment thread src/shared/tokenizer.ts Outdated
Comment on lines +5 to +7
function classifyChar(ch: string): CharKind {
if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r' || ch === '_' || ch === '-')
return 'separator'

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.

medium

Issue: If classifyChar is ever called with undefined or an empty string, ch.codePointAt(0) will throw a TypeError: Cannot read properties of undefined (reading 'codePointAt'). Adding a defensive check at the beginning of the function makes it robust against unexpected inputs.

Suggested change
function classifyChar(ch: string): CharKind {
if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r' || ch === '_' || ch === '-')
return 'separator'
function classifyChar(ch: string | undefined): CharKind {
if (!ch || ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r' || ch === '_' || ch === '-')
return 'separator'

@gdm257

gdm257 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

WIP,暂转 draft
一套较为原始的分词算法(后续或考虑用三方库重构),在极力兼容原算法体验的同时,为接入更灵活的匹配方式与更多编码(如双拼)做准备

@gdm257
gdm257 marked this pull request as draft July 13, 2026 22:02
@gdm257
gdm257 marked this pull request as ready for review August 10, 2026 23:08
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.

[Feature] 间隔匹配

1 participant