artisticstylesettings.cpp 7.72 KB
Newer Older
1
/****************************************************************************
Lorenz Haas's avatar
Lorenz Haas committed
2
**
3 4
** Copyright (C) 2016 Lorenz Haas
** Contact: https://www.qt.io/licensing/
Lorenz Haas's avatar
Lorenz Haas committed
5 6 7 8 9 10 11
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
Lorenz Haas's avatar
Lorenz Haas committed
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
Lorenz Haas's avatar
Lorenz Haas committed
23 24 25 26 27 28 29 30 31 32 33
**
****************************************************************************/

#include "artisticstylesettings.h"

#include "artisticstyleconstants.h"

#include "../beautifierconstants.h"

#include <coreplugin/icore.h>

Eike Ziller's avatar
Eike Ziller committed
34
#include <utils/runextensions.h>
35
#include <utils/synchronousprocess.h>
36

Lorenz Haas's avatar
Lorenz Haas committed
37 38 39
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
Lorenz Haas's avatar
Lorenz Haas committed
40
#include <QRegularExpression>
Lorenz Haas's avatar
Lorenz Haas committed
41 42 43 44 45 46 47
#include <QXmlStreamWriter>

namespace Beautifier {
namespace Internal {
namespace ArtisticStyle {

namespace {
48 49 50 51
const char USE_OTHER_FILES[]  = "useOtherFiles";
const char USE_HOME_FILE[]    = "useHomeFile";
const char USE_CUSTOM_STYLE[] = "useCustomStyle";
const char CUSTOM_STYLE[]     = "customStyle";
Lorenz Haas's avatar
Lorenz Haas committed
52 53 54
}

ArtisticStyleSettings::ArtisticStyleSettings() :
55
    AbstractSettings(Constants::ArtisticStyle::SETTINGS_NAME, ".astyle")
Lorenz Haas's avatar
Lorenz Haas committed
56
{
57 58
    connect(&m_versionWatcher, &QFutureWatcherBase::finished,
            this, &ArtisticStyleSettings::helperSetVersion);
59

60 61 62 63 64
    setCommand("astyle");
    m_settings.insert(USE_OTHER_FILES, QVariant(true));
    m_settings.insert(USE_HOME_FILE, QVariant(false));
    m_settings.insert(USE_CUSTOM_STYLE, QVariant(false));
    m_settings.insert(CUSTOM_STYLE, QVariant());
Lorenz Haas's avatar
Lorenz Haas committed
65 66 67
    read();
}

68 69 70
static int parseVersion(const QString &text)
{
    // The version in Artistic Style is printed like "Artistic Style Version 2.04"
Lorenz Haas's avatar
Lorenz Haas committed
71 72 73 74 75
    const QRegularExpression rx("([2-9]{1})\\.([0-9]{2})(\\.[1-9]{1})?$");
    const QRegularExpressionMatch match = rx.match(text);
    if (match.hasMatch()) {
        const int major = match.capturedRef(1).toInt() * 100;
        const int minor = match.capturedRef(2).toInt();
76 77 78 79 80
        return major + minor;
    }
    return 0;
}

81
static int updateVersionHelper(const QString &command)
82
{
83 84
    Utils::SynchronousProcess process;
    Utils::SynchronousProcessResponse response
85
            = process.runBlocking(command, QStringList("--version"));
86
    if (response.result != Utils::SynchronousProcessResponse::Finished)
87
        return 0;
88

89
    // Astyle prints the version on stdout or stderr, depending on platform
90
    const int version = parseVersion(response.stdOut().trimmed());
91
    if (version != 0)
92
        return version;
93
    return parseVersion(response.stdErr().trimmed());
94 95 96 97 98 99 100 101 102
}

void ArtisticStyleSettings::updateVersion()
{
    if (m_versionFuture.isRunning())
        m_versionFuture.cancel();

    m_versionFuture = Utils::runAsync(updateVersionHelper, command());
    m_versionWatcher.setFuture(m_versionFuture);
103 104 105 106 107 108 109
}

void ArtisticStyleSettings::helperSetVersion()
{
    m_version = m_versionWatcher.result();
}

Lorenz Haas's avatar
Lorenz Haas committed
110 111
bool ArtisticStyleSettings::useOtherFiles() const
{
112
    return m_settings.value(USE_OTHER_FILES).toBool();
Lorenz Haas's avatar
Lorenz Haas committed
113 114 115 116
}

void ArtisticStyleSettings::setUseOtherFiles(bool useOtherFiles)
{
117
    m_settings.insert(USE_OTHER_FILES, QVariant(useOtherFiles));
Lorenz Haas's avatar
Lorenz Haas committed
118 119 120 121
}

bool ArtisticStyleSettings::useHomeFile() const
{
122
    return m_settings.value(USE_HOME_FILE).toBool();
Lorenz Haas's avatar
Lorenz Haas committed
123 124 125 126
}

void ArtisticStyleSettings::setUseHomeFile(bool useHomeFile)
{
127
    m_settings.insert(USE_HOME_FILE, QVariant(useHomeFile));
Lorenz Haas's avatar
Lorenz Haas committed
128 129 130 131
}

bool ArtisticStyleSettings::useCustomStyle() const
{
132
    return m_settings.value(USE_CUSTOM_STYLE).toBool();
Lorenz Haas's avatar
Lorenz Haas committed
133 134 135 136
}

void ArtisticStyleSettings::setUseCustomStyle(bool useCustomStyle)
{
137
    m_settings.insert(USE_CUSTOM_STYLE, QVariant(useCustomStyle));
Lorenz Haas's avatar
Lorenz Haas committed
138 139 140 141
}

QString ArtisticStyleSettings::customStyle() const
{
142
    return m_settings.value(CUSTOM_STYLE).toString();
Lorenz Haas's avatar
Lorenz Haas committed
143 144 145 146
}

void ArtisticStyleSettings::setCustomStyle(const QString &customStyle)
{
147
    m_settings.insert(CUSTOM_STYLE, QVariant(customStyle));
Lorenz Haas's avatar
Lorenz Haas committed
148 149 150 151
}

QString ArtisticStyleSettings::documentationFilePath() const
{
152 153 154
    return Core::ICore::userResourcePath() + '/' + Beautifier::Constants::SETTINGS_DIRNAME + '/'
            + Beautifier::Constants::DOCUMENTATION_DIRNAME + '/'
            + Constants::ArtisticStyle::SETTINGS_NAME + ".xml";
Lorenz Haas's avatar
Lorenz Haas committed
155 156 157 158
}

void ArtisticStyleSettings::createDocumentationFile() const
{
159 160 161
    Utils::SynchronousProcess process;
    process.setTimeoutS(2);
    Utils::SynchronousProcessResponse response
162
            = process.runBlocking(command(), QStringList("-h"));
163
    if (response.result != Utils::SynchronousProcessResponse::Finished)
164 165
        return;

Lorenz Haas's avatar
Lorenz Haas committed
166 167 168 169 170 171 172
    QFile file(documentationFilePath());
    const QFileInfo fi(file);
    if (!fi.exists())
        fi.dir().mkpath(fi.absolutePath());
    if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
        return;

173
    bool contextWritten = false;
Lorenz Haas's avatar
Lorenz Haas committed
174 175
    QXmlStreamWriter stream(&file);
    stream.setAutoFormatting(true);
176 177 178
    stream.writeStartDocument("1.0", true);
    stream.writeComment("Created " + QDateTime::currentDateTime().toString(Qt::ISODate));
    stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT);
Lorenz Haas's avatar
Lorenz Haas committed
179 180

