diff --git a/PoshCode.PoshConsole/PoshConsole.cs b/PoshCode.PoshConsole/PoshConsole.cs index 46e9dad..91ec06b 100644 --- a/PoshCode.PoshConsole/PoshConsole.cs +++ b/PoshCode.PoshConsole/PoshConsole.cs @@ -79,17 +79,9 @@ protected override void OnInitialized(EventArgs e) Loaded += (sender, ignored) => { - if (Runner == null) + if (!Runner.IsInitialized) { - Runner = new RunspaceProxy(_host); - Runner.RunspaceReady += (source, args) => Dispatcher.BeginInvoke((Action) (() => - { - CommandBox.IsEnabled = true; - ExecutePromptFunction(null, PipelineState.Completed); - })); - - // TODO: Improve this interface - Expander.TabComplete = Runner.CompleteInput; + Runner.Initialize(); } }; } @@ -226,7 +218,17 @@ public PoshConsole() str.Append(obj); } Prompt(str.ToString()); - }) { DefaultOutput = false, Secret = true }; + }) { DefaultOutput = false, Secret = true }; + + Runner = new RunspaceProxy(_host); + Runner.RunspaceReady += (source, args) => Dispatcher.BeginInvoke((Action)(() => + { + CommandBox.IsEnabled = true; + ExecutePromptFunction(null, PipelineState.Completed); + })); + + // TODO: Improve this interface + Expander.TabComplete = Runner.CompleteInput; } public Command DefaultOutputCommand { get; set; } diff --git a/PoshCode.PoshConsole/PowerShell/RunspaceProxy.cs b/PoshCode.PoshConsole/PowerShell/RunspaceProxy.cs index 6c91897..370290b 100644 --- a/PoshCode.PoshConsole/PowerShell/RunspaceProxy.cs +++ b/PoshCode.PoshConsole/PowerShell/RunspaceProxy.cs @@ -31,43 +31,36 @@ internal class RunspaceProxy public event RunspaceReadyHandler RunspaceReady; - private SyncEvents _syncEvents = new SyncEvents(); - private readonly Runspace _runSpace; + private readonly SyncEvents _syncEvents = new SyncEvents(); + private Runspace _runSpace; - public Pipeline _pipeline; + private Pipeline _pipeline; public Command DefaultOutputCommand { get; private set; } public Command ContentOutputCommand { get; set; } - protected Queue CommandQueue { get; private set; } + protected Queue CommandQueue { get; } protected Thread WorkerThread; + protected InitialSessionState InitialSessionState => _runSpace.InitialSessionState; - public InitialSessionState InitialSessionState - { - get { return _runSpace.InitialSessionState; } - } - - public RunspaceConfiguration RunspaceConfiguration - { - get { return _runSpace.RunspaceConfiguration; } - } + protected RunspaceConfiguration RunspaceConfiguration => _runSpace.RunspaceConfiguration; - public RunspaceStateInfo RunspaceStateInfo - { - get { return _runSpace.RunspaceStateInfo; } - } + protected RunspaceStateInfo RunspaceStateInfo => _runSpace.RunspaceStateInfo; - private Host _host; + private readonly Host _host; public RunspaceProxy(Host host) { _host = host; CommandQueue = new Queue(); + } + public bool IsInitialized => _runSpace != null; + public void Initialize() { // pre-create reusable commands DefaultOutputCommand = new Command("Out-Default"); //// for now, merge the errors with the rest of the output @@ -120,13 +113,13 @@ public RunspaceProxy(Host host) var path = Path.GetDirectoryName(poshModule.Location); iss.ImportPSModulesFromPath(Path.Combine(path, "Modules")); - var profile = new PSObject(Path.GetFullPath(Path.Combine(currentUserProfilePath, host.Name + "_profile.ps1"))); + var profile = new PSObject(Path.GetFullPath(Path.Combine(currentUserProfilePath, _host.Name + "_profile.ps1"))); //* %windir%\system32\WindowsPowerShell\v1.0\profile.ps1 // This profile applies to all users and all shells. profile.Properties.Add(new PSNoteProperty("AllUsersAllHosts", Path.GetFullPath(Path.Combine(systemProfilePath, "Profile.ps1")))); //* %windir%\system32\WindowsPowerShell\v1.0\PoshConsole_profile.ps1 // This profile applies to all users, but only to the Current shell. - profile.Properties.Add(new PSNoteProperty("AllUsersCurrentHost", Path.GetFullPath(Path.Combine(systemProfilePath, host.Name + "_profile.ps1")))); + profile.Properties.Add(new PSNoteProperty("AllUsersCurrentHost", Path.GetFullPath(Path.Combine(systemProfilePath, _host.Name + "_profile.ps1")))); //* %UserProfile%\My Documents\WindowsPowerShell\profile.ps1 // This profile applies only to the current user, but affects all shells. profile.Properties.Add(new PSNoteProperty("CurrentUserAllHosts", Path.GetFullPath(Path.Combine(currentUserProfilePath, "Profile.ps1")))); @@ -143,7 +136,7 @@ public RunspaceProxy(Host host) iss.Assemblies.Add(new SessionStateAssemblyEntry(sma.FullName, sma.CodeBase)); */ - _runSpace = RunspaceFactory.CreateRunspace(host, iss); + _runSpace = RunspaceFactory.CreateRunspace(_host, iss); // TODO: can we handle profiles this way? /* @@ -417,28 +410,35 @@ internal void ExecuteShutdownProfile(int exitCode) /// private void ExecuteStartupProfile() { - CommandQueue.Clear(); - - Enqueue(new CallbackCommand(new[] { new Command(Resources.Prompt, true, true) }, null) { Secret = true }); - - Enqueue(new CallbackCommand(new[] { new Command(Resources.TabExpansion2, true, true) }, null) { Secret = true }); + // we're going to ensure the startup profile goes _first_ + lock (((ICollection) CommandQueue).SyncRoot) + { + CallbackCommand[] commands = new CallbackCommand[CommandQueue.Count]; + CommandQueue.CopyTo(commands, 0); + CommandQueue.Clear(); + + var existing = ( + from profileVariable in InitialSessionState.Variables["profile"] + from pathProperty in ((PSObject) profileVariable.Value).Properties.Match("*Host*", PSMemberTypes.NoteProperty) + where File.Exists(pathProperty.Value.ToString()) + select pathProperty.Value.ToString() + ).Select(path => new Command(path, false, true)).ToArray(); + // This might be nice to have too (in case anyone was using it): + _runSpace.SessionStateProxy.SetVariable("profiles", existing.ToArray()); + + if (existing.Any()) + { + CommandQueue.Enqueue(new CallbackCommand(existing, + ignored => RunspaceReady(this, _runSpace.RunspaceStateInfo.State)) {Secret = true}); + // this is super important + } - var existing = ( - from profileVariable in InitialSessionState.Variables["profile"] - from pathProperty in ((PSObject)profileVariable.Value).Properties.Match("*Host*", PSMemberTypes.NoteProperty) - where File.Exists(pathProperty.Value.ToString()) - select pathProperty.Value.ToString() - ).Select(path => new Command(path, false, true)).ToArray(); - // This might be nice to have too (in case anyone was using it): - _runSpace.SessionStateProxy.SetVariable("profiles", existing.ToArray()); + CommandQueue.Enqueue(new CallbackCommand(new[] {new Command(Resources.Prompt, true, true)}, null) {Secret = true}); - if (existing.Any()) - { - Enqueue(new CallbackCommand( existing, ignored => RunspaceReady(this, _runSpace.RunspaceStateInfo.State)) { Secret = true }); // this is super important - } - else - { - Enqueue(new CallbackCommand( "New-Paragraph", ignored => RunspaceReady(this, _runSpace.RunspaceStateInfo.State)) { Secret = true }); // this is super important + foreach (var command in commands) + { + CommandQueue.Enqueue(command); + } } } diff --git a/PoshConsole.Demo/MainWindow.xaml.cs b/PoshConsole.Demo/MainWindow.xaml.cs index 77c8481..a100d90 100644 --- a/PoshConsole.Demo/MainWindow.xaml.cs +++ b/PoshConsole.Demo/MainWindow.xaml.cs @@ -1,4 +1,5 @@ -using System.Windows; +using System; +using System.Windows; using System.Windows.Media; using Fluent; @@ -18,5 +19,12 @@ private void ZoomSlider_OnValueChanged(object sender, RoutedPropertyChangedEvent { TextOptions.SetTextFormattingMode(this, e.NewValue > 1.0 ? TextFormattingMode.Ideal : TextFormattingMode.Display); } + + protected override void OnInitialized(EventArgs e) + { + // This is here just to make sure we can run commands in this event handler! + PoshConsole.ExecuteCommand("Write-Output $PSVersionTable"); + base.OnInitialized(e); + } } }