<commit_before>package intellij.haskell.external.component

import java.io.{File, FileInputStream, FileNotFoundException}
import java.net.URL

import com.intellij.openapi.project.Project
import com.intellij.util.io.URLUtil
import intellij.haskell.HaskellNotificationGroup
import intellij.haskell.util.HaskellFileUtil
import org.yaml.snakeyaml.Yaml

import scala.collection.Iterator
import scala.io.Source

object CabalConfigComponent {
  private final val PackageNamePattern = """.* (.*) [==|installed].*""".r
  private final val CabalConfigFileLtsResolverPattern = """.*/(lts-\d+\.\d+)""".r
  private final val CabalConfigFileNightlyResolverPattern = """.*/(nightly-\d{4}-\d{2}-\d{2})""".r

  def getConfigFilePath(project: Project): String = {
    project.getBasePath + File.separator + "cabal.config"
  }

  def getYamlFilePath(project: Project): String = {
    project.getBasePath + File.separator + "stack.yaml"
  }

  def getAllAvailablePackageNames(project: Project): Option[Iterable[String]] = {
    val configFilePath = getConfigFilePath(project)
    val configFile = new File(configFilePath)

    getResolverFromStackYamlFile(project).flatMap(resolver => {
      if (resolver.startsWith("lts") || resolver.startsWith("nightly")) {
        if (!configFile.exists()) {
          downloadAndParseCabalConfigFile(project)
        } else {
          val needUpdate = for {
            oldResolver <- getResolverFromCabalConfigFile(project)
            newResolver <- getResolverFromStackYamlFile(project)
          } yield oldResolver != newResolver

          needUpdate.flatMap(b => {
            if (b) {
              removeCabalConfig(project)
              downloadAndParseCabalConfigFile(project)
            } else {
              parseCabalConfigFile(project)
            }
          }).orElse(parseDefaultCabalConfigFile(project))
        }
      } else {
        parseDefaultCabalConfigFile(project)
      }
    })
  }

  private def downloadAndParseCabalConfigFile(project: Project): Option[Iterable[String]] = {
    downloadCabalConfig(project)
    parseCabalConfigFile(project)
  }

  private def parseCabalConfigFileBase(project: Project, lines: Iterator[String]): Option[Iterable[String]] = {
    try {
      Some(lines.filter(!_.startsWith("--")).map {
        case PackageNamePattern(packageName) => packageName
        case _ => ""
      }.filter(!_.isEmpty).toList)
    } catch {
      case _: FileNotFoundException =>
        HaskellNotificationGroup.logErrorEvent(project, s"Can not find `cabal.config` file.")
        None
    }
  }

  private def parseDefaultCabalConfigFile(project: Project): Option[Iterable[String]] = {
    parseCabalConfigFileBase(project, Source.fromURL(getClass.getResource("/cabal/cabal.config")).getLines())
  }

  private def parseCabalConfigFile(project: Project): Option[Iterable[String]] = {
    parseCabalConfigFileBase(project, Source.fromFile(getConfigFilePath(project)).getLines())
  }

  def downloadCabalConfig(project: Project): Unit = {
    getResolverFromStackYamlFile(project).foreach(resolver => {
      val url = new URL(s"https://www.stackage.org/$resolver/cabal.config")
      val configFilePath = getConfigFilePath(project)
      val targetFile = new File(configFilePath)

      try {
        val in = URLUtil.openStream(url)
        HaskellFileUtil.copyStreamToFile(in, targetFile)
      } catch {
        case _: Exception =>
          HaskellNotificationGroup.logErrorBalloonEvent(project, s"Can not download cabal config file for stack resolver <b>$resolver</b>, please check your network environment.")
      }
    })<commit_msg>Remove redundant option type signature<commit_after>package intellij.haskell.external.component

import java.io.{File, FileInputStream, FileNotFoundException}
import java.net.URL

import com.intellij.openapi.project.Project
import com.intellij.util.io.URLUtil
import intellij.haskell.HaskellNotificationGroup
import intellij.haskell.util.HaskellFileUtil
import org.yaml.snakeyaml.Yaml

import scala.collection.Iterator
import scala.io.Source

object CabalConfigComponent {
  private final val PackageNamePattern = """.* (.*) [==|installed].*""".r
  private final val CabalConfigFileLtsResolverPattern = """.*/(lts-\d+\.\d+)""".r
  private final val CabalConfigFileNightlyResolverPattern = """.*/(nightly-\d{4}-\d{2}-\d{2})""".r

  def getConfigFilePath(project: Project): String = {
    project.getBasePath + File.separator + "cabal.config"
  }

  def getYamlFilePath(project: Project): String = {
    project.getBasePath + File.separator + "stack.yaml"
  }

  def getAllAvailablePackageNames(project: Project): Option[Iterable[String]] = {
    val configFilePath = getConfigFilePath(project)
    val configFile = new File(configFilePath)

    getResolverFromStackYamlFile(project).map(resolver => {
      if (resolver.startsWith("lts") || resolver.startsWith("nightly")) {
        if (!configFile.exists()) {
          downloadAndParseCabalConfigFile(project)
        } else {
          val needUpdate = for {
            oldResolver <- getResolverFromCabalConfigFile(project)
            newResolver <- getResolverFromStackYamlFile(project)
          } yield oldResolver != newResolver

          needUpdate match {
            case Some(b) =>
              if (b) {
                removeCabalConfig(project)
                downloadAndParseCabalConfigFile(project)
              } else {
                parseCabalConfigFile(project)
              }
            case None => parseDefaultCabalConfigFile(project)
          }
        }
      } else {
        parseDefaultCabalConfigFile(project)
      }
    })
  }

  private def downloadAndParseCabalConfigFile(project: Project): Iterable[String] = {
    downloadCabalConfig(project)
    parseCabalConfigFile(project)
  }

  private def parseCabalConfigFileBase(project: Project, lines: Iterator[String]): Iterable[String] = {
    lines.filter(!_.startsWith("--")).map {
      case PackageNamePattern(packageName) => packageName
      case _ => ""
    }.filterNot(_.isEmpty).toList
  }

  private def parseDefaultCabalConfigFile(project: Project): Iterable[String] = {
    parseCabalConfigFileBase(project, Source.fromURL(getClass.getResource("/cabal/cabal.config")).getLines())
  }

  private def parseCabalConfigFile(project: Project): Iterable[String] = {
    parseCabalConfigFileBase(project, Source.fromFile(getConfigFilePath(project)).getLines())
  }

  def downloadCabalConfig(project: Project): Unit = {
    getResolverFromStackYamlFile(project).foreach(resolver => {
      val url = new URL(s"https://www.stackage.org/$resolver/cabal.config")
      val configFilePath = getConfigFilePath(project)
      val targetFile = new File(configFilePath)

      try {
        val in = URLUtil.openStream(url)
        HaskellFileUtil.copyStreamToFile(in, targetFile)
      } catch {
        case _: Exception =>
          HaskellNotificationGroup.logErrorBalloonEvent(project, s"Can not download cabal config file for stack resolver <b>$resolver</b>, please check your network environment.")
      }
    })
{'fraction_non_alphanumeric': 0.11325028312570781, 'fraction_numerical': 0.0008493771234428086, 'mean_word_length': 3.5346598202824135, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1222134', 'n_tokens_mistral': 2105, 'n_tokens_neox': 2049, 'n_words': 354}