It appears that output filters don’t work in a non-SystemAction action’s execAction() or action() method.
Am I just not understanding how output filters are supposed to work?
A trivial example to illustrate. We create an output filter called foozleOutputFilter. When it’s active it blocks all output (by replacing it with an empty string). We define two new actions, >FOO, a system action and >BAR an intransitive action. Both output a string, enable the filter, output another string, and then disable the filter. The behavior I’d expect is that in both cases only the first string would be output. But that only happens with the system action. The intransitive action outputs both strings, suggesting that the filter isn’t working for some reason. It doesn’t appear to be because the filter is on the wrong output stream, because if you just don’t deactivate the filter all output is blocked.
I haven’t checked and certainly don’t know why the code doesn’t work as is. Have you tried CaptureFilter at all? I notice that CaptureFilters return nil instead of empty strings, but I don’t know why that would change your test behavior…
The transcript is then flushed and disabled to allow the SystemAction to prompt for interactive responses. Then execSystemAction() is executed, and finally the transcript is activated again.
So this probably accounts for the difference between the IAction and the SystemAction in the output you’re describing.
“Learning TADS3” says on page 313f.:
[…] there are occasions when your fancy output (or input) can be defeated by the text-buffering that the transcript is performing. In such cases you need to deactivate the (text-buffering) transcript before doing your fancy stuff and reactivate it afterwards, with a coding pattern than typically looks like:
gTranscript.deactivate();
/* do fancy stuff here */
gTranscript.activate();
And indeed, if we insert those calls to deactivate and activate gTranscript into Bar’s execAction from your example, like this:
Ah, perfect. “Manipulating the Transcript” was in fact one of the pieces of documentation I had open, but I was trying to copy an example from Some Common Input/Output Issues, which is one of the “most complete” examples of using OutputFilter I could find, and it doesn’t twiddle the transcript (or at least it doesn’t in any of the code in the example). I think that’s one of the weaknesses in the TADS3 documentation: a relative paucity of completely worked, standalone examples.
Anyway, thanks. That is exactly what I was missing.
FWIW, in my quest to implement a quick-and-dirty “FFW” capability to execute a canned series of commands bypassing output (to quickly zip to the gamepoint under debug/development), I could not find a master “output off” switch. I also struggled to get OutputFiltering/gTranscript to work the way I wanted. The below seemed an effective alternative.
modify mainOutputStream
/* the new enable/disable capability */
outputOn = true
enable() { outputOn = true; }
disable() { outputOn = nil; }
writeFromStream(txt) {
/* if an input event was interrupted, cancel the event */
inputManager.inputEventEnd();
/* write the text to the console - NEW: if output enabled */
if (outputOn) aioSay(txt);
}
;
invokingMethod() {
local cmdLst = ['get foo', 'get bar', 'get baz', 'e', 'e']; //commands to run, hardcoded for now
mainOutputStream.disable();
foreach(local x in cmdLst)
executeCommand(gPlayerChar, gPlayerChar, Tokenizer.tokenize(x), true);
mainOutputStream.enable();
}
Yes, I was so lazy I did not want to replay a command file and have to spam space bar. This big hammer is probably not what you were initially looking for, but helped me!