diff --git a/.gitignore b/.gitignore index 6a5633b..6987464 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,4 @@ assets/diskMediabin/* video_encoder/* assets/disk0/tvdos/bin/tautfont.png +.idea/vcs.xml diff --git a/assets/disk0/home/config/zfmrc b/assets/disk0/home/config/zfmrc new file mode 100644 index 0000000..bdd8ab8 --- /dev/null +++ b/assets/disk0/home/config/zfmrc @@ -0,0 +1,5 @@ +[EXEC_FUNS] +nes,A:/home/tvnes/tvnes.js {0} + +[COL_HL_EXT] +nes,156 \ No newline at end of file diff --git a/assets/disk0/hopper/bin/hop.alias b/assets/disk0/hopper/bin/hop.alias new file mode 100644 index 0000000..874a372 --- /dev/null +++ b/assets/disk0/hopper/bin/hop.alias @@ -0,0 +1 @@ +hopper $0 \ No newline at end of file diff --git a/assets/disk0/hopper/bin/hop.per b/assets/disk0/hopper/bin/hop.per new file mode 100644 index 0000000..dc06dee --- /dev/null +++ b/assets/disk0/hopper/bin/hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:hopper +HopperPackageVersion:0.0.1 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:hopper; +HopperRequires:tvdos 1.* +ProperName:Hopper +ProperAuthor:CuriousTorvald +ProperDescription:Package manager for TVDOS +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +PackageFileList:https://raw.githubusercontent.com/curioustorvald/hopper/refs/heads/master/hopper.js; diff --git a/assets/disk0/hopper/bin/hopper.js b/assets/disk0/hopper/bin/hopper.js index da226cb..72a09e9 100644 --- a/assets/disk0/hopper/bin/hopper.js +++ b/assets/disk0/hopper/bin/hopper.js @@ -1,6 +1,303 @@ /** - * Hopper is a package manager for TSVM + * Hopper is a package manager for TVDOS * Created by CuriousTorvald on 2026-04-16 */ -println("Hopper - Package manager for TSVM") \ No newline at end of file +const SYSTEM_PACKEAGE_DEF_DIR = "A:/tvdos/hopper" +const MANIFEST_EXT = "hop.per" + +// SYNOPSIS +// hopper {search,se} [--provides, --requires, --description, --author] query +//// default searches from ProperName +// hopper {install,in} query [-v version] +// hopper {remove,rm} query + +// ============================================================ +// Manifest parsing +// ============================================================ + +function splitList(s) { + if (!s) return [] + return s.split(";").map(it => it.trim()).filter(it => it.length > 0) +} + +function parseManifest(text) { + const m = {} + text.split("\n").forEach(rawLine => { + const line = rawLine.replace(/\r$/, "") + if (line.length === 0) return + const idx = line.indexOf(":") + if (idx < 0) return + const key = line.substring(0, idx).trim() + const value = line.substring(idx + 1).trim() + m[key] = value + }) + return m +} + +function readManifestFile(path) { + const f = files.open(path) + if (!f.exists || f.isDirectory) return undefined + const m = parseManifest(f.sread()) + m._manifestPath = path + return m +} + +function listInstalledManifests() { + const dir = files.open(SYSTEM_PACKEAGE_DEF_DIR) + if (!dir.exists || !dir.isDirectory) return [] + const out = [] + dir.list().forEach(entry => { + if (entry.isDirectory) return + if (!entry.name.toLowerCase().endsWith(MANIFEST_EXT)) return + const m = readManifestFile(entry.fullPath) + if (m !== undefined) out.push(m) + }) + return out +} + +function findInstalledManifest(name) { + const direct = `${SYSTEM_PACKEAGE_DEF_DIR}/${name}${MANIFEST_EXT}` + const m = readManifestFile(direct) + if (m !== undefined) return m + const all = listInstalledManifests() + for (let i = 0; i < all.length; i++) { + if ((all[i].HopperPackageName || "") === name) return all[i] + } + return undefined +} + +// ============================================================ +// Search +// ============================================================ + +// Dummy "remote" repository -- pretends to be a network query result. +const FAKE_REMOTE_PACKAGES = [ + { + HopperPackageName: "doomster", + HopperPackageVersion: "0.9.3", + ProperName: "Doomster", + ProperAuthor: "id Sortware", + ProperDescription: "First-person shooter game for TSVM", + HopperProvides: "doomster;", + HopperRequires: "tvdos 1.*;libgl 1.*" + }, + { + HopperPackageName: "libfft", + HopperPackageVersion: "0.1.0", + ProperName: "LibFFT", + ProperAuthor: "Soraya Vaughn", + ProperDescription: "Fast Fourier Transform library for TSVM", + HopperProvides: "libfft;", + HopperRequires: "tvdos 1.*" + }, + { + HopperPackageName: "chatlite", + HopperPackageVersion: "2.1.5", + ProperName: "ChatLite", + ProperAuthor: "TerraNetworks Co.", + ProperDescription: "Lightweight IRC-style chat client", + HopperProvides: "chatlite;", + HopperRequires: "tvdos 1.*;wintex 1.*" + }, + { + HopperPackageName: "snakey", + HopperPackageVersion: "1.4.0", + ProperName: "Snakey", + ProperAuthor: "Iben Holst", + ProperDescription: "Classic snake game with TerranBASIC scripting", + HopperProvides: "snakey;", + HopperRequires: "tvdos 1.*;libterranbasic 1.*" + } +] + +function fieldCandidates(manifest, field) { + switch (field) { + case "provides": return splitList(manifest.HopperProvides || "") + case "requires": return splitList(manifest.HopperRequires || "") + case "description": return [manifest.ProperDescription || ""] + case "author": return [manifest.ProperAuthor || ""] + default: return [manifest.ProperName || "", manifest.HopperPackageName || ""] + } +} + +function matchesQuery(manifest, field, query) { + const q = query.toLowerCase() + return fieldCandidates(manifest, field).some(c => c.toLowerCase().indexOf(q) >= 0) +} + +function printSearchResult(m, origin) { + const name = m.ProperName || m.HopperPackageName || "(unnamed)" + const ver = m.HopperPackageVersion || "?" + println(` [${origin}] ${name} -- ${m.HopperPackageName} ${ver}`) + if (m.ProperDescription) println(` ${m.ProperDescription}`) +} + +function cmdSearch(args) { + let field = "name" + let query = undefined + for (let i = 0; i < args.length; i++) { + const a = args[i] + if (a === "--provides") field = "provides" + else if (a === "--requires") field = "requires" + else if (a === "--description") field = "description" + else if (a === "--author") field = "author" + else if (a.startsWith("--")) { printerrln(`Unknown option: ${a}`); return 1 } + else query = a + } + if (query === undefined) { + printerrln("Usage: hopper search [--provides|--requires|--description|--author] ") + return 1 + } + + println(`Searching installed packages in ${SYSTEM_PACKEAGE_DEF_DIR} ...`) + const sysHits = listInstalledManifests().filter(m => matchesQuery(m, field, query)) + if (sysHits.length === 0) println(" (no matches)") + else sysHits.forEach(m => printSearchResult(m, "installed")) + + println("") + println("Searching remote repository ...") + const netHits = FAKE_REMOTE_PACKAGES.filter(m => matchesQuery(m, field, query)) + if (netHits.length === 0) println(" (no matches)") + else netHits.forEach(m => printSearchResult(m, "remote")) + + return 0 +} + +// ============================================================ +// Install (pure dummy) +// ============================================================ + +function cmdInstall(args) { + let query = undefined + let version = undefined + for (let i = 0; i < args.length; i++) { + if (args[i] === "-v") { version = args[i + 1]; i++ } + else if (args[i].startsWith("--")) { printerrln(`Unknown option: ${args[i]}`); return 1 } + else query = args[i] + } + if (query === undefined) { + printerrln("Usage: hopper install [-v ]") + return 1 + } + + const verSuffix = version ? ` (v${version})` : "" + println(`Resolving ${query}${verSuffix} ...`) + println(`Fetching manifest from remote ...`) + println(`Resolving dependencies ...`) + println(`Downloading package payload ...`) + println(`Verifying integrity ...`) + println(`Writing manifest to ${SYSTEM_PACKEAGE_DEF_DIR}/${query}${MANIFEST_EXT} ...`) + println(`Installed ${query}${verSuffix}.`) + println("(dummy install: no files were actually created)") + return 0 +} + +// ============================================================ +// Remove (dry-run; resolves file list from manifest) +// ============================================================ + +// Convert a SystemPackagePath entry (e.g. "/tvdos/bin/taut*") into a +// concrete list of files on the A: drive. Supports a simple '*' wildcard +// in the filename component. +function expandSystemPath(pattern) { + const sysDrive = "A:" + + if (pattern.indexOf("*") < 0) { + return [`${sysDrive}${pattern}`] + } + + const fwd = pattern.lastIndexOf("/") + const bck = pattern.lastIndexOf("\\") + const lastSep = Math.max(fwd, bck) + const dirPart = (lastSep < 0) ? "" : pattern.substring(0, lastSep) + const namePart = (lastSep < 0) ? pattern : pattern.substring(lastSep + 1) + + const dir = files.open(`${sysDrive}${dirPart}/`) + if (!dir.exists || !dir.isDirectory) return [] + + const escaped = namePart.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + const re = new RegExp(`^${escaped}$`, "i") + + const out = [] + dir.list().forEach(entry => { + if (entry.isDirectory) return + if (re.test(entry.name)) out.push(entry.fullPath) + }) + return out +} + +function cmdRemove(args) { + const query = args[0] + if (query === undefined) { + printerrln("Usage: hopper remove ") + return 1 + } + + const m = findInstalledManifest(query) + if (m === undefined) { + printerrln(`Package not installed: ${query}`) + return 2 + } + + const name = m.ProperName || m.HopperPackageName || query + const ver = m.HopperPackageVersion || "?" + println(`Preparing removal of ${name} (${m.HopperPackageName} ${ver}) ...`) + + const paths = splitList(m.SystemPackagePath || "") + println("") + println("The following files would be deleted:") + if (paths.length === 0) { + println(" (manifest declares no files)") + } + paths.forEach(p => { + const expanded = expandSystemPath(p) + if (expanded.length === 0) { + println(` (no match on disk) ${p}`) + } + else { + expanded.forEach(e => println(` ${e}`)) + } + }) + println(` ${m._manifestPath}`) + + println("") + println("(dry-run: no files were actually deleted)") + return 0 +} + +// ============================================================ +// Dispatch +// ============================================================ + +function printUsage() { + println("Hopper - Package manager for TVDOS") + println("") + println("Usage:") + println(" hopper {search,se} [--provides|--requires|--description|--author] ") + println(" hopper {install,in} [-v ]") + println(" hopper {remove,rm} ") +} + +const _hopperArgs = (typeof exec_args !== "undefined" && exec_args) ? exec_args.slice(1) : [] +const _hopperCmd = _hopperArgs[0] +const _hopperRest = _hopperArgs.slice(1) + +switch (_hopperCmd) { + case "search": + case "se": + return cmdSearch(_hopperRest) + case "install": + case "in": + return cmdInstall(_hopperRest) + case "remove": + case "rm": + return cmdRemove(_hopperRest) + case undefined: + printUsage() + return 0 + default: + printerrln(`Unknown command: ${_hopperCmd}`) + printUsage() + return 1 +} diff --git a/assets/disk0/tvdos/bin/taut.js b/assets/disk0/tvdos/bin/taut.js index 1515069..a490347 100644 --- a/assets/disk0/tvdos/bin/taut.js +++ b/assets/disk0/tvdos/bin/taut.js @@ -3781,7 +3781,6 @@ function openFlagsPopup() { while (!done) { input.withEvent(ev => { if (ev[0] !== 'key_down') return - if (1 !== ev[2]) return const ks = ev[1] if (eventJustReceived) { eventJustReceived = false; return } diff --git a/assets/disk0/tvdos/hopper/getopt.hop.per b/assets/disk0/tvdos/hopper/getopt.hop.per new file mode 100644 index 0000000..e21a598 --- /dev/null +++ b/assets/disk0/tvdos/hopper/getopt.hop.per @@ -0,0 +1,11 @@ +HopperManifestVersion:1 +HopperPackageName:getopt +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:getopt; +HopperRequires: +ProperName:getopt.js +ProperAuthor:David Pacheco +ProperDescription:node.js implementation of POSIX getopt() (and then some) +Licence:MIT +SystemPackagePath:/tvdos/include/getopt.mjs diff --git a/assets/disk0/tvdos/hopper/libfs.hop.per b/assets/disk0/tvdos/hopper/libfs.hop.per new file mode 100644 index 0000000..c8f6d99 --- /dev/null +++ b/assets/disk0/tvdos/hopper/libfs.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libfs +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libfs; +HopperRequires:tvdos 1.*; +ProperName:LibFS +ProperAuthor:CuriousTorvald +ProperDescription:NodeJS-compatible Filesystem module for TVDOS +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/fs.mjs diff --git a/assets/disk0/tvdos/hopper/libgl.hop.per b/assets/disk0/tvdos/hopper/libgl.hop.per new file mode 100644 index 0000000..a1412ab --- /dev/null +++ b/assets/disk0/tvdos/hopper/libgl.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libgl +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libgl; +HopperRequires: +ProperName:LibGL +ProperAuthor:CuriousTorvald +ProperDescription:TVDOS Graphics Library +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/gl.mjs diff --git a/assets/disk0/tvdos/hopper/libpcm.hop.per b/assets/disk0/tvdos/hopper/libpcm.hop.per new file mode 100644 index 0000000..ff31d63 --- /dev/null +++ b/assets/disk0/tvdos/hopper/libpcm.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libpcm +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libpcm; +HopperRequires: +ProperName:LibPCM +ProperAuthor:CuriousTorvald +ProperDescription:PCM decoder for TSVM +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/pcm.mjs diff --git a/assets/disk0/tvdos/hopper/libpsg.hop.per b/assets/disk0/tvdos/hopper/libpsg.hop.per new file mode 100644 index 0000000..9b8a998 --- /dev/null +++ b/assets/disk0/tvdos/hopper/libpsg.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libpsg +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libpsg; +HopperRequires: +ProperName:LibPSG +ProperAuthor:CuriousTorvald +ProperDescription:Programmable sound generator library for TSVM +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/psg.mjs diff --git a/assets/disk0/tvdos/hopper/libseqread.hop.per b/assets/disk0/tvdos/hopper/libseqread.hop.per new file mode 100644 index 0000000..9e98bb4 --- /dev/null +++ b/assets/disk0/tvdos/hopper/libseqread.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libseqread +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libseqread; +HopperRequires:tvdos 1.*; +ProperName:LibSeqread +ProperAuthor:CuriousTorvald +ProperDescription:Sequentially read files from disk drive +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/seqread.mjs;/tvdos/include/seqreadtape.mjs diff --git a/assets/disk0/tvdos/hopper/libtaud.hop.per b/assets/disk0/tvdos/hopper/libtaud.hop.per new file mode 100644 index 0000000..a24f1ac --- /dev/null +++ b/assets/disk0/tvdos/hopper/libtaud.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libtaud +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libtaud; +HopperRequires:tvdos 1.*; +ProperName:LibTaud +ProperAuthor:CuriousTorvald +ProperDescription:Helper functions for interaction between Taud format and TSVM Tracker +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/taud.mjs diff --git a/assets/disk0/tvdos/hopper/libterranbasic.hop.per b/assets/disk0/tvdos/hopper/libterranbasic.hop.per new file mode 100644 index 0000000..fb349b6 --- /dev/null +++ b/assets/disk0/tvdos/hopper/libterranbasic.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:libterranbasic +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:libterranbasic; +HopperRequires: +ProperName:LibTerranBasic +ProperAuthor:CuriousTorvald +ProperDescription:Terran BASIC runtime helper for compiled programs +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/tbas.mjs diff --git a/assets/disk0/tvdos/hopper/microtone.hop.per b/assets/disk0/tvdos/hopper/microtone.hop.per new file mode 100644 index 0000000..55973b0 --- /dev/null +++ b/assets/disk0/tvdos/hopper/microtone.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:microtone +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:microtone; +HopperRequires:tvdos 1.*;wintex 1.*;libtaud 1.*;libgl 1.* +ProperName:Microtone +ProperAuthor:CuriousTorvald +ProperDescription:Microtonal tracker for TSVM +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/bin/microtone.alias;/tvdos/bin/taut* diff --git a/assets/disk0/tvdos/hopper/tvdos.hop.per b/assets/disk0/tvdos/hopper/tvdos.hop.per new file mode 100644 index 0000000..8000c8a --- /dev/null +++ b/assets/disk0/tvdos/hopper/tvdos.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:tvdos +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:tvdos; +HopperRequires: +ProperName:TVDOS +ProperAuthor:CuriousTorvald +ProperDescription:TSVM Disk Operating System +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/TVDOS.SYS diff --git a/assets/disk0/tvdos/hopper/wintex.hop.per b/assets/disk0/tvdos/hopper/wintex.hop.per new file mode 100644 index 0000000..e3ea3f6 --- /dev/null +++ b/assets/disk0/tvdos/hopper/wintex.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:wintex +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:wintex; +HopperRequires: +ProperName:WinTex +ProperAuthor:CuriousTorvald +ProperDescription:TUI window management and renderer +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/include/wintex.mjs diff --git a/assets/disk0/tvdos/hopper/zfm.hop.per b/assets/disk0/tvdos/hopper/zfm.hop.per new file mode 100644 index 0000000..8c7b215 --- /dev/null +++ b/assets/disk0/tvdos/hopper/zfm.hop.per @@ -0,0 +1,12 @@ +HopperManifestVersion:1 +HopperPackageName:zfm +HopperPackageVersion:1.0.0 +HopperPackageMaintainer:CuriousTorvald +HopperProvides:zfm; +HopperRequires:tvdos 1.*;wintex 1.* +ProperName:ZFM +ProperAuthor:CuriousTorvald +ProperDescription:Z File Manager - Dual-panel file manager for TVDOS +Licence:MIT +SupportMe:https://github.com/sponsors/curioustorvald/ +SystemPackagePath:/tvdos/bin/zfm*