Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
}
],
"engines": {
"vscode": "^1.93.0"
"vscode": "^1.104.0"
},
"enabledApiProposals": [
"fileSearchProvider",
Expand Down Expand Up @@ -1805,7 +1805,7 @@
"test": "node ./out/test/runTest.js",
"lint": "eslint src/**",
"lint-fix": "eslint --fix src/**",
"download-api": "dts dev 1.93.0",
"download-api": "dts dev 1.104.0",
"postinstall": "npm run download-api"
},
"devDependencies": {
Expand All @@ -1816,7 +1816,7 @@
"@types/mocha": "^7.0.2",
"@types/node": "20.17.6",
"@types/semver": "7.5.4",
"@types/vscode": "1.93.0",
"@types/vscode": "1.104.0",
"@types/ws": "8.18.0",
"@types/xmldom": "^0.1.34",
"@typescript-eslint/eslint-plugin": "^8.15.0",
Expand Down
68 changes: 41 additions & 27 deletions src/commands/webSocketTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
/** The number of characters on the line that the user can't delete */
private _margin = 0;

/** The text writted by the user since the last prompt/read */
/** The text written by the user since the last prompt/read */
private _input = "";

/** The position of the cursor within the line */
Expand Down Expand Up @@ -98,6 +98,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {

constructor(
private readonly _targetUri: vscode.Uri,
private readonly _nonce: string,
private readonly _nsOverride?: string
) {}

Expand Down Expand Up @@ -224,7 +225,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
this._hideCursorWrite("\x1b]633;P;HasRichCommandDetection=True\x07");
// Print the opening message
this._hideCursorWrite(
`\x1b[32mConnected to \x1b[0m\x1b[4m${api.config.host}:${api.config.port}${api.config.pathPrefix}\x1b[0m\x1b[32m as \x1b[0m\x1b[3m${api.config.username}\x1b[0m\r\n\r\n`
`\x1b[32mConnected to \x1b[0m\x1b[4m${api.config.host}:${api.config.port}${api.config.pathPrefix}\x1b[0m\x1b[32m as \x1b[0m\x1b[3m${api.config.username}\x1b[0m\r\n`
);
// Add event handlers to the socket
this._socket
Expand Down Expand Up @@ -273,9 +274,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
if (message.type == "prompt") {
// Write the prompt to the terminal
this._hideCursorWrite(
`\x1b]633;D${this._promptExitCode}\x07${this._margin ? "\r\n" : ""}\x1b]633;A\x07${
message.text
}\x1b]633;B\x07`
`\x1b]633;D${this._promptExitCode}\x07\r\n\x1b]633;A\x07${message.text}\x1b]633;B\x07`
);
this._margin = this._cursorCol = message.text.replace(this._colorsRegex, "").length;
this._prompt = message.text;
Expand Down Expand Up @@ -366,13 +365,14 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
// Send the input to the server for processing
this._socket.send(JSON.stringify({ type: this._state, input: this._input }));
if (this._state == "prompt") {
this._hideCursorWrite(`\x1b]633;E;${this._inputEscaped()}\x07\x1b]633;C\x07\r\n`);
this._hideCursorWrite(`\x1b]633;E;${this._inputEscaped()};${this._nonce}\x07\r\n\x1b]633;C\x07`);
if (this._input == "") {
this._promptExitCode = "";
}
}
this._input = "";
this._state = "eval";
this._margin = this._cursorCol = 0;
return;
}
case keys.ctrlH:
Expand Down Expand Up @@ -561,7 +561,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
if (this._cursorCol == this._margin + inputArr[inputArr.length - 1].length) {
// Move the cursor to the beginning of the input
this._moveCursor(this._margin - this._cursorCol);
// Erase everyhting to the right of the cursor
// Erase everything to the right of the cursor
this._hideCursorWrite("\x1b[0J");
inputArr[inputArr.length - 1] = "";
this._input = inputArr.join("\r\n");
Expand All @@ -588,10 +588,16 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
// Submit the input after processing
// This should only happen due to VS Code's shell integration
submit = true;
char = char.slice(0, -1);
}
// Replace all single \r with \r\n (prompt) or space (read)
char = char.replace(/\r/g, this._state == "prompt" ? "\r\n" : " ");
// Need to remove any multi-line prompts that are in the command lines
// Workaround for https://github.com/microsoft/vscode/issues/258457
char = char
.slice(0, -1)
.split("\r")
.map((l) => (l.startsWith(this._multiLinePrompt) ? l.slice(this._multiLinePrompt.length) : l))
.join("\r");
}
// Replace all single \r with \r\n
char = char.replace(/\r(?!\n)/g, "\r\n");
const inputArr = this._input.split("\r\n");
let eraseAfterCursor = "",
trailingText = "";
Expand All @@ -613,8 +619,10 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
const originalCol = this._cursorCol;
let newRow: number;
if (char.includes("\r\n")) {
char = char.replace(/\r\n/g, `\r\n${this._multiLinePrompt}`);
this._margin = this._multiLinePrompt.length;
if (this._state == "prompt") {
char = char.replaceAll("\r\n", `\r\n${this._multiLinePrompt}`);
this._margin = this._multiLinePrompt.length;
}
const charLines = char.split("\r\n");
newRow =
charLines.reduce(
Expand All @@ -632,21 +640,24 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
const colStr = colDelta ? (colDelta > 0 ? `\x1b[${colDelta}C` : `\x1b[${Math.abs(colDelta)}D`) : "";
char += trailingText;
const spaceOnCurrentLine = this._cols - (originalCol % this._cols);
if (this._state == "read" && char.length >= spaceOnCurrentLine) {
if (this._state == "read" && (char.includes("\r\n") || char.length >= spaceOnCurrentLine)) {
// There's no auto-line wrapping when in read mode, so we must move the cursor manually
const charLines = char.split("\r\n");
// Extract all the characters that fit on the cursor's line
const firstLine = char.slice(0, spaceOnCurrentLine);
const otherLines = char.slice(spaceOnCurrentLine);
const lines: string[] = [];
if (otherLines.length) {
// Split the rest into an array of lines that fit in the viewport
for (let line = 0, i = 0; line < Math.ceil(otherLines.length / this._cols); line++, i += this._cols) {
lines[line] = otherLines.slice(i, i + this._cols);
const firstLine = charLines[0].slice(0, spaceOnCurrentLine);
charLines[0] = charLines[0].slice(spaceOnCurrentLine);
// Split the rest into an array of lines that fit in the viewport
const lines = charLines.flatMap((line, idx) => {
if (idx == charLines.length - 1 && line == "") {
// Add a blank "line" to move the cursor to the next viewport row
return [""];
}
} else {
// Add a blank "line" to move the cursor to the next viewport row
lines.push("");
}
const chunks = [];
for (let i = 0; i < line.length; i += this._cols) {
chunks.push(line.slice(i, i + this._cols));
}
return chunks;
});
// Join the lines with the cursor escape code
lines.unshift(firstLine);
char = lines.join("\r\n");
Expand Down Expand Up @@ -678,13 +689,14 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
// Send the input to the server for processing
this._socket.send(JSON.stringify({ type: this._state, input: this._input }));
if (this._state == "prompt") {
this._hideCursorWrite(`\x1b]633;E;${this._inputEscaped()}\x07\x1b]633;C\x07\r\n`);
this._hideCursorWrite(`\x1b]633;E;${this._inputEscaped()};${this._nonce}\x07\r\n\x1b]633;C\x07`);
if (this._input == "") {
this._promptExitCode = "";
}
}
this._input = "";
this._state = "eval";
this._margin = this._cursorCol = 0;
} else if (this._input != "" && this._state == "prompt" && this._syntaxColoringEnabled()) {
// Syntax color input
this._socket.send(JSON.stringify({ type: "color", input: this._input }));
Expand Down Expand Up @@ -747,6 +759,7 @@ function terminalConfigForUri(
}

sendLiteTerminalTelemetryEvent(throwErrors ? "profile" : "command");
const nonce = crypto.randomUUID();
return {
name: api.config.serverName && api.config.serverName != "" ? api.config.serverName : "iris",
location:
Expand All @@ -756,9 +769,10 @@ function terminalConfigForUri(
vscode.window.terminals.length > 0
? vscode.TerminalLocation.Editor
: vscode.TerminalLocation.Panel,
pty: new WebSocketTerminal(targetUri, nsOverride),
pty: new WebSocketTerminal(targetUri, nonce, nsOverride),
isTransient: true,
iconPath: iscIcon,
shellIntegrationNonce: nonce,
};
}

Expand Down