<commit_before>package org.jetbrains.idea.maven.project;

import com.intellij.ProjectTopics;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.EditorEventMulticaster;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.*;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.util.PathUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.update.Update;
import gnu.trove.THashSet;
import org.jetbrains.idea.maven.embedder.MavenEmbedderFactory;
import org.jetbrains.idea.maven.utils.MavenConstants;
import org.jetbrains.idea.maven.utils.MavenMergingUpdateQueue;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class MavenProjectsManagerWatcher {
  private static final int DOCUMENT_SAVE_DELAY = 1000;

  private final Project myProject;
  private final MavenProjectsTree myProjectsTree;
  private final MavenGeneralSettings myGeneralSettings;
  private final MavenProjectsProcessor myReadingProcessor;
  private final MavenEmbeddersManager myEmbeddersManager;

  private final MessageBusConnection myBusConnection;

  private DocumentAdapter myDocumentListener;
  private MavenGeneralSettings.Listener mySettingsPathsChangesListener;
  private List<VirtualFilePointer> mySettingsFilesPointers = new ArrayList<VirtualFilePointer>();
  private List<LocalFileSystem.WatchRequest> myWatchedRoots = new ArrayList<LocalFileSystem.WatchRequest>();

  private final Set<Document> myChangedDocuments = new THashSet<Document>();
  private final MavenMergingUpdateQueue myChangedDocumentsQueue = new MavenMergingUpdateQueue(getClass() + ": Document changes queue",
                                                                                              DOCUMENT_SAVE_DELAY,
                                                                                              false);

  public MavenProjectsManagerWatcher(Project project,
                                     MavenProjectsTree projectsTree,
                                     MavenGeneralSettings generalSettings,
                                     MavenProjectsProcessor readingProcessor,
                                     MavenEmbeddersManager embeddersManager) {
    myProject = project;
    myProjectsTree = projectsTree;
    myGeneralSettings = generalSettings;
    myReadingProcessor = readingProcessor;
    myEmbeddersManager = embeddersManager;

    myBusConnection = myProject.getMessageBus().connect();
  }

  public synchronized void start() {
    myBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, new MyFileChangeListener());
    myBusConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyRootChangesListener());

    myChangedDocumentsQueue.makeUserAware(myProject);
    myChangedDocumentsQueue.activate();

    myDocumentListener = new DocumentAdapter() {
      public void documentChanged(DocumentEvent event) {
        Document doc = event.getDocument();
        VirtualFile file = FileDocumentManager.getInstance().getFile(doc);

        if (file == null) return;
        boolean isMavenFile = file.getName().equals(MavenConstants.POM_XML)
                              || file.getName().equals(MavenConstants.PROFILES_XML)
                              || isSettingsFile(file);
        if (!isMavenFile) return;

        synchronized (myChangedDocuments) {
          myChangedDocuments.add(doc);
        }
        myChangedDocumentsQueue.queue(new Update(MavenProjectsManagerWatcher.this) {
          public void run() {
            Set<Document> copy;

            synchronized (myChangedDocuments) {
              copy = new THashSet<Document>(myChangedDocuments);
              myChangedDocuments.clear();
            }

            for (Document each : copy) {
              FileDocumentManager.getInstance().saveDocument(each);
            }
          }
        });
      }
    };
    getDocumentEventMulticaster().addDocumentListener(myDocumentListener);

    mySettingsPathsChangesListener = new MavenGeneralSettings.Listener() {
      public void pathChanged() {
        updateSettingsFilePointers();
        onSettingsChange();
      }
    };
    myGeneralSettings.addListener(mySettingsPathsChangesListener);
    updateSettingsFilePointers();
  }

  private void updateSettingsFilePointers() {
    LocalFileSystem.getInstance().removeWatchedRoots(myWatchedRoots);
    mySettingsFilesPointers.clear();
    addFilePointer(MavenEmbedderFactory.resolveGlobalSettingsFile(myGeneralSettings.getMavenHome()));
    addFilePointer(MavenEmbedderFactory.resolveUserSettingsFile(myGeneralSettings.getMavenSettingsFile()));
  }

  private void addFilePointer(File settingsFile) {
    if (settingsFile == null) return;

    myWatchedRoots.add(LocalFileSystem.getInstance().addRootToWatch(getNormalizedPath(settingsFile.getParentFile()), false));

    String url = VfsUtil.pathToUrl(getNormalizedPath(settingsFile));
    mySettingsFilesPointers.add(VirtualFilePointerManager.getInstance().create(url, myProject, new VirtualFilePointerListener() {
      public void beforeValidityChanged(VirtualFilePointer[] pointers) {
      }

      public void validityChanged(VirtualFilePointer[] pointers) {
      }
    }));
  }

  private String getNormalizedPath(File settingsFile) {
    return FileUtil.toSystemIndependentName(PathUtil.getCanonicalPath(settingsFile.getAbsolutePath()));
  }

  public synchronized void stop() {
    Disposer.dispose(myChangedDocumentsQueue);
    getDocumentEventMulticaster().removeDocumentListener(myDocumentListener);
    myGeneralSettings.removeListener(mySettingsPathsChangesListener);
    mySettingsFilesPointers.clear();
    myBusConnection.disconnect();
  }

  private EditorEventMulticaster getDocumentEventMulticaster() {
    return EditorFactory.getInstance().getEventMulticaster();
  }

  public synchronized void addManagedFilesWithProfiles(List<VirtualFile> files, List<String> profiles) {
    myProjectsTree.addManagedFilesWithProfiles(files, profiles);
    scheduleUpdateAll();
  }

  public synchronized void resetManagedFilesAndProfilesInTests(List<VirtualFile> files, List<String> profiles) {
    myProjectsTree.resetManagedFilesAndProfiles(files, profiles);
    scheduleUpdateAll();
  }

  public synchronized void removeManagedFiles(List<VirtualFile> files) {
    myProjectsTree.removeManagedFiles(files);
    scheduleUpdateAll();
  }

  public synchronized void setActiveProfiles(List<String> profiles) {
    myProjectsTree.setActiveProfiles(profiles);
    scheduleUpdateAll();
  }

  private void scheduleUpdateAll() {
    myReadingProcessor.scheduleTask(new MavenProjectsProcessorReadingTask(false, myProjectsTree, myGeneralSettings));
  }

  private void scheduleUpdate(List<VirtualFile> filesToUpdate, List<VirtualFile> filesToDelete) {
    myReadingProcessor.scheduleTask(new MavenProjectsProcessorReadingTask(filesToUpdate,
                                                                          filesToDelete,
                                                                          false,
                                                                          myProjectsTree,
                                                                          myGeneralSettings));
  }

  private void onSettingsChange() {
    myEmbeddersManager.reset();
    scheduleUpdateAll();
  }

  private class MyRootChangesListener implements ModuleRootListener {
    public void beforeRootsChange(ModuleRootEvent event) {
    }

    public void rootsChanged(ModuleRootEvent event) {<commit_msg>Maven: correctly reimporting projects on paths changes<commit_after>package org.jetbrains.idea.maven.project;

import com.intellij.ProjectTopics;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.EditorEventMulticaster;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.*;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.util.PathUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.update.Update;
import gnu.trove.THashSet;
import org.jetbrains.idea.maven.embedder.MavenEmbedderFactory;
import org.jetbrains.idea.maven.utils.MavenConstants;
import org.jetbrains.idea.maven.utils.MavenMergingUpdateQueue;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class MavenProjectsManagerWatcher {
  private static final int DOCUMENT_SAVE_DELAY = 1000;

  private final Project myProject;
  private final MavenProjectsTree myProjectsTree;
  private final MavenGeneralSettings myGeneralSettings;
  private final MavenProjectsProcessor myReadingProcessor;
  private final MavenEmbeddersManager myEmbeddersManager;

  private final MessageBusConnection myBusConnection;

  private DocumentAdapter myDocumentListener;
  private MavenGeneralSettings.Listener mySettingsPathsChangesListener;
  private List<VirtualFilePointer> mySettingsFilesPointers = new ArrayList<VirtualFilePointer>();
  private List<LocalFileSystem.WatchRequest> myWatchedRoots = new ArrayList<LocalFileSystem.WatchRequest>();

  private final Set<Document> myChangedDocuments = new THashSet<Document>();
  private final MavenMergingUpdateQueue myChangedDocumentsQueue = new MavenMergingUpdateQueue(getClass() + ": Document changes queue",
                                                                                              DOCUMENT_SAVE_DELAY,
                                                                                              false);

  public MavenProjectsManagerWatcher(Project project,
                                     MavenProjectsTree projectsTree,
                                     MavenGeneralSettings generalSettings,
                                     MavenProjectsProcessor readingProcessor,
                                     MavenEmbeddersManager embeddersManager) {
    myProject = project;
    myProjectsTree = projectsTree;
    myGeneralSettings = generalSettings;
    myReadingProcessor = readingProcessor;
    myEmbeddersManager = embeddersManager;

    myBusConnection = myProject.getMessageBus().connect();
  }

  public synchronized void start() {
    myBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, new MyFileChangeListener());
    myBusConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyRootChangesListener());

    myChangedDocumentsQueue.makeUserAware(myProject);
    myChangedDocumentsQueue.activate();

    myDocumentListener = new DocumentAdapter() {
      public void documentChanged(DocumentEvent event) {
        Document doc = event.getDocument();
        VirtualFile file = FileDocumentManager.getInstance().getFile(doc);

        if (file == null) return;
        boolean isMavenFile = file.getName().equals(MavenConstants.POM_XML)
                              || file.getName().equals(MavenConstants.PROFILES_XML)
                              || isSettingsFile(file);
        if (!isMavenFile) return;

        synchronized (myChangedDocuments) {
          myChangedDocuments.add(doc);
        }
        myChangedDocumentsQueue.queue(new Update(MavenProjectsManagerWatcher.this) {
          public void run() {
            Set<Document> copy;

            synchronized (myChangedDocuments) {
              copy = new THashSet<Document>(myChangedDocuments);
              myChangedDocuments.clear();
            }

            for (Document each : copy) {
              FileDocumentManager.getInstance().saveDocument(each);
            }
          }
        });
      }
    };
    getDocumentEventMulticaster().addDocumentListener(myDocumentListener);

    mySettingsPathsChangesListener = new MavenGeneralSettings.Listener() {
      public void pathChanged() {
        updateSettingsFilePointers();
        onSettingsChange();
      }
    };
    myGeneralSettings.addListener(mySettingsPathsChangesListener);
    updateSettingsFilePointers();
  }

  private void updateSettingsFilePointers() {
    LocalFileSystem.getInstance().removeWatchedRoots(myWatchedRoots);
    mySettingsFilesPointers.clear();
    addFilePointer(MavenEmbedderFactory.resolveGlobalSettingsFile(myGeneralSettings.getMavenHome()));
    addFilePointer(MavenEmbedderFactory.resolveUserSettingsFile(myGeneralSettings.getMavenSettingsFile()));
  }

  private void addFilePointer(File settingsFile) {
    if (settingsFile == null) return;

    myWatchedRoots.add(LocalFileSystem.getInstance().addRootToWatch(getNormalizedPath(settingsFile.getParentFile()), false));

    String url = VfsUtil.pathToUrl(getNormalizedPath(settingsFile));
    mySettingsFilesPointers.add(VirtualFilePointerManager.getInstance().create(url, myProject, new VirtualFilePointerListener() {
      public void beforeValidityChanged(VirtualFilePointer[] pointers) {
      }

      public void validityChanged(VirtualFilePointer[] pointers) {
      }
    }));
  }

  private String getNormalizedPath(File settingsFile) {
    return FileUtil.toSystemIndependentName(PathUtil.getCanonicalPath(settingsFile.getAbsolutePath()));
  }

  public synchronized void stop() {
    Disposer.dispose(myChangedDocumentsQueue);
    getDocumentEventMulticaster().removeDocumentListener(myDocumentListener);
    myGeneralSettings.removeListener(mySettingsPathsChangesListener);
    mySettingsFilesPointers.clear();
    myBusConnection.disconnect();
  }

  private EditorEventMulticaster getDocumentEventMulticaster() {
    return EditorFactory.getInstance().getEventMulticaster();
  }

  public synchronized void addManagedFilesWithProfiles(List<VirtualFile> files, List<String> profiles) {
    myProjectsTree.addManagedFilesWithProfiles(files, profiles);
    scheduleUpdateAll();
  }

  public synchronized void resetManagedFilesAndProfilesInTests(List<VirtualFile> files, List<String> profiles) {
    myProjectsTree.resetManagedFilesAndProfiles(files, profiles);
    scheduleUpdateAll();
  }

  public synchronized void removeManagedFiles(List<VirtualFile> files) {
    myProjectsTree.removeManagedFiles(files);
    scheduleUpdateAll();
  }

  public synchronized void setActiveProfiles(List<String> profiles) {
    myProjectsTree.setActiveProfiles(profiles);
    scheduleUpdateAll();
  }

  private void scheduleUpdateAll() {
    scheduleUpdateAll(false);
  }

  private void scheduleUpdateAll(boolean force) {
    myReadingProcessor.scheduleTask(new MavenProjectsProcessorReadingTask(force, myProjectsTree, myGeneralSettings));
  }

  private void scheduleUpdate(List<VirtualFile> filesToUpdate, List<VirtualFile> filesToDelete) {
    myReadingProcessor.scheduleTask(new MavenProjectsProcessorReadingTask(filesToUpdate,
                                                                          filesToDelete,
                                                                          false,
                                                                          myProjectsTree,
                                                                          myGeneralSettings));
  }

  private void onSettingsChange() {
    myEmbeddersManager.reset();
    scheduleUpdateAll(true);
  }

  private class MyRootChangesListener implements ModuleRootListener {
    public void beforeRootsChange(ModuleRootEvent event) {
    }

    public void rootsChanged(ModuleRootEvent event) {
{'fraction_non_alphanumeric': 0.07859334434741562, 'fraction_numerical': 0.0004720320981826764, 'mean_word_length': 3.4520619910690833, 'pattern_counts': {'":': 2, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 52, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1094430', 'n_tokens_mistral': 4425, 'n_tokens_neox': 4269, 'n_words': 705}