sl :)
This commit is contained in:
@ -116,6 +116,175 @@ const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
xtermRef.current.write(`\r\nls: cannot access '${currentPath.current}': Not a directory`);
|
xtermRef.current.write(`\r\nls: cannot access '${currentPath.current}': Not a directory`);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'pwd':
|
||||||
|
xtermRef.current.write('\r\n' + currentPath.current);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'find':
|
||||||
|
if (args.length === 0) {
|
||||||
|
xtermRef.current.write('\r\nfind: missing path\r\nUsage: find <path> [-name <pattern>]');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const findPath = args[0];
|
||||||
|
const nameIndex = args.indexOf('-name');
|
||||||
|
const namePattern = nameIndex !== -1 && args[nameIndex + 1] ? args[nameIndex + 1] : '';
|
||||||
|
|
||||||
|
const findResults: string[] = [];
|
||||||
|
|
||||||
|
// Simple recursive search through filesystem
|
||||||
|
const searchInPath = (searchPath: string, depth: number = 0) => {
|
||||||
|
if (depth > 10) return; // Prevent infinite recursion
|
||||||
|
|
||||||
|
const pathContent = fileSystem[searchPath];
|
||||||
|
if (Array.isArray(pathContent)) {
|
||||||
|
pathContent.forEach(item => {
|
||||||
|
const itemPath = searchPath === '/' ? '/' + item : searchPath + '/' + item;
|
||||||
|
|
||||||
|
// Check if item matches pattern (if specified)
|
||||||
|
if (!namePattern || item.includes(namePattern.replace(/\*/g, ''))) {
|
||||||
|
findResults.push(itemPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively search subdirectories
|
||||||
|
if (Array.isArray(fileSystem[itemPath])) {
|
||||||
|
searchInPath(itemPath, depth + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fileSystem[findPath] !== undefined) {
|
||||||
|
if (!namePattern) {
|
||||||
|
findResults.push(findPath);
|
||||||
|
}
|
||||||
|
searchInPath(findPath);
|
||||||
|
|
||||||
|
if (findResults.length > 0) {
|
||||||
|
xtermRef.current.write('\r\n' + findResults.join('\r\n'));
|
||||||
|
} else {
|
||||||
|
xtermRef.current.write(`\r\nfind: no files found`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xtermRef.current.write(`\r\nfind: ${findPath}: No such file or directory`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'head':
|
||||||
|
const headLines = args[0] === '-n' && args[1] ? parseInt(args[1]) : 10;
|
||||||
|
const headFile = args[0] === '-n' ? args[2] : args[0];
|
||||||
|
|
||||||
|
if (!headFile) {
|
||||||
|
xtermRef.current.write('\r\nhead: missing file operand');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let headFilePath: string;
|
||||||
|
if (headFile.startsWith('/')) {
|
||||||
|
headFilePath = headFile;
|
||||||
|
} else {
|
||||||
|
headFilePath = (currentPath.current === '/' ? '' : currentPath.current) + '/' + headFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headContent = fileSystem[headFilePath];
|
||||||
|
if (headContent === undefined) {
|
||||||
|
xtermRef.current.write(`\r\nhead: ${headFile}: No such file or directory`);
|
||||||
|
} else if (Array.isArray(headContent)) {
|
||||||
|
xtermRef.current.write(`\r\nhead: ${headFile}: Is a directory`);
|
||||||
|
} else {
|
||||||
|
const lines = headContent.split('\n');
|
||||||
|
const displayLines = lines.slice(0, headLines);
|
||||||
|
xtermRef.current.write('\r\n' + displayLines.join('\r\n'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tail':
|
||||||
|
const tailLines = args[0] === '-n' && args[1] ? parseInt(args[1]) : 10;
|
||||||
|
const tailFile = args[0] === '-n' ? args[2] : args[0];
|
||||||
|
|
||||||
|
if (!tailFile) {
|
||||||
|
xtermRef.current.write('\r\ntail: missing file operand');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tailFilePath: string;
|
||||||
|
if (tailFile.startsWith('/')) {
|
||||||
|
tailFilePath = tailFile;
|
||||||
|
} else {
|
||||||
|
tailFilePath = (currentPath.current === '/' ? '' : currentPath.current) + '/' + tailFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tailContent = fileSystem[tailFilePath];
|
||||||
|
if (tailContent === undefined) {
|
||||||
|
xtermRef.current.write(`\r\ntail: ${tailFile}: No such file or directory`);
|
||||||
|
} else if (Array.isArray(tailContent)) {
|
||||||
|
xtermRef.current.write(`\r\ntail: ${tailFile}: Is a directory`);
|
||||||
|
} else {
|
||||||
|
const lines = tailContent.split('\n');
|
||||||
|
const displayLines = lines.slice(-tailLines);
|
||||||
|
xtermRef.current.write('\r\n' + displayLines.join('\r\n'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sl':
|
||||||
|
// Easter egg: Steam Locomotive animation
|
||||||
|
xtermRef.current.write('\r\n');
|
||||||
|
const trainFrames = [
|
||||||
|
" ==== ________ ___________",
|
||||||
|
" _D _| |_______/ \\__I_I_____===__|_________|",
|
||||||
|
" |(_)--- | H\\________/ | | =|___ ___|",
|
||||||
|
" / | | H | | | | ||_| |_||",
|
||||||
|
" | | | H |__--------------------| [___] |",
|
||||||
|
" | ________|___H__/__|_____/[][]~\\_______| |",
|
||||||
|
" |/ | |-----------I_____I [][] [] D |=======|__",
|
||||||
|
"__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__|",
|
||||||
|
" |/-=|___|= || || || |_____/~\\___/",
|
||||||
|
" \\_/ \\O=====O=====O=====O_/ \\_/"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Calculate train width (length of longest line)
|
||||||
|
const trainWidth = Math.max(...trainFrames.map(line => line.length));
|
||||||
|
|
||||||
|
// Start position: completely off-screen to the right
|
||||||
|
let position = xtermRef.current.cols + 10;
|
||||||
|
|
||||||
|
const animateTrain = () => {
|
||||||
|
// Stop when train is completely off-screen to the left
|
||||||
|
if (position < -trainWidth - 5) {
|
||||||
|
xtermRef.current?.write('\x1b[2J\x1b[H'); // Clear screen one final time
|
||||||
|
prompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear screen and position cursor at top
|
||||||
|
xtermRef.current?.write('\x1b[2J\x1b[H');
|
||||||
|
|
||||||
|
// Draw each line of the train with proper spacing
|
||||||
|
trainFrames.forEach((line) => {
|
||||||
|
if (position >= 0) {
|
||||||
|
// Train is partially or fully on screen from the right
|
||||||
|
const spaces = ' '.repeat(position);
|
||||||
|
const visiblePart = line.substring(0, xtermRef.current!.cols - position);
|
||||||
|
xtermRef.current?.write(spaces + visiblePart + '\r\n');
|
||||||
|
} else if (position + line.length > 0) {
|
||||||
|
// Train is partially off-screen to the left
|
||||||
|
const startIdx = Math.abs(position);
|
||||||
|
const visiblePart = line.substring(startIdx, startIdx + xtermRef.current!.cols);
|
||||||
|
xtermRef.current?.write(visiblePart + '\r\n');
|
||||||
|
} else {
|
||||||
|
// Train is completely off-screen to the left, just write empty line
|
||||||
|
xtermRef.current?.write('\r\n');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
position -= 3; // Move train left by 3 characters each frame
|
||||||
|
setTimeout(animateTrain, 120); // Slightly slower for smoother animation
|
||||||
|
};
|
||||||
|
|
||||||
|
animateTrain();
|
||||||
|
return; // Don't call prompt() immediately
|
||||||
|
|
||||||
case 'cd':
|
case 'cd':
|
||||||
const targetDir = args[0];
|
const targetDir = args[0];
|
||||||
if (!targetDir) {
|
if (!targetDir) {
|
||||||
@ -188,8 +357,12 @@ const TerminalComponent: React.FC<TerminalProps> = ({
|
|||||||
const helpText =
|
const helpText =
|
||||||
"Available Commands:\r\n" +
|
"Available Commands:\r\n" +
|
||||||
" ls List directory contents\r\n" +
|
" ls List directory contents\r\n" +
|
||||||
|
" pwd Print working directory\r\n" +
|
||||||
" cd <directory> Change directory\r\n" +
|
" cd <directory> Change directory\r\n" +
|
||||||
" cat <file> Display file contents\r\n" +
|
" cat <file> Display file contents\r\n" +
|
||||||
|
" find <path> [-name <pattern>] Search for files\r\n" +
|
||||||
|
" head [-n <num>] <file> Show first lines of file\r\n" +
|
||||||
|
" tail [-n <num>] <file> Show last lines of file\r\n" +
|
||||||
" clear Clear the screen\r\n" +
|
" clear Clear the screen\r\n" +
|
||||||
" help Display this help message\r\n\r\n" +
|
" help Display this help message\r\n\r\n" +
|
||||||
"Tips:\r\n" +
|
"Tips:\r\n" +
|
||||||
|
Reference in New Issue
Block a user