Usage Guide

There’s a default instance defined for any F[_] with a Sync instance named SyncConsole[F]. You can either use this one or define your own by extending Console[F].

DSL style with IO

import cats.effect.IO
import cats.effect.Console.io._

val program: IO[Unit] =
  for {
    _ <- putStrLn("Please enter your name: ")
    n <- readLn
    _ <- if (n.nonEmpty) putStrLn(s"Hello $n!")
         else putError("Name is empty!")
  } yield ()

Tagless final encoding:

import cats.Monad
import cats.data.StateT
import cats.effect.{ Console, IO }
import cats.implicits._

def myProgram[F[_]: Console: Monad]: F[Unit] =
  for {
    _ <- Console[F].putStrLn("Please enter your name: ")
    n <- Console[F].readLn
    _ <- if (n.nonEmpty) Console[F].putStrLn(s"Hello $n!")
         else Console[F].putError("Name is empty!")
  } yield ()

// Providing a default instance for Console[IO]
import cats.effect.Console.implicits._

def entryPoint: IO[Unit] = myProgram[IO]

// You can also use Monad Transformers
def mt: IO[Unit] =
  myProgram[StateT[IO, String, *]].run("foo").void

TestConsole

For testing, we provide a helper that makes it easier to test console output: cats.effect.test.TestConsole.

import cats.data.Chain
import cats.effect.IO
import cats.effect.concurrent.Ref
import cats.effect.test.TestConsole

val test = for {
  out1 <- Ref[IO].of(Chain.empty[String])
  out2 <- Ref[IO].of(Chain.empty[String])
  out3 <- Ref[IO].of(Chain.empty[String])
  in1 <- TestConsole.inputs
          .sequenceAndDefault[IO](Chain("foo", "bar"), "baz")

  console = TestConsole.make(out1, out2, out3, in1)

  input <- console.readLn
  _     <- console.putStrLn(input)
  _     <- console.putStr("boom")
  _     <- console.putError("err")
  rs1 <- out1.get
  rs2 <- out2.get
  rs3 <- out3.get
} yield {
  assert(rs1 == Chain.one("foo"))
  assert(rs2 == Chain.one("boom"))
  assert(rs3 == Chain.one("err"))
}