/
toggle.ts
146 lines (129 loc) 路 3.79 KB
/
toggle.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
import type { KeyCode } from "../keycode/key_code.ts";
import { brightBlue, dim, underline, yellow } from "./deps.ts";
import { Figures } from "./figures.ts";
import {
GenericPrompt,
GenericPromptKeys,
GenericPromptOptions,
GenericPromptSettings,
} from "./_generic_prompt.ts";
/** Toggle key options. */
export interface ToggleKeys extends GenericPromptKeys {
active?: string[];
inactive?: string[];
}
/** Generic prompt options. */
export interface ToggleOptions extends GenericPromptOptions<boolean, string> {
active?: string;
inactive?: string;
keys?: ToggleKeys;
}
/** Toggle prompt settings. */
interface ToggleSettings extends GenericPromptSettings<boolean, string> {
active: string;
inactive: string;
keys: ToggleKeys;
}
/** Toggle prompt representation. */
export class Toggle extends GenericPrompt<boolean, string, ToggleSettings> {
protected status: string = typeof this.settings.default !== "undefined"
? this.format(this.settings.default)
: "";
/** Execute the prompt and show cursor on end. */
public static prompt(
options: string | ToggleOptions,
): Promise<boolean> {
if (typeof options === "string") {
options = { message: options };
}
return new this({
pointer: brightBlue(Figures.POINTER_SMALL),
prefix: yellow("? "),
indent: " ",
active: "Yes",
inactive: "No",
...options,
keys: {
active: ["right", "y", "j", "s", "o"],
inactive: ["left", "n"],
...(options.keys ?? {}),
},
}).prompt();
}
protected message(): string {
let message = super.message() + " " + this.settings.pointer + " ";
if (this.status === this.settings.active) {
message += dim(this.settings.inactive + " / ") +
underline(this.settings.active);
} else if (this.status === this.settings.inactive) {
message += underline(this.settings.inactive) +
dim(" / " + this.settings.active);
} else {
message += dim(this.settings.inactive + " / " + this.settings.active);
}
return message;
}
/** Read user input from stdin, handle events and validate user input. */
protected read(): Promise<boolean> {
this.tty.cursorHide();
return super.read();
}
/**
* Handle user input event.
* @param event Key event.
*/
protected async handleEvent(event: KeyCode): Promise<void> {
switch (true) {
case event.sequence === this.settings.inactive[0].toLowerCase():
case this.isKey(this.settings.keys, "inactive", event):
this.selectInactive();
break;
case event.sequence === this.settings.active[0].toLowerCase():
case this.isKey(this.settings.keys, "active", event):
this.selectActive();
break;
default:
await super.handleEvent(event);
}
}
/** Set active. */
protected selectActive() {
this.status = this.settings.active;
}
/** Set inactive. */
protected selectInactive() {
this.status = this.settings.inactive;
}
/**
* Validate input value.
* @param value User input value.
* @return True on success, false or error message on error.
*/
protected validate(value: string): boolean | string {
return [this.settings.active, this.settings.inactive].indexOf(value) !== -1;
}
/**
* Map input value to output value.
* @param value Input value.
* @return Output value.
*/
protected transform(value: string): boolean | undefined {
switch (value) {
case this.settings.active:
return true;
case this.settings.inactive:
return false;
}
}
/**
* Format output value.
* @param value Output value.
*/
protected format(value: boolean): string {
return value ? this.settings.active : this.settings.inactive;
}
/** Get input value. */
protected getValue(): string {
return this.status;
}
}