Commit 1164d2c6 authored by Waqar Ahmed's avatar Waqar Ahmed
Browse files

Implement new branch simple checkcout

parent f4d90a82
......@@ -199,7 +199,12 @@ BranchesDialog::BranchesDialog(QWidget *parent, KTextEditor::MainWindow *mainWin
void BranchesDialog::openDialog()
{
const QVector<GitUtils::Branch> branches = GitUtils::getAllBranches(m_projectPath);
GitUtils::Branch newBranch;
newBranch.name = QStringLiteral("Create New Branch");
GitUtils::Branch newBranchFrom;
newBranchFrom.name = QStringLiteral("Create New Branch From...");
QVector<GitUtils::Branch> branches{newBranch, newBranchFrom};
/*QVector<GitUtils::Branch> */ branches << GitUtils::getAllBranches(m_projectPath);
m_model->refresh(branches);
reselectFirst();
......@@ -259,19 +264,29 @@ void BranchesDialog::onCheckoutDone()
Q_EMIT branchChanged(res.branch);
}
KTextEditor::Message *msg = new KTextEditor::Message(msgStr, msgType);
msg->setPosition(KTextEditor::Message::TopInView);
msg->setAutoHide(3000);
msg->setAutoHideMode(KTextEditor::Message::Immediate);
msg->setView(m_mainWindow->activeView());
m_mainWindow->activeView()->document()->postMessage(msg);
sendMessage(msgStr, msgType == KTextEditor::Message::Warning);
}
void BranchesDialog::slotReturnPressed()
{
if (m_model->rowCount() == 0) {
createNewBranch(m_lineEdit->text());
;
return;
}
const auto branch = m_proxyModel->data(m_treeView->currentIndex(), BranchesDialogModel::CheckoutName).toString();
QFuture<GitUtils::CheckoutResult> future = QtConcurrent::run(&GitUtils::checkoutBranch, m_projectPath, branch);
m_checkoutWatcher.setFuture(future);
const auto itemType = (BranchesDialogModel::ItemType)m_proxyModel->data(m_treeView->currentIndex(), BranchesDialogModel::ItemTypeRole).toInt();
if (itemType == BranchesDialogModel::BranchItem) {
QFuture<GitUtils::CheckoutResult> future = QtConcurrent::run(&GitUtils::checkoutBranch, m_projectPath, branch);
m_checkoutWatcher.setFuture(future);
} else if (itemType == BranchesDialogModel::CreateBranch) {
m_model->clear();
m_lineEdit->setPlaceholderText(i18n("Enter new branch name. Press 'Esc' to cancel."));
return;
} else if (itemType == BranchesDialogModel::CreateBranchFrom) {
}
m_lineEdit->clear();
hide();
......@@ -283,6 +298,36 @@ void BranchesDialog::reselectFirst()
m_treeView->setCurrentIndex(index);
}
void BranchesDialog::sendMessage(const QString &message, bool warn)
{
KTextEditor::Message *msg = new KTextEditor::Message(message, warn ? KTextEditor::Message::Warning : KTextEditor::Message::Positive);
msg->setPosition(KTextEditor::Message::TopInView);
msg->setAutoHide(3000);
msg->setAutoHideMode(KTextEditor::Message::Immediate);
msg->setView(m_mainWindow->activeView());
m_mainWindow->activeView()->document()->postMessage(msg);
}
void BranchesDialog::createNewBranch(const QString &branch)
{
if (branch.isEmpty()) {
m_lineEdit->clear();
hide();
return;
}
// the branch name might be invalid, let git handle it
const GitUtils::CheckoutResult r = GitUtils::checkoutNewBranch(m_projectPath, branch);
const bool warn = true;
if (r.returnCode == 0) {
sendMessage(i18n("Checked out to new branch: %1", r.branch), !warn);
} else {
sendMessage(i18n("Failed to create new branch. Error \"%1\"", r.error), warn);
}
m_lineEdit->clear();
hide();
}
void BranchesDialog::updateViewGeometry()
{
m_treeView->resizeColumnToContents(0);
......
......@@ -45,8 +45,8 @@ private Q_SLOTS:
void onCheckoutDone();
private:
void sendMessage(const QString& message, bool warn);
void createNewBranch(const QString& branch);
void sendMessage(const QString &message, bool warn);
void createNewBranch(const QString &branch);
private:
QTreeView *m_treeView;
......
......@@ -43,12 +43,15 @@ QVariant BranchesDialogModel::data(const QModelIndex &idx, int role) const
return branch.score;
} else if (role == Role::OriginalSorting) {
return branch.dateSort;
} else if (role == Qt::DecorationRole) {
static const auto branchIcon = QIcon(QStringLiteral(":/kxmlgui5/kateproject/sc-apps-git.svg"));
return branchIcon;
} else if (role == Role::CheckoutName) {
return branch.type == GitUtils::RefType::Remote ? branch.name.mid(branch.remote.size() + 1) : branch.name;
return branch.refType == GitUtils::RefType::Remote ? branch.name.mid(branch.remote.size() + 1) : branch.name;
} else if (role == Role::RefType) {
return branch.type;
return branch.refType;
} else if (role == Role::ItemTypeRole) {
return branch.itemType;
}
return {};
......@@ -56,7 +59,17 @@ QVariant BranchesDialogModel::data(const QModelIndex &idx, int role) const
void BranchesDialogModel::refresh(QVector<GitUtils::Branch> branches)
{
Branch create{branches.at(0).name, {}, {}, 0, 0, ItemType::CreateBranch};
Branch createFrom{branches.at(1).name, {}, {}, 0, 1, ItemType::CreateBranchFrom};
QVector<Branch> temp{create, createFrom};
for (int i = 2; i < branches.size(); ++i) {
temp.append({branches.at(i).name, branches.at(i).remote, branches.at(i).type, -1, i, ItemType::BranchItem});
}
beginResetModel();
m_modelEntries = std::move(branches);
m_modelEntries = std::move(temp);
// m_modelEntries = std::move(branches);
endResetModel();
}
......@@ -17,17 +17,20 @@ class BranchesDialogModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum Role {
FuzzyScore = Qt::UserRole + 1,
OriginalSorting,
CheckoutName,
RefType,
};
enum Role { FuzzyScore = Qt::UserRole + 1, OriginalSorting, CheckoutName, RefType, Creator, ItemTypeRole };
enum ItemType { BranchItem, CreateBranch, CreateBranchFrom };
explicit BranchesDialogModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &idx, int role) const override;
void refresh(QVector<GitUtils::Branch> branches);
void clear()
{
beginResetModel();
QVector<Branch>().swap(m_modelEntries);
endResetModel();
}
bool setData(const QModelIndex &index, const QVariant &value, int role) override
{
......@@ -42,7 +45,16 @@ public:
}
private:
QVector<GitUtils::Branch> m_modelEntries;
struct Branch {
QString name;
QString remote;
GitUtils::RefType refType;
int score;
int dateSort;
ItemType itemType;
};
QVector<BranchesDialogModel::Branch> m_modelEntries;
// QVector<GitUtils::Branch> m_modelEntries;
};
#endif
......@@ -5,10 +5,9 @@
*/
#include "gitutils.h"
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QProcess>
#include <QRegularExpression>
bool GitUtils::isGitRepo(const QString &repo)
{
......@@ -49,41 +48,77 @@ GitUtils::CheckoutResult GitUtils::checkoutBranch(const QString &repo, const QSt
return res;
}
GitUtils::CheckoutResult GitUtils::checkoutNewBranch(const QString &repo, const QString &newBranch, const QString &fromBranch)
{
QProcess git;
git.setWorkingDirectory(repo);
QStringList args{QStringLiteral("checkout"), QStringLiteral("-q"), QStringLiteral("-b"), newBranch};
if (!fromBranch.isEmpty()) {
args.append(fromBranch);
}
git.start(QStringLiteral("git"), args);
CheckoutResult res;
res.branch = newBranch;
if (git.waitForStarted() && git.waitForFinished(-1)) {
res.returnCode = git.exitCode();
res.error = QString::fromUtf8(git.readAllStandardError());
}
return res;
}
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
constexpr auto SkipEmptyParts = QString::SkipEmptyParts;
#else
constexpr auto SkipEmptyParts = Qt::SkipEmptyParts;
#endif
static GitUtils::Branch parseLocalBranch(const QString &raw)
{
auto data = raw.split(QStringLiteral("{sp}"), SkipEmptyParts);
return GitUtils::Branch{data.first().remove(QLatin1String("refs/heads/")), QString(), GitUtils::Head};
}
static GitUtils::Branch parseRemoteBranch(const QString &raw)
{
auto data = raw.split(QStringLiteral("{sp}"), SkipEmptyParts);
int indexofRemote = data.at(0).indexOf(QLatin1Char('/'), 13);
return GitUtils::Branch{data.first().remove(QLatin1String("refs/remotes/")), data.at(0).mid(13, indexofRemote - 13), GitUtils::Remote};
}
QVector<GitUtils::Branch> GitUtils::getAllBranchesAndTags(const QString &repo, RefType ref)
{
// git for-each-ref --format '%(refname) %(objectname) %(*objectname)'
QProcess git;
git.setWorkingDirectory(repo);
QStringList args{QStringLiteral("for-each-ref"), QStringLiteral("--format"), QStringLiteral("%(refname)"), QStringLiteral("--sort=-committerdate")};
QStringList args{QStringLiteral("for-each-ref"), QStringLiteral("--format"), QStringLiteral("%(refname){sp}"), QStringLiteral("--sort=-committerdate")};
if (ref & RefType::Head) {
args.append(QStringLiteral("refs/heads"));
}
if (ref & RefType::Remote) {
args.append(QStringLiteral("refs/remotes"));
}
if (ref & RefType::Tag) {
args.append(QStringLiteral("refs/tags"));
args.append(QStringLiteral("--sort=-taggerdate"));
}
git.start(QStringLiteral("git"), args);
QVector<Branch> branches;
if (git.waitForStarted() && git.waitForFinished(-1)) {
QString gitout = QString::fromUtf8(git.readAllStandardOutput());
QVector<QStringRef> out = gitout.splitRef(QLatin1Char('\n'));
static const QRegularExpression headRe(QStringLiteral("^refs/heads/([^ ]+)$"));
static const QRegularExpression remoteRe(QStringLiteral("^refs/remotes/([^/]+)/([^ ]+)"));
static const QRegularExpression tagRe(QStringLiteral("^refs/tags/([^ ]+)$"));
QStringList out = gitout.split(QLatin1Char('\n'));
branches.reserve(out.size());
QRegularExpressionMatch m;
// clang-format off
for (const auto &o : out) {
if (ref & Head && (m = headRe.match(o)).hasMatch()) {
branches.append({m.captured(1),
QString(), // no remote
RefType::Head,
-1});
} else if (ref & Remote && (m = remoteRe.match(o)).hasMatch()) {
branches.append({m.captured(1).append(QLatin1Char('/') + m.captured(2)),
m.captured(1),
RefType::Remote,
-1});
} else if (ref & Tag && (m = tagRe.match(o)).hasMatch()) {
branches.append({m.captured(1),
QString(), // no remote
RefType::Tag,
-1});
if (ref & Head && o.startsWith(QLatin1String("refs/heads"))) {
branches.append(parseLocalBranch(o));
} else if (ref & Remote && o.startsWith(QLatin1String("refs/remotes"))) {
branches.append(parseRemoteBranch(o));
} else if (ref & Tag && o.startsWith(QLatin1String("refs/tags/"))) {
int indexofSp = o.indexOf(QLatin1String("{sp}"));
branches.append({o.mid(10, indexofSp), {}, RefType::Tag});
}
}
// clang-format on
......
......@@ -17,9 +17,15 @@ enum RefType {
All = 0x7,
};
/**
* @brief Represents a branch
*/
struct Branch {
/** Branch name */
QString name;
/** remote name, will be empty for local branches */
QString remote;
/** Ref type @see RefType */
RefType type;
};
......@@ -35,6 +41,8 @@ QString getCurrentBranchName(const QString &repo);
CheckoutResult checkoutBranch(const QString &repo, const QString &branch);
CheckoutResult checkoutNewBranch(const QString &repo, const QString &newBranch, const QString &fromBranch = QString());
/**
* @brief get all local and remote branches
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment