Describes the parameters for running the console process in the console emulator, including the command line to run.
Example #1
0
        private void Init_WireEvents([NotNull] ConEmuStartInfo startinfo)
        {
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }

            // Advise events before they got chance to fire, use event sinks from startinfo for guaranteed delivery
            if (startinfo.ConsoleProcessExitedEventSink != null)
            {
                ConsoleProcessExited += startinfo.ConsoleProcessExitedEventSink;
            }
            if (startinfo.ConsoleProcessPreExitedEventSink != null)
            {
                ConsoleProcessPreExited += startinfo.ConsoleProcessPreExitedEventSink;
            }
            if (startinfo.ConsoleEmulatorClosedEventSink != null)
            {
                ConsoleEmulatorClosed += startinfo.ConsoleEmulatorClosedEventSink;
            }

            // Re-issue events as async tasks
            // As we advise events before they even fire, the task is guaranteed to get its state
            ConsoleProcessExited  += (sender, args) => _taskConsoleProcessExit.SetResult(args);
            ConsoleEmulatorClosed += delegate { _taskConsoleEmulatorClosed.SetResult(Missing.Value); };
        }
Example #2
0
        public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo)
        {
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }

            // Close prev session if there is one
            _running?.CloseConsoleEmulator();
            if (_running != null)
            {
                throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time.");
            }

            _autostartinfo = null;             // As we're starting, no more chance for an autostart
            if (!IsHandleCreated)
            {
                CreateHandle();
            }

            // Spawn session
            var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void *)Handle, IsStatusbarVisible));

            _running = session;
            StateChanged?.Invoke(this, EventArgs.Empty);
            startinfo.ConsoleProcessPreExitedEventSink += (sender, args) => OnSessionEnds();
            // Wait for its exit
            session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler: TaskScheduler.FromCurrentSynchronizationContext(), continuationAction: task =>
            {
                OnSessionEnds();
            });

            return(session);
        }
        private Process Init_StartConEmu([NotNull] ConEmuStartInfo startinfo, [NotNull] CommandLineBuilder cmdl)
        {
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }
            if (cmdl == null)
            {
                throw new ArgumentNullException(nameof(cmdl));
            }

            try
            {
                if (string.IsNullOrEmpty(startinfo.ConEmuExecutablePath))
                {
                    throw new InvalidOperationException("Could not run the console emulator. The path to ConEmu.exe could not be detected.");
                }
                if (!File.Exists(startinfo.ConEmuExecutablePath))
                {
                    throw new InvalidOperationException($"Missing ConEmu executable at location “{startinfo.ConEmuExecutablePath}”.");
                }
                var processNew = new Process()
                {
                    StartInfo = new ProcessStartInfo(startinfo.ConEmuExecutablePath, cmdl.ToString())
                    {
                        UseShellExecute = false
                    }
                };

                // Bind process termination
                processNew.EnableRaisingEvents = true;
                processNew.Exited += delegate
                {
                    // Ensure STA
                    Task.Factory.StartNew(scheduler: _schedulerSta, cancellationToken: CancellationToken.None, creationOptions: 0, action: () =>
                    {
                        // Tear down all objects
                        TerminateLifetime();

                        // If we haven't separately caught an exit of the payload process
                        TryFireConsoleProcessExited(_process.ExitCode /* We haven't caught the exit of the payload process, so we haven't gotten a message with its errorlevel as well. Assume ConEmu propagates its exit code, as there ain't other way for getting it now */);

                        // Fire client total exited event
                        ConsoleEmulatorClosed?.Invoke(this, EventArgs.Empty);
                    });
                };

                if (!processNew.Start())
                {
                    throw new Win32Exception("The process did not start.");
                }
                return(processNew);
            }
            catch (Win32Exception ex)
            {
                TerminateLifetime();
                throw new InvalidOperationException("Could not run the console emulator. " + ex.Message + $" ({ex.NativeErrorCode:X8})" + Environment.NewLine + Environment.NewLine + "Command:" + Environment.NewLine + startinfo.ConEmuExecutablePath + Environment.NewLine + Environment.NewLine + "Arguments:" + Environment.NewLine + cmdl, ex);
            }
        }
Example #4
0
        /// <summary>
        /// Starts the session.
        /// Opens the emulator view in the control (HWND given in <paramref name="hostcontext" />) by starting the ConEmu child process and giving it that HWND; ConEmu then starts the child Console Process for the commandline given in <paramref name="startinfo" /> and makes it run in the console emulator window.
        /// </summary>
        /// <param name="startinfo">User-defined startup parameters for the console process.</param>
        /// <param name="hostcontext">Control-related parameters.</param>
        /// <param name="joinableTaskFactory">The <see cref="JoinableTaskFactory"/>.</param>
        public ConEmuSession([NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext, [NotNull] JoinableTaskFactory joinableTaskFactory)
        {
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }
            if (hostcontext == null)
            {
                throw new ArgumentNullException(nameof(hostcontext));
            }
            if (joinableTaskFactory == null)
            {
                throw new ArgumentNullException(nameof(joinableTaskFactory));
            }
            if (string.IsNullOrEmpty(startinfo.ConsoleProcessCommandLine))
            {
                throw new InvalidOperationException($"Cannot start a new console process for command line “{startinfo.ConsoleProcessCommandLine}” because it's either NULL, or empty, or whitespace.");
            }

            _joinableTaskFactory = joinableTaskFactory;
            _startinfo           = startinfo;
            startinfo.MarkAsUsedUp();             // No more changes allowed in this copy

            // Directory for working files, +cleanup
            _dirTempWorkingFolder = Init_TempWorkingFolder();

            // Events wiring: make sure sinks pre-installed with start-info also get notified
            Init_WireEvents(startinfo);

            // Should feed ANSI log?
            if (startinfo.IsReadingAnsiStream)
            {
                _ansilog = Init_AnsiLog(startinfo);
            }

            // Cmdline
            CommandLineBuilder cmdl = Init_MakeConEmuCommandLine(startinfo, hostcontext, _ansilog, _dirTempWorkingFolder);

            // Start ConEmu
            // If it fails, lifetime will be terminated; from them on, termination will be bound to ConEmu process exit
            _process = Init_StartConEmu(startinfo, cmdl);

            // GuiMacro executor
            _guiMacroExecutor = new GuiMacroExecutor(startinfo.ConEmuConsoleServerExecutablePath);
            _lifetime.Add(() => ((IDisposable)_guiMacroExecutor).Dispose());

            // Monitor payload process
            Init_ConsoleProcessMonitoring();
        }
Example #5
0
        private AnsiLog Init_AnsiLog([NotNull] ConEmuStartInfo startinfo)
        {
            var ansilog = new AnsiLog(_dirTempWorkingFolder);

            _lifetime.Add(() => ansilog.Dispose());
            if (startinfo.AnsiStreamChunkReceivedEventSink != null)
            {
                ansilog.AnsiStreamChunkReceived += startinfo.AnsiStreamChunkReceivedEventSink;
            }

            // Do the pumping periodically (TODO: take this to async?.. but would like to keep the final evt on the home thread, unless we go to tasks)
            // TODO: if ConEmu writes to a pipe, we might be getting events when more data comes to the pipe rather than poll it by timer
            var timer = new Timer()
            {
                Interval = (int)TimeSpan.FromSeconds(.1).TotalMilliseconds, Enabled = true
            };

            timer.Tick += delegate { ansilog.PumpStream(); };
            _lifetime.Add(() => timer.Dispose());

            return(ansilog);
        }
