{"version":3,"sources":["browser/monaco-editor-model.ts"],"names":[],"mappings":"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","file":"../../src/browser/monaco-editor-model.d.ts","sourcesContent":["import {TextDocumentContentChangeEvent, TextDocumentSaveReason} from 'vscode-languageserver-protocol';\r\nimport {\r\n  CancellationToken,\r\n  CancellationTokenSource,\r\n  Disposable,\r\n  DisposableCollection,\r\n  Emitter,\r\n  Event,\r\n  Resource,\r\n  ResourceError,\r\n  ResourceVersion\r\n} from '@tartjs/core/lib/common';\r\nimport {Position, Range} from 'vscode-languageserver-types';\r\nimport {Saveable, SaveOptions} from '@tartjs/core/lib/browser/saveable';\r\nimport {MonacoToProtocolConverter} from './monaco-to-protocol-converter';\r\nimport {ProtocolToMonacoConverter} from './protocol-to-monaco-converter';\r\nimport {EditorPreferences} from '@tartjs/editor/lib/browser/editor-preference';\r\nimport {EncodingMode, FindMatch, FindMatchesOptions, TextEditorDocument} from '@tartjs/editor/lib/browser/editor';\r\n\r\nexport {\r\n  TextDocumentSaveReason\r\n};\r\n\r\ntype ITextEditorModel = monaco.editor.ITextEditorModel;\r\n\r\nexport interface WillSaveMonacoModelEvent {\r\n  readonly model: MonacoEditorModel;\r\n  readonly reason: TextDocumentSaveReason;\r\n  readonly options?: SaveOptions;\r\n\r\n  waitUntil(thenable: Thenable<monaco.editor.IIdentifiedSingleEditOperation[]>): void;\r\n}\r\n\r\nexport interface MonacoModelContentChangedEvent {\r\n  readonly model: MonacoEditorModel;\r\n  readonly contentChanges: TextDocumentContentChangeEvent[];\r\n}\r\n\r\nexport class MonacoEditorModel implements ITextEditorModel, TextEditorDocument {\r\n\r\n  autoSave: 'on' | 'off' = 'on';\r\n  autoSaveDelay: number = 500;\r\n  suppressOpenEditorWhenDirty = false;\r\n  lineNumbersMinChars = 3;\r\n\r\n  /* @deprecated there is no general save timeout, each participant should introduce a sensible timeout  */\r\n  readonly onWillSaveLoopTimeOut = 1500;\r\n  protected bufferSavedVersionId: number;\r\n\r\n  protected model: monaco.editor.IModel;\r\n  protected readonly resolveModel: Promise<void>;\r\n\r\n  protected readonly toDispose = new DisposableCollection();\r\n  protected readonly toDisposeOnAutoSave = new DisposableCollection();\r\n\r\n  protected readonly onDidChangeContentEmitter = new Emitter<MonacoModelContentChangedEvent>();\r\n  readonly onDidChangeContent = this.onDidChangeContentEmitter.event;\r\n\r\n  protected readonly onDidSaveModelEmitter = new Emitter<monaco.editor.IModel>();\r\n  readonly onDidSaveModel = this.onDidSaveModelEmitter.event;\r\n\r\n  protected readonly onWillSaveModelEmitter = new Emitter<WillSaveMonacoModelEvent>();\r\n  readonly onWillSaveModel = this.onWillSaveModelEmitter.event;\r\n\r\n  protected readonly onDidChangeValidEmitter = new Emitter<void>();\r\n  readonly onDidChangeValid = this.onDidChangeValidEmitter.event;\r\n\r\n  protected readonly onDidChangeEncodingEmitter = new Emitter<string>();\r\n  readonly onDidChangeEncoding = this.onDidChangeEncodingEmitter.event;\r\n  protected resourceVersion: ResourceVersion | undefined;\r\n  protected readonly onDirtyChangedEmitter = new Emitter<void>();\r\n  protected pendingOperation = Promise.resolve();\r\n  protected syncCancellationTokenSource = new CancellationTokenSource();\r\n  protected ignoreDirtyEdits = false;\r\n  protected saveCancellationTokenSource = new CancellationTokenSource();\r\n  protected ignoreContentChanges = false;\r\n  protected readonly contentChanges: TextDocumentContentChangeEvent[] = [];\r\n  private preferredEncoding: string | undefined;\r\n  private contentEncoding: string | undefined;\r\n\r\n  constructor(\r\n      protected readonly resource: Resource,\r\n      protected readonly m2p: MonacoToProtocolConverter,\r\n      protected readonly p2m: ProtocolToMonacoConverter,\r\n      protected readonly editorPreferences?: EditorPreferences\r\n  ) {\r\n    // this.toDispose.push(resource);\r\n    this.toDispose.push(this.toDisposeOnAutoSave);\r\n    this.toDispose.push(this.onDidChangeContentEmitter);\r\n    this.toDispose.push(this.onDidSaveModelEmitter);\r\n    this.toDispose.push(this.onWillSaveModelEmitter);\r\n    this.toDispose.push(this.onDirtyChangedEmitter);\r\n    this.toDispose.push(this.onDidChangeValidEmitter);\r\n    this.toDispose.push(Disposable.create(() => this.cancelSave()));\r\n    this.toDispose.push(Disposable.create(() => this.cancelSync()));\r\n    this.resolveModel = this.readContents().then(\r\n        content => this.initialize(content || '')\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Use `valid` to access it.\r\n   * Use `setValid` to mutate it.\r\n   */\r\n  protected _valid = false;\r\n\r\n  /**\r\n   * Whether it is possible to load content from the underlying resource.\r\n   */\r\n  get valid(): boolean {\r\n    return this._valid;\r\n  }\r\n\r\n  protected _dirty = false;\r\n  get dirty(): boolean {\r\n    return this._dirty;\r\n  }\r\n\r\n  get onDirtyChanged(): Event<void> {\r\n    return this.onDirtyChangedEmitter.event;\r\n  }\r\n\r\n  get uri(): string {\r\n    return '';\r\n    // return this.resource.uri.toString();\r\n  }\r\n\r\n  protected _languageId: string | undefined;\r\n\r\n  get languageId(): string {\r\n    return this._languageId !== undefined ? this._languageId : this.model.getModeId();\r\n  }\r\n\r\n  get version(): number {\r\n    return this.model.getVersionId();\r\n  }\r\n\r\n  get lineCount(): number {\r\n    return this.model.getLineCount();\r\n  }\r\n\r\n  get readOnly(): boolean {\r\n    return this.resource.saveContents === undefined;\r\n  }\r\n\r\n  get onDispose(): monaco.IEvent<void> {\r\n    return this.toDispose.onDispose;\r\n  }\r\n\r\n  get textEditorModel(): monaco.editor.IModel {\r\n    return this.model;\r\n  }\r\n\r\n  dispose(): void {\r\n    this.toDispose.dispose();\r\n  }\r\n\r\n  setEncoding(encoding: string, mode: EncodingMode): Promise<void> {\r\n    if (mode === EncodingMode.Decode && this.dirty) {\r\n      return Promise.resolve();\r\n    }\r\n    if (!this.setPreferredEncoding(encoding)) {\r\n      return Promise.resolve();\r\n    }\r\n    if (mode === EncodingMode.Decode) {\r\n      return this.sync();\r\n    }\r\n    return this.scheduleSave(TextDocumentSaveReason.Manual, this.cancelSave(), true);\r\n  }\r\n\r\n  getEncoding(): string | undefined {\r\n    return this.preferredEncoding || this.contentEncoding;\r\n  }\r\n\r\n  /**\r\n   * It's a hack to dispatch close notification with an old language id, don't use it.\r\n   */\r\n  setLanguageId(languageId: string | undefined): void {\r\n    this._languageId = languageId;\r\n  }\r\n\r\n  /**\r\n   * Return selected text by Range or all text by default\r\n   */\r\n  getText(range?: Range): string {\r\n    if (!range) {\r\n      return this.model.getValue();\r\n    } else {\r\n      return this.model.getValueInRange(this.p2m.asRange(range));\r\n    }\r\n  }\r\n\r\n  positionAt(offset: number): Position {\r\n    const {lineNumber, column} = this.model.getPositionAt(offset);\r\n    return this.m2p.asPosition(lineNumber, column);\r\n  }\r\n\r\n  offsetAt(position: Position): number {\r\n    return this.model.getOffsetAt(this.p2m.asPosition(position));\r\n  }\r\n\r\n  /**\r\n   * Retrieves a line in a text document expressed as a one-based position.\r\n   */\r\n  getLineContent(lineNumber: number): string {\r\n    return this.model.getLineContent(lineNumber);\r\n  }\r\n\r\n  getLineMaxColumn(lineNumber: number): number {\r\n    return this.model.getLineMaxColumn(lineNumber);\r\n  }\r\n\r\n  /**\r\n   * Find all matches in an editor for the given options.\r\n   * @param options the options for finding matches.\r\n   *\r\n   * @returns the list of matches.\r\n   */\r\n  findMatches(options: FindMatchesOptions): FindMatch[] {\r\n    const wordSeparators = '`~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?';\r\n    const results: monaco.editor.FindMatch[] = this.model.findMatches(\r\n        options.searchString,\r\n        false,\r\n        options.isRegex,\r\n        options.matchCase,\r\n        // eslint-disable-next-line no-null/no-null\r\n        options.matchWholeWord ? wordSeparators : null,\r\n        true,\r\n        options.limitResultCount\r\n    );\r\n    const extractedMatches: FindMatch[] = [];\r\n    results.forEach(r => {\r\n      if (r.matches) {\r\n        extractedMatches.push({\r\n          matches: r.matches,\r\n          range: Range.create(r.range.startLineNumber, r.range.startColumn, r.range.endLineNumber, r.range.endColumn)\r\n        });\r\n      }\r\n    });\r\n    return extractedMatches;\r\n  }\r\n\r\n  async load(): Promise<MonacoEditorModel> {\r\n    await this.resolveModel;\r\n    return this;\r\n  }\r\n\r\n  save(options?: SaveOptions): Promise<void> {\r\n    return this.scheduleSave(TextDocumentSaveReason.Manual, undefined, undefined, options);\r\n  }\r\n\r\n  async sync(): Promise<void> {\r\n    const token = this.cancelSync();\r\n    return this.run(() => this.doSync(token));\r\n  }\r\n\r\n  async revert(options?: Saveable.RevertOptions): Promise<void> {\r\n    //this.trace(log => log('MonacoEditorModel.revert - enter'));\r\n    this.cancelSave();\r\n    const soft = options && options.soft;\r\n    if (soft !== true) {\r\n      const dirty = this._dirty;\r\n      this._dirty = false;\r\n      try {\r\n        await this.sync();\r\n      } finally {\r\n        this._dirty = dirty;\r\n      }\r\n    }\r\n    this.setDirty(false);\r\n    //this.trace('MonacoEditorModel.revert - exit');\r\n  }\r\n\r\n  createSnapshot(): object {\r\n    return {\r\n      value: this.getText()\r\n    };\r\n  }\r\n\r\n  applySnapshot(snapshot: { value: string }): void {\r\n    this.model.setValue(snapshot.value);\r\n  }\r\n\r\n  protected setPreferredEncoding(encoding: string): boolean {\r\n    if (encoding === this.preferredEncoding || (!this.preferredEncoding && encoding === this.contentEncoding)) {\r\n      return false;\r\n    }\r\n    this.preferredEncoding = encoding;\r\n    this.onDidChangeEncodingEmitter.fire(encoding);\r\n    return true;\r\n  }\r\n\r\n  protected updateContentEncoding(): void {\r\n    const contentEncoding = this.resource.encoding;\r\n    if (!contentEncoding || this.contentEncoding === contentEncoding) {\r\n      return;\r\n    }\r\n    this.contentEncoding = contentEncoding;\r\n    if (!this.preferredEncoding) {\r\n      this.onDidChangeEncodingEmitter.fire(contentEncoding);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * #### Important\r\n   * Only this method can create an instance of `monaco.editor.IModel`,\r\n   * there should not be other calls to `monaco.editor.createModel`.\r\n   */\r\n  protected initialize(value: string | monaco.editor.ITextBufferFactory): void {\r\n    if (!this.toDispose.disposed) {\r\n      const uri = monaco.Uri.parse(this.resource.uri.toString());\r\n      let firstLine;\r\n      if (typeof value === 'string') {\r\n        firstLine = value;\r\n        const firstLF = value.indexOf('\\n');\r\n        if (firstLF !== -1) {\r\n          firstLine = value.substring(0, firstLF);\r\n        }\r\n      } else {\r\n        firstLine = value.getFirstLineText(1000);\r\n      }\r\n      const languageSelection = monaco.services.StaticServices.modeService.get().createByFilepathOrFirstLine(uri, firstLine);\r\n      this.model = monaco.services.StaticServices.modelService.get().createModel(value, languageSelection, uri);\r\n      this.resourceVersion = this.resource.version;\r\n      this.updateSavedVersionId();\r\n      this.toDispose.push(this.model);\r\n      this.toDispose.push(this.model.onDidChangeContent(event => this.fireDidChangeContent(event)));\r\n      if (this.resource.onDidChangeContents) {\r\n        this.toDispose.push(this.resource.onDidChangeContents(() => this.sync()));\r\n      }\r\n    }\r\n  }\r\n\r\n  protected setValid(valid: boolean): void {\r\n    if (valid === this._valid) {\r\n      return;\r\n    }\r\n    this._valid = valid;\r\n    this.onDidChangeValidEmitter.fire(undefined);\r\n  }\r\n\r\n  protected setDirty(dirty: boolean): void {\r\n    if (dirty === this._dirty) {\r\n      return;\r\n    }\r\n    this._dirty = dirty;\r\n    if (dirty === false) {\r\n      this.updateSavedVersionId();\r\n    }\r\n    this.onDirtyChangedEmitter.fire(undefined);\r\n  }\r\n\r\n  protected async run(operation: () => Promise<void>): Promise<void> {\r\n    if (this.toDispose.disposed) {\r\n      return;\r\n    }\r\n    return this.pendingOperation = this.pendingOperation.then(async () => {\r\n      try {\r\n        await operation();\r\n      } catch (e) {\r\n        console.error(e);\r\n      }\r\n    });\r\n  }\r\n\r\n  protected cancelSync(): CancellationToken {\r\n    //this.trace(log => log('MonacoEditorModel.cancelSync'));\r\n    this.syncCancellationTokenSource.cancel();\r\n    this.syncCancellationTokenSource = new CancellationTokenSource();\r\n    return this.syncCancellationTokenSource.token;\r\n  }\r\n\r\n  protected async doSync(token: CancellationToken): Promise<void> {\r\n    //this.trace(log => log('MonacoEditorModel.doSync - enter'));\r\n    if (token.isCancellationRequested) {\r\n      //this.trace(log => log('MonacoEditorModel.doSync - exit - cancelled'));\r\n      return;\r\n    }\r\n\r\n    const value = await this.readContents();\r\n    if (value === undefined) {\r\n      //this.trace(log => log('MonacoEditorModel.doSync - exit - resource not found'));\r\n      return;\r\n    }\r\n    if (token.isCancellationRequested) {\r\n      //this.trace(log => log('MonacoEditorModel.doSync - exit - cancelled while looking for a resource'));\r\n      return;\r\n    }\r\n    if (this._dirty) {\r\n      //this.trace(log => log('MonacoEditorModel.doSync - exit - pending dirty changes'));\r\n      return;\r\n    }\r\n\r\n    this.resourceVersion = this.resource.version;\r\n    this.updateModel(() => monaco.services.StaticServices.modelService.get().updateModel(this.model, value), {\r\n      ignoreDirty: true,\r\n      ignoreContentChanges: true\r\n    });\r\n    //this.trace(log => log('MonacoEditorModel.doSync - exit'));\r\n  }\r\n\r\n  protected async readContents(): Promise<string | monaco.editor.ITextBufferFactory | undefined> {\r\n    try {\r\n      const options = {encoding: this.getEncoding()};\r\n      const content = await (this.resource.readStream ? this.resource.readStream(options) : this.resource.readContents(options));\r\n      let value;\r\n      if (typeof content === 'string') {\r\n        value = content;\r\n      } else {\r\n        value = monaco.textModel.createTextBufferFactoryFromStream(content);\r\n      }\r\n      this.updateContentEncoding();\r\n      this.setValid(true);\r\n      return value;\r\n    } catch (e) {\r\n      this.setValid(false);\r\n      if (ResourceError.NotFound.is(e)) {\r\n        return undefined;\r\n      }\r\n      throw e;\r\n    }\r\n  }\r\n\r\n  protected markAsDirty(): void {\r\n    //this.trace(log => log('MonacoEditorModel.markAsDirty - enter'));\r\n    if (this.ignoreDirtyEdits) {\r\n      //this.trace(log => log('MonacoEditorModel.markAsDirty - exit - ignoring dirty changes enabled'));\r\n      return;\r\n    }\r\n    this.cancelSync();\r\n    this.setDirty(true);\r\n    this.doAutoSave();\r\n    //this.trace(log => log('MonacoEditorModel.markAsDirty - exit'));\r\n  }\r\n\r\n  protected doAutoSave(): void {\r\n    if (this.autoSave === 'on') {\r\n      const token = this.cancelSave();\r\n      this.toDisposeOnAutoSave.dispose();\r\n      const handle = window.setTimeout(() => {\r\n        this.scheduleSave(TextDocumentSaveReason.AfterDelay, token);\r\n      }, this.autoSaveDelay);\r\n      this.toDisposeOnAutoSave.push(Disposable.create(() =>\r\n          window.clearTimeout(handle))\r\n      );\r\n    }\r\n  }\r\n\r\n  protected cancelSave(): CancellationToken {\r\n    //this.trace(log => log('MonacoEditorModel.cancelSave'));\r\n    this.saveCancellationTokenSource.cancel();\r\n    this.saveCancellationTokenSource = new CancellationTokenSource();\r\n    return this.saveCancellationTokenSource.token;\r\n  }\r\n\r\n  protected scheduleSave(reason: TextDocumentSaveReason, token: CancellationToken = this.cancelSave(), overwriteEncoding?: boolean, options?: SaveOptions): Promise<void> {\r\n    return this.run(() => this.doSave(reason, token, overwriteEncoding, options));\r\n  }\r\n\r\n  protected pushContentChanges(contentChanges: TextDocumentContentChangeEvent[]): void {\r\n    if (!this.ignoreContentChanges) {\r\n      this.contentChanges.push(...contentChanges);\r\n    }\r\n  }\r\n\r\n  protected fireDidChangeContent(event: monaco.editor.IModelContentChangedEvent): void {\r\n    //this.trace(log => log(`MonacoEditorModel.fireDidChangeContent - enter - ${JSON.stringify(event, undefined, 2)}`));\r\n    if (this.model.getAlternativeVersionId() === this.bufferSavedVersionId) {\r\n      this.setDirty(false);\r\n    } else {\r\n      this.markAsDirty();\r\n    }\r\n\r\n    const changeContentEvent = this.asContentChangedEvent(event);\r\n    this.onDidChangeContentEmitter.fire(changeContentEvent);\r\n    this.pushContentChanges(changeContentEvent.contentChanges);\r\n    //this.trace(log => log('MonacoEditorModel.fireDidChangeContent - exit'));\r\n  }\r\n\r\n  protected asContentChangedEvent(event: monaco.editor.IModelContentChangedEvent): MonacoModelContentChangedEvent {\r\n    const contentChanges = event.changes.map(change => this.asTextDocumentContentChangeEvent(change));\r\n    return {model: this, contentChanges};\r\n  }\r\n\r\n  protected asTextDocumentContentChangeEvent(change: monaco.editor.IModelContentChange): TextDocumentContentChangeEvent {\r\n    const range = this.m2p.asRange(change.range);\r\n    const rangeLength = change.rangeLength;\r\n    const text = change.text;\r\n    return {range, rangeLength, text};\r\n  }\r\n\r\n  protected applyEdits(\r\n      operations: monaco.editor.IIdentifiedSingleEditOperation[],\r\n      options?: Partial<MonacoEditorModel.ApplyEditsOptions>\r\n  ): void {\r\n    return this.updateModel(() => this.model.applyEdits(operations), options);\r\n  }\r\n\r\n  protected updateModel<T>(doUpdate: () => T, options?: Partial<MonacoEditorModel.ApplyEditsOptions>): T {\r\n    const resolvedOptions: MonacoEditorModel.ApplyEditsOptions = {\r\n      ignoreDirty: false,\r\n      ignoreContentChanges: false,\r\n      ...options\r\n    };\r\n    const {ignoreDirtyEdits, ignoreContentChanges} = this;\r\n    this.ignoreDirtyEdits = resolvedOptions.ignoreDirty;\r\n    this.ignoreContentChanges = resolvedOptions.ignoreContentChanges;\r\n    try {\r\n      return doUpdate();\r\n    } finally {\r\n      this.ignoreDirtyEdits = ignoreDirtyEdits;\r\n      this.ignoreContentChanges = ignoreContentChanges;\r\n    }\r\n  }\r\n\r\n  protected async doSave(reason: TextDocumentSaveReason, token: CancellationToken, overwriteEncoding?: boolean, options?: SaveOptions): Promise<void> {\r\n    if (token.isCancellationRequested || !this.resource.saveContents) {\r\n      return;\r\n    }\r\n\r\n    await this.fireWillSaveModel(reason, token, options);\r\n    if (token.isCancellationRequested) {\r\n      return;\r\n    }\r\n\r\n    const changes = [...this.contentChanges];\r\n    if (changes.length === 0 && !overwriteEncoding && reason !== TextDocumentSaveReason.Manual) {\r\n      return;\r\n    }\r\n\r\n    const contentLength = this.model.getValueLength();\r\n    const content = this.model.createSnapshot() || this.model.getValue();\r\n    try {\r\n      const encoding = this.getEncoding();\r\n      const version = this.resourceVersion;\r\n      await Resource.save(this.resource, {\r\n        changes,\r\n        content,\r\n        contentLength,\r\n        options: {encoding, overwriteEncoding, version}\r\n      }, token);\r\n      this.contentChanges.splice(0, changes.length);\r\n      this.resourceVersion = this.resource.version;\r\n      this.updateContentEncoding();\r\n      this.setValid(true);\r\n\r\n      if (token.isCancellationRequested) {\r\n        return;\r\n      }\r\n\r\n      this.setDirty(false);\r\n      this.fireDidSaveModel();\r\n    } catch (e) {\r\n      if (!ResourceError.OutOfSync.is(e)) {\r\n        throw e;\r\n      }\r\n    }\r\n  }\r\n\r\n  protected async fireWillSaveModel(reason: TextDocumentSaveReason, token: CancellationToken, options?: SaveOptions): Promise<void> {\r\n    type EditContributor = Thenable<monaco.editor.IIdentifiedSingleEditOperation[]>;\r\n\r\n    const firing = this.onWillSaveModelEmitter.sequence(async listener => {\r\n      if (token.isCancellationRequested) {\r\n        return false;\r\n      }\r\n      const waitables: EditContributor[] = [];\r\n      const {version} = this;\r\n\r\n      const event = {\r\n        model: this, reason, options,\r\n        waitUntil: (thenable: EditContributor) => {\r\n          if (Object.isFrozen(waitables)) {\r\n            throw new Error('waitUntil cannot be called asynchronously.');\r\n          }\r\n          waitables.push(thenable);\r\n        }\r\n      };\r\n\r\n      // Fire.\r\n      try {\r\n        listener(event);\r\n      } catch (err) {\r\n        console.error(err);\r\n        return true;\r\n      }\r\n\r\n      // Asynchronous calls to `waitUntil` should fail.\r\n      Object.freeze(waitables);\r\n\r\n      // Wait for all promises.\r\n      const edits = await Promise.all(waitables).then(allOperations =>\r\n          ([] as monaco.editor.IIdentifiedSingleEditOperation[]).concat(...allOperations)\r\n      );\r\n      if (token.isCancellationRequested) {\r\n        return false;\r\n      }\r\n\r\n      // In a perfect world, we should only apply edits if document is clean.\r\n      if (version !== this.version) {\r\n        console.error('onWillSave listeners should provide edits, not directly alter the document.');\r\n      }\r\n\r\n      // Finally apply edits provided by this listener before firing the next.\r\n      if (edits && edits.length > 0) {\r\n        this.applyEdits(edits, {\r\n          ignoreDirty: true,\r\n        });\r\n      }\r\n\r\n      return true;\r\n    });\r\n\r\n    try {\r\n      await firing;\r\n    } catch (e) {\r\n      console.error(e);\r\n    }\r\n  }\r\n\r\n  protected fireDidSaveModel(): void {\r\n    this.onDidSaveModelEmitter.fire(this.model);\r\n  }\r\n\r\n  protected trace(): void {\r\n    console.log(this.resource.uri.toString(true));\r\n  }\r\n\r\n  private updateSavedVersionId(): void {\r\n    this.bufferSavedVersionId = this.model.getAlternativeVersionId();\r\n  }\r\n\r\n}\r\n\r\nexport namespace MonacoEditorModel {\r\n  export interface ApplyEditsOptions {\r\n    ignoreDirty: boolean\r\n    ignoreContentChanges: boolean\r\n  }\r\n}\r\n"]}