mirror of
https://github.com/wavetermdev/inshellisense.git
synced 2026-08-05 13:43:30 -07:00
feat: implement bind command
Signed-off-by: Chapman Pendery <cpendery@vt.edu>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
},
|
||||
"files": [
|
||||
"build/**",
|
||||
"shell/**",
|
||||
"*.md",
|
||||
"LICENSE"
|
||||
],
|
||||
|
||||
+7
-11
@@ -1,17 +1,13 @@
|
||||
import {Command} from "commander";
|
||||
import { Command } from "commander";
|
||||
import { supportedShells } from "../utils/bindings.js";
|
||||
import { render } from "../ui/ui-bind.js";
|
||||
|
||||
const supportedShells = ["bash", "powershell", "windows-powershell"]
|
||||
|
||||
const action = (shell: string) => {
|
||||
if (!supportedShells.includes(shell)) {
|
||||
console.error(`Unsupported shell: ${shell}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`Adding keybindings to ${shell} shell`);
|
||||
const action = async () => {
|
||||
await render();
|
||||
};
|
||||
|
||||
const cmd = new Command("bind");
|
||||
cmd.description(`adds keybindings to the selected shell: ${supportedShells}`);
|
||||
cmd.description(`adds keybindings to the selected shell: ${supportedShells.join(", ")}`);
|
||||
cmd.action(action);
|
||||
|
||||
export default cmd
|
||||
export default cmd;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Box, Text, render as inkRender, useInput, useApp } from "ink";
|
||||
import chalk from "chalk";
|
||||
|
||||
import { availableBindings, bind, supportedShells, Shell } from "../utils/bindings.js";
|
||||
|
||||
let uiResult = "";
|
||||
|
||||
function UI() {
|
||||
const { exit } = useApp();
|
||||
const [selectionIdx, setSelectionIdx] = useState(0);
|
||||
const [availableShells, setAvailableShells] = useState<Shell[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
availableBindings().then((bindings) => {
|
||||
if (bindings.length == 0) {
|
||||
exit();
|
||||
}
|
||||
setAvailableShells(bindings);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useInput(async (_, key) => {
|
||||
if (key.upArrow) {
|
||||
setSelectionIdx(Math.max(0, selectionIdx - 1));
|
||||
} else if (key.downArrow) {
|
||||
setSelectionIdx(Math.min(availableShells.length - 1, selectionIdx + 1));
|
||||
} else if (key.return) {
|
||||
await bind(availableShells[selectionIdx]);
|
||||
uiResult = availableShells[selectionIdx];
|
||||
exit();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Box flexDirection="column">
|
||||
<Box>
|
||||
<Text bold>Select your desired shell for keybinding creation</Text>
|
||||
</Box>
|
||||
<Box flexDirection="column">
|
||||
{availableShells.map((shell, idx) => {
|
||||
if (idx == selectionIdx) {
|
||||
return (
|
||||
<Text color="cyan" underline key={idx}>
|
||||
{">"} {shell}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Text key={idx}>
|
||||
{" "}
|
||||
{shell}
|
||||
</Text>
|
||||
);
|
||||
})}
|
||||
{supportedShells
|
||||
.filter((s) => !availableShells.includes(s))
|
||||
.map((shell, idx) => (
|
||||
<Text color="gray" key={idx}>
|
||||
{" "}
|
||||
{shell} (already bound)
|
||||
</Text>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export const render = async () => {
|
||||
const { waitUntilExit } = inkRender(<UI />);
|
||||
await waitUntilExit();
|
||||
if (uiResult.length !== 0) {
|
||||
process.stdout.write("\n" + chalk.green("✓") + " successfully created new bindings \n");
|
||||
} else {
|
||||
process.stdout.write("\n");
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,108 @@
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import fsAsync from "node:fs/promises";
|
||||
import fs from "node:fs";
|
||||
import process from "node:process";
|
||||
import url from "node:url";
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export enum Shell {
|
||||
Bash = "bash",
|
||||
Powershell = "powershell",
|
||||
Pwsh = "pwsh",
|
||||
}
|
||||
|
||||
export const supportedShells = [Shell.Bash, Shell.Powershell, Shell.Pwsh];
|
||||
|
||||
const bashScriptCommand = (): string => {
|
||||
return `[ -f ~/.sa/key-bindings.bash ] && source ~/.sa/key-bindings.bash`;
|
||||
};
|
||||
|
||||
const powershellScriptCommand = (): string => {
|
||||
const bindingsPath = path.join(os.homedir(), ".sa", "key-bindings-powershell.ps1");
|
||||
return `if(Test-Path '${bindingsPath}' -PathType Leaf){. ${bindingsPath}}`;
|
||||
};
|
||||
|
||||
const pwshScriptCommand = (): string => {
|
||||
const bindingsPath = path.join(os.homedir(), ".sa", "key-bindings-pwsh.ps1");
|
||||
return `if(Test-Path '${bindingsPath}' -PathType Leaf){. ${bindingsPath}}`;
|
||||
};
|
||||
|
||||
const pwshConfigPath = (): string => {
|
||||
switch (process.platform) {
|
||||
case "win32":
|
||||
return path.join(os.homedir(), "Documents", "Powershell", "Microsoft.PowerShell_profile.ps1");
|
||||
case "linux":
|
||||
case "darwin":
|
||||
return path.join(os.homedir(), ".config", "powershell", "Microsoft.PowerShell_profile.ps1");
|
||||
default:
|
||||
throw new Error("Unsupported platform");
|
||||
}
|
||||
};
|
||||
|
||||
export const availableBindings = async (): Promise<Shell[]> => {
|
||||
const saConfigPath = path.join(os.homedir(), ".sa");
|
||||
if (!fs.existsSync(saConfigPath)) {
|
||||
await fsAsync.mkdir(saConfigPath);
|
||||
}
|
||||
|
||||
const bindings = [];
|
||||
const bashConfigPath = path.join(os.homedir(), ".bashrc");
|
||||
if (!fs.existsSync(bashConfigPath)) {
|
||||
bindings.push(Shell.Bash);
|
||||
} else {
|
||||
const bashConfigContent = fsAsync.readFile(bashConfigPath, { encoding: "utf-8" });
|
||||
if (!(await bashConfigContent).includes(bashScriptCommand())) {
|
||||
bindings.push(Shell.Bash);
|
||||
}
|
||||
}
|
||||
|
||||
const powershellConfigPath = path.join(os.homedir(), "Documents", "WindowsPowershell", "Microsoft.PowerShell_profile.ps1");
|
||||
if (!fs.existsSync(powershellConfigPath)) {
|
||||
bindings.push(Shell.Powershell);
|
||||
} else {
|
||||
const powershellConfigContent = fsAsync.readFile(powershellConfigPath, { encoding: "utf-8" });
|
||||
if (!(await powershellConfigContent).includes(powershellScriptCommand())) {
|
||||
bindings.push(Shell.Powershell);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(pwshConfigPath())) {
|
||||
bindings.push(Shell.Pwsh);
|
||||
} else {
|
||||
const pwshConfigContent = fsAsync.readFile(pwshConfigPath(), { encoding: "utf-8" });
|
||||
if (!(await pwshConfigContent).includes(pwshScriptCommand())) {
|
||||
bindings.push(Shell.Pwsh);
|
||||
}
|
||||
}
|
||||
|
||||
return bindings;
|
||||
};
|
||||
|
||||
export const bind = async (shell: Shell): Promise<void> => {
|
||||
const saConfigPath = path.join(os.homedir(), ".sa");
|
||||
if (!fs.existsSync(saConfigPath)) {
|
||||
await fsAsync.mkdir(saConfigPath);
|
||||
}
|
||||
switch (shell) {
|
||||
case Shell.Bash:
|
||||
const bashConfigPath = path.join(os.homedir(), ".bashrc");
|
||||
await fsAsync.appendFile(bashConfigPath, `\n${bashScriptCommand()}`);
|
||||
await fsAsync.copyFile(path.join(__dirname, "..", "..", "shell", "key-bindings.bash"), path.join(os.homedir(), ".sa", "key-bindings.bash"));
|
||||
break;
|
||||
case Shell.Powershell:
|
||||
const powershellConfigPath = path.join(os.homedir(), "Documents", "WindowsPowershell", "Microsoft.PowerShell_profile.ps1");
|
||||
await fsAsync.appendFile(powershellConfigPath, `\n${powershellScriptCommand()}`);
|
||||
await fsAsync.copyFile(
|
||||
path.join(__dirname, "..", "..", "shell", "key-bindings-powershell.ps1"),
|
||||
path.join(os.homedir(), ".sa", "key-bindings-powershell.ps1")
|
||||
);
|
||||
break;
|
||||
case Shell.Pwsh:
|
||||
await fsAsync.appendFile(pwshConfigPath(), `\n${pwshScriptCommand()}`);
|
||||
await fsAsync.copyFile(path.join(__dirname, "..", "..", "shell", "key-bindings-pwsh.ps1"), path.join(os.homedir(), ".sa", "key-bindings-pwsh.ps1"));
|
||||
break;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user