forked from tools/josh
Classify FileSystem
This commit is contained in:
parent
ea80b978c7
commit
f8fd158135
|
@ -1,14 +1,17 @@
|
||||||
class Commands {
|
class Commands {
|
||||||
constructor() {
|
constructor(terminal, fileSystem) {
|
||||||
|
this._terminal = terminal;
|
||||||
|
this._fileSystem = fileSystem;
|
||||||
|
|
||||||
this._list = {
|
this._list = {
|
||||||
clear: {
|
clear: {
|
||||||
fun: Commands.clear,
|
fun: this.clear,
|
||||||
summary: `clear terminal output`,
|
summary: `clear terminal output`,
|
||||||
usage: `clear`,
|
usage: `clear`,
|
||||||
desc: `Clears all previous terminal output.`.trimLines()
|
desc: `Clears all previous terminal output.`.trimLines()
|
||||||
},
|
},
|
||||||
cd: {
|
cd: {
|
||||||
fun: Commands.cd,
|
fun: this.cd,
|
||||||
summary: `change directory`,
|
summary: `change directory`,
|
||||||
usage: `cd [DIRECTORY]`,
|
usage: `cd [DIRECTORY]`,
|
||||||
desc: "" +
|
desc: "" +
|
||||||
|
@ -44,25 +47,25 @@ class Commands {
|
||||||
If [DIRECTORY] is empty, the files and directories in the current working directory are shown.`.trimLines()
|
If [DIRECTORY] is empty, the files and directories in the current working directory are shown.`.trimLines()
|
||||||
},
|
},
|
||||||
mkdir: {
|
mkdir: {
|
||||||
fun: Commands.mkdir,
|
fun: this.mkdir,
|
||||||
summary: `create directory`,
|
summary: `create directory`,
|
||||||
usage: `mkdir [DIRECTORY]`,
|
usage: `mkdir [DIRECTORY]`,
|
||||||
desc: `Creates a directory with name [DIRECTORY].`.trimLines()
|
desc: `Creates a directory with name [DIRECTORY].`.trimLines()
|
||||||
},
|
},
|
||||||
pwd: {
|
pwd: {
|
||||||
fun: Commands.pwd,
|
fun: this.pwd,
|
||||||
summary: `print working directory`,
|
summary: `print working directory`,
|
||||||
usage: `pwd`,
|
usage: `pwd`,
|
||||||
desc: `Displays the current working directory.`.trimLines()
|
desc: `Displays the current working directory.`.trimLines()
|
||||||
},
|
},
|
||||||
rm: {
|
rm: {
|
||||||
fun: Commands.rm,
|
fun: this.rm,
|
||||||
summary: `remove file`,
|
summary: `remove file`,
|
||||||
usage: `rm [-f | --force] FILE`,
|
usage: `rm [-f | --force] FILE`,
|
||||||
desc: `Removes FILE if it is a file.`.trimLines()
|
desc: `Removes FILE if it is a file.`.trimLines()
|
||||||
},
|
},
|
||||||
rmdir: {
|
rmdir: {
|
||||||
fun: Commands.rmdir,
|
fun: this.rmdir,
|
||||||
summary: `remove directory`,
|
summary: `remove directory`,
|
||||||
usage: `rmdir [-f | --force] DIR`,
|
usage: `rmdir [-f | --force] DIR`,
|
||||||
desc: `Removes DIR if it is a directory.`.trimLines()
|
desc: `Removes DIR if it is a directory.`.trimLines()
|
||||||
|
@ -85,12 +88,12 @@ class Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static cd(args) {
|
cd(args) {
|
||||||
return fs.cd(args[1]);
|
return this._fileSystem.cd(args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static clear() {
|
clear() {
|
||||||
Commands.clear();
|
this._terminal.clear();
|
||||||
return ``;
|
return ``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +138,7 @@ class Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
ls(args) {
|
ls(args) {
|
||||||
const files = fs.ls(args[1]);
|
const files = this._fileSystem.ls(args[1]);
|
||||||
if (files === undefined) {
|
if (files === undefined) {
|
||||||
return `The directory '${args[1]}' does not exist`;
|
return `The directory '${args[1]}' does not exist`;
|
||||||
}
|
}
|
||||||
|
@ -156,19 +159,19 @@ class Commands {
|
||||||
return dirList.concat(fileList).join(`\n`);
|
return dirList.concat(fileList).join(`\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mkdir(args) {
|
mkdir(args) {
|
||||||
return fs.mkdir(args[1]);
|
return this._fileSystem.mkdir(args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static pwd() {
|
pwd() {
|
||||||
return fs.pwd;
|
return this._fileSystem.pwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rm(args) {
|
rm(args) {
|
||||||
return fs.rm(args[1]);
|
return this._fileSystem.rm(args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static rmdir(args) {
|
rmdir(args) {
|
||||||
let path;
|
let path;
|
||||||
let force;
|
let force;
|
||||||
if (args[1] === `-f` || args[1] === `--force`) {
|
if (args[1] === `-f` || args[1] === `--force`) {
|
||||||
|
@ -179,9 +182,6 @@ class Commands {
|
||||||
force = false;
|
force = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs.rmdir(path, force);
|
return this._fileSystem.rmdir(path, force);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const commands = new Commands();
|
|
||||||
|
|
468
js/fs.js
468
js/fs.js
|
@ -1,245 +1,241 @@
|
||||||
const fs = {};
|
class FileSystem {
|
||||||
|
constructor() {
|
||||||
|
this._root = {
|
||||||
|
personal: {
|
||||||
|
steam: `<a href="https://steamcommunity.com/id/Waflix">steam</a>`,
|
||||||
|
nukapedia: `<a href="http://fallout.wikia.com/wiki/User:FDekker">nukapedia</a>`
|
||||||
|
},
|
||||||
|
projects: {
|
||||||
|
minor: {
|
||||||
|
dice: `<a href="https://fwdekker.com/dice">dice_probabilities</a>`
|
||||||
|
},
|
||||||
|
randomness: `<a href="https://github.com/FWDekker/intellij-randomness">randomness</a>`,
|
||||||
|
schaapi: `<a href="http://cafejojo.org/schaapi">schaapi</a>`
|
||||||
|
},
|
||||||
|
social: {
|
||||||
|
github: `<a href="https://github.com/FWDekker/">github</a>`,
|
||||||
|
stackoverflow: `<a href="https://stackoverflow.com/u/3307872">stackoverflow</a>`,
|
||||||
|
linkedin: `<a href="https://www.linkedin.com/in/fwdekker/">linkedin</a>`
|
||||||
|
},
|
||||||
|
"resume.pdf": `<a href="https://fwdekker.com/resume.pdf">resume.pdf</a>`
|
||||||
|
};
|
||||||
|
this.pwd = `/`;
|
||||||
|
|
||||||
|
|
||||||
// Layout
|
const visited = [];
|
||||||
fs.pwd = `/`;
|
const queue = [this._root];
|
||||||
fs.root = {
|
|
||||||
personal: {
|
|
||||||
steam: `<a href="https://steamcommunity.com/id/Waflix">steam</a>`,
|
|
||||||
nukapedia: `<a href="http://fallout.wikia.com/wiki/User:FDekker">nukapedia</a>`
|
|
||||||
},
|
|
||||||
projects: {
|
|
||||||
minor: {
|
|
||||||
dice: `<a href="https://fwdekker.com/dice">dice_probabilities</a>`
|
|
||||||
},
|
|
||||||
randomness: `<a href="https://github.com/FWDekker/intellij-randomness">randomness</a>`,
|
|
||||||
schaapi: `<a href="http://cafejojo.org/schaapi">schaapi</a>`
|
|
||||||
},
|
|
||||||
social: {
|
|
||||||
github: `<a href="https://github.com/FWDekker/">github</a>`,
|
|
||||||
stackoverflow: `<a href="https://stackoverflow.com/u/3307872">stackoverflow</a>`,
|
|
||||||
linkedin: `<a href="https://www.linkedin.com/in/fwdekker/">linkedin</a>`
|
|
||||||
},
|
|
||||||
"resume.pdf": `<a href="https://fwdekker.com/resume.pdf">resume.pdf</a>`
|
|
||||||
};
|
|
||||||
fs.files = fs.root;
|
|
||||||
|
|
||||||
|
this._root[`.`] = this._root;
|
||||||
|
|
||||||
// Functions
|
while (queue.length !== 0) {
|
||||||
fs._absolutePath = function (path) {
|
const next = queue.pop();
|
||||||
if (path.startsWith(`/`)) {
|
if (visited.indexOf(next) >= 0) {
|
||||||
return path;
|
|
||||||
} else {
|
|
||||||
return `${fs.pwd}/${path}`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fs._filePath = function (path) {
|
|
||||||
return fs._normalisePath(path).split(`/`).slice(0, -1).slice(-1).join(`/`);
|
|
||||||
};
|
|
||||||
|
|
||||||
fs._getFile = function (path) {
|
|
||||||
const abPath = fs._normalisePath(path);
|
|
||||||
|
|
||||||
let file = fs.root;
|
|
||||||
abPath.split(`/`).forEach(part => {
|
|
||||||
if (part === ``) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (file === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = file[part];
|
|
||||||
});
|
|
||||||
|
|
||||||
return file;
|
|
||||||
};
|
|
||||||
|
|
||||||
fs._normalisePath = function (path) {
|
|
||||||
return fs._sanitisePath(fs._absolutePath(path));
|
|
||||||
};
|
|
||||||
|
|
||||||
fs._parentPath = function (path) {
|
|
||||||
return fs._normalisePath(path).split(`/`).slice(0, -1).join(`/`);
|
|
||||||
};
|
|
||||||
|
|
||||||
fs._sanitisePath = function (path) {
|
|
||||||
const selfRegex = /\/\.\//; // Match `./`
|
|
||||||
const upRegex = /(\/+)([^./]+)(\/+)(\.\.)(\/+)/; // Match `/directory/../
|
|
||||||
const doubleRegex = /\/{2,}/; // Match `///`
|
|
||||||
|
|
||||||
return path
|
|
||||||
.replaceAll(selfRegex, `/`)
|
|
||||||
.replaceAll(upRegex, `/`)
|
|
||||||
.replaceAll(doubleRegex, `/`)
|
|
||||||
.toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true iff {@code file} represents a directory.
|
|
||||||
*
|
|
||||||
* @param file {Object} an object from the file system
|
|
||||||
* @returns {boolean} true iff {@code file} represents a directory
|
|
||||||
*/
|
|
||||||
fs.isDirectory = function (file) {
|
|
||||||
return (file !== undefined && typeof file !== `string`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true iff {@code file} represents a file.
|
|
||||||
*
|
|
||||||
* @param file {Object} an object from the file system
|
|
||||||
* @returns {boolean} true iff {@code file} represents a file
|
|
||||||
*/
|
|
||||||
fs.isFile = function (file) {
|
|
||||||
return (file !== undefined && typeof file === `string`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the current directory to {@code path}, if it exists.
|
|
||||||
*
|
|
||||||
* @param path the absolute or relative path to change the current directory to
|
|
||||||
* @returns {string} an empty string if the change was successful, or an error message explaining what went wrong
|
|
||||||
*/
|
|
||||||
fs.cd = function (path) {
|
|
||||||
if (path === undefined) {
|
|
||||||
return ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = fs._getFile(path);
|
|
||||||
if (file === undefined || !fs.isDirectory(file)) {
|
|
||||||
return `The directory '${path}' does not exist`;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.pwd = fs._normalisePath(path);
|
|
||||||
fs.files = file;
|
|
||||||
|
|
||||||
return ``;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the directory at {@code path}, or the current directory if no path is given.
|
|
||||||
*
|
|
||||||
* @param path {string} the absolute or relative path to the directory to return
|
|
||||||
* @returns {Object} the directory at {@code path}, or the current directory if no path is given
|
|
||||||
*/
|
|
||||||
fs.ls = function (path) {
|
|
||||||
path = (path || fs.pwd);
|
|
||||||
|
|
||||||
return fs._getFile(path);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty directory in the file system.
|
|
||||||
*
|
|
||||||
* @param path {string} the absolute or relative path to the directory to create
|
|
||||||
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
|
|
||||||
*/
|
|
||||||
fs.mkdir = function (path) {
|
|
||||||
const parentDirName = fs._parentPath(path);
|
|
||||||
const childDirName = fs._filePath(path);
|
|
||||||
|
|
||||||
const parentDir = fs._getFile(parentDirName);
|
|
||||||
if (!fs.isDirectory(parentDir)) {
|
|
||||||
return `The directory '${parentDirName}' does not exist`;
|
|
||||||
}
|
|
||||||
if (parentDir[childDirName] !== undefined) {
|
|
||||||
return `The directory '${childDirName}' already exists`;
|
|
||||||
}
|
|
||||||
|
|
||||||
parentDir[childDirName] = {};
|
|
||||||
parentDir[childDirName][`.`] = parentDir[childDirName];
|
|
||||||
parentDir[childDirName][`..`] = parentDir;
|
|
||||||
return ``;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets navigation in the file system.
|
|
||||||
*/
|
|
||||||
fs.reset = function () {
|
|
||||||
fs.pwd = `/`;
|
|
||||||
fs.files = fs.root;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a file from the file system.
|
|
||||||
*
|
|
||||||
* @param path {string} the absolute or relative path to the file to be removed
|
|
||||||
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
|
|
||||||
*/
|
|
||||||
fs.rm = function (path) {
|
|
||||||
const dirName = fs._parentPath(path);
|
|
||||||
const fileName = fs._filePath(path);
|
|
||||||
|
|
||||||
const dir = fs._getFile(dirName);
|
|
||||||
if (!fs.isDirectory(dir)) {
|
|
||||||
return `The directory '${dirName}' does not exist`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = dir[fileName];
|
|
||||||
if (!fs.isFile(file)) {
|
|
||||||
return `The file '${fileName}' does not exist`;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete dir[fileName];
|
|
||||||
return ``;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a directory from the file system.
|
|
||||||
*
|
|
||||||
* @param path {string} the absolute or relative path to the directory to be removed
|
|
||||||
* @param force {boolean} true iff the directory should be removed regardless of whether it is empty
|
|
||||||
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
|
|
||||||
*/
|
|
||||||
fs.rmdir = function (path, force) {
|
|
||||||
force = (force || false);
|
|
||||||
|
|
||||||
const parentDirName = fs._parentPath(path);
|
|
||||||
const childDirName = fs._filePath(path);
|
|
||||||
|
|
||||||
const parentDir = fs._getFile(parentDirName);
|
|
||||||
if (!fs.isDirectory(parentDir)) {
|
|
||||||
return `The directory '${parentDirName}' does not exist`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const childDir = parentDir[childDirName];
|
|
||||||
if (!fs.isDirectory(childDir)) {
|
|
||||||
return `The directory '${childDirName}' does not exist`;
|
|
||||||
}
|
|
||||||
if (!force && Object.keys(childDir).length > 2) {
|
|
||||||
return `The directory is not empty`;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete parentDir[childDirName];
|
|
||||||
return ``;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Init
|
|
||||||
(() => {
|
|
||||||
const visited = [];
|
|
||||||
const queue = [fs.files];
|
|
||||||
|
|
||||||
fs.files[`.`] = fs.files;
|
|
||||||
|
|
||||||
while (queue.length !== 0) {
|
|
||||||
const next = queue.pop();
|
|
||||||
if (visited.indexOf(next) >= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
visited.push(next);
|
|
||||||
for (const key in next) {
|
|
||||||
if (key === `.` || key === `..`) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
next[key][`.`] = next[key];
|
visited.push(next);
|
||||||
next[key][`..`] = next;
|
for (const key in next) {
|
||||||
queue.push(next[key]);
|
if (key === `.` || key === `..` || FileSystem.isFile(next[key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
next[key][`.`] = next[key];
|
||||||
|
next[key][`..`] = next;
|
||||||
|
queue.push(next[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
|
||||||
|
_absolutePath(path) {
|
||||||
|
if (path.startsWith(`/`)) {
|
||||||
|
return path;
|
||||||
|
} else {
|
||||||
|
return `${this.pwd}/${path}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_filePath(path) {
|
||||||
|
return this._normalisePath(path).split(`/`).slice(0, -1).slice(-1).join(`/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getFile(path) {
|
||||||
|
path = this._normalisePath(path);
|
||||||
|
|
||||||
|
let file = this._root;
|
||||||
|
path.split(`/`).forEach(part => {
|
||||||
|
if (part === ``) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = file[part];
|
||||||
|
});
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
_normalisePath(path) {
|
||||||
|
return FileSystem._sanitisePath(this._absolutePath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
_parentPath(path) {
|
||||||
|
return this._normalisePath(path).split(`/`).slice(0, -1).join(`/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _sanitisePath(path) {
|
||||||
|
const selfRegex = /\/\.\//; // Match `./`
|
||||||
|
const upRegex = /(\/+)([^./]+)(\/+)(\.\.)(\/+)/; // Match `/directory/../
|
||||||
|
const doubleRegex = /\/{2,}/; // Match `///`
|
||||||
|
|
||||||
|
return path
|
||||||
|
.replaceAll(selfRegex, `/`)
|
||||||
|
.replaceAll(upRegex, `/`)
|
||||||
|
.replaceAll(doubleRegex, `/`)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true iff {@code file} represents a directory.
|
||||||
|
*
|
||||||
|
* @param file {Object} an object from the file system
|
||||||
|
* @returns {boolean} true iff {@code file} represents a directory
|
||||||
|
*/
|
||||||
|
static isDirectory(file) {
|
||||||
|
return (file !== undefined && typeof file !== `string`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true iff {@code file} represents a file.
|
||||||
|
*
|
||||||
|
* @param file {Object} an object from the file system
|
||||||
|
* @returns {boolean} true iff {@code file} represents a file
|
||||||
|
*/
|
||||||
|
static isFile(file) {
|
||||||
|
return (file !== undefined && typeof file === `string`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the current directory to {@code path}, if it exists.
|
||||||
|
*
|
||||||
|
* @param path the absolute or relative path to change the current directory to
|
||||||
|
* @returns {string} an empty string if the change was successful, or an error message explaining what went wrong
|
||||||
|
*/
|
||||||
|
cd(path) {
|
||||||
|
if (path === undefined) {
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = this._getFile(path);
|
||||||
|
if (file === undefined || !FileSystem.isDirectory(file)) {
|
||||||
|
return `The directory '${path}' does not exist`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pwd = this._normalisePath(path);
|
||||||
|
this.files = file;
|
||||||
|
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the directory at {@code path}, or the current directory if no path is given.
|
||||||
|
*
|
||||||
|
* @param path {string} the absolute or relative path to the directory to return
|
||||||
|
* @returns {Object} the directory at {@code path}, or the current directory if no path is given
|
||||||
|
*/
|
||||||
|
ls(path) {
|
||||||
|
path = (path || this.pwd);
|
||||||
|
|
||||||
|
return this._getFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty directory in the file system.
|
||||||
|
*
|
||||||
|
* @param path {string} the absolute or relative path to the directory to create
|
||||||
|
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
|
||||||
|
*/
|
||||||
|
mkdir(path) {
|
||||||
|
const parentDirName = this._parentPath(path);
|
||||||
|
const childDirName = this._filePath(path);
|
||||||
|
|
||||||
|
const parentDir = this._getFile(parentDirName);
|
||||||
|
if (!FileSystem.isDirectory(parentDir)) {
|
||||||
|
return `The directory '${parentDirName}' does not exist`;
|
||||||
|
}
|
||||||
|
if (parentDir[childDirName] !== undefined) {
|
||||||
|
return `The directory '${childDirName}' already exists`;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentDir[childDirName] = {};
|
||||||
|
parentDir[childDirName][`.`] = parentDir[childDirName];
|
||||||
|
parentDir[childDirName][`..`] = parentDir;
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets navigation in the file system.
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
this.pwd = `/`;
|
||||||
|
this.files = this._root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a file from the file system.
|
||||||
|
*
|
||||||
|
* @param path {string} the absolute or relative path to the file to be removed
|
||||||
|
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
|
||||||
|
*/
|
||||||
|
rm(path) {
|
||||||
|
const dirName = this._parentPath(path);
|
||||||
|
const fileName = this._filePath(path);
|
||||||
|
|
||||||
|
const dir = this._getFile(dirName);
|
||||||
|
if (!FileSystem.isDirectory(dir)) {
|
||||||
|
return `The directory '${dirName}' does not exist`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = dir[fileName];
|
||||||
|
if (!FileSystem.isFile(file)) {
|
||||||
|
return `The file '${fileName}' does not exist`;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete dir[fileName];
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a directory from the file system.
|
||||||
|
*
|
||||||
|
* @param path {string} the absolute or relative path to the directory to be removed
|
||||||
|
* @param force {boolean} true iff the directory should be removed regardless of whether it is empty
|
||||||
|
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
|
||||||
|
*/
|
||||||
|
rmdir(path, force) {
|
||||||
|
force = (force || false);
|
||||||
|
|
||||||
|
const parentDirName = this._parentPath(path);
|
||||||
|
const childDirName = this._filePath(path);
|
||||||
|
|
||||||
|
const parentDir = this._getFile(parentDirName);
|
||||||
|
if (!FileSystem.isDirectory(parentDir)) {
|
||||||
|
return `The directory '${parentDirName}' does not exist`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const childDir = parentDir[childDirName];
|
||||||
|
if (!FileSystem.isDirectory(childDir)) {
|
||||||
|
return `The directory '${childDirName}' does not exist`;
|
||||||
|
}
|
||||||
|
if (!force && Object.keys(childDir).length > 2) {
|
||||||
|
return `The directory is not empty`;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete parentDir[childDirName];
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
const asciiHeader = ` ________ _______ _ _
|
||||||
|
| ____\\ \\ / / __ \\ | | | |
|
||||||
|
| |__ \\ \\ /\\ / /| | | | ___| | _| | _____ _ __
|
||||||
|
| __| \\ \\/ \\/ / | | | |/ _ \\ |/ / |/ / _ \\ '__|
|
||||||
|
| | \\ /\\ / | |__| | __/ <| < __/ |
|
||||||
|
|_| \\/ \\/ |_____/ \\___|_|\\_\\_|\\_\\___|_| `;
|
||||||
|
|
||||||
|
|
||||||
String.prototype.replaceAll = function (regex, replacement) {
|
String.prototype.replaceAll = function (regex, replacement) {
|
||||||
let string = this;
|
let string = this;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
const asciiHeader = ` ________ _______ _ _
|
|
||||||
| ____\\ \\ / / __ \\ | | | |
|
|
||||||
| |__ \\ \\ /\\ / /| | | | ___| | _| | _____ _ __
|
|
||||||
| __| \\ \\/ \\/ / | | | |/ _ \\ |/ / |/ / _ \\ '__|
|
|
||||||
| | \\ /\\ / | |__| | __/ <| < __/ |
|
|
||||||
|_| \\/ \\/ |_____/ \\___|_|\\_\\_|\\_\\___|_| `;
|
|
||||||
|
|
||||||
|
|
||||||
class InputHistory {
|
class InputHistory {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._history = [];
|
this._history = [];
|
||||||
|
@ -56,6 +48,9 @@ class Terminal {
|
||||||
this._prefixDiv = prefixDiv;
|
this._prefixDiv = prefixDiv;
|
||||||
this._inputHistory = new InputHistory();
|
this._inputHistory = new InputHistory();
|
||||||
|
|
||||||
|
this._fs = new FileSystem();
|
||||||
|
this._commands = new Commands(this, this._fs);
|
||||||
|
|
||||||
this._terminal.addEventListener("click", this._onclick.bind(this));
|
this._terminal.addEventListener("click", this._onclick.bind(this));
|
||||||
this._terminal.addEventListener("keypress", this._onkeypress.bind(this));
|
this._terminal.addEventListener("keypress", this._onkeypress.bind(this));
|
||||||
this._input.addEventListener("keydown", this._onkeydown.bind(this));
|
this._input.addEventListener("keydown", this._onkeydown.bind(this));
|
||||||
|
@ -103,8 +98,8 @@ class Terminal {
|
||||||
`.trimLines();
|
`.trimLines();
|
||||||
}
|
}
|
||||||
|
|
||||||
static generatePrefix() {
|
generatePrefix() {
|
||||||
return `felix@fwdekker.com <span style="color: green;">${fs.pwd}</span>> `;
|
return `felix@fwdekker.com <span style="color: green;">${this._fs.pwd}</span>> `;
|
||||||
}
|
}
|
||||||
|
|
||||||
processInput(input) {
|
processInput(input) {
|
||||||
|
@ -112,19 +107,19 @@ class Terminal {
|
||||||
this.inputText = ``;
|
this.inputText = ``;
|
||||||
this.outputText += `${this.prefixText}${input}\n`;
|
this.outputText += `${this.prefixText}${input}\n`;
|
||||||
|
|
||||||
const output = commands.parse(input.trim());
|
const output = this._commands.parse(input.trim());
|
||||||
if (output !== ``) {
|
if (output !== ``) {
|
||||||
this.outputText += output + `\n`;
|
this.outputText += output + `\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.prefixText = Terminal.generatePrefix();
|
this.prefixText = this.generatePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
fs.reset();
|
this._fs.reset();
|
||||||
|
|
||||||
this.outputText = Terminal.generateHeader();
|
this.outputText = Terminal.generateHeader();
|
||||||
this.prefixText = Terminal.generatePrefix();
|
this.prefixText = this.generatePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,6 +148,7 @@ class Terminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let terminal;
|
let terminal;
|
||||||
|
|
||||||
addOnLoad(() => {
|
addOnLoad(() => {
|
||||||
|
|
Loading…
Reference in New Issue