linuxbashqtqprocessansi-escape

Keep ANSI Escape Sequences in QProcess Output


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.


Solution

  • 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.