-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathdialog.ts
160 lines (143 loc) · 5.16 KB
/
dialog.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import * as vscode from "vscode";
import { Logger } from "../utilities";
type Item<T> = [label: string, value: T];
type NotificationButton = [label: string, callback: () => void];
export interface PercentProgress {
message?: string;
percent?: number;
}
/**
* A class that provides a centralized interface to user dialogue.
*/
export default class Dialog {
private static readonly _logsButton: NotificationButton = [
"Show logs",
(): void => Logger.show(),
];
/**
* Creates a new instance of Dialogue class.
*/
constructor() {}
/**
* Prompts the user with a yes/no dialog.
*
* @param prompt A prompt to present to the user.
* @returns A Boolean indicating the answer or `undefined` if dialogue was dismissed.
*/
public async confirmation(prompt: string): Promise<boolean | undefined> {
return this.selectItem(prompt, ["Yes", true], ["No", false]);
}
/**
* Wrapper for `vscode.window.showErrorMessage` that resolves optional items to associated
* callbacks.
*/
public async errorNotification(
notification: string,
error?: Error,
...items: NotificationButton[]
): Promise<void> {
if (error) {
// Refactor notice: This looks a bit iffy. Maybe error should always exist when calling
// this function?
Logger.error(notification, error);
items = items.concat([Dialog._logsButton]);
}
return vscode.window
.showErrorMessage(`TestMyCode: ${notification}`, ...items.map((item) => item[0]))
.then((selection) => {
items.find((item) => item[0] === selection)?.[1]();
});
}
/**
* Prompts the user with a text input that requires explicitly typing a confirmation.
*
* @param prompt A prompt to be displayed to the user.
* @returns True if and only if user typed `yes`.
*/
public async explicitConfirmation(prompt: string): Promise<boolean> {
return vscode.window
.showInputBox({
placeHolder: "Write 'Yes' to confirm or 'No' to cancel and press 'Enter'.",
prompt,
})
.then((x) => x?.toLocaleLowerCase() === "yes");
}
/**
* Wrapper for `vscode.window.showInformationMessage` that resolves optional items to their
* associated callbacks.
*/
public async notification(message: string, ...items: NotificationButton[]): Promise<void> {
return vscode.window
.showInformationMessage(`TestMyCode: ${message}`, ...items.map((item) => item[0]))
.then((selection) => {
items.find((item) => item[0] === selection)?.[1]();
});
}
/**
* Shows a progress notification to the user.
*
* @param message A prompt to be displayed to the user.
* @param task Long task that determines the duration of the notification.
*/
public async progressNotification<T>(
message: string,
task: (progress: vscode.Progress<PercentProgress>) => Promise<T>,
): Promise<T> {
return vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: "TestMyCode",
},
(progress) => {
progress.report({ message, increment: 0 });
const percentageProgress = this._incrementPercentageWrapper(progress);
return task(percentageProgress);
},
);
}
/**
* Prompts the user with a selection of items and returns their corresponding value.
*/
public async selectItem<T>(prompt: string, ...items: Item<T>[]): Promise<T | undefined> {
return vscode.window
.showQuickPick(
items.map((i) => i[0]),
{ placeHolder: prompt },
)
.then((selection) => items.find((x) => x[0] === selection)?.[1]);
}
/**
* Wrapper for `vscode.window.showWarningMessage` that resolves optional items to associated
* callbacks.
*/
public async warningNotification(
message: string,
...items: NotificationButton[]
): Promise<void> {
return vscode.window
.showWarningMessage(`TestMyCode: ${message}`, ...items.map((item) => item[0]))
.then((selection) => {
items.find((item) => item[0] === selection)?.[1]();
});
}
/**
* Wraps increment-style `vscode.Progress` with a version that allows reporting simple
* percentages instead. This is mostly useful when using `vscode.window.withProgress`.
*/
private _incrementPercentageWrapper(
progress: vscode.Progress<{ message?: string; increment: number }>,
): vscode.Progress<PercentProgress> {
let peak = 0;
const report: (value: { message?: string; percent: number }) => void = ({
message,
percent,
}) => {
const increment = 100 * (percent - peak);
if (increment > 0) {
progress.report({ message, increment });
peak = percent;
}
};
return { report };
}
}