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.
|
||||
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 {};
|
||||
QTest::newRow("arrow functions") << "arrowFunctions.qml"
|
||||
<< "arrowFunctions.formatted.qml" << QStringList {};
|
||||
QTest::newRow("settings") << "settings/Example1.qml"
|
||||
<< "settings/Example1.formatted.qml" << QStringList {};
|
||||
}
|
||||
|
||||
void TestQmlformat::testFormat()
|
||||
|
|
|
@ -10,6 +10,8 @@ qt_internal_add_tool(${target_name}
|
|||
TOOLS_TARGET Qml # special case
|
||||
SOURCES
|
||||
qmlformat.cpp
|
||||
../shared/qqmltoolingsettings.h
|
||||
../shared/qqmltoolingsettings.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Core
|
||||
Qt::QmlDomPrivate
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
# include <QCommandLineParser>
|
||||
#endif
|
||||
|
||||
#include "../shared/qqmltoolingsettings.h"
|
||||
|
||||
using namespace QQmlJS::Dom;
|
||||
|
||||
struct Options
|
||||
|
@ -54,6 +56,8 @@ struct Options
|
|||
bool tabs = false;
|
||||
bool valid = false;
|
||||
bool normalize = false;
|
||||
bool ignoreSettings = false;
|
||||
bool writeDefaultSettings = false;
|
||||
|
||||
int indentWidth = 4;
|
||||
bool indentWidthSet = false;
|
||||
|
@ -168,6 +172,17 @@ Options buildCommandLineOptions(const QCoreApplication &app)
|
|||
QCommandLineOption({ "V", "verbose" },
|
||||
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(
|
||||
{ "i", "inplace" },
|
||||
QStringLiteral("Edit file in-place instead of outputting to stdout.")));
|
||||
|
@ -198,6 +213,13 @@ Options buildCommandLineOptions(const QCoreApplication &app)
|
|||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(writeDefaultsOption)) {
|
||||
Options options;
|
||||
options.writeDefaultSettings = true;
|
||||
options.valid = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
bool indentWidthOkay = false;
|
||||
const int indentWidth = parser.value("indent-width").toInt(&indentWidthOkay);
|
||||
if (!indentWidthOkay) {
|
||||
|
@ -229,6 +251,7 @@ Options buildCommandLineOptions(const QCoreApplication &app)
|
|||
options.force = parser.isSet("force");
|
||||
options.tabs = parser.isSet("tabs");
|
||||
options.normalize = parser.isSet("normalize");
|
||||
options.ignoreSettings = parser.isSet("ignore-settings");
|
||||
options.valid = true;
|
||||
|
||||
options.indentWidth = indentWidth;
|
||||
|
@ -248,6 +271,20 @@ int main(int argc, char *argv[])
|
|||
QCoreApplication::setApplicationName("qmlformat");
|
||||
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);
|
||||
if (!options.valid) {
|
||||
for (const auto &error : options.errors) {
|
||||
|
@ -257,6 +294,32 @@ int main(int argc, char *argv[])
|
|||
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;
|
||||
if (!options.files.isEmpty()) {
|
||||
if (!options.arguments.isEmpty())
|
||||
|
@ -265,12 +328,12 @@ int main(int argc, char *argv[])
|
|||
for (const QString &file : options.files) {
|
||||
Q_ASSERT(!file.isEmpty());
|
||||
|
||||
if (!parseFile(file, options))
|
||||
if (!parseFile(file, getSettings(file, options)))
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
for (const QString &file : options.arguments) {
|
||||
if (!parseFile(file, options))
|
||||
if (!parseFile(file, getSettings(file, options)))
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue