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,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FuzzySelectPrompt = void 0;
|
|
4
|
+
const select_1 = require("./select");
|
|
5
|
+
const theme_1 = require("../theme");
|
|
6
|
+
const ansi_1 = require("../ansi");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
const symbols_1 = require("../symbols");
|
|
9
|
+
class FuzzySelectPrompt extends select_1.SelectPrompt {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.filteredResults = [];
|
|
13
|
+
this.filteredResults = this.options.choices;
|
|
14
|
+
}
|
|
15
|
+
getFilteredChoices() {
|
|
16
|
+
// Safety check: this.filteredResults might be undefined if called from super() constructor
|
|
17
|
+
return this.filteredResults || this.options.choices;
|
|
18
|
+
}
|
|
19
|
+
handleInput(char) {
|
|
20
|
+
// Backspace
|
|
21
|
+
if (char === '\u0008' || char === '\x7f') {
|
|
22
|
+
if (this.searchBuffer.length > 0) {
|
|
23
|
+
this.searchBuffer = this.searchBuffer.slice(0, -1);
|
|
24
|
+
this.performSearch();
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Intercept typing to add debounce
|
|
29
|
+
if (char.length === 1 && !/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
|
|
30
|
+
this.searchBuffer += char;
|
|
31
|
+
// Check if debounce is needed
|
|
32
|
+
if (this.options.choices.length > 1000) {
|
|
33
|
+
if (this.debounceTimer)
|
|
34
|
+
clearTimeout(this.debounceTimer);
|
|
35
|
+
this.debounceTimer = setTimeout(() => {
|
|
36
|
+
this.performSearch();
|
|
37
|
+
}, 150); // 150ms debounce
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
this.performSearch();
|
|
41
|
+
}
|
|
42
|
+
return; // Skip super.handleInput for typing
|
|
43
|
+
}
|
|
44
|
+
super.handleInput(char);
|
|
45
|
+
}
|
|
46
|
+
performSearch() {
|
|
47
|
+
if (!this.searchBuffer) {
|
|
48
|
+
this.filteredResults = this.options.choices;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const results = this.options.choices.map(c => {
|
|
52
|
+
if (this.isSeparator(c))
|
|
53
|
+
return null;
|
|
54
|
+
const match = (0, utils_1.fuzzyMatch)(this.searchBuffer, c.title);
|
|
55
|
+
return { choice: c, match };
|
|
56
|
+
}).filter(item => item && item.match !== null)
|
|
57
|
+
// Sort by score descending
|
|
58
|
+
.sort((a, b) => b.match.score - a.match.score);
|
|
59
|
+
this.filteredResults = results.map(r => {
|
|
60
|
+
r.choice._match = r.match;
|
|
61
|
+
return r.choice;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
this.selectedIndex = 0;
|
|
65
|
+
this.render(false);
|
|
66
|
+
}
|
|
67
|
+
highlight(text, indices, isSelected) {
|
|
68
|
+
let output = '';
|
|
69
|
+
const indexSet = new Set(indices);
|
|
70
|
+
for (let i = 0; i < text.length; i++) {
|
|
71
|
+
if (indexSet.has(i)) {
|
|
72
|
+
if (isSelected) {
|
|
73
|
+
output += `${ansi_1.ANSI.BOLD}${ansi_1.ANSI.FG_WHITE}${text[i]}${theme_1.theme.main}`; // Reset to main theme
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
output += `${ansi_1.ANSI.BOLD}${ansi_1.ANSI.FG_CYAN}${text[i]}${ansi_1.ANSI.RESET}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
output += text[i];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return output;
|
|
84
|
+
}
|
|
85
|
+
render(_firstRender) {
|
|
86
|
+
let output = '';
|
|
87
|
+
const choices = this.getFilteredChoices();
|
|
88
|
+
// Adjust Scroll Top
|
|
89
|
+
if (this.selectedIndex < this.scrollTop) {
|
|
90
|
+
this.scrollTop = this.selectedIndex;
|
|
91
|
+
}
|
|
92
|
+
else if (this.selectedIndex >= this.scrollTop + this.pageSize) {
|
|
93
|
+
this.scrollTop = this.selectedIndex - this.pageSize + 1;
|
|
94
|
+
}
|
|
95
|
+
if (this.scrollTop > choices.length - 1) {
|
|
96
|
+
this.scrollTop = Math.max(0, choices.length - this.pageSize);
|
|
97
|
+
}
|
|
98
|
+
// Header
|
|
99
|
+
const searchStr = this.searchBuffer ? ` ${theme_1.theme.muted}(Fuzzy: ${this.searchBuffer})${ansi_1.ANSI.RESET}` : '';
|
|
100
|
+
output += `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}${searchStr}\n`;
|
|
101
|
+
if (choices.length === 0) {
|
|
102
|
+
output += ` ${theme_1.theme.muted}No results found${ansi_1.ANSI.RESET}`;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const visibleChoices = choices.slice(this.scrollTop, this.scrollTop + this.pageSize);
|
|
106
|
+
visibleChoices.forEach((choice, index) => {
|
|
107
|
+
const actualIndex = this.scrollTop + index;
|
|
108
|
+
if (index > 0)
|
|
109
|
+
output += '\n';
|
|
110
|
+
if (this.isSeparator(choice)) {
|
|
111
|
+
output += ` ${ansi_1.ANSI.DIM}${choice.text || symbols_1.symbols.line.repeat(8)}${ansi_1.ANSI.RESET}`;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
let title = choice.title;
|
|
115
|
+
const match = choice._match;
|
|
116
|
+
const isSelected = actualIndex === this.selectedIndex;
|
|
117
|
+
if (match && this.searchBuffer) {
|
|
118
|
+
title = this.highlight(title, match.indices, isSelected);
|
|
119
|
+
}
|
|
120
|
+
if (isSelected) {
|
|
121
|
+
output += `${theme_1.theme.main}${symbols_1.symbols.pointer} ${title}${ansi_1.ANSI.RESET}`;
|
|
122
|
+
if (match && this.searchBuffer) {
|
|
123
|
+
// Show score
|
|
124
|
+
// output += ` ${theme.muted}(${Math.round(match.score)})${ANSI.RESET}`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
output += ` ${title}`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
this.renderFrame(output);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.FuzzySelectPrompt = FuzzySelectPrompt;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { GaugeOptions } from '../types';
|
|
3
|
+
export declare class GaugePrompt extends Prompt<string, GaugeOptions> {
|
|
4
|
+
private cursor;
|
|
5
|
+
private direction;
|
|
6
|
+
private running;
|
|
7
|
+
private timer?;
|
|
8
|
+
private readonly width;
|
|
9
|
+
private readonly safeZoneHalf;
|
|
10
|
+
private readonly warnZoneHalf;
|
|
11
|
+
private result;
|
|
12
|
+
private resultColor;
|
|
13
|
+
constructor(options: GaugeOptions);
|
|
14
|
+
run(): Promise<string>;
|
|
15
|
+
private startLoop;
|
|
16
|
+
private tick;
|
|
17
|
+
private stop;
|
|
18
|
+
protected handleInput(char: string, _key: Buffer): void;
|
|
19
|
+
protected render(_firstRender: boolean): void;
|
|
20
|
+
protected cleanup(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GaugePrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
class GaugePrompt extends base_1.Prompt {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super(options);
|
|
10
|
+
this.cursor = 0; // 0 to 100
|
|
11
|
+
this.direction = 1;
|
|
12
|
+
this.running = true;
|
|
13
|
+
this.result = null;
|
|
14
|
+
this.resultColor = '';
|
|
15
|
+
this.width = options.width || 40;
|
|
16
|
+
// Calculate safe zone logic (0-100 scale)
|
|
17
|
+
// Default safe width: 20% ( +/- 10%)
|
|
18
|
+
const safeParam = options.safeZone ?? 0.2;
|
|
19
|
+
// Convert to percentage (0-100)
|
|
20
|
+
let safeWidthPct;
|
|
21
|
+
if (safeParam <= 1) {
|
|
22
|
+
safeWidthPct = safeParam * 100;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
safeWidthPct = (safeParam / this.width) * 100;
|
|
26
|
+
}
|
|
27
|
+
this.safeZoneHalf = safeWidthPct / 2;
|
|
28
|
+
// Arbitrary "Good" zone is 3x the safe zone (or until limits)
|
|
29
|
+
this.warnZoneHalf = Math.max(this.safeZoneHalf * 3, 30);
|
|
30
|
+
}
|
|
31
|
+
run() {
|
|
32
|
+
// Start the loop when run is called (after initial render)
|
|
33
|
+
const p = super.run();
|
|
34
|
+
this.startLoop();
|
|
35
|
+
return p;
|
|
36
|
+
}
|
|
37
|
+
startLoop() {
|
|
38
|
+
if (!this.running)
|
|
39
|
+
return;
|
|
40
|
+
this.timer = setTimeout(() => {
|
|
41
|
+
this.tick();
|
|
42
|
+
this.startLoop();
|
|
43
|
+
}, 30); // ~33 FPS
|
|
44
|
+
}
|
|
45
|
+
tick() {
|
|
46
|
+
this.cursor += this.direction * 2; // Speed multiplier
|
|
47
|
+
if (this.cursor >= 100) {
|
|
48
|
+
this.cursor = 100;
|
|
49
|
+
this.direction = -1;
|
|
50
|
+
}
|
|
51
|
+
else if (this.cursor <= 0) {
|
|
52
|
+
this.cursor = 0;
|
|
53
|
+
this.direction = 1;
|
|
54
|
+
}
|
|
55
|
+
this.render(false);
|
|
56
|
+
}
|
|
57
|
+
stop() {
|
|
58
|
+
this.running = false;
|
|
59
|
+
if (this.timer)
|
|
60
|
+
clearTimeout(this.timer);
|
|
61
|
+
// Calculate score
|
|
62
|
+
const center = 50;
|
|
63
|
+
const distance = Math.abs(this.cursor - center);
|
|
64
|
+
if (distance <= this.safeZoneHalf) {
|
|
65
|
+
this.result = 'PERFECT!';
|
|
66
|
+
this.resultColor = theme_1.theme.success;
|
|
67
|
+
}
|
|
68
|
+
else if (distance <= this.warnZoneHalf) {
|
|
69
|
+
this.result = 'GOOD';
|
|
70
|
+
this.resultColor = ansi_1.ANSI.FG_YELLOW;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.result = 'MISS';
|
|
74
|
+
this.resultColor = theme_1.theme.error;
|
|
75
|
+
}
|
|
76
|
+
this.render(false);
|
|
77
|
+
// Wait a moment to show result, then submit
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
this.submit(this.result); // Force non-null
|
|
80
|
+
}, 800);
|
|
81
|
+
}
|
|
82
|
+
handleInput(char, _key) {
|
|
83
|
+
if (!this.running)
|
|
84
|
+
return;
|
|
85
|
+
if (char === ' ') {
|
|
86
|
+
this.stop();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
render(_firstRender) {
|
|
90
|
+
let output = '';
|
|
91
|
+
// Header
|
|
92
|
+
output += `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
93
|
+
// Draw Gauge Bar
|
|
94
|
+
let barStr = '';
|
|
95
|
+
const center = 50;
|
|
96
|
+
for (let i = 0; i < this.width; i++) {
|
|
97
|
+
const pct = (i / this.width) * 100;
|
|
98
|
+
const dist = Math.abs(pct - center);
|
|
99
|
+
let charColor = theme_1.theme.error; // Default Miss (Red)
|
|
100
|
+
if (dist <= this.safeZoneHalf) {
|
|
101
|
+
charColor = theme_1.theme.success; // Perfect (Green)
|
|
102
|
+
}
|
|
103
|
+
else if (dist <= this.warnZoneHalf) {
|
|
104
|
+
charColor = ansi_1.ANSI.FG_YELLOW; // Good (Yellow)
|
|
105
|
+
}
|
|
106
|
+
// Using block characters for the bar
|
|
107
|
+
barStr += `${charColor}━${ansi_1.ANSI.RESET}`;
|
|
108
|
+
}
|
|
109
|
+
output += ` ${barStr}\n`;
|
|
110
|
+
// Draw Cursor
|
|
111
|
+
// Position relative to width
|
|
112
|
+
const pos = Math.floor((this.cursor / 100) * (this.width - 1));
|
|
113
|
+
const padding = ' '.repeat(pos);
|
|
114
|
+
output += ` ${padding}${theme_1.theme.main}▲${ansi_1.ANSI.RESET}\n`;
|
|
115
|
+
// Instructions or Result
|
|
116
|
+
if (this.running) {
|
|
117
|
+
output += `${theme_1.theme.muted}(Press Space to Stop)${ansi_1.ANSI.RESET}`;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
output += `${ansi_1.ANSI.BOLD}${this.resultColor}${this.result}${ansi_1.ANSI.RESET}`;
|
|
121
|
+
}
|
|
122
|
+
this.renderFrame(output);
|
|
123
|
+
}
|
|
124
|
+
cleanup() {
|
|
125
|
+
if (this.timer)
|
|
126
|
+
clearTimeout(this.timer);
|
|
127
|
+
super.cleanup();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.GaugePrompt = GaugePrompt;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { HeatmapOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class HeatmapPrompt extends Prompt<number[][], HeatmapOptions> {
|
|
4
|
+
private grid;
|
|
5
|
+
private cursorRow;
|
|
6
|
+
private cursorCol;
|
|
7
|
+
private validValues;
|
|
8
|
+
constructor(options: HeatmapOptions);
|
|
9
|
+
protected render(_firstRender: boolean): void;
|
|
10
|
+
private getLegend;
|
|
11
|
+
protected handleMouse(event: MouseEvent): void;
|
|
12
|
+
protected handleInput(char: string, _key: Buffer): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HeatmapPrompt = void 0;
|
|
4
|
+
const base_1 = require("../base");
|
|
5
|
+
const ansi_1 = require("../ansi");
|
|
6
|
+
class HeatmapPrompt extends base_1.Prompt {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super(options);
|
|
9
|
+
this.cursorRow = 0;
|
|
10
|
+
this.cursorCol = 0;
|
|
11
|
+
// Initialize grid
|
|
12
|
+
const rows = options.rows.length;
|
|
13
|
+
const cols = options.columns.length;
|
|
14
|
+
if (options.initial) {
|
|
15
|
+
this.grid = options.initial.map(row => [...row]);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.grid = Array.from({ length: rows }, () => Array(cols).fill(0));
|
|
19
|
+
}
|
|
20
|
+
// Get sorted valid values for cycling
|
|
21
|
+
this.validValues = options.legend.map(l => l.value).sort((a, b) => a - b);
|
|
22
|
+
}
|
|
23
|
+
render(_firstRender) {
|
|
24
|
+
let output = `${ansi_1.ANSI.FG_CYAN}? ${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
25
|
+
// Render Column Headers
|
|
26
|
+
output += ' '; // Offset for row labels
|
|
27
|
+
this.options.columns.forEach(col => {
|
|
28
|
+
// Show first 2 chars
|
|
29
|
+
const label = col.substring(0, 2).padEnd(2);
|
|
30
|
+
output += ` ${label} `;
|
|
31
|
+
});
|
|
32
|
+
output += '\n';
|
|
33
|
+
// Grid
|
|
34
|
+
for (let r = 0; r < this.options.rows.length; r++) {
|
|
35
|
+
const rowLabel = this.options.rows[r].substring(0, 4).padStart(4);
|
|
36
|
+
output += `${ansi_1.ANSI.FG_GRAY}${rowLabel} ${ansi_1.ANSI.RESET}`;
|
|
37
|
+
for (let c = 0; c < this.options.columns.length; c++) {
|
|
38
|
+
const val = this.grid[r][c];
|
|
39
|
+
const legend = this.getLegend(val);
|
|
40
|
+
const char = legend?.char || '?';
|
|
41
|
+
const color = legend?.color || ((s) => s);
|
|
42
|
+
const isCursor = r === this.cursorRow && c === this.cursorCol;
|
|
43
|
+
const cellContent = color(char);
|
|
44
|
+
if (isCursor) {
|
|
45
|
+
output += `[${cellContent}]`; // Brackets around
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
output += ` ${cellContent} `;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
output += '\n';
|
|
52
|
+
}
|
|
53
|
+
// Legend
|
|
54
|
+
output += '\nLegend: ';
|
|
55
|
+
this.options.legend.forEach(l => {
|
|
56
|
+
output += `${l.value}:${l.color(l.char)} `;
|
|
57
|
+
});
|
|
58
|
+
output += '\n' + ansi_1.ANSI.FG_GRAY + "(Arrows to move, Space to cycle, 0-9 to set)" + ansi_1.ANSI.RESET;
|
|
59
|
+
this.renderFrame(output);
|
|
60
|
+
}
|
|
61
|
+
getLegend(val) {
|
|
62
|
+
return this.options.legend.find(l => l.value === val);
|
|
63
|
+
}
|
|
64
|
+
handleMouse(event) {
|
|
65
|
+
if (event.action === 'scroll') {
|
|
66
|
+
if (event.scroll === 'up') {
|
|
67
|
+
if (this.cursorRow > 0)
|
|
68
|
+
this.cursorRow--;
|
|
69
|
+
}
|
|
70
|
+
else if (event.scroll === 'down') {
|
|
71
|
+
if (this.cursorRow < this.options.rows.length - 1)
|
|
72
|
+
this.cursorRow++;
|
|
73
|
+
}
|
|
74
|
+
this.render(false);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
handleInput(char, _key) {
|
|
78
|
+
if (char === '\r' || char === '\n') { // Enter
|
|
79
|
+
this.submit(this.grid);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (this.isUp(char)) {
|
|
83
|
+
if (this.cursorRow > 0)
|
|
84
|
+
this.cursorRow--;
|
|
85
|
+
}
|
|
86
|
+
else if (this.isDown(char)) {
|
|
87
|
+
if (this.cursorRow < this.options.rows.length - 1)
|
|
88
|
+
this.cursorRow++;
|
|
89
|
+
}
|
|
90
|
+
else if (this.isLeft(char)) {
|
|
91
|
+
if (this.cursorCol > 0)
|
|
92
|
+
this.cursorCol--;
|
|
93
|
+
}
|
|
94
|
+
else if (this.isRight(char)) {
|
|
95
|
+
if (this.cursorCol < this.options.columns.length - 1)
|
|
96
|
+
this.cursorCol++;
|
|
97
|
+
}
|
|
98
|
+
else if (char === '\t') { // Tab -> Right (Cycle)
|
|
99
|
+
this.cursorCol++;
|
|
100
|
+
if (this.cursorCol >= this.options.columns.length) {
|
|
101
|
+
this.cursorCol = 0;
|
|
102
|
+
this.cursorRow++;
|
|
103
|
+
if (this.cursorRow >= this.options.rows.length) {
|
|
104
|
+
this.cursorRow = 0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (char === '\u001b[Z') { // Shift+Tab -> Left (Cycle)
|
|
109
|
+
this.cursorCol--;
|
|
110
|
+
if (this.cursorCol < 0) {
|
|
111
|
+
this.cursorCol = this.options.columns.length - 1;
|
|
112
|
+
this.cursorRow--;
|
|
113
|
+
if (this.cursorRow < 0) {
|
|
114
|
+
this.cursorRow = this.options.rows.length - 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (char === ' ') {
|
|
119
|
+
const val = this.grid[this.cursorRow][this.cursorCol];
|
|
120
|
+
const idx = this.validValues.indexOf(val);
|
|
121
|
+
let nextVal;
|
|
122
|
+
if (idx === -1) {
|
|
123
|
+
// If current val not in legend (maybe init with invalid), reset to first
|
|
124
|
+
nextVal = this.validValues[0];
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
nextVal = this.validValues[(idx + 1) % this.validValues.length];
|
|
128
|
+
}
|
|
129
|
+
this.grid[this.cursorRow][this.cursorCol] = nextVal;
|
|
130
|
+
}
|
|
131
|
+
else if (/[0-9]/.test(char)) {
|
|
132
|
+
const num = parseInt(char, 10);
|
|
133
|
+
// Only set if valid in legend
|
|
134
|
+
if (this.validValues.includes(num)) {
|
|
135
|
+
this.grid[this.cursorRow][this.cursorCol] = num;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.render(false);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.HeatmapPrompt = HeatmapPrompt;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { IPOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class IPPrompt extends Prompt<string, IPOptions> {
|
|
4
|
+
private octets;
|
|
5
|
+
private activeOctet;
|
|
6
|
+
private errorMsg;
|
|
7
|
+
constructor(options: IPOptions);
|
|
8
|
+
protected render(_firstRender: boolean): void;
|
|
9
|
+
protected handleInput(char: string): void;
|
|
10
|
+
protected handleMouse(event: MouseEvent): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IPPrompt = 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 IPPrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.octets = ['', '', '', ''];
|
|
12
|
+
this.activeOctet = 0;
|
|
13
|
+
this.errorMsg = '';
|
|
14
|
+
if (options.initial) {
|
|
15
|
+
const parts = options.initial.split('.');
|
|
16
|
+
if (parts.length === 4) {
|
|
17
|
+
this.octets = parts.map(p => {
|
|
18
|
+
const num = parseInt(p, 10);
|
|
19
|
+
return !isNaN(num) && num >= 0 && num <= 255 ? p : '';
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
render(_firstRender) {
|
|
25
|
+
let output = '';
|
|
26
|
+
// Title
|
|
27
|
+
const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
|
|
28
|
+
output += `${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
29
|
+
// IP Render
|
|
30
|
+
const partsDisplay = this.octets.map((octet, index) => {
|
|
31
|
+
const isEmpty = octet.length === 0;
|
|
32
|
+
let displayVal = isEmpty ? '_' : octet;
|
|
33
|
+
if (index === this.activeOctet) {
|
|
34
|
+
// Highlight active
|
|
35
|
+
displayVal = `${theme_1.theme.main}${ansi_1.ANSI.UNDERLINE}${displayVal}${ansi_1.ANSI.RESET}`;
|
|
36
|
+
}
|
|
37
|
+
return displayVal;
|
|
38
|
+
});
|
|
39
|
+
output += ` ${partsDisplay.join('.')}`;
|
|
40
|
+
if (this.errorMsg) {
|
|
41
|
+
output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
|
|
42
|
+
}
|
|
43
|
+
this.renderFrame(output);
|
|
44
|
+
}
|
|
45
|
+
handleInput(char) {
|
|
46
|
+
this.errorMsg = '';
|
|
47
|
+
if (char === '\r' || char === '\n') {
|
|
48
|
+
if (this.octets.every(o => o.length > 0)) {
|
|
49
|
+
this.submit(this.octets.join('.'));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this.errorMsg = 'Invalid IP address';
|
|
53
|
+
this.render(false);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (char === '\u0008' || char === '\x7f') { // Backspace
|
|
58
|
+
const current = this.octets[this.activeOctet];
|
|
59
|
+
if (current.length > 0) {
|
|
60
|
+
this.octets[this.activeOctet] = current.slice(0, -1);
|
|
61
|
+
}
|
|
62
|
+
else if (this.activeOctet > 0) {
|
|
63
|
+
this.activeOctet--;
|
|
64
|
+
}
|
|
65
|
+
this.render(false);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Navigation
|
|
69
|
+
if (this.isLeft(char) && this.activeOctet > 0) {
|
|
70
|
+
this.activeOctet--;
|
|
71
|
+
this.render(false);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (this.isRight(char) && this.activeOctet < 3) {
|
|
75
|
+
this.activeOctet++;
|
|
76
|
+
this.render(false);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Dot navigation
|
|
80
|
+
if (char === '.') {
|
|
81
|
+
if (this.activeOctet < 3) {
|
|
82
|
+
this.activeOctet++;
|
|
83
|
+
this.render(false);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Numbers
|
|
88
|
+
if (/^\d$/.test(char)) {
|
|
89
|
+
const current = this.octets[this.activeOctet];
|
|
90
|
+
const newValue = current + char;
|
|
91
|
+
if (parseInt(newValue, 10) <= 255) {
|
|
92
|
+
this.octets[this.activeOctet] = newValue;
|
|
93
|
+
// Auto-jump if 3 digits
|
|
94
|
+
if (newValue.length === 3 && this.activeOctet < 3) {
|
|
95
|
+
this.activeOctet++;
|
|
96
|
+
}
|
|
97
|
+
this.render(false);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
handleMouse(event) {
|
|
102
|
+
if (event.action === 'scroll') {
|
|
103
|
+
if (event.scroll === 'up') {
|
|
104
|
+
if (this.activeOctet > 0) {
|
|
105
|
+
this.activeOctet--;
|
|
106
|
+
this.render(false);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (event.scroll === 'down') {
|
|
110
|
+
if (this.activeOctet < 3) {
|
|
111
|
+
this.activeOctet++;
|
|
112
|
+
this.render(false);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.IPPrompt = IPPrompt;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { KanbanOptions, KanbanItem, MouseEvent } from '../types';
|
|
3
|
+
export declare class KanbanPrompt<V extends KanbanItem> extends Prompt<Record<string, V[]>, KanbanOptions<V>> {
|
|
4
|
+
private columns;
|
|
5
|
+
private activeCol;
|
|
6
|
+
private activeRow;
|
|
7
|
+
private grabbed;
|
|
8
|
+
private scrollStates;
|
|
9
|
+
constructor(options: KanbanOptions<V>);
|
|
10
|
+
protected render(_firstRender: boolean): void;
|
|
11
|
+
private padCenter;
|
|
12
|
+
protected handleMouse(event: MouseEvent): void;
|
|
13
|
+
protected handleInput(char: string, _key: Buffer): void;
|
|
14
|
+
private moveItemHorizontal;
|
|
15
|
+
private clampRow;
|
|
16
|
+
private ensureVisible;
|
|
17
|
+
}
|