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,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScrollPrompt = void 0;
|
|
4
|
+
const base_1 = require("../base");
|
|
5
|
+
const ansi_1 = require("../ansi");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
const symbols_1 = require("../symbols");
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
class ScrollPrompt extends base_1.Prompt {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.scrollTop = 0;
|
|
13
|
+
this.hasReachedBottom = false;
|
|
14
|
+
this.showError = false;
|
|
15
|
+
// Normalize newlines and split content
|
|
16
|
+
this.lines = (options.content || '').replace(/\r\n/g, '\n').split('\n');
|
|
17
|
+
this.height = options.height || 15;
|
|
18
|
+
// Initial check if content fits without scrolling
|
|
19
|
+
if (this.lines.length <= this.height) {
|
|
20
|
+
this.hasReachedBottom = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
render(_firstRender) {
|
|
24
|
+
const width = this.stdout.columns || 80;
|
|
25
|
+
const contentWidth = width - 4; // Border (2) + Padding (2)
|
|
26
|
+
// 1. Header & Progress
|
|
27
|
+
const percent = Math.min(100, Math.round(((this.scrollTop + this.height) / Math.max(this.height, this.lines.length)) * 100));
|
|
28
|
+
const header = `${theme_1.theme.title}${symbols_1.symbols.pointer} ${ansi_1.ANSI.BOLD}${this.options.message}${ansi_1.ANSI.RESET} ${theme_1.theme.muted}[${percent}%]${ansi_1.ANSI.RESET}`;
|
|
29
|
+
// 2. Viewport
|
|
30
|
+
const visibleLines = this.lines.slice(this.scrollTop, this.scrollTop + this.height);
|
|
31
|
+
// Fill empty lines if content is shorter than height
|
|
32
|
+
while (visibleLines.length < this.height) {
|
|
33
|
+
visibleLines.push('');
|
|
34
|
+
}
|
|
35
|
+
const borderTop = `${theme_1.theme.muted}${symbols_1.symbols.topLeft}${symbols_1.symbols.horizontal.repeat(width - 2)}${symbols_1.symbols.topRight}${ansi_1.ANSI.RESET}`;
|
|
36
|
+
const borderBottom = `${theme_1.theme.muted}${symbols_1.symbols.bottomLeft}${symbols_1.symbols.horizontal.repeat(width - 2)}${symbols_1.symbols.bottomRight}${ansi_1.ANSI.RESET}`;
|
|
37
|
+
const contentRows = visibleLines.map(line => {
|
|
38
|
+
let displayLine = line;
|
|
39
|
+
const len = (0, utils_1.stringWidth)(displayLine);
|
|
40
|
+
if (len > contentWidth) {
|
|
41
|
+
// Truncate
|
|
42
|
+
displayLine = this.truncate(displayLine, contentWidth);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// Pad
|
|
46
|
+
displayLine += ' '.repeat(contentWidth - len);
|
|
47
|
+
}
|
|
48
|
+
return `${theme_1.theme.muted}${symbols_1.symbols.vertical}${ansi_1.ANSI.RESET} ${displayLine} ${theme_1.theme.muted}${symbols_1.symbols.vertical}${ansi_1.ANSI.RESET}`;
|
|
49
|
+
});
|
|
50
|
+
// 3. Footer / Status
|
|
51
|
+
let footer = '';
|
|
52
|
+
if (this.showError) {
|
|
53
|
+
footer = `${theme_1.theme.error}>> Please scroll to the bottom before proceeding.${ansi_1.ANSI.RESET}`;
|
|
54
|
+
}
|
|
55
|
+
else if (this.options.requireScrollToBottom && !this.hasReachedBottom) {
|
|
56
|
+
footer = `${theme_1.theme.muted}(Scroll down to read more)${ansi_1.ANSI.RESET}`;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
footer = `${theme_1.theme.success}>> Press Enter to accept${ansi_1.ANSI.RESET}`;
|
|
60
|
+
}
|
|
61
|
+
const output = [
|
|
62
|
+
header,
|
|
63
|
+
borderTop,
|
|
64
|
+
...contentRows,
|
|
65
|
+
borderBottom,
|
|
66
|
+
footer
|
|
67
|
+
].join('\n');
|
|
68
|
+
this.renderFrame(output);
|
|
69
|
+
}
|
|
70
|
+
handleInput(char, key) {
|
|
71
|
+
// Enter
|
|
72
|
+
if (char === '\r' || char === '\n') {
|
|
73
|
+
if (this.options.requireScrollToBottom && !this.hasReachedBottom) {
|
|
74
|
+
this.showError = true;
|
|
75
|
+
this.render(false);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.submit(true);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let didScroll = false;
|
|
82
|
+
// Up / k
|
|
83
|
+
if (this.isUp(char) || char === 'k') {
|
|
84
|
+
if (this.scrollTop > 0) {
|
|
85
|
+
this.scrollTop--;
|
|
86
|
+
didScroll = true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Down / j
|
|
90
|
+
else if (this.isDown(char) || char === 'j') {
|
|
91
|
+
if (this.scrollTop + this.height < this.lines.length) {
|
|
92
|
+
this.scrollTop++;
|
|
93
|
+
didScroll = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// PageUp
|
|
97
|
+
else if (key.toString('hex') === '1b5b357e') { // Standard PageUp sequence
|
|
98
|
+
this.scrollTop = Math.max(0, this.scrollTop - this.height);
|
|
99
|
+
didScroll = true;
|
|
100
|
+
}
|
|
101
|
+
// PageDown / Space
|
|
102
|
+
else if (char === ' ' || key.toString('hex') === '1b5b367e') { // Standard PageDown sequence
|
|
103
|
+
this.scrollTop = Math.min(this.lines.length - this.height, this.scrollTop + this.height);
|
|
104
|
+
if (this.scrollTop < 0)
|
|
105
|
+
this.scrollTop = 0; // Fix if content < height
|
|
106
|
+
didScroll = true;
|
|
107
|
+
}
|
|
108
|
+
// Home
|
|
109
|
+
else if (key.toString('hex') === '1b5b48') {
|
|
110
|
+
this.scrollTop = 0;
|
|
111
|
+
didScroll = true;
|
|
112
|
+
}
|
|
113
|
+
// End
|
|
114
|
+
else if (key.toString('hex') === '1b5b46') {
|
|
115
|
+
this.scrollTop = Math.max(0, this.lines.length - this.height);
|
|
116
|
+
didScroll = true;
|
|
117
|
+
}
|
|
118
|
+
if (didScroll) {
|
|
119
|
+
this.showError = false;
|
|
120
|
+
// Check if reached bottom
|
|
121
|
+
if (this.scrollTop + this.height >= this.lines.length) {
|
|
122
|
+
this.hasReachedBottom = true;
|
|
123
|
+
}
|
|
124
|
+
this.render(false);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
handleMouse(event) {
|
|
128
|
+
if (event.action === 'scroll') {
|
|
129
|
+
let didScroll = false;
|
|
130
|
+
if (event.scroll === 'up') {
|
|
131
|
+
if (this.scrollTop > 0) {
|
|
132
|
+
this.scrollTop--;
|
|
133
|
+
didScroll = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (event.scroll === 'down') {
|
|
137
|
+
if (this.scrollTop + this.height < this.lines.length) {
|
|
138
|
+
this.scrollTop++;
|
|
139
|
+
didScroll = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (didScroll) {
|
|
143
|
+
this.showError = false;
|
|
144
|
+
if (this.scrollTop + this.height >= this.lines.length) {
|
|
145
|
+
this.hasReachedBottom = true;
|
|
146
|
+
}
|
|
147
|
+
this.render(false);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.ScrollPrompt = ScrollPrompt;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { SeatOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class SeatPrompt extends Prompt<string[], SeatOptions> {
|
|
4
|
+
private grid;
|
|
5
|
+
private cursorX;
|
|
6
|
+
private cursorY;
|
|
7
|
+
private selected;
|
|
8
|
+
private height;
|
|
9
|
+
private width;
|
|
10
|
+
private initializedCursor;
|
|
11
|
+
constructor(options: SeatOptions);
|
|
12
|
+
private parseLayout;
|
|
13
|
+
protected render(_firstRender: boolean): void;
|
|
14
|
+
protected handleInput(char: string): void;
|
|
15
|
+
protected handleMouse(event: MouseEvent): void;
|
|
16
|
+
private move;
|
|
17
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SeatPrompt = void 0;
|
|
4
|
+
const base_1 = require("../base");
|
|
5
|
+
const ansi_1 = require("../ansi");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
class SeatPrompt extends base_1.Prompt {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super(options);
|
|
10
|
+
this.grid = [];
|
|
11
|
+
this.cursorX = 0;
|
|
12
|
+
this.cursorY = 0;
|
|
13
|
+
this.selected = new Set();
|
|
14
|
+
this.height = 0;
|
|
15
|
+
this.width = 0;
|
|
16
|
+
this.initializedCursor = false;
|
|
17
|
+
this.parseLayout();
|
|
18
|
+
if (options.initial) {
|
|
19
|
+
options.initial.forEach(id => this.selected.add(id));
|
|
20
|
+
}
|
|
21
|
+
this.checkWindowsAttention();
|
|
22
|
+
}
|
|
23
|
+
parseLayout() {
|
|
24
|
+
this.height = this.options.layout.length;
|
|
25
|
+
this.width = 0;
|
|
26
|
+
this.grid = this.options.layout.map((line, y) => {
|
|
27
|
+
if (line.length > this.width)
|
|
28
|
+
this.width = line.length;
|
|
29
|
+
return line.split('').map((char, x) => {
|
|
30
|
+
const isGap = char === '_' || char === ' ';
|
|
31
|
+
// Convention: 'X' is occupied.
|
|
32
|
+
const isOccupied = char.toUpperCase() === 'X';
|
|
33
|
+
// Label generation: Rows (A, B...), Cols (1, 2...)
|
|
34
|
+
const rowLabel = this.options.rows ? (this.options.rows[y] || String(y + 1)) : String.fromCharCode(65 + y);
|
|
35
|
+
const colLabel = this.options.cols ? (this.options.cols[x] || String(x + 1)) : String(x + 1);
|
|
36
|
+
const label = `${rowLabel}${colLabel}`;
|
|
37
|
+
const selectable = !isGap;
|
|
38
|
+
let status = 'available';
|
|
39
|
+
if (isOccupied)
|
|
40
|
+
status = 'occupied';
|
|
41
|
+
if (this.selected.has(label))
|
|
42
|
+
status = 'selected'; // Though this is dynamic state
|
|
43
|
+
// Initialize cursor to first available seat
|
|
44
|
+
if (selectable && status !== 'occupied' && !this.initializedCursor) {
|
|
45
|
+
this.cursorX = x;
|
|
46
|
+
this.cursorY = y;
|
|
47
|
+
this.initializedCursor = true;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
x, y, char, label, selectable, status
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
render(_firstRender) {
|
|
56
|
+
let output = `${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
57
|
+
output += `${theme_1.theme.muted}(Use arrows to move, Space to select, Enter to confirm)${ansi_1.ANSI.RESET}\n\n`;
|
|
58
|
+
this.grid.forEach((row, y) => {
|
|
59
|
+
let lineStr = '';
|
|
60
|
+
row.forEach((node, x) => {
|
|
61
|
+
const isCursor = x === this.cursorX && y === this.cursorY;
|
|
62
|
+
const isSelected = this.selected.has(node.label);
|
|
63
|
+
const charDisplay = node.char;
|
|
64
|
+
// If occupied, maybe show a different char or color
|
|
65
|
+
let style = ansi_1.ANSI.RESET;
|
|
66
|
+
if (node.status === 'occupied') {
|
|
67
|
+
style = ansi_1.ANSI.FG_RED;
|
|
68
|
+
}
|
|
69
|
+
else if (!node.selectable) {
|
|
70
|
+
style = theme_1.theme.muted;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
style = theme_1.theme.main; // Available seats
|
|
74
|
+
}
|
|
75
|
+
if (isSelected) {
|
|
76
|
+
style = ansi_1.ANSI.BG_GREEN + ansi_1.ANSI.FG_BLACK;
|
|
77
|
+
}
|
|
78
|
+
if (isCursor) {
|
|
79
|
+
// Combine styles? Cursor overrides everything usually
|
|
80
|
+
style = ansi_1.ANSI.BG_CYAN + ansi_1.ANSI.FG_BLACK;
|
|
81
|
+
}
|
|
82
|
+
lineStr += style + charDisplay + ansi_1.ANSI.RESET + ' ';
|
|
83
|
+
});
|
|
84
|
+
output += lineStr + '\n';
|
|
85
|
+
});
|
|
86
|
+
// Show Legend or Current Selection
|
|
87
|
+
if (this.selected.size > 0) {
|
|
88
|
+
output += `\n${theme_1.theme.success}Selected: ${Array.from(this.selected).join(', ')}${ansi_1.ANSI.RESET}`;
|
|
89
|
+
}
|
|
90
|
+
this.renderFrame(output);
|
|
91
|
+
}
|
|
92
|
+
handleInput(char) {
|
|
93
|
+
if (char === '\r' || char === '\n') {
|
|
94
|
+
this.submit(Array.from(this.selected));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (char === ' ') {
|
|
98
|
+
const row = this.grid[this.cursorY];
|
|
99
|
+
if (!row)
|
|
100
|
+
return;
|
|
101
|
+
const node = row[this.cursorX];
|
|
102
|
+
if (node && node.selectable && node.status !== 'occupied') {
|
|
103
|
+
if (this.selected.has(node.label)) {
|
|
104
|
+
this.selected.delete(node.label);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
if (!this.options.multiple)
|
|
108
|
+
this.selected.clear();
|
|
109
|
+
this.selected.add(node.label);
|
|
110
|
+
}
|
|
111
|
+
this.render(false);
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (this.isUp(char))
|
|
116
|
+
this.move(0, -1);
|
|
117
|
+
else if (this.isDown(char))
|
|
118
|
+
this.move(0, 1);
|
|
119
|
+
else if (this.isLeft(char))
|
|
120
|
+
this.move(-1, 0);
|
|
121
|
+
else if (this.isRight(char))
|
|
122
|
+
this.move(1, 0);
|
|
123
|
+
// Tab / Shift+Tab
|
|
124
|
+
else if (char === '\t')
|
|
125
|
+
this.move(1, 0);
|
|
126
|
+
else if (char === '\u001b[Z')
|
|
127
|
+
this.move(-1, 0);
|
|
128
|
+
}
|
|
129
|
+
handleMouse(event) {
|
|
130
|
+
if (event.action === 'scroll') {
|
|
131
|
+
if (event.scroll === 'up')
|
|
132
|
+
this.move(0, -1);
|
|
133
|
+
else if (event.scroll === 'down')
|
|
134
|
+
this.move(0, 1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
move(dx, dy) {
|
|
138
|
+
let nx = this.cursorX;
|
|
139
|
+
let ny = this.cursorY;
|
|
140
|
+
let limit = Math.max(this.width, this.height) + 10;
|
|
141
|
+
do {
|
|
142
|
+
nx += dx;
|
|
143
|
+
ny += dy;
|
|
144
|
+
limit--;
|
|
145
|
+
// Boundary Check
|
|
146
|
+
if (ny < 0 || ny >= this.height)
|
|
147
|
+
return;
|
|
148
|
+
const row = this.grid[ny];
|
|
149
|
+
if (!row)
|
|
150
|
+
return;
|
|
151
|
+
if (nx < 0 || nx >= row.length)
|
|
152
|
+
return;
|
|
153
|
+
const node = row[nx];
|
|
154
|
+
// Stop if node is selectable (seat or occupied seat)
|
|
155
|
+
// Skip gaps ('_' or ' ')
|
|
156
|
+
if (node.selectable) {
|
|
157
|
+
this.cursorX = nx;
|
|
158
|
+
this.cursorY = ny;
|
|
159
|
+
this.render(false);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
} while (limit > 0);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.SeatPrompt = SeatPrompt;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SelectRangeOptions } from '../types';
|
|
2
|
+
import { SelectPrompt } from './select';
|
|
3
|
+
export declare class SelectRangePrompt<V> extends SelectPrompt<V, SelectRangeOptions<V>> {
|
|
4
|
+
protected anchorIndex: number | null;
|
|
5
|
+
constructor(options: SelectRangeOptions<V>);
|
|
6
|
+
protected handleInput(char: string, _key?: Buffer): void;
|
|
7
|
+
protected render(_firstRender: boolean): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SelectRangePrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const theme_1 = require("../theme");
|
|
6
|
+
const symbols_1 = require("../symbols");
|
|
7
|
+
const select_1 = require("./select");
|
|
8
|
+
class SelectRangePrompt extends select_1.SelectPrompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.anchorIndex = null;
|
|
12
|
+
if (options.initial) {
|
|
13
|
+
const maxIdx = Math.max(0, options.choices.length - 1);
|
|
14
|
+
this.anchorIndex = Math.min(Math.max(0, options.initial[0]), maxIdx);
|
|
15
|
+
this.selectedIndex = Math.min(Math.max(0, options.initial[1]), maxIdx);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
handleInput(char, _key) {
|
|
19
|
+
// Handle Enter (Submit)
|
|
20
|
+
if (char === '\r' || char === '\n') {
|
|
21
|
+
const choices = this.getFilteredChoices();
|
|
22
|
+
if (choices.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
if (this.isSeparator(choices[this.selectedIndex]))
|
|
25
|
+
return;
|
|
26
|
+
let start = this.selectedIndex;
|
|
27
|
+
let end = this.selectedIndex;
|
|
28
|
+
if (this.anchorIndex !== null) {
|
|
29
|
+
start = Math.min(this.anchorIndex, this.selectedIndex);
|
|
30
|
+
end = Math.max(this.anchorIndex, this.selectedIndex);
|
|
31
|
+
}
|
|
32
|
+
const selectedItems = [];
|
|
33
|
+
for (let i = start; i <= end; i++) {
|
|
34
|
+
const choice = choices[i];
|
|
35
|
+
if (!this.isSeparator(choice)) {
|
|
36
|
+
selectedItems.push(choice.value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this.submit(selectedItems);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Handle Space (Anchor)
|
|
43
|
+
if (char === ' ') {
|
|
44
|
+
if (this.anchorIndex === null) {
|
|
45
|
+
this.anchorIndex = this.selectedIndex;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.anchorIndex = null;
|
|
49
|
+
}
|
|
50
|
+
this.render(false);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Delegate navigation and search to SelectPrompt
|
|
54
|
+
super.handleInput(char);
|
|
55
|
+
// Check bounds after navigation/filtering
|
|
56
|
+
const choices = this.getFilteredChoices();
|
|
57
|
+
if (this.anchorIndex !== null && this.anchorIndex >= choices.length) {
|
|
58
|
+
this.anchorIndex = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
render(_firstRender) {
|
|
62
|
+
let output = '';
|
|
63
|
+
const choices = this.getFilteredChoices();
|
|
64
|
+
// Scroll Logic
|
|
65
|
+
if (this.selectedIndex < this.scrollTop) {
|
|
66
|
+
this.scrollTop = this.selectedIndex;
|
|
67
|
+
}
|
|
68
|
+
else if (this.selectedIndex >= this.scrollTop + this.pageSize) {
|
|
69
|
+
this.scrollTop = this.selectedIndex - this.pageSize + 1;
|
|
70
|
+
}
|
|
71
|
+
if (this.scrollTop > choices.length - 1) {
|
|
72
|
+
this.scrollTop = Math.max(0, choices.length - this.pageSize);
|
|
73
|
+
}
|
|
74
|
+
// Header
|
|
75
|
+
const searchStr = this.searchBuffer ? ` ${theme_1.theme.muted}(Filter: ${this.searchBuffer})${ansi_1.ANSI.RESET}` : '';
|
|
76
|
+
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`;
|
|
77
|
+
if (choices.length === 0) {
|
|
78
|
+
output += ` ${theme_1.theme.muted}No results found${ansi_1.ANSI.RESET}`;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const visibleChoices = choices.slice(this.scrollTop, this.scrollTop + this.pageSize);
|
|
82
|
+
visibleChoices.forEach((choice, index) => {
|
|
83
|
+
const actualIndex = this.scrollTop + index;
|
|
84
|
+
if (index > 0)
|
|
85
|
+
output += '\n';
|
|
86
|
+
let isSelected = false;
|
|
87
|
+
if (this.anchorIndex !== null) {
|
|
88
|
+
const min = Math.min(this.anchorIndex, this.selectedIndex);
|
|
89
|
+
const max = Math.max(this.anchorIndex, this.selectedIndex);
|
|
90
|
+
if (actualIndex >= min && actualIndex <= max) {
|
|
91
|
+
isSelected = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (actualIndex === this.selectedIndex) {
|
|
95
|
+
isSelected = true;
|
|
96
|
+
}
|
|
97
|
+
if (this.isSeparator(choice)) {
|
|
98
|
+
output += ` ${ansi_1.ANSI.DIM}${choice.text || symbols_1.symbols.line.repeat(8)}${ansi_1.ANSI.RESET}`;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
let prefix = ' ';
|
|
102
|
+
const title = choice.title;
|
|
103
|
+
let content = title;
|
|
104
|
+
// Anchor Marker
|
|
105
|
+
if (actualIndex === this.anchorIndex) {
|
|
106
|
+
prefix = `${theme_1.theme.muted}> ${ansi_1.ANSI.RESET}`;
|
|
107
|
+
}
|
|
108
|
+
// Cursor Marker
|
|
109
|
+
if (actualIndex === this.selectedIndex) {
|
|
110
|
+
prefix = `${theme_1.theme.main}${symbols_1.symbols.pointer} `;
|
|
111
|
+
}
|
|
112
|
+
// Combined Marker
|
|
113
|
+
if (actualIndex === this.selectedIndex && actualIndex === this.anchorIndex) {
|
|
114
|
+
prefix = `${theme_1.theme.main}${symbols_1.symbols.pointer}>`;
|
|
115
|
+
}
|
|
116
|
+
// Highlighting
|
|
117
|
+
if (isSelected) {
|
|
118
|
+
// Inside the range (and not cursor/anchor which have their own prefixes)
|
|
119
|
+
if (actualIndex !== this.selectedIndex && actualIndex !== this.anchorIndex) {
|
|
120
|
+
prefix = `${theme_1.theme.success}* ${ansi_1.ANSI.RESET}`;
|
|
121
|
+
}
|
|
122
|
+
content = `${theme_1.theme.success}${title}${ansi_1.ANSI.RESET}`;
|
|
123
|
+
}
|
|
124
|
+
// Underline Cursor
|
|
125
|
+
if (actualIndex === this.selectedIndex) {
|
|
126
|
+
content = `${ansi_1.ANSI.UNDERLINE}${content}${ansi_1.ANSI.RESET}`;
|
|
127
|
+
}
|
|
128
|
+
output += `${prefix}${content}`;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
output += `\n${theme_1.theme.muted}(Space to anchor, Enter to submit)${ansi_1.ANSI.RESET}`;
|
|
133
|
+
this.renderFrame(output);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.SelectRangePrompt = SelectRangePrompt;
|
package/dist/prompts/select.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Prompt } from '../base';
|
|
2
2
|
import { SelectOptions, MouseEvent } from '../types';
|
|
3
|
-
export declare class SelectPrompt<V
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
constructor(options:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
export declare class SelectPrompt<V, O extends SelectOptions<V> = SelectOptions<V>> extends Prompt<any, O> {
|
|
4
|
+
protected selectedIndex: number;
|
|
5
|
+
protected searchBuffer: string;
|
|
6
|
+
protected scrollTop: number;
|
|
7
|
+
protected readonly pageSize: number;
|
|
8
|
+
constructor(options: O);
|
|
9
|
+
protected isSeparator(item: any): boolean;
|
|
10
|
+
protected findNextSelectableIndex(currentIndex: number, direction: 1 | -1): number;
|
|
11
|
+
protected getFilteredChoices(): (import("../types").Separator | import("../types").SelectChoice<V>)[];
|
|
12
12
|
protected render(_firstRender: boolean): void;
|
|
13
13
|
protected handleInput(char: string): void;
|
|
14
14
|
protected handleMouse(event: MouseEvent): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SemVerPrompt = void 0;
|
|
4
|
+
const select_1 = require("./select");
|
|
5
|
+
class SemVerPrompt extends select_1.SelectPrompt {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
const { currentVersion, ...baseOptions } = options;
|
|
8
|
+
const validVersion = SemVerPrompt.parseVersion(currentVersion) || '0.0.1';
|
|
9
|
+
const [major, minor, patch] = validVersion.split('.').map(Number);
|
|
10
|
+
const choices = [
|
|
11
|
+
{
|
|
12
|
+
title: `Patch (${validVersion} -> ${major}.${minor}.${patch + 1})`,
|
|
13
|
+
value: `${major}.${minor}.${patch + 1}`
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
title: `Minor (${validVersion} -> ${major}.${minor + 1}.0)`,
|
|
17
|
+
value: `${major}.${minor + 1}.0`
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
title: `Major (${validVersion} -> ${major + 1}.0.0)`,
|
|
21
|
+
value: `${major + 1}.0.0`
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
super({ ...baseOptions, choices });
|
|
25
|
+
}
|
|
26
|
+
static parseVersion(version) {
|
|
27
|
+
// Simple SemVer regex: x.y.z
|
|
28
|
+
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
29
|
+
return match ? match[0] : null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.SemVerPrompt = SemVerPrompt;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { ShortcutOptions, ShortcutResult } from '../types';
|
|
3
|
+
export declare class ShortcutPrompt extends Prompt<ShortcutResult, ShortcutOptions> {
|
|
4
|
+
private currentKey?;
|
|
5
|
+
constructor(options: ShortcutOptions);
|
|
6
|
+
protected render(_firstRender: boolean): void;
|
|
7
|
+
protected handleInput(char: string, buffer: Buffer): void;
|
|
8
|
+
private parseKey;
|
|
9
|
+
}
|