Path: blob/main/src/vs/workbench/services/notebook/common/notebookDocumentService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { VSBuffer, decodeBase64, encodeBase64 } from '../../../../base/common/buffer.js';6import { ResourceMap } from '../../../../base/common/map.js';7import { Schemas } from '../../../../base/common/network.js';8import { URI } from '../../../../base/common/uri.js';9import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';10import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';1112export const INotebookDocumentService = createDecorator<INotebookDocumentService>('notebookDocumentService');1314export interface INotebookDocument {15readonly uri: URI;16getCellIndex(cellUri: URI): number | undefined;17}1819const _lengths = ['W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f'];20const _padRegexp = new RegExp(`^[${_lengths.join('')}]+`);21const _radix = 7;22export function parse(cell: URI): { notebook: URI; handle: number } | undefined {23if (cell.scheme !== Schemas.vscodeNotebookCell) {24return undefined;25}2627const idx = cell.fragment.indexOf('s');28if (idx < 0) {29return undefined;30}3132const handle = parseInt(cell.fragment.substring(0, idx).replace(_padRegexp, ''), _radix);33const _scheme = decodeBase64(cell.fragment.substring(idx + 1)).toString();3435if (isNaN(handle)) {36return undefined;37}38return {39handle,40notebook: cell.with({ scheme: _scheme, fragment: null })41};42}4344export function generate(notebook: URI, handle: number): URI {4546const s = handle.toString(_radix);47const p = s.length < _lengths.length ? _lengths[s.length - 1] : 'z';4849const fragment = `${p}${s}s${encodeBase64(VSBuffer.fromString(notebook.scheme), true, true)}`;50return notebook.with({ scheme: Schemas.vscodeNotebookCell, fragment });51}5253export function parseMetadataUri(metadata: URI): URI | undefined {54if (metadata.scheme !== Schemas.vscodeNotebookMetadata) {55return undefined;56}5758const _scheme = decodeBase64(metadata.fragment).toString();5960return metadata.with({ scheme: _scheme, fragment: null });61}6263export function generateMetadataUri(notebook: URI): URI {64const fragment = `${encodeBase64(VSBuffer.fromString(notebook.scheme), true, true)}`;65return notebook.with({ scheme: Schemas.vscodeNotebookMetadata, fragment });66}6768export function extractCellOutputDetails(uri: URI): { notebook: URI; openIn: string; outputId?: string; cellFragment?: string; outputIndex?: number; cellHandle?: number; cellIndex?: number } | undefined {69if (uri.scheme !== Schemas.vscodeNotebookCellOutput) {70return;71}7273const params = new URLSearchParams(uri.query);74const openIn = params.get('openIn');75if (!openIn) {76return;77}78const outputId = params.get('outputId') ?? undefined;79const parsedCell = parse(uri.with({ scheme: Schemas.vscodeNotebookCell, query: null }));80const outputIndex = params.get('outputIndex') ? parseInt(params.get('outputIndex') || '', 10) : undefined;81const notebookUri = parsedCell ? parsedCell.notebook : uri.with({82scheme: params.get('notebookScheme') || Schemas.file,83fragment: null,84query: null,85});86const cellIndex = params.get('cellIndex') ? parseInt(params.get('cellIndex') || '', 10) : undefined;8788return {89notebook: notebookUri,90openIn: openIn,91outputId: outputId,92outputIndex: outputIndex,93cellHandle: parsedCell?.handle,94cellFragment: uri.fragment,95cellIndex: cellIndex,96};97}9899100export interface INotebookDocumentService {101readonly _serviceBrand: undefined;102103getNotebook(uri: URI): INotebookDocument | undefined;104addNotebookDocument(document: INotebookDocument): void;105removeNotebookDocument(document: INotebookDocument): void;106}107108export class NotebookDocumentWorkbenchService implements INotebookDocumentService {109declare readonly _serviceBrand: undefined;110111private readonly _documents = new ResourceMap<INotebookDocument>();112113getNotebook(uri: URI): INotebookDocument | undefined {114if (uri.scheme === Schemas.vscodeNotebookCell) {115const cellUri = parse(uri);116if (cellUri) {117const document = this._documents.get(cellUri.notebook);118if (document) {119return document;120}121}122}123if (uri.scheme === Schemas.vscodeNotebookCellOutput) {124const parsedData = extractCellOutputDetails(uri);125if (parsedData) {126const document = this._documents.get(parsedData.notebook);127if (document) {128return document;129}130}131}132133return this._documents.get(uri);134}135136addNotebookDocument(document: INotebookDocument) {137this._documents.set(document.uri, document);138}139140removeNotebookDocument(document: INotebookDocument) {141this._documents.delete(document.uri);142}143144}145146registerSingleton(INotebookDocumentService, NotebookDocumentWorkbenchService, InstantiationType.Delayed);147148149