@microsoft/inshellisense 0.0.1-rc.2 → 0.0.1-rc.20
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/LICENSE +21 -21
- package/README.md +80 -6
- package/SECURITY.md +41 -41
- package/build/commands/complete.js +16 -0
- package/build/commands/doctor.js +11 -0
- package/build/commands/init.js +24 -0
- package/build/commands/root.js +27 -30
- package/build/commands/specs/list.js +26 -0
- package/build/commands/specs/root.js +8 -0
- package/build/commands/uninstall.js +1 -1
- package/build/index.js +20 -7
- package/build/isterm/commandManager.js +290 -0
- package/build/isterm/index.js +4 -0
- package/build/isterm/pty.js +372 -0
- package/build/runtime/alias.js +61 -0
- package/build/runtime/generator.js +24 -11
- package/build/runtime/parser.js +86 -16
- package/build/runtime/runtime.js +103 -45
- package/build/runtime/suggestion.js +70 -22
- package/build/runtime/template.js +33 -18
- package/build/runtime/utils.js +111 -12
- package/build/ui/suggestionManager.js +162 -0
- package/build/ui/ui-doctor.js +69 -0
- package/build/ui/ui-root.js +130 -64
- package/build/ui/ui-uninstall.js +3 -5
- package/build/ui/utils.js +57 -0
- package/build/utils/ansi.js +37 -0
- package/build/utils/config.js +132 -0
- package/build/utils/log.js +39 -0
- package/build/utils/shell.js +316 -0
- package/package.json +39 -6
- package/scripts/postinstall.js +9 -0
- package/shell/bash-preexec.sh +380 -0
- package/shell/shellIntegration-env.zsh +12 -0
- package/shell/shellIntegration-login.zsh +9 -0
- package/shell/shellIntegration-profile.zsh +9 -0
- package/shell/shellIntegration-rc.zsh +66 -0
- package/shell/shellIntegration.bash +125 -0
- package/shell/shellIntegration.fish +28 -0
- package/shell/shellIntegration.nu +36 -0
- package/shell/shellIntegration.ps1 +27 -0
- package/shell/shellIntegration.xsh +37 -0
- package/build/commands/bind.js +0 -12
- package/build/ui/input.js +0 -55
- package/build/ui/suggestions.js +0 -84
- package/build/ui/ui-bind.js +0 -69
- package/build/utils/bindings.js +0 -216
- package/build/utils/cache.js +0 -21
- package/shell/key-bindings-powershell.ps1 +0 -27
- package/shell/key-bindings-pwsh.ps1 +0 -27
- package/shell/key-bindings.bash +0 -7
- package/shell/key-bindings.fish +0 -8
- package/shell/key-bindings.zsh +0 -10
package/build/ui/ui-root.js
CHANGED
|
@@ -1,71 +1,137 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 } 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
|
+
if (process.stdin.isTTY)
|
|
21
|
+
process.stdin.setRawMode(true);
|
|
22
|
+
readline.emitKeypressEvents(process.stdin);
|
|
23
|
+
const writeOutput = (data) => {
|
|
24
|
+
log.debug({ msg: "writing data", data });
|
|
25
|
+
process.stdout.write(data);
|
|
26
|
+
};
|
|
27
|
+
writeOutput(ansi.clearTerminal);
|
|
28
|
+
term.onData((data) => {
|
|
29
|
+
if (hasActiveSuggestions) {
|
|
30
|
+
// Considers when data includes newlines which have shifted the cursor position downwards
|
|
31
|
+
const newlines = Math.max((data.match(/\r/g) || []).length, (data.match(/\n/g) || []).length);
|
|
32
|
+
const linesOfInterest = MAX_LINES + newlines;
|
|
33
|
+
if (term.getCursorState().remainingLines <= MAX_LINES) {
|
|
34
|
+
// handles when suggestions get loaded before shell output so you need to always clear below output as a precaution
|
|
35
|
+
if (term.getCursorState().remainingLines != 0) {
|
|
36
|
+
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + eraseLinesBelow(linesOfInterest + 1) + ansi.cursorRestorePosition);
|
|
37
|
+
}
|
|
38
|
+
writeOutput(data +
|
|
39
|
+
ansi.cursorHide +
|
|
40
|
+
ansi.cursorSavePosition +
|
|
41
|
+
ansi.cursorPrevLine.repeat(linesOfInterest) +
|
|
42
|
+
term.getCells(linesOfInterest, "above") +
|
|
43
|
+
ansi.cursorRestorePosition +
|
|
44
|
+
ansi.cursorShow);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + eraseLinesBelow(linesOfInterest + 1) + ansi.cursorRestorePosition + ansi.cursorShow + data);
|
|
48
|
+
}
|
|
30
49
|
}
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
else {
|
|
51
|
+
writeOutput(data);
|
|
33
52
|
}
|
|
53
|
+
process.nextTick(async () => {
|
|
54
|
+
// validate result to prevent stale suggestion being provided
|
|
55
|
+
const suggestion = suggestionManager.validate(await suggestionManager.render(term.getCursorState().remainingLines));
|
|
56
|
+
const commandState = term.getCommandState();
|
|
57
|
+
if (suggestion.data != "" && commandState.cursorTerminated && !commandState.hasOutput) {
|
|
58
|
+
if (hasActiveSuggestions) {
|
|
59
|
+
if (term.getCursorState().remainingLines < MAX_LINES) {
|
|
60
|
+
writeOutput(ansi.cursorHide +
|
|
61
|
+
ansi.cursorSavePosition +
|
|
62
|
+
ansi.cursorPrevLine.repeat(MAX_LINES) +
|
|
63
|
+
term.getCells(MAX_LINES, "above") +
|
|
64
|
+
ansi.cursorRestorePosition +
|
|
65
|
+
ansi.cursorSavePosition +
|
|
66
|
+
ansi.cursorUp() +
|
|
67
|
+
suggestion.data +
|
|
68
|
+
ansi.cursorRestorePosition +
|
|
69
|
+
ansi.cursorShow);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const offset = MAX_LINES - suggestion.rows;
|
|
73
|
+
writeOutput(ansi.cursorHide +
|
|
74
|
+
ansi.cursorSavePosition +
|
|
75
|
+
eraseLinesBelow(MAX_LINES) +
|
|
76
|
+
(offset > 0 ? ansi.cursorUp(offset) : "") +
|
|
77
|
+
suggestion.data +
|
|
78
|
+
ansi.cursorRestorePosition +
|
|
79
|
+
ansi.cursorShow);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
if (term.getCursorState().remainingLines < MAX_LINES) {
|
|
84
|
+
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorUp() + suggestion.data + ansi.cursorRestorePosition + ansi.cursorShow);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
writeOutput(ansi.cursorHide +
|
|
88
|
+
ansi.cursorSavePosition +
|
|
89
|
+
ansi.cursorNextLine.repeat(suggestion.rows) +
|
|
90
|
+
suggestion.data +
|
|
91
|
+
ansi.cursorRestorePosition +
|
|
92
|
+
ansi.cursorShow);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
hasActiveSuggestions = true;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
if (hasActiveSuggestions) {
|
|
99
|
+
if (term.getCursorState().remainingLines <= MAX_LINES) {
|
|
100
|
+
writeOutput(ansi.cursorHide +
|
|
101
|
+
ansi.cursorSavePosition +
|
|
102
|
+
ansi.cursorPrevLine.repeat(MAX_LINES) +
|
|
103
|
+
term.getCells(MAX_LINES, "above") +
|
|
104
|
+
ansi.cursorRestorePosition +
|
|
105
|
+
ansi.cursorShow);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + eraseLinesBelow(MAX_LINES) + ansi.cursorRestorePosition + ansi.cursorShow);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
hasActiveSuggestions = false;
|
|
112
|
+
}
|
|
113
|
+
previousSuggestionsRows = suggestion.rows;
|
|
114
|
+
});
|
|
34
115
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
116
|
+
process.stdin.on("keypress", (...keyPress) => {
|
|
117
|
+
const press = keyPress[1];
|
|
118
|
+
const inputHandled = suggestionManager.update(press);
|
|
119
|
+
if (previousSuggestionsRows > 0 && inputHandled) {
|
|
120
|
+
term.noop();
|
|
39
121
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
return (React.createElement(Box, { flexDirection: "column", ref: measureRef },
|
|
53
|
-
React.createElement(Box, null,
|
|
54
|
-
React.createElement(Text, null,
|
|
55
|
-
React.createElement(Input, { value: command, setValue: setCommand, prompt: Prompt, activeSuggestion: activeSuggestion, tabCompletionDropSize: tabCompletionDropSize }))),
|
|
56
|
-
React.createElement(Suggestions, { leftPadding: leftPadding, setActiveSuggestion: setActiveSuggestion, suggestions: suggestions })));
|
|
57
|
-
}
|
|
58
|
-
export const render = async (command) => {
|
|
59
|
-
uiResult = undefined;
|
|
60
|
-
const { waitUntilExit } = inkRender(React.createElement(UI, { startingCommand: command ?? "" }));
|
|
61
|
-
await waitUntilExit();
|
|
62
|
-
return uiResult;
|
|
63
|
-
};
|
|
64
|
-
function getLeftPadding(windowWidth, command) {
|
|
65
|
-
const wrappedText = wrapAnsi(command + "", windowWidth, {
|
|
66
|
-
trim: false,
|
|
67
|
-
hard: true,
|
|
122
|
+
else if (!inputHandled) {
|
|
123
|
+
if (press.name == "backspace") {
|
|
124
|
+
term.write(getBackspaceSequence(keyPress, shell));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
term.write(press.sequence);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
term.onExit(({ exitCode }) => {
|
|
132
|
+
process.exit(exitCode);
|
|
68
133
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
134
|
+
process.stdout.on("resize", () => {
|
|
135
|
+
term.resize(process.stdout.columns, process.stdout.rows);
|
|
136
|
+
});
|
|
137
|
+
};
|
package/build/ui/ui-uninstall.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
-
import {
|
|
4
|
+
import { deleteCacheFolder } from "../utils/config.js";
|
|
5
5
|
export const render = async () => {
|
|
6
|
-
|
|
7
|
-
process.stdout.write(chalk.green("✓") + " successfully
|
|
8
|
-
deleteConfigFolder();
|
|
9
|
-
process.stdout.write(chalk.green("✓") + " successfully deleted the .inshellisense config folder \n");
|
|
6
|
+
deleteCacheFolder();
|
|
7
|
+
process.stdout.write(chalk.green("✓") + " successfully deleted the .inshellisense cache folder \n");
|
|
10
8
|
process.stdout.write(chalk.magenta("•") + " to complete the uninstall, run the the command: " + chalk.underline(chalk.cyan("npm uninstall -g @microsoft/inshellisense")) + "\n");
|
|
11
9
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
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["Prompt"] = "PROMPT";
|
|
15
|
+
})(IstermOscPt || (IstermOscPt = {}));
|
|
16
|
+
export const IstermPromptStart = IS_OSC + IstermOscPt.PromptStarted + BEL;
|
|
17
|
+
export const IstermPromptEnd = IS_OSC + IstermOscPt.PromptEnded + BEL;
|
|
18
|
+
export const cursorHide = CSI + "?25l";
|
|
19
|
+
export const cursorShow = CSI + "?25h";
|
|
20
|
+
export const cursorNextLine = CSI + "E";
|
|
21
|
+
export const eraseLine = CSI + "2K";
|
|
22
|
+
export const resetColor = CSI + "0m";
|
|
23
|
+
export const resetLine = CSI + "2K";
|
|
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
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import fsAsync from "node:fs/promises";
|
|
7
|
+
import toml from "toml";
|
|
8
|
+
import _Ajv from "ajv";
|
|
9
|
+
const Ajv = _Ajv;
|
|
10
|
+
const ajv = new Ajv();
|
|
11
|
+
const bindingSchema = {
|
|
12
|
+
type: "object",
|
|
13
|
+
nullable: true,
|
|
14
|
+
properties: {
|
|
15
|
+
shift: { type: "boolean", nullable: true },
|
|
16
|
+
control: { type: "boolean", nullable: true },
|
|
17
|
+
key: { type: "string" },
|
|
18
|
+
},
|
|
19
|
+
required: ["key"],
|
|
20
|
+
};
|
|
21
|
+
const promptPatternsSchema = {
|
|
22
|
+
type: "array",
|
|
23
|
+
nullable: true,
|
|
24
|
+
items: {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {
|
|
27
|
+
regex: { type: "string" },
|
|
28
|
+
postfix: { type: "string" },
|
|
29
|
+
},
|
|
30
|
+
required: ["regex", "postfix"],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const specPathsSchema = {
|
|
34
|
+
type: "array",
|
|
35
|
+
items: { type: "string" },
|
|
36
|
+
nullable: true,
|
|
37
|
+
};
|
|
38
|
+
const configSchema = {
|
|
39
|
+
type: "object",
|
|
40
|
+
nullable: true,
|
|
41
|
+
properties: {
|
|
42
|
+
bindings: {
|
|
43
|
+
type: "object",
|
|
44
|
+
nullable: true,
|
|
45
|
+
properties: {
|
|
46
|
+
nextSuggestion: bindingSchema,
|
|
47
|
+
previousSuggestion: bindingSchema,
|
|
48
|
+
dismissSuggestions: bindingSchema,
|
|
49
|
+
acceptSuggestion: bindingSchema,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
// DEPRECATED: prompt patterns are no longer used
|
|
53
|
+
prompt: {
|
|
54
|
+
type: "object",
|
|
55
|
+
nullable: true,
|
|
56
|
+
properties: {
|
|
57
|
+
bash: promptPatternsSchema,
|
|
58
|
+
pwsh: promptPatternsSchema,
|
|
59
|
+
powershell: promptPatternsSchema,
|
|
60
|
+
xonsh: promptPatternsSchema,
|
|
61
|
+
nu: promptPatternsSchema,
|
|
62
|
+
fish: promptPatternsSchema,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
specs: {
|
|
66
|
+
type: "object",
|
|
67
|
+
nullable: true,
|
|
68
|
+
properties: {
|
|
69
|
+
path: specPathsSchema,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
additionalProperties: false,
|
|
74
|
+
};
|
|
75
|
+
const rcFile = ".inshellisenserc";
|
|
76
|
+
const xdgFile = "rc.toml";
|
|
77
|
+
const cachePath = path.join(os.homedir(), ".inshellisense");
|
|
78
|
+
const rcPath = path.join(os.homedir(), rcFile);
|
|
79
|
+
const xdgPath = path.join(os.homedir(), ".config", "inshellisense", xdgFile);
|
|
80
|
+
const configPaths = [rcPath, xdgPath];
|
|
81
|
+
let globalConfig = {
|
|
82
|
+
bindings: {
|
|
83
|
+
nextSuggestion: { key: "down" },
|
|
84
|
+
previousSuggestion: { key: "up" },
|
|
85
|
+
acceptSuggestion: { key: "tab" },
|
|
86
|
+
dismissSuggestions: { key: "escape" },
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
export const getConfig = () => globalConfig;
|
|
90
|
+
export const loadConfig = async (program) => {
|
|
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
|
+
};
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
globalConfig.specs = { path: [`${os.homedir()}/.fig/autocomplete/build`, ...(globalConfig.specs?.path ?? [])] };
|
|
127
|
+
};
|
|
128
|
+
export const deleteCacheFolder = () => {
|
|
129
|
+
if (fs.existsSync(cachePath)) {
|
|
130
|
+
fs.rmSync(cachePath, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import fsAsync from "node:fs/promises";
|
|
8
|
+
const logFolder = path.join(os.homedir(), ".inshellisense");
|
|
9
|
+
const logTarget = path.join(logFolder, "inshellisense.log");
|
|
10
|
+
let logEnabled = false;
|
|
11
|
+
const reset = async () => {
|
|
12
|
+
if (!fs.existsSync(logTarget)) {
|
|
13
|
+
await fsAsync.mkdir(logFolder, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
await fsAsync.writeFile(logTarget, "");
|
|
16
|
+
};
|
|
17
|
+
const debug = (content) => {
|
|
18
|
+
if (!logEnabled) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
fs.appendFile(logTarget, JSON.stringify(content) + "\n", (err) => {
|
|
22
|
+
if (err != null) {
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const getLogFunction = (level) => (...data) => debug({ msg: `console.${level}`, data: data.toString() });
|
|
28
|
+
const logConsole = {
|
|
29
|
+
...console,
|
|
30
|
+
log: getLogFunction("log"),
|
|
31
|
+
error: getLogFunction("error"),
|
|
32
|
+
};
|
|
33
|
+
// eslint-disable-next-line no-global-assign
|
|
34
|
+
const overrideConsole = () => (console = logConsole);
|
|
35
|
+
export const enable = async () => {
|
|
36
|
+
await reset();
|
|
37
|
+
logEnabled = true;
|
|
38
|
+
};
|
|
39
|
+
export default { reset, debug, enable, overrideConsole };
|