vscode/qodana/src/core/handler/index.ts (123 lines of code) (raw):

import * as vscode from 'vscode'; import { UriHandler } from 'vscode'; import { FAILED_ID_NOT_PRESENT, FAILED_PATH_NOT_PRESENT, FAILED_PREFIX_NOT_SET, FAILED_REPORT_ID_NOT_PRESENT, ID_CANCEL, ID_SET, idNotEqual, idNotSet } from '../messages'; import config, {CONF_PROJ_ID} from '../config'; import { join } from 'node:path'; import telemetry from '../telemetry'; import { Events } from '../events'; import {extensionInstance} from '../extension'; import {cloudWebsite} from '../defaults'; import {normalizeUrl} from '../auth'; export class ShowMarkerHandler implements UriHandler { private readonly context: vscode.ExtensionContext; constructor(context: vscode.ExtensionContext) { this.context = context; } async projectIdNotSet(projectId: string): Promise<boolean> { let projectIdInSettings = vscode.workspace.getConfiguration().get<string>(CONF_PROJ_ID); return new Promise<boolean>((resolve) => { if (projectId && !projectIdInSettings) { vscode.window.showErrorMessage(idNotSet(projectId), ID_SET, ID_CANCEL).then(async (value) => { if (value === ID_SET) { await vscode.workspace.getConfiguration().update(CONF_PROJ_ID, projectId, vscode.ConfigurationTarget.Workspace); } resolve(value === ID_SET); }); } else if (projectId && projectIdInSettings !== projectId) { vscode.window.showErrorMessage(idNotEqual(projectId), ID_SET, ID_CANCEL).then(async (value) => { if (value === ID_SET) { await vscode.workspace.getConfiguration().update(CONF_PROJ_ID, projectId, vscode.ConfigurationTarget.Workspace); } resolve(value === ID_SET); }); } else { resolve(true); } }); } async handleUri(uri: vscode.Uri) { if (uri.path === '/showMarker') { let query = uri.query.split('&'); let uriPathArg = query.find((value) => { return value.startsWith('path='); }); if (!uriPathArg) { vscode.window.showErrorMessage(FAILED_PATH_NOT_PRESENT); telemetry.errorReceived('#handleUri no path'); return; } let uriPath = decodeURIComponent(uriPathArg?.split('=')[1]); let cloudProjectIdArg = query.find((value) => { return value.startsWith('cloud_project_id='); }); if (!cloudProjectIdArg) { vscode.window.showErrorMessage(FAILED_ID_NOT_PRESENT); telemetry.errorReceived('#handleUri no projectId'); return; } let cloudHostArg = query.find((value) => { return value.startsWith('cloud_host='); }); if (cloudHostArg) { let authorized = extensionInstance.auth?.getAuthorized(); let cloudHost = cloudHostArg.split('=')[1]; if (!authorized || !hostsEqual(authorized.environment?.frontendUrl, cloudHost)) { await extensionInstance.auth?.logOut(); let newAuthorized = await extensionInstance.auth?.logIn(cloudHost); if (!newAuthorized) { return; } } } let cloudProjectId = cloudProjectIdArg.split('=')[1]; let projectIdAccepted = await this.projectIdNotSet(cloudProjectId); if (!projectIdAccepted) { // user didn't accept this project id return; } let cloudReportIdArg = query.find((value) => { return value.startsWith('cloud_report_id='); }); if (!cloudReportIdArg) { vscode.window.showErrorMessage(FAILED_REPORT_ID_NOT_PRESENT); telemetry.errorReceived('#handleUri no reportId'); return; } let cloudReportId = cloudReportIdArg.split('=')[1]; Events.instance.fireUrlCallback({ projectId: cloudProjectId, reportId: cloudReportId }); let pathValueParts = uriPath.split(':'); if (pathValueParts.length === 3) { let filePath = pathValueParts[0]; let line = pathValueParts[1]; let column = pathValueParts[2]; let pathPrefix = config.getAbsolutePrefix(this.context); if (pathPrefix) { let length = query.find((value) => { return value.startsWith('length='); }); let lengthValue = length?.split('=')[1] || '1'; let settings = vscode.Uri.file(join(pathPrefix, filePath)); let doc = await vscode.workspace.openTextDocument(settings); let editor = await vscode.window.showTextDocument(doc); let startPosition = new vscode.Position(Number(line) - 1, Number(column) - 1); let endPosition = new vscode.Position(Number(line) - 1, Number(column) - 1 + Number(lengthValue)); editor.selection = new vscode.Selection(startPosition, endPosition); editor.revealRange(new vscode.Range(startPosition, endPosition), vscode.TextEditorRevealType.InCenter); return; } else { vscode.window.showErrorMessage(FAILED_PREFIX_NOT_SET); telemetry.errorReceived('#handleUri no prefix'); } } } } } function hostsEqual(url1: string | undefined, url2: string | undefined): boolean { if (url1 === undefined || url2 === undefined) { return url1 === url2 || url1 === cloudWebsite() || url2 === cloudWebsite(); } const normalizedUrl1 = normalizeUrl(url1); const normalizedUrl2 = normalizeUrl(url2); const host1 = new URL(normalizedUrl1 ? normalizedUrl1 : url1); const host2 = new URL(normalizedUrl2 ? normalizedUrl2 : url2); return host1.host === host2.host; }