io.write() does not print standard console
io.write does not output to console. It has a green/done status on the StdLib PDF (http://www.moonsharp.org/MoonSharpStdLib.pdf)
Console.WriteLine("Console.WriteLine 1");
Script.RunString("print('lua print')");
Script.RunString("io.write('lua io.write')");
Console.WriteLine("Console.WriteLine 2");
output: Console.WriteLine 1 lua print Console.WriteLine 2
Windows 7 .NET 4.6.1 MoonSharp 1.8.0.0
This is because the StreamWriter instance is not being flushed when io.write is called.
Call io.flush() to flush stdout. The messages will be displayed.
It is possible to fix this using AutoFlush on the stream, but I strongly oppose this approach as this behavior is not necessarily correct. Not only does it affect all streams, it could also change behavior when the process' stdout is being redirected. I'm for closing this issue.
In StandardIOFileUserDataBase:25
f.Initialize(stream, null, new StreamWriter(stream) { AutoFlush = true });
I am unable to make io.flush() affect output
Be aware that Moonsharp currently re-initializes the core modules every time a new Script is instanciated.
If you do
Script.RunString("io.write('lua io.write'); io.flush()");
rather than
Script.RunString("io.write('lua io.write')");
Script.RunString("io.flush()");
you should see the message. You could argue that this behavior is intentional if you think about the StreamWriter's (and its internal buffer's) lifetime being tied to the running Script. On the other hand, you'd probably expect the StreamWriter to be disposed of properly (and possibly even flushed) when the script's lifetime ends (which currently isn't the case, which is strictly speaking a resource leak).
No dice:
Script script = new Script();
script.DoString("print 'print works'");
// doesn't work; with or without flush
script.DoString("io.write('io.write does not work'); io.flush()");
Script.RunString("io.write('lua io.write'); io.flush()");
// hack: assign print to io.write since i can't figure out how to redirect io.write
script.DoString(@"
local _io_write = io.write;
io.write = print;");
script.DoString("io.write('io.write hack works')");
output: print works io.write hack works
OK that worked on my machine, so it could be an issue with your particular setup of stdout. Can you try running
var stream = Console.OpenStandardOutput();
var writer = new StreamWriter(stream);
writer.Write("TEST TEST TEST");
writer.Flush();
, which is the equivalent of what Lua does when you call io.write(); io.flush() in a new Script instance?
E: Also keep in mind that io.write() does NOT append a newline. Maybe your environment is expecting an \n for some reason.
This must just be an idiosyncrasy of Visual Studio's Test Explorer:
Console.WriteLine("begin 1");
Console.Out.WriteLine("begin 2");
var stream = Console.OpenStandardOutput();
var writer = new System.IO.StreamWriter(stream);
writer.Write("TEST TEST TEST");
writer.Flush();
Console.WriteLine("end 1");
Console.Out.WriteLine("end 2");
Standard Output: begin 1 begin 2 end 1 end 2
Well, not exactly.
If you are using visual studio as a host process, then visual studio will most likely want to redirect standard output in some way (for one, to display it in the output window).
The OpenStandardOutput method specifically gets the actual stdout stream (of visual studio), which probably isn't displayed anywhere. If you start devenv.exe from a command prompt, you should see those messages.
@xanathar Maybe it is better to use Console.Out rather than Console.OpenStandardOut() to acquire the application's current stdout when initializing the IO module. Otherwise, Lua is implicitly able to override the host environment's stdout setting (via Console.SetOut()) and access the original stdin, stdout and stderr streams, which is very likely to be unintended (potentially even dangerous if the host's original stdout is being processed further).
This appears to be idiosyncratic/unclear behavior in Visual Studio's Test Explorer, not a Moon# bug. Feel free to close my issue.
These all write to my window in a normal console app. But the first method does not print to "standard output" in VS Test Explorer:
var stream = Console.OpenStandardOutput();
var writer = new System.IO.StreamWriter(stream);
writer.WriteLine("TEST 1 OpenStandardOutput");
writer.Flush();
Console.WriteLine("TEST 2 Console.WriteLine");
Console.Out.WriteLine("TEST 3 Console.Out.WriteLine");
By the way, theoretically it should have been possible to set a Script's output stream via
var s = new Sript();
s.Options.Stdout = someStream;
However in practice this doesn't work for 2 reasons:
-
The core modules are initialized in the
Scriptconstructor before you have the chance to modify theScriptOptions. I personally find theScriptOptionsvery awkward and I'm wondering why they aren't immutable and passed into theScriptconstructor. The way it is currently is just asking for problems. -
ScriptOptions.StdOut(and the other streams) areStream, notTextWriter/TextReader.Console.Out, which is what you'd need to get the same behavior asConsole.WriteLineisTextWriter(which is notably different fromConsole.OpenStandardOutput()). Interestingly, the current architecture of the Lua IO module is so that theStreamfromScriptOptions.StdOutis immediately wrapped by aTextWriteranyway, so it would have been feasible to useTextWriterall along for theScriptOptions.StdOutproperty.
If you really don't consider this a bug, I don't know what else to call it. ScriptOptions.StdOut is currently completely broken.
Thank you for the info on Stdout not working, saved me a world of head-hurt!
For any one else trying to get around the problem, you can as a workaround update the default ScriptOptions before instantiating the script to get it to recognize the setting.
// This won't work, stdout will not be routed to your stream
var s = new Script();
s.Options.Stdout = myStream;
s.DoString("io.stdout.write('foo'); io.stdout.flush();");
// This will work, stdout will now be routed to your stream
MoonSharp.Interpreter.Script.DefaultOptions.Stdout = myStream;
var s = new Script();
s.DoString("io.stdout.write('foo'); io.stdout.flush();");
I personally don't like working with static variables but as long as you only instantiate scripts in a single thread you should be fine.