Skip to content

Commit 627182e

Browse files
committed
Fix some open file/folder issues
- "Open folder" now says "open folder" instead of "open file" - "Open folder" won't allow you to open files - "Open file" won't allow you to open directories Fixes #249.
1 parent 473fd4c commit 627182e

File tree

4 files changed

+80
-13
lines changed

4 files changed

+80
-13
lines changed

packages/server/src/cli.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,13 @@ const bold = (text: string | number): string | number => {
200200
const webpackConfig = require(path.resolve(__dirname, "..", "..", "web", "webpack.config.js"));
201201
const compiler = require("webpack")(webpackConfig);
202202
app.use(require("webpack-dev-middleware")(compiler, {
203-
logger,
203+
logger: {
204+
trace: (m: string): void => logger.trace("webpack", field("message", m)),
205+
debug: (m: string): void => logger.debug("webpack", field("message", m)),
206+
info: (m: string): void => logger.info("webpack", field("message", m)),
207+
warn: (m: string): void => logger.warn("webpack", field("message", m)),
208+
error: (m: string): void => logger.error("webpack", field("message", m)),
209+
},
204210
publicPath: webpackConfig.output.publicPath,
205211
stats: webpackConfig.stats,
206212
}));

packages/vscode/src/dialog.scss

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
--primary: #2A2E37;
33
--border: black;
44
--faded: #a0a1a5;
5+
--disabled: #888;
56
--header-background: #161616;
67
--header-foreground: white;
78
--list-active-selection-background: rgb(0, 120, 160);
@@ -101,6 +102,12 @@
101102
background-color: var(--list-active-selection-background);
102103
color: var(--list-active-selection-foreground);
103104
}
105+
106+
&.disabled, &.disabled:hover {
107+
background-color: var(--primary);
108+
color: var(--disabled);
109+
cursor: initial;
110+
}
104111
}
105112
}
106113

@@ -134,6 +141,11 @@
134141
color: white;
135142
}
136143
}
144+
145+
button[disabled], button[disabled]:hover {
146+
color: var(--disabled);
147+
cursor: initial;
148+
}
137149
}
138150
}
139151

packages/vscode/src/dialog.ts

+47-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import { IThemeService } from "vs/platform/theme/common/themeService";
1616
import { workbench } from "./workbench";
1717
import "./dialog.scss";
1818

19+
/**
20+
* Describes the type of dialog to show.
21+
*/
1922
export enum DialogType {
2023
NewFolder,
2124
Save,
@@ -68,8 +71,12 @@ interface DialogEntry {
6871
readonly isDirectory: boolean;
6972
readonly size: number;
7073
readonly lastModified: string;
74+
readonly isDisabled?: boolean;
7175
}
7276

77+
/**
78+
* Open and save dialogs.
79+
*/
7380
class Dialog {
7481
private _path: string | undefined;
7582

@@ -265,8 +272,7 @@ class Dialog {
265272
}
266273
if (element.isDirectory) {
267274
this.path = element.fullPath;
268-
} else {
269-
// Open
275+
} else if (!(this.options as OpenDialogOptions).properties.openDirectory) {
270276
this.selectEmitter.emit(element.fullPath);
271277
}
272278
});
@@ -282,12 +288,18 @@ class Dialog {
282288
});
283289
buttonsNode.appendChild(cancelBtn);
284290
const confirmBtn = document.createElement("button");
285-
confirmBtn.innerText = "Confirm";
291+
const openFile = (this.options as OpenDialogOptions).properties.openFile;
292+
confirmBtn.innerText = openFile ? "Open" : "Confirm";
286293
confirmBtn.addEventListener("click", () => {
287-
if (this._path) {
294+
if (this._path && !openFile) {
288295
this.selectEmitter.emit(this._path);
289296
}
290297
});
298+
// Since a single click opens a file, the only time this button can be
299+
// used is on a directory, which is invalid for opening files.
300+
if (openFile) {
301+
confirmBtn.disabled = true;
302+
}
291303
buttonsNode.appendChild(confirmBtn);
292304
this.root.appendChild(buttonsNode);
293305
this.entryList.layout();
@@ -303,13 +315,19 @@ class Dialog {
303315
return this.errorEmitter.event;
304316
}
305317

318+
/**
319+
* Remove the dialog.
320+
*/
306321
public dispose(): void {
307322
this.selectEmitter.dispose();
308323
this.errorEmitter.dispose();
309324
this.entryList.dispose();
310325
this.background.remove();
311326
}
312327

328+
/**
329+
* Build and insert the path shown at the top of the dialog.
330+
*/
313331
private buildPath(): void {
314332
while (this.pathNode.lastChild) {
315333
this.pathNode.removeChild(this.pathNode.lastChild);
@@ -376,6 +394,9 @@ class Dialog {
376394
return (<any>this.entryList).typeFilterController.filter._pattern;
377395
}
378396

397+
/**
398+
* List the files and return dialog entries.
399+
*/
379400
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
380401
const paths = (await util.promisify(fs.readdir)(directory)).sort();
381402
const stats = await Promise.all(paths.map(p => util.promisify(fs.stat)(path.join(directory, p))));
@@ -386,6 +407,8 @@ class Dialog {
386407
isDirectory: stat.isDirectory(),
387408
lastModified: stat.mtime.toDateString(),
388409
size: stat.size,
410+
// If we are opening a directory, show files as disabled.
411+
isDisabled: !stat.isDirectory() && (this.options as OpenDialogOptions).properties.openDirectory,
389412
}));
390413
}
391414
}
@@ -397,11 +420,17 @@ interface DialogEntryData {
397420
label: HighlightedLabel;
398421
}
399422

