mepcli 0.5.0 → 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 +182 -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 +26 -1
- package/dist/core.js +72 -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.d.ts +14 -0
- package/dist/prompts/editor.js +207 -0
- 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 +7 -0
- package/dist/prompts/keypress.js +57 -0
- 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 +14 -32
- 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 +20 -0
- package/dist/prompts/tree.js +231 -0
- package/dist/prompts/wait.d.ts +18 -0
- package/dist/prompts/wait.js +62 -0
- package/dist/types.d.ts +105 -0
- package/dist/utils.js +6 -2
- package/example.ts +213 -27
- package/package.json +14 -4
|
@@ -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
package/dist/prompts/text.js
CHANGED
|
@@ -15,14 +15,18 @@ class TextPrompt extends base_1.Prompt {
|
|
|
15
15
|
this.cursor = 0;
|
|
16
16
|
this.hasTyped = false;
|
|
17
17
|
this.segments = [];
|
|
18
|
+
this.lastLinesUp = 0;
|
|
18
19
|
this.value = options.initial || '';
|
|
19
20
|
// Initialize segments from value
|
|
20
21
|
this.segments = (0, utils_1.safeSplit)(this.value);
|
|
21
22
|
this.cursor = this.segments.length;
|
|
22
23
|
}
|
|
23
24
|
render(firstRender) {
|
|
25
|
+
if (!firstRender && this.lastLinesUp > 0) {
|
|
26
|
+
this.print(`\x1b[${this.lastLinesUp}B`);
|
|
27
|
+
}
|
|
28
|
+
this.lastLinesUp = 0;
|
|
24
29
|
// Calculate available width
|
|
25
|
-
const cols = process.stdout.columns || 80;
|
|
26
30
|
// 1. Prepare Prompt Label
|
|
27
31
|
const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
|
|
28
32
|
const hint = this.options.multiline ? ` ${theme_1.theme.muted}(Press Ctrl+D to submit)${ansi_1.ANSI.RESET}` : '';
|
|
@@ -43,31 +47,16 @@ class TextPrompt extends base_1.Prompt {
|
|
|
43
47
|
cursorRelativeCol = 0;
|
|
44
48
|
}
|
|
45
49
|
else {
|
|
46
|
-
const
|
|
50
|
+
const maskChar = this.options.mask ?? (this.options.isPassword ? '*' : undefined);
|
|
47
51
|
// Note: password masking replaces each grapheme with '*'
|
|
48
52
|
// Split by lines (for multiline support)
|
|
49
|
-
const lines = rawValue.split('\n');
|
|
50
53
|
// Determine which line the cursor is on
|
|
51
54
|
// We need to map 'cursor' (segments index) to line/col.
|
|
52
55
|
// This is tricky because segments might contain '\n'.
|
|
53
56
|
// safeSplit treats '\n' as a segment.
|
|
54
57
|
let cursorLineIndex = 0;
|
|
55
|
-
let cursorSegmentIndexOnLine = 0;
|
|
56
|
-
let currentSegmentIndex = 0;
|
|
57
|
-
for (let i = 0; i < lines.length; i++) {
|
|
58
|
-
// How many segments in this line?
|
|
59
|
-
// We can't just use lines[i].length because that's chars.
|
|
60
|
-
// We need to split the line again or iterate segments.
|
|
61
|
-
// Iterating segments is safer.
|
|
62
|
-
// Let's assume we iterate global segments until we hit a newline segment
|
|
63
|
-
let lineSegmentsCount = 0;
|
|
64
|
-
// Since rawValue.split('\n') consumes the newlines, we need to account for them.
|
|
65
|
-
// Alternative: iterate this.segments
|
|
66
|
-
// Find where the cursor falls.
|
|
67
|
-
}
|
|
68
58
|
// Let's iterate segments to find cursor position (row, col)
|
|
69
59
|
cursorLineIndex = 0;
|
|
70
|
-
let colIndex = 0; // Visual column or char index?
|
|
71
60
|
// If we want visual cursor position, we need visual width of segments.
|
|
72
61
|
let visualColIndex = 0;
|
|
73
62
|
for (let i = 0; i < this.cursor; i++) {
|
|
@@ -77,11 +66,11 @@ class TextPrompt extends base_1.Prompt {
|
|
|
77
66
|
visualColIndex = 0;
|
|
78
67
|
}
|
|
79
68
|
else {
|
|
80
|
-
if (
|
|
81
|
-
visualColIndex +=
|
|
69
|
+
if (maskChar !== undefined) {
|
|
70
|
+
visualColIndex += maskChar.length;
|
|
82
71
|
}
|
|
83
72
|
else {
|
|
84
|
-
visualColIndex += this.
|
|
73
|
+
visualColIndex += this.getSegmentWidth(seg);
|
|
85
74
|
}
|
|
86
75
|
}
|
|
87
76
|
}
|
|
@@ -90,7 +79,7 @@ class TextPrompt extends base_1.Prompt {
|
|
|
90
79
|
// Now prepare lines for display (scrolling/truncation)
|
|
91
80
|
// We need to reconstruct lines from segments to apply styling/truncation logic per line.
|
|
92
81
|
let currentLineSegments = [];
|
|
93
|
-
|
|
82
|
+
const processedLines = []; // Array of segment arrays
|
|
94
83
|
for (const seg of this.segments) {
|
|
95
84
|
if (seg === '\n') {
|
|
96
85
|
processedLines.push(currentLineSegments);
|
|
@@ -101,24 +90,16 @@ class TextPrompt extends base_1.Prompt {
|
|
|
101
90
|
}
|
|
102
91
|
}
|
|
103
92
|
processedLines.push(currentLineSegments); // Last line
|
|
104
|
-
processedLines.forEach((lineSegs
|
|
105
|
-
const isCursorLine = idx === cursorLineIndex;
|
|
106
|
-
const linePrefixLen = (idx === 0) ? prefixVisualLen : 0;
|
|
107
|
-
const maxContentLen = Math.max(10, cols - linePrefixLen - 1);
|
|
93
|
+
processedLines.forEach((lineSegs) => {
|
|
108
94
|
// Reconstruct line string for display calculation
|
|
109
95
|
// If password, join with *?
|
|
110
96
|
let visibleLine = '';
|
|
111
|
-
if (
|
|
112
|
-
visibleLine =
|
|
97
|
+
if (maskChar !== undefined) {
|
|
98
|
+
visibleLine = maskChar.repeat(lineSegs.length);
|
|
113
99
|
}
|
|
114
100
|
else {
|
|
115
101
|
visibleLine = lineSegs.join('');
|
|
116
102
|
}
|
|
117
|
-
// If this is cursor line, we need to handle horizontal scroll based on cursorRelativeCol.
|
|
118
|
-
// But cursorRelativeCol is global? No, we reset it on newline.
|
|
119
|
-
// So cursorRelativeCol above was correct for the current line.
|
|
120
|
-
if (isCursorLine) {
|
|
121
|
-
}
|
|
122
103
|
displayValueLines.push(theme_1.theme.main + visibleLine + ansi_1.ANSI.RESET);
|
|
123
104
|
});
|
|
124
105
|
}
|
|
@@ -145,6 +126,7 @@ class TextPrompt extends base_1.Prompt {
|
|
|
145
126
|
if (linesUp > 0) {
|
|
146
127
|
this.print(`\x1b[${linesUp}A`);
|
|
147
128
|
}
|
|
129
|
+
this.lastLinesUp = linesUp;
|
|
148
130
|
let targetCol = 0;
|
|
149
131
|
if (cursorRelativeRow === 0) {
|
|
150
132
|
targetCol = prefixVisualLen + cursorRelativeCol;
|
package/dist/prompts/toggle.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Prompt } from '../base';
|
|
|
2
2
|
import { ToggleOptions, MouseEvent } from '../types';
|
|
3
3
|
export declare class TogglePrompt extends Prompt<boolean, ToggleOptions> {
|
|
4
4
|
constructor(options: ToggleOptions);
|
|
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/toggle.js
CHANGED
|
@@ -10,7 +10,7 @@ class TogglePrompt extends base_1.Prompt {
|
|
|
10
10
|
super(options);
|
|
11
11
|
this.value = options.initial ?? false;
|
|
12
12
|
}
|
|
13
|
-
render(
|
|
13
|
+
render(_firstRender) {
|
|
14
14
|
const activeText = this.options.activeText || 'ON';
|
|
15
15
|
const inactiveText = this.options.inactiveText || 'OFF';
|
|
16
16
|
let toggleDisplay = '';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { TransferOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class TransferPrompt<V> extends Prompt<[V[], V[]], TransferOptions<V>> {
|
|
4
|
+
private leftList;
|
|
5
|
+
private rightList;
|
|
6
|
+
private cursorLeft;
|
|
7
|
+
private cursorRight;
|
|
8
|
+
private scrollTopLeft;
|
|
9
|
+
private scrollTopRight;
|
|
10
|
+
private activeSide;
|
|
11
|
+
private readonly pageSize;
|
|
12
|
+
constructor(options: TransferOptions<V>);
|
|
13
|
+
private normalize;
|
|
14
|
+
protected truncate(str: string, width: number): string;
|
|
15
|
+
protected render(_firstRender: boolean): void;
|
|
16
|
+
protected handleInput(char: string): void;
|
|
17
|
+
protected handleMouse(event: MouseEvent): void;
|
|
18
|
+
}
|