I want to extend the Annotate view of Git VCS. But ...

Answered

I want to extend the Annotate view of Git VCS. But there's no way to add more gutters to it. Currently, I have to duplicate the Annotate view related files in my plugins.

https://github.com/JetBrains/intellij-community/blob/4db80d60d5d768031282e608d39752e5051b3419/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java#L225

And also, I want to get the revision line number. But it's skip in the code. So I can't get it even with reflection.

https://github.com/JetBrains/intellij-community/blob/0ef23ce030b8e84e4c45f3d1bb34f03678c0e53a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java#L273

And also the LineInfo of GitFileAnnotation is not public. Anyway, I can get access to it with reflection.

https://github.com/JetBrains/intellij-community/blob/febdc1ae36aa1f839a5bd3577a5b2a6e2df2da5a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java#L273

 

So, what I want is a simple way to extend the Annotate view of Git VCS, revision line number and previous line number in LineInfo, public LineInfo.

Thank you. 

29 comments
Comment actions Permalink

I do not think there are an easy way to extend this part.

0
Comment actions Permalink

So, at least, is it possible to add line revision number and previous line revision number to LineInfo and make LineInfo public? I can duplicate the files of AnnotateView anyway. But I have no way to duplicate the GitAnnotationProvider and GitFileAnnotation without changing git4idea.

0
Comment actions Permalink

>and make LineInfo public?
Yes, it is possible.

>to add line revision number and previous line revision number
`LineInfo.getFileRevision().getRevisionNumber()` and `LineInfo.getPreviousFileRevision().getRevisionNumber()` are already there.
See also `FileAnnotation#getPreviousFileRevisionProvider` / `FileAnnotation#getCurrentFileRevisionProvider`.
Did you mean something else?

How do you want to extend git annotations?

0
Comment actions Permalink

https://github.com/JetBrains/intellij-community/blob/0ef23ce030b8e84e4c45f3d1bb34f03678c0e53a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java#L273

I mean revision line number. Not the revision number. Just take a reference to the code above. I mean the original line number. It's called revision line number in the it.

0
Comment actions Permalink

https://github.com/JetBrains/intellij-community/blob/0ef23ce030b8e84e4c45f3d1bb34f03678c0e53a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java#L240

I try to duplicate the GitAnnotationProvider and use it as new GitAnnotationProvider(project). I got class not found exception here.

Any idea? I can use it as a temp workaround if I can duplicate it and use it.

com.intellij.openapi.vcs.VcsException: git4idea/GitVcs
at net.kaiba.source.actions.AnnotateLocalFileAction$1.run(AnnotateLocalFileAction.java:135)
at com.intellij.openapi.progress.impl.CoreProgressManager$TaskRunnable.run(CoreProgressManager.java:894)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:169)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:591)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:537)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:59)
at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:156)
at com.intellij.openapi.progress.impl.CoreProgressManager$4.run(CoreProgressManager.java:408)
at com.intellij.openapi.application.impl.ApplicationImpl$1.run(ApplicationImpl.java:294)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NoClassDefFoundError: git4idea/GitVcs
at net.kaiba.source.git4idea.annotate.GitAnnotationProvider.annotate(GitAnnotationProvider.java:129)
at net.kaiba.source.git4idea.annotate.GitAnnotationProvider.annotate(GitAnnotationProvider.java:99)
at net.kaiba.source.git4idea.annotate.GitAnnotationProvider.annotate(GitAnnotationProvider.java:79)
at net.kaiba.source.actions.AnnotateLocalFileAction$1.run(AnnotateLocalFileAction.java:126)
... 13 more
Caused by: java.lang.ClassNotFoundException: git4idea.GitVcs PluginClassLoader[net.kaiba.source, 1.0-SNAPSHOT] com.intellij.ide.plugins.cl.PluginClassLoader@1d3ce528
at com.intellij.ide.plugins.cl.PluginClassLoader.loadClass(PluginClassLoader.java:75)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 17 more

0
Comment actions Permalink