Example #6
0
        private static string Init_MakeConEmuCommandLine_EmitConfigFile([NotNull] DirectoryInfo dirForConfigFile, [NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext)
        {
            if (dirForConfigFile == null)
            {
                throw new ArgumentNullException(nameof(dirForConfigFile));
            }
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }
            if (hostcontext == null)
            {
                throw new ArgumentNullException(nameof(hostcontext));
            }

            // Take baseline settings from the startinfo
            XmlDocument xmlBase = startinfo.BaseConfiguration;

            if (xmlBase.DocumentElement == null)
            {
                throw new InvalidOperationException("The BaseConfiguration parameter of the ConEmuStartInfo must be a non-empty XmlDocument. This one does not have a root element.");
            }
            if (xmlBase.DocumentElement.Name != ConEmuConstants.XmlElementKey)
            {
                throw new InvalidOperationException($"The BaseConfiguration parameter of the ConEmuStartInfo must be an XmlDocument with the root element named “{ConEmuConstants.XmlElementKey}” in an empty namespace. The actual element name is “{xmlBase.DocumentElement.Name}”.");
            }
            if (!String.Equals(xmlBase.DocumentElement.GetAttribute(ConEmuConstants.XmlAttrName), ConEmuConstants.XmlValueSoftware, StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException($"The BaseConfiguration parameter of the ConEmuStartInfo must be an XmlDocument whose root element is named “{ConEmuConstants.XmlElementKey}” and has an attribute “{ConEmuConstants.XmlAttrName}” set to “{ConEmuConstants.XmlValueSoftware}”. The actual value of this attribute is “{xmlBase.DocumentElement.GetAttribute(ConEmuConstants.XmlAttrName)}”.");
            }

            // Load default template
            var xmldoc = new XmlDocument();

            xmldoc.AppendChild(xmldoc.ImportNode(xmlBase.DocumentElement, true));

            // Ensure the settings file has the expected keys structure
            // As we now allow user-supplied documents, we must ensure these elements exist
            XmlElement xmlSoftware = xmldoc.DocumentElement;

            if (xmlSoftware == null)
            {
                throw new InvalidOperationException("Not expecting the cloned element to be NULL.");
            }
            var xmlConEmu = xmlSoftware.SelectSingleNode($"{ConEmuConstants.XmlElementKey}[@{ConEmuConstants.XmlAttrName}='{ConEmuConstants.XmlValueConEmu}']") as XmlElement;

            if (xmlConEmu == null)
            {
                xmlSoftware.AppendChild(xmlConEmu = xmldoc.CreateElement(ConEmuConstants.XmlElementKey));
                xmlConEmu.SetAttribute(ConEmuConstants.XmlAttrName, ConEmuConstants.XmlValueConEmu);
            }
            var xmlDotVanilla = xmlConEmu.SelectSingleNode($"{ConEmuConstants.XmlElementKey}[@{ConEmuConstants.XmlAttrName}='{ConEmuConstants.XmlValueDotVanilla}']") as XmlElement;

            if (xmlDotVanilla == null)
            {
                xmlConEmu.AppendChild(xmlDotVanilla = xmldoc.CreateElement(ConEmuConstants.XmlElementKey));
                xmlDotVanilla.SetAttribute(ConEmuConstants.XmlAttrName, ConEmuConstants.XmlValueDotVanilla);
            }

            // Apply settings from properties
            XmlNode xmlSettings = xmlDotVanilla;

            {
                string keyname = "StatusBar.Show";
                var    xmlElem = ((XmlElement)(xmlSettings.SelectSingleNode($"value[@name='{keyname}']") ?? xmlSettings.AppendChild(xmldoc.CreateElement("value"))));
                xmlElem.SetAttribute(ConEmuConstants.XmlAttrName, keyname);
                xmlElem.SetAttribute("type", "hex");
                xmlElem.SetAttribute("data", (hostcontext.IsStatusbarVisibleInitial ? 1 : 0).ToString());
            }

            // Environment variables
            if ((startinfo.EnumEnv().Any()) || (startinfo.IsEchoingConsoleCommandLine) || (startinfo.GreetingText.Length > 0))
            {
                string keyname = "EnvironmentSet";
                var    xmlElem = ((XmlElement)(xmlSettings.SelectSingleNode($"value[@name='{keyname}']") ?? xmlSettings.AppendChild(xmldoc.CreateElement("value"))));
                xmlElem.SetAttribute(ConEmuConstants.XmlAttrName, keyname);
                xmlElem.SetAttribute("type", "multi");
                foreach (string key in startinfo.EnumEnv())
                {
                    XmlElement xmlLine;
                    xmlElem.AppendChild(xmlLine = xmldoc.CreateElement("line"));
                    xmlLine.SetAttribute("data", $"set {key}={startinfo.GetEnv(key)}");
                }

                // Echo the custom greeting text
                if (startinfo.GreetingText.Length > 0)
                {
                    // Echo each line separately
                    List <string> lines = Regex.Split(startinfo.GreetingText, @"\r\n|\n|\r").ToList();
                    if ((lines.Any()) && (lines.Last().Length == 0))                    // Newline handling, as declared
                    {
                        lines.RemoveAt(lines.Count - 1);
                    }
                    foreach (string line in lines)
                    {
                        XmlElement xmlLine;
                        xmlElem.AppendChild(xmlLine = xmldoc.CreateElement("line"));
                        xmlLine.SetAttribute("data", $"echo {Init_MakeConEmuCommandLine_EmitConfigFile_EscapeEchoText(line)}");
                    }
                }

                // To echo the cmdline, add an echo command to the env-init session
                if (startinfo.IsEchoingConsoleCommandLine)
                {
                    XmlElement xmlLine;
                    xmlElem.AppendChild(xmlLine = xmldoc.CreateElement("line"));
                    xmlLine.SetAttribute("data", $"echo {Init_MakeConEmuCommandLine_EmitConfigFile_EscapeEchoText(startinfo.ConsoleProcessCommandLine)}");
                }
            }

            // Write out to temp location
            dirForConfigFile.Create();
            string sConfigFile = Path.Combine(dirForConfigFile.FullName, "Config.Xml");

            xmldoc.Save(sConfigFile);
            new FileInfo(sConfigFile).IsReadOnly = true;             // Mark the file as readonly, so that ConEmu didn't suggest to save modifications to this temp file

            return(sConfigFile);
        }
Example #7
0
        private static unsafe CommandLineBuilder Init_MakeConEmuCommandLine([NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext, [CanBeNull] AnsiLog ansilog, [NotNull] DirectoryInfo dirLocalTempRoot)
        {
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }
            if (hostcontext == null)
            {
                throw new ArgumentNullException(nameof(hostcontext));
            }

            var cmdl = new CommandLineBuilder();

            // This sets up hosting of ConEmu in our control
            cmdl.AppendSwitch("-InsideWnd");
            cmdl.AppendFileNameIfNotNull("0x" + ((ulong)hostcontext.HWndParent).ToString("X"));

            // Don't use keyboard hooks in ConEmu when embedded
            cmdl.AppendSwitch("-NoKeyHooks");

            switch (startinfo.LogLevel)
            {
            case ConEmuStartInfo.LogLevels.Basic:
                cmdl.AppendSwitch("-Log"); break;

            case ConEmuStartInfo.LogLevels.Detailed:
                cmdl.AppendSwitch("-Log2"); break;

            case ConEmuStartInfo.LogLevels.Advanced:
                cmdl.AppendSwitch("-Log3"); break;

            case ConEmuStartInfo.LogLevels.Full:
                cmdl.AppendSwitch("-Log4"); break;
            }

            // Basic settings, like fonts and hidden tab bar
            // Plus some of the properties on this class
            cmdl.AppendSwitch("-LoadCfgFile");
            cmdl.AppendFileNameIfNotNull(Init_MakeConEmuCommandLine_EmitConfigFile(dirLocalTempRoot, startinfo, hostcontext));

            if (!string.IsNullOrEmpty(startinfo.StartupDirectory))
            {
                cmdl.AppendSwitch("-Dir");
                cmdl.AppendFileNameIfNotNull(startinfo.StartupDirectory);
            }

            // ANSI Log file
            if (ansilog != null)
            {
                cmdl.AppendSwitch("-AnsiLog");
                cmdl.AppendFileNameIfNotNull(ansilog.Directory.FullName);
            }
            if (dirLocalTempRoot == null)
            {
                throw new ArgumentNullException(nameof(dirLocalTempRoot));
            }

            // This one MUST be the last switch
            cmdl.AppendSwitch("-cmd");

            // Console mode command
            // NOTE: if placed AFTER the payload command line, otherwise somehow conemu hooks won't fetch the switch out of the cmdline, e.g. with some complicated git fetch/push cmdline syntax which has a lot of colons inside on itself
            string sConsoleExitMode;

            switch (startinfo.WhenConsoleProcessExits)
            {
            case WhenConsoleProcessExits.CloseConsoleEmulator:
                sConsoleExitMode = "n";
                break;

            case WhenConsoleProcessExits.KeepConsoleEmulator:
                sConsoleExitMode = "c0";
                break;

            case WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage:
                sConsoleExitMode = "c";
                break;

            default:
                throw new ArgumentOutOfRangeException("ConEmuStartInfo" + "::" + "WhenConsoleProcessExits", startinfo.WhenConsoleProcessExits, "This is not a valid enum value.");
            }
            cmdl.AppendSwitchIfNotNull("-cur_console:", $"{(startinfo.IsElevated ? "a" : "")}{sConsoleExitMode}");

            if (!string.IsNullOrEmpty(startinfo.ConsoleProcessExtraArgs))
            {
                cmdl.AppendSwitch(startinfo.ConsoleProcessExtraArgs);
            }

            // And the shell command line itself
            cmdl.AppendSwitch(startinfo.ConsoleProcessCommandLine);

            return(cmdl);
        }
Example #8
0
 private ConEmuSession StartProcess(ConEmuStartInfo startInfo)
 {
     if (control.InvokeRequired)
     {
         return (ConEmuSession)control.Invoke(
             (ConEmuStarter)(si => { return control.Start(si); }),
             startInfo);
     }
     return control.Start(startInfo);
 }
Example #9
0
        private ConEmuStartInfo BuildStartInfo(string cwd, string executable, string arguments)
        {
            // http://www.windowsinspired.com/understanding-the-command-line-string-and-arguments-received-by-a-windows-program/

            var cmdLine = (arguments.Contains("\"") ? "\"" : "")
                + CommandLine.EscapeArgument(executable) + " " + arguments;
            var si = new ConEmuStartInfo();
            si.ConEmuExecutablePath = conEmuExe;
            si.ConsoleProcessCommandLine = cmdLine;
            si.BaseConfiguration = config;
            si.StartupDirectory = cwd;
            si.IsReadingAnsiStream = false;
            si.WhenConsoleProcessExits = WhenConsoleProcessExits.CloseConsoleEmulator;
            return si;
        }
Example #10
0
        /// <summary>
        /// Adds a tab with console interface to Git over the current working copy. Recreates the terminal on tab activation if user exits the shell.
        /// </summary>
        private void FillTerminalTab()
        {
            if (!EnvUtils.RunningOnWindows() || !Module.EffectiveSettings.Detailed.ShowConEmuTab.ValueOrDefault)
                return; // ConEmu only works on WinNT
            TabPage tabpage;
            string sImageKey = "Resources.IconConsole";
            CommitInfoTabControl.ImageList.Images.Add(sImageKey, Resources.IconConsole);
            CommitInfoTabControl.Controls.Add(tabpage = new TabPage(_consoleTabCaption.Text));
            tabpage.ImageKey = sImageKey; // After adding page

            // Delay-create the terminal window when the tab is first selected
            CommitInfoTabControl.Selecting += (sender, args) =>
            {
                if (args.TabPage != tabpage)
                    return;
                if (terminal == null) // Lazy-create on first opening the tab
                {
                    tabpage.Controls.Clear();
                    tabpage.Controls.Add(
                        terminal = new ConEmuControl()
                        {
                            Dock = DockStyle.Fill,
                            AutoStartInfo = null,
                            IsStatusbarVisible = false
                        }
                    );
                }
                if (terminal.IsConsoleEmulatorOpen) // If user has typed "exit" in there, restart the shell; otherwise just return
                    return;

                // Create the terminal
                var startinfo = new ConEmuStartInfo();
                startinfo.StartupDirectory = Module.WorkingDir;
                startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.CloseConsoleEmulator;

                // Choose the console: bash from git with fallback to cmd
                string sJustBash = "bash.exe"; // Generic bash, should generally be in the git dir, less configured than the specific git-bash
                string sJustSh = "sh.exe"; // Fallback to SH

                string cmdPath = new[] { sJustBash, sJustSh }.
                    Select(shell =>
                      {
                          string shellPath;
                          if (PathUtil.TryFindShellPath(shell, out shellPath))
                              return shellPath;
                          return null;
                      }).
                      Where(shellPath => shellPath != null).
                      FirstOrDefault();

                if (cmdPath == null)
                {
                    startinfo.ConsoleProcessCommandLine = ConEmuConstants.DefaultConsoleCommandLine;
                }
                else
                {
                    startinfo.ConsoleProcessCommandLine = cmdPath + " --login -i";
                }
                startinfo.ConsoleProcessExtraArgs = " -new_console:P:\"<Solarized Light>\"";

                // Set path to git in this window (actually, effective with CMD only)
                if (!string.IsNullOrEmpty(AppSettings.GitCommandValue))
                {
                    string dirGit = Path.GetDirectoryName(AppSettings.GitCommandValue);
                    if (!string.IsNullOrEmpty(dirGit))
                        startinfo.SetEnv("PATH", dirGit + ";" + "%PATH%");
                }

                terminal.Start(startinfo);
            };
        }
Example #11
0
	    /// <summary>
	    /// Adds a tab with console interface to Git over the current working copy. Recreates the terminal on tab activation if user exits the shell.
	    /// </summary>
	    private void FillTerminalTab()
	    {
		    if(!EnvUtils.RunningOnWindows() || !Module.EffectiveSettings.Detailed.ShowConEmuTab.ValueOrDefault)
			    return; // ConEmu only works on WinNT
		    TabPage tabpage;
		    string sImageKey = "Resources.IconConsole";
		    CommitInfoTabControl.ImageList.Images.Add(sImageKey, Resources.IconConsole);
		    CommitInfoTabControl.Controls.Add(tabpage = new TabPage("Console"));
		    tabpage.ImageKey = sImageKey; // After adding page

		    // Delay-create the terminal window when the tab is first selected
		    CommitInfoTabControl.Selecting += (sender, args) =>
		    {
			    if(args.TabPage != tabpage)
				    return;
			    if(terminal == null) // Lazy-create on first opening the tab
			    {
				    tabpage.Controls.Clear();
				    tabpage.Controls.Add(terminal = new ConEmuControl() {Dock = DockStyle.Fill, AutoStartInfo = null});
			    }
			    if(terminal.IsConsoleEmulatorOpen) // If user has typed "exit" in there, restart the shell; otherwise just return
				    return;

			    // Create the terminal
			    var startinfo = new ConEmuStartInfo();
			    startinfo.StartupDirectory = Module.WorkingDir;
			    startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.CloseConsoleEmulator;

			    // Choose the console: bash from git with fallback to cmd
			    string sGitBashFromUsrBin = "";/*This is not a console program and is not reliable yet, suppress for now.*/ //Path.Combine(Path.Combine(Path.Combine(AppSettings.GitBinDir, ".."), ".."), "git-bash.exe"); // Git bin dir is /usr/bin under git installdir, so go 2x up
			    string sGitBashFromBinOrCmd = "";/*This is not a console program and is not reliable yet, suppress for now.*/ //Path.Combine(Path.Combine(AppSettings.GitBinDir, ".."), "git-bash.exe"); // In case we're running off just /bin or /cmd
		        var gitDir = Path.GetDirectoryName(AppSettings.GitCommandValue);
			    string sJustBash = Path.Combine(gitDir, "bash.exe"); // Generic bash, should generally be in the git dir, less configured than the specific git-bash
			    string sJustSh = Path.Combine(gitDir, "sh.exe"); // Fallback to SH
			    startinfo.ConsoleProcessCommandLine = new[] {sGitBashFromUsrBin, sGitBashFromBinOrCmd, sJustBash, sJustSh}.Where(File.Exists).FirstOrDefault() ?? ConEmuConstants.DefaultConsoleCommandLine; // Choose whatever exists, or default CMD shell
                if(startinfo.ConsoleProcessCommandLine != ConEmuConstants.DefaultConsoleCommandLine)
                {
                    startinfo.ConsoleProcessCommandLine += " --login -i";
                }

			    // Set path to git in this window (actually, effective with CMD only)
			    if(!string.IsNullOrEmpty(AppSettings.GitCommand))
			    {
				    string dirGit = Path.GetDirectoryName(AppSettings.GitCommand);
				    if(!string.IsNullOrEmpty(dirGit))
					    startinfo.SetEnv("PATH", dirGit + ";" + "%PATH%");
			    }

			    terminal.Start(startinfo);
		    };
	    }
Example #12
0
		/// <summary>
		/// Starts the session.
		/// Opens the emulator view in the control (HWND given in <paramref name="hostcontext" />) by starting the ConEmu child process and giving it that HWND; ConEmu then starts the child Console Process for the commandline given in <paramref name="startinfo" /> and makes it run in the console emulator window.
		/// </summary>
		/// <param name="startinfo">User-defined startup parameters for the console process.</param>
		/// <param name="hostcontext">Control-related parameters.</param>
		public ConEmuSession([NotNull] ConEmuStartInfo startinfo, [NotNull] HostContext hostcontext)
		{
			if(startinfo == null)
				throw new ArgumentNullException(nameof(startinfo));
			if(hostcontext == null)
				throw new ArgumentNullException(nameof(hostcontext));
			if(string.IsNullOrEmpty(startinfo.ConsoleProcessCommandLine))
				throw new InvalidOperationException($"Cannot start a new console process for command line “{startinfo.ConsoleProcessCommandLine}” because it's either NULL, or empty, or whitespace.");

			_startinfo = startinfo;
			startinfo.MarkAsUsedUp(); // No more changes allowed in this copy

			// Directory for working files, +cleanup
			_dirTempWorkingFolder = Init_TempWorkingFolder();

			// Events wiring: make sure sinks pre-installed with start-info also get notified
			Init_WireEvents(startinfo);

			// Should feed ANSI log?
			if(startinfo.IsReadingAnsiStream)
				_ansilog = Init_AnsiLog(startinfo);

			// Cmdline
			CommandLineBuilder cmdl = Init_MakeConEmuCommandLine(startinfo, hostcontext, _ansilog, _dirTempWorkingFolder);

			// Start ConEmu
			// If it fails, lifetime will be terminated; from them on, termination will be bound to ConEmu process exit
			_process = Init_StartConEmu(startinfo, cmdl);

			// GuiMacro executor
			_guiMacroExecutor = new GuiMacroExecutor(startinfo.ConEmuConsoleServerExecutablePath);
			_lifetime.Add(() => ((IDisposable)_guiMacroExecutor).Dispose());

			// Monitor payload process
			Init_ConsoleProcessMonitoring();
		}
        public override void StartProcess(string command, string arguments, string workdir)
		{
			var cmdl = new CommandLineBuilder();
			cmdl.AppendFileNameIfNotNull(command /* do the escaping for it */);
			cmdl.AppendSwitch(arguments /* expecting to be already escaped */);

			var startinfo = new ConEmuStartInfo();
			startinfo.ConsoleProcessCommandLine = cmdl.ToString();
			startinfo.StartupDirectory = workdir;
			startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage;
			startinfo.AnsiStreamChunkReceivedEventSink = (sender, args) => FireDataReceived(new TextEventArgs(args.GetText(GitModule.SystemEncoding)));
			startinfo.ConsoleProcessExitedEventSink = (sender, args) =>
			{
				_nLastExitCode = args.ExitCode;
				FireProcessExited();
			};
			startinfo.ConsoleEmulatorClosedEventSink = (s, e) =>
                {
                    if (s == _terminal.RunningSession)
                    {
                        FireTerminated();
                    }
                };
			startinfo.IsEchoingConsoleCommandLine = true;

			_terminal.Start(startinfo);
		}
        public override void StartProcess(string command, string arguments, string workdir)
        {
            var cmdl = new StringBuilder();
            if (command != null)
            {
                cmdl.Append(command.Quote() /* do the escaping for it */);
                cmdl.Append(" ");
            }
            cmdl.Append(arguments /* expecting to be already escaped */);

            var startinfo = new ConEmuStartInfo();
            startinfo.ConsoleProcessCommandLine = cmdl.ToString();
            startinfo.ConsoleProcessExtraArgs = " -cur_console:P:\"<Solarized Light>\"";
            startinfo.StartupDirectory = workdir;
            startinfo.WhenConsoleProcessExits = WhenConsoleProcessExits.KeepConsoleEmulatorAndShowMessage;
            startinfo.AnsiStreamChunkReceivedEventSink = (sender, args) =>
            {
                var text = args.GetText(GitModule.SystemEncoding);
                if (EnvUtils.RunningOnWindows())
                    text = text.Replace("\n", Environment.NewLine);
                FireDataReceived(new TextEventArgs(text));
            };
            startinfo.ConsoleProcessExitedEventSink = (sender, args) =>
            {
                _nLastExitCode = args.ExitCode;
                FireProcessExited();
            };

            startinfo.ConsoleEmulatorClosedEventSink = (s, e) =>
                {
                    if (s == _terminal.RunningSession)
                    {
                        FireTerminated();
                    }
                };
            startinfo.IsEchoingConsoleCommandLine = true;

            _terminal.Start(startinfo);
        }
Example #15
0
        public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo)
        {
            if(startinfo == null)
                throw new ArgumentNullException(nameof(startinfo));

            // Close prev session if there is one
            _running?.CloseConsoleEmulator();
            if(_running != null)
                throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time.");

            _autostartinfo = null; // As we're starting, no more chance for an autostart
            if(!IsHandleCreated)
                CreateHandle();

            // Spawn session
            var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void*)Handle, IsStatusbarVisible));
            _running = session;
            StateChanged?.Invoke(this, EventArgs.Empty);

            // Wait for its exit
            session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler : TaskScheduler.FromCurrentSynchronizationContext(), continuationAction : task =>
            {
                try
                {
                    _nLastExitCode = _running.GetConsoleProcessExitCode();
                }
                catch(Exception)
                {
                    // NOP
                }
                _running = null;
                Invalidate();
                StateChanged?.Invoke(this, EventArgs.Empty);
            });

            return session;
        }
