homepage.js/react/resume/src/emulator/zsh.js

206 lines
4.3 KiB
JavaScript
Raw Normal View History

2023-03-12 16:09:19 +01:00
import { Terminal } from 'xterm';
import { XTerm } from 'xterm-for-react';
const fs = require('./fs');
global.fs = fs;
const cmds = require('./commands');
2023-03-12 16:09:19 +01:00
/**
2023-03-16 08:31:37 +01:00
* @type { Terminal }
2023-03-12 16:09:19 +01:00
*/
let terminal;
/**
* @type { XTerm }
*/
let dom;
2023-03-12 16:09:19 +01:00
const prompt = '\033[1;32muser@blek.codes \033[36m~ $ \033[0m';
let cmd = '';
2023-03-16 05:10:22 +01:00
let lastcmd = window.sessionStorage.getItem('last_cmd') || '';
2023-03-12 16:20:34 +01:00
function text_prompt() {
return prompt.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
}
2023-03-12 16:09:19 +01:00
2023-03-17 07:08:49 +01:00
/**
*
* @param { string } char
* @param { KeyboardEvent } dom
*/
function pr_char(char, dom) {
if (dom.key.length != 1) return;
2023-03-12 16:09:19 +01:00
cmd += char;
terminal.write(char);
}
function exec_file(f) {
const exists = fs.existsSync(f);
if (!exists) {
terminal.write('zsh: no such file or directory: ' + f);
return;
}
const executable = fs.accessSync(f, fs.constants.X_OK);
if (!executable) {
terminal.writeln('zsh: permission denied: ' + f);
return;
}
terminal.writeln('This is an online resume. It is not big enough to have a script runtime.\n');
return;
2023-03-12 16:09:19 +01:00
}
2023-03-16 08:31:37 +01:00
async function exec_cmd() {
2023-03-12 16:09:19 +01:00
let c = cmd;
2023-03-15 07:13:25 +01:00
const command = c.split(' ')[0];
reset_cmd(c);
2023-03-15 07:13:25 +01:00
lastcmd = c;
2023-03-16 05:10:22 +01:00
window.sessionStorage.setItem('last_cmd', c);
2023-03-15 07:13:25 +01:00
if (command == '') {
print_prompt();
return;
}
// if path
2023-03-15 07:13:25 +01:00
if (command.match(/^((\.|\.\.)\/|\/).+$/gm)) {
exec_file(command);
terminal.writeln('');
print_prompt();
return;
}
2023-03-15 07:13:25 +01:00
if (cmds[command] != undefined) {
2023-03-16 08:31:37 +01:00
const startY = terminal.buffer.normal.cursorY
await cmds[command](c.split(' '), terminal);
await (new Promise(resolve => setTimeout(resolve, 10)));
if (terminal.buffer.active.cursorX != 0 && startY != terminal.buffer.active.cursorY) {
2023-03-16 05:25:41 +01:00
terminal.write('\033[30;47m%\033[0m\n');
}
print_prompt();
return;
}
2023-03-15 07:13:25 +01:00
terminal.writeln('zsh: command not found: ' + command);
2023-03-12 16:09:19 +01:00
print_prompt();
}
function print_prompt() {
terminal.write(prompt);
2023-03-12 16:20:34 +01:00
}
function reprint_prompt() {
terminal.write('\033[2K\r');
print_prompt();
}
2023-03-12 16:09:19 +01:00
function reset_cmd() {
cmd = '';
terminal.writeln('');
}
2023-03-17 07:08:49 +01:00
function cbackspace() {
2023-03-17 07:38:28 +01:00
let exploded = cmd.substring(0, cmd.length - 2).split(' ');
if (exploded.length == 1) {
2023-03-17 07:08:49 +01:00
reprint_prompt();
cmd = '';
return;
}
exploded.pop();
2023-03-17 07:08:49 +01:00
cmd = exploded.join(' ') + ' ';
reprint_prompt();
terminal.write(cmd);
return;
}
function backspace(isCtrl) {
if (terminal.buffer.active.cursorX <= text_prompt().length) return;
if (isCtrl) {
return cbackspace();
}
2023-03-17 07:08:49 +01:00
terminal.write('\b \b');
cmd = cmd.substring(0, cmd.length - 1);
}
/** @param { KeyboardEvent } dom */
function control_char(id, dom) {
2023-03-12 16:09:19 +01:00
switch (id) {
// backspace
case 8:
2023-03-17 07:08:49 +01:00
backspace(dom.ctrlKey);
2023-03-12 16:09:19 +01:00
break;
// enter
case 13:
exec_cmd();
break;
2023-03-15 07:13:25 +01:00
case 38:
if (lastcmd == '') break;
cmd = lastcmd;
reprint_prompt();
terminal.write(lastcmd);
break;
2023-03-12 16:09:19 +01:00
// Ctrl+c
case 67:
if (dom.ctrlKey) {
terminal.write('^C');
reset_cmd();
print_prompt();
break;
}
2023-03-12 16:09:19 +01:00
2023-03-17 07:08:49 +01:00
case 86:
if (dom.altKey) break;
2023-03-12 16:20:34 +01:00
2023-03-12 16:09:19 +01:00
default:
2023-03-16 08:31:37 +01:00
if (dom.ctrlKey && (dom.key.length == 1)) {
terminal.write('^' + dom.key.toUpperCase());
break;
}
terminal.write('<');
if (dom.ctrlKey) terminal.write('C');
if (dom.altKey) terminal.write('A');
if (dom.shiftKey) terminal.write('S');
terminal.write(`${id}>`)
2023-03-12 16:09:19 +01:00
break;
}
}
function key(e) {
/** @type {KeyboardEvent} */
const dom = e.domEvent;
2023-03-15 07:13:25 +01:00
if (dom.key.length == 1 && !(dom.ctrlKey || dom.altKey)) {
2023-03-17 07:08:49 +01:00
pr_char(e.domEvent.key, dom);
2023-03-12 16:09:19 +01:00
} else {
control_char(e.domEvent.keyCode, dom)
2023-03-12 16:09:19 +01:00
}
}
2023-03-17 07:08:49 +01:00
function register(t, d) {
2023-03-12 16:09:19 +01:00
terminal = t;
dom = d;
2023-03-12 16:09:19 +01:00
terminal.onKey(key);
terminal.write(prompt);
2023-03-17 07:08:49 +01:00
}
register.pr_char = pr_char;
module.exports = register;