QmakePM: Respect editor settings when adding files to project

If the user wants to indent with tabs, then consider that when adding
source files via the UI. But try not to mix: If the respective variable
already uses a different indentation consistently, then keep using that
one.

Fixes: QTCREATORBUG-8016
Change-Id: I037c9ac4d4e7fbbe5753a846e57d938bbb440d6a
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2019-02-01 16:50:29 +01:00
parent 719749103a
commit 69565d6c88
5 changed files with 120 additions and 65 deletions

View File

@@ -36,10 +36,14 @@
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <cpptools/cpptoolsconstants.h>
#include <projectexplorer/editorconfiguration.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <qtsupport/profilereader.h>
#include <texteditor/icodestylepreferences.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
#include <utils/algorithm.h>
#include <utils/filesystemwatcher.h>
@@ -378,6 +382,19 @@ void QmakePriFile::watchFolders(const QSet<FileName> &folders)
m_watchedFolders = folderStrings;
}
QString QmakePriFile::continuationIndent() const
{
const EditorConfiguration *editorConf = project()->editorConfiguration();
const TextEditor::TabSettings &tabSettings = editorConf->useGlobalSettings()
? TextEditor::TextEditorSettings::codeStyle()->tabSettings()
: editorConf->codeStyle()->tabSettings();
if (tabSettings.m_continuationAlignBehavior == TextEditor::TabSettings::ContinuationAlignWithIndent
&& tabSettings.m_tabPolicy == TextEditor::TabSettings::TabsOnlyTabPolicy) {
return QString("\t");
}
return QString(tabSettings.m_indentSize, ' ');
}
bool QmakePriFile::knowsFile(const FileName &filePath) const
{
return m_recursiveEnumerateFiles.contains(filePath);
@@ -747,7 +764,8 @@ bool QmakePriFile::renameFile(const QString &oldName,
ProWriter::addFiles(includeFile, &lines,
QStringList(newName),
varNameForAdding(mimeType));
varNameForAdding(mimeType),
continuationIndent());
if (mode == Change::Save)
save(lines);
includeFile->deref();
@@ -777,7 +795,8 @@ void QmakePriFile::changeFiles(const QString &mimeType,
if (change == AddToProFile) {
// Use the first variable for adding.
ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType));
ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType),
continuationIndent());
notChanged->clear();
} else { // RemoveFromProFile
QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString());
@@ -818,7 +837,7 @@ bool QmakePriFile::setProVariable(const QString &var, const QStringList &values,
ProWriter::putVarValues(includeFile, &lines, values, var,
ProWriter::PutFlags(flags),
scope);
scope, continuationIndent());
save(lines);
includeFile->deref();

View File

@@ -216,6 +216,8 @@ private:
static void processValues(Internal::QmakePriFileEvalResult &result);
void watchFolders(const QSet<Utils::FileName> &folders);
QString continuationIndent() const;
QmakeProject *m_project = nullptr;
QmakeProFile *m_qmakeProFile = nullptr;
QmakePriFile *m_parent = nullptr;

View File

