如何保持msbuild输出的颜色
本文关键字:颜色 输出 msbuild 何保持 | 更新日期: 2023-09-27 18:21:07
当我在命令行运行msbuild时,它在控制台中显示出漂亮的颜色。
然而,当我用Process.Start
从C#运行它时,输出显示为黑白。我怎样才能保留这些颜色?
var info = new ProcessStartInfo("msbuild")
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
};
using (var p = Process.Start(info) )
{
p.ErrorDataReceived += (s, e) => Console.Error.WriteLine(e.Data);
p.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
}
此外,当我们在这里时,这比我在BeginOutputReadLine
之前运行Process.Start
重要吗?是否会丢失任何输出?
动机,为那些感兴趣的人。我正在进行的一个项目使用了一个自定义的构建工具(重新发明轮子imho)。它使用msbuild,但在错综复杂的间接层后面(上面的简化模型)。Msbuild有用的颜色消失了。我想救他们。
p.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
Process.OutputDataReceived读取文本,而不是颜色。这个下面的输出重定向功能只重定向stdout文本,而不是控制台颜色属性。当您使用>
重定向操作符从命令行运行msbuild以将其输出发送到文本文件时,会得到完全相同的结果。当你在记事本中打开文本文件时,你当然会看到平淡的文本。
解析重定向的输出以重新着色自己的输出是非常不切实际的。你被乏味所困扰。再说一遍,程序员不会经常抱怨IDE中错误列表窗口的外观:)
仅此而已,没有其他方法。您的代码首先启动进程,然后附加事件处理程序。因此,可能会有一些数据丢失,但这取决于cpu处理代码的速度。最好先附加事件处理程序,然后再启动进程。(见下文)
using (var p = new Process())
{
p.StartInfo = new ProcessStartInfo("msbuild")
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
};
p.ErrorDataReceived += (s, e) => ErrorLine(e.Data);
p.OutputDataReceived += (s, e) => OutputLine(e.Data);
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.Start();
p.WaitForExit();
}
void ErrorLine(string text)
{
Console.ForegroundColor = ConsoleColor.White;
Console.BackgroundColor = ConsoleColor.DarkRed;
Console.Error.WriteLine(text);
Console.ResetColor();
}
void OutputLine(string text)
{
Console.Error.WriteLine(text);
}
我不知道如何专门针对msbuild使用所有警告/错误/其他不同颜色的东西来做到这一点,但您可以在写入控制台之前使用Console.ForegroundColor = ConsoleColor.Red;
更改控制台颜色,并使用Console.ResetColor();
重置它
因此,您可以更改ErrorDataReciveved订阅,在写入之前将颜色更改为红色,并在写入输出后重置颜色。
此问题的潜在解决方案。现在可以解决这个问题,因为控制台基础结构几乎完全是在Windows上重新设计的。介绍Windows伪控制台
使用ConPTY创建MsBuild将给出完整的VT输出。
public void Start(string command, int consoleWidth = 80, int consoleHeight = 30)
{
using (var inputPipe = new PseudoConsolePipe())
using (var outputPipe = new PseudoConsolePipe())
using (var pseudoConsole = PseudoConsole.Create(inputPipe.ReadSide, outputPipe.WriteSide, consoleWidth, consoleHeight))
using (var process = ProcessFactory.Start(command, PseudoConsole.PseudoConsoleThreadAttribute, pseudoConsole.Handle))
{
// copy all pseudoconsole output to a FileStream and expose it to the rest of the app
ConsoleOutStream = new FileStream(outputPipe.ReadSide, FileAccess.Read);
OutputReady.Invoke(this, EventArgs.Empty);
// Store input pipe handle, and a writer for later reuse
_consoleInputPipeWriteHandle = inputPipe.WriteSide;
_consoleInputWriter = new StreamWriter(new FileStream(_consoleInputPipeWriteHandle, FileAccess.Write))
{
AutoFlush = true
};
// free resources in case the console is ungracefully closed (e.g. by the 'x' in the window titlebar)
OnClose(() => DisposeResources(process, pseudoConsole, outputPipe, inputPipe, _consoleInputWriter));
WaitForExit(process).WaitOne(Timeout.Infinite);
}
}
来源:https://github.com/microsoft/terminal/blob/07d06f62aa5a883f70cbe8572bf8ea1f8577f53f/samples/ConPTY/GUIConsole/GUIConsole.ConPTY/Terminal.cs