1010import com .google .common .collect .Lists ;
1111import com .google .common .collect .Maps ;
1212import com .google .common .collect .Sets ;
13- import com .google .common .collect .Streams ;
1413import com .google .gson .Gson ;
1514import com .google .gson .JsonSyntaxException ;
1615import com .intellij .ide .plugins .IdeaPluginDescriptor ;
1716import com .intellij .ide .plugins .PluginManager ;
1817import com .intellij .ide .scratch .ScratchFileType ;
1918import com .intellij .injected .editor .VirtualFileWindow ;
19+ import com .intellij .json .JsonFileType ;
2020import com .intellij .lang .jsgraphql .GraphQLFileType ;
2121import com .intellij .lang .jsgraphql .GraphQLLanguage ;
2222import com .intellij .lang .jsgraphql .ide .editor .GraphQLIntrospectionHelper ;
4040import com .intellij .openapi .roots .ModuleRootManager ;
4141import com .intellij .openapi .util .Ref ;
4242import com .intellij .openapi .util .text .StringUtil ;
43- import com .intellij .openapi .vfs .*;
43+ import com .intellij .openapi .vfs .LocalFileSystem ;
44+ import com .intellij .openapi .vfs .VirtualFile ;
45+ import com .intellij .openapi .vfs .VirtualFileManager ;
46+ import com .intellij .openapi .vfs .newvfs .BulkFileListener ;
47+ import com .intellij .openapi .vfs .newvfs .events .VFileEvent ;
48+ import com .intellij .openapi .vfs .newvfs .events .VFilePropertyChangeEvent ;
4449import com .intellij .psi .*;
4550import com .intellij .psi .search .FilenameIndex ;
4651import com .intellij .psi .search .GlobalSearchScope ;
@@ -87,6 +92,8 @@ public class GraphQLConfigManager {
8792 GRAPHQLCONFIG_YAML
8893 };
8994
95+ private static final Set <String > GRAPHQLCONFIG_FILE_NAMES_SET = Sets .newHashSet (GRAPHQLCONFIG_FILE_NAMES );
96+
9097 private static final GraphQLNamedScope NONE = new GraphQLNamedScope ("" , null );
9198
9299 private final Project myProject ;
@@ -98,7 +105,6 @@ public class GraphQLConfigManager {
98105 private volatile Map <GraphQLResolvedConfigData , GraphQLFile > configDataToEntryFiles = Maps .newConcurrentMap ();
99106 private volatile Map <GraphQLResolvedConfigData , GraphQLConfigPackageSet > configDataToPackageset = Maps .newConcurrentMap ();
100107 private final Map <String , GraphQLNamedScope > virtualFilePathToScopes = Maps .newConcurrentMap ();
101- private VirtualFileListener virtualFileListener ;
102108
103109 public GraphQLConfigManager (Project myProject ) {
104110 this .myProject = myProject ;
@@ -195,7 +201,7 @@ public void createAndOpenConfigFile(VirtualFile configBaseDir, Boolean openEdito
195201 /**
196202 * Gets the currently discovered configurations
197203 *
198- * @see #buildConfigurationModel()
204+ * @see #buildConfigurationModel(List )
199205 */
200206 public Map <VirtualFile , GraphQLConfigData > getConfigurationsByPath () {
201207 return configPathToConfigurations ;
@@ -264,41 +270,38 @@ public List<GraphQLConfigEndpoint> getEndpoints(VirtualFile virtualFile) {
264270 }
265271
266272 void initialize () {
267- virtualFileListener = new VirtualFileListener () {
268-
273+ myProject .getMessageBus ().connect ().subscribe (VirtualFileManager .VFS_CHANGES , new BulkFileListener () {
269274 @ Override
270- public void propertyChanged (@ NotNull VirtualFilePropertyEvent event ) {
271- onVirtualFileChange (event );
272- }
273-
274- @ Override
275- public void contentsChanged (@ NotNull VirtualFileEvent event ) {
276- onVirtualFileChange (event );
277- }
278-
279- @ Override
280- public void fileDeleted (@ NotNull VirtualFileEvent event ) {
281- onVirtualFileChange (event );
282- }
283-
284- @ Override
285- public void fileCreated (@ NotNull VirtualFileEvent event ) {
286- onVirtualFileChange (event );
287- }
288-
289- @ Override
290- public void fileCopied (@ NotNull VirtualFileCopyEvent event ) {
291- onVirtualFileChange (event );
292- }
293-
294- @ Override
295- public void fileMoved (@ NotNull VirtualFileMoveEvent event ) {
296- onVirtualFileChange (event );
275+ public void after (@ NotNull List <? extends VFileEvent > events ) {
276+ final List <VirtualFile > changedConfigFiles = Lists .newArrayList ();
277+ boolean configurationsRenamed = false ;
278+ for (VFileEvent event : events ) {
279+ final VirtualFile file = event .getFile ();
280+ if (file != null ) {
281+ if (event instanceof VFilePropertyChangeEvent ) {
282+ // renames
283+ final VFilePropertyChangeEvent propertyChangeEvent = (VFilePropertyChangeEvent ) event ;
284+ if (VirtualFile .PROP_NAME .equals (propertyChangeEvent .getPropertyName ())) {
285+ if (propertyChangeEvent .getNewValue () instanceof String && GRAPHQLCONFIG_FILE_NAMES_SET .contains (propertyChangeEvent .getNewValue ())) {
286+ configurationsRenamed = true ;
287+ } else if (propertyChangeEvent .getOldValue () instanceof String && GRAPHQLCONFIG_FILE_NAMES_SET .contains (propertyChangeEvent .getOldValue ())) {
288+ configurationsRenamed = true ;
289+ }
290+ }
291+ } else {
292+ // other changes
293+ final String name = file .getName ();
294+ if (GRAPHQLCONFIG_FILE_NAMES_SET .contains (name )) {
295+ changedConfigFiles .add (file );
296+ }
297+ }
298+ }
299+ }
300+ if (!changedConfigFiles .isEmpty () || configurationsRenamed ) {
301+ buildConfigurationModel (changedConfigFiles );
302+ }
297303 }
298-
299-
300- };
301- VirtualFileManager .getInstance ().addVirtualFileListener (virtualFileListener );
304+ });
302305
303306 PsiManager .getInstance (myProject ).addPsiTreeChangeListener (new PsiTreeChangeAdapter () {
304307
@@ -314,7 +317,7 @@ public void childReplaced(@NotNull PsiTreeChangeEvent event) {
314317 }
315318 });
316319
317- buildConfigurationModel ();
320+ buildConfigurationModel (null );
318321
319322 introspectEndpoints ();
320323
@@ -327,39 +330,27 @@ private boolean hasGraphQLConfigComment(PsiElement psiElement) {
327330 return false ;
328331 }
329332
330- private void onVirtualFileChange (VirtualFileEvent event ) {
331- if (myProject .isDisposed ()) {
332- VirtualFileManager .getInstance ().removeVirtualFileListener (virtualFileListener );
333- return ;
334- }
335- String oldName = null ;
336- if (event instanceof VirtualFilePropertyEvent ) {
337- final VirtualFilePropertyEvent propertyEvent = (VirtualFilePropertyEvent ) event ;
338- if (VirtualFile .PROP_NAME .equals (propertyEvent .getPropertyName ())) {
339- oldName = String .valueOf (propertyEvent .getOldValue ());
340- }
341- }
342- final String [] names = new String []{event .getFile ().getName (), oldName };
343- for (String name : names ) {
344- if (name == null ) {
345- continue ;
346- }
347- if (name .startsWith (GRAPHQLCONFIG )) {
348- if (name .length () == GRAPHQLCONFIG .length () || name .equals (GRAPHQLCONFIG_YML ) || name .equals (GRAPHQLCONFIG_YAML )) {
349- buildConfigurationModel ();
350- break ;
351- }
352- }
353-
354- }
355- }
356-
357- public void buildConfigurationModel () {
333+ /**
334+ * Builds a model of the .graphqlconfig files in the project
335+ *
336+ * @param changedConfigurationFiles config files that were changed in the Virtual File System and should be explicitly processed given that they haven't been indexed yet
337+ */
338+ public void buildConfigurationModel (@ Nullable List <VirtualFile > changedConfigurationFiles ) {
358339
359340 final Map <VirtualFile , GraphQLConfigData > newConfigPathToConfigurations = Maps .newConcurrentMap ();
360341
361342 // JSON format
362- final Collection <VirtualFile > jsonFiles = FilenameIndex .getVirtualFilesByName (myProject , GRAPHQLCONFIG , projectScope );
343+ final Collection <VirtualFile > jsonFiles = Sets .newLinkedHashSet (FilenameIndex .getVirtualFilesByName (myProject , GRAPHQLCONFIG , projectScope ));
344+ if (changedConfigurationFiles != null ) {
345+ for (VirtualFile configurationFile : changedConfigurationFiles ) {
346+ if (configurationFile .getFileType ().equals (JsonFileType .INSTANCE )) {
347+ if (configurationFile .isValid ()) { // don't process deletions
348+ jsonFiles .add (configurationFile );
349+ }
350+ }
351+ }
352+ }
353+
363354 final Gson gson = new Gson ();
364355 for (VirtualFile jsonFile : jsonFiles ) {
365356 try {
@@ -374,13 +365,22 @@ public void buildConfigurationModel() {
374365 }
375366
376367 // YAML format
377- final Collection <VirtualFile > ymlFiles = FilenameIndex .getVirtualFilesByName (myProject , GRAPHQLCONFIG_YML , projectScope );
378- final Collection <VirtualFile > yamlFiles = FilenameIndex .getVirtualFilesByName (myProject , GRAPHQLCONFIG_YAML , projectScope );
379- if (!ymlFiles .isEmpty () || !yamlFiles .isEmpty ()) {
368+ final Collection <VirtualFile > yamlFiles = Sets .newLinkedHashSet (FilenameIndex .getVirtualFilesByName (myProject , GRAPHQLCONFIG_YML , projectScope ));
369+ yamlFiles .addAll (FilenameIndex .getVirtualFilesByName (myProject , GRAPHQLCONFIG_YAML , projectScope ));
370+ if (changedConfigurationFiles != null ) {
371+ for (VirtualFile configurationFile : changedConfigurationFiles ) {
372+ if (configurationFile .getName ().equals (GRAPHQLCONFIG_YML ) || configurationFile .getName ().equals (GRAPHQLCONFIG_YAML )) {
373+ if (configurationFile .isValid ()) { // don't process deletions
374+ yamlFiles .add (configurationFile );
375+ }
376+ }
377+ }
378+ }
379+ if (!yamlFiles .isEmpty ()) {
380380 final Representer representer = new Representer ();
381381 representer .getPropertyUtils ().setSkipMissingProperties (true );
382382 final Yaml yaml = new Yaml (new Constructor (GraphQLConfigData .class ), representer );
383- Streams . concat ( ymlFiles . stream (), yamlFiles . stream ()) .forEach (yamlFile -> {
383+ yamlFiles .forEach (yamlFile -> {
384384 try {
385385 final String yamlText = new String (yamlFile .contentsToByteArray (), yamlFile .getCharset ());
386386 final GraphQLConfigData graphQLConfigData = yaml .load (yamlText );
0 commit comments