itty-repo/smol.yarn
Luna Magdalena :3 4cbc81688a add smol v1
2026-03-11 13:55:59 -03:00

1 line
No EOL
12 KiB
Text

{"protected":false,"mode":"f","metadata":{"name":"smol","author":"Luna Magdalena :3","version":[1],"dependencies":[],"paths":{"smol.js":"%B/smol.js","smol":"%D/smol"}},"content":"{\"smol.js\":{\"protected\":true,\"metadata\":{\"runner\":[]},\"mode\":\"f\",\"content\":\"let file\\n\\n// attempt to open file\\ntry {\\n\\tfile = io.open(args[0], \\\"a\\\")\\n} catch {\\n\\ttry {\\n\\t\\tfs.makeNode(args[0], \\\"f\\\")\\n\\t} catch {\\n\\t\\tdisplay.print(\\\"Cannot access destination file\\\", 0x9000)\\n\\t\\tquit()\\n\\t}\\n\\tfile = io.open(args[0], \\\"a\\\")\\n}\\n\\n// go fullscreen\\nprogram.enterFullscreen()\\ndisplay.storeFrame()\\nstartcursor = [itty.cursorX, itty.cursorY]\\n\\n// vars\\nlet text = file.lines()\\nlet pan = {\\n\\tx: 0,\\n\\ty: 0\\n}\\nlet pos = {\\n\\tx: 0,\\n\\ty: 0\\n}\\nlet basestyle = itty.baseStyle.toString(16).padStart(4, \\\"0\\\")\\nlet changed = false\\nlet ruler = true\\n\\n// render lines\\nfunction render() {\\n\\t// clear screen\\n\\tdisplay.clear(false)\\n\\n\\t// count digits in line count\\n\\trulerwidth = (text.length).toString().length + 1\\n\\n\\t// write all the lines\\n\\tfor (let i = pan.y; i < text.length && i < pan.y + itty.height - 1; i++) {\\n\\t\\tif (ruler) { // draw ruler if enabled\\n\\t\\t\\tdisplay.buffer(i + 1, 0x6800)\\n\\t\\t\\tdisplay.setStyle(0x6800, rulerwidth - itty.cursorX)\\n\\t\\t\\titty.cursorX = rulerwidth\\n\\t\\t}\\n\\t\\tdisplay.buffer(text[i]\\n\\t\\t\\t.replace(/\\\\t/g, \\\" \\\".repeat(itty.env.tab_length))\\n\\t\\t\\t.replace(/\\\\x11/g, `\\\\x11[sA050]1\\\\x11[s${basestyle}]`) // replace any escape sequences with non-escape sequences with some extra styling\\n\\t\\t\\t.replace(/\\\\x12/g, `\\\\x11[sA050]2\\\\x11[s${basestyle}]`)\\n\\t\\t\\t.replace(/\\\\x13/g, `\\\\x11[sA050]3\\\\x11[s${basestyle}]`)\\n\\t\\t\\t.replace(/\\\\x14/g, `\\\\x11[sA050]4\\\\x11[s${basestyle}]`)\\n\\t\\t\\t.replace(/(\\\\x11\\\\[s.{4}\\\\][1-4]\\\\x11\\\\[s.{4}\\\\])([^\\\\[]|\\\\[[^\\\\]]*\\\\])/g, `$1\\\\x11[s2040]$2\\\\x11[s${basestyle}]`)\\n\\t\\t\\t.substring(pan.x), itty.baseStyle)\\n\\t\\titty.cursorX = 0\\n\\t\\titty.cursorY++\\n\\t}\\n\\n\\t// add empty ruler lines\\n\\tif (ruler)\\n\\t\\tfor (let i = itty.cursorY; i < itty.height - 1; i++) {\\n\\t\\t\\tdisplay.setStyle(0x6800, rulerwidth)\\n\\t\\t\\titty.cursorX = 0\\n\\t\\t\\titty.cursorY++\\n\\t\\t}\\n\\n\\t// write status line in the bottom\\n\\titty.cursorY = itty.height - 1\\n\\tdisplay.setStyle(0xc800, itty.width - 1)\\n\\titty.cursorX = 0\\n\\tdisplay.buffer(fs.resolve(args[0]).replace(/\\\\/$/, \\\"\\\"), 0xc800)\\n\\tif (changed)\\n\\t\\tdisplay.buffer(\\\" (Unsaved)\\\", 0x2800)\\n\\tlet position = `R: ${(pos.y + 1).toString()}, C: ${(pos.x + 1).toString()} `\\n\\titty.cursorX = itty.width - position.length\\n\\tdisplay.buffer(position, 0xc800)\\n\\n\\t// place cursor, adjusting offset because of tabs\\n\\tlet cursorx = 0 - pan.x + (ruler ? rulerwidth : 0) + (itty.env.cursor[4] || 0) + text[pos.y].substring(0, pos.x).replace(/\\\\t/g, \\\" \\\".repeat(itty.env.tab_length)).length\\n\\tlet cursory = pos.y - pan.y\\n\\tif (0 <= cursorx && cursorx < itty.width && 0 <= cursory && cursory <= itty.height) {\\n\\t\\titty.cursorX = cursorx\\n\\t\\titty.cursorY = cursory\\n\\t\\tdisplay.setStyle(display.getStyle() + 0x0080)\\n\\t}\\n\\n\\tdisplay.render()\\n}\\n\\nrender()\\n\\n// make sure cursor is visible\\nfunction fixPan() {\\n\\tpan.y = Math.max(pos.y - itty.height + 2, Math.min(pan.y, pos.y))\\n\\tpan.x = Math.max(pos.x - itty.width + 2 + (ruler ? rulerwidth : 0), Math.min(pan.x, pos.x))\\n}\\n\\nasync function onInput(k) {\\n\\tif (itty.mod.ctrl) {\\n\\t\\tswitch (k) {\\n\\t\\t\\tcase \\\"q\\\":\\n\\t\\t\\t\\tquit()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"r\\\":\\n\\t\\t\\t\\truler = ruler ? false : true\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"s\\\":\\n\\t\\t\\t\\tfile.content = text.join(\\\"\\\\n\\\")\\n\\t\\t\\t\\ttry {\\n\\t\\t\\t\\t\\tfile.writeOut()\\n\\t\\t\\t\\t\\tchanged = false\\n\\t\\t\\t\\t\\trender()\\n\\t\\t\\t\\t} catch {\\n\\t\\t\\t\\t\\titty.cursorX = 0\\n\\t\\t\\t\\t\\titty.cursorY = itty.height - 1\\n\\t\\t\\t\\t\\tdisplay.buffer(\\\"Failed to save file\\\", 0x9800)\\n\\t\\t\\t\\t\\tdisplay.setStyle(0x9800, itty.width - 1)\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"1\\\":\\n\\t\\t\\tcase \\\"2\\\":\\n\\t\\t\\tcase \\\"3\\\":\\n\\t\\t\\tcase \\\"4\\\":\\n\\t\\t\\t\\tescapes = {\\n\\t\\t\\t\\t\\t\\\"1\\\": \\\"\\\\x11\\\",\\n\\t\\t\\t\\t\\t\\\"2\\\": \\\"\\\\x12\\\",\\n\\t\\t\\t\\t\\t\\\"3\\\": \\\"\\\\x13\\\",\\n\\t\\t\\t\\t\\t\\\"4\\\": \\\"\\\\x14\\\"\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tchanged = true\\n\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x) + escapes[k] + text[pos.y].substring(pos.x)\\n\\t\\t\\t\\tpos.x++\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"v\\\":\\n\\t\\t\\t\\tclipboard = await io.readClipboard(100000)\\n\\t\\t\\t\\tif (!clipboard)\\n\\t\\t\\t\\t\\tbreak\\n\\t\\t\\t\\tclipboard = clipboard.split(\\\"\\\\n\\\")\\n\\t\\t\\t\\t// store future cursor position\\n\\t\\t\\t\\tx = clipboard.length > 1 ? clipboard[clipboard.length - 1].length : pos.x + clipboard[0].length\\n\\t\\t\\t\\ty = pos.y + clipboard.length - 1\\n\\t\\t\\t\\t// add anything after cursor to the last line of clipboard content\\n\\t\\t\\t\\tclipboard[clipboard.length - 1] += text[pos.y].substring(pos.x)\\n\\t\\t\\t\\t// replace current line of text with content before cursor and first line of clipboard. remove from clipboard as well\\n\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x) + clipboard[0]\\n\\t\\t\\t\\tclipboard.splice(0, 1)\\n\\t\\t\\t\\t// concatenate the arrays\\n\\t\\t\\t\\ttext = text.slice(0, pos.y + 1).concat(clipboard).concat(text.slice(pos.y + 1))\\n\\t\\t\\t\\t// position cursor\\n\\t\\t\\t\\tpos.x = x\\n\\t\\t\\t\\tpos.y = y\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%<\\\":\\n\\t\\t\\t\\tpos.x = text[pos.y].substring(0, pos.x).replace(/(.*)(?:^|\\\\s)[^\\\\s]+(\\\\s?)$/, \\\"$1\\\").length\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%>\\\":\\n\\t\\t\\t\\tpos.x += text[pos.y].substring(pos.x).replace(/(^\\\\s?[^\\\\s]+).*/, \\\"$1\\\").length\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%b\\\":\\n\\t\\t\\t\\ts = text[pos.y].substring(0, pos.x).replace(/(.*)(?:^|\\\\s)[^\\\\s]+(\\\\s?)$/, \\\"$1\\\")\\n\\t\\t\\t\\ttext[pos.y] = s + text[pos.y].substring(pos.x)\\n\\t\\t\\t\\tpos.x = s.length\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t}\\n\\t} else {\\n\\t\\tswitch (k) {\\n\\t\\t\\tcase \\\"%U\\\":\\n\\t\\t\\t\\tdisplay.lift()\\n\\t\\t\\t\\tpan.y = Math.max(pan.y - 1, 0)\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%D\\\":\\n\\t\\t\\t\\tdisplay.lower()\\n\\t\\t\\t\\tpan.y = Math.min(pan.y + 1, text.length - 1)\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%^\\\":\\n\\t\\t\\t\\tpos.y = Math.max(pos.y - 1, 0)\\n\\t\\t\\t\\tpos.x = Math.min(pos.x, text[pos.y].length) // change x pos in case prev line is shorter\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%v\\\":\\n\\t\\t\\t\\tpos.y = Math.min(pos.y + 1, text.length - 1)\\n\\t\\t\\t\\tpos.x = Math.min(pos.x, text[pos.y].length) // change x pos in case next line is shorter\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%<\\\":\\n\\t\\t\\t\\tif (pos.x != 0) {\\n\\t\\t\\t\\t\\tpos.x--\\n\\t\\t\\t\\t} else if (pos.y > 0) {\\n\\t\\t\\t\\t\\tpos.y--\\n\\t\\t\\t\\t\\tpos.x = text[pos.y].length\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%>\\\":\\n\\t\\t\\t\\tif (pos.x < text[pos.y].length) {\\n\\t\\t\\t\\t\\tpos.x++\\n\\t\\t\\t\\t} else if (pos.y < text.length - 1) {\\n\\t\\t\\t\\t\\tpos.y++\\n\\t\\t\\t\\t\\tpos.x = 0\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%n\\\":\\n\\t\\t\\t\\tchanged = true\\n\\t\\t\\t\\ttext.splice(pos.y + 1, 0, text[pos.y].substring(pos.x))\\n\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x)\\n\\t\\t\\t\\tpos.y = Math.min(pos.y + 1, text.length - 1)\\n\\t\\t\\t\\tpos.x = 0\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%b\\\":\\n\\t\\t\\t\\tchanged = true\\n\\t\\t\\t\\tif (pos.x > 0) {\\n\\t\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x - 1) + text[pos.y].substring(pos.x)\\n\\t\\t\\t\\t\\tpos.x--\\n\\t\\t\\t\\t} else if (pos.y > 0) {\\n\\t\\t\\t\\t\\tpos.x = text[pos.y - 1].length\\n\\t\\t\\t\\t\\ttext[pos.y - 1] = text[pos.y - 1] + text[pos.y]\\n\\t\\t\\t\\t\\ttext.splice(pos.y, 1)\\n\\t\\t\\t\\t\\tpos.y--\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%d\\\":\\n\\t\\t\\t\\tchanged = true\\n\\t\\t\\t\\tif (pos.x < text[pos.y].length) {\\n\\t\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x) + text[pos.y].substring(pos.x + 1)\\n\\t\\t\\t\\t} else if (pos.y < text.length - 1) {\\n\\t\\t\\t\\t\\ttext[pos.y] = text[pos.y] + text[pos.y + 1]\\n\\t\\t\\t\\t\\ttext.splice(pos.y + 1, 1)\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%H\\\":\\n\\t\\t\\t\\tpos.x = 0\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%E\\\":\\n\\t\\t\\t\\tpos.x = text[pos.y].length\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\t\\tbreak\\n\\t\\t\\tcase \\\"%t\\\":\\n\\t\\t\\t\\tchanged = true\\n\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x) + \\\"\\\\t\\\" + text[pos.y].substring(pos.x)\\n\\t\\t\\t\\tpos.x++\\n\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\trender()\\n\\t\\t\\tdefault:\\n\\t\\t\\t\\tif (k.length == 1) {\\n\\t\\t\\t\\t\\tchanged = true\\n\\t\\t\\t\\t\\ttext[pos.y] = text[pos.y].substring(0, pos.x) + k + text[pos.y].substring(pos.x)\\n\\t\\t\\t\\t\\tpos.x++\\n\\t\\t\\t\\t\\tfixPan()\\n\\t\\t\\t\\t\\trender()\\n\\t\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n}\\n\\nfunction onQuit() {\\n\\titty.cursorX = startcursor[0]\\n\\titty.cursorY = startcursor[1]\\n\\tdisplay.restoreFrame()\\n}\\n\\nfunction onResize() {\\n\\trender()\\n}\"},\"smol\":{\"protected\":false,\"metadata\":{},\"mode\":\"f\",\"content\":\"\\u0011[sD050]Smol - Simple text editor\\u0011[s7000]\\n\\na simple text editor with basic features and support for working with escape sequences\\n\\n\\u0011[s5040]Usage\\u0011[s7000]\\n\\tsmol \\u0011[s6040]file-path\\u0011[s7000]\\n\\n\\u0011[s5040]Binds\\u0011[s7000]\\n\\u0011[sC000]- \\u0011[s6020]arrow keys\\u0011[s7000]: moves the cursor\\n\\u0011[sC000]- \\u0011[s6020]ctrl+left and ctrl+right\\u0011[s7000]: moves by a whole word\\n\\u0011[sC000]- \\u0011[s6020]page up and page down\\u0011[s7000]: scrolls the view without moving the cursor\\n\\u0011[sC000]- \\u0011[s6020]home and end\\u0011[s7000]: moves to the start / end of the line\\n\\u0011[sC000]- \\u0011[s6020]backspace\\u0011[s7000]: deletes previous character\\n\\u0011[sC000]- \\u0011[s6020]delete\\u0011[s7000]: deletes next character\\n\\u0011[sC000]- \\u0011[s6020]ctrl+backspace\\u0011[s7000]: deletes previous word\\n\\u0011[sC000]- \\u0011[s6020]enter\\u0011[s7000]: inserts a new line\\n\\u0011[sC000]- \\u0011[s6020]ctrl+s\\u0011[s7000]: saves changes to the file\\n\\u0011[sC000]- \\u0011[s6020]ctrl+r\\u0011[s7000]: toggles the ruler\\n\\u0011[sC000]- \\u0011[s6020]ctrl+1 to 4\\u0011[s7000]: inserts one of the 4 escape characters\\n\\n\\u0011[s5040]Interface\\u0011[s7000]\\nsmol's interface features multiple elements:\\n\\n\\u0011[sC000]- \\u0011[s7000]a ruler to the left numbering the lines, which can be toggled\\n\\u0011[sC000]- \\u0011[s7000]a status bar on the bottom showing the current cursor position and open file\\n\\u0011[sC000]- \\u0011[s7000]highligted text showing escape sequences which can be manipulated\"}}"}