✨ feat(vscode): 代码阅读「未提交的更改」点文件行改成打开标准预览(和主栏一样不标差异),文件行上加「打开更改」按钮才打开对比上一次提交的预览,语言没有代码阅读的走 VS Code 自带的差异视图,删掉的文件行不挂这个按钮
This commit is contained in:
1 parent
4b6e110a44
commit
c2a13e5691
18 files changed
+211
-79
No files matched your search
@@ -208,7 +208,7 @@ export interface StickyScrollSettings {
|
||||
* openFind:打开查找栏,由「查找」命令发给活动的预览
|
||||
* moveFind:查找栏里跳到下一处(step 1)/ 上一处(step -1)命中,由「查找下一处 / 上一处」命令发给查找栏开着的预览
|
||||
* displayNames:version 这份文档里显示成中文名的名字,查到一步发一步(先本文件定义的,再别的文件定义的);不是页面上这个版本的不理
|
||||
* diff:这份文件相比对比基准改了什么(审查工作副本里的、从「未提交的更改」点开的有改动的才有,见 [对比基准](vscode/src/codeReader/diff/diffBase.ts#DiffBase)):每发一份文档之后算好了补发,
|
||||
* diff:这份文件相比对比基准改了什么(审查工作副本里的、用「未提交的更改」文件行上的「打开更改」打开的有改动的才有,见 [对比基准](vscode/src/codeReader/diff/diffBase.ts#DiffBase)):每发一份文档之后算好了补发,
|
||||
* 基准变了(提交后 HEAD 动了、换了审查的工单、文件有了改动、这个标签页换了从哪儿打开)再发;null 是不比了(退出了审查、改动提交了、从别处点开了)
|
||||
* openedFrom:这个标签页是从哪儿打开的,页面记进自己的状态,VS Code 重启后恢复这个标签页时随 ready 报回来;ready 后发一次,开着时又从侧栏点开、换了从哪儿打开的再发
|
||||
* repoLinksChecked:id 那次 checkRepoLinks 的回答,missing 是仓库里没有的路径,unresolved 是找不到的不带路径的引用(原样带回问的那几条)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { Uri } from 'vscode'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Range, workspace } from 'vscode'
|
||||
import { languageOf, linesSpot, openingFor } from './openTarget'
|
||||
import type { PreviewEditorProvider } from './previewEditor'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { commands, Range, workspace } from 'vscode'
|
||||
import { languageOf, linesSpot, openFile, openingFor } from './openTarget'
|
||||
|
||||
vi.mock('vscode', () => ({
|
||||
commands: { executeCommand: vi.fn() },
|
||||
workspace: { openTextDocument: vi.fn() },
|
||||
Range: class {
|
||||
readonly start: { line: number, character: number }
|
||||
@@ -77,3 +79,58 @@ describe('文件的语言', () => {
|
||||
expect(await languageOf({} as Uri)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('侧栏打开文件', () => {
|
||||
const uri = { path: '/ws/src/a' } as Uri
|
||||
const executeCommand = vi.mocked(commands.executeCommand)
|
||||
const previews = { open: vi.fn<PreviewEditorProvider['open']>(async () => {}) }
|
||||
|
||||
/** VS Code 把这个文件认成 languageId;undefined 是打不开成文本(图片等) */
|
||||
function languageIs(languageId: string | undefined): void {
|
||||
const openTextDocument = vi.mocked(workspace.openTextDocument)
|
||||
if (languageId === undefined)
|
||||
openTextDocument.mockRejectedValueOnce(new Error('binary'))
|
||||
else
|
||||
openTextDocument.mockResolvedValueOnce({ languageId } as Awaited<ReturnType<typeof workspace.openTextDocument>>)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
executeCommand.mockClear()
|
||||
previews.open.mockClear()
|
||||
})
|
||||
|
||||
it('「打开更改」:语言有代码阅读的用预览打开,带上 uncommitted(预览对比上一次提交)', async () => {
|
||||
languageIs('python')
|
||||
await openFile(uri, 'uncommitted', supports, previews)
|
||||
expect(previews.open).toHaveBeenCalledWith(uri, { from: 'uncommitted' })
|
||||
expect(executeCommand).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('「打开更改」:预览打不开的(语言没有代码阅读、打不开成文本)用 VS Code 自带的差异视图', async () => {
|
||||
for (const languageId of ['c', undefined]) {
|
||||
languageIs(languageId)
|
||||
await openFile(uri, 'uncommitted', supports, previews)
|
||||
expect(executeCommand).toHaveBeenLastCalledWith('git.openChange', uri)
|
||||
}
|
||||
expect(previews.open).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('点文件行:语言有代码阅读的用预览打开、带上 other(不标差异),没有的用 VS Code 默认的打开方式', async () => {
|
||||
languageIs('python')
|
||||
await openFile(uri, 'other', supports, previews)
|
||||
expect(previews.open).toHaveBeenCalledWith(uri, { from: 'other' })
|
||||
languageIs('c')
|
||||
await openFile(uri, 'other', supports, previews)
|
||||
expect(executeCommand).toHaveBeenCalledWith('vscode.open', uri, undefined)
|
||||
expect(executeCommand).not.toHaveBeenCalledWith('git.openChange', expect.anything())
|
||||
})
|
||||
|
||||
it('给了位置:预览滚过去、闪这处定义,普通编辑器选中它', async () => {
|
||||
languageIs('python')
|
||||
await openFile(uri, 'other', supports, previews, spot)
|
||||
expect(previews.open).toHaveBeenCalledWith(uri, { from: 'other', reveal: { line: 41, definition: 1200 } })
|
||||
languageIs('c')
|
||||
await openFile(uri, 'other', supports, previews, spot)
|
||||
expect(executeCommand).toHaveBeenCalledWith('vscode.open', uri, { selection: range })
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Uri } from 'vscode'
|
||||
import type { OpenedFrom } from '../diff/diffBase'
|
||||
import type { LineRange, Reveal } from './messages'
|
||||
import { Range, workspace } from 'vscode'
|
||||
import type { PreviewEditorProvider } from './previewEditor'
|
||||
import { commands, Range, workspace } from 'vscode'
|
||||
|
||||
/**
|
||||
* 别的文件里要打开的一处:普通编辑器选中 `range`;预览按 `offset`(定义处的下标)滚过去、闪这处定义。
|
||||
@@ -29,6 +31,29 @@ export function openingFor(languageId: string | undefined, supports: (languageId
|
||||
return { kind: 'default', ...(spot && { selection: spot.range }) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 侧栏打开一个文件(点文件行、点「打开更改」、点「了解一块代码」栏里的一条):语言受支持的用预览打开,告诉预览是从哪儿打开的;
|
||||
* 预览打不开的(见 [openingFor]),从「打开更改」来的用 VS Code 自带的差异视图看这个文件的改动,别处来的用 VS Code 默认的打开方式。
|
||||
*
|
||||
* @param uri 要打开的文件
|
||||
* @param from 从哪儿打开的:`uncommitted` 时预览标出和上一次提交的差异
|
||||
* @param supports 这种语言有没有代码阅读
|
||||
* @param previews 语言受支持时用它打开预览
|
||||
* @param spot 要跳到的那一处(预览滚过去、闪一下,普通编辑器选中它);只打开文件时没有
|
||||
*/
|
||||
export async function openFile(uri: Uri, from: OpenedFrom, supports: (languageId: string) => boolean, previews: Pick<PreviewEditorProvider, 'open'>, spot?: TargetSpot): Promise<void> {
|
||||
const opening = openingFor(await languageOf(uri), supports, spot)
|
||||
if (opening.kind === 'preview') {
|
||||
await previews.open(uri, { from, ...(opening.reveal && { reveal: opening.reveal }) })
|
||||
return
|
||||
}
|
||||
if (from === 'uncommitted') {
|
||||
await commands.executeCommand('git.openChange', uri)
|
||||
return
|
||||
}
|
||||
await commands.executeCommand('vscode.open', uri, opening.selection && { selection: opening.selection })
|
||||
}
|
||||
|
||||
/** 预览怎么滚到这一处:有 `offset` 的跳到定义,没有的跳到 `range` 那几行。 */
|
||||
export function revealOf({ range, offset }: TargetSpot): Reveal {
|
||||
return offset === undefined ? { line: range.start.line, endLine: range.end.line } : { line: range.start.line, definition: offset }
|
||||
|
||||
@@ -197,7 +197,7 @@ function themeColors(colors: CodeColors) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 对比基准只认从「未提交的更改」点开的:从那儿点开的对比上一次提交,别处打开的不比 */
|
||||
/** 对比基准只认用「未提交的更改」文件行上的「打开更改」打开的:这样打开的对比上一次提交,别处打开的不比 */
|
||||
function opening(profiles = { ask: profileSet(''), rewrite: profileSet('') }, colors = themeColors(COLORS), languageFor: (languageId: string) => unknown = () => undefined) {
|
||||
const subscribe = () => ({ dispose: () => {} })
|
||||
const diffBase = vi.fn((_uri: unknown, from: OpenedFrom): DiffBase | undefined => from === 'uncommitted' ? HEAD_BASE : undefined)
|
||||
@@ -276,7 +276,7 @@ function edit(document: { version: number }, version: number): void {
|
||||
const comparedWithHead = expect.objectContaining({ type: 'diff', diff: expect.objectContaining({ base: '上一次提交' }) })
|
||||
|
||||
describe('预览对比什么看这个标签页是从哪儿打开的', () => {
|
||||
it('从「未提交的更改」点开的新预览对比上一次提交,页面记下是从哪儿打开的', async () => {
|
||||
it('用「打开更改」打开的新预览对比上一次提交,页面记下是从哪儿打开的', async () => {
|
||||
const { provider, document } = opening()
|
||||
const page = tab()
|
||||
await provider.open(document.uri as never, { from: 'uncommitted' }, async () => provider.resolveCustomTextEditor(document as never, page.panel))
|
||||
@@ -307,7 +307,7 @@ describe('预览对比什么看这个标签页是从哪儿打开的', () => {
|
||||
expect(diffBase).not.toHaveBeenCalledWith(document.uri, 'uncommitted')
|
||||
})
|
||||
|
||||
it('开着的预览再从主栏点开就不比,再从「未提交的更改」点开又比;页面重新加载后按它记着的照旧比', async () => {
|
||||
it('开着的预览再点文件行打开就不比,再点「打开更改」又比;页面重新加载后按它记着的照旧比', async () => {
|
||||
const { provider, document } = opening()
|
||||
const page = tab()
|
||||
await provider.open(document.uri as never, { from: 'uncommitted' }, async () => provider.resolveCustomTextEditor(document as never, page.panel))
|
||||
|
||||
Reference in new issue
Block a user