diff --git a/bg.yarn b/bg.yarn deleted file mode 100644 index 79f55ca..0000000 --- a/bg.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"bg","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"bg.js":"%B/bg.js"}},"content":"{\"bg.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No program specified\\\", 0x1000)\\n quit()\\n}\\n\\nconst programName = args[0]\\nargs.splice(0, 1)\\n\\ntry {\\n exec.runProgram(programName, args)\\n} catch (e) {\\n if (e[0]) {\\n io.log(e)\\n }\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/cat.yarn b/cat.yarn deleted file mode 100644 index 3142329..0000000 --- a/cat.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"cat","author":"Luna Magdalena :3","version":[1,1],"dependencies":[],"paths":{"cat.js":"%B/cat.js"}},"content":"{\"cat.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"program.autoOutput = false\\n\\nfor (let a of args) {\\n let file\\n try {\\n file = io.open(a)\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000)\\n }\\n if (file) {\\n const lines = file.lines()\\n for (let line of lines) {\\n line = line.replace(/%/g, \\\"%%\\\")\\n io.output(\\\"\\\\n\\\" + line)\\n display.print(line, itty.baseStyle, false)\\n }\\n }\\n}\\n \\nquit()\"}}"} \ No newline at end of file diff --git a/clear.yarn b/clear.yarn deleted file mode 100644 index cf3e1df..0000000 --- a/clear.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"clear","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"clear.js":"%B/clear.js"}},"content":"{\"clear.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"display.clear(); quit()\"}}"} \ No newline at end of file diff --git a/cp.yarn b/cp.yarn deleted file mode 100644 index 5dda7e0..0000000 --- a/cp.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"cp","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"cp.js":"%B/cp.js"}},"content":"{\"cp.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[0] && !args[1]) {\\n itty.display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n itty.fs.copyNode(args[0], args[1])\\n} catch (e) {\\n itty.display.print(e[1] || \\\"Error copying node\\\", 0x9000)\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/echo.yarn b/echo.yarn deleted file mode 100644 index e17d900..0000000 --- a/echo.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"echo","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"echo.js":"%B/echo.js"}},"content":"{\"echo.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"let echo = pipe\\nif (!pipe)\\n echo = args.join(\\\" \\\")\\n\\ndisplay.print(echo, itty.baseStyle, false)\\nquit()\"}}"} \ No newline at end of file diff --git a/env.yarn b/env.yarn deleted file mode 100644 index 78d30da..0000000 --- a/env.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"env","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"env.js":"%B/env.js"}},"content":"{\"env.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"const subcommand = args[0]\\nconst env = args[1]\\n\\nconst envtype = typeof itty.env[env]\\nlet value\\n\\nlet listing = false\\nlet listIndex = 0\\n\\nswitch(subcommand) {\\n case \\\"get\\\":\\n if (!env) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n display.print(JSON.stringify(itty.env[env]), getEnvStyle(envtype))\\n quit()\\n break\\n case \\\"set\\\":\\n if (!env) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n await parseValue()\\n if (itty.env[env] && typeof itty.env[env] !== typeof value) {\\n let r = await io.read(\\\"Mismatch between env type and provided value type. Continue? [y/N]: \\\")\\n if (r.length === 0 || r[0].toLowerCase() !== \\\"y\\\") {\\n display.print(\\\"Aborting...\\\")\\n quit()\\n }\\n }\\n itty.env[env] = value\\n quit()\\n break\\n case \\\"list\\\":\\n if (Object.keys(itty.env).length < itty.height - 4) {\\n for (let e in itty.env) {\\n display.buffer(e, getEnvStyle(typeof itty.env[e]))\\n display.buffer(\\\" = \\\", 0xe000)\\n display.print(JSON.stringify(itty.env[e]).replaceAll(\\\"%\\\", \\\"%%\\\"))\\n }\\n display.render()\\n quit()\\n } else {\\n program.enterFullscreen()\\n listing = true\\n onInput(\\\"\\\", {})\\n }\\n}\\n\\nfunction onInput(k) {\\n if (!listing)\\n return\\n\\n switch (k) {\\n case \\\"%^\\\":\\n listIndex = Math.max(listIndex - 1, 0)\\n break\\n case \\\"%v\\\":\\n listIndex = Math.min(listIndex + 1, Object.keys(itty.env).length - 1)\\n break\\n case \\\"%e\\\":\\n display.clear()\\n quit()\\n }\\n\\n display.clear()\\n for (let i = listIndex; i < itty.height - 1 + listIndex; i++) {\\n const e = Object.keys(itty.env)[i]\\n if (!e)\\n break\\n\\n display.buffer(e, getEnvStyle(typeof itty.env[e]))\\n display.buffer(\\\" = \\\", 0xe000)\\n display.buffer(JSON.stringify(itty.env[e]) + \\\"%n\\\")\\n }\\n itty.cursorY = itty.height - 1\\n display.write(\\\"Arrow Up/Down to scroll, Escape to quit\\\")\\n}\\n\\nasync function parseValue() {\\n let v = await io.read([[\\\"Value: \\\", 0xe000]])\\n v = v.replaceAll(\\\"%%\\\", \\\"%\\\")\\n\\n try {\\n v = JSON.parse(v)\\n } catch (e) {\\n try {\\n v = JSON.parse('\\\"' + v + '\\\"')\\n } catch (e) {\\n throw [1, \\\"Cannot parse value\\\"]\\n }\\n }\\n value = v\\n}\\n \\nfunction getEnvStyle(type) {\\n let style = 0xf000\\n switch(type) {\\n case \\\"object\\\":\\n style = 0x4000\\n break\\n case \\\"string\\\":\\n style = 0x6000\\n break\\n case \\\"number\\\":\\n style = 0x5000\\n break\\n case \\\"boolean\\\":\\n style = 0xa000\\n break\\n }\\n return style\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/info.yarn b/info.yarn deleted file mode 100644 index ae2c2ad..0000000 --- a/info.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"info","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"info.js":"%B/info.js"}},"content":"{\"info.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"display.buffer(`Itty version: v${itty.version[0]}.${itty.version[1]}${itty.version[2] ? \\\".\\\" + itty.version[2] : \\\"\\\"} ${itty.version[3] || \\\"\\\"}%nRoot FS: ${itty.disk.version}`, 0x4000)\\ndisplay.buffer(\\\"%n%nDisplay dimensions: \\\", 0x7000)\\ndisplay.buffer(itty.width + \\\"x\\\" + itty.height + \\\"%n%n\\\", 0x6000)\\nfor (let i=0; i < 8; i++) {\\n display.buffer(\\\" \\\", 0x0100 * i)\\n}\\nitty.cursorY++\\nitty.cursorX = 0\\nfor (let i=8; i < 16; i++) {\\n display.buffer(\\\" \\\", 0x0100 * i)\\n}\\n\\ndisplay.buffer(\\\"%n%nITTY: Incredibly Tiny Terminal, Yay!\\\", 0x4041)\\ndisplay.buffer(\\\" by \\\", 0x7041)\\ndisplay.buffer(\\\"Magdalunaa\\\", 0x6051)\\nstyle.setAttribute(1, {_link: \\\"https://codeberg.org/Magdalunaa/itty\\\", style: \\\"cursor: pointer; text-decoration-color: var(--itty-c-4)\\\"})\\ndisplay.render()\\nquit()\"}}"} \ No newline at end of file diff --git a/kill.yarn b/kill.yarn deleted file mode 100644 index 4f69db2..0000000 --- a/kill.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"kill","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"kill.js":"%B/kill.js"}},"content":"{\"kill.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"const id = Number(args[0])\\n\\nif (id)\\n try {\\n exec.quit(id)\\n } catch {}\\nquit()\"}}"} \ No newline at end of file diff --git a/lazybox.yarn b/lazybox.yarn new file mode 100644 index 0000000..5354859 --- /dev/null +++ b/lazybox.yarn @@ -0,0 +1 @@ +{"protected":false,"mode":"f","metadata":{"name":"lazybox","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"lazybox.js":"%B/lazybox.js","links/bg":"%B/bg","links/cat":"%B/cat","links/clear":"%B/clear","links/cp":"%B/cp","links/echo":"%B/echo","links/env":"%B/env","links/info":"%B/info","links/kill":"%B/kill","links/ln":"%B/ln","links/loader":"%B/loader","links/ls":"%B/ls","links/meta":"%B/meta","links/mkdir":"%B/mkdir","links/mv":"%B/mv","links/persist":"%B/persist","links/plist":"%B/plist","links/programs":"%B/programs","links/rm":"%B/rm","links/scroll":"%B/scroll","links/shutdown":"%B/shutdown","links/slog":"%B/slog","links/touch":"%B/touch","links/woman":"%B/woman","lazybox/bg":"%D/bg","lazybox/cat":"%D/cat","lazybox/clear":"%D/clear","lazybox/cp":"%D/cp","lazybox/echo":"%D/echo","lazybox/env":"%D/env","lazybox/info":"%D/info","lazybox/kill":"%D/kill","lazybox/ln":"%D/ln","lazybox/loader":"%D/loader","lazybox/ls":"%D/ls","lazybox/meta":"%D/meta","lazybox/mkdir":"%D/mkdir","lazybox/mv":"%D/mv","lazybox/persist":"%D/persist","lazybox/plist":"%D/plist","lazybox/programs":"%D/programs","lazybox/rm":"%D/rm","lazybox/scroll":"%D/scroll","lazybox/shutdown":"%D/shutdown","lazybox/slog":"%D/slog","lazybox/touch":"%D/touch","lazybox/woman":"%D/woman","lazybox/woman.template":"%D/woman.template"}},"content":"{\"links\":{\"protected\":false,\"metadata\":{},\"mode\":\"d\",\"content\":{\"bg\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"cat\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"clear\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"cp\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"echo\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"env\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"info\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"kill\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"ln\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"loader\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"ls\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"meta\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"mkdir\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"mv\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"persist\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"plist\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"programs\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"rm\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"scroll\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"shutdown\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"slog\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"touch\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"woman\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"},\"yarn\":{\"protected\":true,\"metadata\":{},\"mode\":\"l\",\"content\":\"./lazybox.js\"}}},\"lazybox\":{\"protected\":false,\"metadata\":{},\"mode\":\"d\",\"content\":{\"bg\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]bg\\u0011[s7000]\\n\\nbg is a utility for starting programs in the background\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tbg \\u0011[s6040]program\\u0011[s7000] [\\u0011[sE000]arguments\\u0011[s7000]]\"},\"cat\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]cat\\u0011[s7000]\\n\\ncat concatenates files, outputting their content to the next program or displaying it on screen\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tcat \\u0011[s6040]file\\u0011[s7000] [\\u0011[sE000]additional-files\\u0011[s7000]]\"},\"clear\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]clear\\u0011[s7000]\\n\\nclears the screen\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tclear\"},\"cp\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]cp\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mv\\trm\\tln\\tmkdir\\ttouch\\u0011[s7000]\\n\\nattempts to copy the given node to the given destination\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tcp \\u0011[s6040]node\\u0011[s7000] \\u0011[s6040]destination\\u0011[s7000]\"},\"echo\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]echo\\u0011[s7000]\\n\\ndisplays or outputs the text content passed to it with a pipe or as command line arguments\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\techo [\\u0011[sE000]text\\u0011[s7000]]\"},\"env\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]env\\u0011[s7000]\\n\\nutility for manipulating environment variables\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tenv \\u0011[s6040]subcommand\\u0011[s7000] [\\u0011[sE000]arguments\\u0011[s7000]]\\n\\n\\u0011[s4020]Subcommands:\\u0011[s7000]\\n\\t\\u0011[s6010]get \\u0011[s2040]variable\\u0011[s7000]\\n\\t\\tprints the value of the given variable\\n\\t\\u0011[s6010]set \\u0011[s2040]variable\\u0011[s7000]\\n\\t\\tinteractively sets the value of the given variable. values are JSON parsed\\n\\t\\u0011[s6010]list\\u0011[s7000]\\n\\t\\tdisplays a list of all currently set environment variables and their values\\n\\t\\u0011[s6010]save \\u0011[s2040]file\\u0011[s7000]\\n\\t\\tattempts to save all current environment variables and their values to the given file\\n\\t\\u0011[s6010]load \\u0011[s2040]file\\u0011[s7000]\\n\\t\\tattempts to load environment variable values from the given file. file content must be a JSON object with each key being the name of a variable, as created by \\u0011[sE800] env save \\u0011[s7000]\"},\"info\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]info\\u0011[s7000]\\n\\ndisplays basic system info\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tinfo\"},\"kill\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]kill\\u0011[s7000]\\n\\n\\t\\u0011[s4000]plist\\u0011[s7000]\\n\\nkill quits the program with the provided id. running programs and their ids can be found with the \\u0011[sA000]plist\\u0011[s7000] utility\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tkill \\u0011[s6040]id\\u0011[s7000]\"},\"ln\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]ln\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mv\\tcp\\trm\\tmkdir\\ttouch\\u0011[s7000]\\n\\nattempts to create a link from \\u0011[sA000]link-path\\u0011[s7000] to \\u0011[sA000]target\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tln \\u0011[s6040]target\\u0011[s7000] \\u0011[s6040]link-path\\u0011[s7000]\"},\"loader\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]*loader\\u0011[s7000]\\n\\n*loader is a file transfer utility. it can download and upload nodes between itty and the underlying device. it can also download nodes over https, provided CORS allows it\\n\\nnodes must be valid itty nodes. these can be created and extracted from outside itty by using the \\u0011[sA000]thread\\u0011[s7000] utility found in the itty repo\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tloader \\u0011[s6040]subcommand\\u0011[s7000] \\u0011[s6040]arguments\\u0011[s7000]\\n\\n\\u0011[s4020]Subcommands:\\u0011[s7000]\\n\\t\\u0011[s6010]download \\u0011[s2040]path\\u0011[s7000]\\n\\t\\tdownloads the node at \\u0011[sA000]path\\u0011[s7000] onto the device running itty\\n\\t\\u0011[s6010]upload \\u0011[s2040]path\\u0011[s7000]\\n\\t\\tdisplays a file picker and uploads the provided node, attempting to load it at \\u0011[sA000]path\\u0011[s7000]\\n\\t\\u0011[s6010]fetch \\u0011[s2040]path\\u0011[s7000] \\u0011[s2040]url\\u0011[s7000]\\n\\t\\tattempts to download the node at \\u0011[sA000]url\\u0011[s7000], and then attempts to load it at \\u0011[sA000]path\\u0011[s7000]\"},\"ls\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]ls\\u0011[s7000]\\n\\nls displays the contents of the given directory. if no directory is given, it displays the contents of the current one instead\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tls [\\u0011[sE000]flags\\u0011[s7000]] [\\u0011[sE000]directory\\u0011[s7000]]\\n\\n\\u0011[s4020]Flags:\\u0011[s7000]\\n\\t\\u0011[s3000]-a\\u0011[s7000] display hidden nodes\\n\\t\\u0011[s3000]-l\\u0011[s7000] use a list view\"},\"meta\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]meta\\u0011[s7000]\\n\\nmeta is a utility to manipulate file metadata\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tmeta \\u0011[s6040]subcommand\\u0011[s7000] \\u0011[s6040]arguments\\u0011[s7000]\\n\\n\\u0011[s4020]Subcommands:\\u0011[s7000]\\n\\t\\u0011[s6010]get \\u0011[s2040]file\\u0011[s7000] \\u0011[s2040]field\\u0011[s7000]\\n\\t\\tprints the value of \\u0011[sA000]field\\u0011[s7000] in \\u0011[sA000]file\\u0011[s7000]'s metadata\\n\\t\\u0011[s6010]set \\u0011[s2040]file\\u0011[s7000] \\u0011[s2040]field\\u0011[s7000]\\n\\t\\tattempts to interactively set the value of \\u0011[sA000]field\\u0011[s7000] in \\u0011[sA000]file\\u0011[s7000]'s metadata. values are JSON parsed\\n \\u0011[s6010]list \\u0011[s2040]file\\u0011[s7000]\\n\\t\\tdisplays a list of all fields and their values in \\u0011[sA000]file\\u0011[s7000]'s metadata\"},\"mkdir\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]mkdir\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mv\\tcp\\trm\\tln\\ttouch\\u0011[s7000]\\n\\nattempts to create a directory at the given \\u0011[sA000]path\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tmkdir \\u0011[s6040]path\\u0011[s7000]\"},\"mv\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]mv\\u0011[s7000]\\n\\n\\t\\u0011[s4000]cp\\trm\\tln\\tmkdir\\ttouch\\u0011[s7000]\\n\\nattempts to move the node at \\u0011[sA000]origin\\u0011[s7000] to \\u0011[sA000]destination\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tmv \\u0011[s6040]origin\\u0011[s7000] \\u0011[s6040]destination\\u0011[s7000]\"},\"persist\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]persist\\u0011[s7000]\\n\\npersist is a utility to work with filesystem persistence\\n\\na positive persistence level means the given path and its children will be saved in persistent storage. a negative level means the given path and its children will never be saved in persistent storage\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tpersist \\u0011[s6040]subcommand\\u0011[s7000] \\u0011[s6040]arguments\\u0011[s7000]\\n\\n\\u0011[s4020]Subcommands:\\u0011[s7000]\\n\\t\\u0011[s6010]get \\u0011[s2040]path\\u0011[s7000]\\n\\t\\tget the persistence level of the given path\\n\\t\\u0011[s6010]set \\u0011[s2040]path\\u0011[s7000] \\u0011[s2040]level\\u0011[s7000]\\n\\t\\tset the persistence level of the given path to the provided level\\n\\t\\u0011[s6010]list\\u0011[s7000]\\n\\t\\tdisplay a list of all paths with non-zero persistence levels\\n\\t\\u0011[s6010]backup\\u0011[s7000]\\n\\t\\tcreate a backup of persistent storage and download it\\n\\t\\u0011[s6010]restore\\u0011[s7000]\\n\\t\\tdisplay a file picker and attempt to restore the uploaded persistent storage backup\\n\\t\\u0011[s6010]save\\u0011[s7000]\\n\\t\\ttrigger a filesystem save\"},\"plist\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]plist\\u0011[s7000]\\n\\n\\t\\u0011[s4000]kill\\u0011[s7000]\\n\\nplist will output a list of running programs, with each program on its own line\\n\\nthe number in square brackets is the program's id, which can be used to quit it with \\u0011[sA000]kill\\u0011[s7000]. the number in parentheses is the program's unique id. after these, follows the program's name\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tplist\"},\"programs\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]programs\\u0011[s7000]\\n\\ndisplays a list of all programs found in the \\u0011[sA000]path\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tprograms\"},\"rm\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]rm\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mv\\tcp\\tln\\tmkdir\\ttouch\\u0011[s7000]\\n\\nattempts to remove the given node\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\trm \\u0011[s6040]node\\u0011[s7000]\"},\"scroll\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]scroll\\u0011[s7000]\\n\\nscroll will display any text piped to it, allowing the user to scroll the text to be able to read all its contents\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tscroll\\n\\n\\u0011[s5040]Binds\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]Escape\\u0011[s7000] or \\u0011[s6020]q\\u0011[s7000]: quits the program\\n\\u0011[sC000]- \\u0011[s6020]Arrow up\\u0011[s7000] or \\u0011[s6020]k\\u0011[s7000]: scrolls up\\n\\u0011[sC000]- \\u0011[s6020]Arrow down\\u0011[s7000] or \\u0011[s6020]j\\u0011[s7000]: scrolls down\"},\"shutdown\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]shutdown\\u0011[s7000]\\n\\nshuts itty down. if shutdown functionality is disabled, restarts itty instead. this saves the filesystem and then reloads it\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tshutdown\"},\"slog\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]slog\\u0011[s7000]\\n\\nslog is a simple log utility. when called, it will parse text piped to it as JSON and interpret it as an error. if the error level is 0, it is logged as INFO. if the error level is non-zero, it is logged and also output to the developer console\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tslog\\n\\n\\u0011[s5040]Files\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/itty/slog\\u0011[s7000]: the log file slog writes to\"},\"touch\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]touch\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mv\\tcp\\trm\\tln\\tmkdir\\u0011[s7000]\\n\\nif there is no node at the given \\u0011[sA000]path\\u0011[s7000], attempts to create an empty file\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\ttouch \\u0011[s6040]path\\u0011[s7000]\"},\"woman\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]woman\\u0011[s7000]\\n\\n\\t\\u0011[s4000]woman.template\\u0011[s7000]\\n\\nwoman is a simple utility for displaying documentation provided by itty packages\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\twoman \\u0011[s6040]page\\u0011[s7000]\\n\\n\\u0011[s5040]Binds\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]Escape\\u0011[s7000] or \\u0011[s6020]q\\u0011[s7000]: quits the scroll view\\n\\u0011[sC000]- \\u0011[s6020]Arrow up\\u0011[s7000] or \\u0011[s6020]k\\u0011[s7000]: scrolls up\\n\\u0011[sC000]- \\u0011[s6020]Arrow down\\u0011[s7000] or \\u0011[s6020]j\\u0011[s7000]: scrolls down\\n\\n\\u0011[s5040]Environment\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]dir_docs\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to search for documentation\\n\\n\\u0011[s5040]Woman page guidelines\\u0011[s7000]\\nwoman pages are plaintext with itty escape sequences used to add styling to text\\n\\nwoman pages should, for the most part, follow certain guidelines\\n\\nthese guidelines may be broken, if the writer considers this will make their documentation easier to understand\\n\\nto better understand the structure and style of woman pages, please see the page \\u0011[sA000]woman.template\\n\\n\\u0011[sC000]- \\u0011[s7000]they should be friendly and easy to understand\\n\\u0011[sC000]- \\u0011[s7000]they should all use the same style and formatting\\n\\u0011[sC000]- \\u0011[s7000]they shouldn't be too long. if a package needs extensive documentation, it can be split between multiple pages\\n\\u0011[sC000]- \\u0011[s7000]if a package has documentation, there must be a page by the most obvious name for the package\\n\\u0011[sC000]- \\u0011[s7000]additional page names must consist of this name, a period, and any name the writer desires for the page\\n\\u0011[sC000]- \\u0011[s7000]they should look good on displays of most sizes\\n\\u0011[sC000]- \\u0011[s7000]normal text should have style \\u0011[sA000]7000\\n\\u0011[sC000]- \\u0011[s7000]decorations should have style \\u0011[sA000]C000\\n\\u0011[sC000]- \\u0011[s7000]elements of a list should have style \\u0011[sA000]6020\\n\\u0011[sC000]- \\u0011[s7000]file paths should have style \\u0011[sA000]2040\\n\\u0011[sC000]- \\u0011[s7000]titles should have style \\u0011[sA000]5040\\n\\u0011[sC000]- \\u0011[s7000]subtitles should have style \\u0011[sA000]4020\\n\\u0011[sC000]- \\u0011[s7000]verbatim command and code examples should use style \\u0011[sA000]E800\\n\\u0011[sC000]- \\u0011[s7000]highlighted text should use styles \\u0011[sA000]A000\\u0011[s7000] or \\u0011[sA000]A020\\n\\n\\u0011[s4020]Structure:\\u0011[s7000]\\nwoman pages have the following sections, in this order:\\n\\u0011[sC000]- \\u0011[s6000]Title\\u0011[s7000]:\\n the title of the woman page, with style D050. mandatory\\n\\u0011[sC000]- \\u0011[s6000]Suggested pages\\u0011[s7000]:\\n other woman pages that may be of interest to the reader. starts with a tab, with additional tabs between pages. optional\\n\\u0011[sC000]- \\u0011[s6000]Introduction\\u0011[s7000]:\\n a little introduction about the program, package, or page. mandatory\\n\\u0011[sC000]- \\u0011[s6000]Usage\\u0011[s7000]:\\n contains a brief usage explanation, example command, and lists of subcommands, flags, and other arguments. mandatory if it applies\\n\\u0011[sC000]- \\u0011[s6000]Binds\\u0011[s7000]:\\n a list of keybinds if the program is interactive. mandatory if it applies\\n\\u0011[sC000]- \\u0011[s6000]Environment\\u0011[s7000]:\\n a list of environment variables the program reads or uses, and what they are for. mandatory if it applies\\n\\u0011[sC000]- \\u0011[s6000]Configuration\\u0011[s7000]:\\n an explanation of how to configure the program. mandatory if it applies\\n\\u0011[sC000]- \\u0011[s6000]Files\\u0011[s7000]:\\n a list of files the program writes or reads, and what they are for. mandatory if it applies\\n\\u0011[sC000]- \\u0011[s6000]Notes\\u0011[s7000]:\\n additional nodes regarding the page. optional\"},\"woman.template\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]Example Woman Page\\u0011[s7000]\\n\\n\\t\\u0011[s4000]woman\\u0011[s7000]\\n\\na template of a woman page, showing all sections and styles\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tcommand \\u0011[s6040]mandatory\\u0011[s7000] [\\u0011[sE000]optional\\u0011[s7000]]\\n\\n\\u0011[s4020]Subcommands:\\u0011[s7000]\\n\\t\\u0011[s6010]subcommand \\u0011[s2040]mandatory-argument\\u0011[s7000] [\\u0011[sE000]optional-argument\\u0011[s7000]]\\n\\t\\texplanation of what the subcommand does\\n\\t\\u0011[s6010]another-subcommand\\u0011[s7000]\\n\\t\\tanother explanation\\n\\n\\u0011[s4020]Flags:\\u0011[s7000]\\n\\t\\u0011[s3000]-f\\u0011[s7000] explanation of what the flag does\\n\\t\\u0011[s3000]-l\\u0011[s7000] another explanation\\n\\n\\u0011[s5040]Binds\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]key\\u0011[s7000]: what the keybind does\\n\\n\\u0011[s5040]Custom\\u0011[s7000]\\nthis is a custom section of the page, it can contain whatever you want\\n\\nthis here is \\u0011[sA000]highlighted\\u0011[s7000]. so is \\u0011[sA020]this\\u0011[s7000].\\n\\n\\u0011[s4020]A subtitle:\\u0011[s7000]\\nhere is some text that is \\u0011[sE800] supposed to be code \\u0011[s7000]\\n\\n\\u0011[s5040]Environment\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]environment_variable\\u0011[s7000] (\\u0011[sE000]type\\u0011[s7000]): what the variable is used for\\n\\n\\u0011[s5040]Configuration\\u0011[s7000]\\nexplanation of how to configure the program\\n\\u0011[sC000]- \\u0011[s6020]value\\u0011[s7000]: what the value does\\n\\n\\u0011[s5040]Files\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/path/to/file\\u0011[s7000]: what the file is used for\\n\\n\\u0011[s5040]Notes\\u0011[s7000]\\nspecial notes regarding the woman page\"},\"yarn\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]yarn\\u0011[s7000]\\n\\nyarn is a utility for creating and extracting archives called \\u0011[sA000]yarnballs\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tyarn \\u0011[s6040]subcommand\\u0011[s7000] \\u0011[s6040]arguments\\u0011[s7000]\\n\\n\\u0011[s4020]Subcommands:\\u0011[s7000]\\n\\t\\u0011[s6010]spool \\u0011[s2040]yarnball\\u0011[s7000] \\u0011[s2040]files\\u0011[s7000]\\n\\t\\tattempts to create a new yarnball, containing all the provided files\\n\\t\\u0011[s6010]unspool \\u0011[s2040]yarnball\\u0011[s7000] \\u0011[s2040]destination\\u0011[s7000]\\n\\t\\tattempts to extract the provided yarnball to the given destination\\n\\t\\u0011[s6010]metadata-from-json \\u0011[s2040]yarnball\\u0011[s7000] \\u0011[s2040]json-file\\u0011[s7000]\\n\\t\\tattempts to set the yarnball's metadata from the given JSON file. yarnball metadata can also be manipulated with the \\u0011[sA000]meta\\u0011[s7000] util\\n\\n\\u0011[s5040]Yarnball format\\u0011[s7000]\\nyarnballs are normal files whose content is stringified JSON\\n\\nthis JSON contains multiple entries. in each entry, the key is the filename of the contained node, and the content is an itty filesystem node\"}}},\"lazybox.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"\\nconst subprogram = program.name.replace(/\\\\.[^\\\\.]*$/, \\\"\\\").replace(/^.*\\\\//, \\\"\\\")\\n\\nswitch (subprogram) {\\n case \\\"bg\\\":\\n bg()\\n break\\n case \\\"cat\\\":\\n cat()\\n break\\n case \\\"clear\\\":\\n clear()\\n break\\n case \\\"cp\\\":\\n cp()\\n break\\n case \\\"echo\\\":\\n echo()\\n break\\n case \\\"env\\\":\\n await env()\\n break\\n case \\\"info\\\":\\n info()\\n break\\n case \\\"kill\\\":\\n kill()\\n break\\n case \\\"loader\\\":\\n await loader()\\n break\\n case \\\"ls\\\":\\n ls()\\n break\\n case \\\"meta\\\":\\n await meta()\\n break\\n case \\\"mkdir\\\":\\n mkdir()\\n break\\n case \\\"mv\\\":\\n mv()\\n break\\n case \\\"plist\\\":\\n plist()\\n break\\n case \\\"programs\\\":\\n programs()\\n break\\n case \\\"rm\\\":\\n rm()\\n break\\n case \\\"scroll\\\":\\n await scroll()\\n break\\n case \\\"shutdown\\\":\\n await shutdown()\\n break\\n case \\\"slog\\\":\\n slog()\\n break\\n case \\\"touch\\\":\\n touch()\\n break\\n case \\\"yarn\\\":\\n await yarn()\\n break\\n case \\\"ln\\\":\\n ln()\\n break\\n case \\\"woman\\\":\\n await woman()\\n break\\n case \\\"persist\\\":\\n await persist()\\n break\\n default:\\n quit()\\n}\\n\\n// programs are their own functions and defined here\\n\\nfunction bg() {\\n if (!args[0]) {\\n display.print(\\\"No program specified\\\", 0x1000)\\n quit()\\n }\\n\\n const programName = args[0]\\n args.splice(0, 1)\\n\\n try {\\n exec.runProgram(programName, args)\\n } catch (e) {\\n if (e[0]) {\\n io.log(e)\\n }\\n }\\n\\n quit()\\n}\\n\\nfunction cat() {\\n program.autoOutput = false\\n\\n const baseStyle = itty.baseStyle\\n\\n for (let a of args) {\\n let file\\n try {\\n file = io.open(a)\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000)\\n }\\n if (file) {\\n const lines = file.lines()\\n for (let line of lines) {\\n io.output(\\\"\\\\n\\\" + line)\\n display.print(line, itty.baseStyle, false)\\n }\\n }\\n }\\n \\n itty.baseStyle = baseStyle\\n\\n quit()\\n}\\n\\nfunction clear() {\\n program.enterFullscreen()\\n display.clear()\\n quit()\\n}\\n\\nfunction cp() {\\n if (!args[0] && !args[1]) {\\n itty.display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n }\\n\\n try {\\n itty.fs.copyNode(args[0], args[1])\\n } catch (e) {\\n itty.display.print(e[1] || \\\"Error copying node\\\", 0x9000)\\n }\\n\\n quit()\\n}\\n\\nfunction echo() {\\n const baseStyle = itty.baseStyle\\n let echo = pipe\\n if (!pipe)\\n echo = args.join(\\\" \\\")\\n\\n display.print(echo, itty.baseStyle, false)\\n itty.baseStyle = baseStyle\\n quit()\\n}\\n\\nasync function env() {\\n const subcommand = args[0]\\n const env = args[1]\\n\\n const envtype = typeof itty.env[env]\\n let value\\n\\n let listing = false\\n let listIndex = 0\\n\\n switch(subcommand) {\\n case \\\"get\\\":\\n if (!env) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n display.print(JSON.stringify(itty.env[env]) || \\\"undefined\\\", getEnvStyle(envtype))\\n quit()\\n break\\n case \\\"set\\\":\\n if (!env) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n await parseValue()\\n if (itty.env[env] && typeof itty.env[env] !== typeof value) {\\n let r = await io.read(\\\"Mismatch between env type and provided value type. Continue? [y/N]: \\\")\\n if (r.length === 0 || r[0].toLowerCase() !== \\\"y\\\") {\\n display.print(\\\"Aborting...\\\")\\n quit()\\n }\\n }\\n itty.env[env] = value\\n quit()\\n break\\n case \\\"list\\\":\\n const base = itty.baseStyle.toString(16)\\n for (let e in itty.env) {\\n display.buffer(`\\\\x11[s${getEnvStyle(typeof itty.env[e]).toString(16)}]${e}`)\\n display.buffer(\\\"\\\\x11[sE000] = \\\")\\n display.print(`\\\\x11[s${base}]${JSON.stringify(itty.env[e])}`)\\n }\\n display.render()\\n quit()\\n break\\n case \\\"save\\\":\\n try {\\n envfile = io.open(args[1], \\\"w\\\")\\n } catch {\\n try {\\n fs.makeNode(args[1], \\\"f\\\")\\n envfile = io.open(args[1], \\\"w\\\")\\n } catch {\\n display.print(\\\"Error creating file\\\", 0x9000)\\n quit()\\n }\\n }\\n\\n try {\\n envfile.write(JSON.stringify(itty.env))\\n envfile.writeOut()\\n } catch {\\n display.print(\\\"Error writing to file\\\", 0x9000)\\n quit()\\n }\\n\\n quit()\\n break\\n case \\\"load\\\":\\n try {\\n envfile = io.open(args[1], \\\"r\\\")\\n } catch {\\n display.print(\\\"File does not exist\\\", 0x9000)\\n quit()\\n }\\n\\n try {\\n envfile = JSON.parse(envfile.read())\\n } catch {\\n display.print(\\\"Cannot parse JSON\\\", 0x9000)\\n quit()\\n }\\n\\n for (let e of Object.entries(envfile))\\n itty.env[e[0]] = e[1]\\n\\n quit()\\n }\\n\\n async function parseValue() {\\n let v = await io.read([[\\\"Value: \\\", 0xe000]])\\n\\n try {\\n v = JSON.parse(v)\\n } catch (e) {\\n try {\\n v = JSON.parse('\\\"' + v + '\\\"')\\n } catch (e) {\\n throw [1, \\\"Cannot parse value\\\"]\\n }\\n }\\n value = v\\n }\\n \\n function getEnvStyle(type) {\\n let style = 0xf000\\n switch(type) {\\n case \\\"object\\\":\\n style = 0x4000\\n break\\n case \\\"string\\\":\\n style = 0x6000\\n break\\n case \\\"number\\\":\\n style = 0x5000\\n break\\n case \\\"boolean\\\":\\n style = 0xa000\\n break\\n }\\n return style\\n }\\n\\n quit()\\n}\\n\\nfunction info() {\\n const baseStyle = itty.baseStyle\\n\\n style.setAttribute(1, {_link: \\\"https://codeberg.org/Magdalunaa/itty\\\", style: \\\"cursor: pointer; text-decoration-color: var(--itty-c-4)\\\"})\\n\\n display.print(`Itty version: v${itty.version[0]}.${itty.version[1]}${itty.version[2] ? \\\".\\\" + itty.version[2] : \\\"\\\"} ${itty.version[3] || \\\"\\\"}\\\\nRoot FS: ${itty.disk.version}`, 0x4000)\\n display.buffer(\\\"\\\\nDisplay dimensions: \\\", 0x7000)\\n display.buffer(itty.width + \\\"x\\\" + itty.height + \\\"\\\\n\\\\n\\\", 0x6000)\\n for (let i=0; i < 8; i++) {\\n display.buffer(\\\" \\\", 0x0100 * i)\\n }\\n itty.cursorY++\\n itty.cursorX = 0\\n for (let i=8; i < 16; i++) {\\n display.buffer(\\\" \\\", 0x0100 * i)\\n }\\n\\n display.print(\\\"\\\\n\\\\n\\\\x11[s4041]ITTY: Incredibly Tiny Terminal, Yay! \\\\x11[s7041]by \\\\x11[s6051]Luna Magdalena :3\\\", undefined, true)\\n\\n itty.baseStyle = baseStyle\\n\\n quit()\\n}\\n\\nfunction kill() {\\n const id = Number(args[0])\\n\\n if (id)\\n try {\\n exec.quit(id)\\n } catch {}\\n quit()\\n}\\n\\nasync function loader() {\\n if (!args[1]) {\\n display.print(\\\"Not enough arguments\\\")\\n quit()\\n }\\n\\n const command = args[0]\\n const mountpoint = args[1]\\n const node = fs.getNode(mountpoint)\\n let content\\n\\n switch(command) {\\n case \\\"save\\\":\\n case \\\"download\\\":\\n content = fs.export(node)\\n\\n const blob = new Blob([content], { type: \\\"text/plain\\\" })\\n const url = URL.createObjectURL(blob)\\n\\n const a = document.createElement(\\\"a\\\")\\n a.href = url\\n a.download = node.name\\n a.style.display = \\\"none\\\"\\n\\n document.body.appendChild(a)\\n a.click()\\n document.body.removeChild(a)\\n\\n URL.revokeObjectURL(url)\\n break\\n case \\\"load\\\":\\n case \\\"upload\\\":\\n content = await getFile()\\n await fs.import(content.text, mountpoint)\\n display.print(\\\"Disk loaded successfully\\\", 0x3000)\\n break\\n case \\\"fetch\\\":\\n try {\\n content = await fetch(args[2])\\n } catch {\\n display.print(\\\"Cannot fetch remote file\\\", 0x9000)\\n quit()\\n }\\n try {\\n content = await content.json()\\n } catch {\\n display.print(\\\"Cannot parse file JSON\\\", 0x9000)\\n quit()\\n }\\n await fs.import(content, mountpoint)\\n break\\n }\\n\\n quit()\\n\\n function getFile() {\\n return new Promise(resolve => {\\n const input = document.createElement(\\\"input\\\")\\n input.type = \\\"file\\\"\\n input.accept = \\\"*/*\\\"\\n input.style.display = \\\"none\\\"\\n\\n document.body.appendChild(input)\\n\\n input.onchange = async () => {\\n const file = input.files[0]\\n const text = await file.text();\\n document.body.removeChild(input)\\n resolve({ file, text })\\n }\\n\\n input.click()\\n })\\n }\\n}\\n\\nfunction ls() {\\n // get flags\\n let flags = {}\\n let dir = \\\".\\\"\\n for (let i=0; i < args.length; i++) {\\n if (args[i][0] === \\\"-\\\") {\\n if (args[i].indexOf(\\\"l\\\") !== -1)\\n flags.l = true\\n if (args[i].indexOf(\\\"a\\\") !== -1)\\n flags.a = true\\n } else {\\n dir = args[i]\\n break\\n }\\n }\\n\\n // get node\\n let node\\n try {\\n node = fs.getNode(dir)\\n } catch (e) {\\n display.print(\\\"Not a directory\\\")\\n quit()\\n }\\n\\n if (!node || node.mode !== \\\"d\\\") {\\n display.print(\\\"Not a directory\\\")\\n quit()\\n }\\n\\n let empty = true\\n for (let n of fs.listDir(node)) {\\n if (n.name[0] === \\\".\\\" && !flags.a)\\n continue\\n\\n empty = false\\n\\n let style = 0x7000\\n if (n.mode === \\\"d\\\")\\n style = 0x5010\\n else if (n.mode === \\\"l\\\")\\n style = 0x3040\\n\\n if (n.protected)\\n style += 0x0020\\n\\n if (itty.cursorX + n.name.length >= itty.width) {\\n itty.cursorX = 0\\n itty.cursorY++\\n }\\n\\n while (itty.cursorY >= itty.height - 1)\\n display.lift()\\n\\n if (!flags.l)\\n display.buffer(n.name + \\\"\\\\x11[s7000]\\\\t\\\", style)\\n else\\n display.print(`\\\\x11[sc000]${n.mode} \\\\x11[s${style.toString(16)}]${n.name}${n.mode === \\\"l\\\" ? \\\"\\\\x11[sf000] -> \\\\x11[sb000]\\\" + n.content : \\\"\\\"}${n.protected ? \\\"\\\\x11[sf000] (protected)\\\" : \\\"\\\"}`)\\n }\\n\\n if (empty)\\n display.print(\\\"Directory is empty\\\", 0xf000)\\n\\n display.render()\\n quit()\\n}\\n\\nasync function meta() {\\n const file = fs.getNode(args[1])\\n\\n if (!file) {\\n display.print(\\\"File not found\\\", 0x1000)\\n quit()\\n }\\n\\n const meta = file.metadata\\n\\n const subcommand = args[0]\\n const key = args[2]\\n\\n let value\\n\\n switch(subcommand) {\\n case \\\"get\\\":\\n if (!key) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n display.print(JSON.stringify(meta[key]) || \\\"undefined\\\", getStyle(typeof meta[key]))\\n quit()\\n break\\n case \\\"set\\\":\\n if (!key) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n await parseValue()\\n try {\\n fs.setMetadata(file, key, value)\\n } catch (e) {\\n display.print(\\\"Error setting metadata: \\\" + e[1], 0x1000)\\n }\\n quit()\\n break\\n case \\\"list\\\":\\n const base = itty.baseStyle.toString(16)\\n for (let m in meta) {\\n display.buffer(`\\\\x11[s${getStyle(typeof meta[m]).toString(16)}]${m}`)\\n display.buffer(\\\"\\\\x11[sE000] = \\\")\\n display.print(`\\\\x11[s${base}]${JSON.stringify(meta[m])}`)\\n }\\n display.render()\\n quit()\\n }\\n\\n async function parseValue() {\\n let v = await io.read([[\\\"Value: \\\", 0xe000]])\\n\\n try {\\n v = JSON.parse(v)\\n } catch (e) {\\n try {\\n v = JSON.parse('\\\"' + v + '\\\"')\\n } catch (e) {\\n throw [1, \\\"Cannot parse value\\\"]\\n }\\n }\\n value = v\\n }\\n \\n function getStyle(type) {\\n let style = 0xf000\\n switch(type) {\\n case \\\"object\\\":\\n style = 0x4000\\n break\\n case \\\"string\\\":\\n style = 0x6000\\n break\\n case \\\"number\\\":\\n style = 0x5000\\n break\\n case \\\"boolean\\\":\\n style = 0xa000\\n break\\n }\\n return style\\n }\\n\\n quit()\\n}\\n\\nfunction mkdir() {\\n if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n }\\n\\n try {\\n fs.makeDir(args[0])\\n } catch (e) {\\n display.print(\\\"Error creating directory\\\", 0x1000)\\n }\\n quit()\\n}\\n\\nfunction mv() {\\n if (!args[0] && !args[1]) {\\n display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n }\\n\\n try {\\n fs.moveNode(args[0], args[1])\\n } catch (e) {\\n display.print(e[1] || \\\"Error moving node\\\", 0x9000)\\n }\\n\\n quit()\\n}\\n\\nfunction plist() {\\n const baseStyle = itty.baseStyle\\n // iterate over itty.program\\n\\n const programList = exec.listPrograms()\\n for (let p of programList) {\\n if (!p)\\n continue\\n display.buffer(\\\"\\\\x11[sF000][\\\")\\n display.buffer(\\\"\\\\x11[s6000]\\\" + p.id)\\n display.buffer(\\\"\\\\x11[sF000]] (\\\")\\n display.buffer(\\\"\\\\x11[s4000]\\\" + p.uid)\\n display.buffer(\\\"\\\\x11[sF000])\\\\t\\\")\\n display.buffer(\\\"\\\\x11[sE000]\\\" + p.name)\\n if (p.background) {\\n display.buffer(\\\"\\\\x11[sF000]\\\\t(\\\")\\n display.buffer(\\\"\\\\x11[s5000]background\\\")\\n display.buffer(\\\"\\\\x11[sF000])\\\")\\n }\\n display.write(\\\"\\\\n\\\")\\n }\\n\\n itty.baseStyle = baseStyle\\n quit()\\n}\\n\\nfunction programs() {\\n for (let path of itty.env.path) {\\n path = fs.resolve(path)\\n pathList = fs.listDir(path)\\n for (let p in pathList) {\\n p = pathList[p]\\n let name = p.shortname\\n\\n if (p.mode === \\\"l\\\")\\n p = fs.getNode(path + p.name)\\n\\n if (!p)\\n continue\\n\\n if (p.metadata.runner) {\\n if (itty.cursorX + name.length >= itty.width) {\\n itty.cursorX = 0\\n itty.cursorY++\\n }\\n while (itty.cursorY >= itty.height)\\n display.lift()\\n display.buffer(name + \\\" \\\")\\n }\\n }\\n }\\n \\n display.render()\\n quit()\\n}\\n\\nfunction rm() {\\n if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n }\\n\\n for (let node of args) {\\n try {\\n fs.removeNode(node)\\n } catch (e) {\\n display.print(e[1] || \\\"Error removing node\\\", 0x9000)\\n }\\n }\\n\\n quit()\\n}\\n\\nasync function scroll() {\\n if (!pipe)\\n quit()\\n\\n program.enterFullscreen()\\n const baseStyle = itty.baseStyle\\n\\n const lines = pipe.split(\\\"\\\\n\\\")\\n\\n function renderLines() {\\n display.clear()\\n for (let i = start; i < lines.length; i++) {\\n if ((lines[i].length + Math.floor(lines[i].length / itty.width) * 12) / itty.width > itty.height - itty.cursorY) {\\n break\\n }\\n display.print(lines[i] || \\\"\\\\x11 \\\")\\n }\\n }\\n\\n let start = 0\\n renderLines()\\n\\n program.onInput = (k) => {\\n switch (k) {\\n case \\\"%^\\\":\\n case \\\"k\\\":\\n start = Math.max(start - 1, 0)\\n renderLines()\\n break\\n case \\\"%v\\\":\\n case \\\"j\\\":\\n start = Math.min(start + 1, lines.length - 1)\\n renderLines()\\n break\\n case \\\"%e\\\":\\n case \\\"q\\\":\\n try {\\n quit()\\n } catch {}\\n }\\n }\\n\\n program.onResize = () => {\\n renderLines()\\n }\\n\\n program.onQuit = () => {\\n itty.baseStyle = baseStyle\\n display.clear()\\n }\\n}\\n\\nasync function shutdown() {\\n await exec.shutdown()\\n}\\n\\nfunction slog() {\\n // ensure log file exists\\n\\n let logfile\\n\\n try {\\n logfile = io.open(\\\"/itty/slog\\\", \\\"a\\\")\\n } catch {}\\n\\n if (!logfile) {\\n fs.getNode(\\\"/itty/\\\").content[\\\"slog\\\"] = {\\n protected: false,\\n mode: \\\"f\\\",\\n content: \\\"\\\",\\n parent: fs.getNode(\\\"/itty/\\\"),\\n name: \\\"slog\\\",\\n js: \\\"\\\",\\n metadata: {}\\n }\\n logfile = io.open(\\\"/itty/slog\\\", \\\"a\\\")\\n }\\n\\n const message = JSON.parse(pipe)\\n\\n if (message[1][0] !== 0)\\n console.log(\\\"ERROR\\\", message[1])\\n\\n logfile.print(`(${message[0].id}/${message[0].uid}) ${message[0].name}: [${message[1][0] || \\\"INFO\\\"}] ${message[1][1]}`)\\n logfile.writeOut()\\n\\n quit()\\n}\\n\\nfunction touch() {\\n if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n }\\n\\n try {\\n fs.makeNode(args[0], \\\"f\\\")\\n } catch (e) {\\n switch (e[0]) {\\n case 1:\\n display.print(\\\"File already exists\\\", 0xf000)\\n break\\n case 3:\\n display.print(\\\"Parent directory is protected\\\", 0x9000)\\n break\\n case 10:\\n display.print(\\\"Parent directory does not exist\\\", 0x9000)\\n break\\n default:\\n display.print(\\\"Error creating file\\\", 0x9000)\\n }\\n }\\n quit()\\n}\\n\\nasync function yarn() {\\n function spool(nodes) {\\n const yarnball = {}\\n\\n for (let node of nodes) {\\n let n\\n try {\\n n = fs.getNode(node)\\n } catch {\\n continue\\n }\\n\\n yarnball[n.name] = n\\n }\\n\\n return JSON.stringify(yarnball, (key, value) => {if (key === \\\"parent\\\" || key === \\\"name\\\" || key === \\\"ext\\\") {return undefined}; return value})\\n }\\n\\n function unspool(yarnball, path) {\\n fs.makeDir(path)\\n const node = fs.getNode(path)\\n if (node.protected)\\n io.error([3, \\\"Destination is protected\\\"])\\n\\n try {\\n yarnball = JSON.parse(yarnball)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(yarnball)) {\\n if (node.content[file])\\n continue\\n const obj = yarnball[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n fs.save()\\n }\\n\\n let yarnfile\\n let meta\\n let jsonfile\\n\\n switch (args[0]) {\\n case \\\"spool\\\":\\n yarnfile = io.open(args[1], \\\"w\\\")\\n yarnfile.write(spool(args.slice(2)))\\n yarnfile.writeOut()\\n break\\n case \\\"unspool\\\":\\n yarnfile = io.open(args[1], \\\"r\\\")\\n unspool(yarnfile.read(), args[2])\\n break\\n case \\\"metadata-from-json\\\":\\n try {\\n yarnfile = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n if (yarnfile.protected)\\n io.error([2, \\\"Yarnball is protected\\\"])\\n\\n try {\\n jsonfile = fs.getNode(args[2])\\n } catch {\\n io.error([1, \\\"Cannot find JSON file\\\"])\\n }\\n\\n try {\\n meta = JSON.parse(jsonfile.content)\\n } catch {\\n io.error([6, \\\"Cannot parse JSON\\\"])\\n }\\n\\n yarnfile.metadata = meta\\n break\\n }\\n quit()\\n}\\n\\nfunction ln() {\\n if (!args[1]) {\\n display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n }\\n\\n try {\\n fs.makeLink(args[1], args[0])\\n } catch (e) {\\n display.print(e[1] || \\\"Error creating link\\\", 0x9000)\\n }\\n\\n quit()\\n}\\n\\nasync function woman() {\\n if (!args[0]) {\\n display.print(\\\"No page specified\\\", 0xf000)\\n quit()\\n }\\n\\n // try to find the requested node\\n const dir = fs.resolve(itty.env.dir_docs || \\\"/itty/docs\\\")\\n const page = fs.getNode(dir + args[0])\\n\\n if (!page) {\\n display.print(\\\"Page does not exist\\\", 0xf000)\\n quit()\\n }\\n\\n program.autoOutput = false\\n io.output(io.fread(page))\\n\\n if (!program.visible)\\n quit()\\n\\n // get the expected max line count\\n let linecount = 0\\n\\n for (let line of io.flines(page)) {\\n l = (line.length + Math.ceil(line.length / itty.width) * 12) || 1\\n linecount += Math.ceil(l / itty.width)\\n }\\n\\n if (linecount < itty.height - 1) {\\n const baseStyle = itty.baseStyle\\n for (let line of io.flines(page))\\n display.print(line)\\n itty.baseStyle = baseStyle\\n quit()\\n } else {\\n pipe = \\\"\\\"\\n for (let line of io.flines(page))\\n pipe += \\\"\\\\n\\\" + line\\n pipe = pipe.replace(/^\\\\n/, \\\"\\\")\\n await scroll()\\n }\\n}\\n\\nasync function persist() {\\n // switch over arguments\\n\\n let disk\\n let diskmeta\\n let content\\n\\n switch (args[0]) {\\n case \\\"set\\\":\\n if (!args[2]) {\\n display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n }\\n\\n try {\\n fs.setPersistence(args[1], Number(args[2]))\\n } catch {\\n display.print(\\\"Error setting persistence level\\\", 0x9000)\\n quit()\\n }\\n\\n display.print(`Set persistence level for ${args[1]} to ${args[2]}`, 0x3000)\\n break\\n case \\\"get\\\":\\n if (!args[1]) {\\n display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n }\\n\\n args[1] = fs.resolve(args[1], false)\\n\\n diskmeta = localStorage.getItem(\\\"diskmeta\\\") || '{\\\"whitelist\\\": [], \\\"blacklist\\\": []}'\\n \\n try {\\n diskmeta = JSON.parse(diskmeta)\\n } catch {\\n display.print(\\\"Error parsing persistence metadata\\\", 0x9000)\\n quit()\\n }\\n\\n if (diskmeta.whitelist.includes(args[1]))\\n display.print(`${args[1]} is marked to persist`, 0x3000)\\n else if (diskmeta.blacklist.includes(args[1]))\\n display.print(`${args[1]} is marked to not persist`, 0x1000)\\n else\\n display.print(`${args[1]} is unmarked`, 0x7000)\\n\\n break\\n case \\\"list\\\":\\n diskmeta = localStorage.getItem(\\\"diskmeta\\\") || '{\\\"whitelist\\\": [], \\\"blacklist\\\": []}'\\n \\n try {\\n diskmeta = JSON.parse(diskmeta)\\n } catch {\\n display.print(\\\"Error parsing persistence metadata\\\", 0x9000)\\n quit()\\n }\\n\\n if (diskmeta.whitelist.length) {\\n display.print(\\\"Marked to persist:\\\", 0xB050)\\n for (let p of diskmeta.whitelist)\\n display.print(p, 0x3000)\\n }\\n\\n if (diskmeta.blacklist.length) {\\n display.print(\\\"Marked to not persist:\\\", 0x9050)\\n for (let p of diskmeta.blacklist)\\n display.print(p, 0x1000)\\n }\\n\\n break\\n case \\\"backup\\\":\\n diskmeta = localStorage.getItem(\\\"diskmeta\\\") || '{\\\"whitelist\\\": [], \\\"blacklist\\\": []}'\\n disk = localStorage.getItem(\\\"disksaved\\\") || '{}'\\n\\n try {\\n content = JSON.stringify({\\n disk: disk,\\n meta: diskmeta\\n })\\n } catch {\\n display.print(\\\"Error converting saved disk into a string\\\", 0x9000)\\n quit()\\n }\\n\\n const blob = new Blob([content], { type: \\\"text/plain\\\" })\\n const url = URL.createObjectURL(blob)\\n\\n const a = document.createElement(\\\"a\\\")\\n a.href = url\\n a.download = \\\"Itty Disk\\\"\\n a.style.display = \\\"none\\\"\\n\\n document.body.appendChild(a)\\n a.click()\\n document.body.removeChild(a)\\n\\n URL.revokeObjectURL(url)\\n break\\n case \\\"restore\\\":\\n content = await getFile()\\n content = content.text\\n\\n try {\\n content = JSON.parse(content)\\n } catch {\\n display.print(\\\"Error parsing disk content\\\", 0x9000)\\n quit()\\n }\\n\\n console.log(content)\\n\\n try {\\n localStorage.setItem(\\\"diskmeta\\\", content.meta)\\n localStorage.setItem(\\\"disksaved\\\", content.disk)\\n } catch {\\n display.print(\\\"Error storing disk data\\\", 0x9000)\\n quit()\\n }\\n\\n await exec.shutdown(true)\\n\\n break\\n case \\\"save\\\":\\n fs.save()\\n break\\n default:\\n display.print(\\\"No subcommand specified\\\", 0xf000)\\n }\\n\\n quit()\\n\\n function getFile() {\\n return new Promise(resolve => {\\n const input = document.createElement(\\\"input\\\")\\n input.type = \\\"file\\\"\\n input.accept = \\\"*/*\\\"\\n input.style.display = \\\"none\\\"\\n\\n document.body.appendChild(input)\\n\\n input.onchange = async () => {\\n const file = input.files[0]\\n const text = await file.text();\\n document.body.removeChild(input)\\n resolve({ file, text })\\n }\\n\\n input.click()\\n })\\n }\\n}\"}}"} \ No newline at end of file diff --git a/loader.yarn b/loader.yarn deleted file mode 100644 index 980f9ec..0000000 --- a/loader.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"loader","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"loader.js":"%B/loader.js"}},"content":"{\"loader.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[1]) {\\n display.print(\\\"Not enough arguments\\\")\\n quit()\\n}\\n\\nconst command = args[0]\\nargs.splice(0, 1)\\nconst mountpoint = args.join(\\\" \\\")\\nconst node = fs.getNode(mountpoint)\\nlet content\\n\\nswitch(command) {\\n case \\\"save\\\":\\n case \\\"download\\\":\\n content = fs.export(node)\\n\\n const blob = new Blob([content], { type: \\\"text/plain\\\" })\\n const url = URL.createObjectURL(blob)\\n\\n const a = document.createElement(\\\"a\\\")\\n a.href = url\\n a.download = node.name\\n a.style.display = \\\"none\\\"\\n\\n document.body.appendChild(a)\\n a.click()\\n document.body.removeChild(a)\\n\\n URL.revokeObjectURL(url)\\n break\\n case \\\"load\\\":\\n case \\\"upload\\\":\\n content = await getFile()\\n await fs.import(content.text, mountpoint)\\n display.print(\\\"Disk loaded successfully\\\", 0x3000)\\n}\\n\\nquit()\\n\\nfunction getFile() {\\n return new Promise(resolve => {\\n const input = document.createElement(\\\"input\\\")\\n input.type = \\\"file\\\"\\n input.accept = \\\"*/*\\\"\\n input.style.display = \\\"none\\\"\\n\\n document.body.appendChild(input)\\n\\n input.onchange = async () => {\\n const file = input.files[0]\\n const text = await file.text();\\n document.body.removeChild(input)\\n resolve({ file, text })\\n }\\n\\n input.click()\\n })\\n}\"}}"} \ No newline at end of file diff --git a/ls.yarn b/ls.yarn deleted file mode 100644 index a8ff0f1..0000000 --- a/ls.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"ls","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"ls.js":"%B/ls.js"}},"content":"{\"ls.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"// get flags\\nlet flags = {}\\nlet dir = \\\".\\\"\\nfor (let i=0; i < args.length; i++) {\\n if (args[i][0] === \\\"-\\\") {\\n if (args[i].indexOf(\\\"l\\\") !== -1)\\n flags.l = true\\n if (args[i].indexOf(\\\"a\\\") !== -1)\\n flags.a = true\\n } else {\\n dir = args[i]\\n break\\n }\\n}\\n\\n// get node\\nlet node\\ntry {\\n node = fs.getNode(dir)\\n} catch (e) {\\n display.print(\\\"Not a directory\\\")\\n quit()\\n}\\n\\nif (!node || node.mode !== \\\"d\\\") {\\n display.print(\\\"Not a directory\\\")\\n quit()\\n}\\n\\nlet empty = true\\nfor (let n of fs.listDir(node)) {\\n if (n.name[0] === \\\".\\\" && !flags.a)\\n continue\\n\\n empty = false\\n\\n let style = 0x7000\\n if (n.mode === \\\"d\\\")\\n style = 0x5000\\n\\n if (n.protected)\\n style += 0x0020\\n\\n if (itty.cursorX + n.name.length >= itty.width) {\\n itty.cursorX = 0\\n itty.cursorY++\\n }\\n\\n while (itty.cursorY >= itty.height)\\n display.lift()\\n\\n if (!flags.l) {\\n display.buffer(n.name + \\\" \\\", style)\\n } else {\\n display.buffer(n.mode + \\\" \\\", 0xc000)\\n display.buffer(n.name, style)\\n display.buffer(n.protected ? \\\" (protected)%n\\\" : \\\"%n\\\", 0xf000)\\n }\\n}\\n\\nif (empty)\\n display.print(\\\"Directory is empty\\\", 0xf000)\\n\\ndisplay.render()\\nquit()\"}}"} \ No newline at end of file diff --git a/meta.yarn b/meta.yarn deleted file mode 100644 index 9f767b1..0000000 --- a/meta.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"meta","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"meta.js":"%B/meta.js"}},"content":"{\"meta.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"const file = fs.getNode(args[1])\\nconst meta = file.metadata\\n\\nif (!file) {\\n display.print(\\\"File not found\\\", 0x1000)\\n quit()\\n}\\n\\nconst subcommand = args[0]\\nconst key = args[2]\\n\\nlet value\\n\\nlet listing = false\\nlet listIndex = 0\\n\\nswitch(subcommand) {\\n case \\\"get\\\":\\n if (!key) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n display.print(JSON.stringify(meta[key]), getStyle(typeof meta[key]))\\n quit()\\n break\\n case \\\"set\\\":\\n if (!key) {\\n display.print(\\\"No variable specified\\\")\\n quit()\\n }\\n await parseValue()\\n try {\\n fs.setMetadata(file, key, value)\\n } catch (e) {\\n display.print(\\\"Error setting metadata: \\\" + e[1], 0x1000)\\n }\\n quit()\\n break\\n case \\\"list\\\":\\n for (let e in meta) {\\n display.buffer(e, getStyle(typeof meta[e]))\\n display.buffer(\\\" = \\\", 0xe000)\\n display.print(JSON.stringify(meta[e]).replaceAll(\\\"%\\\", \\\"%%\\\"))\\n }\\n display.render()\\n quit()\\n}\\n \\nfunction getStyle(type) {\\n let style = 0xf000\\n switch(type) {\\n case \\\"object\\\":\\n style = 0x4000\\n break\\n case \\\"string\\\":\\n style = 0x6000\\n break\\n case \\\"number\\\":\\n style = 0x5000\\n break\\n case \\\"boolean\\\":\\n style = 0xa000\\n break\\n }\\n return style\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/miss.yarn b/miss.yarn index f5e021d..4ca0b6a 100644 --- a/miss.yarn +++ b/miss.yarn @@ -1 +1 @@ -{"protected":false,"mode":"f","metadata":{"name":"miss","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"miss.js":"%B/miss.js"}},"content":"{\"miss.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\" // check if there is a config file\\nlet config = {}\\n\\nif (fs.getNode(fs.resolve(itty.env.dir_conf || \\\"/conf/\\\") + \\\"miss.conf\\\")) {\\n try {\\n const configFile = io.open(fs.resolve(itty.env.dir_conf || \\\"/conf/\\\") + \\\"miss.conf\\\")\\n config = configFile.read()\\n config = JSON.parse(config)\\n } catch (e) {\\n io.error([1, \\\"Error parsing config\\\"])\\n config = {}\\n }\\n}\\n\\nlet history = []\\nlet historyIndex = 0\\n\\nfunction onInput(key) {\\n switch (key) {\\n case \\\"%^\\\":\\n historyIndex = Math.max(historyIndex - 1, 0)\\n if (history[historyIndex]) {\\n program.read.input = history[historyIndex]\\n program.read.cursor = program.read.input.length\\n }\\n break\\n case \\\"%v\\\":\\n historyIndex = Math.min(historyIndex + 1, history.length)\\n if (history[historyIndex]) {\\n program.read.input = history[historyIndex]\\n program.read.cursor = program.read.input.length\\n } else if (historyIndex === history.length) {\\n program.read.input = \\\"\\\"\\n program.read.cursor = 0\\n }\\n break\\n }\\n}\\n\\nlet running = false\\n// this runs on every new line\\nasync function line() {\\n // promt! %D gets replaced by the active dir\\n const prompt = config.prompt || [[\\\"%D\\\", 0xc000], [\\\" > \\\", 0xd000]]\\n\\n for (let p of prompt)\\n p[0] = p[0].replace(/%D/g, program.currentDir)\\n\\n // parse arguments\\n let command = await io.read(prompt)\\n if (command !== \\\"\\\" && command !== history[history.length - 1]) {\\n history.push(command)\\n historyIndex = history.length\\n }\\n command = command.replace(/%%/g, \\\"%\\\")\\n let args = command.match(/\\\"([^\\\"%]*(%.[^\\\"%]*)*)\\\"|'([^'%]*(%.[^'%]*)*)'|\\\\S+/g)\\n\\n if (args) {\\n for (let i=0; i < args.length; i++) {\\n args[i] = args[i].replace(/^'(.*)'$|^\\\"(.*)\\\"$/, \\\"$1$2\\\")\\n args[i] = args[i].replace(/%(['\\\"])/g, \\\"$1\\\")\\n }\\n\\n // split into multiple commands\\n const commands = []\\n let redir\\n let c = []\\n for (let a of args) {\\n if (a !== \\\"|\\\") {\\n c.push(a)\\n } else {\\n commands.push(c.slice())\\n c = []\\n }\\n }\\n commands.push(c)\\n\\n let redirIndex = commands[commands.length - 1].indexOf(\\\">\\\")\\n if (redirIndex !== -1) {\\n redir = commands[commands.length - 1][redirIndex + 1]\\n commands[commands.length - 1] = commands[commands.length - 1].slice(0, redirIndex)\\n }\\n\\n running = true\\n let output = \\\"\\\"\\n for (let c = 0; c < commands.length; c++) {\\n const hidden = (c < commands.length - 1 || redir ? true : false)\\n output = await run(commands[c], output, hidden)\\n }\\n \\n if (redir) {\\n let file\\n try {\\n file = io.open(redir, \\\"a\\\")\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000) \\n }\\n if (file) {\\n file.write(output)\\n try {\\n file.writeOut()\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000) \\n }\\n }\\n }\\n\\n running = false\\n \\n if (itty.cursorX !== 0)\\n itty.cursorY++\\n\\n line()\\n } else {\\n line()\\n }\\n}\\n\\n// attempt to run autorun functions!\\nif (program.uid === 0) {\\n for (let a of [\\\"/autorun\\\", \\\"/autorun.js\\\", \\\"/.autorun\\\", \\\"/.autorun.js\\\"]) {\\n try {\\n exec.runProgram(a, [], \\\"\\\", false)\\n } catch {}\\n }\\n}\\n\\nline()\\n\\nasync function run(arg, input, hidden) {\\n const program = arg[0]\\n if (arg.length > 1)\\n arg.splice(0, 1)\\n else\\n arg = []\\n let file = null\\n\\n switch (program) {\\n // built in \\\"programs\\\"\\n case \\\"cd\\\":\\n try {\\n fs.changeDir(arg[0] || itty.env.home)\\n } catch (e) {\\n display.print(\\\"Not a directory\\\")\\n }\\n break\\n case \\\"exit\\\":\\n quit()\\n display.print(\\\"Cannot quit init process\\\", 0xf000)\\n return\\n break\\n // otherwise, call\\n default:\\n let output\\n try {\\n output = await exec.runProgram(program, arg, input, hidden)\\n } catch (e) {\\n if (e[0] !== 0) {\\n if (e[0] === -1 && e[1] === \\\"Cannot find program file\\\") {\\n display.print(`${program}: command not found.`, 0x2000)\\n return\\n } else\\n display.print(\\\"Error running program\\\", 0x9000)\\n }\\n }\\n\\n return output\\n }\\n}\\n\\nfunction onReturn() {\\n if (running)\\n return\\n\\n program.visible = true\\n program.focused = true\\n historyIndex = history.length\\n if (itty.cursorX !== 0)\\n itty.cursorY++\\n onError()\\n}\\n\\nfunction onError() {\\n if (program.visible) {\\n for (let e of io.getErrors()) {\\n display.write(`[${e[0]}] `, 0x9010)\\n display.print(e[1] || \\\"\\\")\\n }\\n }\\n}\\n\\nfunction onResize() {\\n if (program.focused) {\\n program.read.line = 0\\n display.clear()\\n }\\n}\"}}"} \ No newline at end of file +{"protected":false,"mode":"f","metadata":{"name":"miss","author":"Luna Magdalena :3","version":[1,1],"dependencies":[],"paths":{"miss.js":"%B/miss.js","miss":"%D/miss"}},"content":"{\"miss.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\" // check if there is a config file\\nlet config = {}\\n\\nif (fs.getNode(fs.resolve(itty.env.dir_conf || \\\"/conf/\\\") + \\\"miss.conf\\\")) {\\n try {\\n const configFile = io.open(fs.resolve(itty.env.dir_conf || \\\"/conf/\\\") + \\\"miss.conf\\\")\\n config = configFile.read()\\n config = JSON.parse(config)\\n } catch (e) {\\n io.error([1, \\\"Error parsing config\\\"])\\n config = {}\\n }\\n}\\n\\n// promt! %D gets replaced by the active dir\\nconst prompt = config.prompt || [[\\\"%D\\\", 0xc000], [\\\" > \\\", 0xd000]]\\n\\nlet history = []\\nlet historyIndex = 0\\n\\nfunction onInput(key) {\\n switch (key) {\\n case \\\"%^\\\":\\n historyIndex = Math.max(historyIndex - 1, 0)\\n if (history[historyIndex]) {\\n program.read.input = history[historyIndex]\\n program.read.cursor = program.read.input.length\\n }\\n break\\n case \\\"%v\\\":\\n historyIndex = Math.min(historyIndex + 1, history.length)\\n if (history[historyIndex]) {\\n program.read.input = history[historyIndex]\\n program.read.cursor = program.read.input.length\\n } else if (historyIndex === history.length) {\\n program.read.input = \\\"\\\"\\n program.read.cursor = 0\\n }\\n break\\n }\\n}\\n\\nlet running = false\\n// this runs on every new line\\nasync function line() {\\n itty.baseStyle = config.style || 0x7000 \\n\\n for (let p of prompt)\\n p[0] = p[0].replace(/%D/g, program.currentDir)\\n\\n // parse arguments\\n let command = await io.read(prompt)\\n if (command !== \\\"\\\" && command !== history[history.length - 1]) {\\n history.push(command)\\n historyIndex = history.length\\n }\\n\\n let args = command.match(/\\\"([^\\\"\\\\\\\\]*(\\\\\\\\.[^\\\"\\\\\\\\]*)*)\\\"|'([^'\\\\\\\\]*(\\\\\\\\.[^'\\\\\\\\]*)*)'|\\\\S+/g)\\n\\n if (args) {\\n for (let i=0; i < args.length; i++) {\\n args[i] = args[i].replace(/\\\\\\\\\\\\\\\\/g, \\\"\\\\x14b\\\")\\n args[i] = args[i].replace(/^'(.*)'$|^\\\"(.*)\\\"$/, \\\"$1$2\\\")\\n args[i] = args[i].replace(/\\\\\\\\(['\\\"])/g, \\\"$1\\\")\\n }\\n\\n // split into multiple commands\\n const commands = []\\n let redir\\n let c = []\\n for (let a of args) {\\n if (a !== \\\"|\\\") {\\n c.push(a)\\n } else {\\n commands.push(c.slice())\\n c = []\\n }\\n }\\n commands.push(c)\\n\\n let redirIndex = commands[commands.length - 1].indexOf(\\\">\\\")\\n if (redirIndex !== -1) {\\n redir = commands[commands.length - 1][redirIndex + 1]\\n commands[commands.length - 1] = commands[commands.length - 1].slice(0, redirIndex)\\n }\\n\\n running = true\\n let output = \\\"\\\"\\n for (let c = 0; c < commands.length; c++) {\\n const hidden = (c < commands.length - 1 || redir ? true : false)\\n output = await run(commands[c], output, hidden)\\n }\\n \\n if (redir) {\\n let file\\n redir = redir.replace(/\\\\x14b/g, \\\"\\\\\\\\\\\")\\n try {\\n file = io.open(redir, \\\"a\\\")\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000) \\n }\\n if (file) {\\n file.write(output)\\n try {\\n file.writeOut()\\n } catch (e) {\\n display.print(\\\"Cannot open file\\\", 0x9000) \\n }\\n }\\n }\\n\\n running = false\\n \\n if (itty.cursorX !== 0)\\n itty.cursorY++\\n\\n line()\\n } else {\\n line()\\n }\\n}\\n\\n// attempt to run autorun functions!\\nif (program.uid === 0) {\\n for (let a of [\\\"/autorun\\\", \\\"/autorun.js\\\", \\\"/.autorun\\\", \\\"/.autorun.js\\\"]) {\\n try {\\n exec.runProgram(a, [], \\\"\\\", false)\\n } catch {}\\n }\\n}\\n\\nline()\\n\\nasync function run(arg, input, hidden) {\\n const program = arg[0]\\n if (arg.length > 1)\\n arg.splice(0, 1)\\n else\\n arg = []\\n let file = null\\n\\n // do a bit of cleanup on the args\\n for (let i = 0; i < arg.length; i++) {\\n arg[i] = arg[i].replace(/\\\\\\\\([|>])/g, \\\"$1\\\")\\n arg[i] = arg[i].replace(/\\\\x14b/g, \\\"\\\\\\\\\\\")\\n }\\n\\n switch (program) {\\n // built in \\\"programs\\\"\\n case \\\"cd\\\":\\n try {\\n fs.changeDir(arg[0] || itty.env.home)\\n } catch (e) {\\n display.print(\\\"Not a directory\\\")\\n }\\n break\\n case \\\"exit\\\":\\n quit()\\n display.print(\\\"Cannot quit init process\\\", 0xf000)\\n return\\n break\\n // otherwise, call\\n default:\\n let output\\n try {\\n output = await exec.runProgram(program, arg, input, hidden)\\n } catch (e) {\\n if (e[0] !== 0) {\\n if (e[0] === -1 && e[1] === \\\"Cannot find program file\\\") {\\n display.print(`${program}: command not found.`, 0x2000)\\n return\\n } else\\n display.print(\\\"Error running program\\\", 0x9000)\\n }\\n }\\n\\n return output\\n }\\n}\\n\\nfunction onReturn() {\\n if (running)\\n return\\n\\n program.visible = true\\n program.focused = true\\n historyIndex = history.length\\n if (itty.cursorX !== 0)\\n itty.cursorY++\\n onError()\\n}\\n\\nfunction onError() {\\n if (program.visible) {\\n for (let e of io.getErrors()) {\\n display.write(`[${e[0]}] `, 0x9010)\\n display.print(e[1] || \\\"\\\")\\n }\\n }\\n}\"},\"miss\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]MISS - Magdalena's Init and Simple Shell\\u0011[s7000]\\n\\nmiss is a simple shell and init system for itty\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tmiss\\n\\n\\u0011[s5040]Binds\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]Arrow up\\u0011[s7000]: move up in command history\\n\\u0011[sC000]- \\u0011[s6020]Arrow down\\u0011[s7000]: move down in command history\\n\\u0011[sC000]- \\u0011[s6020]Enter\\u0011[s7000]: input command\\n\\u0011[sC000]- \\u0011[s6020]Control + v\\u0011[s7000]: paste from clipboard\\n\\n\\u0011[s5040]Prompt\\u0011[s7000]\\nthe prompt will separate arguments by spaces, unless they are surrounded by single (\\u0011[sA000]'\\u0011[s7000]) or double (\\u0011[sA000]\\\"\\u0011[s7000]) quotes\\n\\nby using the \\u0011[sA000]|\\u0011[s7000] character, you can send one program's output to a different program. the \\u0011[sA000]>\\u0011[s7000] sign will instead redirect the program's output to a file\\n\\na backslash (\\u0011[sA000]\\\\\\u0011[s7000]) can be used to escape special characters\\n\\n\\u0011[s5040]Environment\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]dir_conf\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the config directory that miss will look for a config file in\\n\\n\\u0011[s5040]Configuration\\u0011[s7000]\\nmiss will read configuration from a \\u0011[s2040]miss.conf\\u0011[s7000] file located in the config directory. this file must be valid JSON\\n\\nthe file contains the following values:\\n\\n\\u0011[sC000]- \\u0011[s6020]prompt\\u0011[s7000]: the prompt to start every line with. it is an array, whose elements are arrays containing a string and itty style info. the \\u0011[sA000]%D\\u0011[s7000] string will be replaced by the current working directory\\n\\u0011[sC000]- \\u0011[s6020]style\\u0011[s7000]: the default itty style to use for text\\n\\n\\u0011[s5040]Files\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]miss.conf\\u0011[s7000]: must be in the config directory. miss will read this file for configuration\\n\\non startup, before the first prompt, miss will attempt to execute the following files:\\n\\u0011[sC000]- \\u0011[s2040]/autorun\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/autorun.js\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/.autorun\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/.autorun.js\\u0011[s7000]\"}}"} \ No newline at end of file diff --git a/mkdir.yarn b/mkdir.yarn deleted file mode 100644 index 4b58a19..0000000 --- a/mkdir.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"mkdir","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"mkdir.js":"%B/mkdir.js"}},"content":"{\"mkdir.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.makeDir(args[0])\\n} catch (e) {\\n display.print(\\\"Error creating directory\\\", 0x1000)\\n}\\nquit()\"}}"} \ No newline at end of file diff --git a/mrrp.yarn b/mrrp.yarn index c9f5260..9f2f6a4 100644 --- a/mrrp.yarn +++ b/mrrp.yarn @@ -1 +1 @@ -{"protected":false,"mode":"f","metadata":{"name":"mrrp","author":"Luna Magdalena :3","version":[1,1],"dependencies":[],"paths":{"mrrp.js":"%B/mrrp.js"}},"content":"{\"mrrp.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"let yarnball\\nlet repoNode = fs.getNode(\\\"/itty/repos.json\\\")\\nlet repoList = JSON.parse(repoNode.content)\\nlet pkgList\\nlet updateList = []\\nlet world = io.flines(fs.getNode(\\\"/itty/world\\\")).filter(Boolean)\\nlet unwantedPkgs\\n\\n// we use some env vars, parse them\\nconst dirs = {\\n bin: fs.resolve(itty.env.dir_bin).slice(0, -1) || \\\"/itty/bin\\\",\\n docs: fs.resolve(itty.env.dir_docs).slice(0, -1) || \\\"/itty/docs\\\",\\n conf: fs.resolve(itty.env.dir_conf) + \\\"examples\\\" || \\\"/conf/examples\\\",\\n lib: fs.resolve(itty.env.dir_lib).slice(0, -1) || \\\"/itty/lib\\\"\\n}\\n\\n// cache repo indexes, so querying and updating is faster\\nlet repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\nif (!repoCache) {\\n fs.makeDir(\\\"/.tmp/mrrp/\\\")\\n fs.makeNode(\\\"/.tmp/mrrp/repocache\\\", \\\"f\\\")\\n await refreshCache()\\n} else {\\n repoCache = JSON.parse(repoCache.content) \\n}\\n\\n// refresh the repo cache!\\nasync function refreshCache() {\\n repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\n const list = {}\\n for (let r of Object.entries(repoList)) {\\n let rj\\n try {\\n rj = await fetch(r[1].url + \\\"repo.json\\\")\\n rj = await rj.json()\\n } catch {\\n display.print(\\\"Cannot fetch repository info for \\\" + r[0], 0x9000)\\n continue\\n }\\n rj.url = r[1].url\\n list[r[0]] = rj\\n }\\n repoCache.content = JSON.stringify(list)\\n repoCache = list\\n}\\n\\n// confirmation as to whether to do things\\nasync function ask(message) {\\n const res = await io.read([[message + \\\" [y/N]: \\\"]])\\n\\n if (res.toLowerCase() !== \\\"y\\\" && res.toLowerCase() !== \\\"yes\\\") {\\n display.print(\\\"Aborting...\\\", 0x9000)\\n return false\\n }\\n\\n display.print(\\\"Proceeding...\\\", 0x3000)\\n return true\\n}\\n\\n// install a program\\nasync function install(yarnball, reponame, interactive = true, wanted) {\\n wanted = wanted || world.includes(yarnball.metadata.name)\\n\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n // substitute %B, %C and %D in paths with env vars\\n for (let path of Object.keys(yarnball.metadata.paths)) {\\n let p = yarnball.metadata.paths[path]\\n p = p.replaceAll(\\\"%B\\\", dirs.bin)\\n p = p.replaceAll(\\\"%D\\\", dirs.docs)\\n p = p.replaceAll(\\\"%C\\\", dirs.conf)\\n p = p.replaceAll(\\\"%L\\\", dirs.lib)\\n yarnball.metadata.paths[path] = p\\n }\\n\\n // ask the user!\\n if (interactive) {\\n const v = yarnball.metadata.version\\n display.print(\\\"Installing \\\" + yarnball.metadata.name + \\\" version \\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" from \\\" + reponame, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path in yarnball.metadata.paths) {\\n display.print(yarnball.metadata.paths[path], 0x2000)\\n }\\n if (yarnball.metadata.dependencies.length)\\n display.print(\\\"The following dependencies also need to be installed:\\\", 0x6000)\\n for (let d of yarnball.metadata.dependencies) {\\n if (!list[d])\\n display.print(d, 0x6000)\\n }\\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // uninstall if already installed\\n if (list[yarnball.metadata.name])\\n await uninstall(yarnball.metadata.name, false)\\n\\n // unspool the yarnball\\n fs.removeNode(\\\"/.tmp/mrrp/x\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/x\\\")\\n const node = fs.getNode(\\\"/.tmp/mrrp/x\\\")\\n let content\\n\\n try {\\n content = JSON.parse(yarnball.content)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(content)) {\\n if (node.content[file])\\n continue\\n const obj = content[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n\\n // move files accordingly\\n for (let path of Object.entries(yarnball.metadata.paths)) {\\n const paths = fs.splitPath(path[1])\\n makeDir(paths[0])\\n const parent = fs.getNode(paths[0])\\n parent.content[paths[1]] = fs.getNode(\\\"/.tmp/mrrp/x/\\\" + path[0])\\n fs.refreshPathAttributes(parent)\\n }\\n\\n // keep track!\\n list[yarnball.metadata.name] = {\\n name: yarnball.metadata.name,\\n repo: reponame,\\n version: yarnball.metadata.version,\\n paths: [],\\n dependencies: yarnball.metadata.dependencies\\n }\\n\\n for (let path of Object.entries(yarnball.metadata.paths))\\n list[yarnball.metadata.name].paths.push(path[1])\\n\\n listNode.content = JSON.stringify(list)\\n\\n if (wanted && !world.includes[yarnball.metadata.name])\\n world.push(yarnball.metadata.name)\\n\\n if (interactive)\\n display.print(\\\"Package \\\" + yarnball.metadata.name + \\\" installed\\\", 0x6000)\\n\\n // handle dependencies but after install because we only keep one package in the cache hehe this is awful i'm sorry\\n for (let d of yarnball.metadata.dependencies) {\\n if (list[d])\\n continue\\n const reponame = await fetchPkg(d)\\n if (!reponame) {\\n display.print(\\\"Could not install dependency \\\" + d, 0x9000)\\n continue\\n }\\n const yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, interactive)\\n }\\n}\\n\\nasync function uninstall(package, interactive = true) {\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n const pkginfo = list[package]\\n if (!pkginfo) {\\n if (interactive)\\n display.print(\\\"Package is not installed\\\", 0x6000)\\n return\\n }\\n \\n // ask the user!\\n if (interactive) {\\n display.print(\\\"Removing \\\" + pkginfo.name, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path of pkginfo.paths)\\n display.print(path, 0x2000)\\n \\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // actually remove\\n for (let path of pkginfo.paths) {\\n const paths = fs.splitPath(path)\\n delete fs.getNode(paths[0]).content[paths[1]]\\n }\\n\\n delete list[pkginfo.name]\\n list = JSON.stringify(list)\\n listNode.content = list\\n\\n const i = world.indexOf(pkginfo.name)\\n if (i > -1)\\n world.splice(i)\\n\\n if (interactive)\\n display.print(\\\"Package removed\\\", 0x6000)\\n}\\n\\nasync function fetchPkg(package, repo, reponame, interactive = true) {\\n let repojson\\n let rlist = []\\n if (repo) {\\n repojson = repo\\n \\n if (!repojson) {\\n display.print(\\\"Cannot find repository info for \\\" + reponame, 0x2000)\\n io.error([1, \\\"Cannot find repository info\\\"])\\n }\\n } else {\\n // look for package in repos\\n for (let r of Object.entries(repoCache)) {\\n let rj = r[1]\\n \\n if (rj.packages[package])\\n rlist.push([r[0], r[1], rj])\\n }\\n \\n switch (rlist.length) {\\n case 0:\\n display.print(\\\"Cannot find package \\\" + package, 0x9000)\\n return false\\n case 1:\\n repojson = rlist[0][2]\\n repo = rlist[0][1]\\n reponame = rlist[0][0]\\n break\\n case 2:\\n display.print(\\\"Package \\\" + package + \\\" is available in the following repositories:\\\", 0x5000)\\n for (let i=0; i < rlist.length; i++) {\\n const v = rlist[i][2].packages[package].version\\n display.buffer(\\\"[\\\" + (i + 1) + \\\"] \\\")\\n display.buffer(rlist[i][0], 0x2000)\\n display.print(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n }\\n const sel = await io.read([[\\\"Selection: \\\"]])\\n if (!sel)\\n return false\\n else {\\n repojson = rlist[sel-1][2]\\n repo = rlist[sel-1][1]\\n reponame = rlist[sel-1][0]\\n }\\n }\\n }\\n\\n // download\\n\\n let pkg\\n try {\\n pkg = await fetch(repojson.packages[package].url.replace(/^~/, repo.url))\\n pkg = await pkg.json()\\n } catch {\\n display.print(\\\"Cannot fetch package \\\" + package + \\\" from repository \\\" + reponame, 0x9000)\\n throw [2, \\\"Cannot fetch package\\\"]\\n }\\n\\n fs.removeNode(\\\"/.tmp/mrrp/dl\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/dl\\\")\\n const dl = fs.getNode(\\\"/.tmp/mrrp/dl\\\")\\n dl.content.yarn = pkg\\n fs.refreshPathAttributes(dl)\\n\\n return reponame\\n}\\n\\nfunction want(package) {\\n const index = unwantedPkgs.indexOf(package)\\n if (index > -1)\\n unwantedPkgs.splice(index)\\n\\n if (pkgList[pkg])\\n for (let dep of pkgList[package].dependencies)\\n want(dep)\\n}\\n\\nswitch (args[0]) {\\n case \\\"yarn\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n yarnball = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n\\n await install(yarnball, \\\"local yarnball\\\", true, true)\\n break\\n case \\\"uninstall\\\":\\n case \\\"remove\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n await uninstall(args[1])\\n break\\n case \\\"list-repos\\\":\\n for (let repo of Object.entries(repoList)) {\\n display.write(repo[0] + \\\" \\\", 0x2000)\\n display.print(repo[1].url)\\n }\\n break\\n case \\\"remove-repo\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n delete repoList[args[1]]\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Removed repo \\\" + args[1], 0x6000)\\n await refreshCache()\\n break\\n case \\\"add-repo\\\":\\n if (args.length < 3) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n \\n args[2] = args[2].replace(/([^\\\\/])$/, \\\"$1/\\\")\\n\\n // fetch repo\\n try {\\n repo = await fetch(args[2] + \\\"repo.json\\\")\\n } catch {\\n display.print(\\\"Cannot fetch repository info\\\", 0x9000)\\n quit()\\n }\\n\\n if (repoList[args[1]]) {\\n display.print(\\\"Repository \\\" + args[1] + \\\" already exists.\\\", 0x2000)\\n if (!await ask(\\\"Overwrite?\\\"))\\n quit()\\n }\\n\\n repoList[args[1]] = {\\n url: args[2]\\n }\\n\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Added repo \\\" + args[1] + \\\" with url \\\" + args[2], 0x6000)\\n await refreshCache()\\n break\\n case \\\"install\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const reponame = await fetchPkg(args[1])\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n break\\n case \\\"refresh-repos\\\":\\n await refreshCache()\\n display.print(\\\"Refreshed repository cache\\\", 0x6000)\\n break\\n case \\\"update\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n if (pkg[1].repo === \\\"local yarnball\\\" || !repoCache[pkg[1].repo])\\n continue\\n\\n const iv = pkg[1].version\\n const rv = repoCache[pkg[1].repo].packages[pkg[0]].version\\n\\n iv[1] = iv[1] || 0\\n iv[2] = iv[2] || 0\\n rv[1] = rv[1] || 0\\n rv[2] = rv[2] || 0\\n\\n if (rv[0] > iv[0] || rv[0] == iv[0] && rv[1] > iv[1] || rv[0] == iv[0] && rv[1] == iv[1] && rv[2] > iv[2])\\n updateList.push([pkg[0], pkg[1].repo, repoCache[pkg[1].repo]])\\n }\\n\\n if (!updateList.length) {\\n display.print(\\\"No packages need updating\\\", 0x3000)\\n quit()\\n }\\n\\n if (args[1] !== \\\"bg\\\") {\\n display.print(\\\"Packages to update:\\\", 0x6000)\\n for (let pkg of updateList)\\n display.print(pkg[0], 0x2000)\\n if (!await ask(\\\"Proceed?\\\"))\\n quit()\\n }\\n\\n for (let pkg of updateList) {\\n let f\\n try {\\n f = await fetchPkg(pkg[0], pkg[2], pkg[1], false)\\n } catch {\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Could not fetch \\\" + pkg[0] + \\\" from \\\" + pkg[1], 0x1000)\\n continue\\n }\\n if (f) {\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, pkg[1], false)\\n }\\n }\\n\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Updated packages\\\", 0x3000)\\n break\\n case \\\"list\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x4000)\\n display.buffer(\\\"(\\\")\\n display.buffer(pkg[1].repo, 0x2000)\\n display.print(\\\")\\\")\\n }\\n break\\n case \\\"query\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n \\n for (let repo of Object.entries(repoCache)) {\\n for (let pkg of Object.entries(repo[1].packages)) {\\n if (pkg[0].match(args[1])) {\\n display.buffer(\\\"[\\\")\\n display.buffer(repo[0], 0x2000)\\n display.buffer(\\\"]%t\\\")\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n if (pkgList[pkg[0]] && pkgList[pkg[0]].repo == repo[0]) {\\n display.buffer(\\\"%t(\\\")\\n const v = pkgList[pkg[0]].version\\n if (pkg[1].version[0] != v[0] || pkg[1].version[1] != v[1] || pkg[1].version[2] != v[2])\\n display.buffer(\\\"v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x5000)\\n display.buffer(\\\"installed\\\", 0x5000)\\n display.buffer(\\\")\\\")\\n }\\n display.write(\\\"%n\\\")\\n }\\n }\\n }\\n break\\n case \\\"prune\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n unwantedPkgs = Object.keys(pkgList)\\n\\n for (let pkg of world)\\n want(pkg)\\n\\n if (unwantedPkgs.length) {\\n display.print(\\\"The following packages will be removed:\\\", 0x6000)\\n for (let pkg of unwantedPkgs)\\n display.print(pkg, 0x2000)\\n\\n if (await ask(\\\"Proceed?\\\"))\\n for (let pkg of unwantedPkgs)\\n uninstall(pkg, false)\\n } else\\n display.print(\\\"No unwanted packages to remove\\\", 0x3000)\\n break\\n case \\\"batch\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const batchList = io.flines(fs.getNode(args[1])).filter(Boolean)\\n if (!batchList) {\\n display.print(\\\"Cannot find file\\\", 0x9000)\\n quit()\\n }\\n for (let pkg of batchList) {\\n const reponame = await fetchPkg(pkg)\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n }\\n}\\n\\nconst worldfile = io.open(\\\"/itty/world\\\", \\\"w\\\")\\nfor (let w of world)\\n worldfile.print(w)\\nworldfile.writeOut()\\n\\nquit()\\n\\n// fs functions but copies that don't care about protectedness\\nfunction makeNode(path, mode) {\\n path = fs.resolve(path)\\n\\n // mode is bad?\\n if (mode != \\\"d\\\" && mode != \\\"f\\\")\\n throw [2, \\\"Invalid mode\\\"]\\n\\n // skip if it exists\\n const node = fs.getNode(path)\\n if (node && node.mode === \\\"d\\\")\\n return\\n else if (node)\\n throw [1, \\\"Node already exists\\\"]\\n\\n const paths = fs.splitPath(path)\\n const parentNode = fs.getNode(paths[0])\\n const pathEnd = paths[1]\\n\\n if (!parentNode)\\n throw [10, \\\"Parent node does not exist\\\"]\\n\\n // make the node\\n parentNode.content[pathEnd] = {\\n mode: mode,\\n protected: parentNode.protected ? true : false,\\n content: mode === \\\"d\\\" ? {} : \\\"\\\",\\n }\\n fs.setPathAttributes(parentNode.content[pathEnd], parentNode, pathEnd)\\n}\\n\\nfunction makeDir(path) {\\n path = fs.resolve(path)\\n const pathArray = path.split(\\\"/\\\").filter(Boolean)\\n let currentPath = \\\"\\\"\\n for (let part of pathArray) {\\n currentPath += \\\"/\\\" + part\\n makeNode(currentPath, \\\"d\\\")\\n }\\n}\"}}"} \ No newline at end of file +{"protected":false,"mode":"f","metadata":{"name":"mrrp","author":"Luna Magdalena :3","version":[1,2],"dependencies":[],"paths":{"mrrp.js":"%B/mrrp.js","mrrp":"%D/mrrp","mrrp.packaging":"%D/mrrp.packaging"}},"content":"{\"mrrp.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"let yarnball\\nlet repoNode = fs.getNode(\\\"/itty/repos.json\\\")\\nlet repoList = JSON.parse(repoNode.content)\\nlet pkgList\\nlet updateList = []\\nlet world = io.flines(fs.getNode(\\\"/itty/world\\\")).filter(Boolean)\\nlet unwantedPkgs\\n\\n// we use some env vars, parse them\\nconst dirs = {\\n bin: fs.resolve(itty.env.dir_bin).slice(0, -1) || \\\"/itty/bin\\\",\\n docs: fs.resolve(itty.env.dir_docs).slice(0, -1) || \\\"/itty/docs\\\",\\n conf: fs.resolve(itty.env.dir_conf) + \\\"examples\\\" || \\\"/conf/examples\\\",\\n lib: fs.resolve(itty.env.dir_lib).slice(0, -1) || \\\"/itty/lib\\\"\\n}\\n\\n// cache repo indexes, so querying and updating is faster\\nlet repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\nif (!repoCache) {\\n fs.makeDir(\\\"/.tmp/mrrp/\\\")\\n fs.makeNode(\\\"/.tmp/mrrp/repocache\\\", \\\"f\\\")\\n await refreshCache()\\n} else {\\n repoCache = JSON.parse(repoCache.content) \\n}\\n\\n// refresh the repo cache!\\nasync function refreshCache() {\\n repoCache = fs.getNode(\\\"/.tmp/mrrp/repocache\\\")\\n const list = {}\\n for (let r of Object.entries(repoList)) {\\n let rj\\n try {\\n rj = await fetch(r[1].url + \\\"repo.json\\\")\\n rj = await rj.json()\\n } catch {\\n display.print(\\\"Cannot fetch repository info for \\\" + r[0], 0x9000)\\n continue\\n }\\n rj.url = r[1].url\\n list[r[0]] = rj\\n }\\n repoCache.content = JSON.stringify(list)\\n repoCache = list\\n}\\n\\n// confirmation as to whether to do things\\nasync function ask(message) {\\n const res = await io.read([[message + \\\" [y/N]: \\\"]])\\n\\n if (res.toLowerCase() !== \\\"y\\\" && res.toLowerCase() !== \\\"yes\\\") {\\n display.print(\\\"Aborting...\\\", 0x9000)\\n return false\\n }\\n\\n display.print(\\\"Proceeding...\\\", 0x3000)\\n return true\\n}\\n\\n// install a program\\nasync function install(yarnball, reponame, interactive = true, wanted) {\\n wanted = wanted || world.includes(yarnball.metadata.name)\\n\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n // substitute %B, %C and %D in paths with env vars\\n for (let path of Object.keys(yarnball.metadata.paths)) {\\n let p = yarnball.metadata.paths[path]\\n p = p.replaceAll(\\\"%B\\\", dirs.bin)\\n p = p.replaceAll(\\\"%D\\\", dirs.docs)\\n p = p.replaceAll(\\\"%C\\\", dirs.conf)\\n p = p.replaceAll(\\\"%L\\\", dirs.lib)\\n yarnball.metadata.paths[path] = p\\n }\\n\\n // ask the user!\\n if (interactive) {\\n const v = yarnball.metadata.version\\n display.print(\\\"Installing \\\" + yarnball.metadata.name + \\\" version \\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" from \\\" + reponame, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path in yarnball.metadata.paths) {\\n display.print(yarnball.metadata.paths[path], 0x2000)\\n }\\n if (yarnball.metadata.dependencies.length)\\n display.print(\\\"The following dependencies also need to be installed:\\\", 0x6000)\\n for (let d of yarnball.metadata.dependencies) {\\n if (!list[d])\\n display.print(d, 0x6000)\\n }\\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // uninstall if already installed\\n if (list[yarnball.metadata.name])\\n await uninstall(yarnball.metadata.name, false)\\n\\n // unspool the yarnball\\n fs.removeNode(\\\"/.tmp/mrrp/x\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/x\\\")\\n const node = fs.getNode(\\\"/.tmp/mrrp/x\\\")\\n let content\\n\\n try {\\n content = JSON.parse(yarnball.content)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(content)) {\\n if (node.content[file])\\n continue\\n const obj = content[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n\\n // move files accordingly\\n for (let path of Object.entries(yarnball.metadata.paths)) {\\n const paths = fs.splitPath(path[1])\\n makeDir(paths[0])\\n const parent = fs.getNode(paths[0])\\n parent.content[paths[1]] = fs.getNode(\\\"/.tmp/mrrp/x/\\\" + path[0], false)\\n fs.refreshPathAttributes(parent)\\n }\\n\\n // keep track!\\n list[yarnball.metadata.name] = {\\n name: yarnball.metadata.name,\\n repo: reponame,\\n version: yarnball.metadata.version,\\n paths: [],\\n dependencies: yarnball.metadata.dependencies\\n }\\n\\n for (let path of Object.entries(yarnball.metadata.paths))\\n list[yarnball.metadata.name].paths.push(path[1])\\n\\n listNode.content = JSON.stringify(list)\\n\\n if (wanted && !world.includes[yarnball.metadata.name])\\n world.push(yarnball.metadata.name)\\n\\n if (interactive)\\n display.print(\\\"Package \\\" + yarnball.metadata.name + \\\" installed\\\", 0x6000)\\n\\n // handle dependencies but after install because we only keep one package in the cache hehe this is awful i'm sorry\\n for (let d of yarnball.metadata.dependencies) {\\n if (list[d])\\n continue\\n const reponame = await fetchPkg(d)\\n if (!reponame) {\\n display.print(\\\"Could not install dependency \\\" + d, 0x9000)\\n continue\\n }\\n const yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, interactive)\\n }\\n}\\n\\nasync function uninstall(package, interactive = true) {\\n const listNode = fs.getNode(\\\"/itty/packages.json\\\")\\n let list = JSON.parse(listNode.content)\\n\\n const pkginfo = list[package]\\n if (!pkginfo) {\\n if (interactive)\\n display.print(\\\"Package is not installed\\\", 0x6000)\\n return\\n }\\n \\n // ask the user!\\n if (interactive) {\\n display.print(\\\"Removing \\\" + pkginfo.name, 0x5000)\\n display.print(\\\"Warning: this will affect the following path(s):\\\", 0x2000)\\n for (let path of pkginfo.paths)\\n display.print(path, 0x2000)\\n \\n if (!await ask(\\\"Proceed?\\\"))\\n return\\n }\\n\\n // actually remove\\n for (let path of pkginfo.paths) {\\n const paths = fs.splitPath(path)\\n delete fs.getNode(paths[0]).content[paths[1]]\\n }\\n\\n delete list[pkginfo.name]\\n list = JSON.stringify(list)\\n listNode.content = list\\n\\n const i = world.indexOf(pkginfo.name)\\n if (i > -1)\\n world.splice(i)\\n\\n if (interactive)\\n display.print(\\\"Package removed\\\", 0x6000)\\n}\\n\\nasync function fetchPkg(package, repo, reponame, interactive = true) {\\n let repojson\\n let rlist = []\\n if (repo) {\\n repojson = repo\\n \\n if (!repojson) {\\n display.print(\\\"Cannot find repository info for \\\" + reponame, 0x2000)\\n io.error([1, \\\"Cannot find repository info\\\"])\\n }\\n } else {\\n // look for package in repos\\n for (let r of Object.entries(repoCache)) {\\n let rj = r[1]\\n \\n if (rj.packages[package])\\n rlist.push([r[0], r[1], rj])\\n }\\n \\n switch (rlist.length) {\\n case 0:\\n display.print(\\\"Cannot find package \\\" + package, 0x9000)\\n return false\\n case 1:\\n repojson = rlist[0][2]\\n repo = rlist[0][1]\\n reponame = rlist[0][0]\\n break\\n case 2:\\n display.print(\\\"Package \\\" + package + \\\" is available in the following repositories:\\\", 0x5000)\\n for (let i=0; i < rlist.length; i++) {\\n const v = rlist[i][2].packages[package].version\\n display.buffer(\\\"[\\\" + (i + 1) + \\\"] \\\")\\n display.buffer(rlist[i][0], 0x2000)\\n display.print(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n }\\n const sel = await io.read([[\\\"Selection: \\\"]])\\n if (!sel)\\n return false\\n else {\\n repojson = rlist[sel-1][2]\\n repo = rlist[sel-1][1]\\n reponame = rlist[sel-1][0]\\n }\\n }\\n }\\n\\n // download\\n\\n let pkg\\n try {\\n pkg = await fetch(repojson.packages[package].url.replace(/^~/, repo.url))\\n pkg = await pkg.json()\\n } catch {\\n display.print(\\\"Cannot fetch package \\\" + package + \\\" from repository \\\" + reponame, 0x9000)\\n throw [2, \\\"Cannot fetch package\\\"]\\n }\\n\\n fs.removeNode(\\\"/.tmp/mrrp/dl\\\")\\n fs.makeDir(\\\"/.tmp/mrrp/dl\\\")\\n const dl = fs.getNode(\\\"/.tmp/mrrp/dl\\\")\\n dl.content.yarn = pkg\\n fs.refreshPathAttributes(dl)\\n\\n return reponame\\n}\\n\\nfunction want(package) {\\n const index = unwantedPkgs.indexOf(package)\\n if (index > -1)\\n unwantedPkgs.splice(index)\\n\\n if (pkgList[pkg])\\n for (let dep of pkgList[package].dependencies)\\n want(dep)\\n}\\n\\nswitch (args[0]) {\\n case \\\"yarn\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n yarnball = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n\\n await install(yarnball, \\\"local yarnball\\\", true, true)\\n break\\n case \\\"uninstall\\\":\\n case \\\"remove\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n await uninstall(args[1])\\n break\\n case \\\"list-repos\\\":\\n for (let repo of Object.entries(repoList)) {\\n display.write(repo[0] + \\\" \\\", 0x2000)\\n display.print(repo[1].url)\\n }\\n break\\n case \\\"remove-repo\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n delete repoList[args[1]]\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Removed repo \\\" + args[1], 0x6000)\\n await refreshCache()\\n break\\n case \\\"add-repo\\\":\\n if (args.length < 3) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n \\n args[2] = args[2].replace(/([^\\\\/])$/, \\\"$1/\\\")\\n\\n // fetch repo\\n try {\\n repo = await fetch(args[2] + \\\"repo.json\\\")\\n } catch {\\n display.print(\\\"Cannot fetch repository info\\\", 0x9000)\\n quit()\\n }\\n\\n if (repoList[args[1]]) {\\n display.print(\\\"Repository \\\" + args[1] + \\\" already exists.\\\", 0x2000)\\n if (!await ask(\\\"Overwrite?\\\"))\\n quit()\\n }\\n\\n repoList[args[1]] = {\\n url: args[2]\\n }\\n\\n repoNode.content = JSON.stringify(repoList)\\n display.print(\\\"Added repo \\\" + args[1] + \\\" with url \\\" + args[2], 0x6000)\\n await refreshCache()\\n break\\n case \\\"install\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const reponame = await fetchPkg(args[1])\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n break\\n case \\\"refresh-repos\\\":\\n await refreshCache()\\n display.print(\\\"Refreshed repository cache\\\", 0x6000)\\n break\\n case \\\"update\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n if (pkg[1].repo === \\\"local yarnball\\\" || !repoCache[pkg[1].repo])\\n continue\\n\\n const iv = pkg[1].version\\n const rv = repoCache[pkg[1].repo].packages[pkg[0]].version\\n\\n iv[1] = iv[1] || 0\\n iv[2] = iv[2] || 0\\n rv[1] = rv[1] || 0\\n rv[2] = rv[2] || 0\\n\\n if (rv[0] > iv[0] || rv[0] == iv[0] && rv[1] > iv[1] || rv[0] == iv[0] && rv[1] == iv[1] && rv[2] > iv[2])\\n updateList.push([pkg[0], pkg[1].repo, repoCache[pkg[1].repo]])\\n }\\n\\n if (!updateList.length) {\\n display.print(\\\"No packages need updating\\\", 0x3000)\\n quit()\\n }\\n\\n if (args[1] !== \\\"bg\\\") {\\n display.print(\\\"Packages to update:\\\", 0x6000)\\n for (let pkg of updateList)\\n display.print(pkg[0], 0x2000)\\n if (!await ask(\\\"Proceed?\\\"))\\n quit()\\n }\\n\\n for (let pkg of updateList) {\\n let f\\n try {\\n f = await fetchPkg(pkg[0], pkg[2], pkg[1], false)\\n } catch {\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Could not fetch \\\" + pkg[0] + \\\" from \\\" + pkg[1], 0x1000)\\n continue\\n }\\n if (f) {\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, pkg[1], false)\\n }\\n }\\n\\n if (args[1] !== \\\"bg\\\")\\n display.print(\\\"Updated packages\\\", 0x3000)\\n break\\n case \\\"list\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n\\n for (let pkg of Object.entries(pkgList)) {\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x4000)\\n display.buffer(\\\"(\\\")\\n display.buffer(pkg[1].repo, 0x2000)\\n display.print(\\\")\\\")\\n }\\n break\\n case \\\"query\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n \\n for (let repo of Object.entries(repoCache)) {\\n for (let pkg of Object.entries(repo[1].packages)) {\\n if (pkg[0].match(args[1])) {\\n display.buffer(\\\"[\\\")\\n display.buffer(repo[0], 0x2000)\\n display.buffer(\\\"]\\\\t\\\")\\n display.buffer(pkg[0], 0x6000)\\n const v = pkg[1].version\\n display.buffer(\\\" v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\"), 0x4000)\\n if (pkgList[pkg[0]] && pkgList[pkg[0]].repo == repo[0]) {\\n display.buffer(\\\"\\\\t(\\\")\\n const v = pkgList[pkg[0]].version\\n if (pkg[1].version[0] != v[0] || pkg[1].version[1] != v[1] || pkg[1].version[2] != v[2])\\n display.buffer(\\\"v\\\" + v[0] + (v[1] ? \\\".\\\" + v[1] : \\\".0\\\") + (v[2] ? \\\".\\\" + v[2] : \\\"\\\") + \\\" \\\", 0x5000)\\n display.buffer(\\\"installed\\\", 0x5000)\\n display.buffer(\\\")\\\")\\n }\\n display.write(\\\"\\\\n\\\")\\n }\\n }\\n }\\n break\\n case \\\"prune\\\":\\n try {\\n pkgList = JSON.parse(fs.getNode(\\\"/itty/packages.json\\\").content)\\n } catch {\\n display.print(\\\"Cannot parse package list\\\", 0x9000)\\n quit() \\n }\\n unwantedPkgs = Object.keys(pkgList)\\n\\n for (let pkg of world)\\n want(pkg)\\n\\n if (unwantedPkgs.length) {\\n display.print(\\\"The following packages will be removed:\\\", 0x6000)\\n for (let pkg of unwantedPkgs)\\n display.print(pkg, 0x2000)\\n\\n if (await ask(\\\"Proceed?\\\"))\\n for (let pkg of unwantedPkgs)\\n uninstall(pkg, false)\\n } else\\n display.print(\\\"No unwanted packages to remove\\\", 0x3000)\\n break\\n case \\\"batch\\\":\\n if (args.length < 2) {\\n display.print(\\\"Not enough arguments\\\", 0x1000)\\n quit()\\n }\\n const batchList = io.flines(fs.getNode(args[1])).filter(Boolean)\\n if (!batchList) {\\n display.print(\\\"Cannot find file\\\", 0x9000)\\n quit()\\n }\\n for (let pkg of batchList) {\\n const reponame = await fetchPkg(pkg)\\n if (!reponame)\\n quit()\\n yarnball = fs.getNode(\\\"/.tmp/mrrp/dl/yarn\\\")\\n await install(yarnball, reponame, true, true)\\n }\\n}\\n\\nconst worldfile = io.open(\\\"/itty/world\\\", \\\"w\\\")\\nfor (let w of world)\\n worldfile.print(w)\\nworldfile.writeOut()\\n\\nquit()\\n\\n// fs functions but copies that don't care about protectedness\\nfunction makeNode(path, mode) {\\n path = fs.resolve(path)\\n\\n // mode is bad?\\n if (mode != \\\"d\\\" && mode != \\\"f\\\")\\n throw [2, \\\"Invalid mode\\\"]\\n\\n // skip if it exists\\n const node = fs.getNode(path)\\n if (node && node.mode === \\\"d\\\")\\n return\\n else if (node)\\n throw [1, \\\"Node already exists\\\"]\\n\\n const paths = fs.splitPath(path)\\n const parentNode = fs.getNode(paths[0])\\n const pathEnd = paths[1]\\n\\n if (!parentNode)\\n throw [10, \\\"Parent node does not exist\\\"]\\n\\n // make the node\\n parentNode.content[pathEnd] = {\\n mode: mode,\\n protected: parentNode.protected ? true : false,\\n content: mode === \\\"d\\\" ? {} : \\\"\\\",\\n }\\n fs.setPathAttributes(parentNode.content[pathEnd], parentNode, pathEnd)\\n}\\n\\nfunction makeDir(path) {\\n path = fs.resolve(path)\\n const pathArray = path.split(\\\"/\\\").filter(Boolean)\\n let currentPath = \\\"\\\"\\n for (let part of pathArray) {\\n currentPath += \\\"/\\\" + part\\n makeNode(currentPath, \\\"d\\\")\\n }\\n}\\n\\nfunction onQuit() {\\n fs.save()\\n}\"},\"mrrp\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]MRRP - Manager for Retrieving and Removing Packages\\u0011[s7000]\\n\\n\\t\\u0011[s4000]mrrp.packaging\\u0011[s7000]\\n\\nMRRP is a simple package manager for itty. it features a world file, and allows installing packages from yarnballs and remote repositories, as well as updating these packages\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tmrrp \\u0011[s6040]subcommand\\n\\n\\u0011[s4020]Subcommands:\\n\\t\\u0011[s6010]yarn \\u0011[s2040]path-to-yarnball\\u0011[s7000]\\n\\t\\tattempt to install a package from a yarnball\\n\\t\\u0011[s6010]install \\u0011[s2040]package\\u0011[s7000]\\n\\t\\tattempt to install a package from the remote repositories\\n\\t\\u0011[s6010]remove \\u0011[s2040]package\\u0011[s7000]\\n\\t\\tremove the package from the system\\n\\t\\u0011[s6010]update\\u0011[s7000]\\n\\t\\tsearch repositories for package updates and install them\\n\\t\\u0011[s6010]list\\u0011[s7000]\\n\\t\\tshow a list of all installed packages\\n\\t\\u0011[s6010]query \\u0011[s2040]package\\u0011[s7000]\\n\\t\\tsearch for a string in the remote repositories and show a list of matching packages\\n\\t\\u0011[s6010]prune\\u0011[s7000]\\n\\t\\tremove unwanted packages (those not in \\u0011[sA000]world\\u0011[s7000] and unneeded dependencies)\\n\\t\\u0011[s6010]batch \\u0011[s2040]path-to-file\\u0011[s7000]\\n\\t\\tinstall all packages listed in the given file, which must only contain exact package names separated by newlines\\n\\t\\u0011[s6010]list-repos\\u0011[s7000]\\n\\t\\tlist all repositories that \\u0011[sA000]mrrp\\u0011[s7000] is configured to use\\n\\t\\u0011[s6010]add-repo \\u0011[s2040]repo\\u0011[s0000] \\u0011[s2040]url\\u0011[s7000]\\n\\t\\tadd a repository under the given name, with the provided url\\n\\t\\u0011[s6010]remove-repo \\u0011[s2040]repo\\u0011[s7000]\\n\\t\\tremove a repository from the list\\n\\t\\u0011[s6010]refresh-repos\\u0011[s7000]\\n\\t\\tupdate cached repository data\\n\\n\\u0011[s5040]Environment\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]dir_bin\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install programs to\\n\\u0011[sC000]- \\u0011[s6020]dir_lib\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install libraries to\\n\\u0011[sC000]- \\u0011[s6020]dir_conf\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install example config files to. example config files go in the \\u0011[sA000]/example\\u0011[s7000] subdirectory of this directory\\n\\u0011[sC000]- \\u0011[s6020]dir_docs\\u0011[s7000] (\\u0011[sE000]string\\u0011[s7000]): the directory to install documentation to\\n\\n\\u0011[s5040]Files\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s2040]/itty/world\\u0011[s7000]: a newline separated list of packages wanted by the user. this is used to distinguish wanted and unwanted dependencies\\n\\u0011[sC000]- \\u0011[s2040]/itty/packages.json\\u0011[s7000]: JSON containing information about installed packages, such as their files, dependencies, version and repo\\n\\u0011[sC000]- \\u0011[s2040]/itty/repos.json\\u0011[s7000]: JSON containing a list of remote repositories and their URLs\"},\"mrrp.packaging\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]Packaging for MRRP\\u0011[s7000]\\n\\n \\u0011[s4000] mrrp\\n\\n\\u0011[s5040]Creating a package yarnball\\u0011[s7000]\\nif what you are packaging is a \\u0011[sA000]program\\u0011[s7000], then the file needs to be executable. check \\u0011[sA000]exec.md\\u0011[s7000] in the itty docs for instructions on how to do that\\n\\nsecond, itty packages are \\u0011[sA000]yarnfiles\\u0011[s7000], you can make a yarnfile from itty with the \\u0011[sA000]yarn\\u0011[s7000] utility, or from a non-itty device with the \\u0011[sA000]thread\\u0011[s7000] utility provided in the \\u0011[sA000]utils\\u0011[s7000] directory of the itty repository\\n\\nthe files inside your yarnball should be the files you are going to package, and the yarnball's metadata should contain the following fields:\\n- \\u0011[s6000]name\\u0011[s7000]: this is the package name, the user will use this name when looking up the package or uninstalling it\\n- \\u0011[s6000]version\\u0011[s7000]: this an array with 3 integer values, the \\u0011[sA000]major version\\u0011[s7000], \\u0011[sA000]minor version\\u0011[s7000] and \\u0011[sA000]patch version\\u0011[s7000]. the package manager will use this to know whether your package has received an update\\n- \\u0011[s6000]dependencies\\u0011[s7000]: this is an array, which may be empty. each value is a string containing a program name, which the package manager will look up and attempt to install\\n- \\u0011[s6000]paths\\u0011[s7000]: this is an object, where every key is the relative path to a file or node inside the yarnball and its value is the destination path it should have. a file can have multiple destinations. you can use \\u0011[sA000]%B\\u0011[s7000] as a shortcut for the binaries directory, \\u0011[sA000]%C\\u0011[s7000] as a shortcut for the config directory, \\u0011[sA000]%D\\u0011[s7000] for the documentation directory, and \\u0011[sA000]%L\\u0011[s7000] for the libraries directory. additionally, libraries go in a subdirectory in the libraries directory according to language. for example, javascript libraries go in \\u0011[sA000]%L/js/\\u0011[s7000]\\n- \\u0011[s6000]author\\u0011[s7000], \\u0011[s6000]license\\u0011[s7000], \\u0011[s6000]source\\u0011[s7000] and \\u0011[s6000]contact\\u0011[s7000]: these are information fields for the package's author, license, link to source code, and a way to contact the author if needed\\n\\na package yarnball can be installed with the \\u0011[sA000]mrrp\\u0011[s7000] package manager by using \\u0011[sE800] mrrp yarn \\u0011[s7000] and a path to the yarnball. you can also add your package to a repo\\n\\n\\u0011[s5040]Setting up a repository\\u0011[s7000]\\na repository is a collection of files hosted in servers whose CORS policies allow any browser to fetch from them. repositories are added by their URL, and a file \\u0011[sA000]URL/repo.json\\u0011[s7000] must be available to provide repo info\\n\\nthe \\u0011[sA000]repo.json\\u0011[s7000] file is JSON with a \\u0011[sA000]name\\u0011[s7000] field containing the repository name, and a \\u0011[sA000]packages\\u0011[s7000] field\\n\\nthe \\u0011[sA000]packages\\u0011[s7000] field is an object where every key is the \\u0011[sA000]name\\u0011[s7000] of a package. this is the same name as reported in the yarnball's metadata\\nthe value will be another object with the following fields:\\n\\u0011[sC000]- \\u0011[s6000]url\\u0011[s7000]: the url to the package yarnball, using \\u0011[sA000]~\\u0011[s7000] as a shortcut for the repo's URL\\n\\u0011[sC000]- \\u0011[s6000]version\\u0011[s7000]: an array with 3 number values which must be the same as the yarnball's metadata version value. a mismatch in the version or name between the repo and the yarnball will cause problems while updating\"}}"} \ No newline at end of file diff --git a/mv.yarn b/mv.yarn deleted file mode 100644 index eadbccd..0000000 --- a/mv.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"mv","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"mv.js":"%B/mv.js"}},"content":"{\"mv.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[0] && !args[1]) {\\n display.print(\\\"Not enough arguments\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.moveNode(args[0], args[1])\\n} catch (e) {\\n display.print(e[1] || \\\"Error moving node\\\", 0x9000)\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/plist.yarn b/plist.yarn deleted file mode 100644 index 1dea110..0000000 --- a/plist.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name": "plist", "author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"plist.js":"%B/plist.js"}},"content":"{\"plist.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"// iterate over itty.program\\n\\nconst programList = exec.listPrograms()\\nfor (let p of programList) {\\n if (!p)\\n continue\\n display.buffer(\\\"[\\\", 0xf000)\\n display.buffer(p.id, 0x6000)\\n display.buffer(\\\"] (\\\", 0xf000)\\n display.buffer(p.uid, 0x4000)\\n display.buffer(\\\")%t\\\", 0xf000)\\n display.buffer(p.name, 0xe000)\\n if (p.background) {\\n display.buffer(\\\"%t(\\\", 0xf000)\\n display.buffer(\\\"background\\\", 0x5000)\\n display.buffer(\\\")\\\", 0xf000)\\n }\\n display.write(\\\"%n\\\")\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/programs.yarn b/programs.yarn deleted file mode 100644 index 9c4642a..0000000 --- a/programs.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"programs","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"programs.js":"%B/programs.js"}},"content":"{\"programs.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"for (let path of itty.env.path) {\\n path = fs.listDir(path)\\n for (let p in path) {\\n p = path[p]\\n if (p.ext === \\\"js\\\") {\\n const name = p.name.slice(0, -3)\\n if (itty.cursorX + name.length >= itty.width) {\\n itty.cursorX = 0\\n itty.cursorY++\\n }\\n while (itty.cursorY >= itty.height)\\n display.lift()\\n display.buffer(name + \\\" \\\")\\n }\\n }\\n}\\n \\ndisplay.render()\\nquit()\"}}"} \ No newline at end of file diff --git a/repo.json b/repo.json index 89fc09e..c270672 100644 --- a/repo.json +++ b/repo.json @@ -1,28 +1,8 @@ { "name": "itty", "packages": { - "cat": {"url": "~cat.yarn", "version": [1, 1]}, - "clear": {"url": "~clear.yarn", "version": [1]}, - "cp": {"url": "~cp.yarn", "version": [1]}, - "echo": {"url": "~echo.yarn", "version": [1]}, - "env": {"url": "~env.yarn", "version": [1]}, - "info": {"url": "~info.yarn", "version": [1]}, - "loader": {"url": "~loader.yarn", "version": [1]}, - "ls": {"url": "~ls.yarn", "version": [1]}, - "miss": {"url": "~miss.yarn", "version": [1]}, - "mkdir": {"url": "~mkdir.yarn", "version": [1]}, - "mrrp": {"url": "~mrrp.yarn", "version": [1, 1]}, - "mv": {"url": "~mv.yarn", "version": [1]}, - "programs": {"url": "~programs.yarn", "version": [1]}, - "rm": {"url": "~rm.yarn", "version": [1]}, - "shutdown": {"url": "~shutdown.yarn", "version": [1]}, - "slog": {"url": "~slog.yarn", "version": [1]}, - "touch": {"url": "~touch.yarn", "version": [1]}, - "yarn": {"url": "~yarn.yarn", "version": [1]}, - "plist": {"url": "~plist.yarn", "version": [1]}, - "kill": {"url": "~kill.yarn", "version": [1]}, - "bg": {"url": "~bg.yarn", "version": [1]}, - "scroll": {"url": "~scroll.yarn", "version": [1]}, - "meta": {"url": "~meta.yarn", "version": [1]} + "lazybox": {"url": "~lazybox.yarn", "version": [1]}, + "miss": {"url": "~miss.yarn", "version": [1, 1]}, + "mrrp": {"url": "~mrrp.yarn", "version": [1, 2]} } } diff --git a/rm.yarn b/rm.yarn deleted file mode 100644 index 710fb35..0000000 --- a/rm.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"rm","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"rm.js":"%B/rm.js"}},"content":"{\"rm.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.removeNode(args[0])\\n} catch (e) {\\n display.print(e[1] || \\\"Error removing node\\\", 0x9000)\\n}\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/scroll.yarn b/scroll.yarn deleted file mode 100644 index 7ad6191..0000000 --- a/scroll.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"scroll","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"scroll.js":"%B/scroll.js"}},"content":"{\"scroll.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!pipe)\\n quit()\\n\\nprogram.enterFullscreen()\\n\\nconst lines = pipe.split(\\\"\\\\n\\\")\\n\\nfunction renderLines() {\\n display.clear()\\n for (let i = start; i < lines.length; i++) {\\n if (lines[i].length / itty.width > itty.height - itty.cursorY) {\\n for (let x = 0; x < Math.floor(lines[i].length / itty.width); x++)\\n display.lift()\\n break\\n }\\n display.print(lines[i] || \\\" \\\", undefined, false)\\n }\\n}\\n\\nlet start = 0\\nrenderLines()\\n\\nfunction onInput(k) {\\n switch (k) {\\n case \\\"%^\\\":\\n start = Math.max(start - 1, 0)\\n renderLines()\\n break\\n case \\\"%v\\\":\\n start = Math.min(start + 1, lines.length - 1)\\n renderLines()\\n break\\n case \\\"%e\\\":\\n case \\\"q\\\":\\n quit()\\n }\\n}\\n\\nfunction onQuit() {\\n display.clear()\\n}\"}}"} \ No newline at end of file diff --git a/shutdown.yarn b/shutdown.yarn deleted file mode 100644 index 7ecd0a2..0000000 --- a/shutdown.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"shutdown","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"shutdown.js":"%B/shutdown.js"}},"content":"{\"shutdown.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"exec.shutdown(); quit()\"}}"} \ No newline at end of file diff --git a/slog.yarn b/slog.yarn deleted file mode 100644 index fbc6a78..0000000 --- a/slog.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"slog","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"slog.js":"%B/slog.js"}},"content":"{\"slog.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"// ensure log file exists\\n\\nlet logfile\\n\\ntry {\\n logfile = io.open(\\\"/itty/slog\\\", \\\"a\\\")\\n} catch {}\\n\\nif (!logfile) {\\n fs.getNode(\\\"/itty/\\\").content[\\\"slog\\\"] = {\\n protected: false,\\n mode: \\\"f\\\",\\n content: \\\"\\\",\\n parent: fs.getNode(\\\"/itty/\\\"),\\n name: \\\"slog\\\",\\n js: \\\"\\\",\\n metadata: {}\\n }\\n logfile = io.open(\\\"/itty/slog\\\", \\\"a\\\")\\n}\\n\\nconst message = JSON.parse(pipe)\\n\\nif (message[1][0] !== 0)\\n console.log(\\\"ERROR\\\", message[1])\\n\\nlogfile.print(`(${message[0].id}/${message[0].uid}) ${message[0].name}: [${message[1][0] || \\\"INFO\\\"}] ${message[1][1]}`)\\nlogfile.writeOut()\\n\\nquit()\"}}"} \ No newline at end of file diff --git a/touch.yarn b/touch.yarn deleted file mode 100644 index ecce0b2..0000000 --- a/touch.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"touch","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"touch.js":"%B/touch.js"}},"content":"{\"touch.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"if (!args[0]) {\\n display.print(\\\"No path provided\\\", 0xf000)\\n quit()\\n}\\n\\ntry {\\n fs.makeNode(args[0], \\\"f\\\")\\n} catch (e) {\\n switch (e[0]) {\\n case 1:\\n display.print(\\\"File already exists\\\", 0xf000)\\n break\\n case 3:\\n display.print(\\\"Parent directory is protected\\\", 0x9000)\\n break\\n case 10:\\n display.print(\\\"Parent directory does not exist\\\", 0x9000)\\n break\\n default:\\n display.print(\\\"Error creating file\\\", 0x9000)\\n }\\n}\\nquit()\"}}"} \ No newline at end of file diff --git a/yarn.yarn b/yarn.yarn deleted file mode 100644 index 006b2d8..0000000 --- a/yarn.yarn +++ /dev/null @@ -1 +0,0 @@ -{"protected":false,"mode":"f","metadata":{"name":"yarn","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"yarn.js":"%B/yarn.js"}},"content":"{\"yarn.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"function spool(nodes) {\\n const yarnball = {}\\n\\n for (let node of nodes) {\\n let n\\n try {\\n n = fs.getNode(node)\\n } catch {\\n continue\\n }\\n\\n yarnball[n.name] = n\\n }\\n\\n return JSON.stringify(yarnball, (key, value) => {if (key === \\\"parent\\\" || key === \\\"name\\\" || key === \\\"ext\\\") {return undefined}; return value})\\n}\\n\\nfunction unspool(yarnball, path) {\\n fs.makeDir(path)\\n const node = fs.getNode(path)\\n if (node.protected)\\n io.error([3, \\\"Destination is protected\\\"])\\n\\n try {\\n yarnball = JSON.parse(yarnball)\\n } catch {\\n io.error([5, \\\"Cannot parse yarnball\\\"])\\n }\\n\\n for (let file of Object.keys(yarnball)) {\\n if (node.content[file])\\n continue\\n const obj = yarnball[file]\\n node.content[file] = obj\\n }\\n fs.refreshPathAttributes(node)\\n}\\n\\nlet yarnfile\\nlet meta\\nlet jsonfile\\n\\nswitch (args[0]) {\\n case \\\"spool\\\":\\n yarnfile = io.open(args[1], \\\"w\\\")\\n yarnfile.write(spool(args.slice(2)))\\n yarnfile.writeOut()\\n break\\n case \\\"unspool\\\":\\n yarnfile = io.open(args[1], \\\"r\\\")\\n unspool(yarnfile.read(), args[2])\\n break\\n case \\\"get-metadata\\\":\\n yarnfile = io.open(args[1], \\\"r\\\")\\n if (args[2])\\n display.print(JSON.stringify(fs.getMetadata(yarnfile, args[2])))\\n else\\n for (let m of Object.keys(yarnfile.metadata))\\n display.print(m + \\\": \\\" + JSON.stringify(fs.getMetadata(yarnfile, m)))\\n break\\n case \\\"set-metadata\\\":\\n yarnfile = fs.getNode(args[1])\\n meta = await io.read()\\n fs.setMetadata(yarnfile, args[2], meta)\\n break\\n case \\\"metadata-from-json\\\":\\n try {\\n yarnfile = fs.getNode(args[1])\\n } catch {\\n io.error([1, \\\"Cannot find yarnball\\\"])\\n }\\n if (yarnfile.protected)\\n io.error([2, \\\"Yarnball is protected\\\"])\\n\\n try {\\n jsonfile = fs.getNode(args[2])\\n } catch {\\n io.error([1, \\\"Cannot find JSON file\\\"])\\n }\\n\\n try {\\n meta = JSON.parse(jsonfile.content)\\n } catch {\\n io.error([6, \\\"Cannot parse JSON\\\"])\\n }\\n\\n yarnfile.metadata = meta\\n break\\n}\\nquit()\"}}"} \ No newline at end of file