423+
/**
424+
* Rendering for the different parts of a dialog entry.
425+
*/
400426
class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEntryData> {
401427
public get templateId(): string {
402428
return "dialog-entry";
403429
}
404430

431+
/**
432+
* Append and return containers for each part of the dialog entry.
433+
*/
405434
public renderTemplate(container: HTMLElement): DialogEntryData {
406435
addClass(container, "dialog-entry");
407436
addClass(container, "dialog-grid");
@@ -422,6 +451,9 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
422451
};
423452
}
424453

454+
/**
455+
* Render a dialog entry.
456+
*/
425457
public renderElement(node: ITreeNode<DialogEntry, string>, _index: number, templateData: DialogEntryData): void {
426458
templateData.icon.className = "dialog-entry-icon monaco-icon-label";
427459
const classes = getIconClasses(
@@ -444,8 +476,19 @@ class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEn
444476
}] : []);
445477
templateData.size.innerText = node.element.size.toString();
446478
templateData.lastModified.innerText = node.element.lastModified;
479+
480+
// We know this exists because we created the template.
481+
const entryContainer = templateData.label.element.parentElement!.parentElement!.parentElement!;
482+
if (node.element.isDisabled) {
483+
entryContainer.classList.add("disabled");
484+
} else {
485+
entryContainer.classList.remove("disabled");
486+
}
447487
}
448488

489+
/**
490+
* Does nothing (not implemented).
491+
*/
449492
public disposeTemplate(_templateData: DialogEntryData): void {
450493
// throw new Error("Method not implemented.");
451494
}

packages/vscode/src/fill/windowsService.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ export class WindowsService implements IWindowsService {
4747
private readonly window = new electron.BrowserWindow();
4848

4949
// Dialogs
50-
public async pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
50+
public async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
5151
showOpenDialog({
52-
...(_options.dialogOptions || {}),
52+
...(options.dialogOptions || {}),
5353
properties: {
5454
openFile: true,
5555
openDirectory: true,
@@ -66,9 +66,9 @@ export class WindowsService implements IWindowsService {
6666
});
6767
}
6868

69-
public async pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
69+
public async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
7070
showOpenDialog({
71-
...(_options.dialogOptions || {}),
71+
...(options.dialogOptions || {}),
7272
properties: {
7373
openFile: true,
7474
},
@@ -84,9 +84,15 @@ export class WindowsService implements IWindowsService {
8484
});
8585
}
8686

87-
public async pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
87+
public async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
88+
if (!options.dialogOptions) {
89+
options.dialogOptions = {};
90+
}
91+
if (!options.dialogOptions.title) {
92+
options.dialogOptions.title = "Open Folder";
93+
}
8894
showOpenDialog({
89-
...(_options.dialogOptions || {}),
95+
...(options.dialogOptions || {}),
9096
properties: {
9197
openDirectory: true,
9298
},
@@ -97,9 +103,9 @@ export class WindowsService implements IWindowsService {
97103
});
98104
}
99105

100-
public async pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
106+
public async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
101107
showOpenDialog({
102-
...(_options.dialogOptions || {}),
108+
...(options.dialogOptions || {}),
103109
properties: {
104110
openDirectory: true,
105111
},

0 commit comments

Comments
 (0)