diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsole.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsole.cs index 9d12db7ffc..5d1945fc73 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsole.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsole.cs @@ -12,17 +12,27 @@ namespace ICSharpCode.PythonBinding { public class PythonConsole : ThreadSafeScriptingConsole, IConsole, IMemberProvider { + IScriptingConsoleTextEditor textEditor; + IControlDispatcher dispatcher; + public PythonConsole(IScriptingConsoleTextEditor textEditor, IControlDispatcher dispatcher) : this(new ScriptingConsole(textEditor), dispatcher) { + this.textEditor = textEditor; } PythonConsole(ScriptingConsole console, IControlDispatcher dispatcher) : base(console, dispatcher) { + this.dispatcher = dispatcher; console.MemberProvider = this; } + public ScriptingConsoleOutputStream CreateOutputStream() + { + return new ScriptingConsoleOutputStream(textEditor, dispatcher); + } + public CommandLine CommandLine { get; set; } public TextWriter Output { diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsoleHost.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsoleHost.cs index 40d21132e4..ac1b67a32b 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsoleHost.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConsoleHost.cs @@ -16,12 +16,10 @@ namespace ICSharpCode.PythonBinding public class PythonConsoleHost : ConsoleHost, IScriptingConsoleHost { Thread thread; - IScriptingConsoleTextEditor textEditor; PythonConsole pythonConsole; public PythonConsoleHost(IScriptingConsoleTextEditor textEditor, IControlDispatcher dispatcher) { - this.textEditor = textEditor; pythonConsole = new PythonConsole(textEditor, dispatcher); } @@ -71,7 +69,8 @@ namespace ICSharpCode.PythonBinding /// protected override IConsole CreateConsole(ScriptEngine engine, CommandLine commandLine, ConsoleOptions options) { - SetOutput(new ScriptingConsoleOutputStream(textEditor)); + ScriptingConsoleOutputStream stream = pythonConsole.CreateOutputStream(); + SetOutput(stream); pythonConsole.CommandLine = commandLine; return pythonConsole; } diff --git a/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsole.cs b/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsole.cs index 0a282237a4..85fb650a9b 100644 --- a/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsole.cs +++ b/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsole.cs @@ -12,17 +12,27 @@ namespace ICSharpCode.RubyBinding { public class RubyConsole : ThreadSafeScriptingConsole, IConsole, IMemberProvider { + IScriptingConsoleTextEditor textEditor; + IControlDispatcher dispatcher; + public RubyConsole(IScriptingConsoleTextEditor textEditor, IControlDispatcher dispatcher) : this(new ScriptingConsole(textEditor), dispatcher) { + this.textEditor = textEditor; } RubyConsole(ScriptingConsole console, IControlDispatcher dispatcher) : base(console, dispatcher) { + this.dispatcher = dispatcher; console.MemberProvider = this; } + public ScriptingConsoleOutputStream CreateOutputStream() + { + return new ScriptingConsoleOutputStream(textEditor, dispatcher); + } + public CommandLine CommandLine { get; set; } public TextWriter Output { diff --git a/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsoleHost.cs b/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsoleHost.cs index 67ed74cbd1..46238708be 100644 --- a/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsoleHost.cs +++ b/src/AddIns/BackendBindings/Ruby/RubyBinding/Project/Src/RubyConsoleHost.cs @@ -87,7 +87,8 @@ namespace ICSharpCode.RubyBinding /// protected override IConsole CreateConsole(ScriptEngine engine, CommandLine commandLine, ConsoleOptions options) { - SetOutput(new ScriptingConsoleOutputStream(textEditor)); + ScriptingConsoleOutputStream stream = rubyConsole.CreateOutputStream(); + SetOutput(stream); rubyConsole.CommandLine = commandLine; return rubyConsole; } diff --git a/src/AddIns/BackendBindings/Scripting/Project/Src/ScriptingConsoleOutputStream.cs b/src/AddIns/BackendBindings/Scripting/Project/Src/ScriptingConsoleOutputStream.cs index 0ccb3c7be3..115ee9cb28 100644 --- a/src/AddIns/BackendBindings/Scripting/Project/Src/ScriptingConsoleOutputStream.cs +++ b/src/AddIns/BackendBindings/Scripting/Project/Src/ScriptingConsoleOutputStream.cs @@ -10,10 +10,12 @@ namespace ICSharpCode.Scripting public class ScriptingConsoleOutputStream : Stream { IScriptingConsoleTextEditor textEditor; + IControlDispatcher dispatcher; - public ScriptingConsoleOutputStream(IScriptingConsoleTextEditor textEditor) + public ScriptingConsoleOutputStream(IScriptingConsoleTextEditor textEditor, IControlDispatcher dispatcher) { this.textEditor = textEditor; + this.dispatcher = dispatcher; } public override bool CanRead { @@ -61,7 +63,17 @@ namespace ICSharpCode.Scripting public override void Write(byte[] buffer, int offset, int count) { string text = UTF8Encoding.UTF8.GetString(buffer, offset, count); - textEditor.Write(text); + ThreadSafeTextEditorWrite(text); + } + + void ThreadSafeTextEditorWrite(string text) + { + if (dispatcher.CheckAccess()) { + textEditor.Write(text); + } else { + Action action = ThreadSafeTextEditorWrite; + dispatcher.Invoke(action, text); + } } } } diff --git a/src/AddIns/BackendBindings/Scripting/Test/Console/ScriptingConsoleOutputStreamTests.cs b/src/AddIns/BackendBindings/Scripting/Test/Console/ScriptingConsoleOutputStreamTests.cs index dd69a77b1a..f913ea9e74 100644 --- a/src/AddIns/BackendBindings/Scripting/Test/Console/ScriptingConsoleOutputStreamTests.cs +++ b/src/AddIns/BackendBindings/Scripting/Test/Console/ScriptingConsoleOutputStreamTests.cs @@ -12,54 +12,87 @@ using NUnit.Framework; namespace ICSharpCode.Scripting.Tests.Console { [TestFixture] - public class ScriptingConsoleOutputStreamTestFixture + public class ScriptingConsoleOutputStreamTests { ScriptingConsoleOutputStream stream; FakeConsoleTextEditor textEditor; + FakeControlDispatcher dispatcher; - [TestFixtureSetUp] - public void SetUpFixture() + [SetUp] + public void Init() { textEditor = new FakeConsoleTextEditor(); - stream = new ScriptingConsoleOutputStream(textEditor); + dispatcher = new FakeControlDispatcher(); + dispatcher.CheckAccessReturnValue = true; + + stream = new ScriptingConsoleOutputStream(textEditor, dispatcher); } [Test] - public void CanReadIsFalse() + public void CanRead_NewInstance_ReturnsFalse() { Assert.IsFalse(stream.CanRead); } [Test] - public void CanSeekIsFalse() + public void CanSeek_NewInstance_ReturnsFalse() { Assert.IsFalse(stream.CanSeek); } [Test] - public void CanWriteIsTrue() + public void CanWrite_NewInstance_ReturnsTrue() { Assert.IsTrue(stream.CanWrite); } [Test] - public void WriteAddsTextToTextEditor() + public void Write_UTF8ByteArrayPassed_AddsTextToTextEditor() { - textEditor.Text = String.Empty; byte[] bytes = UTF8Encoding.UTF8.GetBytes("test"); stream.Write(bytes, 0, bytes.Length); - Assert.AreEqual("test", textEditor.Text); + string text = textEditor.TextPassedToWrite; + + string expectedText = "test"; + Assert.AreEqual(expectedText, text); } [Test] - public void OffsetAndLengthUsedInWriteMethod() + public void Write_UTF8ByteArrayPassed_OffsetAndLengthUsedInWriteMethod() { textEditor.Text = String.Empty; byte[] bytes = UTF8Encoding.UTF8.GetBytes("0output1"); stream.Write(bytes, 1, bytes.Length - 2); - Assert.AreEqual("output", textEditor.Text); - } + string text = textEditor.TextPassedToWrite; + string expectedText = "output"; + + Assert.AreEqual(expectedText, text); + } + + [Test] + public void Write_DispatcherCheckAccessReturnsFalse_WriteMethodIsInvoked() + { + dispatcher.CheckAccessReturnValue = false; + + byte[] bytes = UTF8Encoding.UTF8.GetBytes("test"); + stream.Write(bytes, 0, bytes.Length); + + Assert.IsNotNull(dispatcher.MethodInvoked); + } + + [Test] + public void Write_DispatcherCheckAccessReturnsFalse_WriteMethodIsInvokedWithTextAsArgument() + { + dispatcher.CheckAccessReturnValue = false; + + byte[] bytes = UTF8Encoding.UTF8.GetBytes("test"); + stream.Write(bytes, 0, bytes.Length); + + object[] expectedArgs = new object[] { "test" }; + + Assert.AreEqual(expectedArgs, dispatcher.MethodInvokedArgs); + } } }