⚡ perf(vscode): 代码阅读预览按卡片订阅状态:中文名、调用树棵数、单击高亮、问答一条消息只重画受影响的卡片和文字,新文档里内容没变的块沿用原来的对象不重画,没展开又没说过的块不画问答区
This commit is contained in:
1 parent
6e2c541558
commit
0ad4748cc6
27 files changed
+1359
-620
No files matched your search
@@ -1,11 +1,26 @@
|
||||
import type { LucideIcon } from 'lucide-react'
|
||||
import type { CSSProperties, ReactElement } from 'react'
|
||||
import type { GroupStyle, Inline, SegmentGroup } from './types'
|
||||
import { useContext, useState } from 'react'
|
||||
import { DisplayNameContext, shownName } from './displayNames'
|
||||
import type { NameMap } from './displayNames'
|
||||
import type { Highlight, OccurrenceStyle } from './occurrences'
|
||||
import type { ReadableStore } from './store'
|
||||
import type { GroupStyle, Inline, Segment, SegmentGroup, ShownName } from './types'
|
||||
import { createContext, memo, useContext, useState } from 'react'
|
||||
import { sameShownName, shownName } from './displayNames'
|
||||
import { KIND_ICON_COMPONENTS } from './kindIcons'
|
||||
import { isCurrent, segmentOccurrence, sourceOf } from './occurrences'
|
||||
import { HighlightContext } from './useOccurrences'
|
||||
import { staticStore, useStore } from './store'
|
||||
|
||||
/** 页面上文字的两样标记:中文名(下标 → 显示成什么),眼下高亮着的名字(没有高亮时没有)。 */
|
||||
export interface TextMarks {
|
||||
names: NameMap
|
||||
highlight?: Highlight
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字的标记从哪份 store 读:页面上是 App 的那份(中文名、单击高亮都记在里面);定义卡片浮窗是那个文件的中文名,钉住的行不画高亮。
|
||||
* 每段文字只订阅自己那几段的标记。
|
||||
*/
|
||||
export const TextMarksContext = createContext<ReadableStore<TextMarks>>(staticStore({ names: new Map() }))
|
||||
|
||||
/**
|
||||
* 按词性给每一段上色,颜色在 codeReader.css 的 .cr-role-* 里按主题切换,带自己颜色(color)的段用它(.cr-colored);带源码下标的名字记在 data-offset 上
|
||||
@@ -13,24 +28,25 @@ import { HighlightContext } from './useOccurrences'
|
||||
* 再标 data-current。起了中文名的名字显示中文名(data-name),悬停看原名,定义处本身在后面淡淡写原名;下标照旧,跳到定义、高亮照常。
|
||||
* 带悬停提示(tooltip)的段悬停看它。
|
||||
* 框起来的一组词画成小框,框里的词同样处理。
|
||||
* 中文名和高亮只订阅自己这几段的(TextMarksContext):中文名到了、换了高亮的名字,只有字或底色变了的那几串文字重画。
|
||||
*/
|
||||
export function SegmentText({ segments }: { segments: Inline[] }): ReactElement {
|
||||
const highlight = useContext(HighlightContext)
|
||||
const names = useContext(DisplayNameContext)
|
||||
export const SegmentText = memo(({ segments }: { segments: Inline[] }): ReactElement => {
|
||||
const marks = useStore(useContext(TextMarksContext), current => segments.map(piece => 'role' in piece ? markOf(piece, current) : undefined), sameMarks)
|
||||
return (
|
||||
<>
|
||||
{segments.map((piece, index) => {
|
||||
if (!('role' in piece))
|
||||
return <GroupBox key={index} group={piece} />
|
||||
const shown = shownName(piece, names)
|
||||
const mark = marks[index]
|
||||
const shown = mark?.shown
|
||||
return (
|
||||
<span
|
||||
key={index}
|
||||
className={piece.color ? `cr-role-${piece.role} cr-colored` : `cr-role-${piece.role}`}
|
||||
style={piece.color && { '--color-dark': piece.color.dark, '--color-light': piece.color.light } as CSSProperties}
|
||||
data-offset={sourceOf(piece)?.start}
|
||||
data-occurrence={highlight && segmentOccurrence(piece, highlight.occurrences)}
|
||||
data-current={highlight && isCurrent(piece, highlight) ? '' : undefined}
|
||||
data-occurrence={mark?.occurrence}
|
||||
data-current={mark?.current ? '' : undefined}
|
||||
data-name={shown?.name}
|
||||
data-tooltip={shown ? `原名 ${piece.text}` : piece.tooltip}
|
||||
>
|
||||
@@ -41,6 +57,28 @@ export function SegmentText({ segments }: { segments: Inline[] }): ReactElement
|
||||
})}
|
||||
</>
|
||||
)
|
||||
})
|
||||
SegmentText.displayName = 'SegmentText'
|
||||
|
||||
/** 一段的标记:显示成的中文名,高亮里画哪种底色、是不是当前那一处;都没有时没有。 */
|
||||
interface SegmentMark {
|
||||
shown?: ShownName
|
||||
occurrence?: OccurrenceStyle
|
||||
current: boolean
|
||||
}
|
||||
|
||||
function markOf(piece: Segment, { names, highlight }: TextMarks): SegmentMark | undefined {
|
||||
const shown = shownName(piece, names)
|
||||
const occurrence = highlight && segmentOccurrence(piece, highlight.occurrences)
|
||||
const current = highlight !== undefined && isCurrent(piece, highlight)
|
||||
return shown || occurrence || current ? { shown, occurrence, current } : undefined
|
||||
}
|
||||
|
||||
function sameMarks(a: (SegmentMark | undefined)[], b: (SegmentMark | undefined)[]): boolean {
|
||||
return a.length === b.length && a.every((mark, index) => {
|
||||
const other = b[index]
|
||||
return mark === other || (mark !== undefined && other !== undefined && sameShownName(mark.shown, other.shown) && mark.occurrence === other.occurrence && mark.current === other.current)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user