From 594c4c674dd357540beee9eace3789b33f692e8f Mon Sep 17 00:00:00 2001 From: Jason Pochanke Date: Tue, 30 Jun 2026 20:23:53 +0200 Subject: [PATCH] init --- index.html | 19 + input.js | 71 +++ main.js | 20 + parser.js | 1424 ++++++++++++++++++++++++++++++++++++++++++++++++++++ render.js | 13 + 5 files changed, 1547 insertions(+) create mode 100644 index.html create mode 100644 input.js create mode 100644 main.js create mode 100644 parser.js create mode 100644 render.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..5e3380f --- /dev/null +++ b/index.html @@ -0,0 +1,19 @@ + + +
+ diff --git a/input.js b/input.js new file mode 100644 index 0000000..056b1f0 --- /dev/null +++ b/input.js @@ -0,0 +1,71 @@ +export function setupInput(buffer, cursor, onChange) { + document.addEventListener("keydown", (e) => { + if (e.key === "ArrowUp") { + e.preventDefault(); + if (cursor.line > 0) cursor.line--; + cursor.col = Math.min(cursor.col, buffer[cursor.line].length); + onChange(); + return; + } + if (e.key === "ArrowDown") { + e.preventDefault(); + if (cursor.line < buffer.length - 1) cursor.line++; + cursor.col = Math.min(cursor.col, buffer[cursor.line].length); + onChange(); + return; + } + if (e.key === "ArrowLeft") { + e.preventDefault(); + if (cursor.col > 0) cursor.col--; + else if (cursor.line > 0) { + cursor.line--; + cursor.col = buffer[cursor.line].length; + } + onChange(); + return; + } + if (e.key === "ArrowRight") { + e.preventDefault(); + if (cursor.col < buffer[cursor.line].length) cursor.col++; + else if (cursor.line < buffer.length - 1) { + cursor.line++; + cursor.col = 0; + } + onChange(); + return; + } + if (e.key === "Backspace") { + e.preventDefault(); + if (cursor.col > 0) { + const line = buffer[cursor.line]; + buffer[cursor.line] = line.slice(0, cursor.col - 1) + line.slice(cursor.col); + cursor.col--; + } else if (cursor.line > 0) { + cursor.col = buffer[cursor.line - 1].length; + buffer[cursor.line - 1] += buffer[cursor.line]; + buffer.splice(cursor.line, 1); + cursor.line--; + } + onChange(); + return; + } + if (e.key === "Enter") { + e.preventDefault(); + const line = buffer[cursor.line]; + const rest = line.slice(cursor.col); + buffer[cursor.line] = line.slice(0, cursor.col); + buffer.splice(cursor.line + 1, 0, rest); + cursor.line++; + cursor.col = 0; + onChange(); + return; + } + if (e.key.length === 1) { + e.preventDefault(); + const line = buffer[cursor.line]; + buffer[cursor.line] = line.slice(0, cursor.col) + e.key + line.slice(cursor.col); + cursor.col++; + onChange(); + } + }); +} diff --git a/main.js b/main.js new file mode 100644 index 0000000..ef67114 --- /dev/null +++ b/main.js @@ -0,0 +1,20 @@ +import { render } from "./render.js"; +import { setupInput } from "./input.js"; + +const buffer = ["Hello, world!", "Second line."]; +const cursor = { line: 0, col: 0 }; + +function onChange() { + render(buffer, cursor); + try { + console.log(buffer.map((line) => JSON.parse(App.testing(line)))); + } catch (e) { + console.error(e); + } + document.getElementById("text").innerHTML += "
"; +} + +function escapeHtml(s) {} + +setupInput(buffer, cursor, onChange); +render(buffer, cursor); diff --git a/parser.js b/parser.js new file mode 100644 index 0000000..d02cca5 --- /dev/null +++ b/parser.js @@ -0,0 +1,1424 @@ +var App = (() => { + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from2, except, desc) => { + if (from2 && typeof from2 === "object" || typeof from2 === "function") { + for (let key of __getOwnPropNames(from2)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + + // build/dev/javascript/markdown2/markdown2.mjs + var markdown2_exports = {}; + __export(markdown2_exports, { + main: () => main, + testing: () => testing + }); + + // build/dev/javascript/prelude.mjs + var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label) => label in fields ? fields[label] : this[label] + ); + return new this.constructor(...properties); + } + }; + var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + atLeastLength(desired) { + let current = this; + while (desired-- > 0 && current) current = current.tail; + return current !== void 0; + } + hasLength(desired) { + let current = this; + while (desired-- > 0 && current) current = current.tail; + return desired === -1 && current instanceof Empty; + } + countLength() { + let current = this; + let length2 = 0; + while (current) { + current = current.tail; + length2++; + } + return length2 - 1; + } + }; + function prepend(element, tail) { + return new NonEmpty(element, tail); + } + function toList(elements, tail) { + return List.fromArray(elements, tail); + } + var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } + }; + var Empty = class extends List { + }; + var List$Empty = () => new Empty(); + var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } + }; + var List$NonEmpty = (head, tail) => new NonEmpty(head, tail); + var List$isNonEmpty = (value) => value instanceof NonEmpty; + var List$NonEmpty$first = (value) => value.head; + var List$NonEmpty$rest = (value) => value.tail; + var BitArray = class { + /** + * The size in bits of this bit array's data. + * + * @type {number} + */ + bitSize; + /** + * The size in bytes of this bit array's data. If this bit array doesn't store + * a whole number of bytes then this value is rounded up. + * + * @type {number} + */ + byteSize; + /** + * The number of unused high bits in the first byte of this bit array's + * buffer prior to the start of its data. The value of any unused high bits is + * undefined. + * + * The bit offset will be in the range 0-7. + * + * @type {number} + */ + bitOffset; + /** + * The raw bytes that hold this bit array's data. + * + * If `bitOffset` is not zero then there are unused high bits in the first + * byte of this buffer. + * + * If `bitOffset + bitSize` is not a multiple of 8 then there are unused low + * bits in the last byte of this buffer. + * + * @type {Uint8Array} + */ + rawBuffer; + /** + * Constructs a new bit array from a `Uint8Array`, an optional size in + * bits, and an optional bit offset. + * + * If no bit size is specified it is taken as `buffer.length * 8`, i.e. all + * bytes in the buffer make up the new bit array's data. + * + * If no bit offset is specified it defaults to zero, i.e. there are no unused + * high bits in the first byte of the buffer. + * + * @param {Uint8Array} buffer + * @param {number} [bitSize] + * @param {number} [bitOffset] + */ + constructor(buffer, bitSize, bitOffset) { + if (!(buffer instanceof Uint8Array)) { + throw globalThis.Error( + "BitArray can only be constructed from a Uint8Array" + ); + } + this.bitSize = bitSize ?? buffer.length * 8; + this.byteSize = Math.trunc((this.bitSize + 7) / 8); + this.bitOffset = bitOffset ?? 0; + if (this.bitSize < 0) { + throw globalThis.Error(`BitArray bit size is invalid: ${this.bitSize}`); + } + if (this.bitOffset < 0 || this.bitOffset > 7) { + throw globalThis.Error( + `BitArray bit offset is invalid: ${this.bitOffset}` + ); + } + if (buffer.length !== Math.trunc((this.bitOffset + this.bitSize + 7) / 8)) { + throw globalThis.Error("BitArray buffer length is invalid"); + } + this.rawBuffer = buffer; + } + /** + * Returns a specific byte in this bit array. If the byte index is out of + * range then `undefined` is returned. + * + * When returning the final byte of a bit array with a bit size that's not a + * multiple of 8, the content of the unused low bits are undefined. + * + * @param {number} index + * @returns {number | undefined} + */ + byteAt(index3) { + if (index3 < 0 || index3 >= this.byteSize) { + return void 0; + } + return bitArrayByteAt(this.rawBuffer, this.bitOffset, index3); + } + equals(other) { + if (this.bitSize !== other.bitSize) { + return false; + } + const wholeByteCount = Math.trunc(this.bitSize / 8); + if (this.bitOffset === 0 && other.bitOffset === 0) { + for (let i = 0; i < wholeByteCount; i++) { + if (this.rawBuffer[i] !== other.rawBuffer[i]) { + return false; + } + } + const trailingBitsCount = this.bitSize % 8; + if (trailingBitsCount) { + const unusedLowBitCount = 8 - trailingBitsCount; + if (this.rawBuffer[wholeByteCount] >> unusedLowBitCount !== other.rawBuffer[wholeByteCount] >> unusedLowBitCount) { + return false; + } + } + } else { + for (let i = 0; i < wholeByteCount; i++) { + const a = bitArrayByteAt(this.rawBuffer, this.bitOffset, i); + const b = bitArrayByteAt(other.rawBuffer, other.bitOffset, i); + if (a !== b) { + return false; + } + } + const trailingBitsCount = this.bitSize % 8; + if (trailingBitsCount) { + const a = bitArrayByteAt( + this.rawBuffer, + this.bitOffset, + wholeByteCount + ); + const b = bitArrayByteAt( + other.rawBuffer, + other.bitOffset, + wholeByteCount + ); + const unusedLowBitCount = 8 - trailingBitsCount; + if (a >> unusedLowBitCount !== b >> unusedLowBitCount) { + return false; + } + } + } + return true; + } + /** + * Returns this bit array's internal buffer. + * + * @deprecated + * + * @returns {Uint8Array} + */ + get buffer() { + if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) { + throw new globalThis.Error( + "BitArray.buffer does not support unaligned bit arrays" + ); + } + return this.rawBuffer; + } + /** + * Returns the length in bytes of this bit array's internal buffer. + * + * @deprecated + * + * @returns {number} + */ + get length() { + if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) { + throw new globalThis.Error( + "BitArray.length does not support unaligned bit arrays" + ); + } + return this.rawBuffer.length; + } + }; + function bitArrayByteAt(buffer, bitOffset, index3) { + if (bitOffset === 0) { + return buffer[index3] ?? 0; + } else { + const a = buffer[index3] << bitOffset & 255; + const b = buffer[index3 + 1] >> 8 - bitOffset; + return a | b; + } + } + var UtfCodepoint = class { + constructor(value) { + this.value = value; + } + }; + var Result = class _Result extends CustomType { + static isResult(data2) { + return data2 instanceof _Result; + } + }; + var Ok = class extends Result { + constructor(value) { + super(); + this[0] = value; + } + isOk() { + return true; + } + }; + var Result$Ok = (value) => new Ok(value); + var Error2 = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + isOk() { + return false; + } + }; + var Result$Error = (detail) => new Error2(detail); + function isEqual(x, y) { + let values2 = [x, y]; + while (values2.length) { + let a = values2.pop(); + let b = values2.pop(); + if (a === b) continue; + if (!isObject(a) || !isObject(b)) return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) continue; + else return false; + } catch { + } + } + let [keys, get2] = getters(a); + const ka = keys(a); + const kb = keys(b); + if (ka.length !== kb.length) return false; + for (let k of ka) { + values2.push(get2(a, k), get2(b, k)); + } + } + return true; + } + function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } + } + function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); + } + function unequalBuffers(a, b) { + return !(a instanceof BitArray) && a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); + } + function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; + } + function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; + } + function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); + } + function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); + } + function isObject(a) { + return typeof a === "object" && a !== null; + } + function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) return false; + return a.constructor === b.constructor; + } + + // build/dev/javascript/gleam_stdlib/dict.mjs + var referenceMap = /* @__PURE__ */ new WeakMap(); + var tempDataView = /* @__PURE__ */ new DataView( + /* @__PURE__ */ new ArrayBuffer(8) + ); + var referenceUID = 0; + function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== void 0) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; + } + function hashMerge(a, b) { + return a ^ b + 2654435769 + (a << 6) + (a >> 2) | 0; + } + function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; + } + function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; + } + function hashBigInt(n) { + return hashString(n.toString()); + } + function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch { + } + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0; i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys = Object.keys(o); + for (let i = 0; i < keys.length; i++) { + const k = keys[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; + } + function getHash(u) { + if (u === null) return 1108378658; + if (u === void 0) return 1108378659; + if (u === true) return 1108378657; + if (u === false) return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } + } + var Dict = class { + constructor(size2, root) { + this.size = size2; + this.root = root; + } + }; + var bits = 5; + var mask = (1 << bits) - 1; + var noElementMarker = /* @__PURE__ */ Symbol(); + var generationKey = /* @__PURE__ */ Symbol(); + var emptyNode = /* @__PURE__ */ newNode(0); + var emptyDict = /* @__PURE__ */ new Dict(0, emptyNode); + var errorNil = /* @__PURE__ */ Result$Error(void 0); + function makeNode(generation, datamap, nodemap, data2) { + return { + // A node is a high-arity (32 in practice) hybrid tree node. + // Hybrid means that it stores data directly as well as pointers to child nodes. + // + // Each node contains 2 bitmaps: + // - The datamap has a bit set if that slot in the node contains direct data + // - The nodemap has a bit set if that slot in the node contains another node. + // + // Both are exclusive to on another, so datamap & nodemap == 0. + // + // Every key/hash value directly correlates to a specific bit by using a trie + // suffix (least significant bits first) encoding. + // For example, if the last 5 bits of the hash are 1101, the bit to check for + // that value is the 13th bit. + datamap, + nodemap, + // The slots itself are stored in a single contiguous array that contains + // both direct k/v-pairs and child nodes. + // + // The direct children come first, followed by the child nodes in _reverse order_: + // + // 7654321 + // datamap: 1000100 + // nodemap: 10011 + // data: [key3, value3, key7, value7, child5, child2, child1] + // -------------------------> <--------------------- + // datamap nodemap + // + // Every `1` bit in the datamap corresponds to a pair of [key, value] entries, + // and every `1` bit in the nodemap corresponds to a child node entry. + // + // Children are stored in reverse order to avoid having to store or calculate an + // "offset" value to skip over the direct children. + data: data2, + // The generation is used to track which nodes need to be copied during transient updates. + // Using a symbol here makes `isEqual` ignore this field. + [generationKey]: generation + }; + } + function newNode(generation) { + return makeNode(generation, 0, 0, []); + } + function copyNode(node, generation) { + if (node[generationKey] === generation) { + return node; + } + const newData = node.data.slice(0); + return makeNode(generation, node.datamap, node.nodemap, newData); + } + function copyAndSet(node, generation, idx, val) { + if (node.data[idx] === val) { + return node; + } + node = copyNode(node, generation); + node.data[idx] = val; + return node; + } + function copyAndInsertPair(node, generation, bit, idx, key, val) { + const data2 = node.data; + const length2 = data2.length; + const newData = new Array(length2 + 2); + let readIndex = 0; + let writeIndex = 0; + while (readIndex < idx) newData[writeIndex++] = data2[readIndex++]; + newData[writeIndex++] = key; + newData[writeIndex++] = val; + while (readIndex < length2) newData[writeIndex++] = data2[readIndex++]; + return makeNode(generation, node.datamap | bit, node.nodemap, newData); + } + function make() { + return emptyDict; + } + function get(dict2, key) { + const result = lookup(dict2.root, key, getHash(key)); + return result !== noElementMarker ? Result$Ok(result) : errorNil; + } + function lookup(node, key, hash) { + for (let shift = 0; shift < 32; shift += bits) { + const data2 = node.data; + const bit = hashbit(hash, shift); + if (node.nodemap & bit) { + node = data2[data2.length - 1 - index(node.nodemap, bit)]; + } else if (node.datamap & bit) { + const dataidx = Math.imul(index(node.datamap, bit), 2); + return isEqual(key, data2[dataidx]) ? data2[dataidx + 1] : noElementMarker; + } else { + return noElementMarker; + } + } + const overflow = node.data; + for (let i = 0; i < overflow.length; i += 2) { + if (isEqual(key, overflow[i])) { + return overflow[i + 1]; + } + } + return noElementMarker; + } + function toTransient(dict2) { + return { + generation: nextGeneration(dict2), + root: dict2.root, + size: dict2.size, + dict: dict2 + }; + } + function fromTransient(transient) { + if (transient.root === transient.dict.root) { + return transient.dict; + } + return new Dict(transient.size, transient.root); + } + function nextGeneration(dict2) { + const root = dict2.root; + if (root[generationKey] < Number.MAX_SAFE_INTEGER) { + return root[generationKey] + 1; + } + const queue = [root]; + while (queue.length) { + const node = queue.pop(); + node[generationKey] = 0; + const nodeStart = data.length - popcount(node.nodemap); + for (let i = nodeStart; i < node.data.length; ++i) { + queue.push(node.data[i]); + } + } + return 1; + } + function destructiveTransientInsert(key, value, transient) { + const hash = getHash(key); + transient.root = insertIntoNode(transient, transient.root, key, value, hash, 0); + return transient; + } + function insertIntoNode(transient, node, key, value, hash, shift) { + const data2 = node.data; + const generation = transient.generation; + if (shift > 32) { + for (let i = 0; i < data2.length; i += 2) { + if (isEqual(key, data2[i])) { + return copyAndSet(node, generation, i + 1, value); + } + } + transient.size += 1; + return copyAndInsertPair(node, generation, 0, data2.length, key, value); + } + const bit = hashbit(hash, shift); + if (node.nodemap & bit) { + const nodeidx2 = data2.length - 1 - index(node.nodemap, bit); + let child2 = data2[nodeidx2]; + child2 = insertIntoNode(transient, child2, key, value, hash, shift + bits); + return copyAndSet(node, generation, nodeidx2, child2); + } + const dataidx = Math.imul(index(node.datamap, bit), 2); + if ((node.datamap & bit) === 0) { + transient.size += 1; + return copyAndInsertPair(node, generation, bit, dataidx, key, value); + } + if (isEqual(key, data2[dataidx])) { + return copyAndSet(node, generation, dataidx + 1, value); + } + const childShift = shift + bits; + let child = emptyNode; + child = insertIntoNode(transient, child, key, value, hash, childShift); + const key2 = data2[dataidx]; + const value2 = data2[dataidx + 1]; + const hash2 = getHash(key2); + child = insertIntoNode(transient, child, key2, value2, hash2, childShift); + transient.size -= 1; + const length2 = data2.length; + const nodeidx = length2 - 1 - index(node.nodemap, bit); + const newData = new Array(length2 - 1); + let readIndex = 0; + let writeIndex = 0; + while (readIndex < dataidx) newData[writeIndex++] = data2[readIndex++]; + readIndex += 2; + while (readIndex <= nodeidx) newData[writeIndex++] = data2[readIndex++]; + newData[writeIndex++] = child; + while (readIndex < length2) newData[writeIndex++] = data2[readIndex++]; + return makeNode(generation, node.datamap ^ bit, node.nodemap | bit, newData); + } + function fold(dict2, state, fun) { + const queue = [dict2.root]; + while (queue.length) { + const node = queue.pop(); + const data2 = node.data; + const edgesStart = data2.length - popcount(node.nodemap); + for (let i = 0; i < edgesStart; i += 2) { + state = fun(state, data2[i], data2[i + 1]); + } + for (let i = edgesStart; i < data2.length; ++i) { + queue.push(data2[i]); + } + } + return state; + } + function popcount(n) { + n -= n >>> 1 & 1431655765; + n = (n & 858993459) + (n >>> 2 & 858993459); + return Math.imul(n + (n >>> 4) & 252645135, 16843009) >>> 24; + } + function index(bitmap, bit) { + return popcount(bitmap & bit - 1); + } + function hashbit(hash, shift) { + return 1 << (hash >>> shift & mask); + } + + // build/dev/javascript/gleam_stdlib/gleam/dict.mjs + function from_list_loop(loop$transient, loop$list) { + while (true) { + let transient = loop$transient; + let list2 = loop$list; + if (list2 instanceof Empty) { + return fromTransient(transient); + } else { + let rest = list2.tail; + let key = list2.head[0]; + let value = list2.head[1]; + loop$transient = destructiveTransientInsert(key, value, transient); + loop$list = rest; + } + } + } + function from_list(list2) { + return from_list_loop(toTransient(make()), list2); + } + + // build/dev/javascript/gleam_stdlib/gleam/list.mjs + function reverse_and_prepend(loop$prefix, loop$suffix) { + while (true) { + let prefix = loop$prefix; + let suffix = loop$suffix; + if (prefix instanceof Empty) { + return suffix; + } else { + let first$1 = prefix.head; + let rest$1 = prefix.tail; + loop$prefix = rest$1; + loop$suffix = prepend(first$1, suffix); + } + } + } + function reverse(list2) { + return reverse_and_prepend(list2, toList([])); + } + function filter_loop(loop$list, loop$fun, loop$acc) { + while (true) { + let list2 = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list2 instanceof Empty) { + return reverse(acc); + } else { + let first$1 = list2.head; + let rest$1 = list2.tail; + let _block; + let $ = fun(first$1); + if ($) { + _block = prepend(first$1, acc); + } else { + _block = acc; + } + let new_acc = _block; + loop$list = rest$1; + loop$fun = fun; + loop$acc = new_acc; + } + } + } + function filter(list2, predicate) { + return filter_loop(list2, predicate, toList([])); + } + function map_loop(loop$list, loop$fun, loop$acc) { + while (true) { + let list2 = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list2 instanceof Empty) { + return reverse(acc); + } else { + let first$1 = list2.head; + let rest$1 = list2.tail; + loop$list = rest$1; + loop$fun = fun; + loop$acc = prepend(fun(first$1), acc); + } + } + } + function map2(list2, fun) { + return map_loop(list2, fun, toList([])); + } + function flatten_loop(loop$lists, loop$acc) { + while (true) { + let lists = loop$lists; + let acc = loop$acc; + if (lists instanceof Empty) { + return reverse(acc); + } else { + let list2 = lists.head; + let further_lists = lists.tail; + loop$lists = further_lists; + loop$acc = reverse_and_prepend(list2, acc); + } + } + } + function flatten(lists) { + return flatten_loop(lists, toList([])); + } + function flat_map(list2, fun) { + return flatten(map2(list2, fun)); + } + + // build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs + var Nil = void 0; + function identity(x) { + return x; + } + function parse_int(value) { + if (/^[-+]?(\d+)$/.test(value)) { + return Result$Ok(parseInt(value)); + } else { + return Result$Error(Nil); + } + } + function string_replace(string3, target, substitute) { + return string3.replaceAll(target, substitute); + } + function graphemes(string3) { + const iterator = graphemes_iterator(string3); + if (iterator) { + return arrayToList(Array.from(iterator).map((item) => item.segment)); + } else { + return arrayToList(string3.match(/./gsu)); + } + } + var segmenter = void 0; + function graphemes_iterator(string3) { + if (globalThis.Intl && Intl.Segmenter) { + segmenter ||= new Intl.Segmenter(); + return segmenter.segment(string3)[Symbol.iterator](); + } + } + function pop_grapheme(string3) { + let first; + const iterator = graphemes_iterator(string3); + if (iterator) { + first = iterator.next().value?.segment; + } else { + first = string3.match(/./su)?.[0]; + } + if (first) { + return Result$Ok([first, string3.slice(first.length)]); + } else { + return Result$Error(Nil); + } + } + function split(xs, pattern) { + return arrayToList(xs.split(pattern)); + } + function starts_with(haystack, needle) { + return haystack.startsWith(needle); + } + function split_once(haystack, needle) { + const index3 = haystack.indexOf(needle); + if (index3 >= 0) { + const before = haystack.slice(0, index3); + const after = haystack.slice(index3 + needle.length); + return Result$Ok([before, after]); + } else { + return Result$Error(Nil); + } + } + var unicode_whitespaces = [ + " ", + // Space + " ", + // Horizontal tab + "\n", + // Line feed + "\v", + // Vertical tab + "\f", + // Form feed + "\r", + // Carriage return + "\x85", + // Next line + "\u2028", + // Line separator + "\u2029" + // Paragraph separator + ].join(""); + var trim_start_regex = /* @__PURE__ */ new RegExp( + `^[${unicode_whitespaces}]*` + ); + var trim_end_regex = /* @__PURE__ */ new RegExp(`[${unicode_whitespaces}]*$`); + function trim_start(string3) { + return string3.replace(trim_start_regex, ""); + } + function trim_end(string3) { + return string3.replace(trim_end_regex, ""); + } + function print(string3) { + if (typeof process === "object" && process.stdout?.write) { + process.stdout.write(string3); + } else if (typeof Deno === "object") { + Deno.stdout.writeSync(new TextEncoder().encode(string3)); + } else { + console.log(string3); + } + } + var MIN_I32 = -(2 ** 31); + var MAX_I32 = 2 ** 31 - 1; + var U32 = 2 ** 32; + var MAX_SAFE = Number.MAX_SAFE_INTEGER; + var MIN_SAFE = Number.MIN_SAFE_INTEGER; + function arrayToList(array3) { + let list2 = List$Empty(); + let i = array3.length; + while (i--) { + list2 = List$NonEmpty(array3[i], list2); + } + return list2; + } + + // build/dev/javascript/gleam_stdlib/gleam/string.mjs + function replace(string3, pattern, substitute) { + let _pipe = string3; + let _pipe$1 = identity(_pipe); + let _pipe$2 = string_replace(_pipe$1, pattern, substitute); + return identity(_pipe$2); + } + function split2(x, substring) { + if (substring === "") { + return graphemes(x); + } else { + let _pipe = x; + let _pipe$1 = identity(_pipe); + let _pipe$2 = split(_pipe$1, substring); + return map2(_pipe$2, identity); + } + } + function trim(string3) { + let _pipe = string3; + let _pipe$1 = trim_start(_pipe); + return trim_end(_pipe$1); + } + + // build/dev/javascript/gleam_stdlib/gleam/result.mjs + function unwrap(result, default$) { + if (result instanceof Ok) { + let v = result[0]; + return v; + } else { + return default$; + } + } + + // build/dev/javascript/gleam_json/gleam_json_ffi.mjs + function json_to_string(json) { + return JSON.stringify(json); + } + function object(entries) { + return Object.fromEntries(entries); + } + function identity2(x) { + return x; + } + function array(list2) { + const array3 = []; + while (List$isNonEmpty(list2)) { + array3.push(List$NonEmpty$first(list2)); + list2 = List$NonEmpty$rest(list2); + } + return array3; + } + + // build/dev/javascript/gleam_json/gleam/json.mjs + function to_string2(json) { + return json_to_string(json); + } + function string2(input) { + return identity2(input); + } + function int2(input) { + return identity2(input); + } + function object2(entries) { + return object(entries); + } + function preprocessed_array(from2) { + return array(from2); + } + function array2(entries, inner_type) { + let _pipe = entries; + let _pipe$1 = map2(_pipe, inner_type); + return preprocessed_array(_pipe$1); + } + + // build/dev/javascript/markdown2/mode.mjs + var Hirachy = class extends CustomType { + }; + var Truth = class extends CustomType { + }; + var Marking = class extends CustomType { + }; + var Quote = class extends CustomType { + }; + + // build/dev/javascript/markdown2/definition.mjs + var Line = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Text = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Push = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Pop = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Hirachy2 = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Truth2 = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Marking2 = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + var Quote2 = class extends CustomType { + constructor($0) { + super(); + this[0] = $0; + } + }; + + // build/dev/javascript/markdown2/parser.mjs + function whatsthat(mod) { + let modes = from_list( + toList([ + [ + "!", + [ + new Marking(), + (var0) => { + return new Marking2(var0); + } + ] + ], + [ + "@", + [new Truth(), (var0) => { + return new Truth2(var0); + }] + ], + [ + ">", + [new Quote(), (var0) => { + return new Quote2(var0); + }] + ], + [ + "#", + [ + new Hirachy(), + (var0) => { + return new Hirachy2(var0); + } + ] + ] + ]) + ); + let $ = pop_grapheme(mod); + if ($ instanceof Ok) { + let prefix = $[0][0]; + let rest = $[0][1]; + let $1 = get(modes, prefix); + if ($1 instanceof Ok) { + let m = $1[0][0]; + let make_definition = $1[0][1]; + if (rest === "-") { + return new Pop(m); + } else { + let _block; + let _pipe = parse_int(rest); + _block = unwrap(_pipe, 1); + let value = _block; + return new Push(make_definition(value)); + } + } else { + return new Text(mod); + } + } else { + return new Text(mod); + } + } + function parse(modificators) { + let _pipe = modificators; + let _pipe$1 = replace(_pipe, "#", " |#"); + let _pipe$2 = replace(_pipe$1, "@", " |@"); + let _pipe$3 = replace(_pipe$2, "!", " |!"); + let _pipe$4 = replace(_pipe$3, ">", " |>"); + let _pipe$5 = split2(_pipe$4, " |"); + let _pipe$6 = flat_map( + _pipe$5, + (block) => { + let $ = starts_with(block, "#") || starts_with( + block, + "@" + ) || starts_with(block, "!") || starts_with(block, ">"); + if ($) { + let $1 = split_once(block, " "); + if ($1 instanceof Ok) { + let tag = $1[0][0]; + let rest = $1[0][1]; + return toList([tag, rest]); + } else { + return toList([block]); + } + } else { + return toList([block]); + } + } + ); + let _pipe$7 = map2(_pipe$6, trim); + return filter(_pipe$7, (x) => { + return x !== ""; + }); + } + function handler(line) { + let result = parse(line); + let result$1 = echo( + map2(result, whatsthat), + void 0, + "src/parser.gleam", + 10 + ); + return new Line(result$1); + } + function echo(value, message, file, line) { + const grey = "\x1B[90m"; + const reset_color = "\x1B[39m"; + const file_line = `${file}:${line}`; + const inspector = new Echo$Inspector(); + const string_value = inspector.inspect(value); + const string_message = message === void 0 ? "" : " " + message; + if (globalThis.process?.stderr?.write) { + const string3 = `${grey}${file_line}${reset_color}${string_message} +${string_value} +`; + globalThis.process.stderr.write(string3); + } else if (globalThis.Deno) { + const string3 = `${grey}${file_line}${reset_color}${string_message} +${string_value} +`; + globalThis.Deno.stderr.writeSync(new TextEncoder().encode(string3)); + } else { + const string3 = `${file_line}${string_message} +${string_value}`; + globalThis.console.log(string3); + } + return value; + } + var Echo$Inspector = class { + #references = new globalThis.Set(); + #isDict(value) { + try { + const empty_dict = make(); + const dict_class = empty_dict.constructor; + return value instanceof dict_class; + } catch { + return false; + } + } + #float(float2) { + const string3 = float2.toString().replace("+", ""); + if (string3.indexOf(".") >= 0) { + return string3; + } else { + const index3 = string3.indexOf("e"); + if (index3 >= 0) { + return string3.slice(0, index3) + ".0" + string3.slice(index3); + } else { + return string3 + ".0"; + } + } + } + inspect(v) { + const t = typeof v; + if (v === true) return "True"; + if (v === false) return "False"; + if (v === null) return "//js(null)"; + if (v === void 0) return "Nil"; + if (t === "string") return this.#string(v); + if (t === "bigint" || globalThis.Number.isInteger(v)) return v.toString(); + if (t === "number") return this.#float(v); + if (v instanceof UtfCodepoint) return this.#utfCodepoint(v); + if (v instanceof BitArray) return this.#bit_array(v); + if (v instanceof globalThis.RegExp) return `//js(${v})`; + if (v instanceof globalThis.Date) return `//js(Date("${v.toISOString()}"))`; + if (v instanceof globalThis.Error) return `//js(${v.toString()})`; + if (v instanceof globalThis.Function) { + const args = []; + for (const i of globalThis.Array(v.length).keys()) + args.push(globalThis.String.fromCharCode(i + 97)); + return `//fn(${args.join(", ")}) { ... }`; + } + if (this.#references.size === this.#references.add(v).size) { + return "//js(circular reference)"; + } + let printed; + if (globalThis.Array.isArray(v)) { + printed = `#(${v.map((v2) => this.inspect(v2)).join(", ")})`; + } else if (v instanceof List) { + printed = this.#list(v); + } else if (v instanceof CustomType) { + printed = this.#customType(v); + } else if (this.#isDict(v)) { + printed = this.#dict(v); + } else if (v instanceof Set) { + return `//js(Set(${[...v].map((v2) => this.inspect(v2)).join(", ")}))`; + } else { + printed = this.#object(v); + } + this.#references.delete(v); + return printed; + } + #object(v) { + const name = globalThis.Object.getPrototypeOf(v)?.constructor?.name || "Object"; + const props = []; + for (const k of globalThis.Object.keys(v)) { + props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); + } + const body = props.length ? " " + props.join(", ") + " " : ""; + const head = name === "Object" ? "" : name + " "; + return `//js(${head}{${body}})`; + } + #dict(map3) { + let body = "dict.from_list(["; + let first = true; + let key_value_pairs = fold(map3, [], (pairs, key, value) => { + pairs.push([key, value]); + return pairs; + }); + key_value_pairs.sort(); + key_value_pairs.forEach(([key, value]) => { + if (!first) body = body + ", "; + body = body + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")"; + first = false; + }); + return body + "])"; + } + #customType(record) { + const props = globalThis.Object.keys(record).map((label) => { + const value = this.inspect(record[label]); + return isNaN(parseInt(label)) ? `${label}: ${value}` : value; + }).join(", "); + return props ? `${record.constructor.name}(${props})` : record.constructor.name; + } + #list(list2) { + if (list2 instanceof Empty) { + return "[]"; + } + let char_out = 'charlist.from_string("'; + let list_out = "["; + let current = list2; + while (current instanceof NonEmpty) { + let element = current.head; + current = current.tail; + if (list_out !== "[") { + list_out += ", "; + } + list_out += this.inspect(element); + if (char_out) { + if (globalThis.Number.isInteger(element) && element >= 32 && element <= 126) { + char_out += globalThis.String.fromCharCode(element); + } else { + char_out = null; + } + } + } + if (char_out) { + return char_out + '")'; + } else { + return list_out + "]"; + } + } + #string(str) { + let new_str = '"'; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + switch (char) { + case "\n": + new_str += "\\n"; + break; + case "\r": + new_str += "\\r"; + break; + case " ": + new_str += "\\t"; + break; + case "\f": + new_str += "\\f"; + break; + case "\\": + new_str += "\\\\"; + break; + case '"': + new_str += '\\"'; + break; + default: + if (char < " " || char > "~" && char < "\xA0") { + new_str += "\\u{" + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + "}"; + } else { + new_str += char; + } + } + } + new_str += '"'; + return new_str; + } + #utfCodepoint(codepoint2) { + return `//utfcodepoint(${globalThis.String.fromCodePoint(codepoint2.value)})`; + } + #bit_array(bits2) { + if (bits2.bitSize === 0) { + return "<<>>"; + } + let acc = "<<"; + for (let i = 0; i < bits2.byteSize - 1; i++) { + acc += bits2.byteAt(i).toString(); + acc += ", "; + } + if (bits2.byteSize * 8 === bits2.bitSize) { + acc += bits2.byteAt(bits2.byteSize - 1).toString(); + } else { + const trailingBitsCount = bits2.bitSize % 8; + acc += bits2.byteAt(bits2.byteSize - 1) >> 8 - trailingBitsCount; + acc += `:size(${trailingBitsCount})`; + } + acc += ">>"; + return acc; + } + }; + + // build/dev/javascript/markdown2/markdown2.mjs + function inline_to_json(inline) { + if (inline instanceof Text) { + let text = inline[0]; + return object2( + toList([["type", string2("text")], ["value", string2(text)]]) + ); + } else if (inline instanceof Push) { + let feeling = inline[0]; + if (feeling instanceof Hirachy2) { + let level = feeling[0]; + return object2( + toList([["type", string2("hirachy")], ["value", int2(level)]]) + ); + } else if (feeling instanceof Truth2) { + let level = feeling[0]; + return object2( + toList([["type", string2("truth")], ["value", int2(level)]]) + ); + } else if (feeling instanceof Marking2) { + let level = feeling[0]; + return object2( + toList([["type", string2("marking")], ["value", int2(level)]]) + ); + } else { + let level = feeling[0]; + return object2( + toList([["type", string2("quote")], ["value", int2(level)]]) + ); + } + } else { + let text = inline[0]; + return object2( + toList([ + ["type", string2("pop")], + [ + "value", + (() => { + if (text instanceof Hirachy) { + return string2("Hirachy"); + } else if (text instanceof Truth) { + return string2("Truth"); + } else if (text instanceof Marking) { + return string2("Marking"); + } else { + return string2("Quote"); + } + })() + ] + ]) + ); + } + } + function line_to_json(line) { + let inlines = line[0]; + let _pipe = array2(inlines, inline_to_json); + return to_string2(_pipe); + } + function main() { + let input = "ljiosfgdjiosdfgj\n @2! A slightly important statement !1 I believe is wrong, !- quoted inside another quote.\n !3 A slightly important statement I believe is wrong, quoted inside another quote.\n #3!2@2 A slightly important statement I believe is wrong, quoted inside another quote.\n\n !2@3 important trusted but @- important !5 more important !- 2 important and !- normal"; + print(line_to_json(handler(input))); + return void 0; + } + function testing(input) { + return line_to_json(handler(input)); + } + return __toCommonJS(markdown2_exports); +})(); diff --git a/render.js b/render.js new file mode 100644 index 0000000..d8bd1a2 --- /dev/null +++ b/render.js @@ -0,0 +1,13 @@ +export function render(buffer, cursor) { + const html = buffer.map((line, i) => { + if (i !== cursor.line) return `${escapeHtml(line)}`; + const before = escapeHtml(line.slice(0, cursor.col)); + const after = escapeHtml(line.slice(cursor.col)); + return `${before}${after}`; + }); + document.getElementById("text").innerHTML = html.join("
"); +} + +function escapeHtml(s) { + return s.replace(/&/g, "&").replace(//g, ">"); +}