Modifying the commits shown in the file history UI

Answered

Hello - I managed to create an action that opens a new tabbed file history in the VCS log tool window:

I did this by getting the existing tabbed file history UI and re-using properties with `FileHistoryUiFactory#createLogUi` to get a copy of it.

With this `FileHistoryUi` object, is it possible to modify the object so that either of the following is possible?
1) Remove/filter the commits in the file history UI so that only a subset of commits are shown.
2) Change the highlighting or the text colour of some of the commits shown.

For 1), I thought that creating a new `VisiblePack` object and then calling `setVisiblePack` on the file history UI with it might work as I saw creating a `VisiblePack` requires passing in a `VcsLogFilterCollection` object. However, when I try to create a filter with just one commit and do this, it seems like it causes the diff preview to be removed along with the the red and green bars on the left showing file rename:

0
6 comments

Sorry - as follow up, I think I figured out that I need to use `PermanentGraph#createVisibleGraph` to get a subset of commits for showing in the `VisiblePack`. My current question now though is that if I have a `PermanentGraph<Integer>` type object, and if this is the signature for `createVisibleGraph`:

VisibleGraph<Id> createVisibleGraph(@NotNull SortType sortType,
@Nullable Set<? extends Id> headsOfVisibleBranches,
@Nullable Set<? extends Id> matchedCommits);

What would `Set<Integer> matchedCommits` contain as a set of integers representing commits? What would the integers be?

Also, what is the purpose of the `fitlers` parameter when creating a `VisiblePack`?

public VisiblePack(@NotNull DataPackBase dataPack,
@NotNull VisibleGraph<Integer> graph,
boolean canRequestMore,
@NotNull VcsLogFilterCollection filters)

Thanks in advance!

0

Hi, Alison Li,

when I try to create a filter with just one commit and do this, it seems like it causes the diff preview to be removed along with the the red and green bars on the left showing file rename

`VisiblePack` for file history should contain information about `FilePath` for each visible commit (with some other stuff in a form of `com.intellij.vcs.log.history.FileHistory` object) so that it could be shown in the first column and used to query file content for the diff.

What would `Set<Integer> matchedCommits` contain as a set of integers representing commits?

`matchedCommits` is a set of commits which match the provided filters. Vcs Log has all commits represented as integers to save memory. This mapping is kept on disk and could be accessed using `VcsLogStorage` (`getCommitIndex`/`getCommitId`)

Also, what is the purpose of the `fitlers` parameter when creating a `VisiblePack`?

Filters are the filters which used to build this `VisiblePack`, so basically this is the information about "what is shown here". For file history `VcsLogFileHistoryFilter` is used which contains file path and commit hash.

creating a new `VisiblePack` object and then calling `setVisiblePack` on the file history UI

Manually setting the `VisiblePack` won't work as file history is refreshed automatically as repository changes. Each `VcsLogUi` has a `com.intellij.vcs.log.visible.VcsLogFilterer` object which is responsible for filtering the repository. So if the goal is to "open the same ui as file history, but build file history differently", you'd need to create your own `VcsLogFilterer` implementation (you can look at `com.intellij.vcs.log.history.FileHistoryFilterer` for the reference). Then, implement `com.intellij.vcs.log.impl.VcsLogManager.VcsLogUiFactory` to create a `VcsLogUi` with your new `VcsLogFilterer`. This factory should be passed to `com.intellij.vcs.log.impl.VcsLogManager#createLogUi(com.intellij.vcs.log.impl.VcsLogManager.VcsLogUiFactory<U>, com.intellij.vcs.log.impl.VcsLogTabLocation)` which will actually create a `VcsLogUi` instance for you. You can also use the `com.intellij.vcs.log.impl.VcsLogContentUtil#openLogTab` utility method, it creates the `VcsLogUi` and a tool window tab with it. Note that most of the described api was not intended for external usage and will likely change in the future.

1

Hi Julia, thank you a lot for the explanation! I'll look into creating my own filterer implementation and log UI factory.

