Commit 41359c04 authored by Waqar Ahmed's avatar Waqar Ahmed
Browse files

Remove raw diff stuff

Now we use DiffWidget for diff viewing
parent 60d3b464
......@@ -589,7 +589,7 @@ void KateGitBlamePluginView::showDiffForFile(const QByteArray &diffContents, con
{
auto mw = m_mainWindow->window();
DiffParams d;
d.tabTitle = file;
d.srcFile = file;
QMetaObject::invokeMethod(mw, "showDiff", Q_ARG(QByteArray, diffContents), Q_ARG(DiffParams, d));
}
......
......@@ -75,7 +75,6 @@ target_sources(
tools/flake8.cpp
tools/shellcheck.cpp
git/gitdiff.cpp
git/gitutils.cpp
git/gitstatus.cpp
......
......@@ -5,8 +5,10 @@
*/
#include "comparebranchesview.h"
#include "diffparams.h"
#include "kateprojectpluginview.h"
#include "kateprojectworker.h"
#include "ktexteditor_utils.h"
#include <gitprocess.h>
......@@ -18,6 +20,7 @@
#include <KColorScheme>
#include <KLocalizedString>
#include <KTextEditor/MainWindow>
class DiffStyleDelegate : public QStyledItemDelegate
{
......@@ -168,5 +171,10 @@ void CompareBranchesView::showDiff(const QModelIndex &idx)
return;
}
}
m_pluginView->showDiffInFixedView(git.readAllStandardOutput());
auto mw = m_pluginView->mainWindow()->window();
DiffParams d;
d.tabTitle = QStringLiteral("Diff %1[%2 .. %3]").arg(Utils::fileNameFromPath(file)).arg(m_fromBr).arg(m_toBr);
d.workingDir = m_gitDir;
d.arguments = git.arguments();
QMetaObject::invokeMethod(mw, "showDiff", Q_ARG(QByteArray, git.readAllStandardOutput()), Q_ARG(DiffParams, d));
}
This diff is collapsed.
/*
SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de>
SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
SPDX-FileCopyrightText: 2020 Jonathan Verner <jonathan.verner@matfyz.cz>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KDEVPLATFORM_VCSDIFF_H
#define KDEVPLATFORM_VCSDIFF_H
#include <QMetaType>
#include <QVector>
#include <QtGlobal>
#include <memory>
class QUrl;
class QString;
/**
* A class representing a unified diff, possibly with
* conflict markers.
*
* A diff is assumed to be a collection of hunks, where each hunk has the
* following structure:
*
* METADATA
* --- a/SOURCE_PATH
* +++ b/TARGET_PATH
* HUNK1 HEADER
* HUNK1 CONTENT
* [METADATA]
* HUNK2 HEADER
* HUNK2 CONTENT
* ...
*
* METADATA are lines which start with anything except for a '+', '-' and ' '.
* The path specifications may optionally precede a hunk and are assumed to
* apply to all following hunks until a new path specification
* is found. These indicate the files for which the diff is generated.
*
* Hunk Header
* ------------
*
* Each hunk header has the following form
*
* @@ -SRC_OFFSET[, SRC_CHANGES_COUNT] +TGT_OFFSET[, TGT_CHANGES_COUNT] @@ Heading
*
* where the SRC_OFFSET is a 1-based line index pointing to the source file where
* the hunk applies and TGT_OFFSET is a 1-based line index pointing to the target
* file where the hunk applies. The optional SRC_CHANGES_COUNTS (assumed to be 1
* if not present) specifies the number of context lines plus the number of
* deleted lines. Similarly, the optional TGT_CHANGES_COUNT specifies the
* number of context lines plus the number of added lines. The Heading, used as a
* visual aid for users, is supposed to show the line where the nearest enclosing
* function scope of the hunk starts.
*
* Hunk Content
* ------------
*
* The hunk content is a collection of lines which starting with '+' (additions),
* '-' (deletions) and ' ' (context lines; empty lines are also take to be context
* lines). Additionally, a hunk may contain conflict markers which are of the form
*
* >>>>>>> our ref
* our content
* ...
* =======
* their content
* ...
* <<<<<<< their ref
*
* and indicate unresolved conflicts.
*
*/
class VcsDiff
{
public:
/* Used to represent a patch or its inverse */
enum DiffDirection {
Normal = 0 /**< the unchanged patch */
,
Forward = 0 /**< the unchanged patch */
,
Reverse = 1 /**< the inverse of the patch (i.e. a new patch which, when applied, undoes the old patch) */
};
VcsDiff();
~VcsDiff();
VcsDiff(VcsDiff &&rhs);
/**
* @returns the source of the diff.
*/
QString diff() const;
/** @returns the base directory of the diff. */
QUrl baseDiff() const;
/**
* Depth - number of directories to left-strip from paths in the patch - see "patch -p"
* Defaults to 0
*/
uint depth() const;
/** Sets the base directory of the diff to the @p url */
void setBaseDiff(const QUrl &url);
/** Sets the depth of the diff to @p depth */
void setDepth(const uint depth);
/** Sets the diff source and parses it.
*
* @param diff the diff in unified diff format
*/
void setDiff(const QString &diff);
/** @returns whether or not there are changes in the diff */
bool isEmpty() const;
/**
* Creates a standalone diff containing the differences in a given range.
*
* @returns a diff containing only the changes from the current diff
* which are in the range startLine-endLine (in the diff text)
*
* @param startLine 0-based line number (in the diff) of the first line in the range
* @param endLine 0-based line number (in the diff) of the last line in the range
* @param dir if set to Reverse, the role of src and tgt are reversed, i.e. a diff is
* generated which can be applied to the target to get the source.
*/
VcsDiff subDiff(const uint startLine, const uint endLine, DiffDirection dir = Normal) const;
/**
* Creates a new standalone diff from a single hunk identified by a containing line.
*
* @returns a diff containing only the changes from hunk containing
* the line the line
*
* @param line 0-based line number (in the diff) of the line in the hunk
* @param dir if set to Reverse, the role of src and tgt are reversed, i.e. a diff is
* generated which can be applied to the target to get the source.
*/
VcsDiff subDiffHunk(const uint line, DiffDirection dir = Normal) const;
/**
* Maps a line position in the diff to a corresponding line position in the source file.
*
* @param line a 0-based line position in the diff
* @returns the 0-based line position in the source file or -1 if no such position exists.
*/
int diffLineToSourceLine(const uint line) const;
/**
* Maps a line position in the diff to a corresponding line position in the source file.
*
* @param line a 0-based line position in the diff
* @returns the 0-based line position in the source file or -1 if no such position exists.
*/
int diffLineToTargetLine(const uint line) const;
/**
* Represents a pair of files which are compared
*/
struct FilePair {
QString source;
QString target;
bool operator==(const FilePair p) const
{
return (source == p.source && target == p.target);
}
};
/**
* @returns a list of filename pairs that the patch applies to
*
* @note: Each file-pair is only listed once for each consecutive run
* of hunks which apply to it.
*/
const QVector<FilePair> fileNames() const;
private:
std::unique_ptr<class VcsDiffPrivate> d;
};
#endif
......@@ -10,7 +10,6 @@
#include "branchesdialog.h"
#include "comparebranchesview.h"
#include "diffparams.h"
#include "git/gitdiff.h"
#include "gitcommitdialog.h"
#include "gitstatusmodel.h"
#include "kateproject.h"
......@@ -624,7 +623,7 @@ void GitWidget::openAtHEAD(const QString &file)
startHostProcess(*git, QProcess::ReadOnly);
}
void GitWidget::showDiff(const QString &file, bool staged, bool showInKate)
void GitWidget::showDiff(const QString &file, bool staged)
{
auto args = QStringList{QStringLiteral("diff")};
if (staged) {
......@@ -637,54 +636,19 @@ void GitWidget::showDiff(const QString &file, bool staged, bool showInKate)
}
auto git = gitp(args);
connect(git, &QProcess::finished, this, [this, file, staged, git, showInKate](int exitCode, QProcess::ExitStatus es) {
connect(git, &QProcess::finished, this, [this, file, staged, git](int exitCode, QProcess::ExitStatus es) {
if (es != QProcess::NormalExit || exitCode != 0) {
sendMessage(i18n("Failed to get Diff of file: %1", QString::fromUtf8(git->readAllStandardError())), true);
} else {
if (showInKate) {
auto mw = mainWindow()->window();
DiffParams d;
d.srcFile = file;
d.workingDir = m_activeGitDirPath;
d.arguments = git->arguments();
d.flags.setFlag(DiffParams::Flag::ShowStage, !staged);
d.flags.setFlag(DiffParams::Flag::ShowUnstage, staged);
d.flags.setFlag(DiffParams::Flag::ShowDiscard, !staged);
QMetaObject::invokeMethod(mw, "showDiff", Q_ARG(QByteArray, git->readAllStandardOutput()), Q_ARG(DiffParams, d));
return;
}
auto addContextMenuActions = [this, file, staged](KTextEditor::View *v) {
QMenu *menu = new QMenu(v);
if (!staged) {
auto sh = menu->addAction(i18n("Stage Hunk"));
auto sl = menu->addAction(i18n("Stage Lines"));
auto dl = menu->addAction(i18n("Discard Lines"));
connect(sh, &QAction::triggered, v, [=] {
applyDiff(file, ApplyFlags::Hunk, v);
});
connect(sl, &QAction::triggered, v, [=] {
applyDiff(file, ApplyFlags::None, v);
});
connect(dl, &QAction::triggered, v, [=] {
applyDiff(file, ApplyFlags::Discard, v);
});
} else {
auto ush = menu->addAction(i18n("Unstage Hunk"));
auto usl = menu->addAction(i18n("Unstage Lines"));
connect(ush, &QAction::triggered, v, [=] {
applyDiff(file, ApplyFlags(Staged | Hunk), v);
});
connect(usl, &QAction::triggered, v, [=] {
applyDiff(file, ApplyFlags::Staged, v);
});
}
menu->addActions(v->contextMenu()->actions());
v->setContextMenu(menu);
};
m_pluginView->showDiffInFixedView(git->readAllStandardOutput(), addContextMenuActions);
auto mw = mainWindow()->window();
DiffParams d;
d.srcFile = file;
d.workingDir = m_activeGitDirPath;
d.arguments = git->arguments();
d.flags.setFlag(DiffParams::Flag::ShowStage, !staged);
d.flags.setFlag(DiffParams::Flag::ShowUnstage, staged);
d.flags.setFlag(DiffParams::Flag::ShowDiscard, !staged);
QMetaObject::invokeMethod(mw, "showDiff", Q_ARG(QByteArray, git->readAllStandardOutput()), Q_ARG(DiffParams, d));
}
git->deleteLater();
});
......@@ -743,70 +707,6 @@ void GitWidget::commitChanges(const QString &msg, const QString &desc, bool sign
startHostProcess(*git, QProcess::ReadOnly);
}
QString GitWidget::getDiff(KTextEditor::View *v, bool hunk, bool alreadyStaged)
{
auto range = v->selectionRange();
int startLine = range.start().line();
int endLine = range.end().line();
if (range.isEmpty() || hunk) {
startLine = endLine = v->cursorPosition().line();
}
VcsDiff full;
full.setDiff(v->document()->text());
full.setBaseDiff(QUrl::fromUserInput(m_activeGitDirPath));
const auto dir = alreadyStaged ? VcsDiff::Reverse : VcsDiff::Forward;
VcsDiff selected = hunk ? full.subDiffHunk(startLine, dir) : full.subDiff(startLine, endLine, dir);
return selected.diff();
}
void GitWidget::applyDiff(const QString &fileName, ApplyFlags flags, KTextEditor::View *v)
{
if (!v) {
return;
}
const QString diff = getDiff(v, flags & Hunk, flags & (Staged | Discard));
if (diff.isEmpty()) {
return;
}
QTemporaryFile *file = new QTemporaryFile(this);
if (!file->open()) {
sendMessage(i18n("Failed to stage selection"), true);
return;
}
file->write(diff.toUtf8());
file->close();
QProcess *git = nullptr;
if (flags & Discard) {
git = gitp({QStringLiteral("apply"), file->fileName()});
} else {
git = gitp({QStringLiteral("apply"), QStringLiteral("--index"), QStringLiteral("--cached"), file->fileName()});
}
connect(git, &QProcess::finished, this, [=](int exitCode, QProcess::ExitStatus es) {
if (es != QProcess::NormalExit || exitCode != 0) {
sendMessage(i18n("Failed to stage: %1", QString::fromUtf8(git->readAllStandardError())), true);
} else {
// close and reopen doc to show updated diff
if (v && v->document()) {
showDiff(fileName, flags & Staged, false);
}
// must come at the end
QTimer::singleShot(10, this, [this] {
updateStatus();
});
}
delete file;
git->deleteLater();
});
startHostProcess(*git, QProcess::ReadOnly);
}
void GitWidget::openCommitChangesDialog(bool amend)
{
if (!amend && m_model->stagedFiles().isEmpty()) {
......@@ -1048,7 +948,11 @@ void GitWidget::createStashDialog(StashMode m, const QString &gitPath)
auto stashDialog = new StashDialog(this, mainWindow()->window(), gitPath);
connect(stashDialog, &StashDialog::message, this, &GitWidget::sendMessage);
connect(stashDialog, &StashDialog::showStashDiff, this, [this](const QByteArray &r) {
m_pluginView->showDiffInFixedView(r);
auto mw = mainWindow()->window();
DiffParams d;
d.tabTitle = i18n("Diff - stash");
d.workingDir = m_activeGitDirPath;
QMetaObject::invokeMethod(mw, "showDiff", Q_ARG(QByteArray, r), Q_ARG(DiffParams, d));
});
connect(stashDialog, &StashDialog::done, this, [this, stashDialog] {
updateStatus();
......@@ -1139,7 +1043,7 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
discardAct->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete-remove")));
auto ignoreAct = untracked ? menu.addAction(i18n("Open .gitignore")) : nullptr;
auto diff = !untracked ? menu.addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), i18n("Show diff")) : nullptr;
auto diff = !untracked ? menu.addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), i18n("Show Diff")) : nullptr;
// get files
auto act = menu.exec(m_treeView->viewport()->mapToGlobal(e->pos()));
if (!act) {
......@@ -1177,7 +1081,7 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
m_mainWin->openUrl(QUrl::fromLocalFile(*it));
}
} else if (!untracked && act == diff) {
showDiff(QString(), false, true);
showDiff(QString(), false);
}
} else if (treeItem == GitStatusModel::NodeFile) {
QMenu menu;
......@@ -1186,8 +1090,7 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
const bool untracked = statusItemType == GitStatusModel::NodeUntrack;
auto openFile = menu.addAction(i18n("Open File"));
auto diff = untracked ? nullptr : menu.addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), i18n("Diff"));
auto showDiffAct = untracked ? nullptr : menu.addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), i18n("Show Raw Diff"));
auto showDiffAct = untracked ? nullptr : menu.addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), i18n("Show Diff"));
auto launchDifftoolAct = untracked ? nullptr : menu.addAction(QIcon::fromTheme(QStringLiteral("kdiff3")), i18n("Show in External Git Diff Tool"));
auto openAtHead = untracked ? nullptr : menu.addAction(i18n("Open at HEAD"));
auto stageAct = staged ? menu.addAction(i18n("Unstage File")) : menu.addAction(i18n("Stage File"));
......@@ -1214,8 +1117,8 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
}
} else if (act == openAtHead && !untracked) {
openAtHEAD(idx.data(GitStatusModel::FileNameRole).toString());
} else if ((showDiffAct || diff) && (act == showDiffAct || act == diff) && !untracked) {
showDiff(file, staged, /*showInKate=*/act == diff);
} else if (showDiffAct && act == showDiffAct && !untracked) {
showDiff(file, staged);
} else if (act == discardAct && untracked) {
auto ret = confirm(this, i18n("Are you sure you want to remove this file?"), KStandardGuiItem::remove());
if (ret == KMessageBox::Yes) {
......
......@@ -124,11 +124,9 @@ private:
void discard(const QStringList &files);
void clean(const QStringList &files);
void openAtHEAD(const QString &file);
void showDiff(const QString &file, bool staged, bool showInKate = false);
void showDiff(const QString &file, bool staged);
void launchExternalDiffTool(const QString &file, bool staged);
void commitChanges(const QString &msg, const QString &desc, bool signOff, bool amend = false);
enum ApplyFlags { None = 0, Staged = 1, Hunk = 2, Discard = 4 };
void applyDiff(const QString &fileName, ApplyFlags flags, KTextEditor::View *v);
void branchCompareFiles(const QString &from, const QString &to);
QMenu *stashMenu(KActionCollection *pCollection);
......@@ -137,7 +135,6 @@ private:
void treeViewContextMenuEvent(QContextMenuEvent *e);
void selectedContextMenu(QContextMenuEvent *e);
QString getDiff(KTextEditor::View *view, bool hunk, bool alreadyStaged);
void createStashDialog(StashMode m, const QString &gitPath);
void enableCancel(QProcess *git);
......
......@@ -14,7 +14,6 @@
#include "kateprojectplugin.h"
#include "kateprojectview.h"
#include "ktexteditor_utils.h"
#include <KTextEditor/Command>
#include <ktexteditor/application.h>
#include <ktexteditor/codecompletioninterface.h>
......@@ -830,25 +829,6 @@ void KateProjectPluginView::showProjectTodos()
pgrep->exec(nullptr, QStringLiteral("preg (TODO|FIXME)\\b"), msg);
}
void KateProjectPluginView::showDiffInFixedView(const QByteArray &contents)
{
if (!m_fixedView.view) {
m_fixedView.view = mainWindow()->openUrl(QUrl());
m_fixedView.defaultMenu = m_fixedView.view->contextMenu();
}
auto v = m_fixedView.view;
Utils::KateScrollBarRestorer restorer(v);
v->document()->setText(QString::fromUtf8(contents));
v->document()->setHighlightingMode(QStringLiteral("Diff"));
/** We don't want save dialog on close */
v->document()->setModified(false);
v->setCursorPosition(KTextEditor::Cursor{0, 0});
m_fixedView.restoreMenu();
/** Activate this view */
m_mainWindow->activateView(v->document());
}
void KateProjectPluginView::openTerminal(const QString &dirPath, KateProject *project)
{
m_mainWindow->showToolView(m_toolInfoView);
......
......@@ -113,26 +113,6 @@ public:
return m_plugin;
}
/**
* @brief Shows diff in a fixed view, i.e., the view is recycled instead
* of creating new view every time
* @param contents diff contents
*/
void showDiffInFixedView(const QByteArray &contents);
/**
* Same as above with call back for setting a context menu
*
* @param cb Callback on the view. This should always take KTextEditor::View*
* as a parameter. This is mainly used to plug-in context-menu actions.
*/
template<typename ViewCallback>
void showDiffInFixedView(const QByteArray &contents, ViewCallback cb)
{
showDiffInFixedView(contents);
cb(m_fixedView.view);
}
/**
* Open terminal view at \p dirPath location for project \p project
*/
......
......@@ -26,6 +26,7 @@
#include "katestashmanager.h"
#include "kateupdatedisabler.h"
#include "kateviewspace.h"
#include "ktexteditor_utils.h"
#include <KAboutData>
#include <KActionCollection>
......@@ -1309,19 +1310,14 @@ void KateMainWindow::addWidgetAsTab(QWidget *widget)
void KateMainWindow::showDiff(const QByteArray &wordDiff, const DiffParams &params)
{
auto getFileName = [](const QString &s) {
int lastSlash = s.lastIndexOf(QLatin1Char('/'));
return lastSlash == -1 ? s : s.mid(lastSlash + 1);
};
auto w = new DiffWidget(params, this);
if (!params.tabTitle.isEmpty()) {
w->setWindowTitle(i18n("Diff %1", params.tabTitle));
w->setWindowTitle(params.tabTitle);
} else {
if (params.destFile.isEmpty())
w->setWindowTitle(i18n("Diff %1", getFileName(params.srcFile)));
w->setWindowTitle(i18n("Diff %1", Utils::fileNameFromPath(params.srcFile)));
else
w->setWindowTitle(i18n("Diff %1..%2", getFileName(params.srcFile), getFileName(params.destFile)));
w->setWindowTitle(i18n("Diff %1..%2", Utils::fileNameFromPath(params.srcFile), Utils::fileNameFromPath(params.destFile)));
}
addWidgetAsTab(w);
w->openDiff(wordDiff);
......
......@@ -82,6 +82,12 @@ inline QFont viewFont(KTextEditor::View *view)
return editorFont();
}
inline QString fileNameFromPath(const QString &path)
{
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
return lastSlash == -1 ? path : path.mid(lastSlash + 1);
}
/**
* Return a matching icon for the given document.
* We use the mime type icon for unmodified stuff and the modified one for modified docs.
......
Supports Markdown
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