Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ${author} and ${branch} in templates #792

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 92 additions & 28 deletions src/ui/CommitEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,17 @@ CommitEditor::CommitEditor(const git::Repository &repo, QWidget *parent)
}
}
}
applyTemplate(t, files);

RepoView *view = RepoView::parentView(this);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not sure if there was an easier way to get the author and branch name at this point

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Because of the possibility to temporarly changing the username amd email, I think you need to take the one from the repoview

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you change temporarly the username (click on the Author link above the commit message), still the old name is used.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@esteban-aliverti can you have a look into it?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git::Reference head = view ? view->repo().head() : git::Reference();
git::Branch headBranch = head;

QString branchName = git::Branch(head).name();
git::Config config =
view ? view->repo().gitConfig() : git::Config::global();
QString author = config.value<QString>("user.name").toHtmlEscaped();

applyTemplate(t, author, branchName, files);
});

QLabel *label = new QLabel(tr("<b>Commit Message:</b>"), this);
Expand Down Expand Up @@ -605,9 +615,11 @@ QString CommitEditor::createFileList(const QStringList &list, int maxFiles) {
return msg;
}

void CommitEditor::setMessage(const QStringList &files) {
void CommitEditor::setMessage(const QString author, const QString branchName,
const QStringList &files) {
if (mTemplate->templates().count() > 0) {
applyTemplate(mTemplate->templates().first().value, files);
applyTemplate(mTemplate->templates().first().value, author, branchName,
files);
} else {
QString msg = createFileList(files, 3);
if (!msg.isEmpty())
Expand All @@ -634,49 +646,97 @@ void CommitEditor::setDiff(const git::Diff &diff) {
}

// public slots
void CommitEditor::applyTemplate(const QString &t, const QStringList &files) {
void CommitEditor::applyTemplate(const QString &t, const QString &author,
const QString &branchName,
const QStringList &files) {

QString templ = t;
templ = applyAuthorTemplate(templ, author);
templ = applyBranchTemplate(templ, branchName);
templ = applyFileTemplate(templ, files);

auto index = templ.indexOf(TemplateButton::cursorPositionString);
if (index < 0) {
index = templ.length();
}

templ.replace(TemplateButton::cursorPositionString, "");
mMessage->setText(templ);
auto cursor = mMessage->textCursor();
cursor.setPosition(index);
mMessage->setTextCursor(cursor);
}

void CommitEditor::applyTemplate(const QString &t, const QString &author,
const QString &branchName) {
applyTemplate(t, author, branchName, {});
}

QString CommitEditor::applyAuthorTemplate(const QString &t,
const QString author) {
QString templateText = t;
//${author}
QString pattern = TemplateButton::authorPattern;
pattern.replace("{", "\\{");
pattern.replace("}", "\\}");
pattern.replace("$", "\\$");
QRegularExpression re(pattern);
QRegularExpressionMatch match = re.match(templateText);
if (match.hasMatch()) {
const auto matchComplete = match.captured(0);
templateText.replace(matchComplete, author);
}
return templateText;
}

QString CommitEditor::applyBranchTemplate(const QString &t,
const QString branchName) {
QString templateText = t;
//${branch(:.*){0,1}}
QString pattern = TemplateButton::branchPattern;
pattern = pattern.replace(QRegularExpression("^\\$\\{"), "\\$\\{");
pattern = pattern.replace(QRegularExpression("\\}$"), "\\}");
QRegularExpression re(pattern);
QRegularExpressionMatch match = re.match(templateText);
if (match.hasMatch()) {
const auto matchComplete = match.captured(0);
QString branchPart = branchName;
int idx = matchComplete.indexOf(':');
if (idx > 0) {
QRegularExpression branchRegex(
"(" + matchComplete.mid(idx + 1, matchComplete.length() - idx - 2) +
")");
match = branchRegex.match(branchName);
branchPart = match.captured(1);
}
templateText.replace(matchComplete, branchPart);
}
return templateText;
}

QString CommitEditor::applyFileTemplate(const QString &t,
const QStringList &files) {
QString templateText = t;
//${file:}
QString pattern = TemplateButton::filesPosition;
pattern.replace("{", "\\{");
pattern.replace("}", "\\}");
pattern.replace("$", "\\$");
QRegularExpression re(pattern);
QRegularExpressionMatch match = re.match(templ);
int start = -1;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't understand why were we calculating the offset instead of simply replacing all the variables and then checking where the placeholder for the cursor was left after all the substitutions.
This is what I'm doing not, but I may have missed something.

int offset = 0;
QRegularExpressionMatch match = re.match(templateText);
if (match.hasMatch()) {
start = match.capturedStart(0);
int origLength = match.capturedLength(0);
const auto matchComplete = match.captured(0);
bool ok;
const auto number = match.captured(1).toInt(&ok);

if (ok) {
const QString filesStr = createFileList(files, number);
templ.replace(matchComplete, filesStr);
offset = filesStr.length() - origLength;
templateText.replace(matchComplete, filesStr);
}
}

auto index = t.indexOf(TemplateButton::cursorPositionString);
if (index < 0)
index = templ.length();
else if (start > 0 && index > start) {
// offset, because fileStr has different length than matchComplete
index += offset;
}

templ.replace(TemplateButton::cursorPositionString, "");
mMessage->setText(templ);
auto cursor = mMessage->textCursor();
cursor.setPosition(index);
mMessage->setTextCursor(cursor);
return templateText;
}

void CommitEditor::applyTemplate(const QString &t) { applyTemplate(t, {}); }

void CommitEditor::updateButtons(bool yieldFocus) {
RepoView *view = RepoView::parentView(this);
if (!view || !view->repo().isValid()) {
Expand Down Expand Up @@ -720,6 +780,10 @@ void CommitEditor::updateButtons(bool yieldFocus) {
git::Reference head = view ? view->repo().head() : git::Reference();
git::Branch headBranch = head;

QString branchName = git::Branch(head).name();
git::Config config = view ? view->repo().gitConfig() : git::Config::global();
QString author = config.value<QString>("user.name").toHtmlEscaped();

mMergeAbort->setText(tr("Abort %1").arg(text));
mMergeAbort->setVisible(headBranch.isValid() && merging);

Expand Down Expand Up @@ -763,7 +827,7 @@ void CommitEditor::updateButtons(bool yieldFocus) {
QSignalBlocker blocker(mMessage);
(void)blocker;

setMessage(files);
setMessage(author, branchName, files);
if (yieldFocus && !mMessage->toPlainText().isEmpty())
mMessage->setFocus();
}
Expand Down
13 changes: 10 additions & 3 deletions src/ui/CommitEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,24 @@ class CommitEditor : public QFrame {
void unstage();
bool isUnstageEnabled() const;
static QString createFileList(const QStringList &list, int maxFiles);
void setMessage(const QStringList &files);
void setMessage(const QString author, const QString branchName,
const QStringList &files);
void setMessage(const QString &message);
QString message() const;
void setDiff(const git::Diff &diff);

public slots:
void applyTemplate(const QString &t, const QStringList &files);
void applyTemplate(const QString &t);
void applyTemplate(const QString &t, const QString &author,
const QString &branchName, const QStringList &files);
void applyTemplate(const QString &t, const QString &author,
const QString &branchName);

private:
void updateButtons(bool yieldFocus = true);
QString applyAuthorTemplate(const QString &t, const QString author);
QString applyBranchTemplate(const QString &t, const QString branchName);
QString applyFileTemplate(const QString &templateText,
const QStringList &files);
QTextEdit *textEdit() const;

git::Repository mRepo;
Expand Down
5 changes: 5 additions & 0 deletions src/ui/TemplateButton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const QString TemplateButton::cursorPositionString = QStringLiteral("%|");
const QString TemplateButton::filesPosition =
QStringLiteral("${files:([0-9]*)}");

const QString TemplateButton::authorPattern = QStringLiteral("${author}");

const QString TemplateButton::branchPattern =
QStringLiteral("${branch(:.*){0,1}}");

TemplateButton::TemplateButton(QWidget *parent) : QToolButton(parent) {
setPopupMode(QToolButton::InstantPopup);
mMenu = new QMenu(this);
Expand Down
2 changes: 2 additions & 0 deletions src/ui/TemplateButton.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class TemplateButton : public QToolButton {
};
static const QString cursorPositionString;
static const QString filesPosition;
static const QString authorPattern;
static const QString branchPattern;

TemplateButton(QWidget *parent = nullptr);
QMenu *menu() const;
Expand Down
11 changes: 11 additions & 0 deletions src/ui/TemplateDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ TemplateDialog::TemplateDialog(QList<TemplateButton::Template> &templates,
vBox->addWidget(new QLabel(tr("use %1 to declare the position of the cursor.")
.arg(TemplateButton::cursorPositionString),
this));
vBox->addWidget(
new QLabel(tr("use ${author} to add the author of the commit"), this));

vBox->addWidget(
new QLabel(tr("use ${branch} to add the name of the branch."), this));

vBox->addWidget(new QLabel(
tr("use ${branch:x} to add part of the name of the branch.,\nx (regex)"
"determines the regular expression used to extract the desired part"),
this));

vBox->addWidget(
new QLabel(tr("use ${files:x} to add all updated file names,\nx (number) "
"determines the number of maximum files shown"),
Expand Down
81 changes: 79 additions & 2 deletions test/commitEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ private slots:
void testCreateFileList();
void applyTemplate1();
void applyTemplate2();
void applyTemplate3();
void applyTemplate4();
void applyTemplate5();
void applyTemplate6();
void applyTemplate7();
};

void TestCommitEditor::testCreateFileList() {
Expand All @@ -32,7 +37,7 @@ void TestCommitEditor::applyTemplate1() {
Test::ScratchRepository repo;
CommitEditor e(repo);

e.applyTemplate(QStringLiteral("Description: %|\nfiles: ${files:3}"),
e.applyTemplate(QStringLiteral("Description: %|\nfiles: ${files:3}"), "", "",
{"file.txt"});
QCOMPARE(e.textEdit()->toPlainText(),
QStringLiteral("Description: \nfiles: file.txt"));
Expand All @@ -46,13 +51,85 @@ void TestCommitEditor::applyTemplate2() {
// Cursor after inserted files
e.applyTemplate(
QStringLiteral("Description: \nfiles: ${files:3}\nCursorPosition: %|"),
{"reallylongfilename.txt"});
"", "", {"reallylongfilename.txt"});
QCOMPARE(
e.textEdit()->toPlainText(),
QStringLiteral(
"Description: \nfiles: reallylongfilename.txt\nCursorPosition: "));
QCOMPARE(e.textEdit()->textCursor().position(), 60);
}

void TestCommitEditor::applyTemplate3() {
Test::ScratchRepository repo;
CommitEditor e(repo);

// author
e.applyTemplate(
QStringLiteral("Description: \nauthor: ${author}\nCursorPosition: %|"),
"john.doe", "", {"file.txt"});
QCOMPARE(e.textEdit()->toPlainText(),
QStringLiteral("Description: \nauthor: john.doe\nCursorPosition: "));
QCOMPARE(e.textEdit()->textCursor().position(), 47);
}

void TestCommitEditor::applyTemplate4() {
Test::ScratchRepository repo;
CommitEditor e(repo);

// branch
e.applyTemplate(
QStringLiteral("Description: \nbranch: ${branch}\nCursorPosition: %|"),
"john.doe", "bugfix/GTTY-01", {"file.txt"});
QCOMPARE(e.textEdit()->toPlainText(),
QStringLiteral(
"Description: \nbranch: bugfix/GTTY-01\nCursorPosition: "));
QCOMPARE(e.textEdit()->textCursor().position(), 53);
}

void TestCommitEditor::applyTemplate5() {
Test::ScratchRepository repo;
CommitEditor e(repo);

// branch
e.applyTemplate(
QStringLiteral("Description: \nissue: "
"${branch:(GTTY-[0-9]{2})}\nCursorPosition: %|"),
"john.doe", "bugfix/GTTY-01", {"file.txt"});
QCOMPARE(e.textEdit()->toPlainText(),
QStringLiteral("Description: \nissue: GTTY-01\nCursorPosition: "));
QCOMPARE(e.textEdit()->textCursor().position(), 45);
}

void TestCommitEditor::applyTemplate6() {
Test::ScratchRepository repo;
CommitEditor e(repo);

// branch (no match)
e.applyTemplate(
QStringLiteral(
"Description: \nissue: ${branch:(XXX-[0-9]{2})}\nCursorPosition: %|"),
"john.doe", "bugfix/GTTY-01", {"file.txt"});
QCOMPARE(e.textEdit()->toPlainText(),
QStringLiteral("Description: \nissue: \nCursorPosition: "));
QCOMPARE(e.textEdit()->textCursor().position(), 38);
}

void TestCommitEditor::applyTemplate7() {
Test::ScratchRepository repo;
CommitEditor e(repo);

// author, branch and files
e.applyTemplate(
QStringLiteral(
"Description: \nauthor: ${author} \nissue: ${branch:(GTTY-[0-9]{2})} "
"\nfiles: ${files:2} \nCursorPosition: %|"),
"john.doe", "bugfix/GTTY-02", {"file1.txt", "file2.txt", "file3.txt"});
QCOMPARE(e.textEdit()->toPlainText(),
QStringLiteral(
"Description: \nauthor: john.doe \nissue: GTTY-02 \nfiles: "
"file1.txt, file2.txt, and 1 more file \nCursorPosition: "));
QCOMPARE(e.textEdit()->textCursor().position(), 110);
}

TEST_MAIN(TestCommitEditor)
#include "commitEditor.moc"
Loading