@microsoft/inshellisense 0.0.1-rc.14 → 0.0.1-rc.15
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/README.md +1 -13
- package/build/isterm/commandManager.js +96 -90
- package/build/isterm/pty.js +25 -5
- package/build/ui/suggestionManager.js +7 -1
- package/build/ui/utils.js +2 -1
- package/build/utils/ansi.js +4 -0
- package/build/utils/config.js +42 -33
- package/build/utils/shell.js +18 -0
- package/package.json +2 -1
- package/shell/shellIntegration.bash +15 -0
- package/shell/shellIntegration.fish +8 -5
- package/shell/shellIntegration.nu +11 -3
- package/shell/shellIntegration.ps1 +5 -2
- package/shell/shellIntegration.xsh +12 -4
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ inshellisense supports the following shells:
|
|
|
81
81
|
|
|
82
82
|
## Configuration
|
|
83
83
|
|
|
84
|
-
All configuration is done through a [toml](https://toml.io/) file
|
|
84
|
+
All configuration is done through a [toml](https://toml.io/) file. You can create this file at `~/.inshellisenserc` or, for XDG compliance, at `~/.config/inshellisense/rc.toml`. The [JSON schema](https://json-schema.org/) for the configuration file can be found [here](https://github.com/microsoft/inshellisense/blob/main/src/utils/config.ts).
|
|
85
85
|
|
|
86
86
|
### Keybindings
|
|
87
87
|
|
|
@@ -106,18 +106,6 @@ key = "escape"
|
|
|
106
106
|
|
|
107
107
|
Key names are matched against the Node.js [keypress](https://nodejs.org/api/readline.html#readlineemitkeypresseventsstream-interface) events.
|
|
108
108
|
|
|
109
|
-
### Custom Prompts (Windows)
|
|
110
|
-
|
|
111
|
-
If you are using a custom prompt in your shell (anything that is not the default PS1), you will need to set up a custom prompt in the inshellisense config file. This is because Windows strips details from your prompt which are required for inshellisense to work. To do this, update your config file in your home directory and add the following configuration:
|
|
112
|
-
|
|
113
|
-
```toml
|
|
114
|
-
[[prompt.bash]]
|
|
115
|
-
regex = "(?<prompt>^>\\s*)" # the prompt match group will be used to detect the prompt
|
|
116
|
-
postfix = ">" # the postfix is the last expected character in your prompt
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
This example adds custom prompt detection for bash where the prompt is expected to be only `> `. You can add similar configurations for other shells as well as well as multiple configurations for each shell.
|
|
120
|
-
|
|
121
109
|
## Contributing
|
|
122
110
|
|
|
123
111
|
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
|
@@ -4,19 +4,21 @@ import convert from "color-convert";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import { getShellPromptRewrites, Shell } from "../utils/shell.js";
|
|
6
6
|
import log from "../utils/log.js";
|
|
7
|
-
import { getConfig } from "../utils/config.js";
|
|
8
7
|
const maxPromptPollDistance = 10;
|
|
9
8
|
export class CommandManager {
|
|
10
9
|
#activeCommand;
|
|
11
10
|
#terminal;
|
|
12
11
|
#previousCommandLines;
|
|
12
|
+
#maxCursorY;
|
|
13
13
|
#shell;
|
|
14
14
|
#promptRewrites;
|
|
15
15
|
#supportsProperOscPlacements = os.platform() !== "win32";
|
|
16
|
+
promptTerminator = "";
|
|
16
17
|
constructor(terminal, shell) {
|
|
17
18
|
this.#terminal = terminal;
|
|
18
19
|
this.#shell = shell;
|
|
19
20
|
this.#activeCommand = {};
|
|
21
|
+
this.#maxCursorY = 0;
|
|
20
22
|
this.#previousCommandLines = new Set();
|
|
21
23
|
this.#promptRewrites = getShellPromptRewrites(shell);
|
|
22
24
|
if (this.#supportsProperOscPlacements) {
|
|
@@ -45,17 +47,9 @@ export class CommandManager {
|
|
|
45
47
|
}
|
|
46
48
|
handleClear() {
|
|
47
49
|
this.handlePromptStart();
|
|
50
|
+
this.#maxCursorY = 0;
|
|
48
51
|
this.#previousCommandLines = new Set();
|
|
49
52
|
}
|
|
50
|
-
_extractPrompt(lineText, patterns) {
|
|
51
|
-
for (const { regex, postfix } of patterns) {
|
|
52
|
-
const customPrompt = lineText.match(new RegExp(regex))?.groups?.prompt;
|
|
53
|
-
const adjustedPrompt = this._adjustPrompt(customPrompt, lineText, postfix);
|
|
54
|
-
if (adjustedPrompt) {
|
|
55
|
-
return adjustedPrompt;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
53
|
_getWindowsPrompt(y) {
|
|
60
54
|
const line = this.#terminal.buffer.active.getLine(y);
|
|
61
55
|
if (!line) {
|
|
@@ -65,15 +59,16 @@ export class CommandManager {
|
|
|
65
59
|
if (!lineText) {
|
|
66
60
|
return;
|
|
67
61
|
}
|
|
62
|
+
// dynamic prompt terminator
|
|
63
|
+
if (this.promptTerminator && lineText.trim().endsWith(this.promptTerminator)) {
|
|
64
|
+
const adjustedPrompt = this._adjustPrompt(lineText, lineText, this.promptTerminator);
|
|
65
|
+
if (adjustedPrompt) {
|
|
66
|
+
return adjustedPrompt;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
68
69
|
// User defined prompt
|
|
69
|
-
const inshellisenseConfig = getConfig();
|
|
70
70
|
if (this.#shell == Shell.Bash) {
|
|
71
|
-
|
|
72
|
-
const extractedPrompt = this._extractPrompt(lineText, inshellisenseConfig.prompt.bash);
|
|
73
|
-
if (extractedPrompt)
|
|
74
|
-
return extractedPrompt;
|
|
75
|
-
}
|
|
76
|
-
const bashPrompt = lineText.match(/^(?<prompt>.*\$\s?)/)?.groups?.prompt;
|
|
71
|
+
const bashPrompt = lineText.match(/^(?<prompt>\$\s?)/)?.groups?.prompt;
|
|
77
72
|
if (bashPrompt) {
|
|
78
73
|
const adjustedPrompt = this._adjustPrompt(bashPrompt, lineText, "$");
|
|
79
74
|
if (adjustedPrompt) {
|
|
@@ -81,12 +76,16 @@ export class CommandManager {
|
|
|
81
76
|
}
|
|
82
77
|
}
|
|
83
78
|
}
|
|
84
|
-
if (this.#shell == Shell.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
if (this.#shell == Shell.Fish) {
|
|
80
|
+
const fishPrompt = lineText.match(/(?<prompt>.*>\s?)/)?.groups?.prompt;
|
|
81
|
+
if (fishPrompt) {
|
|
82
|
+
const adjustedPrompt = this._adjustPrompt(fishPrompt, lineText, ">");
|
|
83
|
+
if (adjustedPrompt) {
|
|
84
|
+
return adjustedPrompt;
|
|
85
|
+
}
|
|
89
86
|
}
|
|
87
|
+
}
|
|
88
|
+
if (this.#shell == Shell.Nushell) {
|
|
90
89
|
const nushellPrompt = lineText.match(/(?<prompt>.*>\s?)/)?.groups?.prompt;
|
|
91
90
|
if (nushellPrompt) {
|
|
92
91
|
const adjustedPrompt = this._adjustPrompt(nushellPrompt, lineText, ">");
|
|
@@ -96,11 +95,6 @@ export class CommandManager {
|
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
if (this.#shell == Shell.Xonsh) {
|
|
99
|
-
if (inshellisenseConfig?.prompt?.xonsh != null) {
|
|
100
|
-
const extractedPrompt = this._extractPrompt(lineText, inshellisenseConfig.prompt.xonsh);
|
|
101
|
-
if (extractedPrompt)
|
|
102
|
-
return extractedPrompt;
|
|
103
|
-
}
|
|
104
98
|
let xonshPrompt = lineText.match(/(?<prompt>.*@\s?)/)?.groups?.prompt;
|
|
105
99
|
if (xonshPrompt) {
|
|
106
100
|
const adjustedPrompt = this._adjustPrompt(xonshPrompt, lineText, "@");
|
|
@@ -117,16 +111,6 @@ export class CommandManager {
|
|
|
117
111
|
}
|
|
118
112
|
}
|
|
119
113
|
if (this.#shell == Shell.Powershell || this.#shell == Shell.Pwsh) {
|
|
120
|
-
if (inshellisenseConfig?.prompt?.powershell != null) {
|
|
121
|
-
const extractedPrompt = this._extractPrompt(lineText, inshellisenseConfig.prompt.powershell);
|
|
122
|
-
if (extractedPrompt)
|
|
123
|
-
return extractedPrompt;
|
|
124
|
-
}
|
|
125
|
-
if (inshellisenseConfig?.prompt?.pwsh != null) {
|
|
126
|
-
const extractedPrompt = this._extractPrompt(lineText, inshellisenseConfig.prompt.pwsh);
|
|
127
|
-
if (extractedPrompt)
|
|
128
|
-
return extractedPrompt;
|
|
129
|
-
}
|
|
130
114
|
const pwshPrompt = lineText.match(/(?<prompt>(\(.+\)\s)?(?:PS.+>\s?))/)?.groups?.prompt;
|
|
131
115
|
if (pwshPrompt) {
|
|
132
116
|
const adjustedPrompt = this._adjustPrompt(pwshPrompt, lineText, ">");
|
|
@@ -191,13 +175,78 @@ export class CommandManager {
|
|
|
191
175
|
clearActiveCommand() {
|
|
192
176
|
this.#activeCommand = {};
|
|
193
177
|
}
|
|
178
|
+
_getCommandLines() {
|
|
179
|
+
const lines = [];
|
|
180
|
+
let lineY = this.#activeCommand.promptEndMarker.line;
|
|
181
|
+
let line = this.#terminal.buffer.active.getLine(this.#activeCommand.promptEndMarker.line);
|
|
182
|
+
const absoluteY = this.#terminal.buffer.active.baseY + this.#terminal.buffer.active.cursorY;
|
|
183
|
+
for (; lineY < this.#terminal.buffer.active.baseY + this.#terminal.rows;) {
|
|
184
|
+
if (line)
|
|
185
|
+
lines.push(line);
|
|
186
|
+
lineY += 1;
|
|
187
|
+
line = this.#terminal.buffer.active.getLine(lineY);
|
|
188
|
+
const lineWrapped = line?.isWrapped;
|
|
189
|
+
const cursorWrapped = absoluteY > lineY - 1;
|
|
190
|
+
const wrapped = lineWrapped || cursorWrapped;
|
|
191
|
+
if (!wrapped)
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
return lines;
|
|
195
|
+
}
|
|
196
|
+
_getCommandText(commandLines) {
|
|
197
|
+
const absoluteY = this.#terminal.buffer.active.baseY + this.#terminal.buffer.active.cursorY;
|
|
198
|
+
const cursorLine = Math.max(absoluteY - this.#activeCommand.promptEndMarker.line, 0);
|
|
199
|
+
let preCursorCommand = "";
|
|
200
|
+
let postCursorCommand = "";
|
|
201
|
+
let suggestion = "";
|
|
202
|
+
for (const [y, line] of commandLines.entries()) {
|
|
203
|
+
const startX = y == 0 ? this.#activeCommand.promptText?.length ?? 0 : 0;
|
|
204
|
+
for (let x = startX; x < this.#terminal.cols; x++) {
|
|
205
|
+
if (postCursorCommand.endsWith(" "))
|
|
206
|
+
break; // assume that a command that ends with 4 spaces is terminated, avoids capturing right prompts
|
|
207
|
+
const cell = line.getCell(x);
|
|
208
|
+
if (cell == null)
|
|
209
|
+
continue;
|
|
210
|
+
const chars = cell.getChars() == "" ? " " : cell.getChars();
|
|
211
|
+
const beforeCursor = y < cursorLine || (y == cursorLine && x < this.#terminal.buffer.active.cursorX);
|
|
212
|
+
const isCommand = !this._isSuggestion(cell) && suggestion.length == 0;
|
|
213
|
+
if (isCommand && beforeCursor) {
|
|
214
|
+
preCursorCommand += chars;
|
|
215
|
+
}
|
|
216
|
+
else if (isCommand) {
|
|
217
|
+
postCursorCommand += chars;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
suggestion += chars;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
log.debug({ msg: "command text", preCursorCommand, postCursorCommand, suggestion });
|
|
225
|
+
return { suggestion, preCursorCommand, postCursorCommand };
|
|
226
|
+
}
|
|
227
|
+
_getCommandOutputStatus(commandLines) {
|
|
228
|
+
const outputLineY = this.#activeCommand.promptEndMarker.line + commandLines;
|
|
229
|
+
const maxLineY = this.#terminal.buffer.active.baseY + this.#terminal.rows;
|
|
230
|
+
if (outputLineY >= maxLineY)
|
|
231
|
+
return false;
|
|
232
|
+
const line = this.#terminal.buffer.active.getLine(outputLineY);
|
|
233
|
+
let cell = undefined;
|
|
234
|
+
for (let i = 0; i < this.#terminal.cols; i++) {
|
|
235
|
+
cell = line?.getCell(i, cell);
|
|
236
|
+
if (cell?.getChars() != "") {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
194
242
|
termSync() {
|
|
195
243
|
if (this.#activeCommand.promptEndMarker == null || this.#activeCommand.promptStartMarker == null) {
|
|
196
244
|
return;
|
|
197
245
|
}
|
|
198
246
|
const globalCursorPosition = this.#terminal.buffer.active.baseY + this.#terminal.buffer.active.cursorY;
|
|
199
247
|
const withinPollDistance = globalCursorPosition < this.#activeCommand.promptEndMarker.line + 5;
|
|
200
|
-
|
|
248
|
+
this.#maxCursorY = Math.max(this.#maxCursorY, globalCursorPosition);
|
|
249
|
+
if (globalCursorPosition < this.#activeCommand.promptStartMarker.line || globalCursorPosition < this.#maxCursorY) {
|
|
201
250
|
this.handleClear();
|
|
202
251
|
this.#activeCommand.promptEndMarker = this.#terminal.registerMarker(0);
|
|
203
252
|
return;
|
|
@@ -221,60 +270,15 @@ export class CommandManager {
|
|
|
221
270
|
}
|
|
222
271
|
// if the prompt is set, now parse out the values from the terminal
|
|
223
272
|
if (this.#activeCommand.promptText != null) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
let isWrapped = false;
|
|
230
|
-
for (; lineY < this.#terminal.buffer.active.baseY + this.#terminal.rows;) {
|
|
231
|
-
for (let i = lineY == this.#activeCommand.promptEndMarker.line ? this.#activeCommand.promptText.length : 0; i < this.#terminal.cols; i++) {
|
|
232
|
-
if (command.endsWith(" "))
|
|
233
|
-
break; // assume that a command that ends with 4 spaces is terminated, avoids capturing right prompts
|
|
234
|
-
const cell = line?.getCell(i);
|
|
235
|
-
if (cell == null)
|
|
236
|
-
continue;
|
|
237
|
-
const chars = cell.getChars();
|
|
238
|
-
const cleanedChars = chars == "" ? " " : chars;
|
|
239
|
-
if (!this._isSuggestion(cell) && suggestions.length == 0) {
|
|
240
|
-
command += cleanedChars;
|
|
241
|
-
wrappedCommand += cleanedChars;
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
suggestions += cleanedChars;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
lineY += 1;
|
|
248
|
-
line = this.#terminal.buffer.active.getLine(lineY);
|
|
249
|
-
const wrapped = line?.isWrapped || this.#terminal.buffer.active.cursorY + this.#terminal.buffer.active.baseY != lineY - 1;
|
|
250
|
-
isWrapped = isWrapped || wrapped;
|
|
251
|
-
if (!wrapped) {
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
wrappedCommand = "";
|
|
255
|
-
}
|
|
256
|
-
const cursorAtEndOfInput = isWrapped
|
|
257
|
-
? wrappedCommand.trim().length % this.#terminal.cols <= this.#terminal.buffer.active.cursorX
|
|
258
|
-
: (this.#activeCommand.promptText.length + command.trimEnd().length) % this.#terminal.cols <= this.#terminal.buffer.active.cursorX;
|
|
259
|
-
let hasOutput = false;
|
|
260
|
-
let cell = undefined;
|
|
261
|
-
for (let i = 0; i < this.#terminal.cols; i++) {
|
|
262
|
-
cell = line?.getCell(i, cell);
|
|
263
|
-
if (cell == null)
|
|
264
|
-
continue;
|
|
265
|
-
hasOutput = cell.getChars() != "";
|
|
266
|
-
if (hasOutput) {
|
|
267
|
-
break;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const postfixActive = isWrapped
|
|
271
|
-
? wrappedCommand.trim().length < this.#terminal.buffer.active.cursorX
|
|
272
|
-
: this.#activeCommand.promptText.length + command.trimEnd().length < this.#terminal.buffer.active.cursorX;
|
|
273
|
-
const commandPostfix = postfixActive ? " " : "";
|
|
273
|
+
const commandLines = this._getCommandLines();
|
|
274
|
+
const { suggestion, preCursorCommand, postCursorCommand } = this._getCommandText(commandLines);
|
|
275
|
+
const command = preCursorCommand + postCursorCommand.trim();
|
|
276
|
+
const cursorAtEndOfInput = postCursorCommand.trim() == "";
|
|
277
|
+
const hasOutput = this._getCommandOutputStatus(commandLines.length);
|
|
274
278
|
this.#activeCommand.persistentOutput = this.#activeCommand.hasOutput && hasOutput;
|
|
275
279
|
this.#activeCommand.hasOutput = hasOutput;
|
|
276
|
-
this.#activeCommand.suggestionsText =
|
|
277
|
-
this.#activeCommand.commandText = command
|
|
280
|
+
this.#activeCommand.suggestionsText = suggestion;
|
|
281
|
+
this.#activeCommand.commandText = command;
|
|
278
282
|
this.#activeCommand.cursorTerminated = cursorAtEndOfInput;
|
|
279
283
|
}
|
|
280
284
|
log.debug({
|
|
@@ -282,6 +286,8 @@ export class CommandManager {
|
|
|
282
286
|
...this.#activeCommand,
|
|
283
287
|
promptEndMarker: this.#activeCommand.promptEndMarker?.line,
|
|
284
288
|
promptStartMarker: this.#activeCommand.promptStartMarker?.line,
|
|
289
|
+
cursorX: this.#terminal.buffer.active.cursorX,
|
|
290
|
+
cursorY: globalCursorPosition,
|
|
285
291
|
});
|
|
286
292
|
}
|
|
287
293
|
}
|
package/build/isterm/pty.js
CHANGED
|
@@ -6,6 +6,7 @@ import os from "node:os";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import url from "node:url";
|
|
8
8
|
import fs from "node:fs";
|
|
9
|
+
import stripAnsi from "strip-ansi";
|
|
9
10
|
import pty from "@homebridge/node-pty-prebuilt-multiarch";
|
|
10
11
|
import { Shell, userZdotdir, zdotdir } from "../utils/shell.js";
|
|
11
12
|
import { IsTermOscPs, IstermOscPt, IstermPromptStart, IstermPromptEnd } from "../utils/ansi.js";
|
|
@@ -13,8 +14,8 @@ import xterm from "@xterm/headless";
|
|
|
13
14
|
import { CommandManager } from "./commandManager.js";
|
|
14
15
|
import log from "../utils/log.js";
|
|
15
16
|
import { gitBashPath } from "../utils/shell.js";
|
|
16
|
-
import ansi from "ansi-escapes";
|
|
17
17
|
import styles from "ansi-styles";
|
|
18
|
+
import * as ansi from "../utils/ansi.js";
|
|
18
19
|
const ISTermOnDataEvent = "data";
|
|
19
20
|
export class ISTerm {
|
|
20
21
|
pid;
|
|
@@ -84,6 +85,9 @@ export class ISTerm {
|
|
|
84
85
|
}
|
|
85
86
|
return cwd;
|
|
86
87
|
}
|
|
88
|
+
_sanitizedPrompt(prompt) {
|
|
89
|
+
return stripAnsi(prompt);
|
|
90
|
+
}
|
|
87
91
|
_handleIsSequence(data) {
|
|
88
92
|
const argsIndex = data.indexOf(";");
|
|
89
93
|
const sequence = argsIndex === -1 ? data : data.substring(0, argsIndex);
|
|
@@ -101,6 +105,19 @@ export class ISTerm {
|
|
|
101
105
|
}
|
|
102
106
|
break;
|
|
103
107
|
}
|
|
108
|
+
case IstermOscPt.Prompt: {
|
|
109
|
+
const prompt = data.split(";").slice(1).join(";");
|
|
110
|
+
if (prompt != null) {
|
|
111
|
+
const sanitizedPrompt = this._sanitizedPrompt(this._deserializeIsMessage(prompt));
|
|
112
|
+
const lastPromptLine = sanitizedPrompt.substring(sanitizedPrompt.lastIndexOf("\n")).trim();
|
|
113
|
+
const promptTerminator = lastPromptLine.substring(lastPromptLine.lastIndexOf(" ")).trim();
|
|
114
|
+
if (promptTerminator) {
|
|
115
|
+
this.#commandManager.promptTerminator = promptTerminator;
|
|
116
|
+
log.debug({ msg: "prompt terminator", promptTerminator });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
104
121
|
default:
|
|
105
122
|
return false;
|
|
106
123
|
}
|
|
@@ -216,7 +233,7 @@ export class ISTerm {
|
|
|
216
233
|
const currentCursorPosition = this.#term.buffer.active.cursorY + this.#term.buffer.active.baseY;
|
|
217
234
|
const writeLine = (y) => {
|
|
218
235
|
const line = this.#term.buffer.active.getLine(y);
|
|
219
|
-
const ansiLine = [
|
|
236
|
+
const ansiLine = [ansi.resetColor, ansi.resetLine];
|
|
220
237
|
if (line == null)
|
|
221
238
|
return "";
|
|
222
239
|
let prevCell;
|
|
@@ -226,7 +243,7 @@ export class ISTerm {
|
|
|
226
243
|
const sameColor = this._sameColor(prevCell, cell);
|
|
227
244
|
const sameAccents = this._sameAccent(prevCell, cell);
|
|
228
245
|
if (!sameColor || !sameAccents) {
|
|
229
|
-
ansiLine.push(
|
|
246
|
+
ansiLine.push(ansi.resetColor);
|
|
230
247
|
}
|
|
231
248
|
if (!sameColor) {
|
|
232
249
|
ansiLine.push(this._getAnsiColors(cell));
|
|
@@ -234,7 +251,7 @@ export class ISTerm {
|
|
|
234
251
|
if (!sameAccents) {
|
|
235
252
|
ansiLine.push(this._getAnsiAccents(cell));
|
|
236
253
|
}
|
|
237
|
-
ansiLine.push(chars == "" ?
|
|
254
|
+
ansiLine.push(chars == "" ? ansi.cursorForward() : chars);
|
|
238
255
|
prevCell = cell;
|
|
239
256
|
}
|
|
240
257
|
return ansiLine.join("");
|
|
@@ -275,7 +292,10 @@ const convertToPtyTarget = async (shell, underTest, login) => {
|
|
|
275
292
|
shellArgs = ["-noexit", "-command", `try { . "${path.join(shellFolderPath, "shellIntegration.ps1")}" } catch {}`];
|
|
276
293
|
break;
|
|
277
294
|
case Shell.Fish:
|
|
278
|
-
shellArgs =
|
|
295
|
+
shellArgs =
|
|
296
|
+
platform == "win32"
|
|
297
|
+
? ["--init-command", `. "$(cygpath -u '${path.join(shellFolderPath, "shellIntegration.fish")}')"`]
|
|
298
|
+
: ["--init-command", `. ${path.join(shellFolderPath, "shellIntegration.fish").replace(/(\s+)/g, "\\$1")}`];
|
|
279
299
|
break;
|
|
280
300
|
case Shell.Xonsh: {
|
|
281
301
|
const sharedConfig = os.platform() == "win32" ? path.join("C:\\ProgramData", "xonsh", "xonshrc") : path.join("etc", "xonsh", "xonshrc");
|
|
@@ -19,6 +19,7 @@ export class SuggestionManager {
|
|
|
19
19
|
#activeSuggestionIdx;
|
|
20
20
|
#suggestBlob;
|
|
21
21
|
#shell;
|
|
22
|
+
#hideSuggestions = false;
|
|
22
23
|
constructor(terminal, shell) {
|
|
23
24
|
this.#term = terminal;
|
|
24
25
|
this.#suggestBlob = { suggestions: [] };
|
|
@@ -28,7 +29,7 @@ export class SuggestionManager {
|
|
|
28
29
|
}
|
|
29
30
|
async _loadSuggestions() {
|
|
30
31
|
const commandText = this.#term.getCommandState().commandText;
|
|
31
|
-
if (!commandText) {
|
|
32
|
+
if (!commandText || this.#hideSuggestions) {
|
|
32
33
|
this.#suggestBlob = undefined;
|
|
33
34
|
this.#activeSuggestionIdx = 0;
|
|
34
35
|
return;
|
|
@@ -125,12 +126,17 @@ export class SuggestionManager {
|
|
|
125
126
|
if (name == "return") {
|
|
126
127
|
this.#term.clearCommand(); // clear the current command on enter
|
|
127
128
|
}
|
|
129
|
+
// if suggestions are hidden, keep them hidden until during command navigation
|
|
130
|
+
if (this.#hideSuggestions) {
|
|
131
|
+
this.#hideSuggestions = name == "up" || name == "down";
|
|
132
|
+
}
|
|
128
133
|
if (!this.#suggestBlob) {
|
|
129
134
|
return false;
|
|
130
135
|
}
|
|
131
136
|
const { dismissSuggestions: { key: dismissKey, shift: dismissShift, control: dismissCtrl }, acceptSuggestion: { key: acceptKey, shift: acceptShift, control: acceptCtrl }, nextSuggestion: { key: nextKey, shift: nextShift, control: nextCtrl }, previousSuggestion: { key: prevKey, shift: prevShift, control: prevCtrl }, } = getConfig().bindings;
|
|
132
137
|
if (name == dismissKey && shift == !!dismissShift && ctrl == !!dismissCtrl) {
|
|
133
138
|
this.#suggestBlob = undefined;
|
|
139
|
+
this.#hideSuggestions = true;
|
|
134
140
|
}
|
|
135
141
|
else if (name == prevKey && shift == !!prevShift && ctrl == !!prevCtrl) {
|
|
136
142
|
this.#activeSuggestionIdx = Math.max(0, this.#activeSuggestionIdx - 1);
|
package/build/ui/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
import ansi from "ansi-escapes";
|
|
4
|
+
import { resetColor } from "../utils/ansi.js";
|
|
4
5
|
import wrapAnsi from "wrap-ansi";
|
|
5
6
|
import chalk from "chalk";
|
|
6
7
|
import wcwidth from "wcwidth";
|
|
@@ -12,7 +13,7 @@ import wcwidth from "wcwidth";
|
|
|
12
13
|
*/
|
|
13
14
|
export const renderBox = (rows, width, x, borderColor) => {
|
|
14
15
|
const result = [];
|
|
15
|
-
const setColor = (text) => (borderColor ? chalk.hex(borderColor).apply(text) : text);
|
|
16
|
+
const setColor = (text) => resetColor + (borderColor ? chalk.hex(borderColor).apply(text) : text);
|
|
16
17
|
result.push(ansi.cursorTo(x) + setColor("┌" + "─".repeat(width - 2) + "┐") + ansi.cursorTo(x));
|
|
17
18
|
rows.forEach((row) => {
|
|
18
19
|
result.push(ansi.cursorDown() + setColor("│") + row + setColor("│") + ansi.cursorTo(x));
|
package/build/utils/ansi.js
CHANGED
|
@@ -11,6 +11,7 @@ export var IstermOscPt;
|
|
|
11
11
|
IstermOscPt["PromptStarted"] = "PS";
|
|
12
12
|
IstermOscPt["PromptEnded"] = "PE";
|
|
13
13
|
IstermOscPt["CurrentWorkingDirectory"] = "CWD";
|
|
14
|
+
IstermOscPt["Prompt"] = "PROMPT";
|
|
14
15
|
})(IstermOscPt || (IstermOscPt = {}));
|
|
15
16
|
export const IstermPromptStart = IS_OSC + IstermOscPt.PromptStarted + BEL;
|
|
16
17
|
export const IstermPromptEnd = IS_OSC + IstermOscPt.PromptEnded + BEL;
|
|
@@ -18,7 +19,10 @@ export const cursorHide = CSI + "?25l";
|
|
|
18
19
|
export const cursorShow = CSI + "?25h";
|
|
19
20
|
export const cursorNextLine = CSI + "E";
|
|
20
21
|
export const eraseLine = CSI + "2K";
|
|
22
|
+
export const resetColor = CSI + "0m";
|
|
23
|
+
export const resetLine = CSI + "2K";
|
|
21
24
|
export const cursorBackward = (count = 1) => CSI + count + "D";
|
|
25
|
+
export const cursorForward = (count = 1) => CSI + count + "C";
|
|
22
26
|
export const cursorTo = ({ x, y }) => {
|
|
23
27
|
return CSI + (y ?? "") + ";" + (x ?? "") + "H";
|
|
24
28
|
};
|
package/build/utils/config.js
CHANGED
|
@@ -49,6 +49,7 @@ const configSchema = {
|
|
|
49
49
|
acceptSuggestion: bindingSchema,
|
|
50
50
|
},
|
|
51
51
|
},
|
|
52
|
+
// DEPRECATED: prompt patterns are no longer used
|
|
52
53
|
prompt: {
|
|
53
54
|
type: "object",
|
|
54
55
|
nullable: true,
|
|
@@ -58,6 +59,7 @@ const configSchema = {
|
|
|
58
59
|
powershell: promptPatternsSchema,
|
|
59
60
|
xonsh: promptPatternsSchema,
|
|
60
61
|
nu: promptPatternsSchema,
|
|
62
|
+
fish: promptPatternsSchema,
|
|
61
63
|
},
|
|
62
64
|
},
|
|
63
65
|
specs: {
|
|
@@ -70,9 +72,12 @@ const configSchema = {
|
|
|
70
72
|
},
|
|
71
73
|
additionalProperties: false,
|
|
72
74
|
};
|
|
73
|
-
const
|
|
75
|
+
const rcFile = ".inshellisenserc";
|
|
76
|
+
const xdgFile = "rc.toml";
|
|
74
77
|
const cachePath = path.join(os.homedir(), ".inshellisense");
|
|
75
|
-
const
|
|
78
|
+
const rcPath = path.join(os.homedir(), rcFile);
|
|
79
|
+
const xdgPath = path.join(os.homedir(), ".config", "inshellisense", xdgFile);
|
|
80
|
+
const configPaths = [rcPath, xdgPath];
|
|
76
81
|
let globalConfig = {
|
|
77
82
|
bindings: {
|
|
78
83
|
nextSuggestion: { key: "down" },
|
|
@@ -83,38 +88,42 @@ let globalConfig = {
|
|
|
83
88
|
};
|
|
84
89
|
export const getConfig = () => globalConfig;
|
|
85
90
|
export const loadConfig = async (program) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
configPaths.forEach(async (configPath) => {
|
|
92
|
+
if (fs.existsSync(configPath)) {
|
|
93
|
+
let config;
|
|
94
|
+
try {
|
|
95
|
+
config = toml.parse((await fsAsync.readFile(configPath)).toString());
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
program.error(`${configPath} is invalid toml. Parsing error on line ${e.line}, column ${e.column}: ${e.message}`);
|
|
100
|
+
}
|
|
101
|
+
const isValid = ajv.validate(configSchema, config);
|
|
102
|
+
if (!isValid) {
|
|
103
|
+
program.error(`${configPath} is invalid: ${ajv.errorsText()}`);
|
|
104
|
+
}
|
|
105
|
+
globalConfig = {
|
|
106
|
+
bindings: {
|
|
107
|
+
nextSuggestion: config?.bindings?.nextSuggestion ?? globalConfig.bindings.nextSuggestion,
|
|
108
|
+
previousSuggestion: config?.bindings?.previousSuggestion ?? globalConfig.bindings.previousSuggestion,
|
|
109
|
+
acceptSuggestion: config?.bindings?.acceptSuggestion ?? globalConfig.bindings.acceptSuggestion,
|
|
110
|
+
dismissSuggestions: config?.bindings?.dismissSuggestions ?? globalConfig.bindings.dismissSuggestions,
|
|
111
|
+
},
|
|
112
|
+
prompt: {
|
|
113
|
+
bash: config.prompt?.bash ?? globalConfig?.prompt?.bash,
|
|
114
|
+
powershell: config.prompt?.powershell ?? globalConfig?.prompt?.powershell,
|
|
115
|
+
xonsh: config.prompt?.xonsh ?? globalConfig?.prompt?.xonsh,
|
|
116
|
+
pwsh: config.prompt?.pwsh ?? globalConfig?.prompt?.pwsh,
|
|
117
|
+
nu: config.prompt?.nu ?? globalConfig?.prompt?.nu,
|
|
118
|
+
fish: config.prompt?.fish ?? globalConfig?.prompt?.fish,
|
|
119
|
+
},
|
|
120
|
+
specs: {
|
|
121
|
+
path: [...(config?.specs?.path ?? []), ...(config?.specs?.path ?? [])],
|
|
122
|
+
},
|
|
123
|
+
};
|
|
91
124
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
const isValid = ajv.validate(configSchema, config);
|
|
96
|
-
if (!isValid) {
|
|
97
|
-
program.error(`${configFile} is invalid: ${ajv.errorsText()}`);
|
|
98
|
-
}
|
|
99
|
-
globalConfig = {
|
|
100
|
-
bindings: {
|
|
101
|
-
nextSuggestion: config?.bindings?.nextSuggestion ?? globalConfig.bindings.nextSuggestion,
|
|
102
|
-
previousSuggestion: config?.bindings?.previousSuggestion ?? globalConfig.bindings.previousSuggestion,
|
|
103
|
-
acceptSuggestion: config?.bindings?.acceptSuggestion ?? globalConfig.bindings.acceptSuggestion,
|
|
104
|
-
dismissSuggestions: config?.bindings?.dismissSuggestions ?? globalConfig.bindings.dismissSuggestions,
|
|
105
|
-
},
|
|
106
|
-
prompt: {
|
|
107
|
-
bash: config.prompt?.bash,
|
|
108
|
-
powershell: config.prompt?.powershell,
|
|
109
|
-
xonsh: config.prompt?.xonsh,
|
|
110
|
-
pwsh: config.prompt?.pwsh,
|
|
111
|
-
nu: config.prompt?.nu,
|
|
112
|
-
},
|
|
113
|
-
specs: {
|
|
114
|
-
path: [`${os.homedir()}/.fig/autocomplete/build`, ...(config?.specs?.path ?? [])],
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
}
|
|
125
|
+
});
|
|
126
|
+
globalConfig.specs = { path: [`${os.homedir()}/.fig/autocomplete/build`, ...(globalConfig.specs?.path ?? [])] };
|
|
118
127
|
};
|
|
119
128
|
export const deleteCacheFolder = async () => {
|
|
120
129
|
const cliConfigPath = path.join(os.homedir(), cachePath);
|
package/build/utils/shell.js
CHANGED
|
@@ -50,6 +50,23 @@ export const setupZshDotfiles = async () => {
|
|
|
50
50
|
await fsAsync.cp(path.join(shellFolderPath, "shellIntegration-login.zsh"), path.join(zdotdir, ".zlogin"));
|
|
51
51
|
};
|
|
52
52
|
export const inferShell = async () => {
|
|
53
|
+
// try getting shell from shell specific env variables
|
|
54
|
+
if (process.env.NU_VERSION != null) {
|
|
55
|
+
return Shell.Nushell;
|
|
56
|
+
}
|
|
57
|
+
else if (process.env.XONSHRC != null) {
|
|
58
|
+
return Shell.Xonsh;
|
|
59
|
+
}
|
|
60
|
+
else if (process.env.FISH_VERSION != null) {
|
|
61
|
+
return Shell.Fish;
|
|
62
|
+
}
|
|
63
|
+
else if (process.env.ZSH_VERSION != null) {
|
|
64
|
+
return Shell.Zsh;
|
|
65
|
+
}
|
|
66
|
+
else if (process.env.BASH_VERSION != null) {
|
|
67
|
+
return Shell.Bash;
|
|
68
|
+
}
|
|
69
|
+
// try getting shell from env
|
|
53
70
|
try {
|
|
54
71
|
const name = path.parse(process.env.SHELL ?? "").name;
|
|
55
72
|
const shellName = supportedShells.find((shell) => name.includes(shell));
|
|
@@ -59,6 +76,7 @@ export const inferShell = async () => {
|
|
|
59
76
|
catch {
|
|
60
77
|
/* empty */
|
|
61
78
|
}
|
|
79
|
+
// try getting shell from parent process
|
|
62
80
|
const processResult = (await find("pid", process.ppid)).at(0);
|
|
63
81
|
const name = processResult?.name;
|
|
64
82
|
return name != null ? supportedShells.find((shell) => name.includes(shell)) : undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microsoft/inshellisense",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.15",
|
|
4
4
|
"description": "IDE style command line auto complete",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"color-convert": "^2.0.1",
|
|
50
50
|
"commander": "^11.0.0",
|
|
51
51
|
"find-process": "^1.4.7",
|
|
52
|
+
"strip-ansi": "^7.1.0",
|
|
52
53
|
"toml": "^3.0.0",
|
|
53
54
|
"wcwidth": "^1.0.1",
|
|
54
55
|
"which": "^4.0.0",
|
|
@@ -40,6 +40,10 @@ __is_escape_value() {
|
|
|
40
40
|
token="\\\\"
|
|
41
41
|
elif [ "$byte" = ";" ]; then
|
|
42
42
|
token="\\x3b"
|
|
43
|
+
elif [ "$byte" = $'\n' ]; then
|
|
44
|
+
token="\x0a"
|
|
45
|
+
elif [ "$byte" = $'\e' ]; then
|
|
46
|
+
token="\\x1b"
|
|
43
47
|
else
|
|
44
48
|
token="$byte"
|
|
45
49
|
fi
|
|
@@ -54,6 +58,16 @@ __is_update_cwd() {
|
|
|
54
58
|
builtin printf '\e]6973;CWD;%s\a' "$(__is_escape_value "$PWD")"
|
|
55
59
|
}
|
|
56
60
|
|
|
61
|
+
__is_report_prompt() {
|
|
62
|
+
if ((BASH_VERSINFO[0] >= 4)); then
|
|
63
|
+
__is_prompt=${__is_original_PS1@P}
|
|
64
|
+
else
|
|
65
|
+
__is_prompt=${__is_original_PS1}
|
|
66
|
+
fi
|
|
67
|
+
__is_prompt="$(builtin printf "%s" "${__is_prompt//[$'\001'$'\002']}")"
|
|
68
|
+
builtin printf "\e]6973;PROMPT;%s\a" "$(__is_escape_value "${__is_prompt}")"
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
if [[ -n "${bash_preexec_imported:-}" ]]; then
|
|
58
72
|
precmd_functions+=(__is_precmd)
|
|
59
73
|
fi
|
|
@@ -61,6 +75,7 @@ fi
|
|
|
61
75
|
__is_precmd() {
|
|
62
76
|
__is_update_cwd
|
|
63
77
|
__is_update_prompt
|
|
78
|
+
__is_report_prompt
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
__is_update_prompt() {
|
|
@@ -2,15 +2,18 @@ function __is_copy_function; functions $argv[1] | sed "s/^function $argv[1]/func
|
|
|
2
2
|
function __is_prompt_start; printf '\e]6973;PS\a'; end
|
|
3
3
|
function __is_prompt_end; printf '\e]6973;PE\a'; end
|
|
4
4
|
|
|
5
|
+
__is_copy_function fish_prompt is_user_prompt
|
|
6
|
+
|
|
5
7
|
function __is_escape_value
|
|
6
8
|
echo $argv \
|
|
7
|
-
| string replace
|
|
8
|
-
| string replace
|
|
9
|
+
| string replace -a '\\' '\\\\' \
|
|
10
|
+
| string replace -a ';' '\\x3b' \
|
|
11
|
+
| string replace -a \e '\\x1b' \
|
|
12
|
+
| string split \n | string join '\x0a' \
|
|
9
13
|
;
|
|
10
14
|
end
|
|
11
|
-
function __is_update_cwd --on-event fish_prompt; set __is_cwd (__is_escape_value "$PWD"); printf "\e]6973;CWD
|
|
12
|
-
|
|
13
|
-
__is_copy_function fish_prompt is_user_prompt
|
|
15
|
+
function __is_update_cwd --on-event fish_prompt; set __is_cwd (__is_escape_value "$PWD"); printf "\e]6973;CWD;%s\a" $__is_cwd; end
|
|
16
|
+
function __is_report_prompt --on-event fish_prompt; set __is_prompt (__is_escape_value (is_user_prompt)); printf "\e]6973;PROMPT;%s\a" $__is_prompt; end
|
|
14
17
|
|
|
15
18
|
if [ "$ISTERM_TESTING" = "1" ]
|
|
16
19
|
function is_user_prompt; printf '> '; end
|
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
let __is_escape_value = {|x| $x | str replace --all "\\" "\\\\" | str replace --all ";" "\\x3b" }
|
|
1
|
+
let __is_escape_value = {|x| $x | str replace --all "\\" "\\\\" | str replace --all ";" "\\x3b" | str replace --all "\n" '\x0a' | str replace --all "\e" "\\x1b" }
|
|
2
|
+
let __is_original_PROMPT_COMMAND = if 'PROMPT_COMMAND' in $env { $env.PROMPT_COMMAND } else { "" }
|
|
3
|
+
let __is_original_PROMPT_INDICATOR = if 'PROMPT_INDICATOR' in $env { $env.PROMPT_INDICATOR } else { "" }
|
|
2
4
|
|
|
3
5
|
let __is_update_cwd = {
|
|
4
6
|
let pwd = do $__is_escape_value $env.PWD
|
|
5
7
|
$"\e]6973;CWD;($pwd)\a"
|
|
6
8
|
}
|
|
7
|
-
let
|
|
9
|
+
let __is_report_prompt = {
|
|
10
|
+
let __is_indicatorCommandType = $__is_original_PROMPT_INDICATOR | describe
|
|
11
|
+
mut __is_prompt_ind = if $__is_indicatorCommandType == "closure" { do $__is_original_PROMPT_INDICATOR } else { $__is_original_PROMPT_INDICATOR }
|
|
12
|
+
let __is_esc_prompt_ind = do $__is_escape_value $__is_prompt_ind
|
|
13
|
+
$"\e]6973;PROMPT;($__is_esc_prompt_ind)\a"
|
|
14
|
+
}
|
|
8
15
|
let __is_custom_PROMPT_COMMAND = {
|
|
9
16
|
let promptCommandType = $__is_original_PROMPT_COMMAND | describe
|
|
10
17
|
mut cmd = if $promptCommandType == "closure" { do $__is_original_PROMPT_COMMAND } else { $__is_original_PROMPT_COMMAND }
|
|
11
18
|
let pwd = do $__is_update_cwd
|
|
19
|
+
let prompt = do $__is_report_prompt
|
|
12
20
|
if 'ISTERM_TESTING' in $env {
|
|
13
21
|
$cmd = ""
|
|
14
22
|
}
|
|
15
|
-
$"\e]6973;PS\a($cmd)($pwd)"
|
|
23
|
+
$"\e]6973;PS\a($cmd)($pwd)($prompt)"
|
|
16
24
|
}
|
|
17
25
|
$env.PROMPT_COMMAND = $__is_custom_PROMPT_COMMAND
|
|
18
26
|
|
|
@@ -8,7 +8,7 @@ if ($env:ISTERM_TESTING -eq "1") {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
function Global:__IS-Escape-Value([string]$value) {
|
|
11
|
-
[regex]::Replace($value,
|
|
11
|
+
[regex]::Replace($value, "[$([char]0x1b)\\\n;]", { param($match)
|
|
12
12
|
-Join (
|
|
13
13
|
[System.Text.Encoding]::UTF8.GetBytes($match.Value) | ForEach-Object { '\x{0:x2}' -f $_ }
|
|
14
14
|
)
|
|
@@ -17,8 +17,11 @@ function Global:__IS-Escape-Value([string]$value) {
|
|
|
17
17
|
|
|
18
18
|
function Global:Prompt() {
|
|
19
19
|
$Result = "$([char]0x1b)]6973;PS`a"
|
|
20
|
-
$
|
|
20
|
+
$OriginalPrompt += $Global:__IsOriginalPrompt.Invoke()
|
|
21
|
+
$Result += $OriginalPrompt
|
|
21
22
|
$Result += "$([char]0x1b)]6973;PE`a"
|
|
23
|
+
|
|
24
|
+
$Result += "$([char]0x1b)]6973;PROMPT;$(__IS-Escape-Value $OriginalPrompt)`a"
|
|
22
25
|
$Result += if ($pwd.Provider.Name -eq 'FileSystem') { "$([char]0x1b)]6973;CWD;$(__IS-Escape-Value $pwd.ProviderPath)`a" }
|
|
23
26
|
return $Result
|
|
24
27
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from xonsh.main import XSH
|
|
2
3
|
|
|
3
4
|
def __is_prompt_start() -> str:
|
|
4
5
|
return "\001" + "\x1b]6973;PS\x07"
|
|
@@ -7,23 +8,30 @@ def __is_prompt_start() -> str:
|
|
|
7
8
|
def __is_prompt_end() -> str:
|
|
8
9
|
return "\001" + "\x1b]6973;PE\x07" + "\002"
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
def __is_escape_value(value: str) -> str:
|
|
12
12
|
byte_list = [bytes([byte]).decode("utf-8") for byte in list(value.encode("utf-8"))]
|
|
13
13
|
return "".join(
|
|
14
14
|
[
|
|
15
|
-
"\\x3b" if byte == ";" else "\\\\" if byte == "\\" else byte
|
|
15
|
+
"\\x3b" if byte == ";" else "\\\\" if byte == "\\" else "\\x1b" if byte == "\x1b" else "\x0a" if byte == "\n" else byte
|
|
16
16
|
for byte in byte_list
|
|
17
17
|
]
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
def __is_update_cwd() -> str:
|
|
21
|
-
return f"\x1b]6973;CWD;{__is_escape_value(os.getcwd())}\x07"
|
|
21
|
+
return f"\x1b]6973;CWD;{__is_escape_value(os.getcwd())}\x07"
|
|
22
|
+
|
|
23
|
+
__is_original_prompt = $PROMPT
|
|
24
|
+
def __is_report_prompt() -> str:
|
|
25
|
+
prompt = ""
|
|
26
|
+
formatted_prompt = XSH.shell.prompt_formatter(__is_original_prompt)
|
|
27
|
+
prompt = "".join([text for _, text in XSH.shell.format_color(formatted_prompt)])
|
|
28
|
+
return f"\x1b]6973;PROMPT;{__is_escape_value(prompt)}\x07" + "\002"
|
|
22
29
|
|
|
23
30
|
$PROMPT_FIELDS['__is_prompt_start'] = __is_prompt_start
|
|
24
31
|
$PROMPT_FIELDS['__is_prompt_end'] = __is_prompt_end
|
|
25
32
|
$PROMPT_FIELDS['__is_update_cwd'] = __is_update_cwd
|
|
33
|
+
$PROMPT_FIELDS['__is_report_prompt'] = __is_report_prompt
|
|
26
34
|
if 'ISTERM_TESTING' in ${...}:
|
|
27
35
|
$PROMPT = "> "
|
|
28
36
|
|
|
29
|
-
$PROMPT = "{__is_prompt_start}{__is_update_cwd}" + $PROMPT + "{__is_prompt_end}"
|
|
37
|
+
$PROMPT = "{__is_prompt_start}{__is_update_cwd}{__is_report_prompt}" + $PROMPT + "{__is_prompt_end}"
|