Files
Thing/src/modules/quickpanel/providers/special.ts
T
2026-08-06 10:33:16 +08:00

94 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* special ProviderWindows 常用快捷位置。
* 列表由 Rust 提供(quickpanel_get_special_locations),1 分钟缓存。
*/
import { bestScore } from '../engine'
import type { QPItem, QPProvider } from './types'
import { buildItemForms } from './utils'
// Rust 端通过 tauri-specta 生成的命令绑定与类型(bindings.ts
import { commands, type SpecialLocation } from '@/lib/bindings'
let specialCache: SpecialLocation[] | null = null
let specialCacheTime = 0
const SPECIAL_CACHE_TTL = 60_000 // 1 分钟缓存
async function loadSpecials(): Promise<SpecialLocation[]> {
if (specialCache && Date.now() - specialCacheTime < SPECIAL_CACHE_TTL) {
return specialCache
}
try {
const list = await commands.quickpanelGetSpecialLocations()
specialCache = list
specialCacheTime = Date.now()
return list
} catch (e) {
console.error('[quickpanel] 获取快捷位置失败:', e)
return []
}
}
export class SpecialProvider implements QPProvider {
id = 'special'
label = '快捷'
priority = 60
async search(query: string): Promise<QPItem[]> {
const list = await loadSpecials()
if (!list.length) return []
if (!query.trim()) return [] // 空查询不占用列表,由用户主动搜索
const open = async (s: SpecialLocation) => {
try {
await commands.quickpanelOpenSpecial(s.kind, s.target, s.args)
} catch (e) {
console.error('[quickpanel] 打开快捷位置失败:', e)
}
}
const items: QPItem[] = list.map(s => ({
id: `sp-${s.id}`,
title: s.title,
subtitle: s.subtitle,
group: '快捷',
action: () => open(s),
subActions:
s.kind === 'file'
? [
{ id: 'open', label: '打开', action: () => open(s) },
{
id: 'reveal',
label: '在资源管理器中显示',
action: async () => {
try {
await commands.quickpanelRevealInExplorer(s.target)
} catch (e) {
console.error('[quickpanel] 资源管理器显示失败:', e)
}
},
},
{
id: 'copy-path',
label: '复制路径',
action: async () => {
try {
await navigator.clipboard.writeText(s.target)
} catch {
/* 忽略 */
}
},
},
]
: undefined,
}))
const scored: Array<{ item: QPItem; score: number }> = []
items.forEach((item, idx) => {
const forms = buildItemForms(item.title, list[idx].keywords)
const score = bestScore(query, forms)
if (score >= 0) scored.push({ item, score })
})
scored.sort((a, b) => b.score - a.score)
return scored.slice(0, 8).map(s => ({ ...s.item, score: s.score }))
}
}