@@ -246,6 +246,7 @@ bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd,
struct LineInfo
{
QString indent;
int continuationPos = 0;
bool hasComment = false;
};
@@ -260,14 +261,29 @@ static LineInfo lineInfo(const QString &line)
li.continuationPos = idx;
for (int i = idx - 1; i >= 0 && (line.at(i) == ' ' || line.at(i) == '\t'); --i)
--li.continuationPos;
for (int i = 0; i < line.length() && (line.at(i) == ' ' || line.at(i) == '\t'); ++i)
li.indent += line.at(i);
return li;
}
static int skipContLines(QStringList *lines, int lineNo, bool addCont)
struct ContinuationInfo {
QString indent; // Empty means use default
int lineNo;
};
static ContinuationInfo skipContLines(QStringList *lines, int lineNo, bool addCont)
{
bool hasConsistentIndent = true;
QString lastIndent;
for (; lineNo < lines->count(); lineNo++) {
const QString line = lines->at(lineNo);
LineInfo li = lineInfo(line);
if (hasConsistentIndent) {
if (lastIndent.isEmpty())
lastIndent = li.indent;
else if (lastIndent != li.indent)
hasConsistentIndent = false;
}
if (li.continuationPos == 0) {
if (li.hasComment)
continue;
@@ -280,34 +296,45 @@ static int skipContLines(QStringList *lines, int lineNo, bool addCont)
break;
}
}
return lineNo;
ContinuationInfo ci;
if (hasConsistentIndent)
ci.indent = lastIndent;
ci.lineNo = lineNo;
return ci;
}
void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QString &var, PutFlags flags, const QString &scope)
void ProWriter::putVarValues(ProFile *profile, QStringList *lines, const QStringList &values,
const QString &var, PutFlags flags, const QString &scope,
const QString &continuationIndent)
{
QString indent = scope.isEmpty() ? QString() : QLatin1String(" ");
QString indent = scope.isEmpty() ? QString() : continuationIndent;
const auto effectiveContIndent = [indent, continuationIndent](const ContinuationInfo &ci) {
return !ci.indent.isEmpty() ? ci.indent : continuationIndent + indent;
};
int scopeStart = -1, lineNo;
if (locateVarValues(profile->tokPtr(), profile->tokPtrEnd(), scope, var, &scopeStart, &lineNo)) {
if (flags & ReplaceValues) {
// remove continuation lines with old values
int lNo = skipContLines(lines, lineNo, false);
lines->erase(lines->begin() + lineNo + 1, lines->begin() + lNo);
const ContinuationInfo contInfo = skipContLines(lines, lineNo, false);
lines->erase(lines->begin() + lineNo + 1, lines->begin() + contInfo.lineNo);
// remove rest of the line
QString &line = (*lines)[lineNo];
int eqs = line.indexOf(QLatin1Char('='));
if (eqs >= 0) // If this is not true, we mess up the file a bit.
line.truncate(eqs + 1);
// put new values
foreach (const QString &v, values)
line += ((flags & MultiLine) ? QLatin1String(" \\\n ") + indent : QString::fromLatin1(" ")) + v;
foreach (const QString &v, values) {
line += ((flags & MultiLine) ? QLatin1String(" \\\n") + effectiveContIndent(contInfo)
: QString::fromLatin1(" ")) + v;
}
} else {
int endLineNo = skipContLines(lines, lineNo, false);
const ContinuationInfo contInfo = skipContLines(lines, lineNo, false);
int endLineNo = contInfo.lineNo;
for (const QString &v : values) {
int curLineNo = lineNo + 1;
while (curLineNo < endLineNo && v >= lines->at(curLineNo).trimmed())
++curLineNo;
QString newLine = " " + indent + v;
QString newLine = effectiveContIndent(contInfo) + v;
if (curLineNo == endLineNo) {
QString &oldLastLine = (*lines)[endLineNo - 1];
oldLastLine.insert(lineInfo(oldLastLine).continuationPos, " \\");
@@ -322,6 +349,7 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
// Create & append new variable item
QString added;
int lNo = lines->count();
ContinuationInfo contInfo;
if (!scope.isEmpty()) {
if (scopeStart < 0) {
added = QLatin1Char('\n') + scope + QLatin1String(" {");
@@ -329,8 +357,10 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
QRegExp rx(QLatin1String("(\\s*") + scope + QLatin1String("\\s*:\\s*)[^\\s{].*"));
if (rx.exactMatch(lines->at(scopeStart))) {
(*lines)[scopeStart].replace(0, rx.cap(1).length(),
QString(scope + QLatin1String(" {\n ")));
lNo = skipContLines(lines, scopeStart, false);
QString(scope + QLatin1String(" {\n")
+ continuationIndent));
contInfo = skipContLines(lines, scopeStart, false);
lNo = contInfo.lineNo;
scopeStart = -1;
}
}
@@ -357,14 +387,16 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines,
added += QLatin1Char('\n');
added += indent + var + QLatin1String((flags & AppendOperator) ? " +=" : " =");
foreach (const QString &v, values)
added += ((flags & MultiLine) ? QLatin1String(" \\\n ") + indent : QString::fromLatin1(" ")) + v;
added += ((flags & MultiLine) ? QLatin1String(" \\\n") + effectiveContIndent(contInfo)
: QString::fromLatin1(" ")) + v;
if (!scope.isEmpty() && scopeStart < 0)
added += QLatin1String("\n}");
lines->insert(lNo, added);
}
}
void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList &values, const QString &var)
void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList &values,
const QString &var, const QString &continuationIndent)
{
QStringList valuesToWrite;
QString prefixPwd;
@@ -374,7 +406,8 @@ void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList
foreach (const QString &v, values)
valuesToWrite << (prefixPwd + baseDir.relativeFilePath(v));
putVarValues(profile, lines, valuesToWrite, var, AppendValues | MultiLine | AppendOperator);
putVarValues(profile, lines, valuesToWrite, var, AppendValues | MultiLine | AppendOperator,
QString(), continuationIndent);
}
static void findProVariables(const ushort *tokPtr, const QStringList &vars,

View File

@@ -51,11 +51,12 @@ public:
static void putVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QString &var, PutFlags flags,
const QString &scope = QString());
const QString &scope, const QString &continuationIndent);
static QList<int> removeVarValues(ProFile *profile, QStringList *lines,
const QStringList &values, const QStringList &vars);
static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths, const QString &var);
static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths,
const QString &var, const QString &continuationIndent);
static QStringList removeFiles(ProFile *profile, QStringList *lines,
const QDir &proFileDir, const QStringList &filePaths, const QStringList &vars);

