minercon 3.0.3 → 3.0.4

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.
@@ -1,286 +0,0 @@
1
- "use strict";
2
- // src/suggestionDisplay.ts
3
- //
4
- // Owns the suggestion-list / argument-hint display: the items, the selected
5
- // index, paging state, and the ANSI rendering/clearing of whatever's drawn
6
- // below the prompt. Pulled out of RconTerminal as part of the mega-module
7
- // split — see lineEditor.ts for the sibling extraction and its rationale.
8
- //
9
- // This class has no notion of the completionEngine or of dispatching events —
10
- // RconSession remains the single place that talks to the engine (it's the
11
- // one piece deliberately kept pure/central). Callers that need to know
12
- // *whether* an action makes sense (page forward/back) ask the read-only
13
- // `...Index()` queries, which return `number | null` — `null` meaning
14
- // "nothing to do" — and decide for themselves whether to dispatch.
15
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- var desc = Object.getOwnPropertyDescriptor(m, k);
18
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
- desc = { enumerable: true, get: function() { return m[k]; } };
20
- }
21
- Object.defineProperty(o, k2, desc);
22
- }) : (function(o, m, k, k2) {
23
- if (k2 === undefined) k2 = k;
24
- o[k2] = m[k];
25
- }));
26
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
- Object.defineProperty(o, "default", { enumerable: true, value: v });
28
- }) : function(o, v) {
29
- o["default"] = v;
30
- });
31
- var __importStar = (this && this.__importStar) || (function () {
32
- var ownKeys = function(o) {
33
- ownKeys = Object.getOwnPropertyNames || function (o) {
34
- var ar = [];
35
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
- return ar;
37
- };
38
- return ownKeys(o);
39
- };
40
- return function (mod) {
41
- if (mod && mod.__esModule) return mod;
42
- var result = {};
43
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
- __setModuleDefault(result, mod);
45
- return result;
46
- };
47
- })();
48
- Object.defineProperty(exports, "__esModule", { value: true });
49
- exports.SuggestionDisplay = void 0;
50
- const argumentHint_1 = require("./argumentHint");
51
- const ansi = __importStar(require("./ansi"));
52
- class SuggestionDisplay {
53
- host;
54
- currentSuggestions = [];
55
- suggestionIndex = -1;
56
- showing = false;
57
- displayLines = 0;
58
- // Paging
59
- visibleStart = 0;
60
- maxVisible = 10;
61
- currentPage = 1;
62
- needsClearOnNextRender = false;
63
- constructor(host) {
64
- this.host = host;
65
- }
66
- get isShowing() {
67
- return this.showing;
68
- }
69
- get itemCount() {
70
- return this.currentSuggestions.length;
71
- }
72
- get totalPages() {
73
- return Math.ceil(this.currentSuggestions.length / this.maxVisible);
74
- }
75
- /** Replaces the direct `needsClearBeforeSuggestions = true` assignment from `executeCommand` — the next render should wipe the screen below the cursor first (e.g. after a multi-line command response may have pushed the display area around). */
76
- markNeedsClearOnNextRender() {
77
- this.needsClearOnNextRender = true;
78
- }
79
- nextPageIndex() {
80
- if (!this.showing || this.currentSuggestions.length === 0 || this.totalPages <= 1) {
81
- return null;
82
- }
83
- const nextPageStart = this.currentPage * this.maxVisible;
84
- return nextPageStart < this.currentSuggestions.length ? nextPageStart : 0;
85
- }
86
- previousPageIndex() {
87
- if (!this.showing || this.currentSuggestions.length === 0 || this.totalPages <= 1) {
88
- return null;
89
- }
90
- return this.currentPage > 1
91
- ? (this.currentPage - 2) * this.maxVisible
92
- : (this.totalPages - 1) * this.maxVisible;
93
- }
94
- /**
95
- * Sets the displayed items/selection from the engine's `render` effect and
96
- * draws the appropriate combination of suggestion list and argument hint —
97
- * `usage` is only ever a single, resolved usage line (the engine collapses
98
- * "(too broad...)" failures and ambiguous-prefix multi-candidate responses
99
- * down to empty), so a non-null `display` here means the command portion is
100
- * fully resolved — independent of how many argument-level completions
101
- * remain, so it's shown alongside the list whenever available.
102
- */
103
- render(items, selectedIndex, usage, currentLine) {
104
- this.currentSuggestions = items;
105
- this.suggestionIndex = selectedIndex;
106
- this.clear();
107
- const display = usage ? (0, argumentHint_1.formatArgumentHint)(usage, currentLine) : null;
108
- let lines = [];
109
- if (items.length > 0) {
110
- this.showing = true;
111
- lines = this.buildSuggestionListLines(currentLine);
112
- if (display) {
113
- lines = lines.concat(this.buildArgumentHintLines(display));
114
- }
115
- }
116
- else {
117
- this.showing = false;
118
- if (display) {
119
- lines = this.buildArgumentHintLines(display);
120
- }
121
- }
122
- this.renderSuggestionArea(lines);
123
- }
124
- hide() {
125
- this.clear();
126
- this.showing = false;
127
- this.suggestionIndex = -1;
128
- this.currentSuggestions = [];
129
- this.visibleStart = 0;
130
- this.currentPage = 1;
131
- }
132
- /** Erases whatever's currently drawn in the display area — the single source of truth for "clear the old frame before drawing (or removing) the new one." */
133
- clear() {
134
- if (this.displayLines === 0) {
135
- return;
136
- }
137
- this.host.write('\r\n'); // Move to the display area
138
- for (let i = 0; i < this.displayLines; i++) {
139
- this.host.write('\x1b[2K'); // Clear entire line
140
- if (i < this.displayLines - 1) {
141
- this.host.write('\r\n');
142
- }
143
- }
144
- // Scroll-safe return: relative cursor-up is correct even when the \r\n
145
- // above caused the terminal to scroll (absolute \x1b7/\x1b8 are not).
146
- this.host.write(`\x1b[${this.displayLines}A`);
147
- this.host.write('\r');
148
- const col = this.host.cursorColumn();
149
- if (col > 0) {
150
- this.host.write(`\x1b[${col}C`);
151
- }
152
- this.displayLines = 0;
153
- }
154
- /**
155
- * Builds the suggestion list's content lines — fully ANSI-styled, but with
156
- * no `\x1b[2K`/`\r\n` baked in. `renderSuggestionArea` is the single place
157
- * that turns a list of content strings into clear-and-draw ANSI, whether
158
- * it's drawing the list alone, the hint alone, or (when there's exactly one
159
- * suggestion left) both stacked together in one frame.
160
- */
161
- buildSuggestionListLines(currentLine) {
162
- // Calculate the visible window based on the selected index
163
- this.updateVisibleWindow();
164
- const lines = [];
165
- // Get only the completed parts of the command (everything before the last space or the whole line if no space)
166
- let completedText = '';
167
- if (currentLine.includes(' ')) {
168
- // If there's a space, get everything up to and including the last space
169
- const lastSpaceIndex = currentLine.lastIndexOf(' ');
170
- completedText = currentLine.substring(0, lastSpaceIndex + 1);
171
- }
172
- const prefix = completedText ? ansi.hidden(completedText) : '';
173
- // Show indicator if there are items above the visible window
174
- if (this.visibleStart > 0) {
175
- lines.push(prefix + ansi.gray(' ▲ (' + this.visibleStart + ' more above)'));
176
- }
177
- // Show visible suggestions in vertical list
178
- const visibleEnd = Math.min(this.visibleStart + this.maxVisible, this.currentSuggestions.length);
179
- for (let i = this.visibleStart; i < visibleEnd; i++) {
180
- // Show selection indicator and item
181
- if (i === this.suggestionIndex) {
182
- // Yellow for selected item with arrow indicator
183
- lines.push(prefix + ansi.brightYellow('→ ' + this.currentSuggestions[i]));
184
- }
185
- else {
186
- // Gray for other items with space for alignment
187
- lines.push(prefix + ansi.gray(' ' + this.currentSuggestions[i]));
188
- }
189
- }
190
- // Show indicator if there are items below the visible window
191
- if (visibleEnd < this.currentSuggestions.length) {
192
- const remaining = this.currentSuggestions.length - visibleEnd;
193
- lines.push(prefix + ansi.gray(' ▼ (' + remaining + ' more below)'));
194
- }
195
- // Show current position and page indicator at bottom
196
- lines.push(prefix + ansi.gray(' [' + (this.suggestionIndex + 1) + '/' + this.currentSuggestions.length + '] ' +
197
- 'Page ' + this.currentPage + '/' + this.totalPages));
198
- return lines;
199
- }
200
- /**
201
- * Builds the argument-hint's content lines: the usage line, shown in full
202
- * and literally — with the argument the user is currently editing bolded
203
- * and everything else (command prefix and other tokens alike) gray. Same
204
- * "fully-styled content strings, no \x1b[2K/\r\n" convention as
205
- * `buildSuggestionListLines`, so `renderSuggestionArea` can draw either or
206
- * both in one frame.
207
- *
208
- * Shown alongside or in place of the suggestion list when a command has
209
- * argument structure worth showing — e.g. "/gamemode creative " (nothing
210
- * left to complete for the target selector, but worth showing what comes
211
- * next), or "/gamemode cr" (one match left — "creative" — where seeing the
212
- * full usage helps confirm that's the right command to commit to). The
213
- * actual parsing of `usage`/`line` into positions and hint text is pure —
214
- * see argumentHint.ts — this is just the ANSI rendering of that
215
- * already-computed structure.
216
- */
217
- buildArgumentHintLines(display) {
218
- let usageLine = ' ' + ansi.gray(display.commandPrefixText);
219
- for (let i = 0; i < display.tokens.length; i++) {
220
- usageLine += ' ';
221
- usageLine += (i === display.currentArgIndex)
222
- ? ansi.boldBrightWhite(display.tokens[i])
223
- : ansi.gray(display.tokens[i]);
224
- }
225
- return [usageLine];
226
- }
227
- /**
228
- * Draws a single frame of suggestion-area content — one save/clear/restore
229
- * cycle, regardless of whether `lines` came from the list, the hint, or
230
- * both stacked together. `clear` (called centrally before this, by `render`)
231
- * has already erased whatever was there before, so this only ever draws
232
- * onto a blank area — each line gets its own `\x1b[2K` defensively, but
233
- * there's no "clear the old N lines" dance to duplicate here.
234
- */
235
- renderSuggestionArea(lines) {
236
- if (lines.length === 0) {
237
- return;
238
- }
239
- if (this.needsClearOnNextRender) {
240
- this.host.write('\x1b[J'); // Clear from cursor to end of screen
241
- this.needsClearOnNextRender = false;
242
- }
243
- this.host.write('\r\n'); // Move to the display area
244
- for (let i = 0; i < lines.length; i++) {
245
- this.host.write('\x1b[2K'); // Clear line first
246
- this.host.write(lines[i]);
247
- if (i < lines.length - 1) {
248
- this.host.write('\r\n');
249
- }
250
- }
251
- this.displayLines = lines.length;
252
- // Scroll-safe return: \x1b[N]A (relative up) is correct even when the
253
- // \r\n outputs above caused the terminal to scroll. \x1b7/\x1b8 (absolute
254
- // save/restore) fail in that case because the saved row is invalidated.
255
- this.host.write(`\x1b[${lines.length}A`);
256
- this.host.write('\r');
257
- const col = this.host.cursorColumn();
258
- if (col > 0) {
259
- this.host.write(`\x1b[${col}C`);
260
- }
261
- }
262
- updateVisibleWindow() {
263
- // Keep a buffer of 2 items above and below the selected item when possible
264
- const buffer = 2;
265
- // Calculate which page the selected item is on
266
- const selectedPage = Math.floor(this.suggestionIndex / this.maxVisible) + 1;
267
- // Update current page if it changed
268
- if (selectedPage !== this.currentPage) {
269
- this.currentPage = selectedPage;
270
- }
271
- // Update the visible window
272
- if (this.suggestionIndex < this.visibleStart + buffer) {
273
- // Scrolling up
274
- this.visibleStart = Math.max(0, this.suggestionIndex - buffer);
275
- }
276
- else if (this.suggestionIndex >= this.visibleStart + this.maxVisible - buffer) {
277
- // Scrolling down
278
- this.visibleStart = Math.min(this.suggestionIndex - this.maxVisible + buffer + 1, Math.max(0, this.currentSuggestions.length - this.maxVisible));
279
- }
280
- // Final boundary check
281
- this.visibleStart = Math.max(0, this.visibleStart);
282
- this.visibleStart = Math.min(this.visibleStart, Math.max(0, this.currentSuggestions.length - this.maxVisible));
283
- }
284
- }
285
- exports.SuggestionDisplay = SuggestionDisplay;
286
- //# sourceMappingURL=suggestionDisplay.js.map
@@ -1,110 +0,0 @@
1
- "use strict";
2
- // src/terminalOutput.ts
3
- //
4
- // Coordinates the CLI's logger output with in-place terminal redraws (the
5
- // command-loading progress bar, the line editor's prompt, ...). Kept
6
- // separate from cli.ts (which wires it to process.stdout and argv) so it can
7
- // be unit-tested without a real TTY.
8
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
- if (k2 === undefined) k2 = k;
10
- var desc = Object.getOwnPropertyDescriptor(m, k);
11
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
- desc = { enumerable: true, get: function() { return m[k]; } };
13
- }
14
- Object.defineProperty(o, k2, desc);
15
- }) : (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- o[k2] = m[k];
18
- }));
19
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
- Object.defineProperty(o, "default", { enumerable: true, value: v });
21
- }) : function(o, v) {
22
- o["default"] = v;
23
- });
24
- var __importStar = (this && this.__importStar) || (function () {
25
- var ownKeys = function(o) {
26
- ownKeys = Object.getOwnPropertyNames || function (o) {
27
- var ar = [];
28
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
- return ar;
30
- };
31
- return ownKeys(o);
32
- };
33
- return function (mod) {
34
- if (mod && mod.__esModule) return mod;
35
- var result = {};
36
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
- __setModuleDefault(result, mod);
38
- return result;
39
- };
40
- })();
41
- Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.createTerminalWriter = createTerminalWriter;
43
- exports.createCliLogger = createCliLogger;
44
- const ansi = __importStar(require("./ansi"));
45
- const logger_1 = require("./logger");
46
- const fs = __importStar(require("fs"));
47
- // Computed once at module load (not per log line) - see `logLevelRank`.
48
- const ERROR_RANK = (0, logger_1.logLevelRank)('error');
49
- const WARNING_RANK = (0, logger_1.logLevelRank)('warning');
50
- const INFO_RANK = (0, logger_1.logLevelRank)('info');
51
- const DEBUG_RANK = (0, logger_1.logLevelRank)('debug');
52
- /** Formats a Date as "HH:MM:SS.mmm" — used to timestamp debug log lines down to the millisecond. */
53
- function formatTimestamp(d) {
54
- const pad = (n, width = 2) => String(n).padStart(width, '0');
55
- return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${pad(d.getMilliseconds(), 3)}`;
56
- }
57
- function createTerminalWriter(sink) {
58
- let currentLine = '';
59
- return {
60
- write(text) {
61
- sink(text);
62
- const lastCr = text.lastIndexOf('\r');
63
- currentLine = lastCr === -1 ? currentLine + text : text.slice(lastCr + 1);
64
- const lastNl = currentLine.lastIndexOf('\n');
65
- if (lastNl !== -1) {
66
- currentLine = currentLine.slice(lastNl + 1);
67
- }
68
- },
69
- writeLogLine(line) {
70
- if (currentLine) {
71
- this.write('\r\x1b[K' + line + currentLine);
72
- }
73
- else {
74
- this.write(line);
75
- }
76
- },
77
- };
78
- }
79
- /**
80
- * A `Logger` that writes through `terminal` (stdout) or, if `logFile` is
81
- * given, appends to that file instead. Messages below `logLevel` (default
82
- * "info", so "debug" is suppressed) are dropped entirely. Debug lines are
83
- * additionally prefixed with a millisecond-resolution timestamp, since
84
- * they're meant for performance investigation.
85
- */
86
- function createCliLogger(terminal, logFile, logLevel = 'info') {
87
- const thresholdRank = (0, logger_1.logLevelRank)(logLevel);
88
- function write(levelRank, label, color, msg) {
89
- if (levelRank < thresholdRank) {
90
- return;
91
- }
92
- const prefix = levelRank === DEBUG_RANK ? `${formatTimestamp(new Date())} ${label}` : label;
93
- if (logFile) {
94
- // Synchronous append: log lines are infrequent, and a WriteStream's
95
- // async open left a window where a write could be queued before the
96
- // file existed on disk, racing readers (and CI) that check it back.
97
- fs.appendFileSync(logFile, `${prefix} ${msg}\n`);
98
- }
99
- else {
100
- terminal.writeLogLine(`${ansi.style(color, prefix)} ${msg}\n`);
101
- }
102
- }
103
- return {
104
- error: (msg) => write(ERROR_RANK, 'ERROR', ansi.RED, msg),
105
- warning: (msg) => write(WARNING_RANK, 'WARN', ansi.YELLOW, msg),
106
- info: (msg) => write(INFO_RANK, 'INFO', ansi.CYAN, msg),
107
- debug: (msg) => write(DEBUG_RANK, 'DEBUG', ansi.GRAY, msg),
108
- };
109
- }
110
- //# sourceMappingURL=terminalOutput.js.map