Path: blob/main/src/vs/workbench/contrib/notebook/common/model/notebookMetadataTextModel.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 { toFormattedString } from '../../../../../base/common/jsonFormatter.js';6import { INotebookDocumentMetadataTextModel, INotebookTextModel, NotebookCellMetadata, NotebookCellsChangeType, NotebookDocumentMetadata, NotebookMetadataUri, TransientDocumentMetadata } from '../notebookCommon.js';7import { StringSHA1 } from '../../../../../base/common/hash.js';8import { Disposable } from '../../../../../base/common/lifecycle.js';9import { URI } from '../../../../../base/common/uri.js';10import { DefaultEndOfLine, EndOfLinePreference, ITextBuffer } from '../../../../../editor/common/model.js';11import { Emitter } from '../../../../../base/common/event.js';12import { Range } from '../../../../../editor/common/core/range.js';13import { createTextBuffer } from '../../../../../editor/common/model/textModel.js';1415export function getFormattedNotebookMetadataJSON(transientMetadata: TransientDocumentMetadata | undefined, metadata: NotebookDocumentMetadata) {16let filteredMetadata: { [key: string]: any } = {};1718if (transientMetadata) {19const keys = new Set([...Object.keys(metadata)]);20for (const key of keys) {21if (!(transientMetadata[key as keyof NotebookCellMetadata])22) {23filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata];24}25}26} else {27filteredMetadata = metadata;28}2930const metadataSource = toFormattedString(filteredMetadata, {});3132return metadataSource;33}3435export class NotebookDocumentMetadataTextModel extends Disposable implements INotebookDocumentMetadataTextModel {36public readonly uri: URI;37public get metadata(): NotebookDocumentMetadata {38return this.notebookModel.metadata;39}40private readonly _onDidChange = this._register(new Emitter<void>());41public readonly onDidChange = this._onDidChange.event;4243private _textBufferHash: string | null = null;44private _textBuffer?: ITextBuffer;45get textBuffer() {46if (this._textBuffer) {47return this._textBuffer;48}4950const source = getFormattedNotebookMetadataJSON(this.notebookModel.transientOptions.transientDocumentMetadata, this.metadata);51this._textBuffer = this._register(createTextBuffer(source, DefaultEndOfLine.LF).textBuffer);5253this._register(this._textBuffer.onDidChangeContent(() => {54this._onDidChange.fire();55}));5657return this._textBuffer;58}5960constructor(public readonly notebookModel: INotebookTextModel) {61super();62this.uri = NotebookMetadataUri.generate(this.notebookModel.uri);63this._register(this.notebookModel.onDidChangeContent((e) => {64if (e.rawEvents.some(event => event.kind === NotebookCellsChangeType.ChangeDocumentMetadata || event.kind === NotebookCellsChangeType.ModelChange)) {65this._textBuffer?.dispose();66this._textBuffer = undefined;67this._textBufferHash = null;68this._onDidChange.fire();69}70}));71}7273getHash() {74if (this._textBufferHash !== null) {75return this._textBufferHash;76}7778const shaComputer = new StringSHA1();79const snapshot = this.textBuffer.createSnapshot(false);80let text: string | null;81while ((text = snapshot.read())) {82shaComputer.update(text);83}84this._textBufferHash = shaComputer.digest();85return this._textBufferHash;86}8788public getValue() {89const fullRange = this.getFullModelRange();90const eol = this.textBuffer.getEOL();91if (eol === '\n') {92return this.textBuffer.getValueInRange(fullRange, EndOfLinePreference.LF);93} else {94return this.textBuffer.getValueInRange(fullRange, EndOfLinePreference.CRLF);95}96}97private getFullModelRange() {98const lineCount = this.textBuffer.getLineCount();99return new Range(1, 1, lineCount, this.textBuffer.getLineLength(lineCount) + 1);100}101102}103104105