Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/filesystem/node/fileSystemServiceImpl.ts
13400 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as fs from 'fs';
7
import type { FileStat, FileSystemWatcher, RelativePattern, Uri } from 'vscode';
8
import { Event } from '../../../util/vs/base/common/event';
9
import { dirname, isEqual } from '../../../util/vs/base/common/resources';
10
import { URI } from '../../../util/vs/base/common/uri';
11
import { IWorkspaceService } from '../../workspace/common/workspaceService';
12
import { assertReadFileSizeLimit, IFileSystemService } from '../common/fileSystemService';
13
import { FileType } from '../common/fileTypes';
14
15
export class NodeFileSystemService implements IFileSystemService {
16
17
declare readonly _serviceBrand: undefined;
18
19
20
async stat(uri: URI): Promise<FileStat> {
21
const stat = await fs.promises.stat(uri.fsPath);
22
return {
23
type: stat.isFile() ? FileType.File : FileType.Directory,
24
ctime: stat.ctimeMs,
25
mtime: stat.mtimeMs,
26
size: stat.size
27
};
28
}
29
30
async readDirectory(uri: URI): Promise<[string, FileType][]> {
31
assetIsFileUri(uri);
32
const readDir = await fs.promises.readdir(uri.fsPath, { withFileTypes: true });
33
const result: [string, FileType][] = [];
34
for (const file of readDir) {
35
result.push([file.name, file.isFile() ? FileType.File : FileType.Directory]);
36
}
37
return result;
38
}
39
40
async createDirectory(uri: URI): Promise<void> {
41
assetIsFileUri(uri);
42
return fs.promises.mkdir(uri.fsPath);
43
}
44
45
async readFile(uri: URI, disableLimit?: boolean): Promise<Uint8Array> {
46
assetIsFileUri(uri);
47
await assertReadFileSizeLimit(this, uri, disableLimit);
48
return fs.promises.readFile(uri.fsPath);
49
}
50
51
async writeFile(uri: URI, content: Uint8Array): Promise<void> {
52
assetIsFileUri(uri);
53
await fs.promises.mkdir(dirname(uri).fsPath, { recursive: true });
54
return fs.promises.writeFile(uri.fsPath, content);
55
}
56
57
async delete(uri: URI, options?: { recursive?: boolean; useTrash?: boolean }): Promise<void> {
58
assetIsFileUri(uri);
59
return fs.promises.rm(uri.fsPath, { recursive: options?.recursive ?? false });
60
}
61
62
async rename(oldURI: URI, newURI: URI, options?: { overwrite?: boolean }): Promise<void> {
63
assetIsFileUri(oldURI);
64
assetIsFileUri(newURI);
65
// Check if new path exists if overwrite is not set return
66
if (!options?.overwrite && fs.existsSync(newURI.fsPath)) {
67
return;
68
}
69
70
return fs.promises.rename(oldURI.fsPath, newURI.fsPath);
71
}
72
73
async copy(source: URI, destination: URI, options?: { overwrite?: boolean }): Promise<void> {
74
assetIsFileUri(source);
75
assetIsFileUri(destination);
76
// Calculate copy contants based on overwrite option
77
const copyConstant = options?.overwrite ? fs.constants.COPYFILE_FICLONE : fs.constants.COPYFILE_EXCL;
78
return fs.promises.copyFile(source.fsPath, destination.fsPath, copyConstant);
79
}
80
81
isWritableFileSystem(scheme: string): boolean | undefined {
82
return true;
83
}
84
85
createFileSystemWatcher(_glob: string | RelativePattern): FileSystemWatcher {
86
return new class implements FileSystemWatcher {
87
ignoreCreateEvents = false;
88
ignoreChangeEvents = false;
89
ignoreDeleteEvents = false;
90
onDidCreate = Event.None;
91
onDidChange = Event.None;
92
onDidDelete = Event.None;
93
dispose() {
94
// noop
95
}
96
};
97
}
98
}
99
100
/**
101
* A helper utility to read a file from the open text buffer if applicable otherwise from the filesystem.
102
* This can be useful when you want to get the contents that are shown in the editor if a file is open, otherwise delegate to disk
103
* @param fileSystemService The filesystem service
104
* @param workspaceService The workspace service
105
* @param uri The uri to read
106
* @param maxBytesToRead An optional max bytes to read from the file system. If open, the entire document is always read.
107
* @returns A promise that resolves to the file content or the file buffer
108
*/
109
export async function readFileFromTextBufferOrFS(fileSystemService: IFileSystemService, workspaceService: IWorkspaceService, uri: Uri, maxBytesToRead?: number): Promise<string | Uint8Array> {
110
// First check open text documents
111
const file = workspaceService.textDocuments.find(d => isEqual(d.uri, uri));
112
if (file) {
113
return file.getText();
114
}
115
try {
116
assetIsFileUri(uri);
117
if (maxBytesToRead !== undefined) {
118
const fileHandle = await fs.promises.open(uri.fsPath, 'r');
119
try {
120
const buffer = Buffer.alloc(maxBytesToRead);
121
const { bytesRead } = await fileHandle.read(buffer, 0, maxBytesToRead, 0);
122
return buffer.subarray(0, bytesRead);
123
} finally {
124
await fileHandle.close();
125
}
126
}
127
return fileSystemService.readFile(uri);
128
} catch {
129
const buffer = await fileSystemService.readFile(uri);
130
if (maxBytesToRead) {
131
return buffer.subarray(0, maxBytesToRead);
132
}
133
return buffer;
134
}
135
}
136
137
138
function assetIsFileUri(uri: URI) {
139
if (uri.scheme !== 'file') {
140
throw new Error(`URI must be of file scheme, received ${uri.scheme}`);
141
}
142
}
143
144