@codingame/monaco-vscode-dialogs-service-override 36.2.6 → 37.0.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codingame/monaco-vscode-dialogs-service-override",
3
- "version": "36.2.6",
3
+ "version": "37.0.0",
4
4
  "private": false,
5
5
  "description": "VSCode public API plugged on the monaco editor - dialogs service-override",
6
6
  "keywords": [],
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "type": "module",
17
17
  "dependencies": {
18
- "@codingame/monaco-vscode-api": "36.2.6"
18
+ "@codingame/monaco-vscode-api": "37.0.0"
19
19
  },
20
20
  "main": "index.js",
21
21
  "module": "index.js",
@@ -21,5 +21,7 @@ export declare class BrowserDialogHandler extends AbstractDialogHandler {
21
21
  confirm(confirmation: IConfirmation): Promise<IConfirmationResult>;
22
22
  input(input: IInput): Promise<IInputResult>;
23
23
  about(title: string, details: string, detailsToCopy: string): Promise<void>;
24
+ /** Default link handler for Markdown rendered within a dialog, see {@link openLinkFromMarkdown}. */
25
+ private defaultMarkdownActionHandler;
24
26
  private doShow;
25
27
  }
@@ -5,7 +5,7 @@ import { AbstractDialogHandler } from '@codingame/monaco-vscode-api/vscode/vs/pl
5
5
  import { ILayoutService } from '@codingame/monaco-vscode-api/vscode/vs/platform/layout/browser/layoutService.service';
6
6
  import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
7
7
  import Severity from '@codingame/monaco-vscode-api/vscode/vs/base/common/severity';
8
- import { Dialog } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/ui/dialog/dialog';
8
+ import { Dialog, DialogContentsAlignment } from '@codingame/monaco-vscode-api/vscode/vs/base/browser/ui/dialog/dialog';
9
9
  import { DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
10
10
  import { IKeybindingService } from '@codingame/monaco-vscode-api/vscode/vs/platform/keybinding/common/keybinding.service';
11
11
  import { IClipboardService } from '@codingame/monaco-vscode-api/vscode/vs/platform/clipboard/common/clipboardService.service';
@@ -118,11 +118,19 @@ let BrowserDialogHandler = class BrowserDialogHandler extends AbstractDialogHand
118
118
  async about(title, details, detailsToCopy) {
119
119
  const {
120
120
  button
121
- } = await this.doShow(Severity.Info, title, [( localize(3302, "&&Copy")), ( localize(3303, "OK"))], details, 1);
121
+ } = await this.doShow(Severity.Info, title, [( localize(3523, "&&Copy")), ( localize(3524, "OK"))], details, 1);
122
122
  if (button === 0) {
123
123
  this.clipboardService.writeText(detailsToCopy);
124
124
  }
125
125
  }
