void () { Application app = ApplicationManager.getApplication(); if (app == null) return; app.getMessageBus().connect(this).subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { WeakReference<MyUndoableAction> lastAction; @Override public void before(@NotNull List<? extends @NotNull VFileEvent> events) { if (CommandProcessor.getInstance().isUndoTransparentActionInProgress()) return; Project project = CommandProcessor.getInstance().getCurrentCommandProject(); if (project == null || !project.isOpen()) return; MyUndoableAction action = createUndoableAction(events); if (action == null) return; action.doRemove(action.removed); lastAction = new WeakReference<>(action); UndoManager.getInstance(project).undoableActionPerformed(action); } @Override public void after(@NotNull List<? extends @NotNull VFileEvent> events) { MyUndoableAction action = SoftReference.dereference(lastAction); lastAction = null; if (action != null) { ApplicationManager.getApplication().invokeLater(() -> action.doAdd(action.added)); } } @Nullable MyUndoableAction createUndoableAction(@NotNull List<? extends VFileEvent> events) { // NOTE: VFS handles renames, so the code for RENAME events is deleted (see history) List<? extends VFileEvent> eventsFiltered = JBIterable.from(events).filter(VFileDeleteEvent.class).toList(); if (eventsFiltered.isEmpty()) return null; Map<String, T> removed = new HashMap<>(); NavigableSet<VirtualFile> navSet = null; synchronized (myMappings) { ensureStateLoaded(); for (VFileEvent event : eventsFiltered) { VirtualFile file = event.getFile(); if (file == null) continue; String fileUrl = file.getUrl(); if (!file.isDirectory()) { T m = doGetImmediateMapping(file); if (m != null) { removed.put(fileUrl, m); } } else { if (navSet == null) { navSet = new TreeSet<>( (f1, f2) -> Comparing.compare(f1 == null ? null : f1.getUrl(), f2 == null ? null : f2.getUrl())); navSet.addAll(myMappings.keySet()); } for (VirtualFile child : navSet.tailSet(file)) { if (!VfsUtilCore.isAncestor(file, child, false)) break; String childUrl = child.getUrl(); T m = doGetImmediateMapping(child); removed.put(childUrl, m); } } } } return removed.isEmpty() ? null : new MyUndoableAction(new HashMap<>(), removed); } }); }