mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[vcs-log] implement "Show in File History" action for the annotations context menu
GitOrigin-RevId: 8d10e772c0270b444e67a23bae747a40150ba2d3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
15fd756008
commit
0fca4e09bd
+11
-75
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.vcs.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -25,22 +11,15 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.AbstractVcsHelper;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.annotate.FileAnnotation;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vcs.changes.TextRevisionNumber;
|
||||
import com.intellij.openapi.vcs.history.VcsFileRevision;
|
||||
import com.intellij.openapi.vcs.history.VcsFileRevisionEx;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vcs.impl.BackgroundableActionLock;
|
||||
import com.intellij.openapi.vcs.vfs.ContentRevisionVirtualFile;
|
||||
import com.intellij.openapi.vcs.vfs.VcsVirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.vcs.AnnotationProviderEx;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
@@ -60,13 +39,13 @@ public class AnnotateVcsVirtualFileAction {
|
||||
|
||||
if (VcsAnnotateUtil.getEditorFor(file, e.getDataContext()) == null) return false;
|
||||
|
||||
AnnotationData data = extractData(project, file);
|
||||
AnnotationData data = AnnotationData.extractFrom(project, file);
|
||||
if (data == null) return false;
|
||||
|
||||
AnnotationProviderEx provider = ObjectUtils.tryCast(data.vcs.getAnnotationProvider(), AnnotationProviderEx.class);
|
||||
AnnotationProviderEx provider = ObjectUtils.tryCast(data.getVcs().getAnnotationProvider(), AnnotationProviderEx.class);
|
||||
if (provider == null) return false;
|
||||
|
||||
return provider.isAnnotationValid(data.filePath, data.revisionNumber);
|
||||
return provider.isAnnotationValid(data.getFilePath(), data.getRevisionNumber());
|
||||
}
|
||||
|
||||
private static boolean isSuspended(@NotNull AnActionEvent e) {
|
||||
@@ -94,10 +73,10 @@ public class AnnotateVcsVirtualFileAction {
|
||||
}
|
||||
|
||||
private static void doAnnotate(@NotNull final Project project, @NotNull final Editor editor, @NotNull final VirtualFile file) {
|
||||
final AnnotationData data = extractData(project, file);
|
||||
final AnnotationData data = AnnotationData.extractFrom(project, file);
|
||||
assert data != null;
|
||||
|
||||
final AnnotationProviderEx provider = (AnnotationProviderEx)data.vcs.getAnnotationProvider();
|
||||
final AnnotationProviderEx provider = (AnnotationProviderEx)data.getVcs().getAnnotationProvider();
|
||||
assert provider != null;
|
||||
|
||||
|
||||
@@ -111,7 +90,7 @@ public class AnnotateVcsVirtualFileAction {
|
||||
@Override
|
||||
public void run(final @NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
fileAnnotationRef.set(provider.annotate(data.filePath, data.revisionNumber));
|
||||
fileAnnotationRef.set(provider.annotate(data.getFilePath(), data.getRevisionNumber()));
|
||||
}
|
||||
catch (VcsException e) {
|
||||
exceptionRef.set(e);
|
||||
@@ -138,7 +117,7 @@ public class AnnotateVcsVirtualFileAction {
|
||||
}
|
||||
|
||||
if (!fileAnnotationRef.isNull()) {
|
||||
AnnotateToggleAction.doAnnotate(editor, project, fileAnnotationRef.get(), data.vcs);
|
||||
AnnotateToggleAction.doAnnotate(editor, project, fileAnnotationRef.get(), data.getVcs());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,49 +129,6 @@ public class AnnotateVcsVirtualFileAction {
|
||||
ProgressManager.getInstance().run(annotateTask);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AnnotationData extractData(@NotNull Project project, @NotNull VirtualFile file) {
|
||||
FilePath filePath = null;
|
||||
VcsRevisionNumber revisionNumber = null;
|
||||
if (file instanceof VcsVirtualFile) {
|
||||
VcsFileRevision revision = ((VcsVirtualFile)file).getFileRevision();
|
||||
if (revision instanceof VcsFileRevisionEx) {
|
||||
filePath = ((VcsFileRevisionEx)revision).getPath();
|
||||
}
|
||||
else {
|
||||
filePath = VcsUtil.getFilePath(file);
|
||||
}
|
||||
revisionNumber = revision != null ? revision.getRevisionNumber() : null;
|
||||
}
|
||||
else if (file instanceof ContentRevisionVirtualFile) {
|
||||
ContentRevision revision = ((ContentRevisionVirtualFile)file).getContentRevision();
|
||||
filePath = revision.getFile();
|
||||
revisionNumber = revision.getRevisionNumber();
|
||||
}
|
||||
if (filePath == null || revisionNumber == null) return null;
|
||||
if (revisionNumber instanceof TextRevisionNumber ||
|
||||
revisionNumber == VcsRevisionNumber.NULL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AbstractVcs vcs = VcsUtil.getVcsFor(project, filePath);
|
||||
return vcs != null ? new AnnotationData(vcs, filePath, revisionNumber) : null;
|
||||
}
|
||||
|
||||
private static class AnnotationData {
|
||||
@NotNull public final AbstractVcs vcs;
|
||||
@NotNull public final FilePath filePath;
|
||||
@NotNull public final VcsRevisionNumber revisionNumber;
|
||||
|
||||
AnnotationData(@NotNull AbstractVcs vcs,
|
||||
@NotNull FilePath filePath,
|
||||
@NotNull VcsRevisionNumber revisionNumber) {
|
||||
this.vcs = vcs;
|
||||
this.filePath = filePath;
|
||||
this.revisionNumber = revisionNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Provider implements AnnotateToggleAction.Provider {
|
||||
@Override
|
||||
public boolean isEnabled(AnActionEvent e) {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.vcs.actions
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vcs.AbstractVcs
|
||||
import com.intellij.openapi.vcs.FilePath
|
||||
import com.intellij.openapi.vcs.changes.TextRevisionNumber
|
||||
import com.intellij.openapi.vcs.history.VcsFileRevisionEx
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber
|
||||
import com.intellij.openapi.vcs.vfs.ContentRevisionVirtualFile
|
||||
import com.intellij.openapi.vcs.vfs.VcsVirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.vcsUtil.VcsUtil
|
||||
|
||||
data class AnnotationData(val vcs: AbstractVcs, val filePath: FilePath, val revisionNumber: VcsRevisionNumber) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun extractFrom(project: Project, file: VirtualFile): AnnotationData? {
|
||||
val filePath: FilePath
|
||||
val revisionNumber: VcsRevisionNumber
|
||||
when (file) {
|
||||
is VcsVirtualFile -> {
|
||||
val revision = file.fileRevision ?: return null
|
||||
filePath = if (revision is VcsFileRevisionEx) revision.path else VcsUtil.getFilePath(file)
|
||||
revisionNumber = revision.revisionNumber
|
||||
}
|
||||
is ContentRevisionVirtualFile -> {
|
||||
val revision = file.contentRevision
|
||||
filePath = revision.file
|
||||
revisionNumber = revision.revisionNumber
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
if (revisionNumber is TextRevisionNumber || revisionNumber === VcsRevisionNumber.NULL) return null
|
||||
|
||||
val vcs = VcsUtil.getVcsFor(project, filePath) ?: return null
|
||||
return AnnotationData(vcs, filePath, revisionNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,7 @@ action.Vcs.Log.ResumeIndexing.text=Resume Indexing
|
||||
action.Vcs.Log.ResumeIndexing.description=Indexing was paused as it took longer than expected. Resume.
|
||||
action.Vcs.Log.SelectInLog.text=Show in VCS Log
|
||||
action.Vcs.Log.SelectInLog.text.template=Show in {0} Log
|
||||
vcs.log.action.show.in.file.history.text=Show in File History
|
||||
group.Vcs.Log.PresentationSettings.text=View Options
|
||||
group.Vcs.Log.PresentationSettings.description=Configure presentation of the Log
|
||||
group.Vcs.Log.ChangesBrowser.PresentationSettings.text=View Options
|
||||
@@ -164,6 +165,7 @@ file.history.commit.not.found.in.branch={0} does not exist in history for {1} in
|
||||
file.history.commit.not.found={0} does not exist in history for {1}
|
||||
file.history.commit.not.found.view.and.show.all.branches.link=View and show all branches
|
||||
file.history.commit.not.found.view.in.log.link=View in Log
|
||||
file.history.show.commit.in.history.process=Searching commit {0} in file history
|
||||
|
||||
# indexing progress
|
||||
vcs.log.status.bar.indexing.cancel.tooltip=Cancel indexing. Indexing could be restarted manually from {0} Log toolbar.
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<openapi.vcs.history.actions.GetVersionAction.ExtensionProvider
|
||||
implementation="com.intellij.vcs.log.ui.actions.history.GetVersionFromHistoryAction"/>
|
||||
<openapi.vcs.changes.actions.diff.ChangeDiffRequestProvider implementation="com.intellij.vcs.log.impl.MergedChangeDiffRequestProvider"/>
|
||||
<vcsAnnotationGutterActionProvider implementation="com.intellij.vcs.log.ui.actions.history.ShowInFileHistoryAnnotationActionProvider" />
|
||||
|
||||
<actionPromoter implementation="com.intellij.vcs.log.ui.actions.VcsLogActionPromoter"/>
|
||||
|
||||
|
||||
+66
-46
@@ -21,25 +21,43 @@ import com.intellij.vcs.log.visible.filters.VcsLogFilterObject
|
||||
import com.intellij.vcs.log.visible.filters.matches
|
||||
import com.intellij.vcsUtil.VcsUtil
|
||||
|
||||
class VcsLogFileHistoryProviderImpl(project: Project) : VcsLogFileHistoryProvider {
|
||||
private val providers = listOf(VcsLogSingleFileHistoryProvider(project), VcsLogDirectoryHistoryProvider(project))
|
||||
class VcsLogFileHistoryProviderImpl(private val project: Project) : VcsLogFileHistoryProvider {
|
||||
|
||||
override fun canShowFileHistory(paths: Collection<FilePath>, revisionNumber: String?): Boolean {
|
||||
return providers.any { it.canShowFileHistory(paths, revisionNumber) }
|
||||
return canShowFileHistory(project, paths, revisionNumber)
|
||||
}
|
||||
|
||||
override fun showFileHistory(paths: Collection<FilePath>, revisionNumber: String?) {
|
||||
providers.firstOrNull { it.canShowFileHistory(paths, revisionNumber) }?.showFileHistory(paths, revisionNumber)
|
||||
selectProvider(project, paths, revisionNumber)?.showFileHistoryUi(project, paths, revisionNumber)
|
||||
}
|
||||
}
|
||||
|
||||
class VcsLogDirectoryHistoryProvider(private val project: Project) : VcsLogFileHistoryProvider {
|
||||
override fun canShowFileHistory(paths: Collection<FilePath>, revisionNumber: String?): Boolean {
|
||||
internal fun canShowFileHistory(project: Project, paths: Collection<FilePath>, revisionNumber: String?): Boolean {
|
||||
return selectProvider(project, paths, revisionNumber) != null
|
||||
}
|
||||
|
||||
internal fun showFileHistoryUi(project: Project, paths: Collection<FilePath>, revisionNumber: String?, selectRow: Boolean = false): VcsLogUiEx? {
|
||||
return selectProvider(project, paths, revisionNumber)?.showFileHistoryUi(project, paths, revisionNumber, selectRow)
|
||||
}
|
||||
|
||||
private fun selectProvider(project: Project, paths: Collection<FilePath>, revisionNumber: String?): FileHistoryLogUiProvider? {
|
||||
return listOf(VcsLogSingleFileHistoryProvider, VcsLogDirectoryHistoryProvider).firstOrNull {
|
||||
it.canShowFileHistory(project, paths, revisionNumber)
|
||||
}
|
||||
}
|
||||
|
||||
interface FileHistoryLogUiProvider {
|
||||
fun canShowFileHistory(project: Project, paths: Collection<FilePath>, revisionNumber: String?): Boolean
|
||||
fun showFileHistoryUi(project: Project, paths: Collection<FilePath>, revisionNumber: String?, selectRow: Boolean = true): VcsLogUiEx?
|
||||
}
|
||||
|
||||
object VcsLogDirectoryHistoryProvider : FileHistoryLogUiProvider {
|
||||
override fun canShowFileHistory(project: Project, paths: Collection<FilePath>, revisionNumber: String?): Boolean {
|
||||
val dataManager = VcsProjectLog.getInstance(project).dataManager ?: return false
|
||||
return createPathsFilter(project, dataManager.logProviders, paths) != null
|
||||
}
|
||||
|
||||
override fun showFileHistory(paths: Collection<FilePath>, revisionNumber: String?) {
|
||||
override fun showFileHistoryUi(project: Project, paths: Collection<FilePath>, revisionNumber: String?, selectRow: Boolean): VcsLogUiEx? {
|
||||
val hash = revisionNumber?.let { HashImpl.build(it) }
|
||||
val root = VcsLogUtil.getActualRoot(project, paths.first())!!
|
||||
|
||||
@@ -55,58 +73,58 @@ class VcsLogDirectoryHistoryProvider(private val project: Project) : VcsLogFileH
|
||||
val firstTime = ui == null
|
||||
if (firstTime) {
|
||||
val filters = VcsLogFilterObject.collection(pathsFilter, hashFilter)
|
||||
ui = VcsProjectLog.getInstance(project).openLogTab(filters) ?: return
|
||||
ui = VcsProjectLog.getInstance(project).openLogTab(filters) ?: return null
|
||||
ui.properties[MainVcsLogUiProperties.SHOW_ONLY_AFFECTED_CHANGES] = true
|
||||
}
|
||||
selectRowWhenOpen(logManager, hash, root, ui!!, firstTime)
|
||||
if (selectRow) selectRowWhenOpen(logManager, hash, root, ui!!, firstTime)
|
||||
|
||||
return ui
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createPathsFilter(project: Project, logProviders: Map<VirtualFile, VcsLogProvider>, paths: Collection<FilePath>): VcsLogFilter? {
|
||||
val forRootFilter = mutableSetOf<VirtualFile>()
|
||||
val forPathsFilter = mutableListOf<FilePath>()
|
||||
for (path in paths) {
|
||||
val root = VcsLogUtil.getActualRoot(project, path)
|
||||
if (root == null) return null
|
||||
if (!logProviders.keys.contains(root) ||
|
||||
!VcsLogProperties.SUPPORTS_LOG_DIRECTORY_HISTORY.getOrDefault(logProviders[root])) return null
|
||||
fun createPathsFilter(project: Project, logProviders: Map<VirtualFile, VcsLogProvider>, paths: Collection<FilePath>): VcsLogFilter? {
|
||||
val forRootFilter = mutableSetOf<VirtualFile>()
|
||||
val forPathsFilter = mutableListOf<FilePath>()
|
||||
for (path in paths) {
|
||||
val root = VcsLogUtil.getActualRoot(project, path)
|
||||
if (root == null) return null
|
||||
if (!logProviders.keys.contains(root) ||
|
||||
!VcsLogProperties.SUPPORTS_LOG_DIRECTORY_HISTORY.getOrDefault(logProviders[root])) return null
|
||||
|
||||
val correctedPath = getCorrectedPath(project, path, false)
|
||||
if (!correctedPath.isDirectory) return null
|
||||
val correctedPath = getCorrectedPath(project, path, false)
|
||||
if (!correctedPath.isDirectory) return null
|
||||
|
||||
if (path.virtualFile == root) {
|
||||
forRootFilter.add(root)
|
||||
}
|
||||
else {
|
||||
forPathsFilter.add(correctedPath)
|
||||
}
|
||||
|
||||
if (forPathsFilter.isNotEmpty() && forRootFilter.isNotEmpty()) return null
|
||||
if (path.virtualFile == root) {
|
||||
forRootFilter.add(root)
|
||||
}
|
||||
else {
|
||||
forPathsFilter.add(correctedPath)
|
||||
}
|
||||
|
||||
if (forPathsFilter.isNotEmpty()) return VcsLogFilterObject.fromPaths(forPathsFilter)
|
||||
return VcsLogFilterObject.fromRoots(forRootFilter)
|
||||
if (forPathsFilter.isNotEmpty() && forRootFilter.isNotEmpty()) return null
|
||||
}
|
||||
|
||||
private fun createHashFilter(hash: Hash?, root: VirtualFile): VcsLogFilter {
|
||||
if (hash == null) {
|
||||
return VcsLogFilterObject.fromBranch(VcsLogUtil.HEAD)
|
||||
}
|
||||
if (forPathsFilter.isNotEmpty()) return VcsLogFilterObject.fromPaths(forPathsFilter)
|
||||
return VcsLogFilterObject.fromRoots(forRootFilter)
|
||||
}
|
||||
|
||||
return VcsLogFilterObject.fromCommit(CommitId(hash, root))
|
||||
private fun createHashFilter(hash: Hash?, root: VirtualFile): VcsLogFilter {
|
||||
if (hash == null) {
|
||||
return VcsLogFilterObject.fromBranch(VcsLogUtil.HEAD)
|
||||
}
|
||||
|
||||
private fun matches(filters: VcsLogFilterCollection, pathsFilter: VcsLogFilter, hashFilter: VcsLogFilter): Boolean {
|
||||
if (!filters.matches(hashFilter.key, pathsFilter.key)) {
|
||||
return false
|
||||
}
|
||||
return filters.get(pathsFilter.key) == pathsFilter && filters.get(hashFilter.key) == hashFilter
|
||||
return VcsLogFilterObject.fromCommit(CommitId(hash, root))
|
||||
}
|
||||
|
||||
private fun matches(filters: VcsLogFilterCollection, pathsFilter: VcsLogFilter, hashFilter: VcsLogFilter): Boolean {
|
||||
if (!filters.matches(hashFilter.key, pathsFilter.key)) {
|
||||
return false
|
||||
}
|
||||
return filters.get(pathsFilter.key) == pathsFilter && filters.get(hashFilter.key) == hashFilter
|
||||
}
|
||||
}
|
||||
|
||||
private class VcsLogSingleFileHistoryProvider(private val project: Project) : VcsLogFileHistoryProvider {
|
||||
override fun canShowFileHistory(paths: Collection<FilePath>, revisionNumber: String?): Boolean {
|
||||
private object VcsLogSingleFileHistoryProvider : FileHistoryLogUiProvider {
|
||||
override fun canShowFileHistory(project: Project, paths: Collection<FilePath>, revisionNumber: String?): Boolean {
|
||||
if (!isNewHistoryEnabled() || paths.size != 1) return false
|
||||
|
||||
val root = VcsLogUtil.getActualRoot(project, paths.single()) ?: return false
|
||||
@@ -117,12 +135,12 @@ private class VcsLogSingleFileHistoryProvider(private val project: Project) : Vc
|
||||
return logProvider?.diffHandler != null && logProvider.getFileHistoryHandler(project) != null
|
||||
}
|
||||
|
||||
override fun showFileHistory(paths: Collection<FilePath>, revisionNumber: String?) {
|
||||
if (paths.size != 1) return
|
||||
override fun showFileHistoryUi(project: Project, paths: Collection<FilePath>, revisionNumber: String?, selectRow: Boolean): VcsLogUiEx? {
|
||||
if (paths.size != 1) return null
|
||||
|
||||
val root = VcsLogUtil.getActualRoot(project, paths.first())!!
|
||||
val path = getCorrectedPath(project, paths.single(), revisionNumber != null)
|
||||
if (path.isDirectory) return
|
||||
if (path.isDirectory) return null
|
||||
|
||||
val hash = revisionNumber?.let { HashImpl.build(it) }
|
||||
triggerFileHistoryUsage(project, paths, hash)
|
||||
@@ -136,7 +154,9 @@ private class VcsLogSingleFileHistoryProvider(private val project: Project) : Vc
|
||||
if (firstTime) {
|
||||
fileHistoryUi = project.service<FileHistoryTabsManager>().openFileHistoryTab(logManager, path, root, hash)
|
||||
}
|
||||
selectRowWhenOpen(logManager, hash, root, fileHistoryUi!!, firstTime)
|
||||
if (selectRow) selectRowWhenOpen(logManager, hash, root, fileHistoryUi!!, firstTime)
|
||||
|
||||
return fileHistoryUi
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.vcs.log.ui.actions.history
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.vcs.actions.AnnotationData
|
||||
import com.intellij.openapi.vcs.actions.ShowAnnotateOperationsPopup
|
||||
import com.intellij.openapi.vcs.annotate.AnnotationGutterActionProvider
|
||||
import com.intellij.openapi.vcs.annotate.FileAnnotation
|
||||
import com.intellij.platform.ide.progress.withBackgroundProgress
|
||||
import com.intellij.util.io.await
|
||||
import com.intellij.vcs.log.VcsLogBundle
|
||||
import com.intellij.vcs.log.history.canShowFileHistory
|
||||
import com.intellij.vcs.log.history.showFileHistoryUi
|
||||
import com.intellij.vcs.log.impl.VcsLogNavigationUtil.jumpToHash
|
||||
import com.intellij.vcs.log.impl.VcsProjectLog
|
||||
import com.intellij.vcs.log.util.VcsLogUtil
|
||||
import com.intellij.vcsUtil.VcsUtil
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ShowInFileHistoryAnnotationActionProvider : AnnotationGutterActionProvider {
|
||||
override fun createAction(annotation: FileAnnotation): AnAction {
|
||||
return ShowInFileHistoryAnnotationAction(annotation)
|
||||
}
|
||||
}
|
||||
|
||||
private class ShowInFileHistoryAnnotationAction(private val annotation: FileAnnotation) :
|
||||
DumbAwareAction(VcsLogBundle.message("vcs.log.action.show.in.file.history.text")) {
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val project = e.project
|
||||
val file = annotation.file
|
||||
val lineRevisionNumber = getLineRevisionNumber(e)
|
||||
if (project == null || file == null || lineRevisionNumber == null) {
|
||||
e.presentation.isEnabledAndVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
val annotationData = AnnotationData.extractFrom(project, file)
|
||||
val annotatedFilePath = annotationData?.filePath ?: VcsUtil.getFilePath(file)
|
||||
val annotatedRevisionNumber = annotationData?.revisionNumber?.asString()
|
||||
|
||||
e.presentation.isEnabledAndVisible = canShowFileHistory(project, listOf(annotatedFilePath), annotatedRevisionNumber)
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
val file = annotation.file ?: return
|
||||
val lineRevisionNumber = getLineRevisionNumber(e) ?: return
|
||||
|
||||
val annotationData = AnnotationData.extractFrom(project, file)
|
||||
val annotatedFilePath = annotationData?.filePath ?: VcsUtil.getFilePath(file)
|
||||
val annotatedRevisionNumber = annotationData?.revisionNumber?.asString()
|
||||
|
||||
val ui = showFileHistoryUi(project, listOf(annotatedFilePath), annotatedRevisionNumber) ?: return
|
||||
val future = ui.jumpToHash(lineRevisionNumber, false, true)
|
||||
|
||||
VcsProjectLog.getInstance(project).childScope().launch {
|
||||
withBackgroundProgress(project,
|
||||
VcsLogBundle.message("file.history.show.commit.in.history.process",
|
||||
VcsLogUtil.getShortHash(lineRevisionNumber)), true) {
|
||||
future.await()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLineRevisionNumber(e: AnActionEvent): String? {
|
||||
val lineNumber = ShowAnnotateOperationsPopup.getAnnotationLineNumber(e.dataContext)
|
||||
return annotation.getLineRevisionNumber(lineNumber)?.asString()
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread() = ActionUpdateThread.BGT
|
||||
}
|
||||
Reference in New Issue
Block a user