qmlformat: Implement settings file
Implements controlling qmlformat via a settings file as can be done for qmllint. [ChangeLog][General][qmlformat] Adds the ability to set linting options via a settings file rather than using command line parameters. Use --write-defaults to generate a template with default values for editing. Use --ignore-settings to disable this feature. Fixes: QTBUG-86415 Change-Id: I282c3b994ca6cc491a27b45f531f1ba1c2652ef7 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
e2532e8773
commit
e14d13bea6
|
@ -111,4 +111,7 @@ by specifying the \c{-n} flag.
|
||||||
|
|
||||||
By default, qmlformat writes the formatted version of the file to stdout.
|
By default, qmlformat writes the formatted version of the file to stdout.
|
||||||
If you wish to have your file updated in-place specify the \c{-i} flag.
|
If you wish to have your file updated in-place specify the \c{-i} flag.
|
||||||
|
|
||||||
|
You may also change tab widths and line ending types among other settings,
|
||||||
|
either via command line options or by using a settings file.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[General]
|
||||||
|
IndentWidth=2
|
||||||
|
NewlineType=macos
|
||||||
|
NormalizeOrder=true
|
||||||
|
UseTabs=
|
|
@ -0,0 +1,157 @@
|
||||||
|
/* This file is licensed under the not a license license
|
||||||
|
1. You may not comply
|
||||||
|
2. Goodbye
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Importing this is very important
|
||||||
|
import QtQuick 5.15
|
||||||
|
// Muddling the waters!
|
||||||
|
import QtQuick.Models 3.14 as muddle
|
||||||
|
// Importing that is important too
|
||||||
|
import Z
|
||||||
|
import That
|
||||||
|
import This // THIS IS VERY IMPORTANT!
|
||||||
|
import Y
|
||||||
|
import X.Z
|
||||||
|
import X.Y
|
||||||
|
import A.LLOHA
|
||||||
|
import A.B.B.A
|
||||||
|
|
||||||
|
// This comment is related to Item
|
||||||
|
Item {
|
||||||
|
|
||||||
|
// This to id
|
||||||
|
// Also id. (line 2)
|
||||||
|
// This is the third id
|
||||||
|
// fourth id comment
|
||||||
|
id: foo
|
||||||
|
x: 3 // Very cool
|
||||||
|
|
||||||
|
// This to enum
|
||||||
|
enum Foo {
|
||||||
|
A = 3, // This is A
|
||||||
|
B, // This is B
|
||||||
|
C = 4, // This is C
|
||||||
|
D // This is D
|
||||||
|
}
|
||||||
|
|
||||||
|
// This one to aFunc()
|
||||||
|
function aFunc() {
|
||||||
|
var x = 3;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool some_bool: false
|
||||||
|
// This comment is related to the property animation
|
||||||
|
PropertyAnimation on x {
|
||||||
|
id: foo2
|
||||||
|
x: 3
|
||||||
|
y: x + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orphan comment
|
||||||
|
|
||||||
|
// Another orphan
|
||||||
|
|
||||||
|
// More orphans
|
||||||
|
property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3]
|
||||||
|
|
||||||
|
property bool something_computed: function (x) {
|
||||||
|
const PI = 3, DAYS_PER_YEAR = 365.25;
|
||||||
|
var x = 3 + 2;
|
||||||
|
x["bla"] = 50;
|
||||||
|
|
||||||
|
// This is an orphan inside something_computed
|
||||||
|
|
||||||
|
// Are these getting duplicated?
|
||||||
|
|
||||||
|
// This one to var few!
|
||||||
|
var few = new WhatEver();
|
||||||
|
x += Math.sin(3);
|
||||||
|
x--;
|
||||||
|
--x;
|
||||||
|
x++;
|
||||||
|
++x;
|
||||||
|
for (var x = 0; x < 100; x++) {
|
||||||
|
x++;
|
||||||
|
console.log("Foo");
|
||||||
|
}
|
||||||
|
for (var x in [3, 2, 1]) {
|
||||||
|
y++;
|
||||||
|
console.log("Bar");
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
console.log("Wee");
|
||||||
|
}
|
||||||
|
with (foo) {
|
||||||
|
bar;
|
||||||
|
x += 5;
|
||||||
|
} // This is related to with!
|
||||||
|
x3: do {
|
||||||
|
console.log("Hello");
|
||||||
|
} while (3 == 0)
|
||||||
|
try {
|
||||||
|
dangerous();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
} finally {
|
||||||
|
console.log("What else?");
|
||||||
|
}
|
||||||
|
switch (x) {
|
||||||
|
case 0:
|
||||||
|
x = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
x = 5;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
x = 100;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (x == 50) {
|
||||||
|
console.log("true");
|
||||||
|
} else if (x == 50) {
|
||||||
|
console.log("other thing");
|
||||||
|
} else {
|
||||||
|
console.log("false");
|
||||||
|
}
|
||||||
|
if (x == 50) {
|
||||||
|
console.log("true");
|
||||||
|
} else if (x == 50) {
|
||||||
|
console.log("other thing");
|
||||||
|
x--;
|
||||||
|
} else {
|
||||||
|
console.log("false");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another orphan inside something_computed
|
||||||
|
return "foobar";
|
||||||
|
}()
|
||||||
|
|
||||||
|
default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool
|
||||||
|
myFavouriteThings: [
|
||||||
|
// This is an orphan
|
||||||
|
|
||||||
|
// This is a cool text
|
||||||
|
Text {
|
||||||
|
},
|
||||||
|
// This is a cool rectangle
|
||||||
|
Rectangle {
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// some_read_only_bool
|
||||||
|
readonly property bool some_read_only_bool: Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
|
||||||
|
|
||||||
|
signal say(string name, bool caps)
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Bla"
|
||||||
|
|
||||||
|
signal boo(int count, int times, real duration)
|
||||||
|
|
||||||
|
required property string batman
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: console.log("Foo!")
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
|
||||||
|
|
||||||
|
/* This file is licensed under the not a license license
|
||||||
|
1. You may not comply
|
||||||
|
2. Goodbye
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Importing this is very important
|
||||||
|
import QtQuick 5.15
|
||||||
|
// Muddling the waters!
|
||||||
|
import QtQuick.Models 3.14 as muddle
|
||||||
|
// Importing that is important too
|
||||||
|
import Z
|
||||||
|
import That
|
||||||
|
import This // THIS IS VERY IMPORTANT!
|
||||||
|
import Y
|
||||||
|
import X.Z
|
||||||
|
import X.Y
|
||||||
|
import A.LLOHA
|
||||||
|
import A.B.B.A
|
||||||
|
|
||||||
|
// This comment is related to Item
|
||||||
|
Item {
|
||||||
|
x: 3 // Very cool
|
||||||
|
|
||||||
|
// This to enum
|
||||||
|
enum Foo {
|
||||||
|
A = 3, // This is A
|
||||||
|
B, // This is B
|
||||||
|
C = 4, // This is C
|
||||||
|
D // This is D
|
||||||
|
}
|
||||||
|
|
||||||
|
// This one to aFunc()
|
||||||
|
function aFunc() {
|
||||||
|
var x = 3;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool some_bool : false
|
||||||
|
// This comment is related to the property animation
|
||||||
|
PropertyAnimation on x {
|
||||||
|
id: foo2; x: 3; y: x + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orphan comment
|
||||||
|
|
||||||
|
// Another orphan
|
||||||
|
|
||||||
|
// More orphans
|
||||||
|
|
||||||
|
|
||||||
|
property variant some_array_literal: [30,20,Math["PI"],[4,3,2],"foo",0.3]
|
||||||
|
property bool something_computed: function(x) {
|
||||||
|
const PI = 3, DAYS_PER_YEAR=365.25; var x = 3 + 2; x["bla"] = 50;
|
||||||
|
|
||||||
|
// This is an orphan inside something_computed
|
||||||
|
|
||||||
|
// Are these getting duplicated?
|
||||||
|
|
||||||
|
|
||||||
|
// This one to var few!
|
||||||
|
var few = new WhatEver();
|
||||||
|
x += Math.sin(3); x--; --x; x++; ++x;
|
||||||
|
for (var x = 0; x < 100; x++) { x++; console.log("Foo"); }
|
||||||
|
for (var x in [3,2,1]) { y++; console.log("Bar"); }
|
||||||
|
while (true) { console.log("Wee"); }
|
||||||
|
with (foo) { bar; x+=5; } // This is related to with!
|
||||||
|
x3:
|
||||||
|
do { console.log("Hello"); } while (3 == 0)
|
||||||
|
try { dangerous(); } catch(e) { console.log(e); } finally { console.log("What else?"); }
|
||||||
|
switch (x) { case 0: x = 1; break; case 1: x = 5; break; case 4: x = 100; break; }
|
||||||
|
if (x == 50) { console.log("true"); } else if (x == 50) { console.log("other thing"); } else { console.log("false"); }
|
||||||
|
if (x == 50) { console.log("true"); } else if (x == 50) { console.log("other thing"); x--; } else { console.log("false"); }
|
||||||
|
|
||||||
|
// Another orphan inside something_computed
|
||||||
|
|
||||||
|
return "foobar"; }();
|
||||||
|
|
||||||
|
default property bool some_default_bool : 500 % 5 !== 0 // some_default_bool
|
||||||
|
|
||||||
|
myFavouriteThings: [
|
||||||
|
// This is an orphan
|
||||||
|
|
||||||
|
// This is a cool text
|
||||||
|
Text {},
|
||||||
|
// This is a cool rectangle
|
||||||
|
Rectangle {}]
|
||||||
|
|
||||||
|
// some_read_only_bool
|
||||||
|
readonly property bool some_read_only_bool : Math.sin(3) && (aFunc()[30] + 5) | 2 != 0
|
||||||
|
|
||||||
|
signal say(string name, bool caps);
|
||||||
|
|
||||||
|
Text { text: "Bla"; signal boo(int count, int times, real duration); required property string batman; }
|
||||||
|
|
||||||
|
Component.onCompleted: console.log("Foo!");
|
||||||
|
|
||||||
|
// This to id
|
||||||
|
// Also id. (line 2)
|
||||||
|
// This is the third id
|
||||||
|
// fourth id comment
|
||||||
|
id: foo
|
||||||
|
|
||||||
|
}
|
|
@ -252,6 +252,8 @@ void TestQmlformat::testFormat_data()
|
||||||
<< "emptyObject.formatted.qml" << QStringList {};
|
<< "emptyObject.formatted.qml" << QStringList {};
|
||||||
QTest::newRow("arrow functions") << "arrowFunctions.qml"
|
QTest::newRow("arrow functions") << "arrowFunctions.qml"
|
||||||
<< "arrowFunctions.formatted.qml" << QStringList {};
|
<< "arrowFunctions.formatted.qml" << QStringList {};
|
||||||
|
QTest::newRow("settings") << "settings/Example1.qml"
|
||||||
|
<< "settings/Example1.formatted.qml" << QStringList {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestQmlformat::testFormat()
|
void TestQmlformat::testFormat()
|
||||||
|
|
|
@ -10,6 +10,8 @@ qt_internal_add_tool(${target_name}
|
||||||
TOOLS_TARGET Qml # special case
|
TOOLS_TARGET Qml # special case
|
||||||
SOURCES
|
SOURCES
|
||||||
qmlformat.cpp
|
qmlformat.cpp
|
||||||
|
../shared/qqmltoolingsettings.h
|
||||||
|
../shared/qqmltoolingsettings.cpp
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
Qt::Core
|
Qt::Core
|
||||||
Qt::QmlDomPrivate
|
Qt::QmlDomPrivate
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
# include <QCommandLineParser>
|
# include <QCommandLineParser>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../shared/qqmltoolingsettings.h"
|
||||||
|
|
||||||
using namespace QQmlJS::Dom;
|
using namespace QQmlJS::Dom;
|
||||||
|
|
||||||
struct Options
|
struct Options
|
||||||
|
@ -54,6 +56,8 @@ struct Options
|
||||||
bool tabs = false;
|
bool tabs = false;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
bool normalize = false;
|
bool normalize = false;
|
||||||
|
bool ignoreSettings = false;
|
||||||
|
bool writeDefaultSettings = false;
|
||||||
|
|
||||||
int indentWidth = 4;
|
int indentWidth = 4;
|
||||||
bool indentWidthSet = false;
|
bool indentWidthSet = false;
|
||||||
|
@ -168,6 +172,17 @@ Options buildCommandLineOptions(const QCoreApplication &app)
|
||||||
QCommandLineOption({ "V", "verbose" },
|
QCommandLineOption({ "V", "verbose" },
|
||||||
QStringLiteral("Verbose mode. Outputs more detailed information.")));
|
QStringLiteral("Verbose mode. Outputs more detailed information.")));
|
||||||
|
|
||||||
|
QCommandLineOption writeDefaultsOption(
|
||||||
|
QStringList() << "write-defaults",
|
||||||
|
QLatin1String("Writes defaults settings to .qmlformat.ini and exits (Warning: This "
|
||||||
|
"will overwrite any existing settings and comments!)"));
|
||||||
|
parser.addOption(writeDefaultsOption);
|
||||||
|
|
||||||
|
QCommandLineOption ignoreSettings(QStringList() << "ignore-settings",
|
||||||
|
QLatin1String("Ignores all settings files and only takes "
|
||||||
|
"command line options into consideration"));
|
||||||
|
parser.addOption(ignoreSettings);
|
||||||
|
|
||||||
parser.addOption(QCommandLineOption(
|
parser.addOption(QCommandLineOption(
|
||||||
{ "i", "inplace" },
|
{ "i", "inplace" },
|
||||||
QStringLiteral("Edit file in-place instead of outputting to stdout.")));
|
QStringLiteral("Edit file in-place instead of outputting to stdout.")));
|
||||||
|
@ -198,6 +213,13 @@ Options buildCommandLineOptions(const QCoreApplication &app)
|
||||||
|
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
|
if (parser.isSet(writeDefaultsOption)) {
|
||||||
|
Options options;
|
||||||
|
options.writeDefaultSettings = true;
|
||||||
|
options.valid = true;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
bool indentWidthOkay = false;
|
bool indentWidthOkay = false;
|
||||||
const int indentWidth = parser.value("indent-width").toInt(&indentWidthOkay);
|
const int indentWidth = parser.value("indent-width").toInt(&indentWidthOkay);
|
||||||
if (!indentWidthOkay) {
|
if (!indentWidthOkay) {
|
||||||
|
@ -229,6 +251,7 @@ Options buildCommandLineOptions(const QCoreApplication &app)
|
||||||
options.force = parser.isSet("force");
|
options.force = parser.isSet("force");
|
||||||
options.tabs = parser.isSet("tabs");
|
options.tabs = parser.isSet("tabs");
|
||||||
options.normalize = parser.isSet("normalize");
|
options.normalize = parser.isSet("normalize");
|
||||||
|
options.ignoreSettings = parser.isSet("ignore-settings");
|
||||||
options.valid = true;
|
options.valid = true;
|
||||||
|
|
||||||
options.indentWidth = indentWidth;
|
options.indentWidth = indentWidth;
|
||||||
|
@ -248,6 +271,20 @@ int main(int argc, char *argv[])
|
||||||
QCoreApplication::setApplicationName("qmlformat");
|
QCoreApplication::setApplicationName("qmlformat");
|
||||||
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
||||||
|
|
||||||
|
QQmlToolingSettings settings(QLatin1String("qmlformat"));
|
||||||
|
|
||||||
|
const QString &useTabsSetting = QStringLiteral("UseTabs");
|
||||||
|
settings.addOption(useTabsSetting);
|
||||||
|
|
||||||
|
const QString &indentWidthSetting = QStringLiteral("IndentWidth");
|
||||||
|
settings.addOption(indentWidthSetting, 4);
|
||||||
|
|
||||||
|
const QString &normalizeSetting = QStringLiteral("NormalizeOrder");
|
||||||
|
settings.addOption(normalizeSetting);
|
||||||
|
|
||||||
|
const QString &newlineSetting = QStringLiteral("NewlineType");
|
||||||
|
settings.addOption(newlineSetting, QStringLiteral("native"));
|
||||||
|
|
||||||
const auto options = buildCommandLineOptions(app);
|
const auto options = buildCommandLineOptions(app);
|
||||||
if (!options.valid) {
|
if (!options.valid) {
|
||||||
for (const auto &error : options.errors) {
|
for (const auto &error : options.errors) {
|
||||||
|
@ -257,6 +294,32 @@ int main(int argc, char *argv[])
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.writeDefaultSettings)
|
||||||
|
return settings.writeDefaults() ? 0 : -1;
|
||||||
|
|
||||||
|
auto getSettings = [&](const QString &file, Options options) {
|
||||||
|
if (options.ignoreSettings || !settings.search(file))
|
||||||
|
return options;
|
||||||
|
|
||||||
|
Options perFileOptions = options;
|
||||||
|
|
||||||
|
// Allow for tab settings to be overwritten by the command line
|
||||||
|
if (!options.indentWidthSet) {
|
||||||
|
if (settings.isSet(indentWidthSetting))
|
||||||
|
perFileOptions.indentWidth = settings.value(indentWidthSetting).toInt();
|
||||||
|
if (settings.isSet(useTabsSetting))
|
||||||
|
perFileOptions.tabs = settings.value(useTabsSetting).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.isSet(normalizeSetting))
|
||||||
|
perFileOptions.normalize = settings.value(normalizeSetting).toBool();
|
||||||
|
|
||||||
|
if (settings.isSet(newlineSetting))
|
||||||
|
perFileOptions.newline = settings.value(newlineSetting).toString();
|
||||||
|
|
||||||
|
return perFileOptions;
|
||||||
|
};
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (!options.files.isEmpty()) {
|
if (!options.files.isEmpty()) {
|
||||||
if (!options.arguments.isEmpty())
|
if (!options.arguments.isEmpty())
|
||||||
|
@ -265,12 +328,12 @@ int main(int argc, char *argv[])
|
||||||
for (const QString &file : options.files) {
|
for (const QString &file : options.files) {
|
||||||
Q_ASSERT(!file.isEmpty());
|
Q_ASSERT(!file.isEmpty());
|
||||||
|
|
||||||
if (!parseFile(file, options))
|
if (!parseFile(file, getSettings(file, options)))
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const QString &file : options.arguments) {
|
for (const QString &file : options.arguments) {
|
||||||
if (!parseFile(file, options))
|
if (!parseFile(file, getSettings(file, options)))
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue