A file that is a package is still a package to the editor

package_of matched the file being edited against a package's directory, which
is right for every package that is one — and answers "not a package" for one
that is a single file, because the file's directory is not the file. A form
typed into sand.flan with the headless driver running would have spliced as a
bare step, the evaluation would have said ok, and the program would have gone
on calling the step it already had. That is the exact silent failure the
function exists to prevent, so it now matches the file too.
This commit is contained in:
Joseph Ferano 2026-09-11 20:15:31 +07:00
parent f78c935b95
commit fcebe03576
2 changed files with 23 additions and 4 deletions

View File

@ -80,15 +80,21 @@ let package_of t origin =
match origin with
| "" -> None
| origin ->
let dir =
try Filename.dirname (Unix.realpath origin)
with Unix.Unix_error _ -> Filename.dirname origin
let here =
try Unix.realpath origin with Unix.Unix_error _ -> origin
in
let dir = Filename.dirname here in
(* A package is a directory, or a single .flan file named outright — so the
file being edited belongs to it if the package *is* that file, or if it
sits in the package's directory. Comparing only the directory would miss
the file case entirely and answer [None], which is the silent failure
above rather than a loud one: the form splices unqualified and the
running program keeps calling the name it already had. *)
let same p =
let d =
try Unix.realpath p.Load.dir with Unix.Unix_error _ -> p.Load.dir
in
String.equal d dir
String.equal d here || String.equal d dir
in
(match List.filter same t.pkgs with
| [] -> None

View File

@ -167,6 +167,19 @@ let () =
fail "a form from a package file reported %s, wanted agent/poll"
(String.concat " " c.Session.fns)
| exception Loc.Error (_, m) -> fail "redefining agent/poll: %s" m);
(* A package that is a single file, which is what sand.flan is to the
headless driver. The file being edited *is* the package rather than a
member of a directory, so matching on the directory alone would answer
"not a package" and the failure is the silent one above: the form
splices as a bare [step] and the running program keeps the one it had. *)
let t2, _ = Session.create ~file:"programs/sand-headless.flan" in
(match Session.eval ~origin:"../sand.flan" t2 "(defn step [] Unit (do))" with
| c ->
if c.Session.fns <> [ "sand/step" ] then
fail "a form from a single-file package reported %s, wanted sand/step"
(String.concat " " c.Session.fns)
| exception Loc.Error (_, m) -> fail "redefining sand/step: %s" m);
(* And a file that is not a package keeps its names as written. *)
(match Session.eval ~origin:"../sand.flan" t "(defn game-draw [] Unit (do))" with
| c ->