>Caused by: java.lang.ClassNotFoundException: git4idea.GitVcs PluginClassLoader[net.kaiba.source, 1.0-SNAPSHOT]
Probably, you need to mark git4idea plugin as dependency: `<depends>Git4Idea</depends>`.


https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_dependencies.html

0
Comment actions Permalink

Thank you. It does help after I add the <depends>. I can at least achieve what I want with duplicate some files and change them.

 

Anyway, an easy way to extend Annotate view, public LineInfo and LineInfo with revision line number would be great.

 

https://github.com/JetBrains/intellij-community/blob/0ef23ce030b8e84e4c45f3d1bb34f03678c0e53a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java#L273

I mean revision line number. Not the revision number. Just take a reference to the code above. I mean the original line number. It's called revision line number in the it.

0
Comment actions Permalink

>Anyway, an easy way to extend Annotate view would be great.
Yes, but it would require complete overhaul of everything related to it.

Even if LineInfo is made public and has additional data in it, one would need a better way to modify/extend existing AnnotationFieldGutters and a better input data (FileAnnotation has its limitations).

>It's called revision line number in the it.
Yes, I get it.

0
Comment actions Permalink

>Yes, but it would require complete overhaul of everything related to it.

Even if LineInfo is made public and has additional data in it, one would need a better way to modify/extend existing AnnotationFieldGutters and a better input data (FileAnnotation has its limitations).

 

Yes. That's what I'm doing now. It can fulfilled my requirement temporarily.

0
Comment actions Permalink

Hi. Currently, the LineInfo contains the FilePath. How can I get the relative path like the original blame does from a FilePath? Do I have to modify the LineInfo to store the original relative path? Thank you.

0
Comment actions Permalink

You can use 

VirtualFile root = VcsUtil.getVcsRootFor(myProject, myFilePath); // @Nullable, but should be there. Can reuse `GitRepository.getRoot` from GitAnnotationProvider above, if overridden.
String relativePath = VcsFileUtil.relativePath(root, myFilePath);
0
Comment actions Permalink

Thank you. It does help.

Does the intellij-community accept pull request? I found that the revision line number can't be added to LineInfo. Because currently, the LineInfo can be shared between lines while their info are the same. If I store it in the LineInfo, the memory will go up. It would store a lot duplicated LineInfo. Instead, storing a List<Integer> besides List<LineInfo> would be better. Now I have modified a duplicate modified version in my plugin. Can I create a pull request for it?

0
Comment actions Permalink

Yes, we do. See https://github.com/JetBrains/intellij-community/pulls

Probably, we can store `ListInfo(CommitInfo commitInfo, int lineNumber, int originalLineNumber)`.
This should not dramatically increase memory footprint.

0
Comment actions Permalink

Thank you. I'll make a pull request for it.

I thought about this way to avoid increase memory footprint as well. But it may break some plugins if they're use LineInfo with reflection before.

0
Comment actions Permalink

>But it may break some plugins if they're use LineInfo with reflection before.
If LineInfo delegates its methods to CommitInfo, these plugins should not be broken.
(Unless they use reflection to access fields instead of calling getters)

0
Comment actions Permalink

I see. I'll delegate its methods to CommitInfo in the PR.

0
Comment actions Permalink

Hi. Any idea on extending Annotate view?

What about the idea below?

