Keep ANSI Escape Sequences in QProcess Output - linux
I am creating a program where I run processes in Qt using the QProcess framework on Ubuntu 16.04 Qt 5.5.1 with C++ 11 enabled. I am directing the process output stream to a QTextEdit.
I would like to colorize this output to use the same colors which native terminals interpret by using the embedded ANSI escape color sequences. However, I am unable to parse the escape sequences as they appear to be missing from the QProcess output. I originally thought QString was stripping them, but after some testing I do not believe this to be the case.
I found some information to point me in the ANSI escape color interpretation direction if I could just keep the escape sequences in the QProcess output.
Here is an example project of what I am doing in Qt code.
The source file...
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QProcess>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList input = {"gcc will_not_build.c"};
QProcess * proc = new QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory("/path/to/test/c/file/");
//Start bash
proc->start("bash");
proc->waitForStarted();
// Write as many commands to this process as needed
foreach(QString str, input){
proc->write(str.toUtf8() + "\n");
proc->waitForBytesWritten(-1);
}
// Let bash close gracefully
proc->write("exit $?\n");
proc->waitForBytesWritten(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data = proc->readAll();
// The use of tr(read_data) also works here.
QString output = tr(read_data);//QString::fromStdString (read_data.toStdString ());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
delete proc;
// Add the output to the text box
ui->textEdit->append (output);
}
MainWindow::~MainWindow()
{
delete ui;
}
The header file...
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
The form file...
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QTextEdit" name="textEdit">
<property name="geometry">
<rect>
<x>33</x>
<y>19</y>
<width>331</width>
<height>211</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>19</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
The C source file...
int main(){
// Intentionally will not build
I will not build :)
}
My output looks like this:
QProcess gcc output
The output of the native Linux terminal looks like this:
Linux terminal gcc output with colors
Does anyone know how I might go about keeping the ANSI escape color sequences in the QProcess output so I can simulate the Linux terminal colors?
As a side note I have dug around in the Qt Creator source code and there is a class which can convert ANSI escape colors to Rich Text colors so I know someone has been down this road. Then again, when building projects, Qt Creator does not colorize the build output in it's own Terminal for some reason.
QProcess doesn't interfere with the process output, it's just that gcc - as many other programs that emit colored output - by default emit color escape sequences only when it detects that it's writing on a TTY device.
If you want to disable this heuristic and ask to always produce colored output, you have to add the -fdiagnostics-color=always option to the compiler command line.
Thanks to a very insightful answer to my question, I was able to find a solution to my problem. I will share...
QProcess is not at fault nor is QString. The problem lies in the environment the programs are executed. Since the output for these programs (gcc etc) is not connected to a TTY device, all ANSI escape sequences are stripped. There is a way to trick the output to appear as if it were connected to a TTY device though.
Just prepend unbuffer to the command.
Since my use is actually creating a Qt Creator plugin, I was already linking against much of the Qt Creator source code. It just so happens a handy class named AnsiEscapeCodeHandler already exists to convert ANSI escape sequences into QTextCharFormat's and corresponding ANSI escaped sequence stripped strings.
To illustrate how I used this class, but now in my example, I will just copy the ansieescapecodehandler.h and ansiescapecodehandler.cpp to my test project from the downloadable Qt Creator source code. I had to delete a few lines from the AnsiEscapeCodeHandler source files to compile outside the context of the rest of the Qt Creator source, but that was it.
The new source file...
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QProcess>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList input = {"unbuffer gcc will_not_build.c"};
QProcess * proc = new QProcess();
proc->setReadChannel(QProcess::StandardOutput);
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->setWorkingDirectory("/path/to/test/c/file/");
//Start bash
proc->start("bash");
proc->waitForStarted();
// Write as many commands to this process as needed
foreach(QString str, input){
proc->write(str.toUtf8() + "\n");
proc->waitForBytesWritten(-1);
}
// Let bash close gracefully
proc->write("exit $?\n");
proc->waitForBytesWritten(-1);
proc->closeWriteChannel();
proc->waitForFinished();
proc->waitForReadyRead();
QByteArray read_data = proc->readAll();
// The use of tr(read_data) also works here.
QString output = tr(read_data);//QString::fromStdString (read_data.toStdString ());
proc->closeReadChannel(QProcess::StandardOutput);
proc->close();
delete proc;
// Strip default character set escape sequences, since those seem to be left
// See https://stackoverflow.com/questions/36279015/what-does-x1bb-do
output.remove("\x1b(B", Qt::CaseInsensitive);
// Since it is just one single text stream define here instead of globally
Utils::AnsiEscapeCodeHandler ansi_handler;
FormattedTextList result = ansi_handler.parseText (Utils::FormattedText(output, ui->textEdit->currentCharFormat ()));
// Loop through the text/format results
foreach(Utils::FormattedText ft, result){
ui->textEdit->setCurrentCharFormat (ft.format);
ui->textEdit->insertPlainText (ft.text);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
The new header file...
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// This exists in the qtcreator-src code and handles ansi escape code color parsing
#include "ansiescapecodehandler.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
typedef QList<Utils::FormattedText> FormattedTextList;
};
#endif // MAINWINDOW_H
The new colorized output...
QProcess gcc output
Related
SCSS-Mixin SVG works with color keyword, but not with hex-color or variable
Mixin using color variable or hex color code does not work, but works with color constant Tried in React with webpack dev server and babel, also in codepen https://codepen.io/wfpjwporefow/pen/bGbPoEL #mixin telegram-mixin($color) { background-image: url('data:image/svg+xml;utf8,<svg fill="#{$color}" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><path d="M18.384,22.779c0.322,0.228 0.737,0.285 1.107,0.145c0.37,-0.141 0.642,-0.457 0.724,-0.84c0.869,-4.084 2.977,-14.421 3.768,-18.136c0.06,-0.28 -0.04,-0.571 -0.26,-0.758c-0.22,-0.187 -0.525,-0.241 -0.797,-0.14c-4.193,1.552 -17.106,6.397 -22.384,8.35c-0.335,0.124 -0.553,0.446 -0.542,0.799c0.012,0.354 0.25,0.661 0.593,0.764c2.367,0.708 5.474,1.693 5.474,1.693c0,0 1.452,4.385 2.209,6.615c0.095,0.28 0.314,0.5 0.603,0.576c0.288,0.075 0.596,-0.004 0.811,-0.207c1.216,-1.148 3.096,-2.923 3.096,-2.923c0,0 3.572,2.619 5.598,4.062Zm-11.01,-8.677l1.679,5.538l0.373,-3.507c0,0 6.487,-5.851 10.185,-9.186c0.108,-0.098 0.123,-0.262 0.033,-0.377c-0.089,-0.115 -0.253,-0.142 -0.376,-0.064c-4.286,2.737 -11.894,7.596 -11.894,7.596Z"/></svg>'); } $light-highlight: #283044; // works .icon { #include telegram-mixin(red); } // does not work .icon { #include telegram-mixin($light-highlight); } // does not work .icon { #include telegram-mixin(#ffffff); } I want to use a mixin to set a svg background in a specific color. Only works with color constants like red, blue, black, ... I do not get any error messages, my linter is happy, the svg is just not visible.
Your hash needs to be encoded, like this: .icon { #include telegram-mixin("%23ffffff"); } That said, you should encode the entire thing. Not all browsers can read unencoded inline data URI, so encoding it will ensure cross-browser compatibility. Here's a site that'll encode: https://yoksel.github.io/url-encoder/ You can also encode via Sass functions. Here's an example: https://codepen.io/sodapop/pen/PKMwyN
Command writing to standard error does not produce output to ccnet project report?
I wrote a small c program like this: #include<stdio.h> #include<windows.h> void main() { fputs("test\r\n", stderr); fflush(stderr); ExitProcess(-1); } and included it like this in ccnet.config: <project name="foobar"> <tasks> <exec> <executable>C:\temp\test.exe</executable> </exec> </tasks> </project> When I forced the foobar project, I got not output whatsoever in the project report. Why? I may also mention that if I deliberately misspell the exe-filename, I get an exception (which I appreciate). Edit: When debugging CruiseControl.NET, writing a test that tries to run the exe file that looks like this [Test] public void FooTest() { const string xml = "<exec executable=\"C:\\temp\\test.exe\"><buildArgs></buildArgs></exec>"; task = (ExecutableTask) NetReflector.Read(xml); var result = (IntegrationResult) IntegrationResult(); result.Label = "1.0"; result.BuildCondition = BuildCondition.ForceBuild; result.WorkingDirectory = #"c:\temp\"; result.ArtifactDirectory = #"c:\temp\"; task.Run(result); Assert.AreEqual(IntegrationStatus.Failure, result.Status); Assert.IsFalse(task.WasSuccessful); var firstTaskResult = (ProcessTaskResult)result.TaskResults[0]; Debug.WriteLine(firstTaskResult.Data); } The debug console will output xml like this: <buildresults> <task> <buildArgs /> <buildTimeoutSeconds>600</buildTimeoutSeconds> <baseDirectory /> <dynamicValues /> <environment /> <executable>C:\temp\test.exe</executable> <priority>Normal</priority> <successExitCodes /> </task> <message level="Error">test</message> </buildresults> (note, I did beautify this xml before adding it here).
snippet for scss files not working properly
i am creating a snippet for my sass file. here is my snippet <snippet> <content><![CDATA[ #include mobLo { } #include mobileHi { } #include tablet { } #include laptop { } #include desktop { ${} } ]]></content> <tabTrigger>sres</tabTrigger> <scope>scss</scope> </snippet> Now i have saved it in packages folder under different folder like packages>mySnippets But somehow it dosen;t work. Is my Scope right? Thanks.
The scope should probably be source.scss. You can check scope by going to an example file where you would want to use the snippet and hit command + alt + p on Mac and looking in the lower left area. I just noticed that you also have a $ in your snippet. As it says here in the docs under "content", you need to escape all $ with a slash (\). Therefore, it should be like this: <snippet> <content><![CDATA[ #include mobLo { } #include mobileHi { } #include tablet { } #include laptop { } #include desktop { \${} } ]]></content> <tabTrigger>sres</tabTrigger> <scope>source.scss</scope> </snippet>
the scope needs to be source.sass and you need to number your template parameters: ${1} or ${1:placeholder}
Qt 5.3.2 on i.MX6 using Yocto: problems with QML WebView
I am trying to compile Qt 5.3.2 for i.MX6, using Yocto. I am using the dizzy branches of both fsl-community-bsp and meta-qt5. The compilation succeeds, I compile meta-toolchain-qt5 and I configure QtCreator... actually I am able to run minimal Qt applications (both widget-based and QML-based). My problem comes when I want to use the QML WebView element... In such a scenario the application crashes with various (random?) errors: SIGILL, SIGABRT, pointer exceptions and so on... as if someone is overwriting the code memory with garbage... Here it the full stacktrace (taken from QtCreator): My source code is very simple... my main.cpp is the following: #include <QApplication> #include <QQuickView> int main(int argc, char *argv[]) { QApplication app(argc, argv); QQuickView view; view.setSource(QUrl("qrc:/main.qml")); view.showFullScreen(); return app.exec(); } My main.qml is the following: import QtQuick 2.3 import QtWebKit 3.0 Rectangle { visible: true x: 0 y: 0 width: 480 height: 272 Text { text: qsTr("Hello World") x: 0 y: 0 } WebView { id: webview width: 480 height: 272 url: "qrc:/test.html" x: 0 y: 0 } } test.html is a standard HTML page (only some sample text in it)... If I remove WebView from my QML the application works fine... Any ideas about what is causing the problem? Does someone else has similar problems? If it helps, please consider that using Yocto I have compiled the image named fsl-image-multimedia-full and all Yocto and meta-qt5 files are unchanged, except for the fact that I made some modifications to avoid compiling Qt examples, to exclude xcb and dbus support and to include sqlite support.
Ok, I've found a working solution... Playing with framebuffer settings, I've succeeded in making my test working passing fbpix=BGR32 to the kernel command line... My command line is now: console=ttymxc3,115200n8 root=/dev/mmcblk0p2 rootwait rw video=mxcfb0:dev=lcd,SAMSUNG-LMS700,if=RGB24,fbpix=BGR32 splash consoleblank=0 video=mxcfb1:off video=mxcfb2:off and it does work!
How do I use a compass-generated sprite for generated content?
Is it possible to use a compass-generated sprite to replace the icon path below? a:before { content: url(/pathto/icon.png); } Although I can work out how to get the sprite path in there, I don't know if it's possible to get the correct bit of the sprite showing.
Don't load the sprite map as "content". Set content to " ", load the sprite as a background, and control it the way you would with any other text/image-replacement sprite. a:before { #include <map>-sprite(<icon>); #include sprite-dimensions(<map>, <icon>); content: " "; } Where <map> and <icon> are replaced by your specific sprite-map and icon names.