11package fr .adrienbrault .idea .symfony2plugin .translation ;
22
33import com .intellij .openapi .project .Project ;
4+ import com .intellij .openapi .util .Key ;
45import 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 ;
513import fr .adrienbrault .idea .symfony2plugin .Settings ;
614import fr .adrienbrault .idea .symfony2plugin .Symfony2ProjectComponent ;
15+ import fr .adrienbrault .idea .symfony2plugin .dic .container .util .ServiceContainerUtil ;
716import fr .adrienbrault .idea .symfony2plugin .translation .parser .TranslationPsiParser ;
817import 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 ;
921import org .jetbrains .annotations .Nullable ;
1022
1123import java .io .File ;
12- import java .util .HashMap ;
13- import java .util .Map ;
24+ import java .util .* ;
25+ import java .util .stream . Collectors ;
1426
1527/**
1628 * @author Daniel Espendiller <daniel@espendiller.net>
1729 */
1830public 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" );
1933
20- protected static Map <Project , TranslationIndex > instance = new HashMap <>();
34+ private static Map <Project , TranslationIndex > instance = new HashMap <>();
2135
22- protected Project project ;
36+ private Project project ;
2337
2438 @ Nullable
2539 private TranslationStringMap translationStringMap ;
26- private Long translationStringMapModified ;
27-
28- public static TranslationIndex getInstance (Project project ){
40+ private long translationStringMapModified ;
2941
42+ public static TranslationIndex getInstance (@ NotNull Project project ){
3043 TranslationIndex projectInstance = instance .get (project );
3144 if (projectInstance != null ) {
3245 return projectInstance ;
@@ -36,102 +49,92 @@ public static TranslationIndex getInstance(Project project){
3649 instance .put (project , projectInstance );
3750
3851 return projectInstance ;
39-
4052 }
4153
42- public TranslationIndex (Project project ) {
54+ private TranslationIndex (@ NotNull Project project ) {
4355 this .project = project ;
4456 }
4557
46-
4758 synchronized public TranslationStringMap getTranslationMap () {
48-
4959 if (this .translationStringMap != null && this .isCacheValid ()) {
5060 return this .translationStringMap ;
5161 }
5262
53- File translationDirectory = this .getTranslationRoot ();
54- if (null == translationDirectory ) {
63+ Collection < File > translationDirectories = this .getTranslationRoot ();
64+ if (translationDirectories . size () == 0 ) {
5565 return new TranslationStringMap ();
5666 }
5767
58- Symfony2ProjectComponent .getLogger ().info ("translations changed: " + translationDirectory . toString ( ));
68+ Symfony2ProjectComponent .getLogger ().info ("translations changed: " + StringUtils . join ( translationDirectories . stream (). map ( File :: toString ). collect ( Collectors . toSet ()), "," ));
5969
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 ();
6272 }
6373
64- protected boolean isCacheValid () {
65-
74+ private boolean isCacheValid () {
6675 // 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 ) {
6978 return false ;
7079 }
7180
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+ }
8083
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+ }
8194
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+ }
8399
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 <>();
89103
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 ;
94108 }
95109
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 );
112113 }
113-
114-
115114 }
116115
117- return true ;
118- }
116+ VirtualFile baseDir = project .getBaseDir ();
119117
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+ }
122124
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+ }
127130
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+ }
131136 }
132137
133- return file ;
138+ return files ;
134139 }
135-
136-
137140}
0 commit comments