Another issue: it doesn’t respect monospace vs not-monospace fonts, so my automaps are mangled. I imagine if I set up dgdebug to output an appropriate escape code, you can recognize it as easily as the rest? Looks like CSI 11 m is “select alternative font”, but I can also use something like CSI 80 m which is (afaict) completely undefined.
We could just set it up to be fixed-width font by default. I’ll be sad, because I love how it looks now.
The challenge here is that the skein will often run dozens or hundreds of commands at a time and those half seconds are going to add up. If we need to start allowing for a timeout to know when the content is ready, we’re going to need to update the skein in a bunch of ways to allow for longer duration requests (i.e., set up spinners or other activity indicators).
Yeah, I think making it fixed-width only for appropriately-tagged divs and spans is better—that’s the Z-machine’s default too. I don’t really understand ANSI escape sequences, but it’s trivial to implement in dgdebug (Linus just didn’t because terminals are fixed-width by default).
Ah, but the vast majority of commands will have a normal prompt, right? I would only expect two or three “press any key to continue” moments in an average game. (My WIP has three.)
Alternately, we could have a toggle that switches the default from fixed width to proportional that you would use when verifying the automap.
That would also work, yeah! I see that it already preserves runs of consecutive spaces, which is great for my ASCII art purposes. I would prefer to verify the automap alongside the rest of my game text, but I can just leave it in fixed-width mode then—it’s no worse than my terminal’s normal rendering, which is what I’d be using in the absence of the Skein!
I am doing something similar running dgdebug in a pseudo-terminal in Emacs. Rather than modify the output to find ways to identifier additional prompts, I think I’ve decided that it is better handled by running the game with an alternative set of source files, where prompts for input are just overridden to continue running without waiting for input. Or, if using an alternative set of files is an issue, just build the ability to toggle running with no input into the debug version of the game.
I imagine that process output is probably being read in fairly large chunks, but there is already a risk that the end of a chunk happens to look like the "> " prompt. Adding additional special output would likely increase the risk of accidentally matching something that looks like special output.
Maybe it would be more reliable to signal state changes by optionally allowing verbose state information to be sent to stderr, and monitor that separately from main output?
Well, we have the ability to modify dgdebug, but not effectively frotz. And I really think it is worth the effort to ensure that we can use frotz with the skein (though I suspect it will a process of creating the skein with frotz then usually running it from the command line with dgt skein test).
I do like the idea of adding a shim that emits a “>” before prompting for input. Maybe we can have it emit a “>>” before prompting for a single key? Or we could have it emit something invisible, like a special ANSI sequence that isn’t otherwise used.
.
A shim seems like a fine idea, though implementing it might be a bit tricky. User code could call (get input) or (get key) at any time, not necessarily inside predicates the shim can override.
You could just tell authors “use (get input modified) instead”, though.
Here’s an odd one—if the source fails to compile, the Skein doesn’t report anything amiss. I typo’d an (endif) and suddenly nothing I changed was reflected in the Skein, no matter how many times I hit “replay”; I needed to close out and do dgt debug to get the actual error message.
On the “dgt not knowing that dgdebug is waiting for input” problem, it also shows up with the Standard Library predicates (yesno) and (get number from $X to $Y into $Z), which print special prompts like yes / no >. I’m trying to write this current project with no modifications to stdlib.dg at all, but that doesn’t seem possible here.
I’ve tried just entering “no” as the next input, which un-freezes dgt, but also loses all the input in between.
Which is not ideal; I’d like to include those responses in Skein testing.
Finally, a lower-priority suggestion: it would be nice if Ctrl-S saved the Skein, rather than trying to download the web page. I’m the sort of person who saves compulsively all the time.
Well, I said “finally”, but I did find something else. When I try to dgt build, I get this:
Execution error (ClassCastException) at dialog-tool.build/invoke-dialogc (build.clj:32).
class clojure.lang.PersistentVector cannot be cast to class clojure.lang.Named (clojure.lang.PersistentVector and clojure.lang.Named are in unnamed module of loader 'app')
Full report at:
/tmp/clojure-10743268804862925628.edn
Full report
{:clojure.main/message
"Execution error (ClassCastException) at dialog-tool.build/invoke-dialogc (build.clj:32).\nclass clojure.lang.PersistentVector cannot be cast to class clojure.lang.Named (clojure.lang.PersistentVector and clojure.lang.Named are in unnamed module of loader 'app')\n",
:clojure.main/triage
{:clojure.error/class java.lang.ClassCastException,
:clojure.error/line 32,
:clojure.error/cause
"class clojure.lang.PersistentVector cannot be cast to class clojure.lang.Named (clojure.lang.PersistentVector and clojure.lang.Named are in unnamed module of loader 'app')",
:clojure.error/symbol dialog-tool.build/invoke-dialogc,
:clojure.error/source "build.clj",
:clojure.error/phase :execution},
:clojure.main/trace
{:via
[{:type java.lang.ClassCastException,
:message
"class clojure.lang.PersistentVector cannot be cast to class clojure.lang.Named (clojure.lang.PersistentVector and clojure.lang.Named are in unnamed module of loader 'app')",
:at [clojure.core$name invokeStatic "core.clj" 1610]}],
:trace
[[clojure.core$name invokeStatic "core.clj" 1610]
[clojure.core$name invoke "core.clj" 1604]
[dialog_tool.build$invoke_dialogc invokeStatic "build.clj" 32]
[dialog_tool.build$invoke_dialogc invoke "build.clj" 25]
[dialog_tool.build$build_project invokeStatic "build.clj" 56]
[dialog_tool.build$build_project invoke "build.clj" 46]
[dialog_tool.commands$build invokeStatic "commands.clj" 53]
[dialog_tool.commands$build doInvoke "commands.clj" 46]
[clojure.lang.RestFn invoke "RestFn.java" 400]
[clojure.lang.AFn applyToHelper "AFn.java" 152]
[clojure.lang.RestFn applyTo "RestFn.java" 135]
[clojure.lang.Var applyTo "Var.java" 707]
[clojure.core$apply invokeStatic "core.clj" 667]
[clojure.core$apply invoke "core.clj" 662]
[net.lewisship.cli_tools.impl$dispatch$fn__3274$invoke_command__3275
invoke
"impl.clj"
946]
[net.lewisship.cli_tools.impl$dispatch$fn__3274
invoke
"impl.clj"
955]
[net.lewisship.cli_tools.impl$dispatch invokeStatic "impl.clj" 896]
[net.lewisship.cli_tools.impl$dispatch invoke "impl.clj" 894]
[net.lewisship.cli_tools$dispatch_STAR_
invokeStatic
"cli_tools.clj"
225]
[net.lewisship.cli_tools$dispatch_STAR_ invoke "cli_tools.clj" 218]
[net.lewisship.cli_tools$dispatch$callback__3387
invoke
"cli_tools.clj"
318]
[dialog_tool.main$option_handler invokeStatic "main.clj" 12]
[dialog_tool.main$option_handler invoke "main.clj" 6]
[net.lewisship.cli_tools$dispatch$fn__3389
invoke
"cli_tools.clj"
328]
[net.lewisship.cli_tools$color_wrapper
invokeStatic
"cli_tools.clj"
242]
[net.lewisship.cli_tools$color_wrapper invoke "cli_tools.clj" 237]
[net.lewisship.cli_tools$dispatch invokeStatic "cli_tools.clj" 321]
[net.lewisship.cli_tools$dispatch invoke "cli_tools.clj" 249]
[dialog_tool.main$_main invokeStatic "main.clj" 16]
[dialog_tool.main$_main doInvoke "main.clj" 14]
[clojure.lang.RestFn applyTo "RestFn.java" 140]
[clojure.lang.Var applyTo "Var.java" 707]
[clojure.core$apply invokeStatic "core.clj" 667]
[clojure.main$main_opt invokeStatic "main.clj" 515]
[clojure.main$main_opt invoke "main.clj" 511]
[clojure.main$main invokeStatic "main.clj" 665]
[clojure.main$main doInvoke "main.clj" 617]
[clojure.lang.RestFn applyTo "RestFn.java" 140]
[clojure.lang.Var applyTo "Var.java" 707]
[clojure.main main "main.java" 40]],
:cause
"class clojure.lang.PersistentVector cannot be cast to class clojure.lang.Named (clojure.lang.PersistentVector and clojure.lang.Named are in unnamed module of loader 'app')"}}
I think this was caused by trying to build two separate targets? I put this in my dialog.edn file:
:format [:zblorb :aastory]
Should I just build by hand outside dgt if I want both a Z-machine and Å-machine file?
I’ve also discovered there is an ANSI escape sequence for fixed-width text (\e[50m); it’s just that most terminals don’t support it for obvious reasons. So I’m going to make the next version of dgdebug output that as appropriate (but of course dgt is welcome to ignore it).
The next release of the Å-machine tools is also going to include an “aamrun” binary, an equivalent to dumbfrotz for the Å-machine. It’s very simplistic (much like dumbfrotz!), but it seems useful to be able to run a full Skein through the Å-machine as well as the Z-machine if you plan to publish to the web.
Are there any features you would want in such a tool, to work well with dgt? Currently it supports -s and -w in the same way as dgdebug (and in fact uses the same PRNG as dumbfrotz so the same seed should produce the same results).
