Files
superwork/vscode/webview-ui/src/codeReader/stickyScroll.ts
T

69 lines
3.3 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.
/**
* 钉在顶上的卡片(同 VS Code 编辑器的 Sticky Scroll,一张卡片就是一层):卡片的开头已经滚出去、卡片(连同子块)还有一部分看得见时,
* 顶上钉一行它的图标和标题,外层的在上、里层的往下摞,每行一样高。竖直坐标都以筛选栏下沿为 0、往下为正(像素)。
*/
/**
* 页面上一张能钉住的卡片:画出来了、不在编辑的(折叠着的、没有子块的也算;被筛掉的、折起来的子块没画出来,不算)。
* top 是卡片上沿,bottom 是卡片连同画出来的子块的下沿;depth 是它外面套着几张卡片;left、right 是卡片左右边(视口里的 x)
*/
export interface StickyScope {
id: string
depth: number
top: number
bottom: number
left: number
right: number
}
/** 眼下钉着的卡片,从外到里;offset 是最里那行被下面的内容往上顶了多少(≤ 0,它那张卡片快滚完时) */
export interface PinnedLines {
scopes: StickyScope[]
offset: number
}
export const NO_PINNED: PinnedLines = { scopes: [], offset: 0 }
/**
* 钉住哪几张,照 VS Code 的 `StickyScrollController.findScrollWidgetState`:按页面先后(外层在前)看每张,它那一行在 depth × lineHeight;
* 卡片上沿已经在这一行顶上面、下沿(连同子块)还没过这一行顶时钉住。下沿高过这一行的下沿时,这一行跟着往上推。
* 钉满 limit 行就不再往里看:套得深时留外层的,同 VS Code。scopes 要按页面先后排。
*/
export function pinnedLines(scopes: readonly StickyScope[], lineHeight: number, limit: number): PinnedLines {
const pinned: StickyScope[] = []
let offset = 0
for (const scope of scopes) {
if (pinned.length >= limit)
break
const top = scope.depth * lineHeight
if (top <= scope.top || top > scope.bottom)
continue
pinned.push(scope)
offset = Math.min(0, scope.bottom - (top + lineHeight))
}
return { scopes: pinned, offset }
}
/** 最多钉几行:设置里的 maxLineCount,且不超过可视区域(筛选栏下面,高 viewHeight)的四分之一,同 VS Code,窗口矮时不让钉住的行占满 */
export function lineLimit(viewHeight: number, lineHeight: number, maxLineCount: number): number {
return Math.min(maxLineCount, Math.round(viewHeight / lineHeight / 4))
}
/** 一张卡片滚到顶上时,它上面钉着多高:外层的卡片都钉住,最多 limit 行;它自己在这几行下面露出来 */
export function insetAbove(depth: number, lineHeight: number, limit: number): number {
return Math.min(depth, limit) * lineHeight
}
/** 眼下钉着的几行占多高([StickyLines](vscode/webview-ui/src/codeReader/StickyLines.tsx#StickyLines) 画的 `.cr-sticky`),没钉时是 0。 */
export function stickyHeight(): number {
return document.querySelector<HTMLElement>('.cr-sticky')?.offsetHeight ?? 0
}
/** 两次算出来钉的一样(同几张、左右位置一样、推得一样多):一样就不重画 */
export function samePinned(a: PinnedLines, b: PinnedLines): boolean {
return a.offset === b.offset && a.scopes.length === b.scopes.length && a.scopes.every((scope, index) => {
const other = b.scopes[index]
return scope.id === other.id && scope.left === other.left && scope.right === other.right
})
}