public class AnnotateToggleAction extends ToggleAction implements DumbAware {
public static final ExtensionPointName<ExtendedActiveAnnotationGutter> EP_NAME_0 =
ExtensionPointName.create("com.intellij.openapi.vcs.actions.AnnotateToggleAction.Gutter");
for (ExtendedActiveAnnotationGutter extension : EP_NAME_0.getExtensions()) {
extension.setFileAnnotation(fileAnnotation);
extension.setTextAnnotationPresentation(presentation);
extension.setColorScheme(bgColorMap);
extension.initialize();
if (extension.isGutterAction()) {
editor.getGutter().registerTextAnnotation(extension, extension);
} else {
editor.getGutter().registerTextAnnotation(extension);
}
}
public interface ExtendedActiveAnnotationGutter extends ActiveAnnotationGutter {
void initialize();
void setFileAnnotation(FileAnnotation fileAnnotation);
FileAnnotation getFileAnnotation();
void setTextAnnotationPresentation(TextAnnotationPresentation textAnnotationPresentation);
TextAnnotationPresentation getTextAnnotationPresentation();
void setColorScheme(Couple<? extends Map<VcsRevisionNumber, Color>> colorScheme);
Couple<? extends Map<VcsRevisionNumber, Color>> getColorScheme();
default boolean isGutterAction() {
return false;
}
}
0
Comment actions Permalink

I duplicate Annotate view related files like the post above in my plugins. It's ok for my plugin to extend Annotate view. I think it's a proper solution for me.

0
Comment actions Permalink

What do you need to show in this gutter?

Maybe, a simpler EP will do:

public interface AnnotationGutterColumnProvider {
@Nullable
LineAnnotationAspect createColumn(@NotNull FileAnnotation annotation)
}

that gets wrapped into `AspectAnnotationFieldGutter` by `AnnotateToggleAction`?

0
Comment actions Permalink

A number,but I have to control the tooltip, the action and the cursor. The Aspect doesn't meet my need. And I have to change the color and the font maybe in the future.

0
Comment actions Permalink

>to control the tooltip, the action and the cursor. The Aspect doesn't meet my need
`LineAnnotationAspect` and `EditorGutterAction` seems to do this just fine ?

`LineAnnotationAspect.getTooltipText` is ignored here, but it can be fixed.
And it can be extended with `defailt Color getCustomColor() { return null; }` just fine.

0
Comment actions Permalink

PRs are updated with the suggested approach.

0
Comment actions Permalink

Hi. If the PRs are merged, when will they be available to the commercial products? Like IDEA, Rider, Pycharm.

Will they soon available in the nightly builds or EAP builds?

0
Comment actions Permalink

They will be available in 2020.1 branch. The first EAP build should be published at the end of january.

0
Comment actions Permalink

I'm also interested in this feature.

I see that an EAP/snapshot (?) with the relevant code hasn't been released yet.

Is there a way to make intellij-gradle-plugin use a custom version of IntelliJ?

0
Comment actions Permalink
@Nullable
@Override
public LineAnnotationAspect createColumn(@NotNull FileAnnotation annotation) {
VcsUtil.setAspectAvailability("Danmaku", true);
return new DanmakuLineAnnotationAspect(annotation);
}

private static class DanmakuLineAnnotationAspect implements LineAnnotationAspect, EditorGutterAction {
private List<Danmaku> danmakuList = new ArrayList<>();
private FileAnnotation fileAnnotation;

DanmakuLineAnnotationAspect(FileAnnotation fileAnnotation) {
computeDanmaku(fileAnnotation);
this.fileAnnotation = fileAnnotation;
}

Aleksey Pivovarov Hi. The request feature in 2020 is great. But I encounter a small problem here again. My LineAnnotationAspect's data is retrieved from the network with the computeDanmkau method. So it will block the main thread. Is there a way to not block the main thread? Thank you.

0
Comment actions Permalink

Seto IIUC, you're using your own FileAnnotation implementation. Can't this data be loaded with it (right after 'git blame' command is called)?

Another option is to start loading data in background (Task.Backgrountable / executeOnPooledThread) and show some "loading" state until it is ready.

You can store this data in MyFileAnnotation and call 'FileAnnotation#reload' to re-create LineAnnotationAspect (like it is done for 'Commit Number' column in 'GitAnnotationProvider#loadFileHistoryInBackground').

It's also possible to keep state inside 'LineAnnotationAspect' and repaint all editors when data is ready (like 'AnnotateActionGroup#revalidateMarkupInAllEditors' does).
Editor is not passed into LineAnnotationAspect methods, so we can't refrresh singular editor.

0
Comment actions Permalink

I'm not using my own FileAnnotaion. But Task.Backgroundable + AnnotationActionGroup.revalidateMarkupInAllEditors helps. Thank you.

0

Please sign in to leave a comment.