1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
46 #include "qcoloroutput_p.h"
48 // TODO: rename insertMapping() to insertColorMapping()
49 // TODO: Use a smart pointer for managing ColorOutputPrivate *d;
50 // TODO: break out the C++ example into a snippet file
52 /* This include must appear here, because if it appears at the beginning of the file for
53 * instance, it breaks build -- "qglobal.h:628: error: template with
54 * C linkage" -- on Mac OS X 10.4. */
61 using namespace QPatternist;
65 class ColorOutputPrivate
68 ColorOutputPrivate() : currentColorID(-1)
71 /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance
72 * is considered of lower priority.
74 m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered);
76 coloringEnabled = isColoringPossible();
79 ColorOutput::ColorMapping colorMapping;
83 static const char *const foregrounds[];
84 static const char *const backgrounds[];
86 inline void write(const QString &msg)
88 m_out.write(msg.toLocal8Bit());
91 static QString escapeCode(const QString &in)
94 result.append(QChar(0x1B));
95 result.append(QLatin1Char('['));
97 result.append(QLatin1Char('m'));
105 Returns true if it's suitable to send colored output to \c stderr.
107 inline bool isColoringPossible() const
109 # if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
110 /* Windows doesn't at all support ANSI escape codes, unless
111 * the user install a "device driver". See the Wikipedia links in the
112 * class documentation for details. */
115 /* We use QFile::handle() to get the file descriptor. It's a bit unsure
116 * whether it's 2 on all platforms and in all cases, so hopefully this layer
117 * of abstraction helps handle such cases. */
118 return isatty(m_out.handle());
124 const char *const ColorOutputPrivate::foregrounds[] =
144 const char *const ColorOutputPrivate::backgrounds[] =
159 \brief Outputs colored messages to \c stderr.
162 ColorOutput is a convenience class for outputting messages to \c
163 stderr using color escape codes, as mandated in ECMA-48. ColorOutput
164 will only color output when it is detected to be suitable. For
165 instance, if \c stderr is detected to be attached to a file instead
166 of a TTY, no coloring will be done.
168 ColorOutput does its best attempt. but it is generally undefined
169 what coloring or effect the various coloring flags has. It depends
170 strongly on what terminal software that is being used.
172 When using `echo -e 'my escape sequence'`, \c{\033} works as an
173 initiator but not when printing from a C++ program, despite having
174 escaped the backslash. That's why we below use characters with
177 It can be convenient to subclass ColorOutput with a private scope,
178 such that the functions are directly available in the class using
183 To output messages, call write() or writeUncolored(). write() takes
184 as second argument an integer, which ColorOutput uses as a lookup
185 key to find the color it should color the text in. The mapping from
186 keys to colors is done using insertMapping(). Typically this is used
187 by having enums for the various kinds of messages, which
188 subsequently are registered.
198 output.insertMapping(Error, ColorOutput::RedForeground);
199 output.insertMapping(Import, ColorOutput::BlueForeground);
201 output.write("This is important", Important);
202 output.write("Jack, I'm only the selected official!", Error);
205 \sa {http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html}{Bash Prompt HOWTO, 6.1. Colours},
206 {http://linuxgazette.net/issue51/livingston-blade.html}{Linux Gazette, Tweaking Eterm, Edward Livingston-Blade},
207 {http://www.ecma-international.org/publications/standards/Ecma-048.htm}{Standard ECMA-48, Control Functions for Coded Character Sets, ECMA International},
208 {http://en.wikipedia.org/wiki/ANSI_escape_code}{Wikipedia, ANSI escape code},
209 {http://linuxgazette.net/issue65/padala.html}{Linux Gazette, So You Like Color!, Pradeep Padala}
213 \enum ColorOutput::ColorCodeComponent
214 \value BlackForeground
215 \value BlueForeground
216 \value GreenForeground
217 \value CyanForeground
219 \value PurpleForeground
220 \value BrownForeground
221 \value LightGrayForeground
222 \value DarkGrayForeground
223 \value LightBlueForeground
224 \value LightGreenForeground
225 \value LightCyanForeground
226 \value LightRedForeground
227 \value LightPurpleForeground
228 \value YellowForeground
229 \value WhiteForeground
230 \value BlackBackground
231 \value BlueBackground
232 \value GreenBackground
233 \value CyanBackground
235 \value PurpleBackground
236 \value BrownBackground
238 \value DefaultColor ColorOutput performs no coloring. This typically
239 means black on white or white on black, depending
240 on the settings of the user's terminal.
244 Sets the color mapping to be \a cMapping.
246 Negative values are disallowed.
248 \sa colorMapping(), insertMapping()
250 void ColorOutput::setColorMapping(const ColorMapping &cMapping)
252 d->colorMapping = cMapping;
256 Returns the color mappings in use.
258 \sa setColorMapping(), insertMapping()
260 ColorOutput::ColorMapping ColorOutput::colorMapping() const
262 return d->colorMapping;
266 Constructs a ColorOutput instance, ready for use.
268 ColorOutput::ColorOutput() : d(new ColorOutputPrivate())
273 Destructs this ColorOutput instance.
275 ColorOutput::~ColorOutput()
281 Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID.
283 If \a color isn't available in colorMapping(), result and behavior is undefined.
285 If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput
286 is initialized to not color at all.
288 If \a message is empty, effects are undefined.
290 \a message will be printed as is. For instance, no line endings will be inserted.
292 void ColorOutput::write(const QString &message, int colorID)
294 d->write(colorify(message, colorID));
298 Writes \a message to \c stderr as if for instance
299 QTextStream would have been used, and adds a line ending at the end.
301 This function can be practical to use such that one can use ColorOutput for all forms of writing.
303 void ColorOutput::writeUncolored(const QString &message)
305 d->write(message + QLatin1Char('\n'));
309 Treats \a message and \a colorID identically to write(), but instead of writing
310 \a message to \c stderr, it is prepared for being written to \c stderr, but is then
313 This is useful when the colored string is inserted into a translated string(dividing
314 the string into several small strings prevents proper translation).
316 QString ColorOutput::colorify(const QString &message, int colorID) const
318 Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO,
319 qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID)));
320 Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string.");
323 d->currentColorID = colorID;
325 if(d->coloringEnabled && colorID != -1)
327 const int color(d->colorMapping.value(colorID));
329 /* If DefaultColor is set, we don't want to color it. */
330 if(color & DefaultColor)
333 const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift;
334 const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift;
335 QString finalMessage;
336 bool closureNeeded = false;
340 finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
341 closureNeeded = true;
346 finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
347 closureNeeded = true;
350 finalMessage.append(message);
354 finalMessage.append(QChar(0x1B));
355 finalMessage.append(QLatin1String("[0m"));
365 Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance.
367 This is a convenience function for creating a ColorOutput::ColorMapping instance and
368 calling setColorMapping().
370 \sa colorMapping(), setColorMapping()
372 void ColorOutput::insertMapping(int colorID, const ColorCode colorCode)
374 d->colorMapping.insert(colorID, colorCode);