void () { if (ourSubscribed.getAndSet(true)) return; Application app = ApplicationManager.getApplication(); if (app.isDisposed()) return; // we might perform a shutdown activity that includes visiting archives (IDEA-181620) MessageBusConnection connection = app.getMessageBus().connect(app); connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { @Override public void after(@NotNull List<? extends @NotNull VFileEvent> events) { InvalidationState state = null; synchronized (ourLock) { for (var event : events) { if (!(event.getFileSystem() instanceof LocalFileSystem)) continue; if (!(event instanceof VFileContentChangeEvent contentChangeEvent)) continue; String path = contentChangeEvent.getPath(); VirtualFile file = contentChangeEvent.getFile(); if (!file.isDirectory()) { state = invalidate(state, path); } else { Collection<String> affectedPaths = ourDominatorsMap.get(path); if (affectedPaths != null) { affectedPaths = new ArrayList<>(affectedPaths); // defensive copying; original may be updated on invalidation for (String affectedPath : affectedPaths) { state = invalidate(state, affectedPath); } } } } } if (state != null) state.scheduleRefresh(); } }); connection.subscribe(DynamicPluginListener.TOPIC, new DynamicPluginListener() { @Override public void pluginUnloaded(@NotNull IdeaPluginDescriptor pluginDescriptor, boolean isUpdate) { synchronized (ourLock) { // avoid leaking ArchiveFileSystem registered by plugin, e.g. TgzFileSystem from Kubernetes plugin ourHandlerCache.clear(); } } }); }