editx
Version:
Simple but powerful text and code editor for the console.
303 lines (247 loc) • 8.14 kB
JavaScript
const readline = require('readline');
readline.emitKeypressEvents(process.stdin);
let funcs = {}
let setup, draw, keyPressed, frameRate;
funcs.BOX = "\u2588";
funcs.CIRCLE = "\u26AA";
funcs.EMPTY = ' ';
// These are needed for ease of use to easily detect arrow keys. Even p5.js has them. DO NOT DELETE
funcs.UP = '\u001B\u005B\u0041';
funcs.DOWN = '\u001B\u005B\u0042';
funcs.LEFT = '\u001B\u005B\u0044';
funcs.RIGHT = '\u001B\u005B\u0043';
let matrix = []; // Matrix should not be accesible outside engine
let startTime = new Date().getTime();
funcs.width = process.stdout.columns;
funcs.height = process.stdout.rows - 1;
funcs.avaliableColors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'lightblack', 'lightred', 'lightgreen', 'lightyellow', 'lightblue', 'lightmagenta', 'lightcyan', 'lightwhite'];
let foregroundColours = {
black: "\u001b[30m",
red: "\u001b[31m",
green: "\u001b[32m",
yellow: "\u001b[33m",
blue: "\u001b[34m",
magenta: "\u001b[35m",
cyan: "\u001b[36m",
white: "\u001b[37m",
lightblack: "\u001b[30;1m",
lightred: "\u001b[31;1m",
lightgreen: "\u001b[32;1m",
lightyellow: "\u001b[33;1m",
lightblue: "\u001b[34;1m",
lightmagenta: "\u001b[35;1m",
lightcyan: "\u001b[36;1m",
lightwhite: "\u001b[37;1m"
}
let backgroundColours = {
black: "\u001b[40m",
red: "\u001b[41m",
green: "\u001b[42m",
yellow: "\u001b[43m",
blue: "\u001b[44m",
magenta: "\u001b[45m",
cyan: "\u001b[46m",
white: "\u001b[47m",
lightblack: "\u001b[40;1m",
lightred: "\u001b[41;1m",
lightgreen: "\u001b[42;1m",
lightyellow: "\u001b[43;1m",
lightblue: "\u001b[44;1m",
lightmagenta: "\u001b[45;1m",
lightcyan: "\u001b[46;1m",
lightwhite: "\u001b[47;1m"
}
let bg = "",
fg = "";
let createMatrix = function () {
funcs.width = process.stdout.columns;
funcs.height = process.stdout.rows;
matrix = [];
for (let i = 0; i < funcs.height; i++) {
matrix[i] = [];
for (let j = 0; j < funcs.width; j++) {
matrix[i][j] = {
value: '',
fg: '',
bg: ''
};
}
}
}
let lastFGColor, lastBGColor;
let renderMatrix = function () {
let string = "\033[?25h";
for (let y = 0; y < funcs.height; y++) {
for (let x = 0; x < funcs.width; x++) {
string += matrix[y][x].fg;
string += matrix[y][x].bg;
if (lastBGColor != matrix[y][x].bg || lastFGColor != matrix[y][x].fg) {
if (matrix[y][x].value) {
string += matrix[y][x].value
string += "\u001b[0m"
} else {
string += "\u001b[0m"
string += " "
}
} else {
string += matrix[y][x].value || ' ';
}
lastBGColor = matrix[y][x].bg;
lastFGColor = matrix[y][x].fg;
}
}
process.stdout.write('\033[0;0f') // move cursor to 0, 0
process.stdout.write(string); // print contents of matrix
process.stdout.write('\033[' + (cursorY + 1) + ';' + (cursorX + 1) + 'f'); // move cursor to desired location
}
funcs.clear = function () {
for (let y = 0; y < funcs.height; y++) {
for (let x = 0; x < funcs.width; x++) {
matrix[y][x] = {
value: '',
fg: '',
bg: ''
};
}
}
}
funcs.drawRect = function (x, y, w, h, value) {
for (let i = y; i < y + h; i++) {
for (let j = x; j < x + w; j++) {
funcs.drawPoint(j, i, value);
}
}
}
funcs.drawCircle = function (x, y, r, value) {
var px, py;
for (let d = r; d > 0; d -= 0.5) {
for (let i = 0; i < d * 36; i++) {
px = Math.round((Math.sin(i) * d * 1.95) + x);
py = Math.round(Math.cos(i) * d + y);
funcs.drawPoint(px, py, value);
}
}
}
funcs.loop = function (n, min, max) {
return (n < min) ? max - Math.abs(n % max) : n % max
}
funcs.drawPoint = function (x, y, value) {
if (y >= 0 && y < funcs.height && x >= 0 && x < funcs.width) {
matrix[funcs.constrain(Math.floor(y), 0, funcs.height)][funcs.constrain(Math.floor(x), 0, funcs.width)] = {
value: value[0],
fg: fg || "",
bg: bg || ""
};
}
}
funcs.drawLine = function (x, y, dirX, dirY, length, value) {
for (let i = 0; i < length; i++) {
funcs.drawPoint(x, y, value);
x += dirX;
y += dirY;
}
}
funcs.drawText = function (x, y, text) {
for (var i = 0; i < text.length; i++) {
funcs.drawPoint(x + i, y, text[i]);
}
}
funcs.constrain = function (x, min, max) {
return x < min ? min : x > max ? max : x;
}
funcs.map = function (n, start1, stop1, start2, stop2) {
return (n - start1) / (stop1 - start1) * (stop2 - start2) + start2;
}
funcs.fillForeground = function (colour) {
let clr = foregroundColours[colour.toLowerCase()];
if (!clr)
if (colour[0] == "\\") clr = clr
else clr = "";
fg = clr;
}
funcs.fillBackground = function (colour) {
let clr = backgroundColours[colour.toLowerCase()];
if (!clr)
if (colour[0] == "\\") clr = clr
else clr = "";
bg = clr;
}
funcs.noBg = function () {
bg = ""
process.stdout.write('\u001b[0m')
}
funcs.noFg = function () {
fg = ""
process.stdout.write('\u001b[0m')
}
funcs.drawBorder = function (value) {
funcs.drawLine(0, 0, 1, 0, funcs.width, value);
funcs.drawLine(0, funcs.height - 1, 1, 0, funcs.width, value);
funcs.drawLine(0, 0, 0, 1, funcs.height, value);
funcs.drawLine(funcs.width - 1, 0, 0, 1, funcs.height, value);
}
funcs.Vector = function (x, y) {
this.x = x || 0;
this.y = y || 0;
this.mag = () => Math.sqrt(x * x + y * y)
this.dir = () => Math.atan(this.y / this.x);
this.setMag = mag => {
this.normalise();
this.mult(mag);
}
this.setDir = angle => {
this.x = this.mag * Math.cos(angle);
this.y = this.mag * Math.sin(angle);
}
this.mult = n => {
this.x *= n;
this.y *= n;
}
this.normalise = () => {
if (this.mag() != 0) this.mult(1 / this.mag());
}
}
funcs.millis = 0;
// Init function used, so users script has access to engine variable like width in setup; Was not possible in draw
funcs.init = function (s, d, k, f, customRepaint) {
setup = s;
draw = d;
keyPressed = k;
frameRate = f || 30;
process.stdout.write('\033[?25h')
createMatrix();// Setup called after matrix is created
setup();
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on("keypress", (str, key) => { // The event listener only needs to be set once. Not every frame in draw.
if (keyPressed) keyPressed(key);
})
process.stdout.on('resize', () => {
createMatrix();
funcs.render();
}); // Recreate the matrix if window resized.
if (!customRepaint) {
setInterval(() => {
funcs.render();
}, 1000 / frameRate);
}
}
var cursorX = 0, cursorY = 0;
funcs.setCursor = function (x, y) {
cursorX = x;
cursorY = y;
process.stdout.write('\033[' + (cursorY + 1) + ';' + (cursorX + 1) + 'f'); // move cursor to desired location
}
funcs.render = () => {
funcs.clear();
draw();
renderMatrix();
funcs.millis = new Date().getTime() - startTime
}
process.on('SIGINT', e => funcs.exit())
funcs.exit = e => {
process.stdout.write('\033[2J\u001b[0m\033[?25l\033c');
require('child_process').exec(process.platform == "win32" ? "cls" : "clear");
process.exit();
}
module.exports = funcs;