Internally to R3-Alpha there was some code for implementing an ECHO feature, (a command which existed in Rebol2). This was something where you could capture the standard output of your interactive session to a file.
It was one of those things that was hard to keep working... that didn't have any tests... so one didn't know what "working" was in the first place. What were the expectations? If all you have are hooks underneath the PORT! level in C code, that's going to lead to some strange log files. Without console awareness, if you're merely streaming what got printed to standard output, you'd have your transcript littered with non-sequitur >>
prompts.
If you're going to log the prompts, you probably want to log what the Rebol command input to the console was too. If you're not going to log the prompts you probably don't want the command input, but you probably want interactive input in the log for other ASKs from your session. Not to mention that an actually useful echo command would probably have a number of other useful features, for automatically naming and incrementing your log files.
It sounds cool (Red has a wish for it, including echo input, hence console awareness.) But you don't want much of the logic for what ECHO does in C code. So at one point, I took a stab at moving it out to userspace, building on HIJACK of WRITE-STDOUT and INPUT:
https://github.com/metaeducation/ren-c/pull/445
However, it has atrophied. And with INPUT no longer being the chokepoint by which input is read due to the ASK redesign, it seems time to either revisit it and redo it...or let it go for now. (Though of course, you can do a quick and dirty version on par with Rebol2's version if you don't mind it being bad, with hijack 'write-stdout...and just append everything to a file.)
I'm going with letting it go as a feature design space, and let people improvise their own solutions if they need them. It's a nice wish, but as we move forward there's only so much non-maintained code to leave hanging around as a reminder of a wish. So here's what it was, and discussion of the feature can reopen at a later date...when we'll likely be wanting to bring it back with a "web console first" point of view:
echo: function [
{Copies console I/O to a file.}
return: <void>
'instruction [file! text! block! word!]
{File or template with * substitution, or command: [ON OFF RESET].}
<static>
target ([%echo * %.txt])
form-target
sub ("")
old-input (copy :input)
old-write-stdout (copy :write-stdout)
hook-in
hook-out
logger
ensure-echo-on
ensure-echo-off
][
; Sample "interesting" feature, be willing to form the filename by filling
; in the blank with a substitute string you can change.
;
form-target: default [func [return: [file!]] [
either block? target [
as file! unspaced replace (copy target) '* (
either empty? sub [[]] [unspaced ["-" sub]]
)
][
target
]
]]
logger: default [func [value][
write/append form-target either char? value [to-text value][value]
value
]]
; Installed hook; in an ideal world, WRITE-STDOUT would not exist and
; would just be WRITE, so this would be hooking WRITE and checking for
; STDOUT or falling through. Note WRITE doesn't take CHAR! right now.
;
hook-out: default [func [
return: <void>
value [text! char! binary!]
{Text to write, if a STRING! or CHAR! is converted to OS format}
][
old-write-stdout value
logger value
]]
; It looks a bit strange to look at a console log without the input
; being included too. Note that hooking the input function doesn't get
; the newlines, has to be added.
;
hook-in: default [
chain [
:old-input
|
func [value] [
logger value
logger newline
value ; hook still needs to return the original value
]
]
]
ensure-echo-on: default [does [
;
; Hijacking is a NO-OP if the functions are the same.
; (this is indicated by a BLANK! return vs an ACTION!)
;
hijack 'write-stdout 'hook-out
hijack 'input 'hook-in
]]
ensure-echo-off: default [does [
;
; Restoring a hijacked function with its original will
; remove any overhead and be as fast as it was originally.
;
hijack 'write-stdout 'old-write-stdout
hijack 'input 'old-input
]]
switch type of instruction [
word! [
switch instruction [
'on [ensure-echo-on]
'off [ensure-echo-off]
'reset [
delete form-target
write/append form-target "" ; or just have it not exist?
]
] else [
word: to-uppercase word
fail [
"Unknown ECHO command, not [ON OFF RESET]" LF
"Use ECHO" unspaced ["(" word ")"] "to force evaluation"
]
]
]
text! [
sub: instruction
ensure-echo-on
]
block! file! [
target: instruction
ensure-echo-on
]
]
]