1
1
package fr .adrienbrault .idea .symfony2plugin .translation ;
2
2
3
3
import com .intellij .openapi .project .Project ;
4
+ import com .intellij .openapi .util .Key ;
4
5
import com .intellij .openapi .util .io .FileUtil ;
6
+ import com .intellij .openapi .vfs .VfsUtil ;
7
+ import com .intellij .openapi .vfs .VfsUtilCore ;
8
+ import com .intellij .openapi .vfs .VirtualFile ;
9
+ import com .intellij .psi .util .CachedValue ;
10
+ import com .intellij .psi .util .CachedValueProvider ;
11
+ import com .intellij .psi .util .CachedValuesManager ;
12
+ import com .intellij .psi .util .PsiModificationTracker ;
5
13
import fr .adrienbrault .idea .symfony2plugin .Settings ;
6
14
import fr .adrienbrault .idea .symfony2plugin .Symfony2ProjectComponent ;
15
+ import fr .adrienbrault .idea .symfony2plugin .dic .container .util .ServiceContainerUtil ;
7
16
import fr .adrienbrault .idea .symfony2plugin .translation .parser .TranslationPsiParser ;
8
17
import fr .adrienbrault .idea .symfony2plugin .translation .parser .TranslationStringMap ;
18
+ import fr .adrienbrault .idea .symfony2plugin .util .TimeSecondModificationTracker ;
19
+ import org .apache .commons .lang .StringUtils ;
20
+ import org .jetbrains .annotations .NotNull ;
9
21
import org .jetbrains .annotations .Nullable ;
10
22
11
23
import java .io .File ;
12
- import java .util .HashMap ;
13
- import java .util .Map ;
24
+ import java .util .* ;
25
+ import java .util .stream . Collectors ;
14
26
15
27
/**
16
28
* @author Daniel Espendiller <daniel@espendiller.net>
17
29
*/
18
30
public class TranslationIndex {
31
+ private static final Key <CachedValue <Collection <File >>> SYMFONY_TRANSLATION_COMPILED_TIMED_WATCHER = new Key <>("SYMFONY_TRANSLATION_COMPILED_TIMED_WATCHER" );
32
+ private static final Key <CachedValue <Collection <File >>> SYMFONY_TRANSLATION_COMPILED = new Key <>("SYMFONY_TRANSLATION_COMPILED" );
19
33
20
- protected static Map <Project , TranslationIndex > instance = new HashMap <>();
34
+ private static Map <Project , TranslationIndex > instance = new HashMap <>();
21
35
22
- protected Project project ;
36
+ private Project project ;
23
37
24
38
@ Nullable
25
39
private TranslationStringMap translationStringMap ;
26
- private Long translationStringMapModified ;
27
-
28
- public static TranslationIndex getInstance (Project project ){
40
+ private long translationStringMapModified ;
29
41
42
+ public static TranslationIndex getInstance (@ NotNull Project project ){
30
43
TranslationIndex projectInstance = instance .get (project );
31
44
if (projectInstance != null ) {
32
45
return projectInstance ;
@@ -36,102 +49,92 @@ public static TranslationIndex getInstance(Project project){
36
49
instance .put (project , projectInstance );
37
50
38
51
return projectInstance ;
39
-
40
52
}
41
53
42
- public TranslationIndex (Project project ) {
54
+ private TranslationIndex (@ NotNull Project project ) {
43
55
this .project = project ;
44
56
}
45
57
46
-
47
58
synchronized public TranslationStringMap getTranslationMap () {
48
-
49
59
if (this .translationStringMap != null && this .isCacheValid ()) {
50
60
return this .translationStringMap ;
51
61
}
52
62
53
- File translationDirectory = this .getTranslationRoot ();
54
- if (null == translationDirectory ) {
63
+ Collection < File > translationDirectories = this .getTranslationRoot ();
64
+ if (translationDirectories . size () == 0 ) {
55
65
return new TranslationStringMap ();
56
66
}
57
67
58
- Symfony2ProjectComponent .getLogger ().info ("translations changed: " + translationDirectory . toString ( ));
68
+ Symfony2ProjectComponent .getLogger ().info ("translations changed: " + StringUtils . join ( translationDirectories . stream (). map ( File :: toString ). collect ( Collectors . toSet ()), "," ));
59
69
60
- this .translationStringMapModified = translationDirectory . lastModified ();
61
- return this .translationStringMap = new TranslationPsiParser (project ).parsePathMatcher (translationDirectory . getPath () );
70
+ this .translationStringMapModified = translationDirectories . stream (). mapToLong ( File :: lastModified ). sum ();
71
+ return this .translationStringMap = new TranslationPsiParser (project , translationDirectories ).parsePathMatcher ();
62
72
}
63
73
64
- protected boolean isCacheValid () {
65
-
74
+ private boolean isCacheValid () {
66
75
// symfony2 recreates translation file on change, so folder modtime is caching indicator
67
- File translationRootPath = this .getTranslationRoot ();
68
- if ( null == translationRootPath ) {
76
+ Collection < File > translationDirectories = this .getTranslationRoot ();
77
+ if ( translationDirectories . size () == 0 ) {
69
78
return false ;
70
79
}
71
80
72
- Long translationModified = translationRootPath .lastModified ();
73
- if (!translationModified .equals (translationStringMapModified )) {
74
- return false ;
75
- }
76
-
77
- // @TODO make this more abstract
78
- // we check for possible file modifications here per translation file
79
- if (this .translationStringMap != null ) {
81
+ return translationDirectories .stream ().mapToLong (File ::lastModified ).sum () == translationStringMapModified ;
82
+ }
80
83
84
+ @ NotNull
85
+ private Collection <File > getTranslationRoot () {
86
+ return CachedValuesManager .getManager (project )
87
+ .getCachedValue (
88
+ project ,
89
+ SYMFONY_TRANSLATION_COMPILED ,
90
+ () -> CachedValueProvider .Result .create (getTranslationRootInnerTime (), PsiModificationTracker .MODIFICATION_COUNT ),
91
+ false
92
+ );
93
+ }
81
94
82
- File file = new File (translationRootPath .getPath ());
95
+ @ NotNull
96
+ private Collection <File > getTranslationRootInnerTime () {
97
+ return CachedValuesManager .getManager (project ).getCachedValue (project , SYMFONY_TRANSLATION_COMPILED_TIMED_WATCHER , () -> CachedValueProvider .Result .create (getTranslationRootInner (), TimeSecondModificationTracker .TIMED_MODIFICATION_TRACKER_60 ), false );
98
+ }
83
99
84
- // use cache in any i/o error
85
- File [] files = file .listFiles ();
86
- if (null == files ) {
87
- return true ;
88
- }
100
+ @ NotNull
101
+ private Collection <File > getTranslationRootInner () {
102
+ Collection <File > files = new HashSet <>();
89
103
90
- // directory is empty or not exits, before and after instance
91
- Map < String , Long > fileNames = this . translationStringMap . getFileNames ();
92
- if ( files . length == 0 && fileNames . size () == 0 ) {
93
- return true ;
104
+ String translationPath = Settings . getInstance ( project ). pathToTranslation ;
105
+ if ( StringUtils . isNotBlank ( translationPath )) {
106
+ if (! FileUtil . isAbsolute ( translationPath ) ) {
107
+ translationPath = project . getBasePath () + "/" + translationPath ;
94
108
}
95
109
96
- for (File fileEntry : files ) {
97
- if (!fileEntry .isDirectory ()) {
98
- String fileName = fileEntry .getName ();
99
- if (fileName .startsWith ("catalogue" ) && fileName .endsWith ("php" )) {
100
-
101
-
102
- if (!fileNames .containsKey (fileName )) {
103
- return false ;
104
- }
105
-
106
- if (!fileNames .get (fileName ).equals (fileEntry .lastModified ())) {
107
- return false ;
108
- }
109
-
110
- }
111
- }
110
+ File file = new File (translationPath );
111
+ if (file .exists () && file .isDirectory ()) {
112
+ files .add (file );
112
113
}
113
-
114
-
115
114
}
116
115
117
- return true ;
118
- }
116
+ VirtualFile baseDir = project .getBaseDir ();
119
117
120
- @ Nullable
121
- protected File getTranslationRoot () {
118
+ for (String containerFile : ServiceContainerUtil .getContainerFiles (project )) {
119
+ // resolve the file
120
+ VirtualFile containerVirtualFile = VfsUtil .findRelativeFile (containerFile , baseDir );
121
+ if (containerVirtualFile == null ) {
122
+ continue ;
123
+ }
122
124
123
- String translationPath = Settings .getInstance (this .project ).pathToTranslation ;
124
- if (!FileUtil .isAbsolute (translationPath )) {
125
- translationPath = project .getBasePath () + "/" + translationPath ;
126
- }
125
+ // get directory of the file; translation folder is same directory
126
+ VirtualFile cacheDirectory = containerVirtualFile .getParent ();
127
+ if (cacheDirectory == null ) {
128
+ continue ;
129
+ }
127
130
128
- File file = new File (translationPath );
129
- if (!file .exists () || !file .isDirectory ()) {
130
- return null ;
131
+ // get translation sub directory
132
+ VirtualFile translations = cacheDirectory .findChild ("translations" );
133
+ if (translations != null ) {
134
+ files .add (VfsUtilCore .virtualToIoFile (translations ));
135
+ }
131
136
}
132
137
133
- return file ;
138
+ return files ;
134
139
}
135
-
136
-
137
140
}
0 commit comments