@opensumi/ide-workspace 2.12.1-next-079c1930
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/index.d.ts +8 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +36 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/workspace-contextkey.d.ts +8 -0
- package/lib/browser/workspace-contextkey.d.ts.map +1 -0
- package/lib/browser/workspace-contextkey.js +25 -0
- package/lib/browser/workspace-contextkey.js.map +1 -0
- package/lib/browser/workspace-contribution.d.ts +16 -0
- package/lib/browser/workspace-contribution.d.ts.map +1 -0
- package/lib/browser/workspace-contribution.js +97 -0
- package/lib/browser/workspace-contribution.js.map +1 -0
- package/lib/browser/workspace-preferences.d.ts +15 -0
- package/lib/browser/workspace-preferences.d.ts.map +1 -0
- package/lib/browser/workspace-preferences.js +35 -0
- package/lib/browser/workspace-preferences.js.map +1 -0
- package/lib/browser/workspace-service.d.ts +150 -0
- package/lib/browser/workspace-service.d.ts.map +1 -0
- package/lib/browser/workspace-service.js +675 -0
- package/lib/browser/workspace-service.js.map +1 -0
- package/lib/browser/workspace-storage-service.d.ts +18 -0
- package/lib/browser/workspace-storage-service.d.ts.map +1 -0
- package/lib/browser/workspace-storage-service.js +62 -0
- package/lib/browser/workspace-storage-service.js.map +1 -0
- package/lib/browser/workspace-variable-contribution.d.ts +11 -0
- package/lib/browser/workspace-variable-contribution.d.ts.map +1 -0
- package/lib/browser/workspace-variable-contribution.js +119 -0
- package/lib/browser/workspace-variable-contribution.js.map +1 -0
- package/lib/common/index.d.ts +2 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +5 -0
- package/lib/common/index.js.map +1 -0
- package/lib/common/mocks/index.d.ts +2 -0
- package/lib/common/mocks/index.d.ts.map +1 -0
- package/lib/common/mocks/index.js +5 -0
- package/lib/common/mocks/index.js.map +1 -0
- package/lib/common/mocks/workspace-service.d.ts +44 -0
- package/lib/common/mocks/workspace-service.d.ts.map +1 -0
- package/lib/common/mocks/workspace-service.js +108 -0
- package/lib/common/mocks/workspace-service.js.map +1 -0
- package/lib/common/workspace-defination.d.ts +106 -0
- package/lib/common/workspace-defination.d.ts.map +1 -0
- package/lib/common/workspace-defination.js +145 -0
- package/lib/common/workspace-defination.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +5 -0
- package/lib/index.js.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkspaceService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const di_1 = require("@opensumi/di");
|
|
6
|
+
const common_1 = require("../common");
|
|
7
|
+
const ide_core_browser_1 = require("@opensumi/ide-core-browser");
|
|
8
|
+
const ide_core_common_1 = require("@opensumi/ide-core-common");
|
|
9
|
+
const ide_file_service_1 = require("@opensumi/ide-file-service");
|
|
10
|
+
const common_2 = require("@opensumi/ide-file-service/lib/common");
|
|
11
|
+
const common_3 = require("@opensumi/ide-file-service/lib/common");
|
|
12
|
+
const workspace_preferences_1 = require("./workspace-preferences");
|
|
13
|
+
const path_1 = require("@opensumi/ide-core-common/lib/path");
|
|
14
|
+
const jsoncparser = (0, tslib_1.__importStar)(require("jsonc-parser"));
|
|
15
|
+
let WorkspaceService = class WorkspaceService {
|
|
16
|
+
constructor() {
|
|
17
|
+
this._roots = [];
|
|
18
|
+
this.deferredRoots = new ide_core_browser_1.Deferred();
|
|
19
|
+
this._whenReady = new ide_core_browser_1.Deferred();
|
|
20
|
+
this.toDisposableCollection = new ide_core_browser_1.DisposableCollection();
|
|
21
|
+
// 映射工作区显示的文字信息
|
|
22
|
+
this.workspaceToName = {};
|
|
23
|
+
// 工作区改变事件
|
|
24
|
+
this.onWorkspaceChangeEmitter = new ide_core_browser_1.Emitter();
|
|
25
|
+
this.onWorkspaceFileExcludeChangeEmitter = new ide_core_browser_1.Emitter();
|
|
26
|
+
// 操作中的工作区改变事件
|
|
27
|
+
this.onWorkspaceLocationChangedEmitter = new ide_core_browser_1.Emitter();
|
|
28
|
+
this.toDisposeOnWorkspace = new ide_core_browser_1.DisposableCollection();
|
|
29
|
+
this.rootWatchers = new Map();
|
|
30
|
+
}
|
|
31
|
+
init() {
|
|
32
|
+
this.doInit();
|
|
33
|
+
}
|
|
34
|
+
async initFileServiceExclude() {
|
|
35
|
+
await this.setFileServiceExcludes();
|
|
36
|
+
}
|
|
37
|
+
get whenReady() {
|
|
38
|
+
return this._whenReady.promise;
|
|
39
|
+
}
|
|
40
|
+
async doInit() {
|
|
41
|
+
// 这里的 `appName` 存在默认值
|
|
42
|
+
this.applicationName = this.appConfig.appName;
|
|
43
|
+
const wpUriString = this.getDefaultWorkspacePath();
|
|
44
|
+
this.listenPreference();
|
|
45
|
+
if (wpUriString) {
|
|
46
|
+
const wpStat = await this.toFileStat(wpUriString);
|
|
47
|
+
await this.setWorkspace(wpStat);
|
|
48
|
+
this.toDisposableCollection.push(this.fileServiceClient.onFilesChanged((event) => {
|
|
49
|
+
if (this._workspace && common_2.FileChangeEvent.isAffected(event, new ide_core_common_1.URI(this._workspace.uri))) {
|
|
50
|
+
this.updateWorkspace();
|
|
51
|
+
}
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// 处理空工作区情况
|
|
56
|
+
this.deferredRoots.resolve([]);
|
|
57
|
+
}
|
|
58
|
+
this._whenReady.resolve();
|
|
59
|
+
}
|
|
60
|
+
getTemporaryWorkspaceFileUri(home) {
|
|
61
|
+
return home.resolve(this.appConfig.storageDirName || common_1.WORKSPACE_USER_STORAGE_FOLDER_NAME).resolve(`${common_1.UNTITLED_WORKSPACE}.${common_1.KAITIAN_MULTI_WORKSPACE_EXT}`).withScheme('file');
|
|
62
|
+
}
|
|
63
|
+
listenPreference() {
|
|
64
|
+
const watchExcludeName = 'files.watcherExclude';
|
|
65
|
+
const filesExcludeName = 'files.exclude';
|
|
66
|
+
const multiRootPrefName = 'workspace.supportMultiRootWorkspace';
|
|
67
|
+
this.toDisposableCollection.push(this.preferenceService.onPreferenceChanged((e) => {
|
|
68
|
+
// 工作区切换到多工作区时,可能会触发一次所有工作区配置的 Changed
|
|
69
|
+
if (e.preferenceName === watchExcludeName) {
|
|
70
|
+
this.fileServiceClient.setWatchFileExcludes(this.getFlattenExcludes(watchExcludeName));
|
|
71
|
+
}
|
|
72
|
+
else if (e.preferenceName === filesExcludeName) {
|
|
73
|
+
this.fileServiceClient.setFilesExcludes(this.getFlattenExcludes(filesExcludeName), this._roots.map((stat) => {
|
|
74
|
+
return stat.uri;
|
|
75
|
+
})).then(() => {
|
|
76
|
+
// 通知目录树更新
|
|
77
|
+
this.onWorkspaceFileExcludeChangeEmitter.fire();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else if (e.preferenceName === multiRootPrefName) {
|
|
81
|
+
this.updateWorkspace();
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
async setFileServiceExcludes() {
|
|
86
|
+
const watchExcludeName = 'files.watcherExclude';
|
|
87
|
+
const filesExcludeName = 'files.exclude';
|
|
88
|
+
await this.preferenceService.ready;
|
|
89
|
+
await this.fileServiceClient.setWatchFileExcludes(this.getFlattenExcludes(watchExcludeName));
|
|
90
|
+
await this.fileServiceClient.setFilesExcludes(this.getFlattenExcludes(filesExcludeName), this._roots.map((stat) => {
|
|
91
|
+
return stat.uri;
|
|
92
|
+
}));
|
|
93
|
+
this.onWorkspaceFileExcludeChangeEmitter.fire();
|
|
94
|
+
}
|
|
95
|
+
getFlattenExcludes(name) {
|
|
96
|
+
const excludes = [];
|
|
97
|
+
const fileExcludes = this.preferenceService.get(name);
|
|
98
|
+
if (fileExcludes) {
|
|
99
|
+
for (const key of Object.keys(fileExcludes)) {
|
|
100
|
+
if (fileExcludes[key]) {
|
|
101
|
+
excludes.push(key);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return excludes;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 获取默认的workspace路径
|
|
109
|
+
*/
|
|
110
|
+
getDefaultWorkspacePath() {
|
|
111
|
+
if (this.appConfig.workspaceDir) {
|
|
112
|
+
// 默认读取传入配置路径
|
|
113
|
+
let path;
|
|
114
|
+
try {
|
|
115
|
+
// 尝试使用 Windows 下带盘符的路径进行解析
|
|
116
|
+
path = new URL(ide_core_common_1.URI.file(this.appConfig.workspaceDir).codeUri.fsPath).toString();
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
// 解析失败时仍然使用非 Windows 环境下的解析方式
|
|
120
|
+
path = ide_core_common_1.URI.file(this.appConfig.workspaceDir).toString();
|
|
121
|
+
}
|
|
122
|
+
return path;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
get roots() {
|
|
129
|
+
return this.deferredRoots.promise;
|
|
130
|
+
}
|
|
131
|
+
tryGetRoots() {
|
|
132
|
+
return this._roots;
|
|
133
|
+
}
|
|
134
|
+
get workspace() {
|
|
135
|
+
return this._workspace;
|
|
136
|
+
}
|
|
137
|
+
get onWorkspaceChanged() {
|
|
138
|
+
return this.onWorkspaceChangeEmitter.event;
|
|
139
|
+
}
|
|
140
|
+
get onWorkspaceFileExcludeChanged() {
|
|
141
|
+
return this.onWorkspaceFileExcludeChangeEmitter.event;
|
|
142
|
+
}
|
|
143
|
+
get onWorkspaceLocationChanged() {
|
|
144
|
+
return this.onWorkspaceLocationChangedEmitter.event;
|
|
145
|
+
}
|
|
146
|
+
async setWorkspace(workspaceStat) {
|
|
147
|
+
if (ide_file_service_1.FileStat.equals(this._workspace, workspaceStat)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.toDisposeOnWorkspace.dispose();
|
|
151
|
+
this._workspace = workspaceStat;
|
|
152
|
+
if (this._workspace) {
|
|
153
|
+
const uri = new ide_core_common_1.URI(this._workspace.uri);
|
|
154
|
+
this.toDisposeOnWorkspace.push(await this.fileServiceClient.watchFileChanges(uri));
|
|
155
|
+
}
|
|
156
|
+
this.updateTitle();
|
|
157
|
+
await this.updateWorkspace();
|
|
158
|
+
}
|
|
159
|
+
async updateWorkspace() {
|
|
160
|
+
var _a;
|
|
161
|
+
if (this._workspace) {
|
|
162
|
+
this.toFileStat(this._workspace.uri).then((stat) => this._workspace = stat);
|
|
163
|
+
this.setMostRecentlyUsedWorkspace(this._workspace.uri);
|
|
164
|
+
}
|
|
165
|
+
await this.updateRoots();
|
|
166
|
+
if (!((_a = this._workspace) === null || _a === void 0 ? void 0 : _a.isDirectory)) {
|
|
167
|
+
// 工作区模式才需要额外监听根目录,否则会出现重复监听问题
|
|
168
|
+
this.watchRoots();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async updateRoots() {
|
|
172
|
+
const newRoots = await this.computeRoots();
|
|
173
|
+
let rootsChanged = false;
|
|
174
|
+
if (newRoots.length !== this._roots.length || newRoots.length === 0) {
|
|
175
|
+
rootsChanged = true;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
for (const newRoot of newRoots) {
|
|
179
|
+
if (!this._roots.some((r) => r.uri === newRoot.uri)) {
|
|
180
|
+
rootsChanged = true;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (rootsChanged) {
|
|
186
|
+
this._roots = newRoots;
|
|
187
|
+
this.deferredRoots.resolve(this._roots); // in order to resolve first
|
|
188
|
+
this.deferredRoots = new ide_core_browser_1.Deferred();
|
|
189
|
+
this.deferredRoots.resolve(this._roots);
|
|
190
|
+
this.onWorkspaceChangeEmitter.fire(this._roots);
|
|
191
|
+
// 重新根据工作区Roots设置 fileExclude 及 watchExclude
|
|
192
|
+
this.setFileServiceExcludes();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async computeRoots() {
|
|
196
|
+
const roots = [];
|
|
197
|
+
if (this._workspace) {
|
|
198
|
+
if (this._workspace.isDirectory) {
|
|
199
|
+
return [this._workspace];
|
|
200
|
+
}
|
|
201
|
+
const workspaceData = await this.getWorkspaceDataFromFile();
|
|
202
|
+
if (workspaceData) {
|
|
203
|
+
for (let { path } of workspaceData.folders) {
|
|
204
|
+
if (path === '.') {
|
|
205
|
+
path = new ide_core_common_1.URI(this._workspace.uri).parent.toString();
|
|
206
|
+
}
|
|
207
|
+
const valid = await this.toValidRoot(path);
|
|
208
|
+
if (valid) {
|
|
209
|
+
roots.push(valid);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
roots.push({
|
|
213
|
+
uri: path,
|
|
214
|
+
lastModification: Date.now(),
|
|
215
|
+
isDirectory: true,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return roots;
|
|
222
|
+
}
|
|
223
|
+
async getWorkspaceDataFromFile() {
|
|
224
|
+
if (this._workspace && await this.fileServiceClient.access(this._workspace.uri)) {
|
|
225
|
+
if (this._workspace.isDirectory) {
|
|
226
|
+
return {
|
|
227
|
+
folders: [{ path: this._workspace.uri }],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const { content } = await this.fileServiceClient.resolveContent(this._workspace.uri);
|
|
231
|
+
const strippedContent = jsoncparser.stripComments(content);
|
|
232
|
+
const data = jsoncparser.parse(strippedContent);
|
|
233
|
+
if (data && common_1.WorkspaceData.is(data)) {
|
|
234
|
+
const stat = await this.fileServiceClient.getFileStat(this._workspace.uri);
|
|
235
|
+
return common_1.WorkspaceData.transformToAbsolute(data, stat);
|
|
236
|
+
}
|
|
237
|
+
this.logger.error(`Unable to retrieve workspace data from the file: '${this._workspace.uri}'. Please check if the file is corrupted.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
formatTitle(title) {
|
|
241
|
+
const name = this.applicationName;
|
|
242
|
+
let documentTitle = title ? `${title} — ${name}` : name;
|
|
243
|
+
if (this.appConfig.extensionDevelopmentHost) {
|
|
244
|
+
documentTitle = `[${(0, ide_core_common_1.localize)('workspace.development.title')}] ${documentTitle}`;
|
|
245
|
+
}
|
|
246
|
+
return documentTitle;
|
|
247
|
+
}
|
|
248
|
+
// 更新页面Title
|
|
249
|
+
updateTitle() {
|
|
250
|
+
// 是否允许按照 workspace dir 修改 document#title
|
|
251
|
+
if (!this.appConfig.allowSetDocumentTitleFollowWorkspaceDir) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
let title;
|
|
255
|
+
if (this._workspace) {
|
|
256
|
+
const uri = new ide_core_common_1.URI(this._workspace.uri);
|
|
257
|
+
const displayName = uri.displayName;
|
|
258
|
+
if (!this._workspace.isDirectory &&
|
|
259
|
+
(displayName.endsWith(`.${common_1.KAITIAN_MULTI_WORKSPACE_EXT}`))) {
|
|
260
|
+
title = (0, ide_core_common_1.formatLocalize)('file.workspace.defaultWorkspaceTip', displayName.slice(0, displayName.lastIndexOf('.')));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
title = displayName;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
document.title = this.formatTitle(title);
|
|
267
|
+
}
|
|
268
|
+
async getMostRecentlyUsedWorkspace() {
|
|
269
|
+
await this.getGlobalRecentStorage();
|
|
270
|
+
const recentWorkspaces = await this.recentGlobalStorage.get('RECENT_WORKSPACES') || [];
|
|
271
|
+
return recentWorkspaces[0];
|
|
272
|
+
}
|
|
273
|
+
async setMostRecentlyUsedWorkspace(path) {
|
|
274
|
+
await this.getGlobalRecentStorage();
|
|
275
|
+
const recentWorkspaces = await this.recentGlobalStorage.get('RECENT_WORKSPACES') || [];
|
|
276
|
+
recentWorkspaces.unshift(path);
|
|
277
|
+
await this.recentGlobalStorage.set('RECENT_WORKSPACES', Array.from(new Set(recentWorkspaces)));
|
|
278
|
+
}
|
|
279
|
+
async getMostRecentlyUsedWorkspaces() {
|
|
280
|
+
await this.getGlobalRecentStorage();
|
|
281
|
+
const recentWorkspaces = await this.recentGlobalStorage.get('RECENT_WORKSPACES') || [];
|
|
282
|
+
return recentWorkspaces;
|
|
283
|
+
}
|
|
284
|
+
async getMostRecentlyUsedCommands() {
|
|
285
|
+
await this.getGlobalRecentStorage();
|
|
286
|
+
const recentCommands = await this.recentGlobalStorage.get('RECENT_COMMANDS') || [];
|
|
287
|
+
return recentCommands;
|
|
288
|
+
}
|
|
289
|
+
async setMostRecentlyUsedCommand(commandId) {
|
|
290
|
+
await this.getGlobalRecentStorage();
|
|
291
|
+
const recentCommands = await this.recentGlobalStorage.get('RECENT_COMMANDS') || [];
|
|
292
|
+
const commandIndex = recentCommands.indexOf(commandId);
|
|
293
|
+
// 重新排到队列顶部
|
|
294
|
+
if (commandIndex > 0) {
|
|
295
|
+
recentCommands.splice(commandIndex, 1);
|
|
296
|
+
}
|
|
297
|
+
recentCommands.unshift(commandId);
|
|
298
|
+
await this.recentGlobalStorage.set('RECENT_COMMANDS', recentCommands);
|
|
299
|
+
}
|
|
300
|
+
async getGlobalRecentStorage() {
|
|
301
|
+
this.recentGlobalStorage = this.recentGlobalStorage || await this.storageProvider(ide_core_common_1.STORAGE_NAMESPACE.GLOBAL_RECENT_DATA);
|
|
302
|
+
await this.recentGlobalStorage.whenReady;
|
|
303
|
+
return this.recentGlobalStorage;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 当已经存在打开的工作区时,返回true
|
|
307
|
+
* @returns {boolean}
|
|
308
|
+
*/
|
|
309
|
+
get opened() {
|
|
310
|
+
return !!this._workspace;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* 当一个混合工作区打开时,返回 true
|
|
314
|
+
* @returns {boolean}
|
|
315
|
+
*/
|
|
316
|
+
get isMultiRootWorkspaceOpened() {
|
|
317
|
+
return !!this.workspace && !this.workspace.isDirectory;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 当前存在打开的工作区同时支持混合工作区时,返回true
|
|
321
|
+
* @returns {boolean}
|
|
322
|
+
*/
|
|
323
|
+
get isMultiRootWorkspaceEnabled() {
|
|
324
|
+
return this.opened && this.preferences['workspace.supportMultiRootWorkspace'];
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* 打开一个文件夹或创建一个工作区
|
|
328
|
+
* @param {URI} uri
|
|
329
|
+
* @param {WorkspaceInput} [options]
|
|
330
|
+
* @memberof WorkspaceService
|
|
331
|
+
*/
|
|
332
|
+
async open(uri, options) {
|
|
333
|
+
await this.doOpen(uri, options);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 需要判断是否在当前工作区打开窗口
|
|
337
|
+
* 在这里传入的options优先级高于preference设置
|
|
338
|
+
* @protected
|
|
339
|
+
* @param {URI} uri
|
|
340
|
+
* @param {WorkspaceInput} [options]
|
|
341
|
+
* @returns {Promise<void>}
|
|
342
|
+
* @memberof WorkspaceService
|
|
343
|
+
*/
|
|
344
|
+
async doOpen(uri, options) {
|
|
345
|
+
const rootUri = uri.toString();
|
|
346
|
+
const stat = await this.toFileStat(rootUri);
|
|
347
|
+
if (stat) {
|
|
348
|
+
await this.roots;
|
|
349
|
+
const { preserveWindow } = Object.assign({ preserveWindow: this.preferences['workspace.preserveWindow'] || !this.opened }, options);
|
|
350
|
+
if (preserveWindow) {
|
|
351
|
+
this._workspace = stat;
|
|
352
|
+
}
|
|
353
|
+
this.openWindow(stat, { preserveWindow });
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
throw new Error('Invalid workspace root URI. Expected an existing directory location.');
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* 为工作区设置根目录
|
|
360
|
+
* @param uri
|
|
361
|
+
*/
|
|
362
|
+
async addRoot(uri) {
|
|
363
|
+
await this.spliceRoots(this._roots.length, 0, {}, uri);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* 工作区中移除对应根目录
|
|
367
|
+
*/
|
|
368
|
+
async removeRoots(uris) {
|
|
369
|
+
if (!this.opened) {
|
|
370
|
+
throw new Error('Folder cannot be removed as there is no active folder in the current workspace.');
|
|
371
|
+
}
|
|
372
|
+
if (this._workspace) {
|
|
373
|
+
const workspaceData = await this.getWorkspaceDataFromFile();
|
|
374
|
+
this._workspace = await this.writeWorkspaceFile(this._workspace, common_1.WorkspaceData.buildWorkspaceData(this._roots.filter((root) => uris.findIndex((u) => u.toString() === root.uri) < 0), workspaceData.settings));
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async spliceRoots(start, deleteCount = 0, workspaceToName = {}, ...rootsToAdd) {
|
|
378
|
+
if (!this._workspace) {
|
|
379
|
+
throw new Error('There is not active workspace');
|
|
380
|
+
}
|
|
381
|
+
const dedup = new Set();
|
|
382
|
+
const roots = this._roots.map((root) => (dedup.add(root.uri), root.uri));
|
|
383
|
+
const toAdd = [];
|
|
384
|
+
// 更新工作区映射
|
|
385
|
+
for (const uri of Object.keys(workspaceToName)) {
|
|
386
|
+
this.workspaceToName[new ide_core_common_1.URI(uri).toString()] = workspaceToName[uri];
|
|
387
|
+
}
|
|
388
|
+
for (const root of rootsToAdd) {
|
|
389
|
+
const uri = root.toString();
|
|
390
|
+
if (!dedup.has(uri)) {
|
|
391
|
+
dedup.add(uri);
|
|
392
|
+
toAdd.push(uri);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const toRemove = roots.splice(start, deleteCount || 0, ...toAdd);
|
|
396
|
+
if (!toRemove.length && !toAdd.length) {
|
|
397
|
+
return [];
|
|
398
|
+
}
|
|
399
|
+
if (this._workspace.isDirectory) {
|
|
400
|
+
const untitledWorkspace = await this.getUntitledWorkspace();
|
|
401
|
+
if (untitledWorkspace) {
|
|
402
|
+
await this.save(untitledWorkspace);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const currentData = await this.getWorkspaceDataFromFile();
|
|
406
|
+
const newData = common_1.WorkspaceData.buildWorkspaceData(roots, currentData && currentData.settings);
|
|
407
|
+
await this.writeWorkspaceFile(this._workspace, newData);
|
|
408
|
+
return toRemove.map((root) => new ide_core_common_1.URI(root));
|
|
409
|
+
}
|
|
410
|
+
getWorkspaceName(uri) {
|
|
411
|
+
return this.workspaceToName[uri.toString()] || this.workspaceToName[uri.toString() + path_1.Path.separator] || uri.displayName;
|
|
412
|
+
}
|
|
413
|
+
async getUntitledWorkspace() {
|
|
414
|
+
const home = await this.fileServiceClient.getCurrentUserHome();
|
|
415
|
+
return home && this.getTemporaryWorkspaceFileUri(new ide_core_common_1.URI(home.uri));
|
|
416
|
+
}
|
|
417
|
+
async writeWorkspaceFile(workspaceFile, workspaceData) {
|
|
418
|
+
if (workspaceFile) {
|
|
419
|
+
const data = JSON.stringify(common_1.WorkspaceData.transformToRelative(workspaceData, workspaceFile));
|
|
420
|
+
const edits = jsoncparser.format(data, undefined, { tabSize: 2, insertSpaces: true, eol: '' });
|
|
421
|
+
const result = jsoncparser.applyEdits(data, edits);
|
|
422
|
+
const stat = await this.fileServiceClient.setContent(workspaceFile, result);
|
|
423
|
+
if (!stat) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
return stat;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* 清理当前workspace
|
|
431
|
+
*/
|
|
432
|
+
async close() {
|
|
433
|
+
this._workspace = undefined;
|
|
434
|
+
this._roots.length = 0;
|
|
435
|
+
this.reloadWindow();
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* 验证给定的URI是否为有效根目录
|
|
439
|
+
*/
|
|
440
|
+
async toValidRoot(uri) {
|
|
441
|
+
const fileStat = await this.toFileStat(uri);
|
|
442
|
+
if (fileStat && fileStat.isDirectory) {
|
|
443
|
+
return fileStat;
|
|
444
|
+
}
|
|
445
|
+
return undefined;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 返回文件的FileStat
|
|
449
|
+
*/
|
|
450
|
+
async toFileStat(uri) {
|
|
451
|
+
if (!uri) {
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
let uriStr = uri.toString();
|
|
455
|
+
try {
|
|
456
|
+
if (uriStr.endsWith('/')) {
|
|
457
|
+
uriStr = uriStr.slice(0, -1);
|
|
458
|
+
}
|
|
459
|
+
const fileStat = await this.fileServiceClient.getFileStat(uriStr);
|
|
460
|
+
if (!fileStat) {
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
return fileStat;
|
|
464
|
+
}
|
|
465
|
+
catch (error) {
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
openWindow(fileStat, options) {
|
|
470
|
+
const workspacePath = new ide_core_common_1.URI(fileStat.uri).path.toString();
|
|
471
|
+
if (this.shouldPreserveWindow(options)) {
|
|
472
|
+
this.reloadWindow();
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
try {
|
|
476
|
+
this.openNewWindow(workspacePath);
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
// Fall back to reloading the current window in case the browser has blocked the new window
|
|
480
|
+
this._workspace = fileStat;
|
|
481
|
+
this.logger.error(error.toString());
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
reloadWindow() {
|
|
486
|
+
this.clientApp.fireOnReload(true);
|
|
487
|
+
}
|
|
488
|
+
openNewWindow(workspacePath) {
|
|
489
|
+
const url = new URL(window.location.href);
|
|
490
|
+
url.hash = workspacePath;
|
|
491
|
+
this.windowService.openNewWindow(url.toString());
|
|
492
|
+
}
|
|
493
|
+
shouldPreserveWindow(options) {
|
|
494
|
+
return options !== undefined && !!options.preserveWindow;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* 返回根目录下是否存在对应相对路径文件
|
|
498
|
+
*/
|
|
499
|
+
async containsSome(paths) {
|
|
500
|
+
await this.roots;
|
|
501
|
+
if (this.opened) {
|
|
502
|
+
for (const root of this._roots) {
|
|
503
|
+
const uri = new ide_core_common_1.URI(root.uri);
|
|
504
|
+
for (const path of paths) {
|
|
505
|
+
const fileUri = uri.resolve(path).toString();
|
|
506
|
+
const exists = await this.fileServiceClient.access(fileUri);
|
|
507
|
+
if (exists) {
|
|
508
|
+
return exists;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
get saved() {
|
|
516
|
+
return !!this._workspace && !this._workspace.isDirectory;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* 存储工作区数据到文件中
|
|
520
|
+
* @param uri URI or FileStat of the workspace file
|
|
521
|
+
*/
|
|
522
|
+
async save(uri) {
|
|
523
|
+
const uriStr = uri instanceof ide_core_common_1.URI ? uri.toString() : uri.uri;
|
|
524
|
+
if (!await this.fileServiceClient.access(uriStr)) {
|
|
525
|
+
await this.fileServiceClient.createFile(uriStr);
|
|
526
|
+
}
|
|
527
|
+
const workspaceData = { folders: [], settings: {} };
|
|
528
|
+
if (!this.saved) {
|
|
529
|
+
for (const p of Object.keys(this.schemaProvider.getCombinedSchema().properties)) {
|
|
530
|
+
if (this.schemaProvider.isValidInScope(p, ide_core_browser_1.PreferenceScope.Folder)) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
const preferences = this.preferenceService.inspect(p);
|
|
534
|
+
if (preferences && preferences.workspaceValue) {
|
|
535
|
+
workspaceData.settings[p] = preferences.workspaceValue;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
let stat = await this.toFileStat(uriStr);
|
|
540
|
+
Object.assign(workspaceData, await this.getWorkspaceDataFromFile());
|
|
541
|
+
stat = await this.writeWorkspaceFile(stat, common_1.WorkspaceData.buildWorkspaceData(this._roots, workspaceData ? workspaceData.settings : undefined));
|
|
542
|
+
await this.setWorkspace(stat);
|
|
543
|
+
this.onWorkspaceLocationChangedEmitter.fire(stat);
|
|
544
|
+
}
|
|
545
|
+
// 监听所有根路径变化
|
|
546
|
+
async watchRoots() {
|
|
547
|
+
const rootUris = new Set(this._roots.map((r) => r.uri));
|
|
548
|
+
for (const [uri, watcher] of this.rootWatchers.entries()) {
|
|
549
|
+
if (!rootUris.has(uri)) {
|
|
550
|
+
watcher.dispose();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
for (const root of this._roots) {
|
|
554
|
+
this.watchRoot(root);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// 监听根路径变化
|
|
558
|
+
async watchRoot(root) {
|
|
559
|
+
const uriStr = root.uri;
|
|
560
|
+
if (this.rootWatchers.has(uriStr)) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const watcher = this.fileServiceClient.watchFileChanges(new ide_core_common_1.URI(root.uri));
|
|
564
|
+
this.rootWatchers.set(uriStr, ide_core_browser_1.Disposable.create(() => {
|
|
565
|
+
watcher.then((disposable) => disposable.dispose());
|
|
566
|
+
this.rootWatchers.delete(uriStr);
|
|
567
|
+
}));
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* 根据给定的uri获取其根节点
|
|
571
|
+
* 如果不指定uri,则获取默认的根节点
|
|
572
|
+
* @param uri
|
|
573
|
+
*/
|
|
574
|
+
getWorkspaceRootUri(uri) {
|
|
575
|
+
// 获取非file协议文件的根目录,默认返回第一个根目录或undefined
|
|
576
|
+
if (!uri || uri.scheme !== 'file') {
|
|
577
|
+
const root = this.tryGetRoots()[0];
|
|
578
|
+
if (root) {
|
|
579
|
+
return new ide_core_common_1.URI(root.uri);
|
|
580
|
+
}
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
const rootUris = [];
|
|
584
|
+
for (const root of this.tryGetRoots()) {
|
|
585
|
+
const rootUri = new ide_core_common_1.URI(root.uri);
|
|
586
|
+
if (rootUri && rootUri.isEqualOrParent(uri)) {
|
|
587
|
+
rootUris.push(rootUri);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return rootUris.sort((r1, r2) => r2.toString().length - r1.toString().length)[0];
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* 获取相对路径
|
|
594
|
+
* @param pathOrUri
|
|
595
|
+
* @param includeWorkspaceFolder
|
|
596
|
+
*/
|
|
597
|
+
async asRelativePath(pathOrUri, includeWorkspaceFolder) {
|
|
598
|
+
// path 为 uri.path 非 uri.toString()
|
|
599
|
+
let path;
|
|
600
|
+
if (typeof pathOrUri === 'string') {
|
|
601
|
+
path = pathOrUri;
|
|
602
|
+
}
|
|
603
|
+
else if (typeof pathOrUri !== 'undefined') {
|
|
604
|
+
path = pathOrUri.codeUri.fsPath;
|
|
605
|
+
}
|
|
606
|
+
if (!path) {
|
|
607
|
+
return path;
|
|
608
|
+
}
|
|
609
|
+
const roots = await this.roots;
|
|
610
|
+
if (includeWorkspaceFolder && this.isMultiRootWorkspaceOpened) {
|
|
611
|
+
const workspace = await this.workspace;
|
|
612
|
+
if (workspace) {
|
|
613
|
+
roots.push(workspace);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
for (const root of roots) {
|
|
617
|
+
const rootPath = new ide_core_common_1.URI(root.uri).codeUri.fsPath;
|
|
618
|
+
const isRelative = path && path.indexOf(rootPath) >= 0;
|
|
619
|
+
if (isRelative) {
|
|
620
|
+
if (path === rootPath) {
|
|
621
|
+
return '';
|
|
622
|
+
}
|
|
623
|
+
if (rootPath.slice(-1) === '/') {
|
|
624
|
+
return decodeURI(path.replace(rootPath, ''));
|
|
625
|
+
}
|
|
626
|
+
return decodeURI(path.replace(rootPath + '/', ''));
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return decodeURI(path);
|
|
630
|
+
}
|
|
631
|
+
dispose() {
|
|
632
|
+
this.toDisposableCollection.dispose();
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
(0, tslib_1.__decorate)([
|
|
636
|
+
(0, di_1.Autowired)(common_3.IFileServiceClient),
|
|
637
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
638
|
+
], WorkspaceService.prototype, "fileServiceClient", void 0);
|
|
639
|
+
(0, tslib_1.__decorate)([
|
|
640
|
+
(0, di_1.Autowired)(ide_core_browser_1.IWindowService),
|
|
641
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
642
|
+
], WorkspaceService.prototype, "windowService", void 0);
|
|
643
|
+
(0, tslib_1.__decorate)([
|
|
644
|
+
(0, di_1.Autowired)(ide_core_browser_1.ILogger),
|
|
645
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
646
|
+
], WorkspaceService.prototype, "logger", void 0);
|
|
647
|
+
(0, tslib_1.__decorate)([
|
|
648
|
+
(0, di_1.Autowired)(workspace_preferences_1.WorkspacePreferences),
|
|
649
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
650
|
+
], WorkspaceService.prototype, "preferences", void 0);
|
|
651
|
+
(0, tslib_1.__decorate)([
|
|
652
|
+
(0, di_1.Autowired)(ide_core_browser_1.PreferenceService),
|
|
653
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
654
|
+
], WorkspaceService.prototype, "preferenceService", void 0);
|
|
655
|
+
(0, tslib_1.__decorate)([
|
|
656
|
+
(0, di_1.Autowired)(ide_core_browser_1.PreferenceSchemaProvider),
|
|
657
|
+
(0, tslib_1.__metadata)("design:type", ide_core_browser_1.PreferenceSchemaProvider)
|
|
658
|
+
], WorkspaceService.prototype, "schemaProvider", void 0);
|
|
659
|
+
(0, tslib_1.__decorate)([
|
|
660
|
+
(0, di_1.Autowired)(ide_core_browser_1.AppConfig),
|
|
661
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
662
|
+
], WorkspaceService.prototype, "appConfig", void 0);
|
|
663
|
+
(0, tslib_1.__decorate)([
|
|
664
|
+
(0, di_1.Autowired)(ide_core_common_1.StorageProvider),
|
|
665
|
+
(0, tslib_1.__metadata)("design:type", Function)
|
|
666
|
+
], WorkspaceService.prototype, "storageProvider", void 0);
|
|
667
|
+
(0, tslib_1.__decorate)([
|
|
668
|
+
(0, di_1.Autowired)(ide_core_browser_1.IClientApp),
|
|
669
|
+
(0, tslib_1.__metadata)("design:type", Object)
|
|
670
|
+
], WorkspaceService.prototype, "clientApp", void 0);
|
|
671
|
+
WorkspaceService = (0, tslib_1.__decorate)([
|
|
672
|
+
(0, di_1.Injectable)()
|
|
673
|
+
], WorkspaceService);
|
|
674
|
+
exports.WorkspaceService = WorkspaceService;
|
|
675
|
+
//# sourceMappingURL=workspace-service.js.map
|