<commit_before>// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.vcs.changes.ignore

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.*
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vcs.AbstractVcs
import com.intellij.openapi.vcs.FilesProcessorWithNotificationImpl
import com.intellij.openapi.vcs.VcsApplicationSettings
import com.intellij.openapi.vcs.VcsBundle
import com.intellij.openapi.vcs.changes.*
import com.intellij.openapi.vcs.changes.ignore.IgnoreConfigurationProperty.ASKED_MANAGE_IGNORE_FILES_PROPERTY
import com.intellij.openapi.vcs.changes.ignore.IgnoreConfigurationProperty.MANAGE_IGNORE_FILES_PROPERTY
import com.intellij.openapi.vcs.changes.ignore.psi.util.addNewElementsToIgnoreBlock
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.events.*
import com.intellij.project.getProjectStoreDirectory
import com.intellij.project.stateStore
import com.intellij.vcsUtil.VcsImplUtil.findIgnoredFileContentProvider
import com.intellij.vcsUtil.VcsUtil
import com.intellij.vfs.AsyncVfsEventsListener
import com.intellij.vfs.AsyncVfsEventsPostProcessor
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write

private val LOG = logger<IgnoreFilesProcessorImpl>()

class IgnoreFilesProcessorImpl(project: Project, private val vcs: AbstractVcs<*>, private val parentDisposable: Disposable)
  : FilesProcessorWithNotificationImpl(project, parentDisposable), AsyncVfsEventsListener, ChangeListListener {

  private val UNPROCESSED_FILES_LOCK = ReentrantReadWriteLock()

  private val unprocessedFiles = mutableSetOf<VirtualFile>()

  private val changeListManager = ChangeListManagerImpl.getInstanceImpl(project)
  private val vcsIgnoreManager = VcsIgnoreManager.getInstance(project)

  fun install() {
    runReadAction {
      if (!project.isDisposed) {
        changeListManager.addChangeListListener(this, parentDisposable)
        AsyncVfsEventsPostProcessor.getInstance().addListener(this, parentDisposable)
      }
    }
  }

  override fun changeListUpdateDone() {
    if (!needProcessIgnoredFiles() || ApplicationManager.getApplication().isUnitTestMode) return

    val files = UNPROCESSED_FILES_LOCK.read { unprocessedFiles.toList() }
    if (files.isEmpty()) return

    val restFiles = silentlyIgnoreFilesInsideConfigDir(files)
    if (restFiles.isEmpty()) return

    processFiles(restFiles)

    UNPROCESSED_FILES_LOCK.write {
      unprocessedFiles.clear()
    }
  }

  private fun silentlyIgnoreFilesInsideConfigDir(files: List<VirtualFile>): List<VirtualFile> {
    val configDir = project.stateStore.projectConfigDir ?: return files
    val configDirFile = LocalFileSystem.getInstance().findFileByPath(configDir) ?: return files
    val filesInStoreDir = files.filter { VfsUtil.isAncestor(configDirFile, it, true) }

    runInEdt {
      writeIgnores(project, filesInStoreDir)
    }

    return files - filesInStoreDir
  }

  override fun filesChanged(events: List<VFileEvent>) {
    if (!needProcessIgnoredFiles() || ApplicationManager.getApplication().isUnitTestMode) return

    val potentiallyIgnoredFiles =
      events.asSequence()
        .mapNotNull(::getAffectedFile)
        .filter(vcsIgnoreManager::isPotentiallyIgnoredFile)
        .toList()

    if (potentiallyIgnoredFiles.isEmpty()) return
    LOG.debug("Got potentially ignored files from VFS events", potentiallyIgnoredFiles)

    UNPROCESSED_FILES_LOCK.write {
      unprocessedFiles.addAll(potentiallyIgnoredFiles)
    }
  }<commit_msg>vcs-ignore: filter ignored files in config (.idea) dir by current unversioned files<commit_after>// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.vcs.changes.ignore

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.*
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vcs.AbstractVcs
import com.intellij.openapi.vcs.FilesProcessorWithNotificationImpl
import com.intellij.openapi.vcs.VcsApplicationSettings
import com.intellij.openapi.vcs.VcsBundle
import com.intellij.openapi.vcs.changes.*
import com.intellij.openapi.vcs.changes.ignore.IgnoreConfigurationProperty.ASKED_MANAGE_IGNORE_FILES_PROPERTY
import com.intellij.openapi.vcs.changes.ignore.IgnoreConfigurationProperty.MANAGE_IGNORE_FILES_PROPERTY
import com.intellij.openapi.vcs.changes.ignore.psi.util.addNewElementsToIgnoreBlock
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.events.*
import com.intellij.project.getProjectStoreDirectory
import com.intellij.project.stateStore
import com.intellij.vcsUtil.VcsImplUtil.findIgnoredFileContentProvider
import com.intellij.vcsUtil.VcsUtil
import com.intellij.vfs.AsyncVfsEventsListener
import com.intellij.vfs.AsyncVfsEventsPostProcessor
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write

private val LOG = logger<IgnoreFilesProcessorImpl>()

class IgnoreFilesProcessorImpl(project: Project, private val vcs: AbstractVcs<*>, private val parentDisposable: Disposable)
  : FilesProcessorWithNotificationImpl(project, parentDisposable), AsyncVfsEventsListener, ChangeListListener {

  private val UNPROCESSED_FILES_LOCK = ReentrantReadWriteLock()

  private val unprocessedFiles = mutableSetOf<VirtualFile>()

  private val changeListManager = ChangeListManagerImpl.getInstanceImpl(project)
  private val vcsIgnoreManager = VcsIgnoreManager.getInstance(project)

  fun install() {
    runReadAction {
      if (!project.isDisposed) {
        changeListManager.addChangeListListener(this, parentDisposable)
        AsyncVfsEventsPostProcessor.getInstance().addListener(this, parentDisposable)
      }
    }
  }

  override fun changeListUpdateDone() {
    if (!needProcessIgnoredFiles() || ApplicationManager.getApplication().isUnitTestMode) return

    val files = UNPROCESSED_FILES_LOCK.read { unprocessedFiles.toList() }
    if (files.isEmpty()) return

    val restFiles = silentlyIgnoreFilesInsideConfigDir(files)
    if (restFiles.isEmpty()) return

    processFiles(restFiles)

    UNPROCESSED_FILES_LOCK.write {
      unprocessedFiles.clear()
    }
  }

  private fun silentlyIgnoreFilesInsideConfigDir(files: List<VirtualFile>): List<VirtualFile> {
    val configDir = project.stateStore.projectConfigDir ?: return files
    val configDirFile = LocalFileSystem.getInstance().findFileByPath(configDir) ?: return files
    val filesInConfigDir = files.filter { VfsUtil.isAncestor(configDirFile, it, true) }
    val unversionedFilesInConfigDir = doFilterFiles(filesInConfigDir)

    runInEdt {
      writeIgnores(project, unversionedFilesInConfigDir)
    }

    return files - filesInConfigDir
  }

  override fun filesChanged(events: List<VFileEvent>) {
    if (!needProcessIgnoredFiles() || ApplicationManager.getApplication().isUnitTestMode) return

    val potentiallyIgnoredFiles =
      events.asSequence()
        .mapNotNull(::getAffectedFile)
        .filter(vcsIgnoreManager::isPotentiallyIgnoredFile)
        .toList()

    if (potentiallyIgnoredFiles.isEmpty()) return
    LOG.debug("Got potentially ignored files from VFS events", potentiallyIgnoredFiles)

    UNPROCESSED_FILES_LOCK.write {
      unprocessedFiles.addAll(potentiallyIgnoredFiles)
    }
  }
{'fraction_non_alphanumeric': 0.0824381713714714, 'fraction_numerical': 0.002498126405196103, 'mean_word_length': 5.488654781199352, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2020374', 'n_tokens_mistral': 2466, 'n_tokens_neox': 2371, 'n_words': 418}