diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/textstream.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/textstream.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/sources/shiboken6/ApiExtractor/textstream.cpp b/sources/shiboken6/ApiExtractor/textstream.cpp new file mode 100644 index 000000000..83d981b2b --- /dev/null +++ b/sources/shiboken6/ApiExtractor/textstream.cpp @@ -0,0 +1,263 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "textstream.h" + +#include <cstring> + +TextStream::TextStream(QIODevice *device, Language l) : + m_str(device), m_language(l) +{ +} + +TextStream::TextStream(QString *string, Language l) : + m_str(string), m_language(l) +{ +} + +TextStream::TextStream(QByteArray *array, Language l) : + m_str(array), m_language(l) +{ +} + +TextStream::~TextStream() = default; + +QChar TextStream::lastChar() const +{ + auto s = m_str.string(); + return s != nullptr && !s->isEmpty() ? *(s->crbegin()) : QChar(); +} + +void TextStream::setIndentation(int i) +{ + Q_ASSERT(i >= 0); + m_indentation = i; +} + +void TextStream::outdent(int n) +{ + m_indentation -= n; + Q_ASSERT(m_indentation >= 0); +} + +qint64 TextStream::pos() const +{ + // QTextStream::pos() only works for QIODevice, be a bit smarter + if (auto s = m_str.string()) + return s->size(); + // QIODevices need to flushed to tell the correct position. + const_cast<QTextStream &>(m_str).flush(); + return m_str.pos(); +} + +void TextStream::setString(QString *string, QIODeviceBase::OpenMode openMode) +{ + m_str.setString(string, openMode); + m_rstFormattingEnd = false; +} + +void TextStream::putRepetitiveChars(char c, int count) +{ + if (count > 0) { + for (int i = 0; i < count; ++i) { + const int ofw = m_str.fieldWidth(); + m_str.setFieldWidth(0); + m_str << c; + m_str.setFieldWidth(ofw); + } + } +} + +void TextStream::_setRstFormattingEnd() +{ + m_rstFormattingEnd = true; +} + +void TextStream::setLastCharClass(CharClass c) +{ + m_lastCharClass = c; +} + +void TextStream::writeIndent() +{ + putRepetitiveChars(' ', m_indentation * m_tabWidth); +} + +// Indent handling: If the last character was a new line +// and the upcoming one is none, indent the stream +// Special case for C++ : If the upcoming char is a '#', we don't +// indent (preprocessor directive). + +template <class Char> +static TextStream::CharClass charClassHelper(Char c) +{ + switch (c) { + case '\n': + return TextStream::CharClass::NewLine; + case '#': + return TextStream::CharClass::Hash; + case ' ': + case '\t': + return TextStream::CharClass::Space; + case '\\': + return TextStream::CharClass::BackSlash; + default: + break; + } + return TextStream::CharClass::Other; +} + +static inline TextStream::CharClass charClass(char c) +{ return charClassHelper(c); } + +static inline TextStream::CharClass charClass(QChar c) +{ return charClassHelper(c.unicode()); } + +void TextStream::checkIndent(CharClass upComingCharClass) +{ + if (m_rstFormattingEnd) { + if (upComingCharClass != CharClass::Space && upComingCharClass != CharClass::NewLine + && upComingCharClass != CharClass::BackSlash) { + m_str << '\\'; + } + m_rstFormattingEnd = false; + } + if (m_indentationEnabled && m_lastCharClass == CharClass::NewLine + && (upComingCharClass != CharClass::NewLine + && (m_language != Language::Cpp || upComingCharClass != CharClass::Hash))) { + writeIndent(); + } + m_lastCharClass = upComingCharClass; +} + +template <class Char> +void TextStream::putCharHelper(Char c) +{ + const auto klass = charClass(c); + checkIndent(klass); + m_str << c; +} + +void TextStream::putString(QStringView v) +{ + if (v.isEmpty()) + return; + if (v.contains(u'\n')) { + for (auto c : v) + putCharHelper(c); + } else { + // If there is no newline, write as a blob. This is important to make + // field formatting (alignment/width) working, else each char will be + // considered a field. + const auto klass = charClass(*v.cbegin()); + checkIndent(klass); + m_str << v; + m_lastCharClass = CharClass::Other; + } +} + +void TextStream::putChar(QChar c) +{ + putCharHelper(c); +} + +void TextStream::putString(const char *s) +{ + const char firstChar = *s; + if (firstChar == '\0') + return; + if (std::strchr(s, '\n') != nullptr) { // See above + for ( ; *s; ++s) + putCharHelper(*s); + } else { + checkIndent(charClass(firstChar)); + m_str << s; + m_lastCharClass = CharClass::Other; + } +} + +void TextStream::putChar(char c) +{ + putCharHelper(c); +} + +void TextStream::putInt(int t) +{ + checkIndent(CharClass::Other); + m_str << t; +} + +void TextStream::putSizeType(qsizetype t) +{ + checkIndent(CharClass::Other); + m_str << t; +} + +StringStream::StringStream(Language l) : TextStream(&m_buffer, l) +{ +} + +void StringStream::clear() +{ + m_buffer.clear(); + setLastCharClass(CharClass::NewLine); +} + +void indent(TextStream &s) +{ + s.indent(); +} + +void outdent(TextStream &s) +{ + s.outdent(); +} + +void enableIndent(TextStream &s) +{ + s.setIndentationEnabled(true); +} + +void disableIndent(TextStream &s) +{ + s.setIndentationEnabled(false); +} + +void ensureEndl(TextStream &s) +{ + if (s.lastChar() != u'\n') + s << '\n'; +} + +void rstBold(TextStream &s) +{ + s.putRawString("**"); +} + +void rstBoldOff(TextStream &s) +{ + s.putRawString("**"); + s._setRstFormattingEnd(); +} + +void rstItalic(TextStream &s) +{ + s.putRawChar('*'); +} + +void rstItalicOff(TextStream &s) +{ + s.putRawChar('*'); + s._setRstFormattingEnd(); +} + +void rstCode(TextStream &s) +{ + s.putRawString("``"); +} + +void rstCodeOff(TextStream &s) +{ + s.putRawString("``"); + s._setRstFormattingEnd(); +} |