If possible, could you explain further about the `filter` parameter when creating a `VisiblePack`? For example, I use `VcsLogStorage#getCommitIndex` to get a set of matched commits with hashes I specify. The hashes are of commits that are already shown in the file history since my file history tab would show a subset of those commits. If I use the same `VcsLogFilterCollection` that the existing file history UI uses, why would my newly created tab not have a diff preview shown for each commit anymore on the right side? Wouldn't the original file history's filter collection contain the same information I need?

Condition<FileHistoryUi> cond = (FileHistoryUi ui) -> ui.matches(path, hash);
FileHistoryUi fileHistoryUi = VcsLogContentUtil.findAndSelect(project, FileHistoryUi.class, cond);
VisibleGraph<Integer> visibleGraph = permanentGraph.createVisibleGraph(PermanentGraph.SortType.Normal, null, matchedCommits);
VisiblePack visiblePack = new VisiblePack(dataPack, visibleGraph, false, fileHistoryUi.getDataPack().getFilters());

When inspecting the contents of the filter collection with the debugger, it doesn't seem like there is anything specific about it to the old file history UI?

Is this related to why you mentioned implementing my own `VcsLogFilterer` for creating my own log UI?

Thank you again for your time and I really appreciate your response.

0

Wouldn't the original file history's filter collection contain the same information I need?

No, filter collection does not have that information. Filters are just specifications, like parameters for `git log` in the command line. They tell how the log should be filtered, but do not contain any information themselves.

Each `VisiblePack` implements `UserDataHolder` to allow storing additional information. So `FileHistory` object is stored in it using a `FileHistoryPaths#FILE_HISTORY` key (FileHistoryPaths has methods for setting and retrieving `FileHistory` from the `VisiblePack`).

1

Hi Julia, apologies for another follow up question. Instead of developing a plugin, I have switched to working on modifying the IntelliJ Community source code for convenience as my goal is to use a modified version of IntelliJ for a study. 

I'm currently working on bolding specific commits in the file history UI and have been able to do this with some hard-coded commit IDs by creating a new commit highlighter in `FileHistoryUi`. However, from the `FileHistoryUi` class, is it possible to obtain the list of commits that will be shown in the file history? I would like to obtain this set and do some operations to get a filtered list of commits, and use my highlighter to bold commits that belong to that filtered list:

public @NotNull VcsCommitStyle getStyle(int commitId, @NotNull VcsShortCommitDetails commitDetails, boolean isSelected) {
if (filteredCommits.contains(commitId)) return VcsCommitStyleFactory.bold();
return VcsCommitStyle.DEFAULT;
}

I've tried using `VcsLogProvider#getCommitsMatchingFilter` with the file history filter but it seems this can't be run on the EDT?

EDIT - I currently have the following and am wondering if this seems fine:

private static class ImportantCommitsHighlighter implements VcsLogHighlighter {
@Nullable private Set<Integer> myImportantCommits;
@NotNull private VcsLogDataPack myVisiblePack = VisiblePack.EMPTY;

private ImportantCommitsHighlighter(@Nullable Set<Integer> commits) {
myImportantCommits = commits;
}

@Override
public @NotNull VcsCommitStyle getStyle(int commitId, @NotNull VcsShortCommitDetails commitDetails, boolean isSelected) {
// Tip for me: can use `commitId == 647193` to test hardcoding a single commit
if (myImportantCommits.contains(commitId)) return VcsCommitStyleFactory.bold();
return VcsCommitStyle.DEFAULT;
}

@Override
public void update(@NotNull VcsLogDataPack dataPack, boolean refreshHappened) {
myVisiblePack = dataPack;
Set<Integer> fileHistoryCommits = FileHistoryPaths.INSTANCE.getFileHistory(myVisiblePack).getCommitsToPathsMap().keySet();
myImportantCommits = ... // perform filtering on `fileHistoryCommits`
}
}

Thank you!

0

Hi, Alison,

Yes, you can use `FileHistory.commitsToPathsMap`, but in some cases this map could also have some trivial merge commits which are hidden from the history. You can also look at this answer: https://intellij-support.jetbrains.com/hc/en-us/community/posts/4821636311698/comments/5088287876370

0

Please sign in to leave a comment.