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 "fossileditor.h"
#include "constants.h"
#include <coreplugin/id.h>
@@ -93,6 +94,13 @@ public:
mapSetting(addToggleButton("|BLAME|", tr("Show Committers")),
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::VcsBaseEditor::getCodec(source),
vcsCmdString.toLatin1().constData(), id);
QStringList effectiveArgs = extraOptions;
if (!editor->configurationAdded()) {
if (VcsBase::VcsBaseEditorConfig *editorConfig = createAnnotateEditor(editor)) {
// We need to be able to re-query the configuration widget for the arguments
// 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
connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
[=] { return this->annotate(workingDir, file, revision, lineNumber, extraOptions + editorConfig->arguments()); } );
effectiveArgs += editorConfig->arguments();
editor->setConfigurationAdded();
[=]() {
const int line = VcsBase::VcsBaseEditor::lineNumberOfCurrentEditor();
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);
cmd->setCookie(lineNumber);
VcsBase::VcsCommand *cmd = createCommand(workingDir, fossilEditor);
// here we introduce a "|BLAME|" meta-option to allow both annotate and blame modes
int pos = effectiveArgs.indexOf("|BLAME|");
@@ -746,10 +769,15 @@ VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
effectiveArgs.removeAt(pos);
}
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);
return editor;
return fossilEditor;
}
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::VcsBaseEditor::getCodec(source),
vcsCmdString.toLatin1().constData(), id);
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
QStringList effectiveArgs = extraOptions;
if (!editor->configurationAdded()) {
if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(editor)) {
auto *fossilEditor = qobject_cast<FossilEditorWidget *>(editor);
QTC_ASSERT(fossilEditor, return);
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
connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
[=]() { this->log(workingDir, files, extraOptions + editorConfig->arguments(), enableAnnotationContextMenu); } );
effectiveArgs += editorConfig->arguments();
editor->setConfigurationAdded();
[=]() { this->log(workingDir, files, editorConfig->arguments(), enableAnnotationContextMenu); } );
fossilEditor->setConfigurationWidget(editorConfig);
}
}
QStringList effectiveArgs = extraOptions;
if (VcsBase::VcsBaseEditorConfig *editorConfig = fossilEditor->configurationWidget())
effectiveArgs = editorConfig->arguments();
//@TODO: move highlighter and widgets to fossil editor sources.
new FossilLogHighlighter(editor->document());
new FossilLogHighlighter(fossilEditor->document());
QStringList args(vcsCmdString);
args << effectiveArgs;
if (!files.isEmpty())
args << "--path" << files;
enqueueJob(createCommand(workingDir, editor), args);
enqueueJob(createCommand(workingDir, fossilEditor), args);
}
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::VcsBaseEditor::getCodec(source),
vcsCmdString.toLatin1().constData(), id);
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);
QStringList effectiveArgs = extraOptions;
if (!editor->configurationAdded()) {
if (VcsBase::VcsBaseEditorConfig *editorConfig = createLogEditor(editor)) {
auto *fossilEditor = qobject_cast<FossilEditorWidget *>(editor);
QTC_ASSERT(fossilEditor, return);
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
connect(editorConfig, &VcsBase::VcsBaseEditorConfig::commandExecutionRequested,
[=]() { this->logCurrentFile(workingDir, files, extraOptions + editorConfig->arguments(), enableAnnotationContextMenu); } );
effectiveArgs += editorConfig->arguments();
editor->setConfigurationAdded();
[=]() { this->logCurrentFile(workingDir, files, editorConfig->arguments(), enableAnnotationContextMenu); } );
fossilEditor->setConfigurationWidget(editorConfig);
}
}
QStringList effectiveArgs = extraOptions;
if (VcsBase::VcsBaseEditorConfig *editorConfig = fossilEditor->configurationWidget())
effectiveArgs = editorConfig->arguments();
//@TODO: move highlighter and widgets to fossil editor sources.
new FossilLogHighlighter(editor->document());
new FossilLogHighlighter(fossilEditor->document());
QStringList args(vcsCmdString);
args << effectiveArgs << files;
enqueueJob(createCommand(workingDir, editor), args);
enqueueJob(createCommand(workingDir, fossilEditor), args);
}
void FossilClient::revertFile(const QString &workingDir,

View File

@@ -34,6 +34,7 @@
#include <utils/synchronousprocess.h>
#include <vcsbase/diffandloghighlighter.h>
#include <QRegularExpression>
#include <QRegExp>
#include <QString>
#include <QTextCursor>
@@ -44,15 +45,31 @@
namespace Fossil {
namespace Internal {
FossilEditorWidget::FossilEditorWidget() :
class FossilEditorWidgetPrivate
{
public:
FossilEditorWidgetPrivate() :
m_exactChangesetId(Constants::CHANGESET_ID_EXACT),
m_firstChangesetId(QString("\n") + Constants::CHANGESET_ID + " "),
m_nextChangesetId(m_firstChangesetId)
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"));
setAnnotatePreviousRevisionTextFormat(tr("Annotate &Parent Revision %1"));
@@ -65,6 +82,26 @@ FossilEditorWidget::FossilEditorWidget() :
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
{
@@ -77,12 +114,12 @@ QSet<QString> FossilEditorWidget::annotationChanges() const
QSet<QString> changes;
QRegularExpressionMatch firstChangesetIdMatch = m_firstChangesetId.match(txt);
QRegularExpressionMatch firstChangesetIdMatch = d->m_firstChangesetId.match(txt);
if (firstChangesetIdMatch.hasMatch()) {
QString changeId = firstChangesetIdMatch.captured(1);
changes.insert(changeId);
QRegularExpressionMatchIterator i = m_nextChangesetId.globalMatch(txt);
QRegularExpressionMatchIterator i = d->m_nextChangesetId.globalMatch(txt);
while (i.hasNext()) {
const QRegularExpressionMatch nextChangesetIdMatch = i.next();
changeId = nextChangesetIdMatch.captured(1);
@@ -98,7 +135,7 @@ QString FossilEditorWidget::changeUnderCursor(const QTextCursor &cursorIn) const
cursor.select(QTextCursor::WordUnderCursor);
if (cursor.hasSelection()) {
const QString change = cursor.selectedText();
QRegularExpressionMatch exactChangesetIdMatch = m_exactChangesetId.match(change);
QRegularExpressionMatch exactChangesetIdMatch = d->m_exactChangesetId.match(change);
if (exactChangesetIdMatch.hasMatch())
return change;
}

View File

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

View File

@@ -265,7 +265,8 @@ void FossilPlugin::annotateCurrentFile()
{
const VcsBase::VcsBasePluginState state = currentState();
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()

View File

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

View File

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