Example #16
0
        public ConEmuSession Start([NotNull] ConEmuStartInfo startinfo, [NotNull] JoinableTaskFactory joinableTaskFactory,
                                   [NotNull] string conEmuStyle, string conEmuFontSize)
        {
            if (startinfo == null)
            {
                throw new ArgumentNullException(nameof(startinfo));
            }


            SetConsoleFontSize();

            SetConsoleStyle();

            // Close prev session if there is one
            _running?.CloseConsoleEmulator();
            if (_running != null)
            {
                throw new InvalidOperationException("Cannot start a new console process because another console emulator session has failed to close in due time.");
            }

            _autostartinfo = null;             // As we're starting, no more chance for an autostart
            if (!IsHandleCreated)
            {
                CreateHandle();
            }

            // Spawn session
            var session = new ConEmuSession(startinfo, new ConEmuSession.HostContext((void *)Handle, IsStatusbarVisible), joinableTaskFactory);

            _running = session;
            StateChanged?.Invoke(this, EventArgs.Empty);

            // Wait for its exit
            session.WaitForConsoleEmulatorCloseAsync().ContinueWith(scheduler: TaskScheduler.FromCurrentSynchronizationContext(), continuationAction: task =>
            {
                try
                {
                    _nLastExitCode = _running.GetConsoleProcessExitCode();
                }
                catch (Exception)
                {
                    // NOP
                }
                _running = null;
                Invalidate();
                StateChanged?.Invoke(this, EventArgs.Empty);
            }).Forget();

            return(session);

            void SetConsoleFontSize()
            {
                var startInfoBaseConfiguration = startinfo.BaseConfiguration;

                if (!string.IsNullOrWhiteSpace(conEmuFontSize))
                {
                    if (int.TryParse(conEmuFontSize, out var fontSize))
                    {
                        var nodeFontSize =
                            startInfoBaseConfiguration.SelectSingleNode("/key/key/key/value[@name='FontSize']");

                        if (nodeFontSize?.Attributes != null)
                        {
                            nodeFontSize.Attributes["data"].Value = fontSize.ToString("X8");
                        }
                    }
                }

                startinfo.BaseConfiguration = startInfoBaseConfiguration;
            }

            void SetConsoleStyle()
            {
                if (conEmuStyle != "Default")
                {
                    startinfo.ConsoleProcessExtraArgs = " -new_console:P:\"" + conEmuStyle + "\"";
                }
            }
        }