✨ feat(vscode): 代码阅读预览单击名字高亮它在文件里的各处出现
This commit is contained in:
1 parent
5872cf7958
commit
9c0f05362c
12 files changed
+558
-9
No files matched your search
@@ -0,0 +1,133 @@
|
||||
import type { Occurrence, Segment, WebviewToExtension } from './types'
|
||||
|
||||
/** 高亮画成哪种底色,和 VS Code 编辑器一样:写入(定义、赋值)用强高亮色,读取和按文字认出的用普通高亮色。 */
|
||||
export type OccurrenceStyle = 'strong' | 'normal'
|
||||
|
||||
export function occurrenceStyle(kind: Occurrence['kind']): OccurrenceStyle {
|
||||
return kind === 'write' ? 'strong' : 'normal'
|
||||
}
|
||||
|
||||
/**
|
||||
* 一段文字画不画高亮、画哪种:它照抄自源码,在源码里占 [offset, offset + 字数),和哪处出现重叠就画,
|
||||
* 同时碰上写入和读取的按写入画。没有下标的(译词、提示词、编辑状态的源码)不画。
|
||||
*/
|
||||
export function segmentOccurrence(segment: Segment, occurrences: readonly Occurrence[]): OccurrenceStyle | undefined {
|
||||
const { offset } = segment
|
||||
if (offset === undefined)
|
||||
return undefined
|
||||
const end = offset + segment.text.length
|
||||
let style: OccurrenceStyle | undefined
|
||||
for (const occurrence of occurrences) {
|
||||
if (occurrence.start < end && offset < occurrence.end) {
|
||||
style = occurrenceStyle(occurrence.kind)
|
||||
if (style === 'strong')
|
||||
return style
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
/** 一次点击的情况,useOccurrences 从事件和页面上读出来。 */
|
||||
export interface Click {
|
||||
/** 按着 ⌘ / Ctrl / Alt / Shift:不是单纯的单击(⌘ / Ctrl + 点击归跳到定义) */
|
||||
modified: boolean
|
||||
/** 连击的第几下(MouseEvent.detail),双击的第二下是 2 */
|
||||
count: number
|
||||
/** 点完页面上有选中的文字:这是拖着选字,不是点 */
|
||||
selecting: boolean
|
||||
/** 点中的带下标的名字 */
|
||||
name?: { offset: number, text: string }
|
||||
/** 点在自己管点击的东西上:按钮、链接、输入框、下拉列表、筛选栏、属性名 */
|
||||
control: boolean
|
||||
}
|
||||
|
||||
/** find:问 offset 处名字的各处出现;clear:清掉高亮;ignore:不动 */
|
||||
export type ClickAction
|
||||
= | { kind: 'find', offset: number, name: string }
|
||||
| { kind: 'clear' }
|
||||
| { kind: 'ignore' }
|
||||
|
||||
/**
|
||||
* 单击名字就高亮,名字在折叠箭头这类按钮里也算(按钮照旧折叠);点空白处清掉;
|
||||
* 修饰键 + 点击、双击、拖着选字、点在按钮 / 链接 / 筛选栏这些自己管点击的东西上,高亮不动。
|
||||
*/
|
||||
export function clickAction(click: Click): ClickAction {
|
||||
if (click.modified || click.count > 1 || click.selecting)
|
||||
return { kind: 'ignore' }
|
||||
if (click.name)
|
||||
return { kind: 'find', offset: click.name.offset, name: click.name.text }
|
||||
return click.control ? { kind: 'ignore' } : { kind: 'clear' }
|
||||
}
|
||||
|
||||
/** 眼下高亮着的名字:点中时它的文字(筛选栏上显示)和它在文档里的各处出现。 */
|
||||
export interface Highlight {
|
||||
name: string
|
||||
occurrences: readonly Occurrence[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 单击名字高亮它在文档里的各处出现,和编辑器里一样每回点都现问扩展端,回答不留到下次用;
|
||||
* 只认最近一次询问的回答。回答到之前旧高亮留着(点同一个名字的另一处不闪),回答是空的就不高亮。
|
||||
*/
|
||||
export class OccurrenceHighlight {
|
||||
private version: number | undefined
|
||||
private translatorId: string | undefined
|
||||
/** 最近一次询问的 id;别的回答(点了别处、清掉之后才到的)都丢掉 */
|
||||
private request = 0
|
||||
/** 最近一次询问点中的名字;答过或清掉后没有 */
|
||||
private asked: string | undefined
|
||||
private current: Highlight | undefined
|
||||
|
||||
constructor(
|
||||
private readonly post: (msg: WebviewToExtension) => void,
|
||||
private readonly changed: (highlight: Highlight | undefined) => void,
|
||||
) {}
|
||||
|
||||
get highlight(): Highlight | undefined {
|
||||
return this.current
|
||||
}
|
||||
|
||||
/** 换了文档版本或翻译:下标、页面上的名字都换了,高亮清掉 */
|
||||
setDocument(version: number | undefined, translatorId: string | undefined): void {
|
||||
if (version === this.version && translatorId === this.translatorId)
|
||||
return
|
||||
this.version = version
|
||||
this.translatorId = translatorId
|
||||
this.clear()
|
||||
}
|
||||
|
||||
click(action: ClickAction): void {
|
||||
if (action.kind === 'clear')
|
||||
this.clear()
|
||||
else if (action.kind === 'find')
|
||||
this.find(action.offset, action.name)
|
||||
}
|
||||
|
||||
answer(id: number, occurrences: Occurrence[]): void {
|
||||
if (id !== this.request || this.asked === undefined)
|
||||
return
|
||||
const name = this.asked
|
||||
this.asked = undefined
|
||||
this.show(occurrences.length > 0 ? { name, occurrences } : undefined)
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.request++
|
||||
this.asked = undefined
|
||||
this.show(undefined)
|
||||
}
|
||||
|
||||
private find(offset: number, name: string): void {
|
||||
if (this.version === undefined)
|
||||
return
|
||||
this.asked = name
|
||||
this.post({ type: 'findOccurrences', id: ++this.request, version: this.version, offset })
|
||||
}
|
||||
|
||||
private show(highlight: Highlight | undefined): void {
|
||||
if (highlight === this.current)
|
||||
return
|
||||
this.current = highlight
|
||||
this.changed(highlight)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user