Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts
5251 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 { SaveDialogOptions, OpenDialogOptions } from '../../../../base/parts/sandbox/common/electronTypes.js';
7
import { IHostService } from '../../host/browser/host.js';
8
import { IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, IDialogService, INativeOpenDialogOptions } from '../../../../platform/dialogs/common/dialogs.js';
9
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
10
import { IHistoryService } from '../../history/common/history.js';
11
import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js';
12
import { URI } from '../../../../base/common/uri.js';
13
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
14
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
15
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
16
import { IFileService } from '../../../../platform/files/common/files.js';
17
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
18
import { INativeHostOptions, INativeHostService } from '../../../../platform/native/common/native.js';
19
import { AbstractFileDialogService } from '../browser/abstractFileDialogService.js';
20
import { Schemas } from '../../../../base/common/network.js';
21
import { ILanguageService } from '../../../../editor/common/languages/language.js';
22
import { IWorkspacesService } from '../../../../platform/workspaces/common/workspaces.js';
23
import { ILabelService } from '../../../../platform/label/common/label.js';
24
import { IPathService } from '../../path/common/pathService.js';
25
import { ICommandService } from '../../../../platform/commands/common/commands.js';
26
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
27
import { IEditorService } from '../../editor/common/editorService.js';
28
import { ILogService } from '../../../../platform/log/common/log.js';
29
import { getActiveWindow } from '../../../../base/browser/dom.js';
30
import { IRemoteAgentService } from '../../remote/common/remoteAgentService.js';
31
32
export class FileDialogService extends AbstractFileDialogService implements IFileDialogService {
33
34
constructor(
35
@IHostService hostService: IHostService,
36
@IWorkspaceContextService contextService: IWorkspaceContextService,
37
@IHistoryService historyService: IHistoryService,
38
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
39
@IInstantiationService instantiationService: IInstantiationService,
40
@IConfigurationService configurationService: IConfigurationService,
41
@IFileService fileService: IFileService,
42
@IOpenerService openerService: IOpenerService,
43
@INativeHostService private readonly nativeHostService: INativeHostService,
44
@IDialogService dialogService: IDialogService,
45
@ILanguageService languageService: ILanguageService,
46
@IWorkspacesService workspacesService: IWorkspacesService,
47
@ILabelService labelService: ILabelService,
48
@IPathService pathService: IPathService,
49
@ICommandService commandService: ICommandService,
50
@IEditorService editorService: IEditorService,
51
@ICodeEditorService codeEditorService: ICodeEditorService,
52
@ILogService logService: ILogService,
53
@IRemoteAgentService remoteAgentService: IRemoteAgentService
54
) {
55
super(hostService, contextService, historyService, environmentService, instantiationService,
56
configurationService, fileService, openerService, dialogService, languageService, workspacesService, labelService, pathService, commandService, editorService, codeEditorService, logService, remoteAgentService);
57
}
58
59
private toNativeOpenDialogOptions(options: IPickAndOpenOptions): INativeOpenDialogOptions {
60
return {
61
forceNewWindow: options.forceNewWindow,
62
telemetryExtraData: options.telemetryExtraData,
63
defaultPath: options.defaultUri?.fsPath
64
};
65
}
66
67
private shouldUseSimplified(schema: string): { useSimplified: boolean; isSetting: boolean } {
68
const setting = (this.configurationService.getValue('files.simpleDialog.enable') === true);
69
const newWindowSetting = (this.configurationService.getValue('window.openFilesInNewWindow') === 'on');
70
return {
71
// - Only real files can be shown in the native file picker
72
// - If the simple file dialog is enabled
73
// - driver automation (like smoke tests) can use the simple file dialog but not native
74
useSimplified: ((schema !== Schemas.file) && (schema !== Schemas.vscodeUserData)) || setting || !!this.environmentService.enableSmokeTestDriver,
75
isSetting: newWindowSetting
76
};
77
}
78
79
async pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise<void> {
80
const schema = this.getFileSystemSchema(options);
81
82
if (!options.defaultUri) {
83
options.defaultUri = await this.defaultFilePath(schema);
84
}
85
86
const shouldUseSimplified = this.shouldUseSimplified(schema);
87
if (shouldUseSimplified.useSimplified) {
88
return this.pickFileFolderAndOpenSimplified(schema, options, shouldUseSimplified.isSetting);
89
}
90
return this.nativeHostService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options));
91
}
92
93
async pickFileAndOpen(options: IPickAndOpenOptions): Promise<void> {
94
const schema = this.getFileSystemSchema(options);
95
96
if (!options.defaultUri) {
97
options.defaultUri = await this.defaultFilePath(schema);
98
}
99
100
const shouldUseSimplified = this.shouldUseSimplified(schema);
101
if (shouldUseSimplified.useSimplified) {
102
return this.pickFileAndOpenSimplified(schema, options, shouldUseSimplified.isSetting);
103
}
104
return this.nativeHostService.pickFileAndOpen(this.toNativeOpenDialogOptions(options));
105
}
106
107
async pickFolderAndOpen(options: IPickAndOpenOptions): Promise<void> {
108
const schema = this.getFileSystemSchema(options);
109
110
if (!options.defaultUri) {
111
options.defaultUri = await this.defaultFolderPath(schema);
112
}
113
114
if (this.shouldUseSimplified(schema).useSimplified) {
115
return this.pickFolderAndOpenSimplified(schema, options);
116
}
117
return this.nativeHostService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options));
118
}
119
120
async pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise<void> {
121
options.availableFileSystems = this.getWorkspaceAvailableFileSystems(options);
122
const schema = this.getFileSystemSchema(options);
123
124
if (!options.defaultUri) {
125
options.defaultUri = await this.defaultWorkspacePath(schema);
126
}
127
128
if (this.shouldUseSimplified(schema).useSimplified) {
129
return this.pickWorkspaceAndOpenSimplified(schema, options);
130
}
131
return this.nativeHostService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options));
132
}
133
134
async pickFileToSave(defaultUri: URI, availableFileSystems?: string[]): Promise<URI | undefined> {
135
const schema = this.getFileSystemSchema({ defaultUri, availableFileSystems });
136
const options = this.getPickFileToSaveDialogOptions(defaultUri, availableFileSystems);
137
if (this.shouldUseSimplified(schema).useSimplified) {
138
return this.pickFileToSaveSimplified(schema, options);
139
} else {
140
const result = await this.nativeHostService.showSaveDialog(this.toNativeSaveDialogOptions(options));
141
if (result && !result.canceled && result.filePath) {
142
const uri = URI.file(result.filePath);
143
144
this.addFileToRecentlyOpened(uri);
145
146
return uri;
147
}
148
}
149
return;
150
}
151
152
private toNativeSaveDialogOptions(options: ISaveDialogOptions): SaveDialogOptions & INativeHostOptions {
153
options.defaultUri = options.defaultUri ? URI.file(options.defaultUri.path) : undefined;
154
return {
155
defaultPath: options.defaultUri?.fsPath,
156
buttonLabel: typeof options.saveLabel === 'string' ? options.saveLabel : options.saveLabel?.withMnemonic,
157
filters: options.filters,
158
title: options.title,
159
targetWindowId: getActiveWindow().vscodeWindowId
160
};
161
}
162
163
async showSaveDialog(options: ISaveDialogOptions): Promise<URI | undefined> {
164
const schema = this.getFileSystemSchema(options);
165
if (this.shouldUseSimplified(schema).useSimplified) {
166
return this.showSaveDialogSimplified(schema, options);
167
}
168
169
const result = await this.nativeHostService.showSaveDialog(this.toNativeSaveDialogOptions(options));
170
if (result && !result.canceled && result.filePath) {
171
return URI.file(result.filePath);
172
}
173
174
return;
175
}
176
177
async showOpenDialog(options: IOpenDialogOptions): Promise<URI[] | undefined> {
178
const schema = this.getFileSystemSchema(options);
179
if (this.shouldUseSimplified(schema).useSimplified) {
180
return this.showOpenDialogSimplified(schema, options);
181
}
182
183
const newOptions: OpenDialogOptions & { properties: string[] } & INativeHostOptions = {
184
title: options.title,
185
defaultPath: options.defaultUri?.fsPath,
186
buttonLabel: typeof options.openLabel === 'string' ? options.openLabel : options.openLabel?.withMnemonic,
187
filters: options.filters,
188
properties: [],
189
targetWindowId: getActiveWindow().vscodeWindowId
190
};
191
192
newOptions.properties.push('createDirectory');
193
194
if (options.canSelectFiles) {
195
newOptions.properties.push('openFile');
196
}
197
198
if (options.canSelectFolders) {
199
newOptions.properties.push('openDirectory');
200
}
201
202
if (options.canSelectMany) {
203
newOptions.properties.push('multiSelections');
204
}
205
206
const result = await this.nativeHostService.showOpenDialog(newOptions);
207
return result && Array.isArray(result.filePaths) && result.filePaths.length > 0 ? result.filePaths.map(URI.file) : undefined;
208
}
209
}
210
211
registerSingleton(IFileDialogService, FileDialogService, InstantiationType.Delayed);
212
213