@microsoft/inshellisense 0.0.1-rc.21 → 0.0.1-rc.23
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/package.json +11 -78
- package/CODE_OF_CONDUCT.md +0 -9
- package/LICENSE +0 -21
- package/README.md +0 -132
- package/SECURITY.md +0 -41
- package/SUPPORT.md +0 -13
- package/build/commands/complete.js +0 -16
- package/build/commands/doctor.js +0 -11
- package/build/commands/init.js +0 -24
- package/build/commands/root.js +0 -37
- package/build/commands/specs/list.js +0 -26
- package/build/commands/specs/root.js +0 -8
- package/build/commands/uninstall.js +0 -11
- package/build/index.js +0 -35
- package/build/isterm/commandManager.js +0 -184
- package/build/isterm/index.js +0 -4
- package/build/isterm/pty.js +0 -361
- package/build/runtime/alias.js +0 -66
- package/build/runtime/generator.js +0 -55
- package/build/runtime/model.js +0 -3
- package/build/runtime/parser.js +0 -133
- package/build/runtime/runtime.js +0 -282
- package/build/runtime/spec.js +0 -36
- package/build/runtime/suggestion.js +0 -232
- package/build/runtime/template.js +0 -50
- package/build/runtime/utils.js +0 -121
- package/build/ui/suggestionManager.js +0 -162
- package/build/ui/ui-doctor.js +0 -69
- package/build/ui/ui-root.js +0 -141
- package/build/ui/ui-uninstall.js +0 -9
- package/build/ui/utils.js +0 -57
- package/build/utils/ansi.js +0 -37
- package/build/utils/config.js +0 -99
- package/build/utils/log.js +0 -39
- package/build/utils/shell.js +0 -318
- package/build/utils/version.js +0 -13
- package/scripts/postinstall.js +0 -9
- package/shell/bash-preexec.sh +0 -380
- package/shell/shellIntegration-env.zsh +0 -12
- package/shell/shellIntegration-login.zsh +0 -9
- package/shell/shellIntegration-profile.zsh +0 -9
- package/shell/shellIntegration-rc.zsh +0 -66
- package/shell/shellIntegration.bash +0 -114
- package/shell/shellIntegration.fish +0 -27
- package/shell/shellIntegration.nu +0 -29
- package/shell/shellIntegration.ps1 +0 -26
- package/shell/shellIntegration.xsh +0 -31
- package/todo.md +0 -17
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import fsAsync from "node:fs/promises";
|
|
4
|
-
import log from "../utils/log.js";
|
|
5
|
-
const filepathsTemplate = async (cwd) => {
|
|
6
|
-
const files = await fsAsync.readdir(cwd, { withFileTypes: true });
|
|
7
|
-
return files
|
|
8
|
-
.filter((f) => f.isFile() || f.isDirectory())
|
|
9
|
-
.map((f) => ({ name: f.name, priority: 55, context: { templateType: "filepaths" }, type: f.isDirectory() ? "folder" : "file" }));
|
|
10
|
-
};
|
|
11
|
-
const foldersTemplate = async (cwd) => {
|
|
12
|
-
const files = await fsAsync.readdir(cwd, { withFileTypes: true });
|
|
13
|
-
return files
|
|
14
|
-
.filter((f) => f.isDirectory())
|
|
15
|
-
.map((f) => ({
|
|
16
|
-
name: f.name,
|
|
17
|
-
priority: 55,
|
|
18
|
-
context: { templateType: "folders" },
|
|
19
|
-
type: "folder",
|
|
20
|
-
}));
|
|
21
|
-
};
|
|
22
|
-
// TODO: implement history template
|
|
23
|
-
const historyTemplate = () => {
|
|
24
|
-
return [];
|
|
25
|
-
};
|
|
26
|
-
// TODO: implement help template
|
|
27
|
-
const helpTemplate = () => {
|
|
28
|
-
return [];
|
|
29
|
-
};
|
|
30
|
-
export const runTemplates = async (template, cwd) => {
|
|
31
|
-
const templates = template instanceof Array ? template : [template];
|
|
32
|
-
return (await Promise.all(templates.map(async (t) => {
|
|
33
|
-
try {
|
|
34
|
-
switch (t) {
|
|
35
|
-
case "filepaths":
|
|
36
|
-
return await filepathsTemplate(cwd);
|
|
37
|
-
case "folders":
|
|
38
|
-
return await foldersTemplate(cwd);
|
|
39
|
-
case "history":
|
|
40
|
-
return historyTemplate();
|
|
41
|
-
case "help":
|
|
42
|
-
return helpTemplate();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
catch (e) {
|
|
46
|
-
log.debug({ msg: "template failed", e, template: t, cwd });
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
}))).flat();
|
|
50
|
-
};
|
package/build/runtime/utils.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
|
-
import fsAsync from "node:fs/promises";
|
|
6
|
-
import { getPathSeparator, gitBashPath, Shell } from "../utils/shell.js";
|
|
7
|
-
import log from "../utils/log.js";
|
|
8
|
-
const getExecutionShell = async () => {
|
|
9
|
-
if (process.platform !== "win32")
|
|
10
|
-
return;
|
|
11
|
-
try {
|
|
12
|
-
return await gitBashPath();
|
|
13
|
-
}
|
|
14
|
-
catch (e) {
|
|
15
|
-
log.debug({ msg: "failed to load posix shell for windows child_process.spawn, some generators might fail", error: e });
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
const bashSpecialCharacters = /[&|<>\s]/g;
|
|
19
|
-
// escape whitespace & special characters in an argument when not quoted
|
|
20
|
-
const shouldEscapeArg = (arg) => {
|
|
21
|
-
const hasSpecialCharacter = bashSpecialCharacters.test(arg);
|
|
22
|
-
const isSingleCharacter = arg.length === 1;
|
|
23
|
-
return hasSpecialCharacter && !isSingleCharacter && !isQuoted(arg, `"`);
|
|
24
|
-
};
|
|
25
|
-
/* based on libuv process.c used by nodejs, only quotes are escaped for shells. if using git bash need to escape whitespace & special characters in an argument */
|
|
26
|
-
const escapeArgs = (shell, args) => {
|
|
27
|
-
// only escape args for git bash
|
|
28
|
-
if (process.platform !== "win32" || shell == undefined)
|
|
29
|
-
return args;
|
|
30
|
-
return args.map((arg) => (shouldEscapeArg(arg) ? `"${arg.replaceAll('"', '\\"')}"` : arg));
|
|
31
|
-
};
|
|
32
|
-
const isQuoted = (value, quoteChar) => (value?.startsWith(quoteChar) && value?.endsWith(quoteChar)) ?? false;
|
|
33
|
-
const quoteString = (value, quoteChar) => {
|
|
34
|
-
if (isQuoted(value, quoteChar))
|
|
35
|
-
return value;
|
|
36
|
-
const escapedValue = value.replaceAll(`\\${quoteChar}`, quoteChar).replaceAll(quoteChar, `\\${quoteChar}`);
|
|
37
|
-
return `${quoteChar}${escapedValue}${quoteChar}`;
|
|
38
|
-
};
|
|
39
|
-
const needsQuoted = (value, quoteChar) => isQuoted(value, quoteChar) || value.includes(" ");
|
|
40
|
-
const getShellQuoteChar = (shell) => {
|
|
41
|
-
switch (shell) {
|
|
42
|
-
case Shell.Zsh:
|
|
43
|
-
case Shell.Bash:
|
|
44
|
-
case Shell.Fish:
|
|
45
|
-
return `"`;
|
|
46
|
-
case Shell.Xonsh:
|
|
47
|
-
return `'`;
|
|
48
|
-
case Shell.Nushell:
|
|
49
|
-
return "`";
|
|
50
|
-
case Shell.Pwsh:
|
|
51
|
-
case Shell.Powershell:
|
|
52
|
-
return `'`;
|
|
53
|
-
case Shell.Cmd:
|
|
54
|
-
return `"`;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
export const getShellWhitespaceEscapeChar = (shell) => {
|
|
58
|
-
switch (shell) {
|
|
59
|
-
case Shell.Zsh:
|
|
60
|
-
case Shell.Bash:
|
|
61
|
-
case Shell.Fish:
|
|
62
|
-
case Shell.Xonsh:
|
|
63
|
-
case Shell.Nushell:
|
|
64
|
-
return "\\";
|
|
65
|
-
case Shell.Pwsh:
|
|
66
|
-
case Shell.Powershell:
|
|
67
|
-
return "`";
|
|
68
|
-
case Shell.Cmd:
|
|
69
|
-
return "^";
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
export const escapePath = (value, shell) => value != null && needsQuoted(value, getShellQuoteChar(shell)) ? quoteString(value, getShellQuoteChar(shell)) : value;
|
|
73
|
-
export const buildExecuteShellCommand = async (timeout) => async ({ command, env, args, cwd }) => {
|
|
74
|
-
const executionShell = await getExecutionShell();
|
|
75
|
-
const escapedArgs = escapeArgs(executionShell, args);
|
|
76
|
-
const child = spawn(command, escapedArgs, { cwd, env: { ...process.env, ...env, ISTERM: "1" }, shell: executionShell });
|
|
77
|
-
setTimeout(() => child.kill("SIGKILL"), timeout);
|
|
78
|
-
let stdout = "";
|
|
79
|
-
let stderr = "";
|
|
80
|
-
child.stdout.on("data", (data) => (stdout += data));
|
|
81
|
-
child.stderr.on("data", (data) => (stderr += data));
|
|
82
|
-
child.on("error", (err) => {
|
|
83
|
-
log.debug({ msg: "shell command failed", command, args, e: err.message });
|
|
84
|
-
});
|
|
85
|
-
return new Promise((resolve) => {
|
|
86
|
-
child.on("close", (code) => {
|
|
87
|
-
resolve({
|
|
88
|
-
status: code ?? 0,
|
|
89
|
-
stderr,
|
|
90
|
-
stdout,
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
};
|
|
95
|
-
export const resolveCwd = async (cmdToken, cwd, shell) => {
|
|
96
|
-
if (cmdToken == null)
|
|
97
|
-
return { cwd, pathy: false, complete: false };
|
|
98
|
-
const { token: rawToken, isQuoted } = cmdToken;
|
|
99
|
-
const escapedToken = !isQuoted ? rawToken.replaceAll(" ", "\\ ") : rawToken;
|
|
100
|
-
const token = escapedToken;
|
|
101
|
-
const sep = getPathSeparator(shell);
|
|
102
|
-
if (!token.includes(sep))
|
|
103
|
-
return { cwd, pathy: false, complete: false };
|
|
104
|
-
const resolvedCwd = path.isAbsolute(token) ? token : path.join(cwd, token);
|
|
105
|
-
try {
|
|
106
|
-
await fsAsync.access(resolvedCwd, fsAsync.constants.R_OK);
|
|
107
|
-
return { cwd: resolvedCwd, pathy: true, complete: token.endsWith(sep) };
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
// fallback to the parent folder if possible
|
|
111
|
-
const baselessCwd = resolvedCwd.substring(0, resolvedCwd.length - path.basename(resolvedCwd).length);
|
|
112
|
-
try {
|
|
113
|
-
await fsAsync.access(baselessCwd, fsAsync.constants.R_OK);
|
|
114
|
-
return { cwd: baselessCwd, pathy: true, complete: token.endsWith(sep) };
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
/*empty*/
|
|
118
|
-
}
|
|
119
|
-
return { cwd, pathy: false, complete: false };
|
|
120
|
-
}
|
|
121
|
-
};
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import { getSuggestions } from "../runtime/runtime.js";
|
|
4
|
-
import { renderBox, truncateText, truncateMultilineText } from "./utils.js";
|
|
5
|
-
import ansi from "ansi-escapes";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
import log from "../utils/log.js";
|
|
8
|
-
import { getConfig } from "../utils/config.js";
|
|
9
|
-
const maxSuggestions = 5;
|
|
10
|
-
const suggestionWidth = 40;
|
|
11
|
-
const descriptionWidth = 30;
|
|
12
|
-
const descriptionHeight = 5;
|
|
13
|
-
const borderWidth = 2;
|
|
14
|
-
const activeSuggestionBackgroundColor = "#7D56F4";
|
|
15
|
-
export const MAX_LINES = borderWidth + Math.max(maxSuggestions, descriptionHeight);
|
|
16
|
-
export class SuggestionManager {
|
|
17
|
-
#term;
|
|
18
|
-
#command;
|
|
19
|
-
#activeSuggestionIdx;
|
|
20
|
-
#suggestBlob;
|
|
21
|
-
#shell;
|
|
22
|
-
#hideSuggestions = false;
|
|
23
|
-
constructor(terminal, shell) {
|
|
24
|
-
this.#term = terminal;
|
|
25
|
-
this.#suggestBlob = { suggestions: [] };
|
|
26
|
-
this.#command = "";
|
|
27
|
-
this.#activeSuggestionIdx = 0;
|
|
28
|
-
this.#shell = shell;
|
|
29
|
-
}
|
|
30
|
-
async _loadSuggestions() {
|
|
31
|
-
const commandText = this.#term.getCommandState().commandText;
|
|
32
|
-
if (!commandText || this.#hideSuggestions) {
|
|
33
|
-
this.#suggestBlob = undefined;
|
|
34
|
-
this.#activeSuggestionIdx = 0;
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (commandText == this.#command) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
this.#command = commandText;
|
|
41
|
-
const suggestionBlob = await getSuggestions(commandText, this.#term.cwd, this.#shell);
|
|
42
|
-
this.#suggestBlob = suggestionBlob;
|
|
43
|
-
this.#activeSuggestionIdx = 0;
|
|
44
|
-
}
|
|
45
|
-
_renderArgumentDescription(description, x) {
|
|
46
|
-
if (!description)
|
|
47
|
-
return "";
|
|
48
|
-
return renderBox([truncateText(description, descriptionWidth - borderWidth)], descriptionWidth, x);
|
|
49
|
-
}
|
|
50
|
-
_renderDescription(description, x) {
|
|
51
|
-
if (!description)
|
|
52
|
-
return "";
|
|
53
|
-
return renderBox(truncateMultilineText(description, descriptionWidth - borderWidth, descriptionHeight), descriptionWidth, x);
|
|
54
|
-
}
|
|
55
|
-
_descriptionRows(description) {
|
|
56
|
-
if (!description)
|
|
57
|
-
return 0;
|
|
58
|
-
return truncateMultilineText(description, descriptionWidth - borderWidth, descriptionHeight).length;
|
|
59
|
-
}
|
|
60
|
-
_renderSuggestions(suggestions, activeSuggestionIdx, x) {
|
|
61
|
-
return renderBox(suggestions.map((suggestion, idx) => {
|
|
62
|
-
const suggestionText = `${suggestion.icon} ${suggestion.name}`;
|
|
63
|
-
const truncatedSuggestion = truncateText(suggestionText, suggestionWidth - 2);
|
|
64
|
-
return idx == activeSuggestionIdx ? chalk.bgHex(activeSuggestionBackgroundColor)(truncatedSuggestion) : truncatedSuggestion;
|
|
65
|
-
}), suggestionWidth, x);
|
|
66
|
-
}
|
|
67
|
-
validate(suggestion) {
|
|
68
|
-
const commandText = this.#term.getCommandState().commandText;
|
|
69
|
-
return !commandText ? { data: "", rows: 0 } : suggestion;
|
|
70
|
-
}
|
|
71
|
-
async render(remainingLines) {
|
|
72
|
-
await this._loadSuggestions();
|
|
73
|
-
if (!this.#suggestBlob) {
|
|
74
|
-
return { data: "", rows: 0 };
|
|
75
|
-
}
|
|
76
|
-
const { suggestions, argumentDescription } = this.#suggestBlob;
|
|
77
|
-
const page = Math.min(Math.floor(this.#activeSuggestionIdx / maxSuggestions) + 1, Math.floor(suggestions.length / maxSuggestions) + 1);
|
|
78
|
-
const pagedSuggestions = suggestions.filter((_, idx) => idx < page * maxSuggestions && idx >= (page - 1) * maxSuggestions);
|
|
79
|
-
const activePagedSuggestionIndex = this.#activeSuggestionIdx % maxSuggestions;
|
|
80
|
-
const activeDescription = pagedSuggestions.at(activePagedSuggestionIndex)?.description || argumentDescription || "";
|
|
81
|
-
const wrappedPadding = this.#term.getCursorState().cursorX % this.#term.cols;
|
|
82
|
-
const maxPadding = activeDescription.length !== 0 ? this.#term.cols - suggestionWidth - descriptionWidth : this.#term.cols - suggestionWidth;
|
|
83
|
-
const swapDescription = wrappedPadding > maxPadding && activeDescription.length !== 0;
|
|
84
|
-
const swappedPadding = swapDescription ? Math.max(wrappedPadding - descriptionWidth, 0) : wrappedPadding;
|
|
85
|
-
const clampedLeftPadding = Math.min(Math.min(wrappedPadding, swappedPadding), maxPadding);
|
|
86
|
-
if (suggestions.length <= this.#activeSuggestionIdx) {
|
|
87
|
-
this.#activeSuggestionIdx = Math.max(suggestions.length - 1, 0);
|
|
88
|
-
}
|
|
89
|
-
if (pagedSuggestions.length == 0) {
|
|
90
|
-
if (argumentDescription != null) {
|
|
91
|
-
return {
|
|
92
|
-
data: ansi.cursorHide +
|
|
93
|
-
ansi.cursorUp(2) +
|
|
94
|
-
ansi.cursorForward(clampedLeftPadding) +
|
|
95
|
-
this._renderArgumentDescription(argumentDescription, clampedLeftPadding),
|
|
96
|
-
rows: 3,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
return { data: "", rows: 0 };
|
|
100
|
-
}
|
|
101
|
-
const suggestionRowsUsed = pagedSuggestions.length + borderWidth;
|
|
102
|
-
let descriptionRowsUsed = this._descriptionRows(activeDescription) + borderWidth;
|
|
103
|
-
let rows = Math.max(descriptionRowsUsed, suggestionRowsUsed);
|
|
104
|
-
if (rows <= remainingLines) {
|
|
105
|
-
descriptionRowsUsed = suggestionRowsUsed;
|
|
106
|
-
rows = suggestionRowsUsed;
|
|
107
|
-
}
|
|
108
|
-
const descriptionUI = ansi.cursorUp(descriptionRowsUsed - 1) +
|
|
109
|
-
(swapDescription
|
|
110
|
-
? this._renderDescription(activeDescription, clampedLeftPadding)
|
|
111
|
-
: this._renderDescription(activeDescription, clampedLeftPadding + suggestionWidth)) +
|
|
112
|
-
ansi.cursorDown(descriptionRowsUsed - 1);
|
|
113
|
-
const suggestionUI = ansi.cursorUp(suggestionRowsUsed - 1) +
|
|
114
|
-
(swapDescription
|
|
115
|
-
? this._renderSuggestions(pagedSuggestions, activePagedSuggestionIndex, clampedLeftPadding + descriptionWidth)
|
|
116
|
-
: this._renderSuggestions(pagedSuggestions, activePagedSuggestionIndex, clampedLeftPadding)) +
|
|
117
|
-
ansi.cursorDown(suggestionRowsUsed - 1);
|
|
118
|
-
const ui = swapDescription ? descriptionUI + suggestionUI : suggestionUI + descriptionUI;
|
|
119
|
-
return {
|
|
120
|
-
data: ansi.cursorHide + ansi.cursorForward(clampedLeftPadding) + ui + ansi.cursorShow,
|
|
121
|
-
rows,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
update(keyPress) {
|
|
125
|
-
const { name, shift, ctrl } = keyPress;
|
|
126
|
-
if (name == "return") {
|
|
127
|
-
this.#term.clearCommand(); // clear the current command on enter
|
|
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
|
-
}
|
|
133
|
-
if (!this.#suggestBlob) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
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;
|
|
137
|
-
if (name == dismissKey && shift == !!dismissShift && ctrl == !!dismissCtrl) {
|
|
138
|
-
this.#suggestBlob = undefined;
|
|
139
|
-
this.#hideSuggestions = true;
|
|
140
|
-
}
|
|
141
|
-
else if (name == prevKey && shift == !!prevShift && ctrl == !!prevCtrl) {
|
|
142
|
-
this.#activeSuggestionIdx = Math.max(0, this.#activeSuggestionIdx - 1);
|
|
143
|
-
}
|
|
144
|
-
else if (name == nextKey && shift == !!nextShift && ctrl == !!nextCtrl) {
|
|
145
|
-
this.#activeSuggestionIdx = Math.min(this.#activeSuggestionIdx + 1, (this.#suggestBlob?.suggestions.length ?? 1) - 1);
|
|
146
|
-
}
|
|
147
|
-
else if (name == acceptKey && shift == !!acceptShift && ctrl == !!acceptCtrl) {
|
|
148
|
-
const removals = "\u007F".repeat(this.#suggestBlob?.charactersToDrop ?? 0);
|
|
149
|
-
const suggestion = this.#suggestBlob?.suggestions.at(this.#activeSuggestionIdx);
|
|
150
|
-
const chars = suggestion?.insertValue ?? suggestion?.name + " ";
|
|
151
|
-
if (this.#suggestBlob == null || !chars.trim() || this.#suggestBlob?.suggestions.length == 0) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
this.#term.write(removals + chars);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
log.debug({ msg: "handled keypress", ...keyPress });
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
}
|
package/build/ui/ui-doctor.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
import { checkLegacyConfigs, checkShellConfigPlugin, checkShellConfigs } from "../utils/shell.js";
|
|
5
|
-
export const render = async () => {
|
|
6
|
-
let errors = 0;
|
|
7
|
-
errors += await renderLegacyConfigIssues();
|
|
8
|
-
errors += await renderShellPluginIssues();
|
|
9
|
-
errors += renderShellConfigIssues();
|
|
10
|
-
process.exit(errors);
|
|
11
|
-
};
|
|
12
|
-
const renderLegacyConfigIssues = async () => {
|
|
13
|
-
const shellsWithLegacyConfigs = await checkLegacyConfigs();
|
|
14
|
-
if (shellsWithLegacyConfigs.length > 0) {
|
|
15
|
-
process.stderr.write(chalk.red("•") + chalk.bold(" detected legacy configurations\n"));
|
|
16
|
-
process.stderr.write(" the following shells have legacy configurations:\n");
|
|
17
|
-
shellsWithLegacyConfigs.forEach((shell) => {
|
|
18
|
-
process.stderr.write(chalk.red(" - ") + shell + "\n");
|
|
19
|
-
});
|
|
20
|
-
process.stderr.write(chalk.yellow(" remove any inshellisense configurations from your shell profile and re-add them following the instructions in the README\n"));
|
|
21
|
-
return 1;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
process.stdout.write(chalk.green("✓") + " no legacy configurations found\n");
|
|
25
|
-
}
|
|
26
|
-
return 0;
|
|
27
|
-
};
|
|
28
|
-
const renderShellConfigIssues = () => {
|
|
29
|
-
const shellsWithoutConfigs = checkShellConfigs();
|
|
30
|
-
if (shellsWithoutConfigs.length > 0) {
|
|
31
|
-
process.stderr.write(chalk.red("•") + " the following shells do not have configurations:\n");
|
|
32
|
-
shellsWithoutConfigs.forEach((shell) => {
|
|
33
|
-
process.stderr.write(chalk.red(" - ") + shell + "\n");
|
|
34
|
-
});
|
|
35
|
-
process.stderr.write(chalk.yellow(" run " + chalk.underline(chalk.cyan("is init --generate-full-configs")) + " to generate new configurations\n"));
|
|
36
|
-
return 1;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
process.stdout.write(chalk.green("✓") + " all shells have configurations\n");
|
|
40
|
-
}
|
|
41
|
-
return 0;
|
|
42
|
-
};
|
|
43
|
-
const renderShellPluginIssues = async () => {
|
|
44
|
-
const { shellsWithoutPlugin, shellsWithBadPlugin } = await checkShellConfigPlugin();
|
|
45
|
-
if (shellsWithoutPlugin.length == 0) {
|
|
46
|
-
process.stdout.write(chalk.green("✓") + " all shells have plugins\n");
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
process.stderr.write(chalk.red("•") + " the following shells do not have the plugin installed:\n");
|
|
50
|
-
shellsWithoutPlugin.forEach((shell) => {
|
|
51
|
-
process.stderr.write(chalk.red(" - ") + shell + "\n");
|
|
52
|
-
});
|
|
53
|
-
process.stderr.write(chalk.yellow(" review the README to generate the missing shell plugins, this warning can be ignored if you prefer manual startup\n"));
|
|
54
|
-
}
|
|
55
|
-
if (shellsWithBadPlugin.length == 0) {
|
|
56
|
-
process.stdout.write(chalk.green("✓") + " all shells have correct plugins\n");
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
process.stderr.write(chalk.red("•") + " the following shells have plugins incorrectly installed:\n");
|
|
60
|
-
shellsWithBadPlugin.forEach((shell) => {
|
|
61
|
-
process.stderr.write(chalk.red(" - ") + shell + "\n");
|
|
62
|
-
});
|
|
63
|
-
process.stderr.write(chalk.yellow(" remove and regenerate the plugins according to the README, only whitespace can be after the shell plugins\n"));
|
|
64
|
-
}
|
|
65
|
-
if (shellsWithoutPlugin.length > 0 || shellsWithBadPlugin.length > 0) {
|
|
66
|
-
return 1;
|
|
67
|
-
}
|
|
68
|
-
return 0;
|
|
69
|
-
};
|
package/build/ui/ui-root.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import readline from "node:readline";
|
|
4
|
-
import ansi from "ansi-escapes";
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
import log from "../utils/log.js";
|
|
7
|
-
import { getBackspaceSequence } from "../utils/shell.js";
|
|
8
|
-
import isterm from "../isterm/index.js";
|
|
9
|
-
import { eraseLinesBelow, resetToInitialState } from "../utils/ansi.js";
|
|
10
|
-
import { SuggestionManager, MAX_LINES } from "./suggestionManager.js";
|
|
11
|
-
export const renderConfirmation = (live) => {
|
|
12
|
-
const statusMessage = live ? chalk.green("live") : chalk.red("not found");
|
|
13
|
-
return `inshellisense session [${statusMessage}]\n`;
|
|
14
|
-
};
|
|
15
|
-
export const render = async (program, shell, underTest, login) => {
|
|
16
|
-
const term = await isterm.spawn(program, { shell, rows: process.stdout.rows, cols: process.stdout.columns, underTest, login });
|
|
17
|
-
const suggestionManager = new SuggestionManager(term, shell);
|
|
18
|
-
let hasActiveSuggestions = false;
|
|
19
|
-
let previousSuggestionsRows = 0;
|
|
20
|
-
const stdinStartedInRawMode = process.stdin.isRaw;
|
|
21
|
-
if (process.stdin.isTTY)
|
|
22
|
-
process.stdin.setRawMode(true);
|
|
23
|
-
readline.emitKeypressEvents(process.stdin);
|
|
24
|
-
const writeOutput = (data) => {
|
|
25
|
-
log.debug({ msg: "writing data", data });
|
|
26
|
-
process.stdout.write(data);
|
|
27
|
-
};
|
|
28
|
-
writeOutput(ansi.clearTerminal);
|
|
29
|
-
term.onData((data) => {
|
|
30
|
-
if (hasActiveSuggestions) {
|
|
31
|
-
// Considers when data includes newlines which have shifted the cursor position downwards
|
|
32
|
-
const newlines = Math.max((data.match(/\r/g) || []).length, (data.match(/\n/g) || []).length);
|
|
33
|
-
const linesOfInterest = MAX_LINES + newlines;
|
|
34
|
-
if (term.getCursorState().remainingLines <= MAX_LINES) {
|
|
35
|
-
// handles when suggestions get loaded before shell output so you need to always clear below output as a precaution
|
|
36
|
-
if (term.getCursorState().remainingLines != 0) {
|
|
37
|
-
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + eraseLinesBelow(linesOfInterest + 1) + ansi.cursorRestorePosition);
|
|
38
|
-
}
|
|
39
|
-
writeOutput(data +
|
|
40
|
-
ansi.cursorHide +
|
|
41
|
-
ansi.cursorSavePosition +
|
|
42
|
-
ansi.cursorPrevLine.repeat(linesOfInterest) +
|
|
43
|
-
term.getCells(linesOfInterest, "above") +
|
|
44
|
-
ansi.cursorRestorePosition +
|
|
45
|
-
ansi.cursorShow);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + eraseLinesBelow(linesOfInterest + 1) + ansi.cursorRestorePosition + ansi.cursorShow + data);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
writeOutput(data);
|
|
53
|
-
}
|
|
54
|
-
process.nextTick(async () => {
|
|
55
|
-
// validate result to prevent stale suggestion being provided
|
|
56
|
-
const suggestion = suggestionManager.validate(await suggestionManager.render(term.getCursorState().remainingLines));
|
|
57
|
-
const commandState = term.getCommandState();
|
|
58
|
-
if (suggestion.data != "" && commandState.cursorTerminated && !commandState.hasOutput) {
|
|
59
|
-
if (hasActiveSuggestions) {
|
|
60
|
-
if (term.getCursorState().remainingLines < MAX_LINES) {
|
|
61
|
-
writeOutput(ansi.cursorHide +
|
|
62
|
-
ansi.cursorSavePosition +
|
|
63
|
-
ansi.cursorPrevLine.repeat(MAX_LINES) +
|
|
64
|
-
term.getCells(MAX_LINES, "above") +
|
|
65
|
-
ansi.cursorRestorePosition +
|
|
66
|
-
ansi.cursorSavePosition +
|
|
67
|
-
ansi.cursorUp() +
|
|
68
|
-
suggestion.data +
|
|
69
|
-
ansi.cursorRestorePosition +
|
|
70
|
-
ansi.cursorShow);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
const offset = MAX_LINES - suggestion.rows;
|
|
74
|
-
writeOutput(ansi.cursorHide +
|
|
75
|
-
ansi.cursorSavePosition +
|
|
76
|
-
eraseLinesBelow(MAX_LINES) +
|
|
77
|
-
(offset > 0 ? ansi.cursorUp(offset) : "") +
|
|
78
|
-
suggestion.data +
|
|
79
|
-
ansi.cursorRestorePosition +
|
|
80
|
-
ansi.cursorShow);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
if (term.getCursorState().remainingLines < MAX_LINES) {
|
|
85
|
-
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorUp() + suggestion.data + ansi.cursorRestorePosition + ansi.cursorShow);
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
writeOutput(ansi.cursorHide +
|
|
89
|
-
ansi.cursorSavePosition +
|
|
90
|
-
ansi.cursorNextLine.repeat(suggestion.rows) +
|
|
91
|
-
suggestion.data +
|
|
92
|
-
ansi.cursorRestorePosition +
|
|
93
|
-
ansi.cursorShow);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
hasActiveSuggestions = true;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
if (hasActiveSuggestions) {
|
|
100
|
-
if (term.getCursorState().remainingLines <= MAX_LINES) {
|
|
101
|
-
writeOutput(ansi.cursorHide +
|
|
102
|
-
ansi.cursorSavePosition +
|
|
103
|
-
ansi.cursorPrevLine.repeat(MAX_LINES) +
|
|
104
|
-
term.getCells(MAX_LINES, "above") +
|
|
105
|
-
ansi.cursorRestorePosition +
|
|
106
|
-
ansi.cursorShow);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + eraseLinesBelow(MAX_LINES) + ansi.cursorRestorePosition + ansi.cursorShow);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
hasActiveSuggestions = false;
|
|
113
|
-
}
|
|
114
|
-
previousSuggestionsRows = suggestion.rows;
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
process.stdin.on("keypress", (...keyPress) => {
|
|
118
|
-
const press = keyPress[1];
|
|
119
|
-
const inputHandled = suggestionManager.update(press);
|
|
120
|
-
if (previousSuggestionsRows > 0 && inputHandled) {
|
|
121
|
-
term.noop();
|
|
122
|
-
}
|
|
123
|
-
else if (!inputHandled) {
|
|
124
|
-
if (press.name == "backspace") {
|
|
125
|
-
term.write(getBackspaceSequence(keyPress, shell));
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
term.write(press.sequence);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
term.onExit(({ exitCode }) => {
|
|
133
|
-
if (!stdinStartedInRawMode)
|
|
134
|
-
process.stdin.setRawMode(false);
|
|
135
|
-
process.stdout.write(resetToInitialState);
|
|
136
|
-
process.exit(exitCode);
|
|
137
|
-
});
|
|
138
|
-
process.stdout.on("resize", () => {
|
|
139
|
-
term.resize(process.stdout.columns, process.stdout.rows);
|
|
140
|
-
});
|
|
141
|
-
};
|
package/build/ui/ui-uninstall.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
import { deleteCacheFolder } from "../utils/config.js";
|
|
5
|
-
export const render = async () => {
|
|
6
|
-
deleteCacheFolder();
|
|
7
|
-
process.stdout.write(chalk.green("✓") + " successfully deleted the .inshellisense cache folder \n");
|
|
8
|
-
process.stdout.write(chalk.magenta("•") + " to complete the uninstall, run the the command: " + chalk.underline(chalk.cyan("npm uninstall -g @microsoft/inshellisense")) + "\n");
|
|
9
|
-
};
|
package/build/ui/utils.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import ansi from "ansi-escapes";
|
|
4
|
-
import { resetColor } from "../utils/ansi.js";
|
|
5
|
-
import wrapAnsi from "wrap-ansi";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
import wcwidth from "wcwidth";
|
|
8
|
-
/**
|
|
9
|
-
* Renders a box around the given rows
|
|
10
|
-
* @param rows the text content to be included in the box, must be <= width - 2
|
|
11
|
-
* @param width the max width of a row
|
|
12
|
-
* @param x the column to start the box at
|
|
13
|
-
*/
|
|
14
|
-
export const renderBox = (rows, width, x, borderColor) => {
|
|
15
|
-
const result = [];
|
|
16
|
-
const setColor = (text) => resetColor + (borderColor ? chalk.hex(borderColor).apply(text) : text);
|
|
17
|
-
result.push(ansi.cursorTo(x) + setColor("┌" + "─".repeat(width - 2) + "┐") + ansi.cursorTo(x));
|
|
18
|
-
rows.forEach((row) => {
|
|
19
|
-
result.push(ansi.cursorDown() + setColor("│") + row + setColor("│") + ansi.cursorTo(x));
|
|
20
|
-
});
|
|
21
|
-
result.push(ansi.cursorDown() + setColor("└" + "─".repeat(width - 2) + "┘") + ansi.cursorTo(x));
|
|
22
|
-
return result.join("") + ansi.cursorUp(rows.length + 1);
|
|
23
|
-
};
|
|
24
|
-
export const truncateMultilineText = (description, width, maxHeight) => {
|
|
25
|
-
const wrappedText = wrapAnsi(description, width, {
|
|
26
|
-
trim: false,
|
|
27
|
-
hard: true,
|
|
28
|
-
});
|
|
29
|
-
const lines = wrappedText.split("\n");
|
|
30
|
-
const truncatedLines = lines.slice(0, maxHeight);
|
|
31
|
-
if (lines.length > maxHeight) {
|
|
32
|
-
truncatedLines[maxHeight - 1] = [...truncatedLines[maxHeight - 1]].slice(0, -1).join("") + "…";
|
|
33
|
-
}
|
|
34
|
-
return truncatedLines.map((line) => line.padEnd(width));
|
|
35
|
-
};
|
|
36
|
-
const wcPadEnd = (text, width, char = " ") => text + char.repeat(Math.max(width - wcwidth(text), 0));
|
|
37
|
-
const wcPoints = (text, length) => {
|
|
38
|
-
const points = [...text];
|
|
39
|
-
const accPoints = [];
|
|
40
|
-
let accWidth = 0;
|
|
41
|
-
for (const point of points) {
|
|
42
|
-
const width = wcwidth(point);
|
|
43
|
-
if (width + accWidth > length) {
|
|
44
|
-
return wcwidth(accPoints.join("")) < length ? [accPoints.join(""), true] : [accPoints.slice(0, -1).join(""), true];
|
|
45
|
-
}
|
|
46
|
-
accPoints.push(point);
|
|
47
|
-
accWidth += width;
|
|
48
|
-
}
|
|
49
|
-
return [accPoints.join(""), false];
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Truncates the text to the given width
|
|
53
|
-
*/
|
|
54
|
-
export const truncateText = (text, width) => {
|
|
55
|
-
const [points, truncated] = wcPoints(text, width);
|
|
56
|
-
return !truncated ? wcPadEnd(text, width) : wcPadEnd(points + "…", width);
|
|
57
|
-
};
|
package/build/utils/ansi.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
const ESC = "\u001B";
|
|
4
|
-
const CSI = ESC + "[";
|
|
5
|
-
const OSC = "\u001B]";
|
|
6
|
-
const BEL = "\u0007";
|
|
7
|
-
export const IsTermOscPs = 6973;
|
|
8
|
-
const IS_OSC = OSC + IsTermOscPs + ";";
|
|
9
|
-
export var IstermOscPt;
|
|
10
|
-
(function (IstermOscPt) {
|
|
11
|
-
IstermOscPt["PromptStarted"] = "PS";
|
|
12
|
-
IstermOscPt["PromptEnded"] = "PE";
|
|
13
|
-
IstermOscPt["CurrentWorkingDirectory"] = "CWD";
|
|
14
|
-
})(IstermOscPt || (IstermOscPt = {}));
|
|
15
|
-
export const IstermPromptStart = IS_OSC + IstermOscPt.PromptStarted + BEL;
|
|
16
|
-
export const IstermPromptEnd = IS_OSC + IstermOscPt.PromptEnded + BEL;
|
|
17
|
-
export const cursorHide = CSI + "?25l";
|
|
18
|
-
export const cursorShow = CSI + "?25h";
|
|
19
|
-
export const cursorNextLine = CSI + "E";
|
|
20
|
-
export const eraseLine = CSI + "2K";
|
|
21
|
-
export const resetColor = CSI + "0m";
|
|
22
|
-
export const resetLine = CSI + "2K";
|
|
23
|
-
export const resetToInitialState = ESC + "c"; // RIS - Reset to Initial State
|
|
24
|
-
export const cursorBackward = (count = 1) => CSI + count + "D";
|
|
25
|
-
export const cursorForward = (count = 1) => CSI + count + "C";
|
|
26
|
-
export const cursorTo = ({ x, y }) => {
|
|
27
|
-
return CSI + (y ?? "") + ";" + (x ?? "") + "H";
|
|
28
|
-
};
|
|
29
|
-
export const deleteLinesBelow = (count = 1) => {
|
|
30
|
-
return [...Array(count).keys()].map(() => CSI + "B" + CSI + "M").join("");
|
|
31
|
-
};
|
|
32
|
-
export const deleteLine = (count = 1) => CSI + count + "M";
|
|
33
|
-
export const scrollUp = (count = 1) => CSI + count + "S";
|
|
34
|
-
export const scrollDown = (count = 1) => CSI + count + "T";
|
|
35
|
-
export const eraseLinesBelow = (count = 1) => {
|
|
36
|
-
return [...Array(count).keys()].map(() => cursorNextLine + eraseLine).join("");
|
|
37
|
-
};
|