mepcli 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,7 @@ class MapPrompt extends base_1.Prompt {
15
15
  this.scrollTop = 0;
16
16
  this.pageSize = 7;
17
17
  this.errorMsg = '';
18
+ this.ghost = '';
18
19
  if (options.initial) {
19
20
  this.items = Object.entries(options.initial).map(([key, value]) => ({ key, value }));
20
21
  }
@@ -29,7 +30,11 @@ class MapPrompt extends base_1.Prompt {
29
30
  output += `${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
30
31
  // Layout Calculation
31
32
  const maxKeyWidth = Math.max(5, // Minimum width
32
- ...this.items.map(item => (0, utils_1.stringWidth)(item.key))) + 2; // Padding
33
+ ...this.items.map((item, idx) => {
34
+ // Include ghost length in calculation if it's the active row
35
+ const ghostLen = (idx === this.rowIndex && this.colIndex === 0) ? (0, utils_1.stringWidth)(this.ghost) : 0;
36
+ return (0, utils_1.stringWidth)(item.key) + ghostLen;
37
+ })) + 2; // Padding
33
38
  // Scrolling Logic
34
39
  if (this.rowIndex < this.scrollTop) {
35
40
  this.scrollTop = this.rowIndex;
@@ -53,11 +58,16 @@ class MapPrompt extends base_1.Prompt {
53
58
  const pointer = isRowActive ? `${theme_1.theme.main}${symbols_1.symbols.pointer}${ansi_1.ANSI.RESET} ` : ' ';
54
59
  // Render Key
55
60
  let keyStr = item.key;
61
+ let ghostStr = '';
56
62
  if (isRowActive && this.colIndex === 0) {
57
- keyStr = `${theme_1.theme.main}${ansi_1.ANSI.UNDERLINE}${keyStr}${ansi_1.ANSI.RESET}`;
63
+ if (this.ghost) {
64
+ ghostStr = `${theme_1.theme.muted}${this.ghost}${ansi_1.ANSI.RESET}`;
65
+ }
66
+ keyStr = `${theme_1.theme.main}${ansi_1.ANSI.UNDERLINE}${keyStr}${ansi_1.ANSI.RESET}${ghostStr}`;
58
67
  }
59
- // Adjust padding manually because ANSI codes mess up simple padEnd
60
- const keyVisualWidth = (0, utils_1.stringWidth)(item.key);
68
+ // Adjust padding manually
69
+ // We need visual width of key + ghost (if active)
70
+ const keyVisualWidth = (0, utils_1.stringWidth)(item.key) + (isRowActive && this.colIndex === 0 ? (0, utils_1.stringWidth)(this.ghost) : 0);
61
71
  const padding = ' '.repeat(Math.max(0, maxKeyWidth - keyVisualWidth));
62
72
  // Render Value
63
73
  let valStr = item.value;
@@ -79,12 +89,41 @@ class MapPrompt extends base_1.Prompt {
79
89
  return str;
80
90
  return str + ' '.repeat(width - len);
81
91
  }
92
+ updateGhost() {
93
+ this.ghost = '';
94
+ if (this.colIndex !== 0 || !this.options.suggestions)
95
+ return;
96
+ const currentKey = this.items[this.rowIndex].key;
97
+ if (!currentKey)
98
+ return;
99
+ const lowerKey = currentKey.toLowerCase();
100
+ // Find first match
101
+ const match = this.options.suggestions.find(s => s.toLowerCase().startsWith(lowerKey) && s.length > currentKey.length);
102
+ if (match) {
103
+ this.ghost = match.slice(currentKey.length);
104
+ }
105
+ }
82
106
  handleInput(char) {
83
107
  this.errorMsg = '';
108
+ // Tab (Accept Suggestion) or Toggle Column
109
+ if (char === '\t') {
110
+ if (this.colIndex === 0 && this.ghost) {
111
+ this.items[this.rowIndex].key += this.ghost;
112
+ this.ghost = '';
113
+ this.render(false);
114
+ return;
115
+ }
116
+ // Standard Tab behavior (toggle column)
117
+ this.colIndex = this.colIndex === 0 ? 1 : 0;
118
+ this.ghost = ''; // Clear ghost when changing columns
119
+ this.render(false);
120
+ return;
121
+ }
84
122
  // Navigation
85
123
  if (this.isUp(char)) {
86
124
  if (this.rowIndex > 0)
87
125
  this.rowIndex--;
126
+ this.ghost = '';
88
127
  this.render(false);
89
128
  return;
90
129
  }
@@ -96,28 +135,28 @@ class MapPrompt extends base_1.Prompt {
96
135
  // Down at last row adds new row
97
136
  this.items.push({ key: '', value: '' });
98
137
  this.rowIndex++;
99
- this.colIndex = 0; // Optional: Reset to Key col when creating new row
138
+ this.colIndex = 0;
100
139
  }
140
+ this.ghost = '';
101
141
  this.render(false);
102
142
  return;
103
143
  }
104
- if (char === '\t' || this.isRight(char) || this.isLeft(char)) {
105
- // Toggle column
144
+ if (this.isRight(char) || this.isLeft(char)) {
106
145
  this.colIndex = this.colIndex === 0 ? 1 : 0;
146
+ this.ghost = '';
107
147
  this.render(false);
108
148
  return;
109
149
  }
110
150
  // CRUD
111
- // Ctrl+N (Standard ASCII for Ctrl+N is \x0e)
112
- if (char === '\x0e') {
151
+ if (char === '\x0e') { // Ctrl+N
113
152
  this.items.push({ key: '', value: '' });
114
153
  this.rowIndex = this.items.length - 1;
115
154
  this.colIndex = 0;
155
+ this.ghost = '';
116
156
  this.render(false);
117
157
  return;
118
158
  }
119
- // Ctrl+D (Standard ASCII for Ctrl+D is \x04)
120
- if (char === '\x04') {
159
+ if (char === '\x04') { // Ctrl+D
121
160
  if (this.items.length > 1) {
122
161
  this.items.splice(this.rowIndex, 1);
123
162
  if (this.rowIndex >= this.items.length) {
@@ -125,9 +164,9 @@ class MapPrompt extends base_1.Prompt {
125
164
  }
126
165
  }
127
166
  else {
128
- // Clear the last remaining item instead of deleting it
129
167
  this.items[0] = { key: '', value: '' };
130
168
  }
169
+ this.ghost = '';
131
170
  this.render(false);
132
171
  return;
133
172
  }
@@ -157,8 +196,13 @@ class MapPrompt extends base_1.Prompt {
157
196
  if (char === '\u0008' || char === '\x7f') {
158
197
  const item = this.items[this.rowIndex];
159
198
  if (this.colIndex === 0) {
160
- if (item.key.length > 0)
199
+ if (item.key.length > 0) {
161
200
  item.key = item.key.slice(0, -1);
201
+ this.updateGhost();
202
+ }
203
+ else {
204
+ this.ghost = '';
205
+ }
162
206
  }
163
207
  else {
164
208
  if (item.value.length > 0)
@@ -172,6 +216,7 @@ class MapPrompt extends base_1.Prompt {
172
216
  const item = this.items[this.rowIndex];
173
217
  if (this.colIndex === 0) {
174
218
  item.key += char;
219
+ this.updateGhost();
175
220
  }
176
221
  else {
177
222
  item.value += char;
@@ -184,12 +229,14 @@ class MapPrompt extends base_1.Prompt {
184
229
  if (event.scroll === 'up') {
185
230
  if (this.rowIndex > 0) {
186
231
  this.rowIndex--;
232
+ this.ghost = '';
187
233
  this.render(false);
188
234
  }
189
235
  }
190
236
  else if (event.scroll === 'down') {
191
237
  if (this.rowIndex < this.items.length - 1) {
192
238
  this.rowIndex++;
239
+ this.ghost = '';
193
240
  this.render(false);
194
241
  }
195
242
  }
package/dist/types.d.ts CHANGED
@@ -236,6 +236,7 @@ export interface CalendarOptions extends BaseOptions {
236
236
  }
237
237
  export interface MapOptions extends BaseOptions {
238
238
  initial?: Record<string, string>;
239
+ suggestions?: string[];
239
240
  }
240
241
  export interface SemVerOptions extends BaseOptions {
241
242
  currentVersion: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mepcli",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Zero-dependency, interactive CLI prompt",
5
5
  "repository": {
6
6
  "type": "git",