From 5d8a04794993f37cc1facaffffd2b57be3a32c89 Mon Sep 17 00:00:00 2001 From: sample-text-here <56274831+sample-text-here@users.noreply.github.com> Date: Fri, 25 Jun 2021 17:48:30 -0600 Subject: [PATCH] stuff --- README.md | 14 ++++---- canvas.js | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ input.js | 47 ++++++++++++++++++++++++++ server.js | 2 +- 4 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 canvas.js create mode 100644 input.js diff --git a/README.md b/README.md index 6a2c89f..863c05c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # hundred -a coding challenge i made for myself; how much -can i fit in one hundred lines or less? +a coding challenge i made for myself; how much can i fit in one hundred +lines or less? -i'll try to keep these understandable and not -mangle/minify them. if you want to use them, -you probrably should edit them to your liking -first. +i'll try to keep these understandable and not mangle/minify them. if +you want to use them, you probrably should edit them to your liking +first. **note: many of these are buggy. please double check before +using them** - `server.js` basic http server based off of express - `templater.js` pre-render your webpages server side @@ -19,3 +19,5 @@ first. - `tictactoe.js` (deno) two player tic-tac-toe game - `xml.js` xml/html parser - `p2p.js` sample p2p protocol implementation +- `canvas.js` a terminal canvas emulator with many, many known bugs +- `input.js` simple terminal raw input diff --git a/canvas.js b/canvas.js new file mode 100644 index 0000000..9c4b2ea --- /dev/null +++ b/canvas.js @@ -0,0 +1,99 @@ +const block = "\u2580" +const nl = s => s.str.replace(/\n/g, `\n\x1b[${s.x + 1}G`) +const fmt = s => `\x1b[${Math.floor(s.y / 2) + 1};${s.x + 1}H${nl(s)}`; +class Color { + static black = 0; + static red = 1; + static green = 2; + static yellow = 3; + static blue = 4; + static purple = 5; + static cyan = 6; + static white = 7; +} + +class Canvas { + constructor(w, h) { + if(h) this.rw = w, this.rh = h; + this.strs = []; + this.buffer = []; + for(let i = 0; i < this.height; i++) this.buffer.push([]); + this.clear(); + this.color = Color.black; + } + + flush(clear = true) { + let curtop = -1, curbot = -1; + let runtop = true, runbot = true; + let str = "\x1b[0;0H"; + for(let i = 0; i < this.height; i += 2) { + for(let j = 0; j < this.width; j++) { + const top = this.buffer[i][j], bottom = this.buffer[i + 1][j]; + const resumed = !(runtop || runbot); + runtop = top !== -1, runbot = bottom !== -1; + if(!(runtop || runbot)) continue; + if(resumed) str += `\x1b[${i / 2 + 1};${j + 1}H`; + if(top !== curtop) { + str += `\x1b[3${top === -1 ? 0 : top}m`; + curtop = top; + } + if(bottom !== curbot) { + str += `\x1b[4${bottom === -1 ? 0 : bottom}m`; + curbot = bottom; + } + str += block; + } + } + if(curtop !== -1 || curbot !== -1) str += "\x1b[0m"; + for(let i of this.strs) str += fmt(i); + process.stdout.write(str); + if(clear) this.clear(); + } + + clear() { + for(let i = 0; i < this.height; i++) { + for(let j = 0; j < this.width; j++) { + this.buffer[i][j] = -1; + } + } + while(this.strs.length) this.strs.pop(); + } + + pixel(x, y) { + this.buffer[y][x] = this.color; + } + + rect(x, y, w, h) { + for(let i = y; i < y + h; i++) { + for(let j = x; j < x + w; j++) { + this.buffer[i][j] = this.color; + } + } + } + + text(str, x, y) { + this.strs.push({ str, x, y }); + } + + canvas(c, x, y, flush = true) { + for(let i = 0; i < c.height; i++) { + for(let j = 0; j < c.width; j++) { + if(c.buffer[i][j] !== -1) this.buffer[i + y][j + x] = c.buffer[i][j]; + } + } + for(let i of c.strs) this.strs.push({ str: i.str, x: i.x + x, y: i.y + y }); + if(flush) c.clear(); + } + + get width() { + return this.rw ? this.rw : process.stdout.columns; + } + + get height() { + return this.rh ? this.rh : process.stdout.rows * 2; + } + + static color = Color; +} + +module.exports = Canvas; diff --git a/input.js b/input.js new file mode 100644 index 0000000..04df815 --- /dev/null +++ b/input.js @@ -0,0 +1,47 @@ +const EventEmitter = require("events"); +const Keys = { + up: Buffer.from([0x1B, 0x5B, 0x41]), + down: Buffer.from([0x1B, 0x5B, 0x42]), + right: Buffer.from([0x1B, 0x5B, 0x43]), + left: Buffer.from([0x1B, 0x5B, 0x44]), + left: Buffer.from([0x1B, 0x5B, 0x44]), + tab: Buffer.from([0x07]), + enter: Buffer.from([0x0A]), + space: Buffer.from([0x20]), +}; + +function isPrint(char) { + if(char >= 'a' && char <= 'z') return true; + if(char >= 'A' && char <= 'Z') return true; + if(char >= '0' && char <= '9') return true; + if(char >= '[' && char <= '_') return true; + if(char >= '{' && char <= '~') return true; + return false; +} + +class Input extends EventEmitter { + constructor(stream) { + super(); + stream.on("data", this.handle.bind(this)); + this.stream = stream; + } + + handle(data) { + for(let i in Keys) { + if(data.equals(Keys[i])) this.emit(i); + } + const key = data.toString(); + if(isPrint(key)) this.emit(key); + this.emit("data", data); + } + + hijack() { + this.stream.setRawMode(true); + } + + close() { + this.stream?.setRawMode(false); + } +} + +module.exports = Input; diff --git a/server.js b/server.js index b74e838..a24ebc0 100644 --- a/server.js +++ b/server.js @@ -34,6 +34,7 @@ function parse(route, url) { url = url.slice(i.length); } else return null; } + if(url.length) return null; return data; } @@ -91,7 +92,6 @@ class Server extends http.Server { js: "text/javascript", json: "application/json", png: "image/png", - jpg: "image/jpeg", jpeg: "image/jpeg", }; }