You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

57 lines
1.7 KiB

import React from 'react';
import * as bin from './bin';
// Braille frames that read as a single-cell grid of dots appearing to spin.
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
// Commands that fetch from a remote API and may take a moment to respond.
const asyncCommands = ['quote', 'readme'];
export const shell = async (
command: string,
setHistory: (value: string) => void,
updateHistory: (index: number, value: string) => void,
clearHistory: () => void,
setCommand: React.Dispatch<React.SetStateAction<string>>,
historyIndex: number,
) => {
const args = command.split(' ');
args[0] = args[0].toLowerCase();
if (args[0] === 'clear') {
clearHistory();
setCommand('');
} else if (command === '') {
setHistory('');
setCommand('');
} else if (Object.keys(bin).indexOf(args[0]) === -1) {
setHistory(
`
shell: command not found: ${args[0]}. Try 'help' to get started.`,
);
setCommand('');
} else if (asyncCommands.includes(args[0])) {
// Show a spinner and clear the prompt so the user can keep working while
// the request is in flight. The output lands in its own history entry, so
// running other commands meanwhile won't clobber it.
let frame = 0;
setHistory(spinnerFrames[frame]);
setCommand('');
const spinner = setInterval(() => {
frame = (frame + 1) % spinnerFrames.length;
updateHistory(historyIndex, spinnerFrames[frame]);
}, 80);
try {
const output = await bin[args[0]](args.slice(1));
updateHistory(historyIndex, output);
} finally {
clearInterval(spinner);
}
} else {
const output = await bin[args[0]](args.slice(1));
setHistory(output);
setCommand('');
}
};