forked from qt-creator/qt-creator
Add support for annotation of any given revision
- Parent commits are also accessible from Annotate context menu - The client functionality was added in `fossil v2.4` Change-Id: Ia6096432cb1151388b5aebca30a6d25c1c6079f4 Reviewed-by: Eike Ziller <eike.ziller@qt.io> Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -99,7 +99,7 @@ public:
|
||||
// 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")),
|
||||
mapSetting(addToggleButton("--log", tr("List Versions")),
|
||||
settings.boolPointer(FossilSettings::annotateListVersionsKey));
|
||||
}
|
||||
};
|
||||
@@ -342,7 +342,23 @@ QList<BranchInfo> FossilClient::synchronousBranchQuery(const QString &workingDir
|
||||
return branches;
|
||||
}
|
||||
|
||||
RevisionInfo FossilClient::synchronousRevisionQuery(const QString &workingDirectory, const QString &id)
|
||||
QStringList FossilClient::parseRevisionCommentLine(const QString &commentLine)
|
||||
{
|
||||
// "comment: This is a (test) commit message (user: the.name)"
|
||||
|
||||
const QRegularExpression commentRx("^comment:\\s+(.*)\\s\\(user:\\s(.*)\\)$",
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
QTC_ASSERT(commentRx.isValid(), return QStringList());
|
||||
|
||||
const QRegularExpressionMatch match = commentRx.match(commentLine);
|
||||
if (!match.hasMatch())
|
||||
return QStringList();
|
||||
|
||||
return QStringList({match.captured(1), match.captured(2)});
|
||||
}
|
||||
|
||||
RevisionInfo FossilClient::synchronousRevisionQuery(const QString &workingDirectory, const QString &id,
|
||||
bool getCommentMsg) const
|
||||
{
|
||||
// Query details of the given revision/check-out id,
|
||||
// if none specified, provide information about current revision
|
||||
@@ -361,6 +377,9 @@ RevisionInfo FossilClient::synchronousRevisionQuery(const QString &workingDirect
|
||||
|
||||
QString revisionId;
|
||||
QString parentId;
|
||||
QStringList mergeParentIds;
|
||||
QString commentMsg;
|
||||
QString committer;
|
||||
|
||||
const QRegularExpression idRx("([0-9a-f]{5,40})");
|
||||
QTC_ASSERT(idRx.isValid(), return RevisionInfo());
|
||||
@@ -376,6 +395,15 @@ RevisionInfo FossilClient::synchronousRevisionQuery(const QString &workingDirect
|
||||
const QRegularExpressionMatch idMatch = idRx.match(l);
|
||||
if (idMatch.hasMatch())
|
||||
parentId = idMatch.captured(1);
|
||||
} else if (l.startsWith("merged-from: ", Qt::CaseInsensitive)) {
|
||||
const QRegularExpressionMatch idMatch = idRx.match(l);
|
||||
if (idMatch.hasMatch())
|
||||
mergeParentIds.append(idMatch.captured(1));
|
||||
} else if (getCommentMsg
|
||||
&& l.startsWith("comment: ", Qt::CaseInsensitive)) {
|
||||
const QStringList commentLineParts = parseRevisionCommentLine(l);
|
||||
commentMsg = commentLineParts.value(0);
|
||||
committer = commentLineParts.value(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +413,7 @@ RevisionInfo FossilClient::synchronousRevisionQuery(const QString &workingDirect
|
||||
if (parentId.isEmpty())
|
||||
parentId = revisionId; // root
|
||||
|
||||
return RevisionInfo(revisionId, parentId);
|
||||
return RevisionInfo(revisionId, parentId, mergeParentIds, commentMsg, committer);
|
||||
}
|
||||
|
||||
QStringList FossilClient::synchronousTagQuery(const QString &workingDirectory, const QString &id)
|
||||
@@ -452,8 +480,7 @@ RepositorySettings FossilClient::synchronousSettingsQuery(const QString &working
|
||||
|| lcValue == "2")
|
||||
repoSettings.autosync = RepositorySettings::AutosyncPullOnly;
|
||||
}
|
||||
|
||||
if (property == "ssl-identity") {
|
||||
else if (property == "ssl-identity") {
|
||||
repoSettings.sslIdentityFile = value;
|
||||
}
|
||||
}
|
||||
@@ -582,6 +609,7 @@ QString FossilClient::synchronousTopic(const QString &workingDirectory)
|
||||
return QString();
|
||||
|
||||
// return current branch name
|
||||
|
||||
const BranchInfo branchInfo = synchronousCurrentBranch(workingDirectory);
|
||||
if (branchInfo.name().isEmpty())
|
||||
return QString();
|
||||
@@ -726,7 +754,7 @@ VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
|
||||
|
||||
QString vcsCmdString = vcsCommandString(AnnotateCommand);
|
||||
const Core::Id kind = vcsEditorKind(AnnotateCommand);
|
||||
const QString id = VcsBase::VcsBaseEditor::getSource(workingDir, QStringList(file));
|
||||
const QString id = VcsBase::VcsBaseEditor::getTitleId(workingDir, QStringList(file), revision);
|
||||
const QString title = vcsEditorTitle(vcsCmdString, id);
|
||||
const QString source = VcsBase::VcsBaseEditor::getSource(workingDir, file);
|
||||
|
||||
@@ -734,13 +762,6 @@ VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
|
||||
VcsBase::VcsBaseEditor::getCodec(source),
|
||||
vcsCmdString.toLatin1().constData(), id);
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -769,7 +790,11 @@ VcsBase::VcsBaseEditorWidget *FossilClient::annotate(
|
||||
effectiveArgs.removeAt(pos);
|
||||
}
|
||||
QStringList args(vcsCmdString);
|
||||
args << revisionSpec(revision) << effectiveArgs << file;
|
||||
if (!revision.isEmpty()
|
||||
&& supportedFeatures().testFlag(AnnotateRevisionFeature))
|
||||
args << "-r" << revision;
|
||||
|
||||
args << effectiveArgs << file;
|
||||
|
||||
// When version list requested, ignore the source line.
|
||||
if (args.contains("--log"))
|
||||
@@ -805,7 +830,7 @@ bool FossilClient::managesFile(const QString &workingDirectory, const QString &f
|
||||
if (response.result != Utils::SynchronousProcessResponse::Finished)
|
||||
return false;
|
||||
QString output = sanitizeFossilOutput(response.stdOut());
|
||||
return !output.startsWith("no history for file");
|
||||
return !output.startsWith("no history for file", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
unsigned int FossilClient::binaryVersion() const
|
||||
@@ -851,7 +876,9 @@ FossilClient::SupportedFeatures FossilClient::supportedFeatures() const
|
||||
|
||||
const unsigned int version = binaryVersion();
|
||||
|
||||
if (version < 0x13000) {
|
||||
if (version < 0x20400) {
|
||||
features &= ~AnnotateRevisionFeature;
|
||||
if (version < 0x13000)
|
||||
features &= ~TimelinePathFeature;
|
||||
if (version < 0x12900)
|
||||
features &= ~DiffIgnoreWhiteSpaceFeature;
|
||||
@@ -860,6 +887,7 @@ FossilClient::SupportedFeatures FossilClient::supportedFeatures() const
|
||||
features &= ~TimelineWidthFeature;
|
||||
}
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,13 @@ public:
|
||||
TimelineWidthFeature = 0x4,
|
||||
DiffIgnoreWhiteSpaceFeature = 0x8,
|
||||
TimelinePathFeature = 0x10,
|
||||
AnnotateRevisionFeature = 0x20,
|
||||
AllSupportedFeatures = // | all defined features
|
||||
AnnotateBlameFeature
|
||||
| TimelineWidthFeature
|
||||
| DiffIgnoreWhiteSpaceFeature
|
||||
| TimelinePathFeature
|
||||
| AnnotateRevisionFeature
|
||||
};
|
||||
Q_DECLARE_FLAGS(SupportedFeatures, SupportedFeature)
|
||||
|
||||
@@ -64,7 +66,8 @@ public:
|
||||
unsigned int synchronousBinaryVersion() const;
|
||||
BranchInfo synchronousCurrentBranch(const QString &workingDirectory);
|
||||
QList<BranchInfo> synchronousBranchQuery(const QString &workingDirectory);
|
||||
RevisionInfo synchronousRevisionQuery(const QString &workingDirectory, const QString &id = QString());
|
||||
RevisionInfo synchronousRevisionQuery(const QString &workingDirectory, const QString &id = QString(),
|
||||
bool getCommentMsg = false) const;
|
||||
QStringList synchronousTagQuery(const QString &workingDirectory, const QString &id = QString());
|
||||
RepositorySettings synchronousSettingsQuery(const QString &workingDirectory);
|
||||
bool synchronousSetSetting(const QString &workingDirectory, const QString &property,
|
||||
@@ -113,6 +116,7 @@ public:
|
||||
|
||||
private:
|
||||
static QList<BranchInfo> branchListFromOutput(const QString &output, const BranchInfo::BranchFlags defaultFlags = 0);
|
||||
static QStringList parseRevisionCommentLine(const QString &commentLine);
|
||||
|
||||
QString sanitizeFossilOutput(const QString &output) const;
|
||||
QString vcsCommandString(VcsCommandTag cmd) const final;
|
||||
|
||||
@@ -124,8 +124,48 @@ QString FossilEditorWidget::changeUnderCursor(const QTextCursor &cursorIn) const
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString FossilEditorWidget::decorateVersion(const QString &revision) const
|
||||
{
|
||||
static const int shortChangesetIdSize(10);
|
||||
static const int maxTextSize(120);
|
||||
|
||||
VcsBase::BaseAnnotationHighlighter *FossilEditorWidget::createAnnotationHighlighter(const QSet<QString> &changes) const
|
||||
const QFileInfo fi(source());
|
||||
const QString workingDirectory = fi.absolutePath();
|
||||
FossilClient *client = FossilPlugin::instance()->client();
|
||||
RevisionInfo revisionInfo =
|
||||
client->synchronousRevisionQuery(workingDirectory, revision, true);
|
||||
|
||||
// format: 'revision (committer "comment...")'
|
||||
QString output = revision.left(shortChangesetIdSize)
|
||||
+ " (" + revisionInfo.committer
|
||||
+ " \"" + revisionInfo.commentMsg.left(maxTextSize);
|
||||
|
||||
if (output.size() > maxTextSize) {
|
||||
output.truncate(maxTextSize - 3);
|
||||
output.append("...");
|
||||
}
|
||||
output.append("\")");
|
||||
return output;
|
||||
}
|
||||
|
||||
QStringList FossilEditorWidget::annotationPreviousVersions(const QString &revision) const
|
||||
{
|
||||
QStringList revisions;
|
||||
const QFileInfo fi(source());
|
||||
const QString workingDirectory = fi.absolutePath();
|
||||
FossilClient *client = FossilPlugin::instance()->client();
|
||||
RevisionInfo revisionInfo =
|
||||
client->synchronousRevisionQuery(workingDirectory, revision);
|
||||
if (revisionInfo.parentId.isEmpty())
|
||||
return QStringList();
|
||||
|
||||
revisions.append(revisionInfo.parentId);
|
||||
revisions.append(revisionInfo.mergeParentIds);
|
||||
return revisions;
|
||||
}
|
||||
|
||||
VcsBase::BaseAnnotationHighlighter *FossilEditorWidget::createAnnotationHighlighter(
|
||||
const QSet<QString> &changes) const
|
||||
{
|
||||
return new FossilAnnotationHighlighter(changes);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,10 @@ public:
|
||||
private:
|
||||
QSet<QString> annotationChanges() const final;
|
||||
QString changeUnderCursor(const QTextCursor &cursor) const final;
|
||||
VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const final;
|
||||
QString decorateVersion(const QString &revision) const final;
|
||||
QStringList annotationPreviousVersions(const QString &revision) const final;
|
||||
VcsBase::BaseAnnotationHighlighter *createAnnotationHighlighter(
|
||||
const QSet<QString> &changes) const final;
|
||||
|
||||
FossilEditorWidgetPrivate *d;
|
||||
};
|
||||
|
||||
@@ -285,8 +285,9 @@ void FossilPlugin::logCurrentFile()
|
||||
if (features.testFlag(FossilClient::TimelineWidthFeature))
|
||||
extraOptions << "-W" << QString::number(m_client->settings().intValue(FossilSettings::timelineWidthKey));
|
||||
|
||||
// annotate only supported for current revision, so disable context menu
|
||||
bool enableAnnotationContextMenu = false;
|
||||
// disable annotate context menu for older client versions, used to be supported for current revision only
|
||||
bool enableAnnotationContextMenu = features.testFlag(FossilClient::AnnotateRevisionFeature);
|
||||
|
||||
m_client->logCurrentFile(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()),
|
||||
extraOptions, enableAnnotationContextMenu);
|
||||
}
|
||||
|
||||
@@ -28,9 +28,14 @@
|
||||
namespace Fossil {
|
||||
namespace Internal {
|
||||
|
||||
RevisionInfo::RevisionInfo(const QString &revisionId, const QString &parent) :
|
||||
RevisionInfo::RevisionInfo(const QString &revisionId, const QString &parent,
|
||||
const QStringList &mergeParents, const QString &comment,
|
||||
const QString &user) :
|
||||
id(revisionId),
|
||||
parentId(parent)
|
||||
parentId(parent),
|
||||
mergeParentIds(mergeParents),
|
||||
commentMsg(comment),
|
||||
committer(user)
|
||||
{ }
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -36,10 +36,15 @@ namespace Internal {
|
||||
class RevisionInfo
|
||||
{
|
||||
public:
|
||||
explicit RevisionInfo(const QString &revisionId = QString(), const QString &parent = QString());
|
||||
explicit RevisionInfo(const QString &revisionId = QString(), const QString &parent = QString(),
|
||||
const QStringList &mergeParents = QStringList(),
|
||||
const QString &comment = QString(), const QString &user = QString());
|
||||
|
||||
const QString id;
|
||||
const QString parentId;
|
||||
const QStringList mergeParentIds;
|
||||
const QString commentMsg;
|
||||
const QString committer;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user