VcsBase: Create common base diff editor controller

Reuse it in subversion and git plugins.
It makes subversion diff more asynchronous than before.
Make VcsBase plugin dependand on DiffEditor plugin.

Change-Id: Iafea2941b890a95a269362e022af2dc03cdea550
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Jarek Kobus
2017-06-30 14:50:28 +02:00
parent 0a2590e7be
commit 4bea049c45
8 changed files with 341 additions and 197 deletions

View File

@@ -43,7 +43,6 @@
#include <coreplugin/idocument.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <utils/algorithm.h>
#include <utils/asconst.h>
@@ -54,9 +53,9 @@
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <utils/runextensions.h>
#include <vcsbase/submitfilemodel.h>
#include <vcsbase/vcsbasediffeditorcontroller.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorconfig.h>
#include <vcsbase/vcsbaseplugin.h>
@@ -112,138 +111,31 @@ const unsigned silentFlags = unsigned(VcsCommand::SuppressCommandLogging
| VcsCommand::SuppressStdErr
| VcsCommand::SuppressFailMessage);
static void readPatch(QFutureInterface<QList<FileData>> &futureInterface,
const QString &patch)
{
bool ok;
const QList<FileData> &fileDataList = DiffUtils::readPatch(patch, &ok);
futureInterface.reportResult(fileDataList);
}
/////////////////////////////////////
class BaseController : public DiffEditorController
class GitDiffEditorController : public VcsBaseDiffEditorController
{
Q_OBJECT
public:
BaseController(IDocument *document, const QString &dir);
~BaseController();
GitDiffEditorController(IDocument *document, const QString &workingDirectory);
protected:
void runCommand(const QList<QStringList> &args, QTextCodec *codec = 0);
virtual void processCommandOutput(const QString &output);
void runCommand(const QList<QStringList> &args, QTextCodec *codec = nullptr);
QStringList addConfigurationArguments(const QStringList &args) const;
QStringList addHeadWhenCommandInProgress() const;
void setStartupFile(const QString &startupFile) { m_startupFile = startupFile; }
QString startupFile() const { return m_startupFile; }
QString directory() const { return m_directory; }
private:
void processDiff(const QString &patch);
void storeOutput(const QString &output);
void cancelReload();
void commandFinished(bool success);
void processingFinished();
const QString m_directory;
QString m_startupFile;
QString m_output;
QPointer<VcsCommand> m_command;
QFutureWatcher<QList<FileData>> m_processWatcher;
};
BaseController::BaseController(IDocument *document, const QString &dir) :
DiffEditorController(document),
m_directory(dir),
m_command(0)
GitDiffEditorController::GitDiffEditorController(IDocument *document, const QString &workingDirectory) :
VcsBaseDiffEditorController(document, GitPlugin::client(), workingDirectory)
{
connect(&m_processWatcher, &QFutureWatcher<QList<FileData>>::finished,
this, &BaseController::processingFinished);
}
BaseController::~BaseController()
void GitDiffEditorController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
{
cancelReload();
VcsBaseDiffEditorController::runCommand(args, diffExecutionFlags(), codec);
}
void BaseController::cancelReload()
{
if (m_command) {
m_command->disconnect();
m_command->cancel();
m_command.clear();
}
if (m_processWatcher.future().isRunning()) {
m_processWatcher.future().cancel();
m_processWatcher.setFuture(QFuture<QList<FileData>>());
}
m_output = QString();
}
void BaseController::commandFinished(bool success)
{
if (m_command)
m_command.clear();
if (!success) {
cancelReload();
reloadFinished(success);
return;
}
processCommandOutput(m_output);
}
void BaseController::runCommand(const QList<QStringList> &args, QTextCodec *codec)
{
cancelReload();
m_command = new VcsCommand(directory(), GitPlugin::client()->processEnvironment());
m_command->setCodec(codec ? codec : EditorManager::defaultTextCodec());
connect(m_command.data(), &VcsCommand::stdOutText, this, &BaseController::storeOutput);
connect(m_command.data(), &VcsCommand::finished, this, &BaseController::commandFinished);
m_command->addFlags(diffExecutionFlags());
for (const QStringList &arg : args) {
QTC_ASSERT(!arg.isEmpty(), continue);
m_command->addJob(GitPlugin::client()->vcsBinary(), arg, GitPlugin::client()->vcsTimeoutS());
}
m_command->execute();
}
void BaseController::storeOutput(const QString &output)
{
m_output = output;
}
void BaseController::processCommandOutput(const QString &output)
{
processDiff(output);
}
void BaseController::processDiff(const QString &patch)
{
m_processWatcher.setFuture(Utils::runAsync(&readPatch, patch));
Core::ProgressManager::addTask(m_processWatcher.future(),
tr("Processing diff"), "DiffEditor");
}
void BaseController::processingFinished()
{
const QList<FileData> fileDataList = m_processWatcher.future().result();
setDiffFiles(fileDataList, directory(), startupFile());
reloadFinished(true);
}
QStringList BaseController::addConfigurationArguments(const QStringList &args) const
QStringList GitDiffEditorController::addConfigurationArguments(const QStringList &args) const
{
QTC_ASSERT(!args.isEmpty(), return args);
@@ -261,23 +153,23 @@ QStringList BaseController::addConfigurationArguments(const QStringList &args) c
return realArgs;
}
QStringList BaseController::addHeadWhenCommandInProgress() const
QStringList GitDiffEditorController::addHeadWhenCommandInProgress() const
{
// This is workaround for lack of support for merge commits and resolving conflicts,
// we compare the current state of working tree to the HEAD of current branch
// instead of showing unsupported combined diff format.
GitClient::CommandInProgress commandInProgress = GitPlugin::client()->checkCommandInProgress(directory());
GitClient::CommandInProgress commandInProgress = GitPlugin::client()->checkCommandInProgress(workingDirectory());
if (commandInProgress != GitClient::NoCommand)
return {HEAD};
return QStringList();
}
class RepositoryDiffController : public BaseController
class RepositoryDiffController : public GitDiffEditorController
{
Q_OBJECT
public:
RepositoryDiffController(IDocument *document, const QString &dir) :
BaseController(document, dir)
GitDiffEditorController(document, dir)
{ }
void reload() override;
@@ -290,12 +182,12 @@ void RepositoryDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class FileDiffController : public BaseController
class FileDiffController : public GitDiffEditorController
{
Q_OBJECT
public:
FileDiffController(IDocument *document, const QString &dir, const QString &fileName) :
BaseController(document, dir),
GitDiffEditorController(document, dir),
m_fileName(fileName)
{ }
@@ -314,13 +206,13 @@ void FileDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class FileListDiffController : public BaseController
class FileListDiffController : public GitDiffEditorController
{
Q_OBJECT
public:
FileListDiffController(IDocument *document, const QString &dir,
const QStringList &stagedFiles, const QStringList &unstagedFiles) :
BaseController(document, dir),
GitDiffEditorController(document, dir),
m_stagedFiles(stagedFiles),
m_unstagedFiles(unstagedFiles)
{ }
@@ -351,13 +243,13 @@ void FileListDiffController::reload()
runCommand(argLists);
}
class ProjectDiffController : public BaseController
class ProjectDiffController : public GitDiffEditorController
{
Q_OBJECT
public:
ProjectDiffController(IDocument *document, const QString &dir,
const QStringList &projectPaths) :
BaseController(document, dir),
GitDiffEditorController(document, dir),
m_projectPaths(projectPaths)
{ }
@@ -374,13 +266,13 @@ void ProjectDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class BranchDiffController : public BaseController
class BranchDiffController : public GitDiffEditorController
{
Q_OBJECT
public:
BranchDiffController(IDocument *document, const QString &dir,
const QString &branch) :
BaseController(document, dir),
GitDiffEditorController(document, dir),
m_branch(branch)
{ }
@@ -397,12 +289,12 @@ void BranchDiffController::reload()
runCommand(QList<QStringList>() << addConfigurationArguments(args));
}
class ShowController : public BaseController
class ShowController : public GitDiffEditorController
{
Q_OBJECT
public:
ShowController(IDocument *document, const QString &dir, const QString &id) :
BaseController(document, dir),
GitDiffEditorController(document, dir),
m_id(id),
m_state(Idle)
{ }
@@ -421,7 +313,7 @@ void ShowController::reload()
// stage 1
m_state = GettingDescription;
const QStringList args = {"show", "-s", noColorOption, showFormatC, m_id};
runCommand(QList<QStringList>() << args, GitPlugin::client()->encoding(directory(), "i18n.commitEncoding"));
runCommand(QList<QStringList>() << args, GitPlugin::client()->encoding(workingDirectory(), "i18n.commitEncoding"));
setStartupFile(VcsBasePlugin::source(document()));
}
@@ -429,7 +321,7 @@ void ShowController::processCommandOutput(const QString &output)
{
QTC_ASSERT(m_state != Idle, return);
if (m_state == GettingDescription) {
setDescription(GitPlugin::client()->extendedShowDescription(directory(), output));
setDescription(GitPlugin::client()->extendedShowDescription(workingDirectory(), output));
// stage 2
m_state = GettingDiff;
const QStringList args = {"show", "--format=format:", // omit header, already generated
@@ -437,7 +329,7 @@ void ShowController::processCommandOutput(const QString &output)
runCommand(QList<QStringList>() << addConfigurationArguments(args));
} else if (m_state == GettingDiff) {
m_state = Idle;
BaseController::processCommandOutput(output);
GitDiffEditorController::processCommandOutput(output);
}
}