126
+ defaultMarkdownActionHandler(link, mdStr) {
127
+ return openLinkFromMarkdown(
128
+ this.openerService,
129
+ link,
130
+ mdStr.isTrusted,
131
+ true
132
+ );
133
+ }
126
134
  async doShow(
127
135
  type,
128
136
  message,
@@ -135,18 +143,14 @@ let BrowserDialogHandler = class BrowserDialogHandler extends AbstractDialogHand
135
143
  token
136
144
  ) {
137
145
  const dialogDisposables = ( new DisposableStore());
146
+ const detailElement = typeof detail === "object" ? dialogDisposables.add(this.markdownRendererService.render(detail, {
147
+ actionHandler: (link, mdStr) => this.defaultMarkdownActionHandler(link, mdStr)
148
+ })).element : undefined;
138
149
  const renderBody = customOptions ? parent => {
139
150
  parent.classList.add(...(customOptions.classes || []));
140
151
  customOptions.markdownDetails?.forEach(markdownDetail => {
141
152
  const result = dialogDisposables.add(this.markdownRendererService.render(markdownDetail.markdown, {
142
- actionHandler: markdownDetail.actionHandler || ((link, mdStr) => {
143
- return openLinkFromMarkdown(
144
- this.openerService,
145
- link,
146
- mdStr.isTrusted,
147
- true
148
- );
149
- })
153
+ actionHandler: markdownDetail.actionHandler || ((link, mdStr) => this.defaultMarkdownActionHandler(link, mdStr))
150
154
  }));
151
155
  parent.appendChild(result.element);
152
156
  result.element.classList.add(...(markdownDetail.classes || []));
@@ -157,11 +161,13 @@ let BrowserDialogHandler = class BrowserDialogHandler extends AbstractDialogHand
157
161
  message,
158
162
  buttons,
159
163
  createWorkbenchDialogOptions({
160
- detail,
164
+ detail: typeof detail === "string" ? detail : undefined,
165
+ detailElement,
161
166
  cancelId,
162
167
  type: this.getDialogType(type),
163
168
  renderBody,
164
169
  icon: customOptions?.icon,
170
+ alignment: customOptions?.alignment === "vertical" ? DialogContentsAlignment.Vertical : DialogContentsAlignment.Horizontal,
165
171
  disableCloseAction: customOptions?.disableCloseAction,
166
172
  buttonOptions: customOptions?.buttonDetails?.map(detail => ({
167
173
  sublabel: detail
@@ -202,16 +202,16 @@ let AbstractFileDialogService = class AbstractFileDialogService {
202
202
  return ConfirmResult.DONT_SAVE;
203
203
  }
204
204
  let message;
205
- let detail = ( localize(17483, "Your changes will be lost if you don't save them."));
205
+ let detail = ( localize(19247, "Your changes will be lost if you don't save them."));
206
206
  if (fileNamesOrResources.length === 1) {
207
207
  message = ( localize(
208
- 17484,
208
+ 19248,
209
209
  "Do you want to save the changes you made to {0}?",
210
210
  typeof fileNamesOrResources[0] === "string" ? fileNamesOrResources[0] : basename(fileNamesOrResources[0])
211
211
  ));
212
212
  } else {
213
213
  message = ( localize(
214
- 17485,
214
+ 19249,
215
215
  "Do you want to save the changes to the following {0} files?",
216
216
  fileNamesOrResources.length
217
217
  ));
@@ -224,10 +224,10 @@ let AbstractFileDialogService = class AbstractFileDialogService {
224
224
  message,
225
225
  detail,
226
226
  buttons: [{
227
- label: fileNamesOrResources.length > 1 ? ( localize(17486, "&&Save All")) : ( localize(17487, "&&Save")),
227
+ label: fileNamesOrResources.length > 1 ? ( localize(19250, "&&Save All")) : ( localize(19251, "&&Save")),
228
228
  run: () => ConfirmResult.SAVE
229
229
  }, {
230
- label: ( localize(17488, "Do&&n't Save")),
230
+ label: ( localize(19252, "Do&&n't Save")),
231
231
  run: () => ConfirmResult.DONT_SAVE
232
232
  }],
233
233
  cancelButton: {
@@ -240,7 +240,7 @@ let AbstractFileDialogService = class AbstractFileDialogService {
240
240
  return schema === Schemas.untitled ? [Schemas.file] : (schema !== Schemas.file ? [schema, Schemas.file] : [schema]);
241
241
  }
242
242
  async pickFileFolderAndOpenSimplified(schema, options, preferNewWindow) {
243
- const title = ( localize(17489, "Open File or Folder"));
243
+ const title = ( localize(19253, "Open File or Folder"));
244
244
  const availableFileSystems = this.addFileSchemaIfNeeded(schema);
245
245
  const uris = await this.pickResource({
246
246
  canSelectFiles: true,
@@ -280,7 +280,7 @@ let AbstractFileDialogService = class AbstractFileDialogService {
280
280
  }
281
281
  }
282
282
  async pickFileAndOpenSimplified(schema, options, preferNewWindow) {
283
- const title = ( localize(17490, "Open File"));
283
+ const title = ( localize(19254, "Open File"));
284
284
  const availableFileSystems = this.addFileSchemaIfNeeded(schema);
285
285
  const uris = await this.pickResource({
286
286
  canSelectFiles: true,
@@ -322,7 +322,7 @@ let AbstractFileDialogService = class AbstractFileDialogService {
322
322
  }]);
323
323
  }
324
324
  async pickFolderAndOpenSimplified(schema, options) {
325
- const title = ( localize(17491, "Open Folder"));
325
+ const title = ( localize(19255, "Open Folder"));
326
326
  const availableFileSystems = this.addFileSchemaIfNeeded(schema, true);
327
327
  const uris = await this.pickResource({
328
328
  canSelectFiles: false,
@@ -343,9 +343,9 @@ let AbstractFileDialogService = class AbstractFileDialogService {
343
343
  }
344
344
  }
345
345
  async pickWorkspaceAndOpenSimplified(schema, options) {
346
- const title = ( localize(17492, "Open Workspace from File"));
346
+ const title = ( localize(19256, "Open Workspace from File"));
347
347
  const filters = [{
348
- name: ( localize(17493, "Workspace")),
348
+ name: ( localize(19257, "Workspace")),
349
349
  extensions: [WORKSPACE_EXTENSION]
350
350
  }];
351
351
  const availableFileSystems = this.addFileSchemaIfNeeded(schema, true);
@@ -372,7 +372,7 @@ let AbstractFileDialogService = class AbstractFileDialogService {
372
372
  if (!options.availableFileSystems) {
373
373
  options.availableFileSystems = this.addFileSchemaIfNeeded(schema);
374
374
  }
375
- options.title = ( localize(17494, "Save As"));
375
+ options.title = ( localize(19258, "Save As"));
376
376
  const uri = await this.saveRemoteResource(options);
377
377
  if (uri) {
378
378
  this.addFileToRecentlyOpened(uri);
@@ -437,7 +437,7 @@ let AbstractFileDialogService = class AbstractFileDialogService {
437
437
  getPickFileToSaveDialogOptions(defaultUri, availableFileSystems) {
438
438
  const options = {
439
439
  defaultUri,
440
- title: ( localize(17495, "Save As")),
440
+ title: ( localize(19259, "Save As")),
441
441
  availableFileSystems
442
442
  };
443
443
  const ext = defaultUri ? extname(defaultUri) : undefined;
@@ -475,10 +475,10 @@ let AbstractFileDialogService = class AbstractFileDialogService {
475
475
  };
476
476
  }
477
477
  options.filters = coalesce([{
478
- name: ( localize(17496, "All Files")),
478
+ name: ( localize(19260, "All Files")),
479
479
  extensions: ["*"]
480
480
  }, matchingFilter, ...registeredLanguageFilters, {
481
- name: ( localize(17497, "No Extension")),
481
+ name: ( localize(19261, "No Extension")),
482
482
  extensions: [""]
483
483
  }]);
484
484
  return options;
@@ -28,7 +28,7 @@ class FileDialogService extends AbstractFileDialogService {
28
28
  if (this.shouldUseSimplified(schema)) {
29
29
  return super.pickFileFolderAndOpenSimplified(schema, options, false);
30
30
  }
31
- throw ( new Error(( localize(17498, "Can't open folders, try adding a folder to the workspace instead."))));
31
+ throw ( new Error(( localize(19262, "Can't open folders, try adding a folder to the workspace instead."))));
32
32
  }
33
33
  addFileSchemaIfNeeded(schema, isFolder) {
34
34
  return (schema === Schemas.untitled) ? [Schemas.file] : (((schema !== Schemas.file) && (!isFolder || (schema !== Schemas.vscodeRemote))) ? [schema, Schemas.file] : [schema]);
@@ -73,7 +73,7 @@ class FileDialogService extends AbstractFileDialogService {
73
73
  if (this.shouldUseSimplified(schema)) {
74
74
  return super.pickFolderAndOpenSimplified(schema, options);
75
75
  }
76
- throw ( new Error(( localize(17498, "Can't open folders, try adding a folder to the workspace instead."))));
76
+ throw ( new Error(( localize(19262, "Can't open folders, try adding a folder to the workspace instead."))));
77
77
  }
78
78
  async pickWorkspaceAndOpen(options) {
79
79
  options.availableFileSystems = this.getWorkspaceAvailableFileSystems(options);
@@ -85,7 +85,7 @@ class FileDialogService extends AbstractFileDialogService {
85
85
  return super.pickWorkspaceAndOpenSimplified(schema, options);
86
86
  }
87
87
  throw ( new Error(( localize(
88
- 17499,
88
+ 19263,
89
89
  "Can't open workspaces, try adding a folder to the workspace instead."
90
90
  ))));
91
91
  }
@@ -213,19 +213,19 @@ class FileDialogService extends AbstractFileDialogService {
213
213
  }
214
214
  }
215
215
  const buttons = [{
216
- label: ( localize(17500, "&&Open Remote...")),
216
+ label: ( localize(19264, "&&Open Remote...")),
217
217
  run: async () => {
218
218
  await this.commandService.executeCommand("workbench.action.remote.showMenu");
219
219
  }
220
220
  }, {
221
- label: ( localize(17501, "&&Learn More")),
221
+ label: ( localize(19265, "&&Learn More")),
222
222
  run: async () => {
223
223
  await this.openerService.open("https://aka.ms/VSCodeWebLocalFileSystemAccess");
224
224
  }
225
225
  }];
226
226
  if (context === "open") {
227
227
  buttons.push({
228
- label: ( localize(17502, "Open &&Files...")),
228
+ label: ( localize(19266, "Open &&Files...")),
229
229
  run: async () => {
230
230
  const files = await triggerUpload();
231
231
  if (files) {
@@ -247,9 +247,9 @@ class FileDialogService extends AbstractFileDialogService {
247
247
  }
248
248
  await this.dialogService.prompt({
249
249
  type: Severity.Warning,
250
- message: ( localize(17503, "Opening Local Folders is Unsupported")),
250
+ message: ( localize(19267, "Opening Local Folders is Unsupported")),
251
251
  detail: ( localize(
252
- 17504,
252
+ 19268,
253
253
  "Your browser doesn't support opening local folders.\nYou can either open single files or open a remote repository."
254
254
  )),
255
255
  buttons
@@ -132,6 +132,7 @@ export declare class SimpleFileDialog extends Disposable implements ISimpleFileD
132
132
  private trimTrailingSlash;
133
133
  private yesNoPrompt;
134
134
  private validate;
135
+ private canCreateFolder;
135
136
  private updateItems;
136
137
  private pathFromUri;
137
138
  private pathAppend;
@@ -1,9 +1,9 @@
1
1
 
2
2
  import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
3
  import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
4
- import { basename, joinPath, toLocalResource, addTrailingPathSeparator, removeTrailingPathSeparator, extname, dirname, extUriIgnorePathCase, relativePath, hasTrailingPathSeparator, isEqual } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
4
+ import { basename, joinPath, toLocalResource, addTrailingPathSeparator, removeTrailingPathSeparator, extname, dirname, hasTrailingPathSeparator, extUriIgnorePathCase, relativePath, isEqual } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
5
5
  import { deepClone } from '@codingame/monaco-vscode-api/vscode/vs/base/common/objects';
6
- import { FileKind } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files';
6
+ import { toFileSystemProviderErrorCode, FileSystemProviderErrorCode, FileKind } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files';
7
7
  import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
8
8
  import { ItemActivation } from '@codingame/monaco-vscode-api/vscode/vs/platform/quickinput/common/quickInput';
9
9
  import { IQuickInputService } from '@codingame/monaco-vscode-api/vscode/vs/platform/quickinput/common/quickInput.service';
@@ -41,7 +41,7 @@ import { IStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform
41
41
  var OpenLocalFileCommand;
42
42
  (function(OpenLocalFileCommand) {
43
43
  OpenLocalFileCommand.ID = "workbench.action.files.openLocalFile";
44
- OpenLocalFileCommand.LABEL = ( localize(17505, "Open Local File..."));
44
+ OpenLocalFileCommand.LABEL = ( localize(19269, "Open Local File..."));
45
45
  function handler() {
46
46
  return accessor => {
47
47
  const dialogService = accessor.get(IFileDialogService);
@@ -56,7 +56,7 @@ var OpenLocalFileCommand;
56
56
  var SaveLocalFileCommand;
57
57
  (function(SaveLocalFileCommand) {
58
58
  SaveLocalFileCommand.ID = "workbench.action.files.saveLocalFile";
59
- SaveLocalFileCommand.LABEL = ( localize(17506, "Save Local File..."));
59
+ SaveLocalFileCommand.LABEL = ( localize(19270, "Save Local File..."));
60
60
  function handler() {
61
61
  return accessor => {
62
62
  const editorService = accessor.get(IEditorService);
@@ -79,7 +79,7 @@ var SaveLocalFileCommand;
79
79
  var OpenLocalFolderCommand;
80
80
  (function(OpenLocalFolderCommand) {
81
81
  OpenLocalFolderCommand.ID = "workbench.action.files.openLocalFolder";
82
- OpenLocalFolderCommand.LABEL = ( localize(17507, "Open Local Folder..."));
82
+ OpenLocalFolderCommand.LABEL = ( localize(19271, "Open Local Folder..."));
83
83
  function handler() {
84
84
  return accessor => {
85
85
  const dialogService = accessor.get(IFileDialogService);
@@ -94,7 +94,7 @@ var OpenLocalFolderCommand;
94
94
  var OpenLocalFileFolderCommand;
95
95
  (function(OpenLocalFileFolderCommand) {
96
96
  OpenLocalFileFolderCommand.ID = "workbench.action.files.openLocalFileFolder";
97
- OpenLocalFileFolderCommand.LABEL = ( localize(17508, "Open Local..."));
97
+ OpenLocalFileFolderCommand.LABEL = ( localize(19272, "Open Local..."));
98
98
  function handler() {
99
99
  return accessor => {
100
100
  const dialogService = accessor.get(IFileDialogService);
@@ -245,7 +245,7 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
245
245
  }
246
246
  if ((this.scheme !== Schemas.file) && !this.fileService.hasProvider(defaultUri)) {
247
247
  this.notificationService.info(( localize(
248
- 17509,
248
+ 19273,
249
249
  "File system provider for {0} is not available.",
250
250
  (defaultUri.toString())
251
251
  )));
@@ -345,12 +345,12 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
345
345
  this.filePickBox.matchOnLabel = false;
346
346
  this.filePickBox.sortByLabel = false;
347
347
  this.filePickBox.ignoreFocusOut = true;
348
- this.filePickBox.placeholder = ( localize(17510, "Folder path"));
348
+ this.filePickBox.placeholder = ( localize(19274, "Folder path"));
349
349
  this.filePickBox.ok = true;
350
350
  this.filePickBox.okLabel = typeof this.options.openLabel === "string" ? this.options.openLabel : this.options.openLabel?.withoutMnemonic;
351
351
  if ((this.scheme !== Schemas.file) && this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) {
352
352
  this.filePickBox.customButton = true;
353
- this.filePickBox.customLabel = ( localize(17511, "Show Local"));
353
+ this.filePickBox.customLabel = ( localize(19275, "Show Local"));
354
354
  this.filePickBox.customButtonSecondary = true;
355
355
  let action;
356
356
  if (isSave) {
@@ -482,7 +482,10 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
482
482
  this.filePickBox.validationMessage = undefined;
483
483
  const filePickBoxUri = this.filePickBoxValue();
484
484
  let updated = UpdateResult.NotUpdated;
485
- if (!extUriIgnorePathCase.isEqual(this.currentFolder, filePickBoxUri)) {
485
+ if (!hasTrailingPathSeparator(filePickBoxUri, this.separator) && extUriIgnorePathCase.isEqual(this.currentFolder, dirname(filePickBoxUri))) {
486
+ this.setActiveItems(value);
487
+ return;
488
+ } else if (!extUriIgnorePathCase.isEqual(this.currentFolder, filePickBoxUri)) {
486
489
  updated = await this.tryUpdateItems(value, filePickBoxUri);
487
490
  }
488
491
  if ((updated === UpdateResult.NotUpdated) || (updated === UpdateResult.UpdatedWithTrailing)) {
@@ -498,7 +501,7 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
498
501
  setButtons() {
499
502
  this.filePickBox.buttons = [{
500
503
  iconClass: this._showDotFiles ? ThemeIcon.asClassName(Codicon.eye) : ThemeIcon.asClassName(Codicon.eyeClosed),
501
- tooltip: this._showDotFiles ? ( localize(17512, "Hide dot files")) : ( localize(17513, "Show dot files")),
504
+ tooltip: this._showDotFiles ? ( localize(19276, "Hide dot files")) : ( localize(19277, "Show dot files")),
502
505
  alwaysVisible: true
503
506
  }];
504
507
  }
@@ -653,7 +656,7 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
653
656
  valueUri = this.tryAddTrailingSeparatorToDirectory(valueUri, stat);
654
657
  return (await this.updateItems(valueUri)) ? UpdateResult.UpdatedWithTrailing : UpdateResult.Updated;
655
658
  } else if (this.endsWithSlash(value)) {
656
- this.filePickBox.validationMessage = ( localize(17514, "The path does not exist. Use ~ to go to your home directory."));
659
+ this.filePickBox.validationMessage = ( localize(19278, "The path does not exist. Use ~ to go to your home directory."));
657
660
  this.badPath = value;
658
661
  return UpdateResult.InvalidPath;
659
662
  } else {
@@ -817,7 +820,7 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
817
820
  prompt.ignoreFocusOut = true;
818
821
  prompt.ok = true;
819
822
  prompt.customButton = true;
820
- prompt.customLabel = ( localize(17515, "Cancel"));
823
+ prompt.customLabel = ( localize(19279, "Cancel"));
821
824
  prompt.customButtonSecondary = true;
822
825
  prompt.value = this.pathFromUri(uri);
823
826
  let isResolving = false;
@@ -848,7 +851,7 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
848
851
  }
849
852
  async validate(uri) {
850
853
  if (uri === undefined) {
851
- this.filePickBox.validationMessage = ( localize(17516, "Please enter a valid path."));
854
+ this.filePickBox.validationMessage = ( localize(19280, "Please enter a valid path."));
852
855
  return Promise.resolve(false);
853
856
  }
854
857
  let stat;
@@ -859,40 +862,40 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
859
862
  } catch (e) {}
860
863
  if (this.requiresTrailing) {
861
864
  if (stat?.isDirectory) {
862
- this.filePickBox.validationMessage = ( localize(17517, "The folder already exists. Please use a new file name."));
865
+ this.filePickBox.validationMessage = ( localize(19281, "The folder already exists. Please use a new file name."));
863
866
  return false;
864
867
  } else if (stat) {
865
868
  const message = ( localize(
866
- 17518,
869
+ 19282,
867
870
  "{0} already exists. Are you sure you want to overwrite it?",
868
871
  basename(uri)
869
872
  ));
870
873
  return this.yesNoPrompt(uri, message);
871
874
  } else if (!(isValidBasename(basename(uri), this.isWindows))) {
872
- this.filePickBox.validationMessage = ( localize(17519, "Please enter a valid file name."));
875
+ this.filePickBox.validationMessage = ( localize(19283, "Please enter a valid file name."));
873
876
  return false;
874
877
  } else if (!statDirname) {
875
878
  const message = ( localize(
876
- 17520,
879
+ 19284,
877
880
  "The folder {0} does not exist. Would you like to create it?",
878
881
  basename(dirname(uri))
879
882
  ));
880
883
  return this.yesNoPrompt(uri, message);
881
884
  } else if (!statDirname.isDirectory) {
882
- this.filePickBox.validationMessage = ( localize(17521, "Please enter a path that exists."));
885
+ this.filePickBox.validationMessage = ( localize(19285, "Please enter a path that exists."));
883
886
  return false;
884
887
  } else if (statDirname.readonly) {
885
888
  this.filePickBox.validationMessage = ( localize(
886
- 17522,
889
+ 19286,
887
890
  "This folder cannot be used as a save destination. Please choose another folder"
888
891
  ));
889
892
  return false;
890
893
  }
891
894
  } else {
892
895
  if (!stat) {
893
- if (this.allowFolderSelection && !this.allowFileSelection && statDirname?.isDirectory && !statDirname.readonly && isValidBasename(basename(uri), this.isWindows)) {
896
+ if (this.allowFolderSelection && !this.allowFileSelection && (await this.canCreateFolder(uri, statDirname))) {
894
897
  const message = ( localize(
895
- 17523,
898
+ 19287,
896
899
  "The folder {0} does not exist. Would you like to create it?",
897
900
  basename(uri)
898
901
  ));
@@ -904,25 +907,48 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
904
907
  await this.fileService.createFolder(uri);
905
908
  return true;
906
909
  } catch (e) {
907
- this.filePickBox.validationMessage = ( localize(17524, "Could not create folder: {0}", e.message));
910
+ this.filePickBox.validationMessage = ( localize(19288, "Could not create folder: {0}", e.message));
908
911
  return false;
909
912
  }
910
913
  }
911
- this.filePickBox.validationMessage = ( localize(17521, "Please enter a path that exists."));
914
+ this.filePickBox.validationMessage = ( localize(19285, "Please enter a path that exists."));
912
915
  return false;
913
916
  } else if (uri.path === "/" && this.isWindows) {
914
- this.filePickBox.validationMessage = ( localize(17525, "Please start the path with a drive letter."));
917
+ this.filePickBox.validationMessage = ( localize(19289, "Please start the path with a drive letter."));
915
918
  return false;
916
919
  } else if (stat.isDirectory && !this.allowFolderSelection) {
917
- this.filePickBox.validationMessage = ( localize(17526, "Please select a file."));
920
+ this.filePickBox.validationMessage = ( localize(19290, "Please select a file."));
918
921
  return false;
919
922
  } else if (!stat.isDirectory && !this.allowFileSelection) {
920
- this.filePickBox.validationMessage = ( localize(17527, "Please select a folder."));
923
+ this.filePickBox.validationMessage = ( localize(19291, "Please select a folder."));
921
924
  return false;
922
925
  }
923
926
  }
924
927
  return true;
925
928
  }
929
+ async canCreateFolder(uri, parentStat) {
930
+ const immediateParent = dirname(uri);
931
+ let candidate = uri;
932
+ while (true) {
933
+ const name = basename(candidate);
934
+ if (!name || !isValidBasename(name, this.isWindows)) {
935
+ return false;
936
+ }
937
+ const parent = dirname(candidate);
938
+ if (isEqual(parent, candidate)) {
939
+ return false;
940
+ }
941
+ try {
942
+ const stat = parentStat && isEqual(parent, immediateParent) ? parentStat : await this.fileService.stat(parent);
943
+ return stat.isDirectory && !stat.readonly;
944
+ } catch (e) {
945
+ if (toFileSystemProviderErrorCode(e instanceof Error ? e : undefined) !== FileSystemProviderErrorCode.FileNotFound) {
946
+ return false;
947
+ }
948
+ candidate = parent;
949
+ }
950
+ }
951
+ }
926
952
  async updateItems(newFolder, force = false, trailing) {
927
953
  this.busy = true;
928
954
  this.autoCompletePathSegment = "";
@@ -942,13 +968,15 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
942
968
  }
943
969
  } catch (e) {}
944
970
  const newValue = trailing ? this.pathAppend(newFolder, trailing) : this.pathFromUri(newFolder, true);
945
- this.currentFolder = this.endsWithSlash(newFolder.path) ? newFolder : addTrailingPathSeparator(newFolder, this.separator);
946
- this.userEnteredPathSegment = trailing ? trailing : "";
947
- return this.createItems(folderStat, this.currentFolder, token).then(items => {
971
+ const currentFolder = this.endsWithSlash(newFolder.path) ? newFolder : addTrailingPathSeparator(newFolder, this.separator);
972
+ const userEnteredPathSegment = trailing ? trailing : "";
973
+ return this.createItems(folderStat, currentFolder, token).then(items => {
948
974
  if (token.isCancellationRequested) {
949
975
  this.busy = false;
950
976
  return false;
951
977
  }
978
+ this.currentFolder = currentFolder;
979
+ this.userEnteredPathSegment = userEnteredPathSegment;
952
980
  this.filePickBox.itemActivation = ItemActivation.NONE;
953
981
  this.filePickBox.items = items;
954
982
  if (!equalsIgnoreCase(this.filePickBox.value, newValue) && (force || wasDotDot)) {
@@ -1018,7 +1046,7 @@ let SimpleFileDialog = class SimpleFileDialog extends Disposable {
1018
1046
  async createBackItem(currFolder) {
1019
1047
  const compareScheme = this.scopedAuthority ? this.scheme : Schemas.file;
1020
1048
  const compareAuthority = this.scopedAuthority ?? "";
1021
- const fileRepresentationCurr = this.currentFolder.with({
1049
+ const fileRepresentationCurr = currFolder.with({
1022
1050
  scheme: compareScheme,
1023
1051
  authority: compareAuthority
1024
1052
  });