qmltoolings add --dry-run option for qmlformat and qmllint
Add reportConfigForFiles to generic tooling class. It will perform the search for the given files. Use stdout to report. qmllint had already an option --dry-run for printing the fixed codes, but we can still allow this to use that option name. For qmlls, report the path if verbose option is set. Fixes: QTBUG-137874 Change-Id: I6bd43866073b3df832b6fd89d477bced869d74c0 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
141993c0a5
commit
e3891d7459
|
@ -188,6 +188,13 @@ QQmlFormatOptions QQmlFormatOptions::buildCommandLineOptions(const QStringList &
|
|||
"rule"_L1, "always"_L1);
|
||||
parser.addOption(semicolonRuleOption);
|
||||
|
||||
QCommandLineOption dryrunOption(
|
||||
QStringList() << "dry-run"_L1,
|
||||
QStringLiteral("Prints the settings file that would be used for this instance."
|
||||
"This is useful to see what settings would be used "
|
||||
"without actually performing anything."));
|
||||
parser.addOption(dryrunOption);
|
||||
|
||||
parser.addPositionalArgument("filenames"_L1, "files to be processed by qmlformat"_L1);
|
||||
|
||||
parser.process(args);
|
||||
|
@ -250,6 +257,7 @@ QQmlFormatOptions QQmlFormatOptions::buildCommandLineOptions(const QStringList &
|
|||
}
|
||||
}
|
||||
|
||||
options.setDryRun(parser.isSet(dryrunOption));
|
||||
options.setIsVerbose(parser.isSet("verbose"_L1));
|
||||
options.setIsInplace(parser.isSet("inplace"_L1));
|
||||
options.setForceEnabled(parser.isSet("force"_L1));
|
||||
|
@ -322,7 +330,7 @@ QQmlFormatOptions QQmlFormatOptions::optionsForFile(const QString &fileName,
|
|||
if (hasFiles)
|
||||
perFileOptions.setIsInplace(true);
|
||||
|
||||
if (!ignoreSettingsEnabled() && settings->search(fileName).isValid())
|
||||
if (!ignoreSettingsEnabled() && settings->search(fileName, { m_verbose }).isValid())
|
||||
perFileOptions.applySettings(*settings);
|
||||
|
||||
return perFileOptions;
|
||||
|
|
|
@ -126,6 +126,8 @@ public:
|
|||
|
||||
bool indentWidthSet() const { return m_indentWidthSet; }
|
||||
void setIndentWidthSet(bool newIndentWidthSet) { m_indentWidthSet = newIndentWidthSet; }
|
||||
bool dryRun() const { return m_dryRun; }
|
||||
void setDryRun(bool newDryRun) { m_dryRun = newDryRun; }
|
||||
QStringList errors() const { return m_errors; }
|
||||
void addError(const QString &newError) { m_errors.append(newError); };
|
||||
|
||||
|
@ -171,6 +173,7 @@ private:
|
|||
bool m_writeDefaultSettings = false;
|
||||
bool m_indentWidthSet = false;
|
||||
std::bitset<SettingsCount> m_settingBits;
|
||||
bool m_dryRun = false;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -301,6 +301,7 @@ int qmllsMain(int argv, char *argc[])
|
|||
if (parser.isSet(writeDefaultsOption)) {
|
||||
return settings.writeDefaults() ? 0 : 1;
|
||||
}
|
||||
|
||||
if (parser.isSet(logFileOption)) {
|
||||
QString fileName = parser.value(logFileOption);
|
||||
qInfo() << "will log to" << fileName;
|
||||
|
@ -319,8 +320,6 @@ int qmllsMain(int argv, char *argc[])
|
|||
logFile->flush();
|
||||
});
|
||||
}
|
||||
if (parser.isSet(verboseOption))
|
||||
QLoggingCategory::setFilterRules("qt.languageserver*.debug=true\n"_L1);
|
||||
if (parser.isSet(waitOption)) {
|
||||
int waitSeconds = parser.value(waitOption).toInt();
|
||||
if (waitSeconds > 0)
|
||||
|
@ -337,6 +336,10 @@ int qmllsMain(int argv, char *argc[])
|
|||
},
|
||||
(parser.isSet(ignoreSettings) ? nullptr : &settings));
|
||||
|
||||
if (parser.isSet(verboseOption)) {
|
||||
QLoggingCategory::setFilterRules("qt.languageserver*.debug=true\n"_L1);
|
||||
qmlServer.codeModelManager()->setVerbose(true);
|
||||
}
|
||||
if (parser.isSet(docDir))
|
||||
qmlServer.codeModelManager()->setDocumentationRootPath(
|
||||
QString::fromUtf8(parser.value(docDir).toUtf8()));
|
||||
|
|
|
@ -277,7 +277,7 @@ void QQmlCodeModel::initializeCMakeStatus(const QString &pathForSettings)
|
|||
{
|
||||
if (m_settings) {
|
||||
const QString cmakeCalls = u"no-cmake-calls"_s;
|
||||
m_settings->search(pathForSettings);
|
||||
m_settings->search(pathForSettings, { m_verbose });
|
||||
if (m_settings->isSet(cmakeCalls) && m_settings->value(cmakeCalls).toBool()) {
|
||||
qWarning() << "Disabling CMake calls via .qmlls.ini setting.";
|
||||
m_cmakeStatus = DoesNotHaveCMake;
|
||||
|
@ -553,7 +553,8 @@ QStringList QQmlCodeModel::importPathsForUrl(const QByteArray &url)
|
|||
QStringList result = importPaths();
|
||||
|
||||
const QString importPaths = u"importPaths"_s;
|
||||
if (m_settings && m_settings->search(fileName).isValid() && m_settings->isSet(importPaths)) {
|
||||
if (m_settings && m_settings->search(fileName, { m_verbose }).isValid()
|
||||
&& m_settings->isSet(importPaths)) {
|
||||
result.append(m_settings->value(importPaths).toString().split(QDir::listSeparator()));
|
||||
}
|
||||
|
||||
|
@ -628,7 +629,7 @@ QStringList QQmlCodeModel::buildPathsForFileUrl(const QByteArray &url)
|
|||
// look in the settings.
|
||||
// This is the one that is passed via the .qmlls.ini file.
|
||||
if (buildPaths.isEmpty() && m_settings) {
|
||||
m_settings->search(path);
|
||||
m_settings->search(path, { m_verbose });
|
||||
QString buildDir = QStringLiteral(u"buildDir");
|
||||
if (m_settings->isSet(buildDir))
|
||||
buildPaths += m_settings->value(buildDir).toString().split(QDir::listSeparator(),
|
||||
|
|
|
@ -135,6 +135,9 @@ public:
|
|||
QSet<QString> ignoreForWatching() const { return m_ignoreForWatching; }
|
||||
HelpManager *helpManager() { return &m_helpManager; }
|
||||
|
||||
void setVerbose(bool verbose) { m_verbose = verbose; }
|
||||
bool verbose() const { return m_verbose; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void updatedSnapshot(const QByteArray &url);
|
||||
void documentationRootPathChanged(const QString &path);
|
||||
|
@ -174,6 +177,7 @@ private:
|
|||
QString m_documentationRootPath;
|
||||
QSet<QString> m_ignoreForWatching;
|
||||
HelpManager m_helpManager;
|
||||
bool m_verbose = false;
|
||||
private slots:
|
||||
void onCppFileChanged(const QString &);
|
||||
};
|
||||
|
|
|
@ -242,6 +242,13 @@ void QQmlCodeModelManager::setDocumentationRootPath(const QString &path)
|
|||
ws.codeModel->setDocumentationRootPath(path);
|
||||
}
|
||||
|
||||
void QQmlCodeModelManager::setVerbose(bool verbose)
|
||||
{
|
||||
m_verbose = verbose;
|
||||
for (const auto &ws : m_workspaces)
|
||||
ws.codeModel->setVerbose(verbose);
|
||||
}
|
||||
|
||||
void QQmlCodeModelManager::setBuildPathsForRootUrl(const QByteArray &url, const QStringList &paths)
|
||||
{
|
||||
m_buildInformation.loadSettingsFrom(paths);
|
||||
|
|
|
@ -71,6 +71,8 @@ public:
|
|||
void setDocumentationRootPath(const QString &path);
|
||||
HelpManager *helpManagerForUrl(const QByteArray &);
|
||||
|
||||
void setVerbose(bool verbose);
|
||||
|
||||
protected:
|
||||
using Workspaces = std::vector<QQmlWorkspace>;
|
||||
using WorkspaceIterator = Workspaces::const_iterator;
|
||||
|
@ -96,6 +98,7 @@ protected:
|
|||
QStringList m_defaultImportPaths;
|
||||
bool m_defaultDisableCMakeCalls = false;
|
||||
QString m_defaultDocumentationRootPath;
|
||||
bool m_verbose = false;
|
||||
|
||||
Q_SIGNALS:
|
||||
void updatedSnapshot(const QByteArray &url);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qset.h>
|
||||
#include <QtCore/qtextstream.h>
|
||||
#if QT_CONFIG(settings)
|
||||
#include <QtCore/qsettings.h>
|
||||
#endif
|
||||
|
@ -161,8 +162,13 @@ QQmlToolingSettings::SearchResult QQmlToolingSettings::Searcher::search(const QS
|
|||
return SearchResult();
|
||||
}
|
||||
|
||||
QQmlToolingSettings::SearchResult QQmlToolingSettings::search(const QString &path)
|
||||
QQmlToolingSettings::SearchResult QQmlToolingSettings::search(const QString &path, SearchOptions options)
|
||||
{
|
||||
const auto maybeReport = qScopeGuard([&]() {
|
||||
if (options.verbose)
|
||||
reportConfigForFiles({ path });
|
||||
});
|
||||
|
||||
if (const SearchResult result = m_searcher.search(path); result.isValid())
|
||||
return read(result.iniFilePath);
|
||||
|
||||
|
@ -184,3 +190,48 @@ bool QQmlToolingSettings::isSet(const QString &name) const
|
|||
// Unset is encoded as an empty string
|
||||
return !(variant.canConvert(QMetaType(QMetaType::QString)) && variant.toString().isEmpty());
|
||||
}
|
||||
|
||||
bool QQmlToolingSettings::reportConfigForFiles(const QStringList &files)
|
||||
{
|
||||
constexpr int maxAllowedFileLength = 255;
|
||||
constexpr int minAllowedFileLength = 40;
|
||||
bool headerPrinted = false;
|
||||
auto lengthForFile = [maxAllowedFileLength](const QString &file) {
|
||||
return std::min(int(file.length()), maxAllowedFileLength);
|
||||
};
|
||||
|
||||
int maxFileLength =
|
||||
std::accumulate(files.begin(), files.end(), 0, [&](int acc, const QString &file) {
|
||||
return std::max(acc, lengthForFile(file));
|
||||
});
|
||||
|
||||
if (maxFileLength < minAllowedFileLength)
|
||||
maxFileLength = minAllowedFileLength;
|
||||
|
||||
for (const auto &file : files) {
|
||||
if (file.isEmpty()) {
|
||||
qWarning().noquote() << "Error: Could not find file" << file;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString displayFile = file;
|
||||
if (displayFile.length() > maxAllowedFileLength) {
|
||||
displayFile = "..." + displayFile.right(maxAllowedFileLength - 3);
|
||||
}
|
||||
|
||||
const auto result = search(file);
|
||||
|
||||
if (!headerPrinted) {
|
||||
QString header =
|
||||
QStringLiteral("%1 | %2").arg("File", -maxFileLength).arg("Settings File");
|
||||
qWarning().noquote() << header;
|
||||
qWarning().noquote() << QString(header.length(), u'-');
|
||||
headerPrinted = true;
|
||||
}
|
||||
QString line =
|
||||
QStringLiteral("%1 | %2").arg(displayFile, -maxFileLength).arg(result.iniFilePath);
|
||||
qWarning().noquote() << line;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ QT_BEGIN_NAMESPACE
|
|||
class QQmlToolingSettings
|
||||
{
|
||||
public:
|
||||
QQmlToolingSettings(const QString &toolName);
|
||||
struct SearchOptions
|
||||
{
|
||||
bool verbose;
|
||||
};
|
||||
struct SearchResult
|
||||
{
|
||||
enum class ResultType { Found, NotFound };
|
||||
|
@ -56,16 +61,15 @@ public:
|
|||
QHash<QString, QString> m_seenDirectories;
|
||||
};
|
||||
|
||||
QQmlToolingSettings(const QString &toolName);
|
||||
|
||||
void addOption(const QString &name, const QVariant defaultValue = QVariant());
|
||||
|
||||
SearchResult search(const QString &path, SearchOptions options = {});
|
||||
bool writeDefaults() const;
|
||||
SearchResult search(const QString &path);
|
||||
|
||||
QVariant value(const QString &name) const;
|
||||
bool isSet(const QString &name) const;
|
||||
|
||||
bool reportConfigForFiles(const QStringList &files);
|
||||
|
||||
private:
|
||||
QString m_currentSettingsPath;
|
||||
QVariantHash m_values;
|
||||
|
@ -91,10 +95,10 @@ public:
|
|||
return QQmlToolingSettings::writeDefaults();
|
||||
}
|
||||
|
||||
SearchResult search(const QString &path)
|
||||
SearchResult search(const QString &path, SearchOptions options = {})
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
return QQmlToolingSettings::search(path);
|
||||
return QQmlToolingSettings::search(path, options);
|
||||
}
|
||||
|
||||
QVariant value(const QString &name) const
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtTest/QTest>
|
||||
#include <QtLogging>
|
||||
|
||||
#include <QtQmlToolingSettings/private/qqmltoolingsettings_p.h>
|
||||
#include <QtQuickTestUtils/private/qmlutils_p.h>
|
||||
|
@ -16,6 +17,9 @@ public:
|
|||
private Q_SLOTS:
|
||||
void searchConfig_data();
|
||||
void searchConfig();
|
||||
|
||||
void reportConfigForFiles_data();
|
||||
void reportConfigForFiles();
|
||||
};
|
||||
|
||||
tst_qmltoolingsettings::tst_qmltoolingsettings() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
|
||||
|
@ -62,5 +66,40 @@ void tst_qmltoolingsettings::searchConfig()
|
|||
QCOMPARE(actualResult.iniFilePath, expectedResult.iniFilePath);
|
||||
}
|
||||
|
||||
void tst_qmltoolingsettings::reportConfigForFiles_data()
|
||||
{
|
||||
QTest::addColumn<QStringList>("files");
|
||||
QTest::addColumn<QString>("expectedResultCapture"); // string captured from output
|
||||
|
||||
QStringList files = { testFile("B/B1/test.qml"), testFile("B/B2/test.qml") };
|
||||
QTest::newRow("validFiles") << files << "B/B2/test.qml";
|
||||
}
|
||||
|
||||
void tst_qmltoolingsettings::reportConfigForFiles()
|
||||
{
|
||||
QFETCH(QStringList, files);
|
||||
QFETCH(QString, expectedResultCapture);
|
||||
|
||||
static QString out;
|
||||
|
||||
QtMessageHandler handler([](QtMsgType type, const QMessageLogContext &, const QString &msg) {
|
||||
if (type == QtWarningMsg) {
|
||||
QTextStream stream(&out);
|
||||
stream << msg << Qt::endl;
|
||||
}
|
||||
});
|
||||
|
||||
const auto oldMessageHandler = qInstallMessageHandler(handler);
|
||||
const auto guard =
|
||||
qScopeGuard([&oldMessageHandler]() { qInstallMessageHandler(oldMessageHandler); });
|
||||
|
||||
QQmlToolingSettings settings("qmlformat");
|
||||
settings.reportConfigForFiles(files);
|
||||
|
||||
QVERIFY(out.contains("File"));
|
||||
QVERIFY(out.contains("Settings File"));
|
||||
QVERIFY(out.contains(expectedResultCapture));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qmltoolingsettings)
|
||||
#include "tst_qmltoolingsettings.moc"
|
||||
|
|
|
@ -136,6 +136,11 @@ int main(int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (options.dryRun()) {
|
||||
settings.reportConfigForFiles(options.arguments());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options.writeDefaultSettingsEnabled())
|
||||
return settings.writeDefaults() ? 0 : -1;
|
||||
|
||||
|
|
|
@ -165,7 +165,8 @@ All warnings can be set to three levels:
|
|||
|
||||
QCommandLineOption dryRun(QStringList() << "dry-run",
|
||||
QLatin1String("Only print out the contents of the file after fix "
|
||||
"suggestions without applying them"));
|
||||
"suggestions without applying them. Also prints the "
|
||||
"settings file that would be used for this instance."));
|
||||
parser.addOption(dryRun);
|
||||
|
||||
QCommandLineOption listPluginsOption(QStringList() << "list-plugins",
|
||||
|
@ -333,6 +334,9 @@ All warnings can be set to three levels:
|
|||
parser.showHelp(-1);
|
||||
}
|
||||
|
||||
if (parser.isSet(dryRun))
|
||||
settings.reportConfigForFiles(positionalArguments);
|
||||
|
||||
QJsonArray jsonFiles;
|
||||
|
||||
for (const QString &filename : positionalArguments) {
|
||||
|
|
Loading…
Reference in New Issue