Path: blob/main/extensions/copilot/test/simulation/fixtures/multiFileEdit/fsprovider/src/fileSystemProvider.ts
13406 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*--------------------------------------------------------------------------------------------*/456import * as path from 'path';7import * as vscode from 'vscode';89export class File implements vscode.FileStat {1011type: vscode.FileType;12ctime: number;13mtime: number;14size: number;1516name: string;17data?: Uint8Array;1819constructor(name: string) {20this.type = vscode.FileType.File;21this.ctime = Date.now();22this.mtime = Date.now();23this.size = 0;24this.name = name;25}26}2728export class Directory implements vscode.FileStat {2930type: vscode.FileType;31ctime: number;32mtime: number;33size: number;3435name: string;36entries: Map<string, File | Directory>;3738constructor(name: string) {39this.type = vscode.FileType.Directory;40this.ctime = Date.now();41this.mtime = Date.now();42this.size = 0;43this.name = name;44this.entries = new Map();45}46}4748export type Entry = File | Directory;4950export class MemFS implements vscode.FileSystemProvider {5152root = new Directory('');5354// --- manage file metadata5556stat(uri: vscode.Uri): vscode.FileStat {57return this._lookup(uri, false);58}5960readDirectory(uri: vscode.Uri): [string, vscode.FileType][] {61const entry = this._lookupAsDirectory(uri, false);62const result: [string, vscode.FileType][] = [];63for (const [name, child] of entry.entries) {64result.push([name, child.type]);65}66return result;67}6869// --- manage file contents7071readFile(uri: vscode.Uri): Uint8Array {72const data = this._lookupAsFile(uri, false).data;73if (data) {74return data;75}76throw vscode.FileSystemError.FileNotFound();77}7879writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void {80const basename = path.posix.basename(uri.path);81const parent = this._lookupParentDirectory(uri);82let entry = parent.entries.get(basename);83if (entry instanceof Directory) {84throw vscode.FileSystemError.FileIsADirectory(uri);85}86if (!entry && !options.create) {87throw vscode.FileSystemError.FileNotFound(uri);88}89if (entry && options.create && !options.overwrite) {90throw vscode.FileSystemError.FileExists(uri);91}92if (!entry) {93entry = new File(basename);94parent.entries.set(basename, entry);95this._fireSoon({ type: vscode.FileChangeType.Created, uri });96}97entry.mtime = Date.now();98entry.size = content.byteLength;99entry.data = content;100101this._fireSoon({ type: vscode.FileChangeType.Changed, uri });102}103104// --- manage files/folders105106rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void {107108if (!options.overwrite && this._lookup(newUri, true)) {109throw vscode.FileSystemError.FileExists(newUri);110}111112const entry = this._lookup(oldUri, false);113const oldParent = this._lookupParentDirectory(oldUri);114115const newParent = this._lookupParentDirectory(newUri);116const newName = path.posix.basename(newUri.path);117118oldParent.entries.delete(entry.name);119entry.name = newName;120newParent.entries.set(newName, entry);121122this._fireSoon(123{ type: vscode.FileChangeType.Deleted, uri: oldUri },124{ type: vscode.FileChangeType.Created, uri: newUri }125);126}127128delete(uri: vscode.Uri): void {129const dirname = uri.with({ path: path.posix.dirname(uri.path) });130const basename = path.posix.basename(uri.path);131const parent = this._lookupAsDirectory(dirname, false);132if (!parent.entries.has(basename)) {133throw vscode.FileSystemError.FileNotFound(uri);134}135parent.entries.delete(basename);136parent.mtime = Date.now();137parent.size -= 1;138this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { uri, type: vscode.FileChangeType.Deleted });139}140141createDirectory(uri: vscode.Uri): void {142const basename = path.posix.basename(uri.path);143const dirname = uri.with({ path: path.posix.dirname(uri.path) });144const parent = this._lookupAsDirectory(dirname, false);145146const entry = new Directory(basename);147parent.entries.set(entry.name, entry);148parent.mtime = Date.now();149parent.size += 1;150this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { type: vscode.FileChangeType.Created, uri });151}152153// --- lookup154155private _lookup(uri: vscode.Uri, silent: false): Entry;156private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined;157private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined {158const parts = uri.path.split('/');159let entry: Entry = this.root;160for (const part of parts) {161if (!part) {162continue;163}164let child: Entry | undefined;165if (entry instanceof Directory) {166child = entry.entries.get(part);167}168if (!child) {169if (!silent) {170throw vscode.FileSystemError.FileNotFound(uri);171} else {172return undefined;173}174}175entry = child;176}177return entry;178}179180private _lookupAsDirectory(uri: vscode.Uri, silent: boolean): Directory {181const entry = this._lookup(uri, silent);182if (entry instanceof Directory) {183return entry;184}185throw vscode.FileSystemError.FileNotADirectory(uri);186}187188private _lookupAsFile(uri: vscode.Uri, silent: boolean): File {189const entry = this._lookup(uri, silent);190if (entry instanceof File) {191return entry;192}193throw vscode.FileSystemError.FileIsADirectory(uri);194}195196private _lookupParentDirectory(uri: vscode.Uri): Directory {197const dirname = uri.with({ path: path.posix.dirname(uri.path) });198return this._lookupAsDirectory(dirname, false);199}200201// --- manage file events202203private _emitter = new vscode.EventEmitter<vscode.FileChangeEvent[]>();204private _bufferedEvents: vscode.FileChangeEvent[] = [];205private _fireSoonHandle?: NodeJS.Timer;206207readonly onDidChangeFile: vscode.Event<vscode.FileChangeEvent[]> = this._emitter.event;208209watch(_resource: vscode.Uri): vscode.Disposable {210// ignore, fires for all changes...211return new vscode.Disposable(() => { });212}213214private _fireSoon(...events: vscode.FileChangeEvent[]): void {215this._bufferedEvents.push(...events);216217if (this._fireSoonHandle) {218clearTimeout(this._fireSoonHandle);219}220221this._fireSoonHandle = setTimeout(() => {222this._emitter.fire(this._bufferedEvents);223this._bufferedEvents.length = 0;224}, 5);225}226}227// end of MemFS228229230