ProzillaOS/src/components/applications/terminal/Terminal.jsx
2023-07-23 20:00:02 +02:00

145 lines
No EOL
3.1 KiB
JavaScript

import { useState } from "react";
import styles from "./Terminal.module.css";
import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
import { Command } from "../../../features/applications/terminal/commands.js";
const USERNAME = "user";
const HOSTNAME = "prozilla-os";
function OutputLine({ text }) {
return (
<p className={styles.Output}>{text}</p>
);
}
function InputLine({ value, prefix, onChange, onKeyUp, onKeyDown }) {
return (
<span className={styles.Input}>
{prefix && <p className={[styles.Prefix]}>{prefix}</p>}
<label htmlFor="input"/>
<input
id="input"
value={value}
onChange={onChange}
onKeyUp={onKeyUp}
onKeyDown={onKeyDown}
spellCheck={false}
autoComplete="off"
autoFocus
/>
</span>
);
}
export function Terminal() {
const [inputKey, setInputKey] = useState(0);
const [inputValue, setInputValue] = useState("");
const [history, setHistory] = useState([]);
const virtualRoot = useVirtualRoot();
const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate("~"));
// console.log(currentDirectory);
const prefix = `${USERNAME}@${HOSTNAME}:${currentDirectory.root ? "/" : currentDirectory.path}$ `;
const updatedHistory = history;
const pushHistory = (entry) => {
updatedHistory.push(entry);
setHistory(updatedHistory);
};
const promptOutput = (text) => {
pushHistory({
text,
isInput: false
});
};
const submitInput = (value) => {
pushHistory({
text: prefix + value,
isInput: true
});
setInputValue("");
value = value.trim();
if (value === "")
return;
const args = value.split(/ +/);
const commandName = args.shift().toLowerCase();
const command = Command.find(commandName);
if (!command) {
return promptOutput(`${commandName}: Command not found`);
}
let response = null;
try {
response = command.execute(args, {
promptOutput,
pushHistory,
virtualRoot,
currentDirectory,
setCurrentDirectory,
username: USERNAME,
hostname: HOSTNAME,
});
if (response == null)
return promptOutput(`${commandName}: Command failed`);
if (!response.blank)
promptOutput(response);
} catch (error) {
console.error(error);
promptOutput(`${commandName}: Command failed`);
}
};
const onKeyDown = (event) => {
const value = event.target.value;
// console.log(event);
if (event.key === "Enter") {
submitInput(value);
setInputKey((previousKey) => previousKey + 1);
}
};
const onChange = (event) => {
const value = event.target.value;
return setInputValue(value);
};
const displayHistory = () => {
const visibleHistory = history.slice(-16);
let startIndex = 0;
visibleHistory.forEach((entry, index) => {
if (entry.clear)
startIndex = index + 1;
});
return visibleHistory.slice(startIndex).map(({ text }, index) => {
return <OutputLine text={text} key={index}/>
});
}
return (
<div className={styles.Terminal}>
{displayHistory()}
<InputLine
key={inputKey}
value={inputValue}
prefix={prefix}
onKeyDown={onKeyDown}
onChange={onChange}
/>
</div>
)
}