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.
Files changed (113) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +512 -326
  3. package/dist/ansi.d.ts +8 -0
  4. package/dist/ansi.js +8 -0
  5. package/dist/base.d.ts +21 -0
  6. package/dist/base.js +57 -0
  7. package/dist/core.d.ts +48 -1
  8. package/dist/core.js +156 -0
  9. package/dist/data/licenses.d.ts +2 -0
  10. package/dist/data/licenses.js +109 -0
  11. package/dist/highlight.js +58 -26
  12. package/dist/index.d.ts +36 -0
  13. package/dist/index.js +36 -0
  14. package/dist/input.js +0 -3
  15. package/dist/prompts/box.d.ts +21 -0
  16. package/dist/prompts/box.js +192 -0
  17. package/dist/prompts/breadcrumb.d.ts +22 -0
  18. package/dist/prompts/breadcrumb.js +302 -0
  19. package/dist/prompts/byte.d.ts +13 -0
  20. package/dist/prompts/byte.js +159 -0
  21. package/dist/prompts/calculator.d.ts +16 -0
  22. package/dist/prompts/calculator.js +213 -0
  23. package/dist/prompts/calendar.js +0 -5
  24. package/dist/prompts/code.d.ts +2 -0
  25. package/dist/prompts/code.js +104 -70
  26. package/dist/prompts/connection-string.d.ts +18 -0
  27. package/dist/prompts/connection-string.js +97 -0
  28. package/dist/prompts/curl.d.ts +39 -0
  29. package/dist/prompts/curl.js +285 -0
  30. package/dist/prompts/data-inspector.d.ts +22 -0
  31. package/dist/prompts/data-inspector.js +256 -0
  32. package/dist/prompts/dependency.d.ts +16 -0
  33. package/dist/prompts/dependency.js +265 -0
  34. package/dist/prompts/dial.d.ts +10 -0
  35. package/dist/prompts/dial.js +110 -0
  36. package/dist/prompts/diff.d.ts +10 -0
  37. package/dist/prompts/diff.js +101 -0
  38. package/dist/prompts/draw.d.ts +20 -0
  39. package/dist/prompts/draw.js +188 -0
  40. package/dist/prompts/editor.js +0 -4
  41. package/dist/prompts/emoji.d.ts +18 -0
  42. package/dist/prompts/emoji.js +228 -0
  43. package/dist/prompts/exec.d.ts +13 -0
  44. package/dist/prompts/exec.js +83 -0
  45. package/dist/prompts/fuzzy.d.ts +12 -0
  46. package/dist/prompts/fuzzy.js +136 -0
  47. package/dist/prompts/gauge.d.ts +21 -0
  48. package/dist/prompts/gauge.js +130 -0
  49. package/dist/prompts/heatmap.d.ts +13 -0
  50. package/dist/prompts/heatmap.js +141 -0
  51. package/dist/prompts/ip.d.ts +11 -0
  52. package/dist/prompts/ip.js +118 -0
  53. package/dist/prompts/kanban.d.ts +17 -0
  54. package/dist/prompts/kanban.js +228 -0
  55. package/dist/prompts/keypress.js +0 -2
  56. package/dist/prompts/license.d.ts +9 -0
  57. package/dist/prompts/license.js +105 -0
  58. package/dist/prompts/map.d.ts +15 -0
  59. package/dist/prompts/map.js +199 -0
  60. package/dist/prompts/match.d.ts +19 -0
  61. package/dist/prompts/match.js +275 -0
  62. package/dist/prompts/miller.d.ts +15 -0
  63. package/dist/prompts/miller.js +221 -0
  64. package/dist/prompts/multi-column-select.d.ts +10 -0
  65. package/dist/prompts/multi-column-select.js +166 -0
  66. package/dist/prompts/number.js +0 -2
  67. package/dist/prompts/otp.d.ts +10 -0
  68. package/dist/prompts/otp.js +91 -0
  69. package/dist/prompts/pattern.d.ts +22 -0
  70. package/dist/prompts/pattern.js +249 -0
  71. package/dist/prompts/quiz-select.d.ts +10 -0
  72. package/dist/prompts/quiz-select.js +104 -0
  73. package/dist/prompts/quiz-text.d.ts +11 -0
  74. package/dist/prompts/quiz-text.js +82 -0
  75. package/dist/prompts/regex.d.ts +13 -0
  76. package/dist/prompts/regex.js +131 -0
  77. package/dist/prompts/region.d.ts +11 -0
  78. package/dist/prompts/region.js +164 -0
  79. package/dist/prompts/schedule.d.ts +18 -0
  80. package/dist/prompts/schedule.js +221 -0
  81. package/dist/prompts/scroll.d.ts +13 -0
  82. package/dist/prompts/scroll.js +152 -0
  83. package/dist/prompts/seat.d.ts +17 -0
  84. package/dist/prompts/seat.js +165 -0
  85. package/dist/prompts/select-range.d.ts +8 -0
  86. package/dist/prompts/select-range.js +136 -0
  87. package/dist/prompts/select.d.ts +9 -9
  88. package/dist/prompts/semver.d.ts +6 -0
  89. package/dist/prompts/semver.js +32 -0
  90. package/dist/prompts/shortcut.d.ts +9 -0
  91. package/dist/prompts/shortcut.js +135 -0
  92. package/dist/prompts/slot.d.ts +16 -0
  93. package/dist/prompts/slot.js +107 -0
  94. package/dist/prompts/snippet.js +0 -3
  95. package/dist/prompts/sort-grid.d.ts +16 -0
  96. package/dist/prompts/sort-grid.js +146 -0
  97. package/dist/prompts/sort.js +0 -1
  98. package/dist/prompts/spreadsheet.d.ts +21 -0
  99. package/dist/prompts/spreadsheet.js +239 -0
  100. package/dist/prompts/text.d.ts +9 -7
  101. package/dist/prompts/text.js +52 -0
  102. package/dist/prompts/time.d.ts +12 -0
  103. package/dist/prompts/time.js +202 -0
  104. package/dist/prompts/tree-select.d.ts +0 -1
  105. package/dist/prompts/tree-select.js +1 -5
  106. package/dist/symbols.d.ts +12 -0
  107. package/dist/symbols.js +14 -2
  108. package/dist/theme.js +10 -1
  109. package/dist/types.d.ts +264 -1
  110. package/dist/utils.d.ts +53 -0
  111. package/dist/utils.js +252 -0
  112. package/package.json +51 -47
  113. package/example.ts +0 -390
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DiffPrompt = void 0;
4
+ const base_1 = require("../base");
5
+ const theme_1 = require("../theme");
6
+ const ansi_1 = require("../ansi");
7
+ const editor_1 = require("./editor");
8
+ class DiffPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.activeAction = 0; // 0: Original, 1: Modified, 2: Edit
12
+ this.actions = ['Use Original', 'Use Modified', 'Edit'];
13
+ }
14
+ render(_firstRender) {
15
+ let output = `${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
16
+ // Render Diff
17
+ const originalLines = this.options.original ? this.options.original.split('\n') : [];
18
+ const modifiedLines = this.options.modified ? this.options.modified.split('\n') : [];
19
+ const width = Math.max(40, (this.stdout.columns || 80) - 4);
20
+ const borderTop = `${ansi_1.ANSI.FG_GRAY}┌${'─'.repeat(width)}┐${ansi_1.ANSI.RESET}`;
21
+ const borderMid = `${ansi_1.ANSI.FG_GRAY}├${'─'.repeat(width)}┤${ansi_1.ANSI.RESET}`;
22
+ const borderBot = `${ansi_1.ANSI.FG_GRAY}└${'─'.repeat(width)}┘${ansi_1.ANSI.RESET}`;
23
+ output += borderTop + '\n';
24
+ // Original (Red)
25
+ if (originalLines.length === 0) {
26
+ output += `${ansi_1.ANSI.FG_GRAY}│ ${ansi_1.ANSI.DIM}(empty)${ansi_1.ANSI.RESET}\n`;
27
+ }
28
+ else {
29
+ originalLines.forEach(line => {
30
+ const truncated = this.truncate(line, width - 4);
31
+ output += `${ansi_1.ANSI.FG_GRAY}│ ${ansi_1.ANSI.FG_RED}- ${truncated}${ansi_1.ANSI.RESET}\n`;
32
+ });
33
+ }
34
+ output += borderMid + '\n';
35
+ // Modified (Green)
36
+ if (modifiedLines.length === 0) {
37
+ output += `${ansi_1.ANSI.FG_GRAY}│ ${ansi_1.ANSI.DIM}(empty)${ansi_1.ANSI.RESET}\n`;
38
+ }
39
+ else {
40
+ modifiedLines.forEach(line => {
41
+ const truncated = this.truncate(line, width - 4);
42
+ output += `${ansi_1.ANSI.FG_GRAY}│ ${ansi_1.ANSI.FG_GREEN}+ ${truncated}${ansi_1.ANSI.RESET}\n`;
43
+ });
44
+ }
45
+ output += borderBot + '\n';
46
+ // Render Actions
47
+ output += '\n';
48
+ this.actions.forEach((action, index) => {
49
+ if (index === this.activeAction) {
50
+ output += `${ansi_1.ANSI.REVERSE} ${action} ${ansi_1.ANSI.RESET} `;
51
+ }
52
+ else {
53
+ output += `[ ${action} ] `;
54
+ }
55
+ });
56
+ this.renderFrame(output);
57
+ }
58
+ handleInput(char, _key) {
59
+ if (this.isLeft(char)) {
60
+ this.activeAction = (this.activeAction - 1 + this.actions.length) % this.actions.length;
61
+ this.render(false);
62
+ }
63
+ else if (this.isRight(char)) {
64
+ this.activeAction = (this.activeAction + 1) % this.actions.length;
65
+ this.render(false);
66
+ }
67
+ else if (char === '\r' || char === '\n') {
68
+ this.handleSubmit();
69
+ }
70
+ }
71
+ handleSubmit() {
72
+ if (this.activeAction === 0) {
73
+ this.submit(this.options.original);
74
+ }
75
+ else if (this.activeAction === 1) {
76
+ this.submit(this.options.modified);
77
+ }
78
+ else {
79
+ // Edit
80
+ this.cleanup(); // Stop listening to input for this prompt
81
+ // Prepare initial content for editor
82
+ const initial = `<<<<<<< ORIGINAL
83
+ ${this.options.original}
84
+ =======
85
+ ${this.options.modified}
86
+ >>>>>>> MODIFIED`;
87
+ // We delegate to EditorPrompt
88
+ new editor_1.EditorPrompt({
89
+ message: 'Resolve conflict (Edit)',
90
+ initial: initial,
91
+ extension: '.txt',
92
+ waitUserInput: false // Launch immediately
93
+ }).run().then(result => {
94
+ this.submit(result);
95
+ }).catch(_err => {
96
+ this.submit(initial);
97
+ });
98
+ }
99
+ }
100
+ }
101
+ exports.DiffPrompt = DiffPrompt;
@@ -0,0 +1,20 @@
1
+ import { Prompt } from '../base';
2
+ import { DrawOptions, MouseEvent } from '../types';
3
+ export declare class DrawPrompt extends Prompt<string | boolean[][], DrawOptions> {
4
+ private grid;
5
+ private cursorX;
6
+ private cursorY;
7
+ private gridWidth;
8
+ private gridHeight;
9
+ private lastMouse;
10
+ constructor(options: DrawOptions);
11
+ private getBrailleChar;
12
+ private getPixel;
13
+ private setPixel;
14
+ protected render(_firstRender: boolean): void;
15
+ protected handleInput(char: string, _key: Buffer): void;
16
+ protected handleMouse(event: MouseEvent): void;
17
+ private clearGrid;
18
+ private invertGrid;
19
+ private handleSubmit;
20
+ }
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DrawPrompt = void 0;
4
+ const base_1 = require("../base");
5
+ const theme_1 = require("../theme");
6
+ const ansi_1 = require("../ansi");
7
+ class DrawPrompt extends base_1.Prompt {
8
+ constructor(options) {
9
+ super(options);
10
+ this.cursorX = 0;
11
+ this.cursorY = 0;
12
+ this.lastMouse = null;
13
+ this.gridWidth = options.width * 2;
14
+ this.gridHeight = options.height * 4;
15
+ if (options.initial) {
16
+ // Deep copy to avoid mutating original if passed
17
+ this.grid = options.initial.map(row => [...row]);
18
+ }
19
+ else {
20
+ this.grid = [];
21
+ for (let y = 0; y < this.gridHeight; y++) {
22
+ const row = new Array(this.gridWidth).fill(false);
23
+ this.grid.push(row);
24
+ }
25
+ }
26
+ }
27
+ getBrailleChar(x, y) {
28
+ const baseX = x * 2;
29
+ const baseY = y * 4;
30
+ let code = 0x2800; // Base Braille
31
+ // Column 0
32
+ if (this.getPixel(baseX, baseY))
33
+ code |= 0x1; // Dot 1
34
+ if (this.getPixel(baseX, baseY + 1))
35
+ code |= 0x2; // Dot 2
36
+ if (this.getPixel(baseX, baseY + 2))
37
+ code |= 0x4; // Dot 3
38
+ if (this.getPixel(baseX, baseY + 3))
39
+ code |= 0x40; // Dot 7 (Bottom-left)
40
+ // Column 1
41
+ if (this.getPixel(baseX + 1, baseY))
42
+ code |= 0x8; // Dot 4
43
+ if (this.getPixel(baseX + 1, baseY + 1))
44
+ code |= 0x10; // Dot 5
45
+ if (this.getPixel(baseX + 1, baseY + 2))
46
+ code |= 0x20; // Dot 6
47
+ if (this.getPixel(baseX + 1, baseY + 3))
48
+ code |= 0x80; // Dot 8 (Bottom-right)
49
+ return String.fromCharCode(code);
50
+ }
51
+ getPixel(x, y) {
52
+ if (y >= 0 && y < this.gridHeight && x >= 0 && x < this.gridWidth) {
53
+ return this.grid[y][x];
54
+ }
55
+ return false;
56
+ }
57
+ setPixel(x, y, val) {
58
+ if (y >= 0 && y < this.gridHeight && x >= 0 && x < this.gridWidth) {
59
+ this.grid[y][x] = val;
60
+ }
61
+ }
62
+ render(_firstRender) {
63
+ let output = `${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
64
+ output += `${ansi_1.ANSI.FG_GRAY}┌${'─'.repeat(this.options.width + 2)}┐${ansi_1.ANSI.RESET}\n`;
65
+ for (let y = 0; y < this.options.height; y++) {
66
+ let line = '';
67
+ for (let x = 0; x < this.options.width; x++) {
68
+ const char = this.getBrailleChar(x, y);
69
+ // Highlight cursor position (pixel level approximation)
70
+ // If cursor is within this character block
71
+ const containsCursor = Math.floor(this.cursorX / 2) === x &&
72
+ Math.floor(this.cursorY / 4) === y;
73
+ if (containsCursor) {
74
+ line += ansi_1.ANSI.REVERSE + char + ansi_1.ANSI.RESET;
75
+ }
76
+ else {
77
+ line += char;
78
+ }
79
+ }
80
+ output += `${ansi_1.ANSI.FG_GRAY}│ ${ansi_1.ANSI.RESET}${line} ${ansi_1.ANSI.FG_GRAY}│${ansi_1.ANSI.RESET}\n`;
81
+ }
82
+ output += `${ansi_1.ANSI.FG_GRAY}└${'─'.repeat(this.options.width + 2)}┘${ansi_1.ANSI.RESET}\n`;
83
+ output += `\n${ansi_1.ANSI.FG_GRAY}(Arrows: move, Space: toggle, Mouse: drag, 'c': clear, 'i': invert, Enter: done)${ansi_1.ANSI.RESET}`;
84
+ this.renderFrame(output);
85
+ }
86
+ handleInput(char, _key) {
87
+ if (this.isLeft(char)) {
88
+ this.cursorX = Math.max(0, this.cursorX - 1);
89
+ this.render(false);
90
+ }
91
+ else if (this.isRight(char)) {
92
+ this.cursorX = Math.min(this.gridWidth - 1, this.cursorX + 1);
93
+ this.render(false);
94
+ }
95
+ else if (this.isUp(char)) {
96
+ this.cursorY = Math.max(0, this.cursorY - 1);
97
+ this.render(false);
98
+ }
99
+ else if (this.isDown(char)) {
100
+ this.cursorY = Math.min(this.gridHeight - 1, this.cursorY + 1);
101
+ this.render(false);
102
+ }
103
+ else if (char === ' ') {
104
+ const current = this.getPixel(this.cursorX, this.cursorY);
105
+ this.setPixel(this.cursorX, this.cursorY, !current);
106
+ this.render(false);
107
+ }
108
+ else if (char === 'c') {
109
+ this.clearGrid();
110
+ this.render(false);
111
+ }
112
+ else if (char === 'i') {
113
+ this.invertGrid();
114
+ this.render(false);
115
+ }
116
+ else if (char === '\r' || char === '\n') {
117
+ this.handleSubmit();
118
+ }
119
+ }
120
+ handleMouse(event) {
121
+ if (event.action === 'release') {
122
+ this.lastMouse = null;
123
+ return;
124
+ }
125
+ if (this.lastMouse) {
126
+ const dx = event.x - this.lastMouse.x;
127
+ const dy = event.y - this.lastMouse.y;
128
+ // Relative movement: scale to grid density
129
+ // X: 1 char = 2 pixels
130
+ // Y: 1 char = 4 pixels
131
+ if (dx !== 0 || dy !== 0) {
132
+ this.cursorX += dx * 2;
133
+ this.cursorY += dy * 4;
134
+ // Clamp
135
+ this.cursorX = Math.max(0, Math.min(this.gridWidth - 1, this.cursorX));
136
+ this.cursorY = Math.max(0, Math.min(this.gridHeight - 1, this.cursorY));
137
+ // Draw if pressing (Left Button = 0)
138
+ if (event.action === 'press' || (event.action === 'move' && event.button === 0)) {
139
+ this.setPixel(this.cursorX, this.cursorY, true);
140
+ }
141
+ // Eraser (Right Button = 2)
142
+ if ((event.action === 'press' || event.action === 'move') && event.button === 2) {
143
+ this.setPixel(this.cursorX, this.cursorY, false);
144
+ }
145
+ this.render(false);
146
+ }
147
+ }
148
+ else {
149
+ if (event.action === 'press' && event.button === 0) {
150
+ this.setPixel(this.cursorX, this.cursorY, true);
151
+ this.render(false);
152
+ }
153
+ }
154
+ this.lastMouse = { x: event.x, y: event.y };
155
+ }
156
+ clearGrid() {
157
+ for (let y = 0; y < this.gridHeight; y++) {
158
+ for (let x = 0; x < this.gridWidth; x++) {
159
+ this.grid[y][x] = false;
160
+ }
161
+ }
162
+ }
163
+ invertGrid() {
164
+ for (let y = 0; y < this.gridHeight; y++) {
165
+ for (let x = 0; x < this.gridWidth; x++) {
166
+ this.grid[y][x] = !this.grid[y][x];
167
+ }
168
+ }
169
+ }
170
+ handleSubmit() {
171
+ if (this.options.exportType === 'text') {
172
+ // Render to string
173
+ let result = '';
174
+ for (let y = 0; y < this.options.height; y++) {
175
+ for (let x = 0; x < this.options.width; x++) {
176
+ result += this.getBrailleChar(x, y);
177
+ }
178
+ result += '\n';
179
+ }
180
+ this.submit(result.trim());
181
+ }
182
+ else {
183
+ // Default: return matrix
184
+ this.submit(this.grid);
185
+ }
186
+ }
187
+ }
188
+ exports.DrawPrompt = DrawPrompt;
@@ -180,10 +180,6 @@ class EditorPrompt extends base_1.Prompt {
180
180
  }
