diff --git a/addons/vscode/extension/comments/InlineCommentsProvider.ts b/addons/vscode/extension/comments/InlineCommentsProvider.ts deleted file mode 100644 index 71fc0f4927c4d..0000000000000 --- a/addons/vscode/extension/comments/InlineCommentsProvider.ts +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import type {VSCodeRepo, VSCodeReposList} from '../VSCodeRepo'; -import type {ClientToServerMessage, ServerToClientMessage} from './types'; -import type {CodeReviewProvider, DiffSummaries} from 'isl-server/src/CodeReviewProvider'; -import type {RepositoryContext} from 'isl-server/src/serverTypes'; -import type {CommitInfo, DiffComment} from 'isl/src/types'; - -import {getWebviewOptions, htmlForWebview} from '../htmlForWebview'; -import computeLineHeight from './computeLineHeight'; -import {isMac} from 'isl-components/OperatingSystem'; -import * as vscode from 'vscode'; -import {workspace} from 'vscode'; - -export class InlineCommentsProvider implements vscode.Disposable { - private disposables: Array = []; - private repoDisposables: Array = []; - constructor( - private extensionContext: vscode.ExtensionContext, - private reposList: VSCodeReposList, - private ctx: RepositoryContext, - ) { - const config = 'sapling.showDiffComments'; - if (!workspace.getConfiguration().get(config)) { - return; - } - - this.disposables.push( - this.reposList.observeActiveRepos(repos => { - for (const repo of repos) { - this.setupFetchesForRepo(repo); - } - }), - ); - } - - private setupFetchesForRepo(repo: VSCodeRepo): void { - this.repoDisposables.forEach(d => d.dispose()); - if (repo) { - const provider = repo.repo.codeReviewProvider; - if (provider == null) { - return; - } - - this.repoDisposables.push( - new InlineCommentsForRepo(this.extensionContext, repo, provider, this.ctx), - ); - } - } - - dispose(): void { - this.disposables.forEach(d => d.dispose()); - } -} - -declare module 'vscode' { - export interface WebviewEditorInset { - readonly editor: TextEditor; - readonly line: number; - height: number; - readonly webview: Webview; - readonly onDidDispose: Event; - dispose(): void; - } - - // eslint-disable-next-line @typescript-eslint/no-namespace - export namespace window { - export function createWebviewTextEditorInset( - editor: TextEditor, - line: number, - height: number, - options?: WebviewOptions, - ): WebviewEditorInset; - } -} - -class InlineCommentsForRepo implements vscode.Disposable { - private disposables: Array = []; - private currentCommentsPerFile: Map> = new Map(); - private currentDecorations: Array = []; - constructor( - private extensionContext: vscode.ExtensionContext, - private repo: VSCodeRepo, - private provider: CodeReviewProvider, - private ctx: RepositoryContext, - ) { - let currentHead = repo.repo.getHeadCommit(); - let mostRecentDiffInfos: DiffSummaries | undefined = undefined; - - // changing the head commit changes what diff ID we need to fetch comments for - this.disposables.push( - repo.repo.subscribeToHeadCommit(head => { - currentHead = head; - this.addCommentsForDiff(currentHead, mostRecentDiffInfos); - }), - ); - // periodically, diff summaries are refetched, in case comments are edited or added - this.disposables.push( - provider.onChangeDiffSummaries(result => { - mostRecentDiffInfos = result.value ?? undefined; - this.addCommentsForDiff(currentHead, mostRecentDiffInfos); - }), - ); - - this.disposables.push( - vscode.window.onDidChangeActiveTextEditor(editor => { - this.updateActiveFileDecorations(); - }), - ); - } - - private addCommentsForDiff(head: CommitInfo | undefined, summaries: DiffSummaries | undefined) { - const diffId = head?.diffId; - if (diffId == null) { - return; - } - const headDiff = summaries?.get(diffId); - if (headDiff == null) { - return; - } - - const numComments = headDiff.commentCount; - if (numComments > 0) { - this.provider.fetchComments?.(diffId).then(comments => { - this.ctx.logger.info(`Updating ${comments.length} diff comments for diff ${diffId}`); - - this.currentCommentsPerFile.clear(); - for (const comment of comments) { - if (comment.filename) { - const existing = this.currentCommentsPerFile.get(comment.filename) ?? []; - existing.push(comment); - this.currentCommentsPerFile.set(comment.filename, existing); - } - } - this.ctx.logger.info( - `Found comments for files: `, - [...this.currentCommentsPerFile.values()].join(', '), - ); - this.updateActiveFileDecorations(); - }); - } - } - - private disposeActiveFileDecorations() { - this.currentDecorations.forEach(d => d.dispose()); - this.currentDecorations = []; - } - - private updateActiveFileDecorations() { - this.disposeActiveFileDecorations(); - const editor = vscode.window.activeTextEditor; - if (editor?.viewColumn == null || editor.document.uri.scheme !== 'file') { - // this is not a real editor - return; - } - - const filepath = editor.document.uri.fsPath; - const repoRelative = this.repo.repoRelativeFsPath(editor.document.uri); - this.ctx.logger.info('udpate decorations for', filepath, repoRelative); - if (repoRelative == null) { - return; - } - - const comments = this.currentCommentsPerFile.get(repoRelative); - if (comments == null) { - return; - } - for (const comment of comments) { - if (!comment.line) { - continue; - } - const range = new vscode.Range(comment.line, 0, comment.line, 0); - - // TODO: figure out how to use navigator.userAgent to find out window or mac - // for some reason components/OperatingSystem.ts doesn't work - const initialEditorLineHeight = computeLineHeight(true); - const heightInLines = - comment.suggestedChange?.hunks.reduce((count, hunk) => count + hunk.lines.length, 0) ?? 0; - const inset = vscode.window.createWebviewTextEditorInset( - editor, - range.start.line - 2 >= 0 ? range.start.line - 2 : 0, - heightInLines, - { - enableScripts: true, - }, - ); - - inset.webview.options = getWebviewOptions(this.extensionContext, 'dist/webview'); - - inset.webview.html = htmlForWebview({ - context: this.extensionContext, - devModeScripts: ['/extension/comments/webview/inlineCommentWebview.tsx'], - entryPointFile: 'inlineCommentWebview.js', - cssEntryPointFile: 'inlineCommentWebview.css', - extensionRelativeBase: 'dist/webview', - extraStyles: '', - initialScript: ` - window.islCommentHtml = ${JSON.stringify(comment.html)}; - window.initialEditorLineHeight = ${initialEditorLineHeight}; - `, - rootClass: 'inline-comments', - title: 'Inline Comments', - webview: inset.webview, - }); - this.currentDecorations.push(inset); - - inset.webview.onDidReceiveMessage((event: ClientToServerMessage) => { - switch (event.type) { - case 'setInsetHeight': { - if (event.height && event.height >= 0) { - inset.height = event.height; - } - break; - } - case 'fetchDiffComment': { - inset.webview.postMessage({ - type: 'fetchedDiffComment', - hash: this.repo.repo.getHeadCommit()?.hash, - comment, - } as ServerToClientMessage); - break; - } - } - }); - - const decoration = vscode.window.createTextEditorDecorationType({ - overviewRulerLane: vscode.OverviewRulerLane.Left, - overviewRulerColor: '#D6D8E8', - rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed, - }); - editor.setDecorations(decoration, [{range}]); - this.currentDecorations.push(decoration); - } - } - - dispose(): void { - this.disposeActiveFileDecorations(); - this.disposables.forEach(d => d.dispose()); - } -}