-
-
Notifications
You must be signed in to change notification settings - Fork 435
/
Copy pathworkspace-service.ts
136 lines (126 loc) · 5.33 KB
/
workspace-service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { ContributionProvider } from '@theia/core/lib/common/contribution-provider';
import URI from '@theia/core/lib/common/uri';
import {
DEFAULT_WINDOW_HASH,
NewWindowOptions,
} from '@theia/core/lib/common/window';
import { inject, injectable, named } from '@theia/core/shared/inversify';
import { FileStat } from '@theia/filesystem/lib/common/files';
import {
WorkspaceInput,
WorkspaceService as TheiaWorkspaceService,
} from '@theia/workspace/lib/browser/workspace-service';
import {
SketchesError,
SketchesService,
} from '../../../common/protocol/sketches-service';
import {
StartupTask,
StartupTaskProvider,
} from '../../../electron-common/startup-task';
import { WindowServiceExt } from '../core/window-service-ext';
@injectable()
export class WorkspaceService extends TheiaWorkspaceService {
@inject(SketchesService)
private readonly sketchesService: SketchesService;
@inject(WindowServiceExt)
private readonly windowServiceExt: WindowServiceExt;
@inject(ContributionProvider)
@named(StartupTaskProvider)
private readonly providers: ContributionProvider<StartupTaskProvider>;
private _workspaceError: Error | undefined;
get workspaceError(): Error | undefined {
return this._workspaceError;
}
protected override async toFileStat(
uri: string | URI | undefined
): Promise<FileStat | undefined> {
const stat = await super.toFileStat(uri);
if (!stat) {
const newSketchUri = await this.sketchesService.createNewSketch();
return this.toFileStat(newSketchUri.uri);
}
// When opening a file instead of a directory, IDE2 (and Theia) expects a workspace JSON file.
// Nothing will work if the workspace file is invalid. Users tend to start (see #964) IDE2 from the `.ino` files,
// so here, IDE2 tries to load the sketch via the CLI from the main sketch file URI.
// If loading the sketch is OK, IDE2 starts and uses the sketch folder as the workspace root instead of the sketch file.
// If loading fails due to invalid name error, IDE2 loads a temp sketch and preserves the startup error, and offers the sketch move to the user later.
// If loading the sketch fails, create a fallback sketch and open the new temp sketch folder as the workspace root.
if (stat.isFile && stat.resource.path.ext === '.ino') {
try {
const sketch = await this.sketchesService.loadSketch(
stat.resource.toString()
);
return this.toFileStat(sketch.uri);
} catch (err) {
if (SketchesError.InvalidName.is(err)) {
this._workspaceError = err;
const newSketchUri = await this.sketchesService.createNewSketch();
return this.toFileStat(newSketchUri.uri);
} else if (SketchesError.NotFound.is(err)) {
this._workspaceError = err;
const newSketchUri = await this.sketchesService.createNewSketch();
return this.toFileStat(newSketchUri.uri);
}
throw err;
}
}
return stat;
}
// Was copied from the Theia implementation.
// Unlike the default behavior, IDE2 does not check the existence of the workspace before open.
protected override async doGetDefaultWorkspaceUri(): Promise<
string | undefined
> {
// If an empty window is explicitly requested do not restore a previous workspace.
// Note: `window.location.hash` includes leading "#" if non-empty.
if (window.location.hash === `#${DEFAULT_WINDOW_HASH}`) {
window.location.hash = '';
return undefined;
}
// Prefer the workspace path specified as the URL fragment, if present.
if (window.location.hash.length > 1) {
// Remove the leading # and decode the URI.
const wpPath = decodeURI(window.location.hash.substring(1));
const workspaceUri = new URI().withPath(wpPath).withScheme('file');
// ### Customization! Here, we do no check if the workspace exists.
// ### The error or missing sketch handling is done in the customized `toFileStat`.
return workspaceUri.toString();
} else {
// Else, ask the server for its suggested workspace (usually the one
// specified on the CLI, or the most recent).
// ### Customization! the default workspace server will create a new sketch and will return with its URI if no recent workspaces are available.
return this.server.getMostRecentlyUsedWorkspace();
}
}
protected override reloadWindow(options?: WorkspaceInput): void {
const tasks = this.tasks(options);
this.setURLFragment(this._workspace?.resource.path.toString() || '');
this.windowServiceExt.reload({ tasks });
}
protected override openNewWindow(
workspacePath: string,
options?: WorkspaceInput
): void {
const tasks = this.tasks(options);
const url = new URL(window.location.href);
url.hash = encodeURI(workspacePath);
this.windowService.openNewWindow(
url.toString(),
Object.assign({} as NewWindowOptions, { tasks })
);
}
protected override updateTitle(): void {
// NOOP. IDE2 handles the `window.title` updates solely via the customized `WindowTitleUpdater`.
}
private tasks(options?: WorkspaceInput): StartupTask[] {
const tasks = this.providers
.getContributions()
.map((contribution) => contribution.tasks())
.reduce((prev, curr) => prev.concat(curr), []);
if (StartupTask.has(options)) {
tasks.push(...options.tasks);
}
return tasks;
}
}