Vcs: Jump to the current source line in Fossil Annotate editor

* Keep track of the current source line number and pass it to Annotate
  action.
* Add a 'List Versions' toggle in Annotate editor to prepend a list of
  commits that make up the annotated source.
* By default do not show the version list so that annotated line number
  could be matched to the source line.

NOTE: VcsBaseEditorWidget::configurationWidget() query is no longer
available, yet Fossil client needs it in order to process the effective
arguments. So we re-implement it in FossilEditorWidget sub-class.

Change-Id: Idc4c21d074ccf4e1c6d041cce2abceb78665c8f2
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Artur Shepilko
2017-04-20 02:21:51 -05:00
parent ac8005190d
commit 8cc9b5c57d
6 changed files with 127 additions and 44 deletions

View File

@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "fossilclient.h" #include "fossilclient.h"
#include "fossileditor.h"
#include "constants.h" #include "constants.h"
#include <coreplugin/id.h> #include <coreplugin/id.h>
@@ -93,6 +94,13 @@ public:
mapSetting(addToggleButton("|BLAME|", tr("Show Committers")), mapSetting(addToggleButton("|BLAME|", tr("Show Committers")),
settings.boolPointer(FossilSettings::annotateShowCommittersKey)); settings.boolPointer(FossilSettings::annotateShowCommittersKey));
} }
// Force listVersions setting to false by default.
// This way the annotated line number would not get offset by the version list.
settings.setValue(FossilSettings::annotateListVersionsKey, false);
mapSetting(addToggleButton(QLatin1String("--log"), tr("List Versions")),
settings.boolPointer(FossilSettings::annotateListVersionsKey));
} }
}; };
@@ -725,19 +733,34 @@ VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source, VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
VcsBase::VcsBaseEditor::getCodec(source), VcsBase::VcsBaseEditor::getCodec(source),
vcsCmdString.toLatin1().constData(), id); vcsCmdString.toLatin1().constData(), id);
QStringList effectiveArgs = extraOptions;
if (!editor->configurationAdded()) { // We need to be able to re-query the configuration widget for the arguments
if (VcsBase::VcsBaseEditorConfig *editorConfig = createAnnotateEditor(editor)) { // each time the Annotate is requested from the main menu. This allows processing of
// the effective args controlled via configuration widget.
// However VcsBaseEditorWidget no longer stores the configuration widget and thus
// does not support configurationWidget() query.
// So we re-implement the configurationWidget() in FossilEditorWidget sub-class.
auto *fossilEditor = qobject_cast<FossilEditorWidget *>(editor);
QTC_ASSERT(fossilEditor, return editor);
if (!fossilEditor->configurationAdded()) {
if (VcsBase::VcsBaseEditorConfig *editorConfig = createAnnotateEditor(fossilEditor)) {
editorConfig->setBaseArguments(extraOptions);
// editor has been just created, createVcsEditor() didn't set a configuration widget yet // editor has been just created, createVcsEditor() didn't set a configuration widget yet
connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested, connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
[=] { return this->annotate(workingDir, file, revision, lineNumber, extraOptions + editorConfig->arguments()); } ); [=]() {
effectiveArgs += editorConfig->arguments(); const int line = VcsBase::VcsBaseEditor::lineNumberOfCurrentEditor();
editor->setConfigurationAdded(); return this->annotate(workingDir, file, revision, line, editorConfig->arguments());
} );
fossilEditor->setConfigurationWidget(editorConfig);
} }
} }
QStringList effectiveArgs = extraOptions;
if (VcsBase::VcsBaseEditorConfig *editorConfig = fossilEditor->configurationWidget())
effectiveArgs = editorConfig->arguments();
VcsBase::VcsCommand *cmd = createCommand(workingDir, editor); VcsBase::VcsCommand *cmd = createCommand(workingDir, fossilEditor);
cmd->setCookie(lineNumber);
// here we introduce a "|BLAME|" meta-option to allow both annotate and blame modes // here we introduce a "|BLAME|" meta-option to allow both annotate and blame modes
int pos = effectiveArgs.indexOf("|BLAME|"); int pos = effectiveArgs.indexOf("|BLAME|");
@@ -746,10 +769,15 @@ VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
effectiveArgs.removeAt(pos); effectiveArgs.removeAt(pos);
} }
QStringList args(vcsCmdString); QStringList args(vcsCmdString);
args << revisionSpec(revision) << effectiveArgs << "--log" << file; args << revisionSpec(revision) << effectiveArgs << file;
// When version list requested, ignore the source line.
if (args.contains("--log"))
lineNumber = -1;
cmd->setCookie(lineNumber);
enqueueJob(cmd, args); enqueueJob(cmd, args);
return editor; return fossilEditor;
} }
bool FossilClient::isVcsFileOrDirectory(const Utils::FileName &fileName) const bool FossilClient::isVcsFileOrDirectory(const Utils::FileName &fileName) const
@@ -926,28 +954,34 @@ void FossilClient::log(const QString &workingDir, const QStringList &files,
VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source, VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
VcsBase::VcsBaseEditor::getCodec(source), VcsBase::VcsBaseEditor::getCodec(source),
vcsCmdString.toLatin1().constData(), id); vcsCmdString.toLatin1().constData(), id);
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
QStringList effectiveArgs = extraOptions; auto *fossilEditor = qobject_cast<FossilEditorWidget *>(editor);
if (!editor->configurationAdded()) { QTC_ASSERT(fossilEditor, return);
if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(editor)) {
fossilEditor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
if (!fossilEditor->configurationAdded()) {
if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(fossilEditor)) {
editorConfig->setBaseArguments(extraOptions);
// editor has been just created, createVcsEditor() didn't set a configuration widget yet // editor has been just created, createVcsEditor() didn't set a configuration widget yet
connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested, connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
[=]() { this->log(workingDir, files, extraOptions + editorConfig->arguments(), enableAnnotationContextMenu); } ); [=]() { this->log(workingDir, files, editorConfig->arguments(), enableAnnotationContextMenu); } );
effectiveArgs += editorConfig->arguments(); fossilEditor->setConfigurationWidget(editorConfig);
editor->setConfigurationAdded();
} }
} }
QStringList effectiveArgs = extraOptions;
if (VcsBase::VcsBaseEditorConfig *editorConfig = fossilEditor->configurationWidget())
effectiveArgs = editorConfig->arguments();
//@TODO: move highlighter and widgets to fossil editor sources. //@TODO: move highlighter and widgets to fossil editor sources.
new FossilLogHighlighter(editor->document()); new FossilLogHighlighter(fossilEditor->document());
QStringList args(vcsCmdString); QStringList args(vcsCmdString);
args << effectiveArgs; args << effectiveArgs;
if (!files.isEmpty()) if (!files.isEmpty())
args << "--path" << files; args << "--path" << files;
enqueueJob(createCommand(workingDir, editor), args); enqueueJob(createCommand(workingDir, fossilEditor), args);
} }
void FossilClient::logCurrentFile(const QString &workingDir, const QStringList &files, void FossilClient::logCurrentFile(const QString &workingDir, const QStringList &files,
@@ -972,26 +1006,32 @@ void FossilClient::logCurrentFile(const QString &workingDir, const QStringList &
VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source, VcsBase::VcsBaseEditorWidget *editor = createVcsEditor(kind, title, source,
VcsBase::VcsBaseEditor::getCodec(source), VcsBase::VcsBaseEditor::getCodec(source),
vcsCmdString.toLatin1().constData(), id); vcsCmdString.toLatin1().constData(), id);
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
QStringList effectiveArgs = extraOptions; auto *fossilEditor = qobject_cast<FossilEditorWidget *>(editor);
if (!editor->configurationAdded()) { QTC_ASSERT(fossilEditor, return);
if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(editor)) {
fossilEditor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
if (!fossilEditor->configurationAdded()) {
if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(fossilEditor)) {
editorConfig->setBaseArguments(extraOptions);
// editor has been just created, createVcsEditor() didn't set a configuration widget yet // editor has been just created, createVcsEditor() didn't set a configuration widget yet
connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested, connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
[=]() { this->logCurrentFile(workingDir, files, extraOptions + editorConfig->arguments(), enableAnnotationContextMenu); } ); [=]() { this->logCurrentFile(workingDir, files, editorConfig->arguments(), enableAnnotationContextMenu); } );
effectiveArgs += editorConfig->arguments(); fossilEditor->setConfigurationWidget(editorConfig);
editor->setConfigurationAdded();
} }
} }
QStringList effectiveArgs = extraOptions;
if (VcsBase::VcsBaseEditorConfig *editorConfig = fossilEditor->configurationWidget())
effectiveArgs = editorConfig->arguments();
//@TODO: move highlighter and widgets to fossil editor sources. //@TODO: move highlighter and widgets to fossil editor sources.
new FossilLogHighlighter(editor->document()); new FossilLogHighlighter(fossilEditor->document());
QStringList args(vcsCmdString); QStringList args(vcsCmdString);
args << effectiveArgs << files; args << effectiveArgs << files;
enqueueJob(createCommand(workingDir, editor), args); enqueueJob(createCommand(workingDir, fossilEditor), args);
} }
void FossilClient::revertFile(const QString &workingDir, void FossilClient::revertFile(const QString &workingDir,

View File

@@ -34,6 +34,7 @@
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <vcsbase/diffandloghighlighter.h> #include <vcsbase/diffandloghighlighter.h>
#include <QRegularExpression>
#include <QRegExp> #include <QRegExp>
#include <QString> #include <QString>
#include <QTextCursor> #include <QTextCursor>
@@ -44,15 +45,31 @@
namespace Fossil { namespace Fossil {
namespace Internal { namespace Internal {
FossilEditorWidget::FossilEditorWidget() : class FossilEditorWidgetPrivate
m_exactChangesetId(Constants::CHANGESET_ID_EXACT),
m_firstChangesetId(QString("\n") + Constants::CHANGESET_ID + " "),
m_nextChangesetId(m_firstChangesetId)
{ {
QTC_ASSERT(m_exactChangesetId.isValid(), return); public:
QTC_ASSERT(m_firstChangesetId.isValid(), return); FossilEditorWidgetPrivate() :
QTC_ASSERT(m_nextChangesetId.isValid(), return); m_exactChangesetId(Constants::CHANGESET_ID_EXACT),
m_firstChangesetId(QString("\n") + Constants::CHANGESET_ID + " "),
m_nextChangesetId(m_firstChangesetId),
m_configurationWidget(nullptr)
{
QTC_ASSERT(m_exactChangesetId.isValid(), return);
QTC_ASSERT(m_firstChangesetId.isValid(), return);
QTC_ASSERT(m_nextChangesetId.isValid(), return);
}
const QRegularExpression m_exactChangesetId;
const QRegularExpression m_firstChangesetId;
const QRegularExpression m_nextChangesetId;
VcsBase::VcsBaseEditorConfig *m_configurationWidget;
};
FossilEditorWidget::FossilEditorWidget() :
d(new FossilEditorWidgetPrivate)
{
setAnnotateRevisionTextFormat(tr("&Annotate %1")); setAnnotateRevisionTextFormat(tr("&Annotate %1"));
setAnnotatePreviousRevisionTextFormat(tr("Annotate &Parent Revision %1")); setAnnotatePreviousRevisionTextFormat(tr("Annotate &Parent Revision %1"));
@@ -65,6 +82,26 @@ FossilEditorWidget::FossilEditorWidget() :
setLogEntryPattern(logChangePattern); setLogEntryPattern(logChangePattern);
} }
FossilEditorWidget::~FossilEditorWidget()
{
delete d;
}
bool FossilEditorWidget::setConfigurationWidget(VcsBase::VcsBaseEditorConfig *w)
{
if (configurationAdded())
return false;
d->m_configurationWidget = w;
setConfigurationAdded();
return true;
}
VcsBase::VcsBaseEditorConfig *FossilEditorWidget::configurationWidget() const
{
return d->m_configurationWidget;
}
QSet<QString> FossilEditorWidget::annotationChanges() const QSet<QString> FossilEditorWidget::annotationChanges() const
{ {
@@ -77,12 +114,12 @@ QSet<QString> FossilEditorWidget::annotationChanges() const
QSet<QString> changes; QSet<QString> changes;
QRegularExpressionMatch firstChangesetIdMatch = m_firstChangesetId.match(txt); QRegularExpressionMatch firstChangesetIdMatch = d->m_firstChangesetId.match(txt);
if (firstChangesetIdMatch.hasMatch()) { if (firstChangesetIdMatch.hasMatch()) {
QString changeId = firstChangesetIdMatch.captured(1); QString changeId = firstChangesetIdMatch.captured(1);
changes.insert(changeId); changes.insert(changeId);
QRegularExpressionMatchIterator i = m_nextChangesetId.globalMatch(txt); QRegularExpressionMatchIterator i = d->m_nextChangesetId.globalMatch(txt);
while (i.hasNext()) { while (i.hasNext()) {
const QRegularExpressionMatch nextChangesetIdMatch = i.next(); const QRegularExpressionMatch nextChangesetIdMatch = i.next();
changeId = nextChangesetIdMatch.captured(1); changeId = nextChangesetIdMatch.captured(1);
@@ -98,7 +135,7 @@ QString FossilEditorWidget::changeUnderCursor(const QTextCursor &cursorIn) const
cursor.select(QTextCursor::WordUnderCursor); cursor.select(QTextCursor::WordUnderCursor);
if (cursor.hasSelection()) { if (cursor.hasSelection()) {
const QString change = cursor.selectedText(); const QString change = cursor.selectedText();
QRegularExpressionMatch exactChangesetIdMatch = m_exactChangesetId.match(change); QRegularExpressionMatch exactChangesetIdMatch = d->m_exactChangesetId.match(change);
if (exactChangesetIdMatch.hasMatch()) if (exactChangesetIdMatch.hasMatch())
return change; return change;
} }

View File

@@ -27,26 +27,28 @@
#include <vcsbase/vcsbaseeditor.h> #include <vcsbase/vcsbaseeditor.h>
#include <QRegularExpression>
namespace Fossil { namespace Fossil {
namespace Internal { namespace Internal {
class FossilEditorWidgetPrivate;
class FossilEditorWidget : public VcsBase::VcsBaseEditorWidget class FossilEditorWidget : public VcsBase::VcsBaseEditorWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
FossilEditorWidget(); FossilEditorWidget();
~FossilEditorWidget() final;
bool setConfigurationWidget(VcsBase::VcsBaseEditorConfig *w);
VcsBase::VcsBaseEditorConfig *configurationWidget() const;
private: private:
QSet<QString> annotationChanges() const final; QSet<QString> annotationChanges() const final;
QString changeUnderCursor(const QTextCursor &cursor) const final; QString changeUnderCursor(const QTextCursor &cursor) const final;
VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const final; VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const final;
const QRegularExpression m_exactChangesetId; FossilEditorWidgetPrivate *d;
const QRegularExpression m_firstChangesetId;
const QRegularExpression m_nextChangesetId;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -265,7 +265,8 @@ void FossilPlugin::annotateCurrentFile()
{ {
const VcsBase::VcsBasePluginState state = currentState(); const VcsBase::VcsBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return); QTC_ASSERT(state.hasFile(), return);
m_client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile()); const int lineNumber = VcsBase::VcsBaseEditor::lineNumberOfCurrentEditor(state.currentFile());
m_client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile(), QString(), lineNumber);
} }
void FossilPlugin::diffCurrentFile() void FossilPlugin::diffCurrentFile()

View File

@@ -36,6 +36,7 @@ const QString FossilSettings::sslIdentityFileKey("sslIdentityFile");
const QString FossilSettings::diffIgnoreAllWhiteSpaceKey("diffIgnoreAllWhiteSpace"); const QString FossilSettings::diffIgnoreAllWhiteSpaceKey("diffIgnoreAllWhiteSpace");
const QString FossilSettings::diffStripTrailingCRKey("diffStripTrailingCR"); const QString FossilSettings::diffStripTrailingCRKey("diffStripTrailingCR");
const QString FossilSettings::annotateShowCommittersKey("annotateShowCommitters"); const QString FossilSettings::annotateShowCommittersKey("annotateShowCommitters");
const QString FossilSettings::annotateListVersionsKey("annotateListVersions");
const QString FossilSettings::timelineWidthKey("timelineWidth"); const QString FossilSettings::timelineWidthKey("timelineWidth");
const QString FossilSettings::timelineLineageFilterKey("timelineLineageFilter"); const QString FossilSettings::timelineLineageFilterKey("timelineLineageFilter");
const QString FossilSettings::timelineVerboseKey("timelineVerbose"); const QString FossilSettings::timelineVerboseKey("timelineVerbose");
@@ -52,6 +53,7 @@ FossilSettings::FossilSettings()
declareKey(diffIgnoreAllWhiteSpaceKey, false); declareKey(diffIgnoreAllWhiteSpaceKey, false);
declareKey(diffStripTrailingCRKey, false); declareKey(diffStripTrailingCRKey, false);
declareKey(annotateShowCommittersKey, false); declareKey(annotateShowCommittersKey, false);
declareKey(annotateListVersionsKey, false);
declareKey(timelineWidthKey, 0); declareKey(timelineWidthKey, 0);
declareKey(timelineLineageFilterKey, ""); declareKey(timelineLineageFilterKey, "");
declareKey(timelineVerboseKey, false); declareKey(timelineVerboseKey, false);

View File

@@ -38,6 +38,7 @@ public:
static const QString diffIgnoreAllWhiteSpaceKey; static const QString diffIgnoreAllWhiteSpaceKey;
static const QString diffStripTrailingCRKey; static const QString diffStripTrailingCRKey;
static const QString annotateShowCommittersKey; static const QString annotateShowCommittersKey;
static const QString annotateListVersionsKey;
static const QString timelineWidthKey; static const QString timelineWidthKey;
static const QString timelineLineageFilterKey; static const QString timelineLineageFilterKey;
static const QString timelineVerboseKey; static const QString timelineVerboseKey;