Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlformatoptions.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <QCommandLineParser>
8#include <QCommandLineOption>
9
10using namespace Qt::StringLiterals;
11
20
21QQmlFormatOptions::LineEndings QQmlFormatOptions::detectLineEndings(const QString &code)
22{
23 const QQmlJS::Dom::LineWriterOptions::LineEndings defaultEndings =
24#if defined(Q_OS_WIN)
25 LineEndings::Windows;
26#else
27 LineEndings::Unix;
28#endif
29 // find out current line endings...
30 int newlineIndex = code.indexOf(QChar(u'\n'));
31 int crIndex = code.indexOf(QChar(u'\r'));
32 if (newlineIndex >= 0) {
33 if (crIndex >= 0) {
34 if (crIndex + 1 == newlineIndex)
35 return LineEndings::Windows;
36
37 qWarning().noquote() << "Invalid line ending in file, using default";
38 return defaultEndings;
39 }
40 return LineEndings::Unix;
41 }
42 if (crIndex >= 0) {
43 return LineEndings::OldMacOs;
44 }
45
46 qWarning().noquote() << "Unknown line ending in file, using default";
47 return defaultEndings;
48}
49
50QQmlFormatOptionLineEndings QQmlFormatOptions::parseEndings(const QString &endings)
51{
52 if (endings == u"unix")
53 return Unix;
54 if (endings == u"windows")
55 return Windows;
56 if (endings == u"macos")
57 return OldMacOs;
58 if (endings == u"native")
59 return Native;
60
61 qWarning().noquote() << "Unknown line ending type" << endings << ", using default";
62#if defined(Q_OS_WIN)
63 return Windows;
64#else
65 return Unix;
66#endif
67}
68
69void QQmlFormatOptions::applySettings(const QQmlFormatSettings &settings)
70{
71 // If the options is already set by commandline, don't override it with the values in the .ini
72 // file.
73 if (!isMarked(Settings::IndentWidth)
74 && settings.isSet(QQmlFormatSettings::s_indentWidthSetting)) {
75 setIndentWidth(settings.value(QQmlFormatSettings::s_indentWidthSetting).toInt());
76 }
77
78 if (!isMarked(Settings::UseTabs) && settings.isSet(QQmlFormatSettings::s_useTabsSetting)) {
79 setTabsEnabled(settings.value(QQmlFormatSettings::s_useTabsSetting).toBool());
80 }
81
82 if (!isMarked(Settings::MaxColumnWidth)
83 && settings.isSet(QQmlFormatSettings::s_maxColumnWidthSetting)) {
84 setMaxColumnWidth(settings.value(QQmlFormatSettings::s_maxColumnWidthSetting).toInt());
85 }
86
87 if (!isMarked(Settings::NormalizeOrder)
88 && settings.isSet(QQmlFormatSettings::s_normalizeSetting)) {
89 setNormalizeEnabled(settings.value(QQmlFormatSettings::s_normalizeSetting).toBool());
90 }
91
92 if (!isMarked(Settings::NewlineType) && settings.isSet(QQmlFormatSettings::s_newlineSetting)) {
93 setNewline(QQmlFormatOptions::parseEndings(
94 settings.value(QQmlFormatSettings::s_newlineSetting).toString()));
95 }
96
97 if (!isMarked(Settings::ObjectsSpacing)
98 && settings.isSet(QQmlFormatSettings::s_objectsSpacingSetting)) {
99 setObjectsSpacing(settings.value(QQmlFormatSettings::s_objectsSpacingSetting).toBool());
100 }
101
102 if (!isMarked(Settings::FunctionsSpacing)
103 && settings.isSet(QQmlFormatSettings::s_functionsSpacingSetting)) {
104 setFunctionsSpacing(settings.value(QQmlFormatSettings::s_functionsSpacingSetting).toBool());
105 }
106
107 if (!isMarked(Settings::SortImports)
108 && settings.isSet(QQmlFormatSettings::s_sortImportsSetting)) {
109 setSortImports(settings.value(QQmlFormatSettings::s_sortImportsSetting).toBool());
110 }
111}
112
113QQmlFormatOptions QQmlFormatOptions::buildCommandLineOptions(const QStringList &args)
114{
115 QQmlFormatOptions options;
116 QCommandLineParser parser;
117 parser.setApplicationDescription(
118 "Formats QML files according to the QML Coding Conventions."_L1);
119 parser.addHelpOption();
120 parser.addVersionOption();
121
122 parser.addOption(
123 QCommandLineOption({ "V"_L1, "verbose"_L1 },
124 QStringLiteral("Verbose mode. Outputs more detailed information.")));
125
126 QCommandLineOption writeDefaultsOption(
127 QStringList() << "write-defaults"_L1,
128 QLatin1String("Writes defaults settings to .qmlformat.ini and exits (Warning: This "
129 "will overwrite any existing settings and comments!)"_L1));
130 parser.addOption(writeDefaultsOption);
131
132 QCommandLineOption ignoreSettings(QStringList() << "ignore-settings"_L1,
133 QLatin1String("Ignores all settings files and only takes "
134 "command line options into consideration"_L1));
135 parser.addOption(ignoreSettings);
136
137 parser.addOption(QCommandLineOption(
138 { "i"_L1, "inplace"_L1 },
139 QStringLiteral("Edit file in-place instead of outputting to stdout.")));
140
141 parser.addOption(QCommandLineOption({ "f"_L1, "force"_L1 },
142 QStringLiteral("Continue even if an error has occurred.")));
143
144 parser.addOption(QCommandLineOption({ "t"_L1, "tabs"_L1 },
145 QStringLiteral("Use tabs instead of spaces.")));
146
147 parser.addOption(QCommandLineOption({ "w"_L1, "indent-width"_L1 },
148 QStringLiteral("How many spaces are used when indenting."),
149 "width"_L1, "4"_L1));
150
151 QCommandLineOption columnWidthOption(
152 { "W"_L1, "column-width"_L1 },
153 QStringLiteral("Breaks the line into multiple lines if exceedes the specified width."
154 "Use -1 to disable line wrapping. (default)"),
155 "width"_L1, "-1"_L1);
156 parser.addOption(columnWidthOption);
157 parser.addOption(QCommandLineOption({ "n"_L1, "normalize"_L1 },
158 QStringLiteral("Reorders the attributes of the objects "
159 "according to the QML Coding Guidelines.")));
160
161 QCommandLineOption filesOption(
162 { "F"_L1, "files"_L1 }, "Format all files listed in file, in-place"_L1, "file"_L1);
163 parser.addOption(filesOption);
164
165 parser.addOption(QCommandLineOption(
166 { "l"_L1, "newline"_L1 },
167 QStringLiteral("Override the new line format to use (native macos unix windows)."),
168 "newline"_L1, "native"_L1));
169
170 parser.addOption(QCommandLineOption(
171 QStringList() << "objects-spacing"_L1,
172 QStringLiteral("Ensure spaces between objects (only works with normalize option).")));
173
174 parser.addOption(QCommandLineOption(
175 QStringList() << "functions-spacing"_L1,
176 QStringLiteral("Ensure spaces between functions (only works with normalize option).")));
177
178 parser.addOption(
179 QCommandLineOption({ "S"_L1, "sort-imports"_L1 },
180 QStringLiteral("Sort imports alphabetically "
181 "(Warning: this might change semantics if a given "
182 "name identifies types in multiple modules!).")));
183
184 parser.addPositionalArgument("filenames"_L1, "files to be processed by qmlformat"_L1);
185
186 parser.process(args);
187
188 if (parser.isSet(writeDefaultsOption)) {
190 return options;
191 }
192
193 if (parser.positionalArguments().empty() && !parser.isSet(filesOption)) {
194 options.addError("Error: Expected at least one input file."_L1);
195 return options;
196 }
197
198 bool indentWidthOkay = false;
199 const int indentWidth = parser.value("indent-width"_L1).toInt(&indentWidthOkay);
200 if (!indentWidthOkay) {
201 options.addError("Error: Invalid value passed to -w"_L1);
202 return options;
203 }
204
205 QStringList files;
206 if (!parser.value("files"_L1).isEmpty()) {
207 const QString path = parser.value("files"_L1);
208 QFile file(path);
209 if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
210 options.addError("Error: Could not open file \""_L1 + path + "\" for option -F."_L1);
211 return options;
212 }
213
214 QTextStream in(&file);
215 while (!in.atEnd()) {
216 QString file = in.readLine();
217
218 if (file.isEmpty())
219 continue;
220
221 files.push_back(file);
222 }
223
224 if (files.isEmpty()) {
225 options.addError("Error: File \""_L1 + path + "\" for option -F is empty."_L1);
226 return options;
227 }
228
229 for (const auto &file : std::as_const(files)) {
230 if (!QFile::exists(file)) {
231 options.addError("Error: Entry \""_L1 + file + "\" of file \""_L1 + path
232 + "\" passed to option -F could not be found."_L1);
233 return options;
234 }
235 }
236 } else {
237 const auto &args = parser.positionalArguments();
238 for (const auto &file : args) {
239 if (!QFile::exists(file)) {
240 options.addError("Error: Could not find file \""_L1 + file + "\"."_L1);
241 return options;
242 }
243 }
244 }
245
246 options.setIsVerbose(parser.isSet("verbose"_L1));
247 options.setIsInplace(parser.isSet("inplace"_L1));
248 options.setForceEnabled(parser.isSet("force"_L1));
249 options.setIgnoreSettingsEnabled(parser.isSet("ignore-settings"_L1));
250
251 if (parser.isSet("tabs"_L1)) {
252 options.mark(Settings::UseTabs);
253 options.setTabsEnabled(true);
254 }
255 if (parser.isSet("normalize"_L1)) {
256 options.mark(Settings::NormalizeOrder);
257 options.setNormalizeEnabled(true);
258 }
259 if (parser.isSet("objects-spacing"_L1)) {
260 options.mark(Settings::ObjectsSpacing);
261 options.setObjectsSpacing(true);
262 }
263 if (parser.isSet("functions-spacing"_L1)) {
264 options.mark(Settings::FunctionsSpacing);
265 options.setFunctionsSpacing(true);
266 }
267 if (parser.isSet("sort-imports"_L1)) {
268 options.mark(Settings::SortImports);
269 options.setSortImports(true);
270 }
271 if (parser.isSet("indent-width"_L1)) {
272 options.mark(Settings::IndentWidth);
273 options.setIndentWidth(indentWidth);
274 }
275
276 if (parser.isSet("newline"_L1)) {
277 options.mark(Settings::NewlineType);
278 options.setNewline(QQmlFormatOptions::parseEndings(parser.value("newline"_L1)));
279 }
280 options.setFiles(files);
281 options.setArguments(parser.positionalArguments());
282
283 if (parser.isSet(columnWidthOption)) {
284 bool isValidValue = false;
285 const int maxColumnWidth = parser.value(columnWidthOption).toInt(&isValidValue);
286 if (!isValidValue || maxColumnWidth < -1) {
287 options.addError("Error: Invalid value passed to -W. Must be an integer >= -1"_L1);
288 return options;
289 }
290 options.mark(Settings::MaxColumnWidth);
291 options.setMaxColumnWidth(maxColumnWidth);
292 }
293 return options;
294}
295
297 QQmlFormatSettings *settings) const
298{
299 // Perform formatting inplace if --files option is set.
300 const bool hasFiles = !files().isEmpty();
301 QQmlFormatOptions perFileOptions = *this;
302 if (hasFiles)
303 perFileOptions.setIsInplace(true);
304
305 if (!ignoreSettingsEnabled() && settings->search(fileName))
306 perFileOptions.applySettings(*settings);
307
308 return perFileOptions;
309}
void setTabsEnabled(bool tabs)
void setNormalizeEnabled(bool normalize)
void setMaxColumnWidth(int width)
void applySettings(const QQmlFormatSettings &settings)
void setSortImports(bool sort)
void setFunctionsSpacing(bool spacing)
void setIndentWidth(int width)
void setObjectsSpacing(bool spacing)
bool ignoreSettingsEnabled() const
void setIsInplace(bool newInplace)
void setWriteDefaultSettingsEnabled(bool newWriteDefaultSettings)
QQmlFormatOptions optionsForFile(const QString &fileName, QQmlFormatSettings *settings) const