1 package com
.intellij
.openapi
.vcs
.changes
;
3 import com
.intellij
.openapi
.application
.ApplicationManager
;
4 import com
.intellij
.openapi
.editor
.Document
;
5 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
6 import com
.intellij
.openapi
.fileEditor
.impl
.LoadTextUtil
;
7 import com
.intellij
.openapi
.project
.Project
;
8 import com
.intellij
.openapi
.util
.Computable
;
9 import com
.intellij
.openapi
.util
.text
.StringUtil
;
10 import com
.intellij
.openapi
.vcs
.FileStatus
;
11 import com
.intellij
.openapi
.vcs
.FileStatusManager
;
12 import com
.intellij
.openapi
.vcs
.VcsException
;
13 import com
.intellij
.openapi
.vfs
.VirtualFile
;
14 import com
.intellij
.psi
.PsiElement
;
15 import com
.intellij
.psi
.PsiFile
;
16 import com
.intellij
.psi
.PsiFileFactory
;
17 import com
.intellij
.psi
.PsiRecursiveElementVisitor
;
18 import org
.jetbrains
.annotations
.Nullable
;
20 import java
.util
.ArrayList
;
21 import java
.util
.HashMap
;
22 import java
.util
.List
;
26 * @author Konstantin Bulenkov
28 public class PsiChangeTracker
{
29 private PsiChangeTracker() {
32 public static <T
extends PsiElement
> Map
<T
, FileStatus
> getElementsChanged(PsiFile file
, final PsiElementFilter
<T
> filter
) {
33 final Project project
= file
.getProject();
34 final String oldText
= getUnmodifiedDocument(file
.getVirtualFile(), project
);
35 //TODO: make loop for different languages
36 //TODO: for ( PsiFile f : file.getViewProvider().getAllFiles() )
37 //TODO: for some languages (eg XML) isEquivalentTo works ugly. Think about pluggable matchers for different languages/elements
38 final PsiFile oldFile
= oldText
== null
39 ?
null : PsiFileFactory
.getInstance(project
).createFileFromText(oldText
, file
);
40 return getElementsChanged(file
, oldFile
, filter
);
43 public static <T
extends PsiElement
> Map
<T
, FileStatus
> getElementsChanged(PsiFile file
, PsiFile oldFile
, final PsiElementFilter
<T
> filter
) {
44 final Project project
= file
.getProject();
45 final List
<T
> elements
= new ArrayList
<T
>();
46 final List
<T
> oldElements
= new ArrayList
<T
>();
48 file
.accept(new MyVisitor
<T
>(filter
, elements
));
49 final VirtualFile vf
= file
.getVirtualFile();
50 final FileStatus status
= vf
== null ?
null : FileStatusManager
.getInstance(project
).getStatus(vf
);
51 final HashMap
<T
, FileStatus
> result
= new HashMap
<T
, FileStatus
>();
52 if (status
== FileStatus
.ADDED
||
53 status
== FileStatus
.DELETED
||
54 status
== FileStatus
.DELETED_FROM_FS
||
55 status
== FileStatus
.UNKNOWN
) {
56 for (T element
: elements
) {
57 result
.put(element
, status
);
62 if (oldFile
== null) return result
;
63 oldFile
.accept(new MyVisitor
<T
>(filter
, oldElements
));
64 calculateStatuses(elements
, oldElements
, result
);
69 private static <T
extends PsiElement
> Map
<T
, FileStatus
> calculateStatuses(List
<T
> elements
,
71 Map
<T
, FileStatus
> result
) {
72 for (T element
: elements
) {
74 for (T oldElement
: oldElements
) {
75 if (element
.isEquivalentTo(oldElement
)) {
81 oldElements
.remove(e
);
82 if (!element
.getText().equals(e
.getText())) {
83 result
.put(element
, FileStatus
.MODIFIED
);
87 result
.put(element
, FileStatus
.ADDED
);
91 for (T oldElement
: oldElements
) {
92 result
.put(oldElement
, FileStatus
.DELETED
);
99 private static String
getUnmodifiedDocument(final VirtualFile file
, Project project
) {
100 final Change change
= ChangeListManager
.getInstance(project
).getChange(file
);
101 if (change
!= null) {
102 final ContentRevision beforeRevision
= change
.getBeforeRevision();
103 if (beforeRevision
instanceof BinaryContentRevision
) {
106 if (beforeRevision
!= null) {
109 content
= beforeRevision
.getContent();
111 catch (VcsException ex
) {
114 return content
== null ?
null : StringUtil
.convertLineSeparators(content
);
119 final Document document
= FileDocumentManager
.getInstance().getCachedDocument(file
);
120 if (document
!= null && document
.getModificationStamp() != file
.getModificationStamp()) {
121 return ApplicationManager
.getApplication().runReadAction(new Computable
<String
>() {
122 public String
compute() {
123 return LoadTextUtil
.loadText(file
).toString();
131 static class MyVisitor
<T
extends PsiElement
> extends PsiRecursiveElementVisitor
{
132 private final PsiElementFilter
<T
> filter
;
133 private final List
<T
> elements
;
135 protected MyVisitor(final PsiElementFilter
<T
> filter
, final List
<T
> elements
) {
136 this.filter
= filter
;
137 this.elements
= elements
;
141 public void visitElement(PsiElement element
) {
142 if (filter
.getClassFilter().isAssignableFrom(element
.getClass())) {
143 final T e
= (T
)element
;
144 if (filter
.accept(e
)) {
148 super.visitElement(element
);