mepcli 0.5.5 → 0.6.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/README.md +173 -6
- package/dist/ansi.d.ts +1 -0
- package/dist/ansi.js +1 -0
- package/dist/base.d.ts +1 -1
- package/dist/base.js +1 -10
- package/dist/core.d.ts +23 -1
- package/dist/core.js +60 -0
- package/dist/highlight.d.ts +1 -0
- package/dist/highlight.js +40 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/input.js +26 -14
- package/dist/prompts/autocomplete.d.ts +1 -1
- package/dist/prompts/autocomplete.js +2 -7
- package/dist/prompts/calendar.d.ts +20 -0
- package/dist/prompts/calendar.js +329 -0
- package/dist/prompts/checkbox.d.ts +1 -1
- package/dist/prompts/checkbox.js +38 -8
- package/dist/prompts/code.d.ts +17 -0
- package/dist/prompts/code.js +210 -0
- package/dist/prompts/color.d.ts +14 -0
- package/dist/prompts/color.js +147 -0
- package/dist/prompts/confirm.d.ts +1 -1
- package/dist/prompts/confirm.js +1 -1
- package/dist/prompts/cron.d.ts +13 -0
- package/dist/prompts/cron.js +176 -0
- package/dist/prompts/date.d.ts +1 -1
- package/dist/prompts/date.js +15 -5
- package/dist/prompts/editor.js +2 -2
- package/dist/prompts/file.d.ts +7 -0
- package/dist/prompts/file.js +56 -60
- package/dist/prompts/form.d.ts +17 -0
- package/dist/prompts/form.js +225 -0
- package/dist/prompts/grid.d.ts +14 -0
- package/dist/prompts/grid.js +178 -0
- package/dist/prompts/keypress.d.ts +2 -2
- package/dist/prompts/keypress.js +2 -2
- package/dist/prompts/list.d.ts +1 -1
- package/dist/prompts/list.js +42 -22
- package/dist/prompts/multi-select.d.ts +1 -1
- package/dist/prompts/multi-select.js +39 -4
- package/dist/prompts/number.d.ts +1 -1
- package/dist/prompts/number.js +2 -2
- package/dist/prompts/range.d.ts +9 -0
- package/dist/prompts/range.js +140 -0
- package/dist/prompts/rating.d.ts +1 -1
- package/dist/prompts/rating.js +1 -1
- package/dist/prompts/select.d.ts +1 -1
- package/dist/prompts/select.js +1 -1
- package/dist/prompts/slider.d.ts +1 -1
- package/dist/prompts/slider.js +1 -1
- package/dist/prompts/snippet.d.ts +18 -0
- package/dist/prompts/snippet.js +203 -0
- package/dist/prompts/sort.d.ts +1 -1
- package/dist/prompts/sort.js +1 -4
- package/dist/prompts/spam.d.ts +17 -0
- package/dist/prompts/spam.js +62 -0
- package/dist/prompts/table.d.ts +1 -1
- package/dist/prompts/table.js +1 -1
- package/dist/prompts/text.d.ts +1 -0
- package/dist/prompts/text.js +13 -31
- package/dist/prompts/toggle.d.ts +1 -1
- package/dist/prompts/toggle.js +1 -1
- package/dist/prompts/transfer.d.ts +18 -0
- package/dist/prompts/transfer.js +203 -0
- package/dist/prompts/tree-select.d.ts +32 -0
- package/dist/prompts/tree-select.js +277 -0
- package/dist/prompts/tree.d.ts +3 -3
- package/dist/prompts/tree.js +27 -19
- package/dist/prompts/wait.d.ts +18 -0
- package/dist/prompts/wait.js +62 -0
- package/dist/types.d.ts +84 -0
- package/dist/utils.js +1 -1
- package/example.ts +150 -15
- package/package.json +2 -2
package/dist/prompts/number.js
CHANGED
|
@@ -17,7 +17,7 @@ class NumberPrompt extends base_1.Prompt {
|
|
|
17
17
|
this.stringValue = options.initial !== undefined ? options.initial.toString() : '';
|
|
18
18
|
this.cursor = this.stringValue.length;
|
|
19
19
|
}
|
|
20
|
-
render(
|
|
20
|
+
render(_firstRender) {
|
|
21
21
|
// Prepare content
|
|
22
22
|
const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
|
|
23
23
|
// Prefix
|
|
@@ -122,7 +122,7 @@ class NumberPrompt extends base_1.Prompt {
|
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
124
|
// Numeric Input (and . and -)
|
|
125
|
-
if (/^[0-9
|
|
125
|
+
if (/^[0-9.-]+$/.test(char)) {
|
|
126
126
|
// Allow if it looks like a number part
|
|
127
127
|
this.stringValue = this.stringValue.slice(0, this.cursor) + char + this.stringValue.slice(this.cursor);
|
|
128
128
|
this.cursor += char.length;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { RangeOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class RangePrompt extends Prompt<[number, number], RangeOptions> {
|
|
4
|
+
private activeHandle;
|
|
5
|
+
constructor(options: RangeOptions);
|
|
6
|
+
protected render(_firstRender: boolean): void;
|
|
7
|
+
protected handleInput(char: string): void;
|
|
8
|
+
protected handleMouse(event: MouseEvent): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RangePrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
const symbols_1 = require("../symbols");
|
|
8
|
+
class RangePrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.activeHandle = 'low';
|
|
12
|
+
// Ensure initial is sorted and within bounds, default to [min, max] if not provided
|
|
13
|
+
const initial = options.initial || [options.min, options.max];
|
|
14
|
+
// Basic validation for initial
|
|
15
|
+
let [low, high] = initial;
|
|
16
|
+
low = Math.max(options.min, Math.min(low, options.max));
|
|
17
|
+
high = Math.max(options.min, Math.min(high, options.max));
|
|
18
|
+
if (low > high) {
|
|
19
|
+
[low, high] = [high, low];
|
|
20
|
+
}
|
|
21
|
+
this.value = [low, high];
|
|
22
|
+
}
|
|
23
|
+
render(_firstRender) {
|
|
24
|
+
const width = 20;
|
|
25
|
+
const range = this.options.max - this.options.min;
|
|
26
|
+
const [low, high] = this.value;
|
|
27
|
+
// Calculate positions (0 to width)
|
|
28
|
+
// Avoid division by zero if min == max
|
|
29
|
+
const ratioLow = range === 0 ? 0 : (low - this.options.min) / range;
|
|
30
|
+
const posLow = Math.round(ratioLow * width);
|
|
31
|
+
const ratioHigh = range === 0 ? 1 : (high - this.options.min) / range;
|
|
32
|
+
const posHigh = Math.round(ratioHigh * width);
|
|
33
|
+
let bar = '';
|
|
34
|
+
for (let i = 0; i <= width; i++) {
|
|
35
|
+
if (i === posLow && i === posHigh) {
|
|
36
|
+
// Collision
|
|
37
|
+
bar += `${theme_1.theme.main}|${ansi_1.ANSI.RESET}`;
|
|
38
|
+
}
|
|
39
|
+
else if (i === posLow) {
|
|
40
|
+
if (this.activeHandle === 'low') {
|
|
41
|
+
// Highlight active handle
|
|
42
|
+
bar += `${theme_1.theme.main}${ansi_1.ANSI.REVERSE}O${ansi_1.ANSI.RESET}`;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
bar += `${theme_1.theme.main}O${ansi_1.ANSI.RESET}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (i === posHigh) {
|
|
49
|
+
if (this.activeHandle === 'high') {
|
|
50
|
+
// Highlight active handle
|
|
51
|
+
bar += `${theme_1.theme.main}${ansi_1.ANSI.REVERSE}O${ansi_1.ANSI.RESET}`;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
bar += `${theme_1.theme.main}O${ansi_1.ANSI.RESET}`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (i > posLow && i < posHigh) {
|
|
58
|
+
// Active range
|
|
59
|
+
bar += `${theme_1.theme.main}=${ansi_1.ANSI.RESET}`;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Dimmed
|
|
63
|
+
bar += symbols_1.symbols.line;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const unit = this.options.unit || '';
|
|
67
|
+
// Format the value display
|
|
68
|
+
let valueDisplay = '';
|
|
69
|
+
if (this.activeHandle === 'low') {
|
|
70
|
+
valueDisplay = `${ansi_1.ANSI.UNDERLINE}${low}${ansi_1.ANSI.RESET}-${high}`;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
valueDisplay = `${low}-${ansi_1.ANSI.UNDERLINE}${high}${ansi_1.ANSI.RESET}`;
|
|
74
|
+
}
|
|
75
|
+
const output = `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} [${bar}] ${valueDisplay}${unit}`;
|
|
76
|
+
this.renderFrame(output);
|
|
77
|
+
}
|
|
78
|
+
handleInput(char) {
|
|
79
|
+
if (char === '\r' || char === '\n') {
|
|
80
|
+
this.submit(this.value);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (char === ' ' || char === '\t') {
|
|
84
|
+
this.activeHandle = this.activeHandle === 'low' ? 'high' : 'low';
|
|
85
|
+
this.render(false);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const step = this.options.step || 1;
|
|
89
|
+
let [low, high] = this.value;
|
|
90
|
+
if (this.isLeft(char)) { // Left
|
|
91
|
+
if (this.activeHandle === 'low') {
|
|
92
|
+
low = Math.max(this.options.min, low - step);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
high = Math.max(low, high - step);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (this.isRight(char)) { // Right
|
|
99
|
+
if (this.activeHandle === 'low') {
|
|
100
|
+
low = Math.min(high, low + step);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
high = Math.min(this.options.max, high + step);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Rounding to avoid floating point errors
|
|
107
|
+
low = Math.round(low * 10000) / 10000;
|
|
108
|
+
high = Math.round(high * 10000) / 10000;
|
|
109
|
+
this.value = [low, high];
|
|
110
|
+
this.render(false);
|
|
111
|
+
}
|
|
112
|
+
handleMouse(event) {
|
|
113
|
+
if (event.action === 'scroll') {
|
|
114
|
+
const step = this.options.step || 1;
|
|
115
|
+
let [low, high] = this.value;
|
|
116
|
+
if (event.scroll === 'up') { // Increase
|
|
117
|
+
if (this.activeHandle === 'low') {
|
|
118
|
+
low = Math.min(high, low + step);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
high = Math.min(this.options.max, high + step);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (event.scroll === 'down') { // Decrease
|
|
125
|
+
if (this.activeHandle === 'low') {
|
|
126
|
+
low = Math.max(this.options.min, low - step);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
high = Math.max(low, high - step);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Rounding
|
|
133
|
+
low = Math.round(low * 10000) / 10000;
|
|
134
|
+
high = Math.round(high * 10000) / 10000;
|
|
135
|
+
this.value = [low, high];
|
|
136
|
+
this.render(false);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.RangePrompt = RangePrompt;
|
package/dist/prompts/rating.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Prompt } from '../base';
|
|
|
2
2
|
import { RatingOptions, MouseEvent } from '../types';
|
|
3
3
|
export declare class RatingPrompt extends Prompt<number, RatingOptions> {
|
|
4
4
|
constructor(options: RatingOptions);
|
|
5
|
-
protected render(
|
|
5
|
+
protected render(_firstRender: boolean): void;
|
|
6
6
|
protected handleInput(char: string): void;
|
|
7
7
|
protected handleMouse(event: MouseEvent): void;
|
|
8
8
|
}
|
package/dist/prompts/rating.js
CHANGED
|
@@ -11,7 +11,7 @@ class RatingPrompt extends base_1.Prompt {
|
|
|
11
11
|
// Default to min if initial is not provided
|
|
12
12
|
this.value = options.initial ?? (options.min || 1);
|
|
13
13
|
}
|
|
14
|
-
render(
|
|
14
|
+
render(_firstRender) {
|
|
15
15
|
const min = this.options.min || 1;
|
|
16
16
|
const max = this.options.max || 5;
|
|
17
17
|
// Render stars
|
package/dist/prompts/select.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare class SelectPrompt<V> extends Prompt<any, SelectOptions<V>> {
|
|
|
9
9
|
private isSeparator;
|
|
10
10
|
private findNextSelectableIndex;
|
|
11
11
|
private getFilteredChoices;
|
|
12
|
-
protected render(
|
|
12
|
+
protected render(_firstRender: boolean): void;
|
|
13
13
|
protected handleInput(char: string): void;
|
|
14
14
|
protected handleMouse(event: MouseEvent): void;
|
|
15
15
|
}
|
package/dist/prompts/select.js
CHANGED
|
@@ -50,7 +50,7 @@ class SelectPrompt extends base_1.Prompt {
|
|
|
50
50
|
return c.title.toLowerCase().includes(this.searchBuffer.toLowerCase());
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
-
render(
|
|
53
|
+
render(_firstRender) {
|
|
54
54
|
let output = '';
|
|
55
55
|
const choices = this.getFilteredChoices();
|
|
56
56
|
// Adjust Scroll Top
|
package/dist/prompts/slider.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Prompt } from '../base';
|
|
|
2
2
|
import { SliderOptions, MouseEvent } from '../types';
|
|
3
3
|
export declare class SliderPrompt extends Prompt<number, SliderOptions> {
|
|
4
4
|
constructor(options: SliderOptions);
|
|
5
|
-
protected render(
|
|
5
|
+
protected render(_firstRender: boolean): void;
|
|
6
6
|
protected handleInput(char: string): void;
|
|
7
7
|
protected handleMouse(event: MouseEvent): void;
|
|
8
8
|
}
|
package/dist/prompts/slider.js
CHANGED
|
@@ -11,7 +11,7 @@ class SliderPrompt extends base_1.Prompt {
|
|
|
11
11
|
super(options);
|
|
12
12
|
this.value = options.initial ?? options.min;
|
|
13
13
|
}
|
|
14
|
-
render(
|
|
14
|
+
render(_firstRender) {
|
|
15
15
|
const width = 20;
|
|
16
16
|
const range = this.options.max - this.options.min;
|
|
17
17
|
const ratio = (this.value - this.options.min) / range;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { SnippetOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class SnippetPrompt extends Prompt<string, SnippetOptions> {
|
|
4
|
+
private tokens;
|
|
5
|
+
private variableTokens;
|
|
6
|
+
private values;
|
|
7
|
+
private activeVarIndex;
|
|
8
|
+
private cursor;
|
|
9
|
+
private errorMsg;
|
|
10
|
+
private lastLinesUp;
|
|
11
|
+
constructor(options: SnippetOptions);
|
|
12
|
+
private parseTemplate;
|
|
13
|
+
protected render(firstRender: boolean): void;
|
|
14
|
+
protected handleInput(char: string, _key: Buffer): void;
|
|
15
|
+
protected handleMouse(event: MouseEvent): void;
|
|
16
|
+
private moveFocus;
|
|
17
|
+
private submitSnippet;
|
|
18
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SnippetPrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
class SnippetPrompt extends base_1.Prompt {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super(options);
|
|
10
|
+
this.tokens = [];
|
|
11
|
+
this.variableTokens = []; // Indices in this.tokens
|
|
12
|
+
this.values = {};
|
|
13
|
+
this.activeVarIndex = 0; // Index in variableTokens
|
|
14
|
+
this.cursor = 0; // Cursor in active variable value
|
|
15
|
+
this.errorMsg = '';
|
|
16
|
+
this.lastLinesUp = 0;
|
|
17
|
+
this.parseTemplate();
|
|
18
|
+
// Initialize values
|
|
19
|
+
if (options.values) {
|
|
20
|
+
this.values = { ...options.values };
|
|
21
|
+
}
|
|
22
|
+
// Ensure all vars have entries
|
|
23
|
+
this.variableTokens.forEach(idx => {
|
|
24
|
+
const varName = this.tokens[idx].value;
|
|
25
|
+
if (this.values[varName] === undefined) {
|
|
26
|
+
this.values[varName] = '';
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (this.variableTokens.length > 0) {
|
|
30
|
+
const firstVar = this.tokens[this.variableTokens[0]].value;
|
|
31
|
+
this.cursor = this.values[firstVar].length;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
parseTemplate() {
|
|
35
|
+
const regex = /\$\{([a-zA-Z0-9_]+)\}/g;
|
|
36
|
+
let lastIndex = 0;
|
|
37
|
+
let match;
|
|
38
|
+
while ((match = regex.exec(this.options.template)) !== null) {
|
|
39
|
+
if (match.index > lastIndex) {
|
|
40
|
+
this.tokens.push({ type: 'static', value: this.options.template.substring(lastIndex, match.index) });
|
|
41
|
+
}
|
|
42
|
+
this.tokens.push({ type: 'variable', value: match[1] });
|
|
43
|
+
this.variableTokens.push(this.tokens.length - 1);
|
|
44
|
+
lastIndex = regex.lastIndex;
|
|
45
|
+
}
|
|
46
|
+
if (lastIndex < this.options.template.length) {
|
|
47
|
+
this.tokens.push({ type: 'static', value: this.options.template.substring(lastIndex) });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
render(firstRender) {
|
|
51
|
+
if (!firstRender && this.lastLinesUp > 0) {
|
|
52
|
+
this.print(`\x1b[${this.lastLinesUp}B`);
|
|
53
|
+
}
|
|
54
|
+
this.lastLinesUp = 0;
|
|
55
|
+
// Build the string
|
|
56
|
+
let output = '';
|
|
57
|
+
let cursorVisualIndex = 0;
|
|
58
|
+
let currentVisualIndex = 0;
|
|
59
|
+
// Prefix/Message
|
|
60
|
+
const prefix = `${theme_1.theme.success}? ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message || 'Fill snippet'}${ansi_1.ANSI.RESET}\n`;
|
|
61
|
+
output += prefix;
|
|
62
|
+
// cursorVisualIndex should start after prefix?
|
|
63
|
+
// Actually renderFrame handles newlines.
|
|
64
|
+
// We will construct the snippet line.
|
|
65
|
+
let snippetLine = '';
|
|
66
|
+
this.tokens.forEach((token, index) => {
|
|
67
|
+
if (token.type === 'static') {
|
|
68
|
+
snippetLine += `${theme_1.theme.muted}${token.value}${ansi_1.ANSI.RESET}`;
|
|
69
|
+
currentVisualIndex += token.value.length; // assuming simple ascii/static length
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const isFocused = this.variableTokens[this.activeVarIndex] === index;
|
|
73
|
+
const val = this.values[token.value] || '';
|
|
74
|
+
// Placeholder if empty?
|
|
75
|
+
const displayVal = val.length === 0 && isFocused ? '' : val; // maybe show placeholder?
|
|
76
|
+
let styledVal = displayVal;
|
|
77
|
+
if (isFocused) {
|
|
78
|
+
styledVal = `${ansi_1.ANSI.UNDERLINE}${theme_1.theme.main}${displayVal}${ansi_1.ANSI.RESET}`;
|
|
79
|
+
// Calculate cursor position
|
|
80
|
+
cursorVisualIndex = currentVisualIndex + this.cursor;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
styledVal = `${theme_1.theme.main}${displayVal}${ansi_1.ANSI.RESET}`;
|
|
84
|
+
}
|
|
85
|
+
snippetLine += styledVal;
|
|
86
|
+
currentVisualIndex += displayVal.length;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
output += snippetLine;
|
|
90
|
+
if (this.errorMsg) {
|
|
91
|
+
output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
|
|
92
|
+
}
|
|
93
|
+
output += `\n${theme_1.theme.muted}(Tab to next variable, Enter to submit)${ansi_1.ANSI.RESET}`;
|
|
94
|
+
this.renderFrame(output);
|
|
95
|
+
// Position Cursor
|
|
96
|
+
this.print(ansi_1.ANSI.SHOW_CURSOR);
|
|
97
|
+
// We need to move to correct line and column
|
|
98
|
+
// Lines:
|
|
99
|
+
// 1. Message
|
|
100
|
+
// 2. Snippet (cursor here)
|
|
101
|
+
// 3. Error (optional)
|
|
102
|
+
// 4. Hint
|
|
103
|
+
// snippetLine is at index 1 (0-based) if Message has no newlines.
|
|
104
|
+
// Prefix ends with \n. So snippetLine is on 2nd line.
|
|
105
|
+
// Calculate which row relative to bottom the snippet line is.
|
|
106
|
+
// If error: 4 lines total. Snippet is line 1 (2nd). Lines up = 2.
|
|
107
|
+
// If no error: 3 lines total. Snippet is line 1. Lines up = 1.
|
|
108
|
+
let linesUp = 1;
|
|
109
|
+
if (this.errorMsg)
|
|
110
|
+
linesUp++;
|
|
111
|
+
if (linesUp > 0) {
|
|
112
|
+
this.print(`\x1b[${linesUp}A`);
|
|
113
|
+
this.lastLinesUp = linesUp;
|
|
114
|
+
}
|
|
115
|
+
this.print(ansi_1.ANSI.CURSOR_LEFT);
|
|
116
|
+
if (cursorVisualIndex > 0) {
|
|
117
|
+
this.print(`\x1b[${cursorVisualIndex}C`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
handleInput(char, _key) {
|
|
121
|
+
// Navigation: Tab / Shift+Tab
|
|
122
|
+
if (char === '\u001b[Z') {
|
|
123
|
+
// Shift Tab -> Prev
|
|
124
|
+
this.moveFocus(-1);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (char === '\t') {
|
|
128
|
+
this.moveFocus(1);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Enter
|
|
132
|
+
if (char === '\r' || char === '\n') {
|
|
133
|
+
this.submitSnippet();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Editing
|
|
137
|
+
const activeTokenIdx = this.variableTokens[this.activeVarIndex];
|
|
138
|
+
const varName = this.tokens[activeTokenIdx].value;
|
|
139
|
+
const val = this.values[varName];
|
|
140
|
+
if (char === '\u0008' || char === '\x7f') { // Backspace
|
|
141
|
+
if (this.cursor > 0) {
|
|
142
|
+
const pre = val.slice(0, this.cursor - 1);
|
|
143
|
+
const post = val.slice(this.cursor);
|
|
144
|
+
this.values[varName] = pre + post;
|
|
145
|
+
this.cursor--;
|
|
146
|
+
this.render(false);
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (this.isLeft(char)) {
|
|
151
|
+
if (this.cursor > 0)
|
|
152
|
+
this.cursor--;
|
|
153
|
+
this.render(false);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (this.isRight(char)) {
|
|
157
|
+
if (this.cursor < val.length)
|
|
158
|
+
this.cursor++;
|
|
159
|
+
this.render(false);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
|
|
163
|
+
const pre = val.slice(0, this.cursor);
|
|
164
|
+
const post = val.slice(this.cursor);
|
|
165
|
+
this.values[varName] = pre + char + post;
|
|
166
|
+
this.cursor += char.length;
|
|
167
|
+
this.render(false);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
handleMouse(event) {
|
|
171
|
+
if (event.action === 'scroll') {
|
|
172
|
+
if (event.scroll === 'up') {
|
|
173
|
+
this.moveFocus(-1);
|
|
174
|
+
}
|
|
175
|
+
else if (event.scroll === 'down') {
|
|
176
|
+
this.moveFocus(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
moveFocus(direction) {
|
|
181
|
+
const nextIndex = this.activeVarIndex + direction;
|
|
182
|
+
if (nextIndex >= 0 && nextIndex < this.variableTokens.length) {
|
|
183
|
+
this.activeVarIndex = nextIndex;
|
|
184
|
+
const varName = this.tokens[this.variableTokens[this.activeVarIndex]].value;
|
|
185
|
+
this.cursor = this.values[varName].length;
|
|
186
|
+
this.render(false);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
submitSnippet() {
|
|
190
|
+
// Construct final string
|
|
191
|
+
let result = '';
|
|
192
|
+
this.tokens.forEach(token => {
|
|
193
|
+
if (token.type === 'static') {
|
|
194
|
+
result += token.value;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
result += this.values[token.value] || '';
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
this.submit(result);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.SnippetPrompt = SnippetPrompt;
|
package/dist/prompts/sort.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class SortPrompt extends Prompt<string[], SortOptions> {
|
|
|
7
7
|
private scrollTop;
|
|
8
8
|
private readonly pageSize;
|
|
9
9
|
constructor(options: SortOptions);
|
|
10
|
-
protected render(
|
|
10
|
+
protected render(_firstRender: boolean): void;
|
|
11
11
|
protected handleInput(char: string): void;
|
|
12
12
|
private swap;
|
|
13
13
|
protected handleMouse(event: MouseEvent): void;
|
package/dist/prompts/sort.js
CHANGED
|
@@ -14,7 +14,7 @@ class SortPrompt extends base_1.Prompt {
|
|
|
14
14
|
this.pageSize = 10;
|
|
15
15
|
this.items = [...options.items];
|
|
16
16
|
}
|
|
17
|
-
render(
|
|
17
|
+
render(_firstRender) {
|
|
18
18
|
// Adjust Scroll Top
|
|
19
19
|
if (this.selectedIndex < this.scrollTop) {
|
|
20
20
|
this.scrollTop = this.selectedIndex;
|
|
@@ -120,9 +120,6 @@ class SortPrompt extends base_1.Prompt {
|
|
|
120
120
|
swap(i, j) {
|
|
121
121
|
[this.items[i], this.items[j]] = [this.items[j], this.items[i]];
|
|
122
122
|
}
|
|
123
|
-
// Mouse support?
|
|
124
|
-
// Drag and drop is hard with just clicks/scroll.
|
|
125
|
-
// Maybe click to grab, scroll to move?
|
|
126
123
|
handleMouse(event) {
|
|
127
124
|
// Simple scroll support for navigation
|
|
128
125
|
if (event.action === 'scroll') {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { BaseOptions } from '../types';
|
|
3
|
+
interface SpamOptions extends BaseOptions {
|
|
4
|
+
threshold: number;
|
|
5
|
+
spamKey?: string;
|
|
6
|
+
decay?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare class SpamPrompt extends Prompt<boolean, SpamOptions> {
|
|
9
|
+
private count;
|
|
10
|
+
private width;
|
|
11
|
+
private decayTimer?;
|
|
12
|
+
constructor(options: SpamOptions);
|
|
13
|
+
protected cleanup(): void;
|
|
14
|
+
protected render(_firstRender: boolean): void;
|
|
15
|
+
protected handleInput(char: string): void;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SpamPrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
const symbols_1 = require("../symbols");
|
|
8
|
+
class SpamPrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.count = 0;
|
|
12
|
+
this.width = 20; // Visual width of the bar
|
|
13
|
+
if (options.decay) {
|
|
14
|
+
this.decayTimer = setInterval(() => {
|
|
15
|
+
if (this.count > 0) {
|
|
16
|
+
this.count = Math.max(0, this.count - 1);
|
|
17
|
+
this.render(false);
|
|
18
|
+
}
|
|
19
|
+
}, 200); // Drop 5 presses per second
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
cleanup() {
|
|
23
|
+
if (this.decayTimer)
|
|
24
|
+
clearInterval(this.decayTimer);
|
|
25
|
+
super.cleanup();
|
|
26
|
+
}
|
|
27
|
+
render(_firstRender) {
|
|
28
|
+
const progress = Math.min(this.count / this.options.threshold, 1);
|
|
29
|
+
const filledLen = Math.round(progress * this.width);
|
|
30
|
+
const emptyLen = this.width - filledLen;
|
|
31
|
+
// Visual Bar: [#####-----]
|
|
32
|
+
const filled = symbols_1.symbols.line.repeat(filledLen).replace(/./g, '#'); // Or use block char
|
|
33
|
+
const empty = symbols_1.symbols.line.repeat(emptyLen);
|
|
34
|
+
const barColor = progress === 1 ? theme_1.theme.success : theme_1.theme.error;
|
|
35
|
+
const bar = `${theme_1.theme.muted}[${barColor}${filled}${theme_1.theme.muted}${empty}]${ansi_1.ANSI.RESET}`;
|
|
36
|
+
let output = `${theme_1.theme.error}${symbols_1.symbols.cross} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
37
|
+
output += ` ${bar} ${Math.floor(progress * 100)}%`;
|
|
38
|
+
if (this.count >= this.options.threshold) {
|
|
39
|
+
output += ` ${theme_1.theme.success} READY! Press Enter${ansi_1.ANSI.RESET}`;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
output += ` ${theme_1.theme.muted}(Mash '${this.options.spamKey || 'Space'}' to fill)${ansi_1.ANSI.RESET}`;
|
|
43
|
+
}
|
|
44
|
+
this.renderFrame(output);
|
|
45
|
+
}
|
|
46
|
+
handleInput(char) {
|
|
47
|
+
// Confirm execution
|
|
48
|
+
if (this.count >= this.options.threshold && (char === '\r' || char === '\n')) {
|
|
49
|
+
this.submit(true);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const trigger = this.options.spamKey || ' ';
|
|
53
|
+
// Check if key matches (or any key if not specified)
|
|
54
|
+
if (char === trigger) {
|
|
55
|
+
if (this.count < this.options.threshold) {
|
|
56
|
+
this.count++;
|
|
57
|
+
this.render(false);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.SpamPrompt = SpamPrompt;
|
package/dist/prompts/table.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class TablePrompt<V> extends Prompt<V, TableOptions<V>> {
|
|
|
7
7
|
private colWidths;
|
|
8
8
|
constructor(options: TableOptions<V>);
|
|
9
9
|
private calculateColWidths;
|
|
10
|
-
protected render(
|
|
10
|
+
protected render(_firstRender: boolean): void;
|
|
11
11
|
private pad;
|
|
12
12
|
protected handleInput(char: string): void;
|
|
13
13
|
protected handleMouse(event: MouseEvent): void;
|
package/dist/prompts/table.js
CHANGED
|
@@ -28,7 +28,7 @@ class TablePrompt extends base_1.Prompt {
|
|
|
28
28
|
// Add padding
|
|
29
29
|
this.colWidths = this.colWidths.map(w => w + 2);
|
|
30
30
|
}
|
|
31
|
-
render(
|
|
31
|
+
render(_firstRender) {
|
|
32
32
|
// Scroll Logic
|
|
33
33
|
if (this.selectedIndex < this.scrollTop) {
|
|
34
34
|
this.scrollTop = this.selectedIndex;
|
package/dist/prompts/text.d.ts
CHANGED