181
181
  // Success
182
182
  this.status = 'done';
183
- // Trim trailing newline which editors often add
184
- // We only trim the *last* newline added by the editor if it wasn't there?
185
- // Usually editors ensure a final newline.
186
- // If the user entered "abc", vim saves "abc\n". We probably want "abc".
187
183
  if (content.endsWith('\n')) {
188
184
  content = content.slice(0, -1);
189
185
  }
@@ -0,0 +1,18 @@
1
+ import { Prompt } from '../base';
2
+ import { EmojiOptions, MouseEvent } from '../types';
3
+ export declare class EmojiPrompt extends Prompt<string, EmojiOptions> {
4
+ private search;
5
+ private cursor;
6
+ private filtered;
7
+ private sortedEmojis;
8
+ private cols;
9
+ private scrollTop;
10
+ private pageSize;
11
+ constructor(options: EmojiOptions);
12
+ private calculateLayout;
13
+ private updateFilter;
14
+ protected render(_firstRender: boolean): void;
15
+ protected handleInput(char: string): void;
16
+ protected handleMouse(event: MouseEvent): void;
17
+ private adjustScroll;
18
+ }
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EmojiPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ const utils_1 = require("../utils");
8
+ class EmojiPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.search = '';
12
+ this.cursor = 0; // Index in the filtered list
13
+ this.filtered = [];
14
+ this.sortedEmojis = [];
15
+ this.cols = 0;
16
+ this.scrollTop = 0;
17
+ this.pageSize = 8; // Number of rows to display
18
+ // Sort emojis by recent
19
+ this.sortedEmojis = [...options.emojis];
20
+ if (options.recent && options.recent.length > 0) {
21
+ const recentSet = new Set(options.recent);
22
+ this.sortedEmojis.sort((a, b) => {
23
+ const aRecent = recentSet.has(a.name);
24
+ const bRecent = recentSet.has(b.name);
25
+ if (aRecent && !bRecent)
26
+ return -1;
27
+ if (!aRecent && bRecent)
28
+ return 1;
29
+ return 0;
30
+ });
31
+ }
32
+ this.checkWindowsAttention();
33
+ // Initial filter
34
+ this.filtered = this.sortedEmojis;
35
+ // Calculate layout
36
+ this.calculateLayout();
37
+ }
38
+ calculateLayout() {
39
+ if (this.options.cols) {
40
+ this.cols = this.options.cols;
41
+ }
42
+ else {
43
+ // Auto-detect based on terminal width
44
+ // Assume each emoji cell takes ~4 chars (2 char emoji + 2 padding)
45
+ const termWidth = process.stdout.columns || 80;
46
+ this.cols = Math.floor((termWidth - 4) / 4); // -4 for margin
47
+ if (this.cols < 1)
48
+ this.cols = 1;
49
+ }
50
+ }
51
+ updateFilter() {
52
+ if (!this.search) {
53
+ this.filtered = this.sortedEmojis;
54
+ }
55
+ else {
56
+ const lowerSearch = this.search.toLowerCase();
57
+ this.filtered = this.sortedEmojis.filter(e => e.name.toLowerCase().includes(lowerSearch) ||
58
+ (e.description && e.description.toLowerCase().includes(lowerSearch)) ||
59
+ e.char === this.search // Allow searching by exact char
60
+ );
61
+ }
62
+ this.cursor = 0;
63
+ this.scrollTop = 0;
64
+ }
65
+ render(_firstRender) {
66
+ // Prepare header (Search bar)
67
+ const icon = `${theme_1.theme.success}?`;
68
+ const title = `${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}`;
69
+ const searchDisplay = this.search ? `${theme_1.theme.main}${this.search}${ansi_1.ANSI.RESET}` : `${theme_1.theme.muted}Type to search...${ansi_1.ANSI.RESET}`;
70
+ let output = `${icon} ${title} ${searchDisplay}\n`;
71
+ // Render Grid
72
+ if (this.filtered.length === 0) {
73
+ output += `\n${theme_1.theme.error}No results found.${ansi_1.ANSI.RESET}\n`;
74
+ }
75
+ else {
76
+ const totalRows = Math.ceil(this.filtered.length / this.cols);
77
+ const startRow = this.scrollTop;
78
+ const endRow = Math.min(totalRows, startRow + this.pageSize);
79
+ for (let r = startRow; r < endRow; r++) {
80
+ let rowStr = ' '; // Left margin
81
+ for (let c = 0; c < this.cols; c++) {
82
+ const idx = r * this.cols + c;
83
+ if (idx >= this.filtered.length)
84
+ break;
85
+ const item = this.filtered[idx];
86
+ const isSelected = idx === this.cursor;
87
+ // Render Emoji
88
+ // Align center in 4 chars
89
+ // Emoji width is typically 2.
90
+ const emoji = item.char;
91
+ const width = (0, utils_1.stringWidth)(emoji);
92
+ const padding = 4 - width;
93
+ const leftPad = Math.floor(padding / 2);
94
+ const rightPad = padding - leftPad;
95
+ let cell = `${' '.repeat(leftPad)}${emoji}${' '.repeat(rightPad)}`;
96
+ if (isSelected) {
97
+ cell = `${ansi_1.ANSI.REVERSE}${cell}${ansi_1.ANSI.RESET}`;
98
+ }
99
+ rowStr += cell;
100
+ }
101
+ output += rowStr + '\n';
102
+ }
103
+ // Footer (Preview of selected)
104
+ if (this.filtered.length > 0) {
105
+ const selectedItem = this.filtered[this.cursor];
106
+ output += `\n${ansi_1.ANSI.BOLD}${selectedItem.char} ${selectedItem.name}${ansi_1.ANSI.RESET}`;
107
+ if (selectedItem.description) {
108
+ output += ` - ${theme_1.theme.muted}${selectedItem.description}${ansi_1.ANSI.RESET}`;
109
+ }
110
+ }
111
+ else {
112
+ output += '\n'; // Spacer
113
+ }
114
+ }
115
+ // Navigation hints
116
+ // output += `\n${theme.muted}Arrows to navigate, Enter to select${ANSI.RESET}`;
117
+ this.renderFrame(output);
118
+ }
119
+ handleInput(char) {
120
+ // Navigation
121
+ if (this.isUp(char)) {
122
+ if (this.filtered.length === 0)
123
+ return;
124
+ const newCursor = this.cursor - this.cols;
125
+ if (newCursor >= 0) {
126
+ this.cursor = newCursor;
127
+ }
128
+ this.adjustScroll();
129
+ this.render(false);
130
+ return;
131
+ }
132
+ if (this.isDown(char)) {
133
+ if (this.filtered.length === 0)
134
+ return;
135
+ const newCursor = this.cursor + this.cols;
136
+ if (newCursor < this.filtered.length) {
137
+ this.cursor = newCursor;
138
+ }
139
+ this.adjustScroll();
140
+ this.render(false);
141
+ return;
142
+ }
143
+ if (this.isLeft(char)) {
144
+ if (this.filtered.length === 0)
145
+ return;
146
+ if (this.cursor > 0) {
147
+ this.cursor--;
148
+ }
149
+ else {
150
+ // Wrap to end?
151
+ this.cursor = this.filtered.length - 1;
152
+ }
153
+ this.adjustScroll();
154
+ this.render(false);
155
+ return;
156
+ }
157
+ if (this.isRight(char)) {
158
+ if (this.filtered.length === 0)
159
+ return;
160
+ if (this.cursor < this.filtered.length - 1) {
161
+ this.cursor++;
162
+ }
163
+ else {
164
+ // Wrap to start?
165
+ this.cursor = 0;
166
+ }
167
+ this.adjustScroll();
168
+ this.render(false);
169
+ return;
170
+ }
171
+ // Enter
172
+ if (char === '\r' || char === '\n') {
173
+ if (this.filtered.length > 0) {
174
+ this.submit(this.filtered[this.cursor].char);
175
+ }
176
+ return;
177
+ }
178
+ // Backspace
179
+ if (char === '\u0008' || char === '\x7f') {
180
+ if (this.search.length > 0) {
181
+ this.search = this.search.slice(0, -1);
182
+ this.updateFilter();
183
+ this.render(false);
184
+ }
185
+ return;
186
+ }
187
+ // Typing
188
+ if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
189
+ this.search += char;
190
+ this.updateFilter();
191
+ this.render(false);
192
+ }
193
+ }
194
+ handleMouse(event) {
195
+ if (event.action === 'scroll' && this.filtered.length > 0) {
196
+ if (event.scroll === 'up') {
197
+ // Left / Previous
198
+ if (this.cursor > 0) {
199
+ this.cursor--;
200
+ }
201
+ else {
202
+ this.cursor = this.filtered.length - 1;
203
+ }
204
+ }
205
+ else {
206
+ // Right / Next
207
+ if (this.cursor < this.filtered.length - 1) {
208
+ this.cursor++;
209
+ }
210
+ else {
211
+ this.cursor = 0;
212
+ }
213
+ }
214
+ this.adjustScroll();
215
+ this.render(false);
216
+ }
217
+ }
218
+ adjustScroll() {
219
+ const cursorRow = Math.floor(this.cursor / this.cols);
220
+ if (cursorRow < this.scrollTop) {
221
+ this.scrollTop = cursorRow;
222
+ }
223
+ else if (cursorRow >= this.scrollTop + this.pageSize) {
224
+ this.scrollTop = cursorRow - this.pageSize + 1;
225
+ }
226
+ }
227
+ }
228
+ exports.EmojiPrompt = EmojiPrompt;
@@ -0,0 +1,13 @@
1
+ import { Prompt } from '../base';
2
+ import { ExecOptions } from '../types';
3
+ export declare class ExecPrompt extends Prompt<void, ExecOptions> {
4
+ private child?;
5
+ private status;
6
+ private timer?;
7
+ constructor(options: ExecOptions);
8
+ run(): Promise<void>;
9
+ private killChild;
10
+ protected cleanup(): void;
11
+ protected render(_firstRender: boolean): void;
12
+ protected handleInput(_char: string, _key: Buffer): void;
13
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExecPrompt = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ const symbols_1 = require("../symbols");
8
+ const ansi_1 = require("../ansi");
9
+ class ExecPrompt extends base_1.Prompt {
10
+ constructor(options) {
11
+ super(options);
12
+ this.status = 'running';
13
+ this.warnExperimental();
14
+ }
15
+ run() {
16
+ this.child = (0, child_process_1.spawn)(this.options.command, [], {
17
+ cwd: this.options.cwd || process.cwd(),
18
+ shell: true,
19
+ stdio: this.options.streamOutput ? 'inherit' : 'ignore'
20
+ });
21
+ if (this.options.timeout && this.options.timeout > 0) {
22
+ this.timer = setTimeout(() => {
23
+ if (this.status !== 'running')
24
+ return;
25
+ this.status = 'error';
26
+ this.render(false);
27
+ this.cancel(new Error(`Timeout after ${this.options.timeout}ms`));
28
+ }, this.options.timeout);
29
+ }
30
+ this.child.on('exit', (code) => {
31
+ if (this.status !== 'running')
32
+ return;
33
+ if (code === 0) {
34
+ this.status = 'done';
35
+ this.render(false);
36
+ this.submit();
37
+ }
38
+ else {
39
+ this.status = 'error';
40
+ this.render(false);
41
+ this.cancel(new Error(`Command failed with exit code ${code}`));
42
+ }
43
+ });
44
+ this.child.on('error', (err) => {
45
+ if (this.status !== 'running')
46
+ return;
47
+ this.status = 'error';
48
+ this.render(false);
49
+ this.cancel(err);
50
+ });
51
+ return super.run();
52
+ }
53
+ killChild() {
54
+ if (this.child && !this.child.killed) {
55
+ this.child.kill();
56
+ }
57
+ }
58
+ cleanup() {
59
+ this.status = 'done';
60
+ if (this.timer)
61
+ clearTimeout(this.timer);
62
+ this.killChild();
63
+ super.cleanup();
64
+ }
65
+ render(_firstRender) {
66
+ let symbol = '';
67
+ if (this.status === 'running') {
68
+ symbol = theme_1.theme.muted + '...' + ansi_1.ANSI.RESET;
69
+ }
70
+ else if (this.status === 'done') {
71
+ symbol = theme_1.theme.success + symbols_1.symbols.tick + ansi_1.ANSI.RESET;
72
+ }
73
+ else if (this.status === 'error') {
74
+ symbol = theme_1.theme.error + symbols_1.symbols.cross + ansi_1.ANSI.RESET;
75
+ }
76
+ const output = `${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${symbol}`;
77
+ this.renderFrame(output);
78
+ }
79
+ handleInput(_char, _key) {
80
+ // Ignore input
81
+ }
82
+ }
83
+ exports.ExecPrompt = ExecPrompt;
@@ -0,0 +1,12 @@
1
+ import { SelectPrompt } from './select';
2
+ import { FuzzySelectOptions } from '../types';
3
+ export declare class FuzzySelectPrompt<V> extends SelectPrompt<V, FuzzySelectOptions<V>> {
4
+ private filteredResults;
5
+ private debounceTimer;
6
+ constructor(options: FuzzySelectOptions<V>);
7
+ protected getFilteredChoices(): any[];
8
+ protected handleInput(char: string): void;
9
+ private performSearch;
10
+ private highlight;
11
+ protected render(_firstRender: boolean): void;
12
+ }