<commit_before>package org.scalafmt.cli

import java.io.{IOException, InputStream, OutputStream, PrintStream}
import java.nio.charset.UnsupportedCharsetException
import java.nio.file.{Files, Path}

import com.typesafe.config.{ConfigException, ConfigFactory}
import metaconfig.Configured
import org.scalafmt.config.ScalafmtConfig
import org.scalafmt.config.Config
import org.scalafmt.util.{AbsoluteFile, FileOps, GitOps, GitOpsImpl, OsSpecific}

import scala.io.Codec
import scala.util.control.NonFatal
import scala.util.matching.Regex
import scala.util.control.Exception.catching

object CliOptions {
  val default = CliOptions()

  /**
    * Tries to read configuration from
    *
    * 1. .scalafmt.conf in root dir of current git repo
    *     IF the following setting is enabled: project.git = true
    * 2. .scalafmt.conf from init.commong.workingDirectory
    *
    * I am happy to add alternative fallback methods for other VCS.
    *
    * WARNING. Throws an exception if the .scalafmt.conf error exists but
    * contains an error. Why? Because this method is only supposed to be
    * called directly from main.
    */
  def auto(args: Array[String], init: CliOptions)(
      parsed: CliOptions
  ): CliOptions = {
    val style: Option[Path] = if (init.config != parsed.config) {
      parsed.config
    } else {
      tryCurrentDirectory(parsed).orElse(tryGit(parsed))
    }

    val newMode = if (parsed.testing) Stdout else parsed.writeMode

    val auxOut =
      if (parsed.noStdErr || (!parsed.stdIn && parsed.writeMode != Stdout))
        parsed.common.out
      else parsed.common.err

    parsed.copy(
      writeMode = newMode,
      config = style,
      common = parsed.common.copy(
        info = auxOut,
        debug = if (parsed.debug) auxOut else init.common.debug
      )
    )
  }

  private def getConfigJFile(file: AbsoluteFile): AbsoluteFile =
    file / ".scalafmt.conf"

  private def tryDirectory(options: CliOptions)(dir: AbsoluteFile): Path =
    getConfigJFile(dir).jfile.toPath

  private def tryGit(options: CliOptions): Option[Path] = {
    for {
      rootDir <- options.gitOps.rootDir
      path = tryDirectory(options)(rootDir)
      configFilePath <- if (path.toFile.isFile) Some(path) else None
    } yield configFilePath
  }

  private def tryCurrentDirectory(options: CliOptions): Option[Path] = {
    val configFilePath = tryDirectory(options)(options.common.workingDirectory)
    if (configFilePath.toFile.isFile) Some(configFilePath) else None
  }
}

object NoopOutputStream extends OutputStream { self =>
  override def write(b: Int): Unit = ()

  override def write(b : Array[Byte]) : Unit = ()

  override def write(b : Array[Byte], off : Int, len : Int) : Unit = ()

  val printStream = new PrintStream(self)
}

case class CommonOptions(
    workingDirectory: AbsoluteFile = AbsoluteFile.userDir,
    out: PrintStream = System.out,
    in: InputStream = System.in,
    err: PrintStream = System.err,
    debug: PrintStream = NoopOutputStream.printStream,<commit_msg>Fixes formatting<commit_after>package org.scalafmt.cli

import java.io.{IOException, InputStream, OutputStream, PrintStream}
import java.nio.charset.UnsupportedCharsetException
import java.nio.file.{Files, Path}

import com.typesafe.config.{ConfigException, ConfigFactory}
import metaconfig.Configured
import org.scalafmt.config.ScalafmtConfig
import org.scalafmt.config.Config
import org.scalafmt.util.{AbsoluteFile, FileOps, GitOps, GitOpsImpl, OsSpecific}

import scala.io.Codec
import scala.util.control.NonFatal
import scala.util.matching.Regex
import scala.util.control.Exception.catching

object CliOptions {
  val default = CliOptions()

  /**
    * Tries to read configuration from
    *
    * 1. .scalafmt.conf in root dir of current git repo
    *     IF the following setting is enabled: project.git = true
    * 2. .scalafmt.conf from init.commong.workingDirectory
    *
    * I am happy to add alternative fallback methods for other VCS.
    *
    * WARNING. Throws an exception if the .scalafmt.conf error exists but
    * contains an error. Why? Because this method is only supposed to be
    * called directly from main.
    */
  def auto(args: Array[String], init: CliOptions)(
      parsed: CliOptions
  ): CliOptions = {
    val style: Option[Path] = if (init.config != parsed.config) {
      parsed.config
    } else {
      tryCurrentDirectory(parsed).orElse(tryGit(parsed))
    }

    val newMode = if (parsed.testing) Stdout else parsed.writeMode

    val auxOut =
      if (parsed.noStdErr || (!parsed.stdIn && parsed.writeMode != Stdout))
        parsed.common.out
      else parsed.common.err

    parsed.copy(
      writeMode = newMode,
      config = style,
      common = parsed.common.copy(
        info = auxOut,
        debug = if (parsed.debug) auxOut else init.common.debug
      )
    )
  }

  private def getConfigJFile(file: AbsoluteFile): AbsoluteFile =
    file / ".scalafmt.conf"

  private def tryDirectory(options: CliOptions)(dir: AbsoluteFile): Path =
    getConfigJFile(dir).jfile.toPath

  private def tryGit(options: CliOptions): Option[Path] = {
    for {
      rootDir <- options.gitOps.rootDir
      path = tryDirectory(options)(rootDir)
      configFilePath <- if (path.toFile.isFile) Some(path) else None
    } yield configFilePath
  }

  private def tryCurrentDirectory(options: CliOptions): Option[Path] = {
    val configFilePath = tryDirectory(options)(options.common.workingDirectory)
    if (configFilePath.toFile.isFile) Some(configFilePath) else None
  }
}

object NoopOutputStream extends OutputStream { self =>
  override def write(b: Int): Unit = ()

  override def write(b: Array[Byte]): Unit = ()

  override def write(b: Array[Byte], off: Int, len: Int): Unit = ()

  val printStream = new PrintStream(self)
}

case class CommonOptions(
    workingDirectory: AbsoluteFile = AbsoluteFile.userDir,
    out: PrintStream = System.out,
    in: InputStream = System.in,
    err: PrintStream = System.err,
    debug: PrintStream = NoopOutputStream.printStream,
{'fraction_non_alphanumeric': 0.10028131722654311, 'fraction_numerical': 0.0006619228859837829, 'mean_word_length': 3.4903417533432393, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '4738963', 'n_tokens_mistral': 1855, 'n_tokens_neox': 1804, 'n_words': 486}