    // astyle writes its output to 'error'...
181
    const QStringList lines = response.stdErr().split(QLatin1Char('\n'));
Lorenz Haas's avatar
Lorenz Haas committed
182 183
    QStringList keys;
    QStringList docu;
184
    for (QString line : lines) {
185
        line = line.trimmed();
186 187 188
        if ((line.startsWith("--") && !line.startsWith("---")) || line.startsWith("OR ")) {
            const QStringList rawKeys = line.split(" OR ", QString::SkipEmptyParts);
            for (QString k : rawKeys) {
Lorenz Haas's avatar
Lorenz Haas committed
189
                k = k.trimmed();
190
                k.remove('#');
Lorenz Haas's avatar
Lorenz Haas committed
191
                keys << k;
192
                if (k.startsWith("--"))
Lorenz Haas's avatar
Lorenz Haas committed
193 194 195 196 197 198
                    keys << k.right(k.size() - 2);
            }
        } else {
            if (line.isEmpty()) {
                if (!keys.isEmpty()) {
                    // Write entry
199 200 201 202
                    stream.writeStartElement(Constants::DOCUMENTATION_XMLENTRY);
                    stream.writeStartElement(Constants::DOCUMENTATION_XMLKEYS);
                    for (const QString &key : keys)
                        stream.writeTextElement(Constants::DOCUMENTATION_XMLKEY, key);
Lorenz Haas's avatar
Lorenz Haas committed
203
                    stream.writeEndElement();
204
                    const QString text = "<p><span class=\"option\">"
Lorenz Haas's avatar
Lorenz Haas committed
205
                            + keys.filter(QRegularExpression("^\\-")).join(", ") + "</span></p><p>"
206 207
                            + (docu.join(' ').toHtmlEscaped()) + "</p>";
                    stream.writeTextElement(Constants::DOCUMENTATION_XMLDOC, text);
Lorenz Haas's avatar
Lorenz Haas committed
208
                    stream.writeEndElement();
209
                    contextWritten = true;
Lorenz Haas's avatar
Lorenz Haas committed
210 211 212 213 214 215 216 217 218 219 220
                }
                keys.clear();
                docu.clear();
            } else if (!keys.isEmpty()) {
                docu << line;
            }
        }
    }

    stream.writeEndElement();
    stream.writeEndDocument();
221 222 223 224 225 226 227

    // An empty file causes error messages and a contextless file preventing this function to run
    // again in order to generate the documentation successfully. Thus delete the file.
    if (!contextWritten) {
        file.close();
        file.remove();
    }
Lorenz Haas's avatar
Lorenz Haas committed
228 229 230 231 232
}

} // namespace ArtisticStyle
} // namespace Internal
} // namespace Beautifier