diff --git a/bend2/comp.ts b/bend2/comp.ts index f2c29dad0..e298a480c 100644 --- a/bend2/comp.ts +++ b/bend2/comp.ts @@ -1235,7 +1235,9 @@ function eff_src(path: string, seen: Set): string { return ""; } seen.add(path); - return fs.readFileSync(path, "utf8"); + const dir = path.slice(0, path.lastIndexOf("/")); + return fs.readFileSync(path, "utf8").replace(/^\/\/ @src ([a-z0-9_]+\.c)$/gm, + (_: string, name: string) => eff_src(dir + "/" + name, seen)); } // Io diff --git a/bend2/effs/window_close.c b/bend2/effs/window_close.c index affde2de3..e74bb31c9 100644 --- a/bend2/effs/window_close.c +++ b/bend2/effs/window_close.c @@ -1,6 +1,8 @@ // Window // ====== +// @src window_host.c + #ifdef __OBJC__ #import @@ -12,23 +14,6 @@ static void window_close(intptr_t at) { #elif defined(__linux__) -#ifndef BendWin -#define BendWin BendWin -#include -#include -#include - -typedef struct { - Display* dpy; - Window win; - Atom del; - XImage* img; - u32 n; - u32 cap; - u32* evs; -} BendWin; -#endif - static void window_close(intptr_t at) { BendWin* win = (BendWin*)at; XDestroyImage(win->img); diff --git a/bend2/effs/window_frame.c b/bend2/effs/window_frame.c index f35c0bf1e..a0d2cdf6b 100644 --- a/bend2/effs/window_frame.c +++ b/bend2/effs/window_frame.c @@ -1,6 +1,8 @@ // Window // ====== +// @src window_host.c + // An event is five words: kind (0 key, 1 mouse, 2 move, 3 close) and // its fields; a frame answers the events pumped since the last one. #if defined(__OBJC__) || defined(__linux__) @@ -183,23 +185,6 @@ static Term window_frame(Env e, intptr_t at, Term image) { #elif defined(__linux__) -#ifndef BendWin -#define BendWin BendWin -#include -#include -#include - -typedef struct { - Display* dpy; - Window win; - Atom del; - XImage* img; - u32 n; - u32 cap; - u32* evs; -} BendWin; -#endif - // The Mac's key codes: a key's character in lower case, the function // keys' private-use characters (the arrows at 63232), a modifier's // 65536 + its key code. diff --git a/bend2/effs/window_host.c b/bend2/effs/window_host.c new file mode 100644 index 000000000..35c1440f4 --- /dev/null +++ b/bend2/effs/window_host.c @@ -0,0 +1,19 @@ +// Pulled by Window.open/frame/set_title/close (`// @src window_host.c`). +// The X11 window: its own connection (so its queue holds only its +// events), the frame's image and the events pumped since the last +// frame, five words each (kind, a, b, c, d) as on the Mac. +#if defined(__linux__) +#include +#include +#include + +typedef struct { + Display* dpy; + Window win; + Atom del; + XImage* img; + u32 n; + u32 cap; + u32* evs; +} BendWin; +#endif diff --git a/bend2/effs/window_open.c b/bend2/effs/window_open.c index 5ac73521e..63f33ddda 100644 --- a/bend2/effs/window_open.c +++ b/bend2/effs/window_open.c @@ -1,6 +1,8 @@ // Window // ====== +// @src window_host.c + #ifdef __OBJC__ #import @@ -178,27 +180,6 @@ static u32 window_make(const char* title, u32 w, u32 h, intptr_t* out, #elif defined(__linux__) -// The X11 window: its own connection (so its queue holds only its -// events), the frame's image and the events pumped since the last -// frame, five words each (kind, a, b, c, d) as on the Mac. The same -// block sits in window_frame.c and window_close.c under this guard. -#ifndef BendWin -#define BendWin BendWin -#include -#include -#include - -typedef struct { - Display* dpy; - Window win; - Atom del; - XImage* img; - u32 n; - u32 cap; - u32* evs; -} BendWin; -#endif - static u32 window_make(const char* title, u32 w, u32 h, intptr_t* out, const char** why) { if (w < 1 || h < 1 || w > 16384 || h > 16384) { diff --git a/bend2/effs/window_set_title.c b/bend2/effs/window_set_title.c index 91f3c7e3b..698872e83 100644 --- a/bend2/effs/window_set_title.c +++ b/bend2/effs/window_set_title.c @@ -1,6 +1,8 @@ // Window // ====== +// @src window_host.c + #ifdef __OBJC__ #import @@ -13,23 +15,6 @@ static void window_set_title(intptr_t at, const char* text, u64 n) { #elif defined(__linux__) -#ifndef BendWin -#define BendWin BendWin -#include -#include -#include - -typedef struct { - Display* dpy; - Window win; - Atom del; - XImage* img; - u32 n; - u32 cap; - u32* evs; -} BendWin; -#endif - static void window_set_title(intptr_t at, const char* text, u64 n) { BendWin* win = (BendWin*)at; XStoreName(win->dpy, win->win, text); diff --git a/bend2/main.ts b/bend2/main.ts index b9f7c3e5d..49e5631df 100755 --- a/bend2/main.ts +++ b/bend2/main.ts @@ -241,8 +241,10 @@ async function cli_file(args: string[]): Promise { process.exitCode = book_run(book, n0, argv); return; } - const ins = new Set([...seen.keys(), ...Object.values(book.tlds).flatMap((t) => - t.$ === "Def" && t.i !== undefined ? t.i.map(path_real) : [])]); + const foreign = Object.values(book.tlds).flatMap((t) => + t.$ === "Def" && t.i !== undefined ? t.i : []); + const ins = new Set([...seen.keys(), ...foreign.map(path_real), + ...src_deps(foreign)]); for (const out of outs) { const at = path_real(out); if (ins.has(at) || (fs.existsSync(at) && fs.statSync(at).isDirectory())) { @@ -291,6 +293,27 @@ function path_real(p: string): string { return fs.existsSync(p) ? fs.realpathSync(p) : path.resolve(p); } +// Real paths of // @src siblings, a helper's helper included. +function src_deps(files: string[]): string[] { + const out: string[] = []; + const seen = new Set(files.flatMap((f) => + f.endsWith(".c") && fs.existsSync(f) ? [fs.realpathSync(f)] : [])); + for (const q = [...seen]; q.length > 0;) { + const real = q.pop() as string; + const dir = real.slice(0, real.lastIndexOf("/")); + for (const m of fs.readFileSync(real, "utf8") + .matchAll(/^\/\/ @src ([a-z0-9_]+\.c)$/gm)) { + const dep = fs.realpathSync(dir + "/" + m[1]); + if (!seen.has(dep)) { + seen.add(dep); + out.push(dep); + q.push(dep); + } + } + } + return out; +} + function cli_emit(book: Bend.Book, out: string): void { if (/\.c?js$/.test(out)) { fs.writeFileSync(out, Comp.js_book(book)); @@ -449,19 +472,24 @@ async function cli_publish(file: string): Promise { // pkg_files is the package the loader read for this file, the entry first: // every .bend file at its namespace (the entry at its name), every foreign -// .c or .js file at its path from the entry's directory; base and the -// store's packages stay out. A path that climbs above the entry's directory -// takes the entry's ancestor directories along, as many as the deepest climb. +// .c or .js file at its path from the entry's directory, and each // @src +// sibling; base and the store's packages stay out. A path that climbs above +// the entry's directory takes the entry's ancestor directories along, as +// many as the deepest climb. function pkg_files(file: string, book: Bend.Book, seen: Map): Record { const dir = file.slice(0, file.lastIndexOf("/") + 1); + const root = fs.realpathSync(dir === "" ? "." : dir.slice(0, -1)); + const owned = Object.entries(book.tlds).flatMap(([k, tld]): string[] => + tld.$ !== "Def" || tld.i === undefined || tld.b === true + || k.startsWith("0x") ? [] : tld.i); const raws = [...[...seen].flatMap(([real, ns]): [string, string][] => real === BASE || ns === null || ns.startsWith("0x") ? [] : [[ns === "" ? path.basename(file) : ns + ".bend", real]]), - ...Object.entries(book.tlds).flatMap(([k, tld]): [string, string][] => - tld.$ !== "Def" || tld.i === undefined || tld.b === true - || k.startsWith("0x") ? [] : tld.i.map((f) => - [f.startsWith(dir) ? f.slice(dir.length) : f, f]))]; + ...owned.map((f): [string, string] => + [f.startsWith(dir) ? f.slice(dir.length) : f, f]), + ...src_deps(owned).map((real): [string, string] => + [path.posix.relative(root, real), real])]; const ups = raws.map(([p]) => path.posix.normalize(p).split("/") .filter((s) => s === "..").length); const anc = fs.realpathSync(path.dirname(file)).split("/")