View File

@@ -102,7 +102,7 @@ void tst_ProFileWriter::adds_data()
"add new append multi", f_foo, 0,
"",
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -111,7 +111,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n"
"\n"
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -120,7 +120,7 @@ void tst_ProFileWriter::adds_data()
"\n"
"\n",
"SOURCES += \\\n"
" foo\n"
"\tfoo\n"
"\n"
"\n"
"\n"
@@ -135,7 +135,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n"
"\n"
"SOURCES += \\\n"
" foo\n"
"\tfoo\n"
"\n"
"\n"
"\n"
@@ -147,7 +147,7 @@ void tst_ProFileWriter::adds_data()
"# test file\n"
"\n"
"SOURCES = \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::OneLine,
@@ -184,43 +184,43 @@ void tst_ProFileWriter::adds_data()
"unix:SOURCES = some files\n"
"\n"
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add new after some scope", f_foo, 0,
"unix {\n"
" SOMEVAR = foo\n"
"\tSOMEVAR = foo\n"
"}",
"unix {\n"
" SOMEVAR = foo\n"
"\tSOMEVAR = foo\n"
"}\n"
"\n"
"SOURCES += \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add to existing (wrong operator)", f_foo, 0,
"SOURCES = some files",
"SOURCES = some files \\\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"insert at end", f_foo_bar, 0,
"SOURCES = some files",
"SOURCES = some files \\\n"
" bar \\\n"
" foo"
"\tbar \\\n"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"insert into empty", f_foo_bar, 0,
"SOURCES =",
"SOURCES = \\\n"
" bar \\\n"
" foo"
"\tbar \\\n"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -239,33 +239,33 @@ void tst_ProFileWriter::adds_data()
"add to existing after comment (wrong operator)", f_foo, 0,
"SOURCES = some files # comment",
"SOURCES = some files \\ # comment\n"
" foo"
"\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
"add to existing after comment line (wrong operator)", f_foo, 0,
"SOURCES = some \\\n"
" # comment\n"
" files",
"\tfiles",
"SOURCES = some \\\n"
" # comment\n"
" files \\\n"
" foo"
"\tfiles \\\n"
"\tfoo"
},
{
PW::AppendValues|PW::AssignOperator|PW::MultiLine,
"add to existing", f_foo, 0,
"SOURCES = some files",
"SOURCES = some files \\\n"
" foo"
"\tfoo"
},
{
PW::ReplaceValues|PW::AssignOperator|PW::MultiLine,
"replace existing multi", f_foo_bar, 0,
"SOURCES = some files",
"SOURCES = \\\n"
" foo \\\n"
" bar"
"\tfoo \\\n"
"\tbar"
},
{
PW::ReplaceValues|PW::AssignOperator|PW::OneLine,
@@ -278,7 +278,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex last", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files",
"\tfiles",
"SOURCES = foo bar"
},
{
@@ -286,7 +286,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 1", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files\n"
"\tfiles\n"
"HEADERS = blubb",
"SOURCES = foo bar\n"
"HEADERS = blubb"
@@ -296,7 +296,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 2", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files\n"
"\tfiles\n"
"\n"
"HEADERS = blubb",
"SOURCES = foo bar\n"
@@ -308,7 +308,7 @@ void tst_ProFileWriter::adds_data()
"replace existing complex middle 3", f_foo_bar, 0,
"SOURCES = some \\\n"
" # comment\n"
" files \\\n"
"\tfiles \\\n"
"\n"
"HEADERS = blubb",
"SOURCES = foo bar\n"
@@ -324,7 +324,7 @@ void tst_ProFileWriter::adds_data()
"SOURCES = yo\n"
"\n"
"dog {\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -332,13 +332,13 @@ void tst_ProFileWriter::adds_data()
"scoped new / extend scope", f_foo, "dog",
"# test file\n"
"dog {\n"
" HEADERS += yo\n"
"\tHEADERS += yo\n"
"}",
"# test file\n"
"dog {\n"
" HEADERS += yo\n"
"\tHEADERS += yo\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -356,7 +356,7 @@ void tst_ProFileWriter::adds_data()
" yo \\\n"
" blubb\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -367,7 +367,7 @@ void tst_ProFileWriter::adds_data()
"}",
"# test file\n"
"dog {\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -377,9 +377,9 @@ void tst_ProFileWriter::adds_data()
"dog:HEADERS += yo",
"# test file\n"
"dog {\n"
" HEADERS += yo\n"
"\tHEADERS += yo\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -392,10 +392,10 @@ void tst_ProFileWriter::adds_data()
"blubb()",
"# test file\n"
"dog {\n"
" HEADERS += yo \\\n"
"\tHEADERS += yo \\\n"
" you\n"
"\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}\n"
"\n"
"blubb()"
@@ -413,8 +413,8 @@ void tst_ProFileWriter::adds_data()
" SOMEVAR = foo\n"
" }\n"
"\n"
" SOURCES += \\\n"
" foo\n"
"\tSOURCES += \\\n"
"\t\tfoo\n"
"}"
},
{
@@ -425,7 +425,7 @@ void tst_ProFileWriter::adds_data()
"}",
"# test file\n"
"dog: {\n"
" SOURCES += foo\n"
"\tSOURCES += foo\n"
"}"
},
{
@@ -435,7 +435,7 @@ void tst_ProFileWriter::adds_data()
"dog:SOURCES = yo",
"# test file\n"
"dog:SOURCES = yo \\\n"
" foo"
"\t\tfoo"
},
{
PW::AppendValues|PW::AppendOperator|PW::MultiLine,
@@ -446,8 +446,8 @@ void tst_ProFileWriter::adds_data()
"animal:!dog:SOURCES = yo\n"
"\n"
"dog {\n"
" SOURCES += \\\n"
" foo\n"
"\tSOURCES += \\\n"
"\t\tfoo\n"
"}"
},
};
@@ -478,7 +478,7 @@ void tst_ProFileWriter::adds()
QMakeParser parser(0, &vfs, &parseHandler);
ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1);
QVERIFY(proFile);
PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope);
PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope, "\t");
proFile->deref();
QCOMPARE(lines.join(QLatin1Char('\n')), output);
@@ -692,7 +692,7 @@ void tst_ProFileWriter::addFiles()
QStringList lines = input.split(QLatin1Char('\n'));
QString output = QLatin1String(
"SOURCES = foo.cpp \\\n"
" sub/bar.cpp"
"\tsub/bar.cpp"
);
QMakeVfs vfs;
@@ -701,7 +701,7 @@ void tst_ProFileWriter::addFiles()
QVERIFY(proFile);
QmakeProjectManager::Internal::ProWriter::addFiles(proFile, &lines,
QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"),
QLatin1String("SOURCES"));
QLatin1String("SOURCES"), "\t");
proFile->deref();
QCOMPARE(lines.join(QLatin1Char('\n')), output);