mepcli 0.6.1 → 1.0.0-beta.2
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/LICENSE +21 -21
- package/README.md +512 -326
- package/dist/ansi.d.ts +8 -0
- package/dist/ansi.js +8 -0
- package/dist/base.d.ts +21 -0
- package/dist/base.js +57 -0
- package/dist/core.d.ts +48 -1
- package/dist/core.js +156 -0
- package/dist/data/licenses.d.ts +2 -0
- package/dist/data/licenses.js +109 -0
- package/dist/highlight.js +58 -26
- package/dist/index.d.ts +36 -0
- package/dist/index.js +36 -0
- package/dist/input.js +0 -3
- package/dist/prompts/box.d.ts +21 -0
- package/dist/prompts/box.js +192 -0
- package/dist/prompts/breadcrumb.d.ts +22 -0
- package/dist/prompts/breadcrumb.js +302 -0
- package/dist/prompts/byte.d.ts +13 -0
- package/dist/prompts/byte.js +159 -0
- package/dist/prompts/calculator.d.ts +16 -0
- package/dist/prompts/calculator.js +213 -0
- package/dist/prompts/calendar.js +0 -5
- package/dist/prompts/code.d.ts +2 -0
- package/dist/prompts/code.js +104 -70
- package/dist/prompts/connection-string.d.ts +18 -0
- package/dist/prompts/connection-string.js +97 -0
- package/dist/prompts/curl.d.ts +39 -0
- package/dist/prompts/curl.js +285 -0
- package/dist/prompts/data-inspector.d.ts +22 -0
- package/dist/prompts/data-inspector.js +256 -0
- package/dist/prompts/dependency.d.ts +16 -0
- package/dist/prompts/dependency.js +265 -0
- package/dist/prompts/dial.d.ts +10 -0
- package/dist/prompts/dial.js +110 -0
- package/dist/prompts/diff.d.ts +10 -0
- package/dist/prompts/diff.js +101 -0
- package/dist/prompts/draw.d.ts +20 -0
- package/dist/prompts/draw.js +188 -0
- package/dist/prompts/editor.js +0 -4
- package/dist/prompts/emoji.d.ts +18 -0
- package/dist/prompts/emoji.js +228 -0
- package/dist/prompts/exec.d.ts +13 -0
- package/dist/prompts/exec.js +83 -0
- package/dist/prompts/fuzzy.d.ts +12 -0
- package/dist/prompts/fuzzy.js +136 -0
- package/dist/prompts/gauge.d.ts +21 -0
- package/dist/prompts/gauge.js +130 -0
- package/dist/prompts/heatmap.d.ts +13 -0
- package/dist/prompts/heatmap.js +141 -0
- package/dist/prompts/ip.d.ts +11 -0
- package/dist/prompts/ip.js +118 -0
- package/dist/prompts/kanban.d.ts +17 -0
- package/dist/prompts/kanban.js +228 -0
- package/dist/prompts/keypress.js +0 -2
- package/dist/prompts/license.d.ts +9 -0
- package/dist/prompts/license.js +105 -0
- package/dist/prompts/map.d.ts +15 -0
- package/dist/prompts/map.js +199 -0
- package/dist/prompts/match.d.ts +19 -0
- package/dist/prompts/match.js +275 -0
- package/dist/prompts/miller.d.ts +15 -0
- package/dist/prompts/miller.js +221 -0
- package/dist/prompts/multi-column-select.d.ts +10 -0
- package/dist/prompts/multi-column-select.js +166 -0
- package/dist/prompts/number.js +0 -2
- package/dist/prompts/otp.d.ts +10 -0
- package/dist/prompts/otp.js +91 -0
- package/dist/prompts/pattern.d.ts +22 -0
- package/dist/prompts/pattern.js +249 -0
- package/dist/prompts/quiz-select.d.ts +10 -0
- package/dist/prompts/quiz-select.js +104 -0
- package/dist/prompts/quiz-text.d.ts +11 -0
- package/dist/prompts/quiz-text.js +82 -0
- package/dist/prompts/regex.d.ts +13 -0
- package/dist/prompts/regex.js +131 -0
- package/dist/prompts/region.d.ts +11 -0
- package/dist/prompts/region.js +164 -0
- package/dist/prompts/schedule.d.ts +18 -0
- package/dist/prompts/schedule.js +221 -0
- package/dist/prompts/scroll.d.ts +13 -0
- package/dist/prompts/scroll.js +152 -0
- package/dist/prompts/seat.d.ts +17 -0
- package/dist/prompts/seat.js +165 -0
- package/dist/prompts/select-range.d.ts +8 -0
- package/dist/prompts/select-range.js +136 -0
- package/dist/prompts/select.d.ts +9 -9
- package/dist/prompts/semver.d.ts +6 -0
- package/dist/prompts/semver.js +32 -0
- package/dist/prompts/shortcut.d.ts +9 -0
- package/dist/prompts/shortcut.js +135 -0
- package/dist/prompts/slot.d.ts +16 -0
- package/dist/prompts/slot.js +107 -0
- package/dist/prompts/snippet.js +0 -3
- package/dist/prompts/sort-grid.d.ts +16 -0
- package/dist/prompts/sort-grid.js +146 -0
- package/dist/prompts/sort.js +0 -1
- package/dist/prompts/spreadsheet.d.ts +21 -0
- package/dist/prompts/spreadsheet.js +239 -0
- package/dist/prompts/text.d.ts +9 -7
- package/dist/prompts/text.js +52 -0
- package/dist/prompts/time.d.ts +12 -0
- package/dist/prompts/time.js +202 -0
- package/dist/prompts/tree-select.d.ts +0 -1
- package/dist/prompts/tree-select.js +1 -5
- package/dist/symbols.d.ts +12 -0
- package/dist/symbols.js +14 -2
- package/dist/theme.js +10 -1
- package/dist/types.d.ts +264 -1
- package/dist/utils.d.ts +53 -0
- package/dist/utils.js +252 -0
- package/package.json +51 -47
- package/example.ts +0 -390
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BytePrompt = 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
|
+
const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
9
|
+
class BytePrompt extends base_1.Prompt {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.inputValue = 0;
|
|
13
|
+
this.buffer = '';
|
|
14
|
+
this.unitIndex = 0;
|
|
15
|
+
this.errorMsg = '';
|
|
16
|
+
// Parse initial bytes to best unit
|
|
17
|
+
// e.g. 1073741824 -> 1.00 GB
|
|
18
|
+
let val = options.initial || 0;
|
|
19
|
+
let idx = 0;
|
|
20
|
+
while (val >= 1024 && idx < UNITS.length - 1) {
|
|
21
|
+
val /= 1024;
|
|
22
|
+
idx++;
|
|
23
|
+
}
|
|
24
|
+
// Round to 2 decimals for display if float
|
|
25
|
+
this.inputValue = Math.round(val * 100) / 100;
|
|
26
|
+
this.buffer = this.inputValue.toString();
|
|
27
|
+
this.unitIndex = idx;
|
|
28
|
+
}
|
|
29
|
+
render(_firstRender) {
|
|
30
|
+
const unitStr = UNITS[this.unitIndex];
|
|
31
|
+
// 1. Render Question & Input
|
|
32
|
+
const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
|
|
33
|
+
let output = `${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} `;
|
|
34
|
+
// Value part
|
|
35
|
+
output += `${theme_1.theme.main}${ansi_1.ANSI.UNDERLINE}${this.buffer}${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${unitStr}${ansi_1.ANSI.RESET}\n`;
|
|
36
|
+
// 2. Render Unit Bar
|
|
37
|
+
// (Unit: B > KB > [MB] > GB)
|
|
38
|
+
let bar = ' ';
|
|
39
|
+
UNITS.forEach((u, i) => {
|
|
40
|
+
if (i === this.unitIndex) {
|
|
41
|
+
bar += `${theme_1.theme.main}${ansi_1.ANSI.REVERSE} ${u} ${ansi_1.ANSI.RESET}`;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
bar += `${theme_1.theme.muted} ${u} ${ansi_1.ANSI.RESET}`;
|
|
45
|
+
}
|
|
46
|
+
if (i < UNITS.length - 1) {
|
|
47
|
+
bar += ` ${theme_1.theme.muted}›${ansi_1.ANSI.RESET} `;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
output += `\n${bar}\n`;
|
|
51
|
+
// 3. Hints & Errors
|
|
52
|
+
output += `${theme_1.theme.muted} (Arrows: Adjust | Tab: Switch Unit | Enter: Submit)${ansi_1.ANSI.RESET}`;
|
|
53
|
+
if (this.errorMsg) {
|
|
54
|
+
output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
|
|
55
|
+
}
|
|
56
|
+
this.renderFrame(output);
|
|
57
|
+
}
|
|
58
|
+
handleInput(char) {
|
|
59
|
+
this.errorMsg = '';
|
|
60
|
+
// Enter
|
|
61
|
+
if (char === '\r' || char === '\n') {
|
|
62
|
+
const finalVal = parseFloat(this.buffer);
|
|
63
|
+
if (isNaN(finalVal)) {
|
|
64
|
+
this.errorMsg = 'Invalid number';
|
|
65
|
+
this.render(false);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Calculate Bytes: value * 1024^index
|
|
69
|
+
const bytes = finalVal * Math.pow(1024, this.unitIndex);
|
|
70
|
+
// Min/Max Validation (in bytes)
|
|
71
|
+
if (this.options.min !== undefined && bytes < this.options.min) {
|
|
72
|
+
this.errorMsg = `Minimum value is ${this.formatBytes(this.options.min)}`;
|
|
73
|
+
this.render(false);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (this.options.max !== undefined && bytes > this.options.max) {
|
|
77
|
+
this.errorMsg = `Maximum value is ${this.formatBytes(this.options.max)}`;
|
|
78
|
+
this.render(false);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.submit(Math.round(bytes)); // Return integer bytes? Or float? Usually bytes are int.
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Tab / Shift+Tab -> Switch Unit
|
|
85
|
+
if (char === '\t' || this.isRight(char)) {
|
|
86
|
+
if (this.unitIndex < UNITS.length - 1) {
|
|
87
|
+
this.unitIndex++;
|
|
88
|
+
this.render(false);
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (char === '\x1b[Z' || this.isLeft(char)) { // Shift+Tab or Left
|
|
93
|
+
if (this.unitIndex > 0) {
|
|
94
|
+
this.unitIndex--;
|
|
95
|
+
this.render(false);
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Arrows -> Adjust Value
|
|
100
|
+
if (this.isUp(char) || this.isDown(char)) {
|
|
101
|
+
let val = parseFloat(this.buffer) || 0;
|
|
102
|
+
// Adaptive step: 1 if integer, 0.1 if float
|
|
103
|
+
const step = this.buffer.includes('.') ? 0.1 : 1;
|
|
104
|
+
if (this.isUp(char))
|
|
105
|
+
val += step;
|
|
106
|
+
if (this.isDown(char))
|
|
107
|
+
val -= step;
|
|
108
|
+
// Fix Float Precision
|
|
109
|
+
val = Math.round(val * 100) / 100;
|
|
110
|
+
if (val < 0)
|
|
111
|
+
val = 0; // No negative bytes usually
|
|
112
|
+
this.buffer = val.toString();
|
|
113
|
+
this.render(false);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Typing / Backspace
|
|
117
|
+
if (char === '\u0008' || char === '\x7f') {
|
|
118
|
+
if (this.buffer.length > 0) {
|
|
119
|
+
this.buffer = this.buffer.slice(0, -1);
|
|
120
|
+
this.render(false);
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Digits & Dot
|
|
125
|
+
if (/^[0-9.]$/.test(char)) {
|
|
126
|
+
// Prevent multiple dots
|
|
127
|
+
if (char === '.' && this.buffer.includes('.'))
|
|
128
|
+
return;
|
|
129
|
+
this.buffer += char;
|
|
130
|
+
this.render(false);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Helper for error messages
|
|
134
|
+
formatBytes(bytes) {
|
|
135
|
+
if (bytes === 0)
|
|
136
|
+
return '0 B';
|
|
137
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
138
|
+
return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + ' ' + UNITS[i];
|
|
139
|
+
}
|
|
140
|
+
handleMouse(event) {
|
|
141
|
+
if (event.action === 'scroll') {
|
|
142
|
+
if (event.scroll === 'up') {
|
|
143
|
+
// Scroll up -> Increase Value
|
|
144
|
+
let val = parseFloat(this.buffer) || 0;
|
|
145
|
+
val += 1;
|
|
146
|
+
this.buffer = val.toString();
|
|
147
|
+
this.render(false);
|
|
148
|
+
}
|
|
149
|
+
else if (event.scroll === 'down') {
|
|
150
|
+
// Scroll down -> Decrease Value
|
|
151
|
+
let val = parseFloat(this.buffer) || 0;
|
|
152
|
+
val = Math.max(0, val - 1);
|
|
153
|
+
this.buffer = val.toString();
|
|
154
|
+
this.render(false);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.BytePrompt = BytePrompt;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { CalculatorOptions } from '../types';
|
|
3
|
+
export declare class CalculatorPrompt extends Prompt<number, CalculatorOptions> {
|
|
4
|
+
protected errorMsg: string;
|
|
5
|
+
protected cursor: number;
|
|
6
|
+
protected hasTyped: boolean;
|
|
7
|
+
protected segments: string[];
|
|
8
|
+
protected lastLinesUp: number;
|
|
9
|
+
protected previewValue: string;
|
|
10
|
+
constructor(options: CalculatorOptions);
|
|
11
|
+
private updatePreview;
|
|
12
|
+
private evaluate;
|
|
13
|
+
protected render(firstRender: boolean): void;
|
|
14
|
+
private getVisualCursorPosition;
|
|
15
|
+
protected handleInput(char: string): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CalculatorPrompt = 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
|
+
const utils_1 = require("../utils");
|
|
9
|
+
class CalculatorPrompt extends base_1.Prompt {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.errorMsg = '';
|
|
13
|
+
this.cursor = 0;
|
|
14
|
+
this.hasTyped = false;
|
|
15
|
+
this.segments = [];
|
|
16
|
+
this.lastLinesUp = 0;
|
|
17
|
+
this.previewValue = '';
|
|
18
|
+
this.value = options.initial ? String(options.initial) : '';
|
|
19
|
+
this.segments = (0, utils_1.safeSplit)(this.value);
|
|
20
|
+
this.cursor = this.segments.length;
|
|
21
|
+
this.updatePreview();
|
|
22
|
+
}
|
|
23
|
+
updatePreview() {
|
|
24
|
+
const input = this.segments.join('');
|
|
25
|
+
if (!input.trim()) {
|
|
26
|
+
this.previewValue = '';
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const result = this.evaluate(input);
|
|
31
|
+
if (result !== null && !isNaN(result) && isFinite(result)) {
|
|
32
|
+
// Format precision if needed
|
|
33
|
+
if (this.options.precision !== undefined) {
|
|
34
|
+
this.previewValue = parseFloat(result.toFixed(this.options.precision)).toString();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.previewValue = result.toString();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.previewValue = '';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (_e) {
|
|
45
|
+
this.previewValue = '';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
evaluate(expression) {
|
|
49
|
+
let expr = expression;
|
|
50
|
+
// 1. Substitute variables
|
|
51
|
+
if (this.options.variables) {
|
|
52
|
+
// Sort keys by length desc to avoid partial replacement issues (e.g. 'var11' vs 'var1')
|
|
53
|
+
const keys = Object.keys(this.options.variables).sort((a, b) => b.length - a.length);
|
|
54
|
+
for (const key of keys) {
|
|
55
|
+
const val = this.options.variables[key];
|
|
56
|
+
const regex = new RegExp(`\\b${key}\\b`, 'g');
|
|
57
|
+
expr = expr.replace(regex, String(val));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 2. Validate characters
|
|
61
|
+
if (/[a-zA-Z_]/.test(expr)) {
|
|
62
|
+
// Support basic Math functions: sin, cos, tan, log, sqrt, abs, pow, floor, ceil, round
|
|
63
|
+
const allowedMath = ['sin', 'cos', 'tan', 'log', 'sqrt', 'abs', 'pow', 'floor', 'ceil', 'round', 'PI', 'E'];
|
|
64
|
+
// We can prefix them with Math.
|
|
65
|
+
let checkStr = expr;
|
|
66
|
+
allowedMath.forEach(k => {
|
|
67
|
+
checkStr = checkStr.replace(new RegExp(k, 'g'), '');
|
|
68
|
+
});
|
|
69
|
+
if (/[a-zA-Z_]/.test(checkStr)) {
|
|
70
|
+
return null; // Contains unknown variables or functions
|
|
71
|
+
}
|
|
72
|
+
// Now prefix Math functions in the real expr
|
|
73
|
+
allowedMath.forEach(k => {
|
|
74
|
+
// Replace 'sin(' with 'Math.sin('
|
|
75
|
+
// Be careful with PI and E
|
|
76
|
+
if (['PI', 'E'].includes(k)) {
|
|
77
|
+
expr = expr.replace(new RegExp(`\\b${k}\\b`, 'g'), `Math.${k}`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
expr = expr.replace(new RegExp(`\\b${k}\\(`, 'g'), `Math.${k}(`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// 3. Safe Eval using Function
|
|
85
|
+
try {
|
|
86
|
+
const func = new Function(`return (${expr})`);
|
|
87
|
+
const res = func();
|
|
88
|
+
return typeof res === 'number' ? res : null;
|
|
89
|
+
}
|
|
90
|
+
catch (_err) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
render(firstRender) {
|
|
95
|
+
if (!firstRender && this.lastLinesUp > 0) {
|
|
96
|
+
this.print(`\x1b[${this.lastLinesUp}B`);
|
|
97
|
+
}
|
|
98
|
+
this.lastLinesUp = 0;
|
|
99
|
+
const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
|
|
100
|
+
const prefix = `${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} `;
|
|
101
|
+
const prefixVisualLen = this.stripAnsi(prefix).length;
|
|
102
|
+
// Render Input Line
|
|
103
|
+
let displayValue = '';
|
|
104
|
+
const inputStr = this.segments.join('');
|
|
105
|
+
if (!inputStr && this.options.placeholder && !this.errorMsg && !this.hasTyped) {
|
|
106
|
+
displayValue = `${theme_1.theme.muted}${this.options.placeholder}${ansi_1.ANSI.RESET}`;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
displayValue = theme_1.theme.main + inputStr + ansi_1.ANSI.RESET;
|
|
110
|
+
}
|
|
111
|
+
let output = `${prefix}${displayValue}`;
|
|
112
|
+
// Add Preview Line (if available and no error)
|
|
113
|
+
let previewStr = '';
|
|
114
|
+
if (this.previewValue && !this.errorMsg) {
|
|
115
|
+
// Display as "= Result" in muted color
|
|
116
|
+
previewStr = `\n${theme_1.theme.muted}= ${this.previewValue}${ansi_1.ANSI.RESET}`;
|
|
117
|
+
output += previewStr;
|
|
118
|
+
}
|
|
119
|
+
if (this.errorMsg) {
|
|
120
|
+
output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
|
|
121
|
+
}
|
|
122
|
+
this.renderFrame(output);
|
|
123
|
+
this.print(ansi_1.ANSI.SHOW_CURSOR);
|
|
124
|
+
let totalRows = 1;
|
|
125
|
+
if (previewStr)
|
|
126
|
+
totalRows++;
|
|
127
|
+
if (this.errorMsg)
|
|
128
|
+
totalRows++;
|
|
129
|
+
const linesUp = (totalRows - 1);
|
|
130
|
+
if (linesUp > 0) {
|
|
131
|
+
this.print(`\x1b[${linesUp}A`);
|
|
132
|
+
}
|
|
133
|
+
this.lastLinesUp = linesUp;
|
|
134
|
+
// Move cursor to correct column
|
|
135
|
+
// We assume single line input for now
|
|
136
|
+
const cursorVisualCol = this.getVisualCursorPosition();
|
|
137
|
+
const targetCol = prefixVisualLen + cursorVisualCol;
|
|
138
|
+
this.print(ansi_1.ANSI.CURSOR_LEFT);
|
|
139
|
+
if (targetCol > 0) {
|
|
140
|
+
this.print(`\x1b[${targetCol}C`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
getVisualCursorPosition() {
|
|
144
|
+
let width = 0;
|
|
145
|
+
for (let i = 0; i < this.cursor; i++) {
|
|
146
|
+
width += (0, utils_1.stringWidth)(this.segments[i]);
|
|
147
|
+
}
|
|
148
|
+
return width;
|
|
149
|
+
}
|
|
150
|
+
handleInput(char) {
|
|
151
|
+
// Enter
|
|
152
|
+
if (char === '\r' || char === '\n') {
|
|
153
|
+
const input = this.segments.join('');
|
|
154
|
+
const result = this.evaluate(input);
|
|
155
|
+
if (result === null || isNaN(result)) {
|
|
156
|
+
this.errorMsg = 'Invalid expression';
|
|
157
|
+
this.render(false);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.submit(result);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// Backspace
|
|
164
|
+
if (char === '\u0008' || char === '\x7f') {
|
|
165
|
+
this.hasTyped = true;
|
|
166
|
+
if (this.cursor > 0) {
|
|
167
|
+
this.segments.splice(this.cursor - 1, 1);
|
|
168
|
+
this.cursor--;
|
|
169
|
+
this.errorMsg = '';
|
|
170
|
+
this.updatePreview();
|
|
171
|
+
this.render(false);
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// Arrows
|
|
176
|
+
if (this.isLeft(char)) {
|
|
177
|
+
if (this.cursor > 0) {
|
|
178
|
+
this.cursor--;
|
|
179
|
+
this.render(false);
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (this.isRight(char)) {
|
|
184
|
+
if (this.cursor < this.segments.length) {
|
|
185
|
+
this.cursor++;
|
|
186
|
+
this.render(false);
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Delete
|
|
191
|
+
if (char === '\u001b[3~') {
|
|
192
|
+
this.hasTyped = true;
|
|
193
|
+
if (this.cursor < this.segments.length) {
|
|
194
|
+
this.segments.splice(this.cursor, 1);
|
|
195
|
+
this.errorMsg = '';
|
|
196
|
+
this.updatePreview();
|
|
197
|
+
this.render(false);
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Normal typing
|
|
202
|
+
if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
|
|
203
|
+
this.hasTyped = true;
|
|
204
|
+
const newSegments = (0, utils_1.safeSplit)(char);
|
|
205
|
+
this.segments.splice(this.cursor, 0, ...newSegments);
|
|
206
|
+
this.cursor += newSegments.length;
|
|
207
|
+
this.errorMsg = '';
|
|
208
|
+
this.updatePreview();
|
|
209
|
+
this.render(false);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.CalculatorPrompt = CalculatorPrompt;
|
package/dist/prompts/calendar.js
CHANGED
|
@@ -85,8 +85,6 @@ class CalendarPrompt extends base_1.Prompt {
|
|
|
85
85
|
if (this.options.mode === 'range') {
|
|
86
86
|
if (Array.isArray(this.selection)) {
|
|
87
87
|
const [start, end] = this.selection;
|
|
88
|
-
// If the range is complete, highlight everything in between
|
|
89
|
-
// Sort to ensure valid range check even if start > end (though we should normalize)
|
|
90
88
|
const s = start < end ? start : end;
|
|
91
89
|
const e = start < end ? end : start;
|
|
92
90
|
// Set times to midnight for comparison
|
|
@@ -96,9 +94,6 @@ class CalendarPrompt extends base_1.Prompt {
|
|
|
96
94
|
return dTime >= sTime && dTime <= eTime;
|
|
97
95
|
}
|
|
98
96
|
else {
|
|
99
|
-
// Selecting range, but only first point picked?
|
|
100
|
-
// Usually when picking range, first click sets start, moving cursor highlights?
|
|
101
|
-
// For now, if selection is single date in range mode, just highlight it
|
|
102
97
|
return this.isSameDay(d, this.selection);
|
|
103
98
|
}
|
|
104
99
|
}
|
package/dist/prompts/code.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export declare class CodePrompt extends Prompt<string, CodeOptions> {
|
|
|
9
9
|
private lastLinesUp;
|
|
10
10
|
constructor(options: CodeOptions);
|
|
11
11
|
private parseTemplate;
|
|
12
|
+
protected cleanup(): void;
|
|
12
13
|
protected render(firstRender: boolean): void;
|
|
14
|
+
private appendSegment;
|
|
13
15
|
protected handleInput(char: string, _key: Buffer): void;
|
|
14
16
|
protected handleMouse(event: MouseEvent): void;
|
|
15
17
|
private moveFocus;
|
package/dist/prompts/code.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.CodePrompt = void 0;
|
|
|
4
4
|
const ansi_1 = require("../ansi");
|
|
5
5
|
const base_1 = require("../base");
|
|
6
6
|
const theme_1 = require("../theme");
|
|
7
|
-
const
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
8
|
class CodePrompt extends base_1.Prompt {
|
|
9
9
|
constructor(options) {
|
|
10
10
|
super(options);
|
|
@@ -18,11 +18,12 @@ class CodePrompt extends base_1.Prompt {
|
|
|
18
18
|
// Init values
|
|
19
19
|
this.variableTokens.forEach(idx => {
|
|
20
20
|
const name = this.tokens[idx].value;
|
|
21
|
-
this.values[name] = '';
|
|
21
|
+
this.values[name] = (this.options.values && this.options.values[name]) || '';
|
|
22
22
|
});
|
|
23
23
|
// Init cursor at end of first var
|
|
24
24
|
if (this.variableTokens.length > 0) {
|
|
25
|
-
|
|
25
|
+
const activeName = this.tokens[this.variableTokens[0]].value;
|
|
26
|
+
this.cursor = this.values[activeName].length;
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
parseTemplate() {
|
|
@@ -41,80 +42,98 @@ class CodePrompt extends base_1.Prompt {
|
|
|
41
42
|
this.tokens.push({ type: 'static', value: this.options.template.substring(lastIndex) });
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
// FIX: Override cleanup to ensure cursor is reset to bottom
|
|
46
|
+
cleanup() {
|
|
47
|
+
// If the cursor is currently moved up (editing mode), move it back down
|
|
48
|
+
// before the prompt exits. This prevents the next output (or result)
|
|
49
|
+
// from overwriting the bottom part of our UI.
|
|
50
|
+
if (this.lastLinesUp > 0) {
|
|
51
|
+
this.print(`\x1b[${this.lastLinesUp}B`);
|
|
52
|
+
this.lastLinesUp = 0;
|
|
53
|
+
}
|
|
54
|
+
super.cleanup();
|
|
55
|
+
}
|
|
44
56
|
render(firstRender) {
|
|
45
|
-
// Reset cursor from previous render relative position
|
|
46
57
|
if (!firstRender && this.lastLinesUp > 0) {
|
|
47
58
|
this.print(`\x1b[${this.lastLinesUp}B`);
|
|
48
59
|
}
|
|
49
60
|
this.lastLinesUp = 0;
|
|
50
|
-
// 1.
|
|
51
|
-
|
|
52
|
-
let
|
|
61
|
+
// 1. Build Full Raw Text & Identify Active Variable Range
|
|
62
|
+
let fullRawText = '';
|
|
63
|
+
let activeVarStart = -1;
|
|
64
|
+
let activeVarEnd = -1;
|
|
65
|
+
const activeTokenIdx = this.variableTokens[this.activeVarIndex];
|
|
66
|
+
const activeVarName = this.tokens[activeTokenIdx].value;
|
|
53
67
|
this.tokens.forEach((token, idx) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (this.variableTokens[this.activeVarIndex] === idx) {
|
|
59
|
-
rawWithPlaceholder += ACTIVE_PLACEHOLDER;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
rawWithPlaceholder += this.values[token.value] || '';
|
|
63
|
-
}
|
|
68
|
+
const val = (token.type === 'static') ? token.value : (this.values[token.value] || '');
|
|
69
|
+
if (idx === activeTokenIdx) {
|
|
70
|
+
activeVarStart = fullRawText.length;
|
|
71
|
+
activeVarEnd = activeVarStart + val.length;
|
|
64
72
|
}
|
|
73
|
+
fullRawText += val;
|
|
65
74
|
});
|
|
66
|
-
// 2. Highlight
|
|
75
|
+
// 2. Syntax Highlight with Overlap Logic
|
|
67
76
|
let highlighted = '';
|
|
68
|
-
const shouldHighlight = this.options.highlight !== false;
|
|
77
|
+
const shouldHighlight = this.options.highlight !== false;
|
|
69
78
|
if (shouldHighlight) {
|
|
70
|
-
|
|
79
|
+
const jsonTokenRegex = /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"?)|(-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)|(true|false|null)|([{}[\],:])/g;
|
|
80
|
+
let match;
|
|
81
|
+
let lastIndex = 0;
|
|
82
|
+
while ((match = jsonTokenRegex.exec(fullRawText)) !== null) {
|
|
83
|
+
if (match.index > lastIndex) {
|
|
84
|
+
const gap = fullRawText.substring(lastIndex, match.index);
|
|
85
|
+
this.appendSegment(gap, lastIndex, activeVarStart, activeVarEnd, ansi_1.ANSI.FG_WHITE, (s) => highlighted += s);
|
|
86
|
+
}
|
|
87
|
+
const tokenText = match[0];
|
|
88
|
+
const tokenStart = match.index;
|
|
89
|
+
let color = theme_1.theme.syntax?.punctuation || ansi_1.ANSI.FG_WHITE;
|
|
90
|
+
if (tokenText.startsWith('"')) {
|
|
91
|
+
const remaining = fullRawText.substring(jsonTokenRegex.lastIndex);
|
|
92
|
+
if (/^\s*:/.test(remaining)) {
|
|
93
|
+
color = theme_1.theme.syntax?.key || ansi_1.ANSI.FG_CYAN;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
color = theme_1.theme.syntax?.string || ansi_1.ANSI.FG_GREEN;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (/^-?\d/.test(tokenText)) {
|
|
100
|
+
color = theme_1.theme.syntax?.number || ansi_1.ANSI.FG_YELLOW;
|
|
101
|
+
}
|
|
102
|
+
else if (/^(true|false|null)$/.test(tokenText)) {
|
|
103
|
+
color = (tokenText === 'null')
|
|
104
|
+
? (theme_1.theme.syntax?.null || ansi_1.ANSI.FG_RED)
|
|
105
|
+
: (theme_1.theme.syntax?.boolean || ansi_1.ANSI.FG_MAGENTA);
|
|
106
|
+
}
|
|
107
|
+
else if (/^[{}[\],:]$/.test(tokenText)) {
|
|
108
|
+
color = theme_1.theme.syntax?.punctuation || ansi_1.ANSI.FG_WHITE;
|
|
109
|
+
}
|
|
110
|
+
this.appendSegment(tokenText, tokenStart, activeVarStart, activeVarEnd, color, (s) => highlighted += s);
|
|
111
|
+
lastIndex = jsonTokenRegex.lastIndex;
|
|
112
|
+
}
|
|
113
|
+
if (lastIndex < fullRawText.length) {
|
|
114
|
+
const tail = fullRawText.substring(lastIndex);
|
|
115
|
+
this.appendSegment(tail, lastIndex, activeVarStart, activeVarEnd, ansi_1.ANSI.FG_WHITE, (s) => highlighted += s);
|
|
116
|
+
}
|
|
71
117
|
}
|
|
72
118
|
else {
|
|
73
|
-
highlighted
|
|
74
|
-
}
|
|
75
|
-
// 3.
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
highlighted = highlighted.replace(ACTIVE_PLACEHOLDER, styledActive);
|
|
81
|
-
// 4. Output
|
|
82
|
-
const prefix = `${theme_1.theme.success}? ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
119
|
+
this.appendSegment(fullRawText, 0, activeVarStart, activeVarEnd, ansi_1.ANSI.RESET, (s) => highlighted += s);
|
|
120
|
+
}
|
|
121
|
+
// 3. Output Frame
|
|
122
|
+
const warningMsg = shouldHighlight
|
|
123
|
+
? `${ansi_1.ANSI.FG_YELLOW}Warning:${ansi_1.ANSI.RESET} Syntax highlighting is an experimental feature.\n`
|
|
124
|
+
: '';
|
|
125
|
+
const prefix = `${warningMsg}${theme_1.theme.success}? ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
83
126
|
const suffix = `\n${theme_1.theme.muted}(Tab to next, Enter to submit)${ansi_1.ANSI.RESET}`;
|
|
84
127
|
const fullOutput = prefix + highlighted + suffix;
|
|
85
128
|
this.renderFrame(fullOutput);
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
for (let i = 0; i < this.tokens.length; i++) {
|
|
90
|
-
const token = this.tokens[i];
|
|
91
|
-
if (token.type === 'static') {
|
|
92
|
-
textBeforeCursor += token.value;
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
if (this.variableTokens[this.activeVarIndex] === i) {
|
|
96
|
-
textBeforeCursor += activeVal.substring(0, this.cursor);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
textBeforeCursor += this.values[token.value] || '';
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
129
|
+
// 4. Cursor Calculation
|
|
130
|
+
const cursorAbsPos = activeVarStart + this.cursor;
|
|
131
|
+
const textBeforeCursor = fullRawText.substring(0, cursorAbsPos);
|
|
104
132
|
const rowsBefore = textBeforeCursor.split('\n');
|
|
105
133
|
const cursorRow = rowsBefore.length - 1;
|
|
106
|
-
const cursorCol = rowsBefore[rowsBefore.length - 1]
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.tokens.forEach(token => {
|
|
110
|
-
fullRaw += (token.type === 'static' ? token.value : (this.values[token.value] || ''));
|
|
111
|
-
});
|
|
112
|
-
const totalSnippetLines = fullRaw.split('\n').length;
|
|
113
|
-
// Calculate linesUp from the bottom of snippet
|
|
114
|
-
// Suffix is 1 line.
|
|
115
|
-
// CursorRow is 0-based index from top of snippet.
|
|
116
|
-
// If cursorRow is at bottom (totalSnippetLines-1), linesUp = 1 (Suffix).
|
|
117
|
-
// If cursorRow is at top (0), linesUp = 1 + (totalSnippetLines - 1).
|
|
134
|
+
const cursorCol = (0, utils_1.stringWidth)(rowsBefore[rowsBefore.length - 1]);
|
|
135
|
+
const totalSnippetLines = fullRawText.split('\n').length;
|
|
136
|
+
// linesUp calculation: 1 (suffix) + remaining snippet lines
|
|
118
137
|
const linesUp = 1 + (totalSnippetLines - 1 - cursorRow);
|
|
119
138
|
this.print(ansi_1.ANSI.SHOW_CURSOR);
|
|
120
139
|
if (linesUp > 0) {
|
|
@@ -126,9 +145,28 @@ class CodePrompt extends base_1.Prompt {
|
|
|
126
145
|
this.print(`\x1b[${cursorCol}C`);
|
|
127
146
|
}
|
|
128
147
|
}
|
|
148
|
+
appendSegment(text, absStart, activeStart, activeEnd, syntaxColor, append) {
|
|
149
|
+
const absEnd = absStart + text.length;
|
|
150
|
+
const overlapStart = Math.max(absStart, activeStart);
|
|
151
|
+
const overlapEnd = Math.min(absEnd, activeEnd);
|
|
152
|
+
if (overlapStart < overlapEnd) {
|
|
153
|
+
if (absStart < overlapStart) {
|
|
154
|
+
const part = text.substring(0, overlapStart - absStart);
|
|
155
|
+
append(`${syntaxColor}${part}${ansi_1.ANSI.RESET}`);
|
|
156
|
+
}
|
|
157
|
+
const activePart = text.substring(overlapStart - absStart, overlapEnd - absStart);
|
|
158
|
+
append(`${theme_1.theme.main}${ansi_1.ANSI.UNDERLINE}${activePart}${ansi_1.ANSI.RESET}`);
|
|
159
|
+
if (absEnd > overlapEnd) {
|
|
160
|
+
const part = text.substring(overlapEnd - absStart);
|
|
161
|
+
append(`${syntaxColor}${part}${ansi_1.ANSI.RESET}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
append(`${syntaxColor}${text}${ansi_1.ANSI.RESET}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
129
168
|
handleInput(char, _key) {
|
|
130
|
-
|
|
131
|
-
if (char === '\u001b[Z') { // Shift Tab
|
|
169
|
+
if (char === '\u001b[Z') {
|
|
132
170
|
this.moveFocus(-1);
|
|
133
171
|
return;
|
|
134
172
|
}
|
|
@@ -136,7 +174,6 @@ class CodePrompt extends base_1.Prompt {
|
|
|
136
174
|
this.moveFocus(1);
|
|
137
175
|
return;
|
|
138
176
|
}
|
|
139
|
-
// Enter
|
|
140
177
|
if (char === '\r' || char === '\n') {
|
|
141
178
|
this.submitCode();
|
|
142
179
|
return;
|
|
@@ -144,8 +181,7 @@ class CodePrompt extends base_1.Prompt {
|
|
|
144
181
|
const activeTokenIdx = this.variableTokens[this.activeVarIndex];
|
|
145
182
|
const varName = this.tokens[activeTokenIdx].value;
|
|
146
183
|
const val = this.values[varName] || '';
|
|
147
|
-
|
|
148
|
-
if (char === '\u0008' || char === '\x7f') { // Backspace
|
|
184
|
+
if (char === '\u0008' || char === '\x7f') {
|
|
149
185
|
if (this.cursor > 0) {
|
|
150
186
|
const pre = val.slice(0, this.cursor - 1);
|
|
151
187
|
const post = val.slice(this.cursor);
|
|
@@ -177,12 +213,10 @@ class CodePrompt extends base_1.Prompt {
|
|
|
177
213
|
}
|
|
178
214
|
handleMouse(event) {
|
|
179
215
|
if (event.action === 'scroll') {
|
|
180
|
-
if (event.scroll === 'up')
|
|
216
|
+
if (event.scroll === 'up')
|
|
181
217
|
this.moveFocus(-1);
|
|
182
|
-
|
|
183
|
-
else if (event.scroll === 'down') {
|
|
218
|
+
else if (event.scroll === 'down')
|
|
184
219
|
this.moveFocus(1);
|
|
185
|
-
}
|
|
186
220
|
}
|
|
187
221
|
}
|
|
188
222
|
moveFocus(direction) {
|
|
@@ -190,7 +224,7 @@ class CodePrompt extends base_1.Prompt {
|
|
|
190
224
|
if (nextIndex >= 0 && nextIndex < this.variableTokens.length) {
|
|
191
225
|
this.activeVarIndex = nextIndex;
|
|
192
226
|
const varName = this.tokens[this.variableTokens[this.activeVarIndex]].value;
|
|
193
|
-
this.cursor = (this.values[varName] || '').length;
|
|
227
|
+
this.cursor = (this.values[varName] || '').length;
|
|
194
228
|
this.render(false);
|
|
195
229
|
}
|
|
196
230
|
}
|