minercon 3.0.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.
- package/CHANGELOG.md +439 -0
- package/LICENSE +22 -0
- package/README.md +401 -0
- package/images/icon.png +0 -0
- package/out/ansi.js +123 -0
- package/out/argumentHint.js +43 -0
- package/out/bukkitHelpParsing.js +62 -0
- package/out/cli.js +253 -0
- package/out/cliConfig.js +141 -0
- package/out/commandLine.js +28 -0
- package/out/commandSuggestions.js +202 -0
- package/out/commandTree.js +46 -0
- package/out/commandTreeCache.js +171 -0
- package/out/commandTreeCrawler.js +583 -0
- package/out/commandTreeParsingBrigadier.js +426 -0
- package/out/commandTreeParsingBukkit.js +116 -0
- package/out/commandTreeSuggestions.js +142 -0
- package/out/completionBackend.js +94 -0
- package/out/completionEngine.js +376 -0
- package/out/completionQueries.js +86 -0
- package/out/completionsBackend.js +97 -0
- package/out/connectionManager.js +209 -0
- package/out/displayArgumentHint.js +43 -0
- package/out/displayCommandTree.js +115 -0
- package/out/displaySuggestion.js +282 -0
- package/out/extension.js +190 -0
- package/out/helpTextParsing.js +445 -0
- package/out/historySearch.js +46 -0
- package/out/historyStore.js +126 -0
- package/out/lineEditor.js +525 -0
- package/out/localCommandTree.js +541 -0
- package/out/logger.js +14 -0
- package/out/minercon +253 -0
- package/out/pager.js +168 -0
- package/out/pagination.js +142 -0
- package/out/rconClient.js +97 -0
- package/out/rconConnectionManager.js +238 -0
- package/out/rconProtocol.js +421 -0
- package/out/rconSession.js +920 -0
- package/out/rconTerminal.js +80 -0
- package/out/suggestionDisplay.js +286 -0
- package/out/terminalOutput.js +110 -0
- package/out/unpaginate.js +30 -0
- package/package.json +138 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/rconTerminal.ts
|
|
3
|
+
//
|
|
4
|
+
// Thin vscode.Pseudoterminal adapter over RconSession. All interactive logic
|
|
5
|
+
// lives in RconSession (rconSession.ts); this file is just the VS Code glue:
|
|
6
|
+
// EventEmitters, clipboard, extension context, and Pseudoterminal forwarding.
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.RconTerminal = void 0;
|
|
42
|
+
const vscode = __importStar(require("vscode"));
|
|
43
|
+
const rconSession_1 = require("./rconSession");
|
|
44
|
+
class RconTerminal {
|
|
45
|
+
writeEmitter = new vscode.EventEmitter();
|
|
46
|
+
onDidWrite = this.writeEmitter.event;
|
|
47
|
+
closeEmitter = new vscode.EventEmitter();
|
|
48
|
+
onDidClose = this.closeEmitter.event;
|
|
49
|
+
session;
|
|
50
|
+
dims;
|
|
51
|
+
constructor(controller, host, port, password, logger, context) {
|
|
52
|
+
const sessionHost = {
|
|
53
|
+
write: (text) => this.writeEmitter.fire(text),
|
|
54
|
+
close: (code) => this.closeEmitter.fire(code),
|
|
55
|
+
clipboard: {
|
|
56
|
+
readText: () => Promise.resolve(vscode.env.clipboard.readText()),
|
|
57
|
+
writeText: (text) => Promise.resolve(vscode.env.clipboard.writeText(text)),
|
|
58
|
+
},
|
|
59
|
+
cacheDir: context.globalStorageUri.fsPath,
|
|
60
|
+
dimensions: () => this.dims ? { columns: this.dims.columns, rows: this.dims.rows } : undefined,
|
|
61
|
+
historySize: vscode.workspace.getConfiguration('minercon').get('historySize', 100),
|
|
62
|
+
};
|
|
63
|
+
this.session = new rconSession_1.RconSession(controller, host, port, password, logger, sessionHost);
|
|
64
|
+
}
|
|
65
|
+
open(initialDimensions) {
|
|
66
|
+
this.dims = initialDimensions;
|
|
67
|
+
this.session.open();
|
|
68
|
+
}
|
|
69
|
+
close() {
|
|
70
|
+
this.session.close();
|
|
71
|
+
}
|
|
72
|
+
handleInput(data) {
|
|
73
|
+
this.session.handleInput(data);
|
|
74
|
+
}
|
|
75
|
+
setDimensions(dimensions) {
|
|
76
|
+
this.dims = dimensions;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.RconTerminal = RconTerminal;
|
|
80
|
+
//# sourceMappingURL=rconTerminal.js.map
|
|
@@ -0,0 +1,286 @@
|
|
|
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
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/unpaginate.ts
|
|
3
|
+
//
|
|
4
|
+
// Client side of the server-side de-pagination feature. When the TabComplete
|
|
5
|
+
// plugin is present *and* exposes the `rcat` command (Bukkit-family servers —
|
|
6
|
+
// not Fabric, which doesn't paginate), the interactive terminal wraps each
|
|
7
|
+
// server-bound command as `rcat <command>` so its output comes back unpaginated
|
|
8
|
+
// in a single response. See docs/UNPAGINATED_OUTPUT.md.
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.RCAT_PROBE_MARKER = void 0;
|
|
11
|
+
exports.responseSupportsRcat = responseSupportsRcat;
|
|
12
|
+
exports.wrapForUnpagination = wrapForUnpagination;
|
|
13
|
+
/** Line the plugin's `rcat` (no-arg) response emits; used to detect support. */
|
|
14
|
+
exports.RCAT_PROBE_MARKER = 'rcat: returns unpaginated command output';
|
|
15
|
+
/** True iff a probe response indicates the server supports `rcat`. */
|
|
16
|
+
function responseSupportsRcat(response) {
|
|
17
|
+
return !!response && response.includes(exports.RCAT_PROBE_MARKER);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns the command to actually send: `rcat <command>` when de-pagination is
|
|
21
|
+
* active, otherwise the command unchanged. Empty/whitespace input is never
|
|
22
|
+
* wrapped (nothing to run).
|
|
23
|
+
*/
|
|
24
|
+
function wrapForUnpagination(command, supported) {
|
|
25
|
+
if (!supported || command.trim().length === 0) {
|
|
26
|
+
return command;
|
|
27
|
+
}
|
|
28
|
+
return `rcat ${command}`;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=unpaginate.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "minercon",
|
|
3
|
+
"displayName": "Minercon",
|
|
4
|
+
"description": "A powerful RCON client for Minecraft servers with advanced fragmentation support",
|
|
5
|
+
"version": "3.0.0",
|
|
6
|
+
"author": "xton <thisischriston@gmail.com>",
|
|
7
|
+
"icon": "images/icon.png",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"homepage": "https://github.com/xton/minercon",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/xton/minercon/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/xton/minercon.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"minecraft",
|
|
19
|
+
"rcon",
|
|
20
|
+
"terminal",
|
|
21
|
+
"server-admin",
|
|
22
|
+
"tab-completion",
|
|
23
|
+
"minecraft-server",
|
|
24
|
+
"console",
|
|
25
|
+
"rcon-client"
|
|
26
|
+
],
|
|
27
|
+
"files": [
|
|
28
|
+
"out/*.js",
|
|
29
|
+
"out/minercon",
|
|
30
|
+
"images/icon.png",
|
|
31
|
+
"CHANGELOG.md"
|
|
32
|
+
],
|
|
33
|
+
"engines": {
|
|
34
|
+
"vscode": "^1.95.0",
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"categories": [
|
|
38
|
+
"Other"
|
|
39
|
+
],
|
|
40
|
+
"activationEvents": [],
|
|
41
|
+
"main": "./dist/extension.js",
|
|
42
|
+
"bin": {
|
|
43
|
+
"minercon": "out/minercon"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"vscode:prepublish": "npm run compile && node esbuild.js --production",
|
|
47
|
+
"prepublishOnly": "npm run compile",
|
|
48
|
+
"compile": "tsc -p ./ && node esbuild.js && node scripts/post-compile.js",
|
|
49
|
+
"watch": "tsc -w -p ./",
|
|
50
|
+
"pretest": "npm run compile && npm run lint",
|
|
51
|
+
"lint": "eslint src",
|
|
52
|
+
"test": "vscode-test",
|
|
53
|
+
"test:functional": "npm run compile && mocha --ui tdd --timeout 660000 'out/test/functional/**/*.test.js'",
|
|
54
|
+
"test:functional:connection": "npm run compile && mocha --ui tdd --timeout 660000 out/test/functional/connection.test.js",
|
|
55
|
+
"test:functional:local": "npm run compile && mocha --ui tdd --timeout 660000 out/test/functional/localMode.test.js",
|
|
56
|
+
"test:functional:plugin": "npm run compile && mocha --ui tdd --timeout 660000 out/test/functional/pluginMode.test.js",
|
|
57
|
+
"record-rcon-fixtures": "npm run compile && node out/test/recordRconFixtures.js"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/mocha": "^10.0.10",
|
|
61
|
+
"@types/node": "22.x",
|
|
62
|
+
"@types/vscode": "^1.95.0",
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^8.42.0",
|
|
64
|
+
"@typescript-eslint/parser": "^8.42.0",
|
|
65
|
+
"@vscode/test-cli": "^0.0.11",
|
|
66
|
+
"@vscode/test-electron": "^2.5.2",
|
|
67
|
+
"@xterm/headless": "^6.0.0",
|
|
68
|
+
"esbuild": "^0.28.1",
|
|
69
|
+
"eslint": "^9.34.0",
|
|
70
|
+
"testcontainers": "^12.0.1",
|
|
71
|
+
"typescript": "^5.9.2"
|
|
72
|
+
},
|
|
73
|
+
"contributes": {
|
|
74
|
+
"commands": [
|
|
75
|
+
{
|
|
76
|
+
"command": "minercon.connect",
|
|
77
|
+
"title": "Minercon: Connect to Server",
|
|
78
|
+
"category": "Minercon",
|
|
79
|
+
"icon": "$(terminal)"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"command": "minercon.connectNew",
|
|
83
|
+
"title": "Minercon: Connect with New Credentials",
|
|
84
|
+
"category": "Minercon",
|
|
85
|
+
"icon": "$(terminal)"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"command": "minercon.saveDefaults",
|
|
89
|
+
"title": "Minercon: Save Current Connection as Default",
|
|
90
|
+
"category": "Minercon",
|
|
91
|
+
"icon": "$(terminal)"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"terminal": {
|
|
95
|
+
"profiles": [
|
|
96
|
+
{
|
|
97
|
+
"id": "minercon.terminal",
|
|
98
|
+
"title": "Minecraft Server"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
"configuration": {
|
|
103
|
+
"title": "Minercon",
|
|
104
|
+
"properties": {
|
|
105
|
+
"minercon.defaultHost": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"default": "",
|
|
108
|
+
"description": "Default RCON host address"
|
|
109
|
+
},
|
|
110
|
+
"minercon.defaultPort": {
|
|
111
|
+
"type": "number",
|
|
112
|
+
"default": null,
|
|
113
|
+
"description": "Default RCON port"
|
|
114
|
+
},
|
|
115
|
+
"minercon.historySize": {
|
|
116
|
+
"type": "number",
|
|
117
|
+
"default": 100,
|
|
118
|
+
"minimum": 1,
|
|
119
|
+
"description": "Number of commands to remember in history (in-memory and persisted to disk)"
|
|
120
|
+
},
|
|
121
|
+
"minercon.unpaginateOutput": {
|
|
122
|
+
"type": "boolean",
|
|
123
|
+
"default": true,
|
|
124
|
+
"description": "When the server tab-complete plugin is installed, request full unpaginated output for commands (e.g. /help) instead of the server's small pages. No effect on servers without the plugin."
|
|
125
|
+
},
|
|
126
|
+
"minercon.terminalPager": {
|
|
127
|
+
"type": "boolean",
|
|
128
|
+
"default": true,
|
|
129
|
+
"description": "Page command output taller than the terminal window through a built-in pager (Space: more, G: all, q: quit). When off, tall output is printed all at once."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"dependencies": {
|
|
135
|
+
"@clack/prompts": "^1.5.1",
|
|
136
|
+
"consola": "^3.4.2"
|
|
137
|
+
}
|
|
138
|
+
}
|