Add own Line Status / VCS Diff Changes with own Content?

Answered

Hi there,

i would like to know if it is possible to add own line status highlights with own content, so that reverts of old code of another commit / branch was possible. 



any ideas? Thanks!

0
18 comments

Hi,

I'm afraid, there are no API to do so. Are you trying to fix IDEA-24398 with a plugin?

 

A long answer in case if you'd like to try a hacky approach:

You can disable LineStatusTrackerManager by setting VcsApplicationSettings.SHOW_LST_GUTTER_MARKERS to `false`.

After that, you'll have to register your own manager that would do similar job, but take base content from manually selected revision (and ignore FileStatus, because it's no longer relevant).

Also, you'll have to copy all related actions (ex: ShowChangeMarkerAction, RollbackLineStatusAction), because they are using LSTM.

0

Hi!

 

Yes, Im writing a Plugin to make code reviews for bitbucket pullrequests possible inside of phpstorm. at least i would like to have a diff-feature. either via line status or "normal" diff`s against a branch. i assume the second one is the easier one...

your long answer sounds to complicated for a Java and Plugin Developer "starter" like me :-) ... but if i have enough time i will give it a try! but the Problem is also, that I and our team like the "standard"-line-status-feature as well. it can only work if i have the possibility to toggle between the standard and the advanced feature. and im not sure if this was trivial :-/

 

 

0

I dont find the starting point. 

VcsApplicationSettings vcsApplicationSettings = VcsApplicationSettings.getInstance();
vcsApplicationSettings.SHOW_LST_GUTTER_MARKERS = false;

That was easy, but what do you mean with register my own manager. do i ned to extend ShowChangeMarkerAction or what i have to do exactly?

can you help me with an "simple" example code snippet?

0

For the listing, you can take a look at LineStatusTrackerManager. It's more complicated, than you'd need, but is a good starting point.

It's easier to answer specific questions like "How to do X" or "How to get Y having Z", but the general approach can be as following:.
(assuming, that you already knew the revision to compare with - the UI to select it can vary)

* Disable default markers (using SHOW_LST_GUTTER_MARKERS)
  They would interfere with your markers.
  As an alternative, you can reuse "Code coverage" markers - to the left of line numbers. (See LineMarkerRendererEx.getPosition() )
* Register your own ProjectComponent
  This will give you a singleton, that is created for each Project.
* Listen for updates of revision to compare with
* Listen for Editors (using EditorFactory / EditorFactoryListener) - to show markers in newly opened editors

When you want to show markers in Editor for some revision:
* Create new MyLineStatusTracker extending LineStatusTrackerBase (LineStatusTracker can be used as an example)
* Queue loading VCS content for this file in background 
  It can be done in different ways. For example (having Editor and VcsRevisionNumber): 
    file = FileDocumentManager.getFile(editor.getDocument())
    vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file)
    content = vcs.getDiffProvider().createFileContent(revisionNumber, file) 
    revisionText = content.getContent()
* Initialize markers with MyLineStatusTracker.setBaseRevision()
When you no longer want to:
* MyLineStatusTracker.release()

Also, http://www.jetbrains.org/intellij/sdk/docs/ might help.

0

Thanks for that large Answer!

I got something. My "first steps"-Code can render the line status with the content of any revision. nice! But i dont see any buttons in the toolbar (eg revert ect)

At the moment setBaseRevision do the job, but should i better copy createHighlighter -method, LineStatusTrackerDrawing,LineStatusMarkerPopup and all the other -classes?

0

>But i dont see any buttons in the toolbar
Yes, "standard" actions work with LineStatusTrackerManager and not with your markers.
You'll have to implement another ones, that do the same thing (but with your markers).

Links to the "standard" ones can be found here:
https://github.com/JetBrains/intellij-community/blob/master/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java

>At the moment setBaseRevision do the job, but should i better copy createHighlighter -method, LineStatusTrackerDrawing,LineStatusMarkerPopup and all the other -classes?
I'm not sure that i get the question.

Also, you can take a look at another existing usage:
https://github.com/JetBrains/intellij-community/blob/master/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java#L1250

0

Hi!

The Plugin is almost ready to share. this is how its look like:

 

It comes with a Dropdown with a list of all Branches and a TextField to input any revision. After choosing a revision the Diff-Panel show all affected Files ( Same as "Compare with Branch..."-Action).

BUT: Everytime if a File is not under GIT in one of both Revisions (For Example a new File in BranchX which not exists in master) it fails!

 

 

This is the relevant part:

    private void setBaseRevisionForEditor(Editor editor) {

        String revisionText = "";

        try {
            // Load Revision
//            String revisionNumberString = "9700550dae5d7968c5761c8a9a892a9351af8698";
            GitRevisionNumber revisionNumber = new GitRevisionNumber(this.revisionNumberString);

            if (editor == null) {
                return;
            }

            Document doc = editor.getDocument();

            if (doc == null) {
                return;
            }

            VirtualFile file = FileDocumentManager.getInstance().getFile(doc);
            if (file == null) {
                return;
            }
            AbstractVcs vcs = ProjectLevelVcsManager.getInstance(this.project).getVcsFor(file);

            if (vcs == null) {
                return;
            }


//            System.out.println("revison: " + revisionNumber + " file: " + file);

            ContentRevision content = vcs.getDiffProvider().createFileContent(revisionNumber, file);

            if (content == null) {
                return;
            }

            // Try to avoid failing...
////            new GitHelper();
//            Map<String, Object> diffList = this.gitHelper.getDiffList("HEAD", revisionNumber.toString());
//            Gson gson = new Gson();
//            String json = gson.toJson(diffList);
//            System.out.println(json);
//
//            // Check for invalid cases (workaround)
//            FilePath path = VcsUtil.getFilePath(file.getPath());
////            FilePath filePath = new LocalFilePath(file.getPath(), false);
//            System.out.println("1");
//            System.out.println(path);
//            GitFileRevision gitFileRevision = new GitFileRevision(this.project, path, revisionNumber);
//            System.out.println(gitFileRevision);

            revisionText = content.getContent();

            System.out.println("revtext: " + revisionText);

            Document document = new DocumentImpl(revisionText);
            CharSequence charSequence = document.getCharsSequence();

            // Create LineStatusTracker
            MyLineStatusTrackerManager myLineStatusTrackerManager = new MyLineStatusTrackerManager(
                    this.project,
                    editor
            );
            this.myLineStatusTrackerManagerCollection.add(myLineStatusTrackerManager);

            myLineStatusTrackerManager.setBaseRevision(charSequence);

        } catch (VcsException e) {
            System.out.println("Error loading revision");
//                e.printStackTrace();
        }
    }

 


Is it possible use AbstractVcs vcs or similar Objects who represent the Versioned file to check if it exists?

 

Please have a look into my Source-Code: https://bitbucket.org/...

0

I'm not sure if an API for this request exists .

You can try "new git4idea.GitFileRevision().loadContent()" (or directly call git4idea.util.GitFileUtils#getFileContent).
But this approach will fail if file was renamed at some point.

You might have to fall back to git commands (see git4idea.commands.GitImpl for examples).
But I'm not sure if it can be queried with a single git command (ex: if `git show -M -- file.txt:abcd0123` would track renames on the way to the revision)

0

No thats not a good Idea :-)

Ive found a Solution in GitCompareWithBranchAction and getDiffChanges with which i solved the Diff-Tool-Window as well. With this Collection as Base i can use it like

contentRevision = change.getBeforeRevision();
String content = "";
if (contentRevision != null) {
content = contentRevision.getContent();
}

Instead of

ContentRevision content = vcs.getDiffProvider().createFileContent(revisionNumber, file);

This works like a charme! Now i need to cleanup my mess... :-P

0

Another Bug. You said already that this will be maybe a hacky approach :-D

But im confident we can solve this as well....

Problem:

After Rollback via Line Status or manually removing changes to "No Local Changes", Comparing to master, Comparing HEAD again, do changes, i got no differences with my Plugin, but there was some changes! If i leave the focus to antoher window and come back to IDE and repeat the compare action, my plugin is working again.....

Dont understand? See it in Pictures:

0

Probably, the issue is somewhere in logic, reused from GitCompareWithBranchAction.
You have to update it manually when smth is changed. (ex: if you have a file that is the same in "test" and "master" - it will not be the same after a bit of typing).
For "standard" markers it is solved via ChangeListManager (a huge machinery for synchronizing "Local Changes" tab and `git status` output. You really won't copy-paste or even read it).

So, probably, you'll have to listen for VFS events and update differences (preferably, with some delay/throttling, as VFS events are triggered all the time).
VirtualFileManager.getInstance().addVirtualFileListener(VirtualFileListener, disposable);
ApplicationManager.getApplication().getMessageBus().connect(myProject).subscribe(VirtualFileManager.VFS_CHANGES, BulkFileListener);

Also, some changes might happen in-memory (and are not yet saved on disk to be noticed by git).
com.intellij.openapi.fileEditor.FileDocumentManager#isFileModified 
But AFAIU there are no convenient way to listen all Documents for a project.
So you'll have to listen for the ones, that are opened in Editor, or listen for FileStatusManager, that keep track of this flag too.
com.intellij.openapi.vcs.FileStatusListener

Also, the "master" branch might be altered with `git reset` command (or `git fetch`, if you allow comparing with remote branches).
git4idea.repo.GitRepositoryChangeListener


P.S. This is indeed a hacky approach, and LineStatusTrackerBase might change in future version. I hope, you won't mind.

0
VirtualFileListener, BulkFileListener via MesssageBus and FileStatusListener doesnt work! 
All together with the same behaviour as already described... if i focus out of Test-Instance to Development-Window (or anything else) all Actions will released with one shot. It looks as if these events are blocked until leaving the IDE, but why?

The Issue from the post before is solved other way, but one issue left with the diff window, that dont update after typing in one file / changing VCS-Status / ect


0

>It looks as if these events are blocked until leaving the IDE, but why?
Probably, you're observing the "Save on frame deactivation" behavior. 
You can try disabling automatic save in "File | Settings | Appearance & Behavior | System Settings" - and frame deactivation should stop working.
Also, you can try explicit "Save All" action instead of moving focus somewhere.

You're asking git to list files, that are different between local state (file system) and some branch.
But if the changes are still not dumped on disk - it will not notice them.
So for files, that are `FileDocumentManager#isFileModified() == true`, you'll have to load "base" (the one you're comparing with) revision even if git claims that nothing changed.

http://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/virtual_file.html
http://www.jetbrains.org/intellij/sdk/docs/basics/virtual_file_system.html

Surely, you can just dump all files on disk before comparing, but it might be annoying for some people (ex: if they're using scripts that listen for file system events to rebuild project).
com.intellij.openapi.fileEditor.FileDocumentManager#saveAllDocuments

0

File | Settings | Appearance & Behavior | System Settings => Save on frame deactivation should be deactivated, yes! Thats it.

 

This is how it looks now:

https://bitbucket.org/comodmw/rollback/overview

https://www.youtube.com/watch?v=C8vG0QIDKDE&feature=youtu.be

 

Totally awesome!

0

Hello again, after using in productivity a while. this plugin works well. but not very well. It does what it was designed for, and its fast. but the following issue occured this week not often, but constantly, and only after some longer time of usage (3-5 windows open, many git checkouts or other (massiv) git actions like large merges)

"Unable to save plugin settings: The plugin rollback failed to save settings and has been disabled. Please restart PhpStorm"

...buut there is nothing to save. what does it mean?

0

It should have logged an exception in the log.

0

Now ive got this error immediately after starting phpstorm. i dont see anything more as "Unable to save plugin settings: The plugin rollback failed to save settings and has been disabled. Please restart PhpStorm" as popup

maybe some of you guys can have a look into my code https://bitbucket.org/comodmw/rollback.

 

What can i do to get more debug information in a live Environment? The problem is, i dont get this error while developing :-)

0

Please sign in to leave a comment.