diff --git a/lib/Rainbow.hs b/lib/Rainbow.hs
--- a/lib/Rainbow.hs
+++ b/lib/Rainbow.hs
@@ -1,7 +1,4 @@
--- | Handles colors and special effects for text. Internally this
--- module uses the Haskell terminfo library, which links against the
--- UNIX library of the same name, so it should work with a wide
--- variety of UNIX terminals.
+-- | Rainbow handles colors and special effects for text.
 --
 -- The building block of Rainbow is the 'Chunk'. Each 'Chunk' comes with
 -- a 'TextSpec', which specifies how the text should look on 8-color
@@ -14,19 +11,20 @@
 -- for 8 and 256 color terminals; for instance, you can have text
 -- appear red on an 8-color terminal but blue on a 256-color terminal.
 --
--- A 'Chunk' is a 'Data.Monoid.Monoid', so you can combine them using
--- the usual monoid functions, including 'Data.Monoid.<>'. You can
+-- A 'Chunk' is a 'Monoid', so you can combine them using
+-- the usual monoid functions, including '<>'. You can
 -- create a 'Chunk' with text using 'Data.String.fromString', but this
 -- library is much more usable if you enable the OverloadedStrings GHC
 -- extension:
 --
 -- > {-# LANGUAGE OverloadedStrings #-}
 --
--- and all future examples assume you have enabled OverloadedStrings.
--- You will also want the Monoid module in scope:
+-- or, in GHCi:
 --
--- > import Data.Monoid
+-- >>> :set -XOverloadedStrings
 --
+-- and all future examples assume you have enabled OverloadedStrings.
+--
 -- Here are some basic examples:
 --
 -- @
@@ -40,7 +38,7 @@
 -- But what makes Rainbow a little more interesting is that you can
 -- also specify output for 256-color terminals. To use these examples,
 -- be sure your TERM environment variable is set to something that
--- supports 256 colors (like @xterm-256color@) before you start GHCi:
+-- supports 256 colors (like @xterm-256color@) before you start GHCi.
 --
 -- @
 -- 'putChunkLn' $ \"Blue on 8-color terminal, red on 256-color terminal\"
@@ -53,12 +51,11 @@
 -- as it can't be inferred:
 --
 -- @
--- import Data.Word ('Data.Word.Word8')
 -- 'putChunkLn' $ \"Pink on 256-color terminal only\"
---                \<> 'fore' (201 :: 'Data.Word.Word8')
+--                \<> 'fore' (201 :: 'Word8')
 -- @
 --
--- If 'mappend' multiple chunks that change the same property, the
+-- If you 'mappend' multiple chunks that change the same property, the
 -- rightmost one \"wins\":
 --
 -- @
@@ -71,7 +68,7 @@
 --
 -- @
 -- 'putChunkLn' $ \"Red on 8-color, pink on 256-color\"
---                \<> 'fore' 'red' \<> 'fore' (201 :: 'Data.Word.Word8')
+--                \<> 'fore' 'red' \<> 'fore' (201 :: 'Word8')
 -- @
 --
 -- However, if you use 'mappend' to add additional 'Chunk's that have
@@ -91,37 +88,12 @@
 module Rainbow
   (
 
-  -- * Terminal definitions
-    Term(..)
-  , termFromEnv
-  , smartTermFromEnv
-
   -- * Chunks
-  , Chunk(..)
-  , fromText
-  , fromLazyText
-
-  -- * Printing chunks
-  , putChunks
-  , hPutChunks
-
-  -- ** Printing one chunk at a time
-
-  -- | These functions make it easy to print one chunk at a time. Each
-  -- function initializes the terminal once for each chunk, unlike the
-  -- list-oriented functions, which only initialize the terminal
-  -- once. (Initialization does not clear the screen; rather, it is a
-  -- process that the terminfo library requires.) Thus there might be
-  -- a performance penalty for using these functions to print large
-  -- numbers of chunks. Or, there might not be--I have not benchmarked
-  -- them.
-  --
-  -- These functions use the default terminal, obtained using
-  -- 'termFromEnv'.
-  , putChunk
-  , putChunkLn
-  , hPutChunk
-  , hPutChunkLn
+    Chunk
+  , chunkFromText
+  , chunkFromTexts
+  , chunkFromLazyText
+  , chunkFromLazyTexts
 
   -- * Effects for both 8 and 256 color terminals
 
@@ -132,9 +104,13 @@
   -- @
 
   , bold
+  , faint
+  , italic
   , underline
-  , flash
+  , blink
   , inverse
+  , invisible
+  , strikeout
 
   -- * Effects for 8-color terminals only
 
@@ -145,9 +121,13 @@
   -- @
 
   , bold8
+  , faint8
+  , italic8
   , underline8
-  , flash8
+  , blink8
   , inverse8
+  , invisible8
+  , strikeout8
 
   -- * Effects for 256-color terminals only
 
@@ -160,9 +140,13 @@
   -- @
 
   , bold256
+  , faint256
+  , italic256
   , underline256
-  , flash256
+  , blink256
   , inverse256
+  , invisible256
+  , strikeout256
 
   -- * Colors
 
@@ -209,7 +193,138 @@
   , brightWhite
   , to256
 
+  -- * Converting 'Chunk' to 'Data.ByteString.ByteString'
+
+  -- | To print a 'Chunk', you need to convert it to some
+  -- 'Data.ByteString.ByteString's.
+  --
+  -- All these functions convert the 'Data.Text' to UTF-8
+  -- 'Data.ByteString.ByteString's.  Many of these functions return a
+  -- difference list.  Learn You a Haskell for Great Good has a great
+  -- explanation of difference lists:
+  --
+  -- http://learnyouahaskell.com/for-a-few-monads-more
+  --
+  -- If you don't want to learn about difference lists, just stick
+  -- with using 'chunksToByteStrings' and use
+  -- 'byteStringMakerFromEnvironment' if you want to use the highest
+  -- number of colors possible, or, to manually specify the number of
+  -- colors, use 'chunksToByteStrings' with 'toByteStringsColors0',
+  -- 'toByteStringsColors8', or 'toByteStringsColors256' as the first
+  -- argument.  'chunksToByteStrings' has an example.
+  , byteStringMakerFromEnvironment
+  , byteStringMakerFromHandle
+  , toByteStringsColors0
+  , toByteStringsColors8
+  , toByteStringsColors256
+  , chunksToByteStrings
+
+  -- * Quick and dirty functions for IO
+
+  -- | For efficiency reasons you probably don't want to use these
+  -- when printing large numbers of 'Chunk', but they are handy for
+  -- throwaway uses like experimenting in GHCi.
+  , putChunk
+  , putChunkLn
+
+  -- * Re-exports
+  -- $reexports
+  -- | * "Data.Monoid" re-exports '<>' and 'mempty'
+  --
+  -- 
+  , module Data.Monoid
+  , module Data.ByteString
+  , module Data.Text
+  , module Data.Word
+
+  -- * Notes on terminals
+  -- $termNotes
+
   ) where
 
 import Rainbow.Types
 import Rainbow.Colors
+import Rainbow.Translate
+  ( byteStringMakerFromEnvironment
+  , byteStringMakerFromHandle
+  , toByteStringsColors0
+  , toByteStringsColors8
+  , toByteStringsColors256
+  , chunksToByteStrings
+  , putChunk
+  , putChunkLn
+  )
+import Data.Monoid (Monoid, (<>), mempty)
+import Data.Text (Text)
+import Data.ByteString (ByteString)
+import Data.Word (Word8)
+
+{- $reexports
+
+   * "Data.Monoid" re-exports 'Monoid', '<>' and 'mempty'
+
+   * "Data.ByteString" re-exports 'ByteString'
+
+   * "Data.Text" re-exports 'Text'
+
+   * "Data.Word" re-exports 'Word8'
+-}
+
+{- $termNotes
+
+Earlier versions of Rainbow used the Haskell terminfo library for
+dealing with the terminal.  Terminfo is available at
+
+<https://hackage.haskell.org/package/terminfo>
+
+Terminfo, in turn, uses the UNIX terminfo library.  The biggest
+advantage of using Terminfo is that it is compatible with a huge
+variety of terminals.  Many of these terminals are hardware models
+that are gathering dust in an IBM warehouse somewhere, but even modern
+software terminals might have quirks.  Terminfo covers all those.
+
+The disadvantage is that using Terminfo requires you to perform IO
+whenever you need to format output for the terminal.  Your only choice
+when using Terminfo is to send output directly to the terminal, or to
+a handle.  This goes against typical Haskell practice, where we try to
+write pure code whenever possible.
+
+Perhaps surprisingly, there are times where you may want to format
+output, but not immediately send it to the terminal.  Maybe you want
+to send it to a file instead, or maybe you want to use a Haskell
+library like Pipes and stream it somewhere.  Terminfo is a binding to
+a Unix library that is not designed for this sort of thing.  The
+closest you could get using Terminfo would be to make a Handle that is
+backed by a in-memory buffer.  There is a package for that sort of
+thing:
+
+<http://hackage.haskell.org/package/knob>
+
+but it seems like a nasty workaround.  Or you can hijack stdout and
+send that somewhere--again, nasty workaround.
+
+So I decided to stop using Terminfo.  That means Rainbow no longer
+supports a menagerie of bizarre terminals.  It instead just uses the
+standard ISO 6429 / ECMA 48 terminal codes.  These are the same codes
+that are used by xterm, the OS X Terminal, the Linux console, or any
+other reasonably modern software terminal.  Realistically they are the
+only terminals Rainbow would be used for.
+
+The 256 color capability is not in ISO 6429, but it is widely supported.
+
+Probably the most common so-called terminals in use today that do NOT
+support the ISO 6429 codes are those that are not really terminals.
+For instance, you might use an Emacs shell buffer.  For those
+situations just use 'toByteStringsColors0'.
+
+I also decided to standardize on UTF-8 for the 'Text' output..  These
+days that seems reasonable.
+
+Now, to figure out how many colors the terminal supports, Rainbow
+simply uses the @tput@ program.  This removes the dependency on
+Terminfo altogether.
+
+Apparently it's difficult to get ISO 6429 support on Microsoft
+Windows.  Oh well.
+
+-}
diff --git a/lib/Rainbow/Colors.hs b/lib/Rainbow/Colors.hs
--- a/lib/Rainbow/Colors.hs
+++ b/lib/Rainbow/Colors.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DeriveGeneric, DeriveDataTypeable #-}
 -- | Ordinarily you should not need this module; typically you will
 -- just import "Rainbow", which re-exports the most useful things from
 -- this module.  This module also contains data constructors that
@@ -8,6 +9,8 @@
 import Rainbow.Types
 import Data.Monoid
 import Data.Word (Word8)
+import GHC.Generics
+import Data.Typeable
 
 -- * 8 color
 
@@ -83,7 +86,7 @@
   { rad8 :: Color8
   , rad256 :: Maybe Color256
   -- ^ If 'Nothing', use the 'rad8' color on 256-color terminals.
-  } deriving (Eq, Ord, Show)
+  } deriving (Eq, Ord, Show, Generic, Typeable)
 
 -- | A Radiant with the same color for both 8- and 256-color
 -- terminals.
diff --git a/lib/Rainbow/Translate.hs b/lib/Rainbow/Translate.hs
new file mode 100644
--- /dev/null
+++ b/lib/Rainbow/Translate.hs
@@ -0,0 +1,338 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Rainbow.Translate where
+
+import Data.Monoid
+import qualified Data.ByteString.Char8 as BS8
+import qualified Data.ByteString as BS
+import Data.ByteString (ByteString)
+import Data.Word
+import Data.List (intersperse)
+import Rainbow.Types
+  ( Color8(..), Enum8(..), Color256(..),
+    StyleCommon(..), Style8(..), Style256(..), TextSpec)
+import qualified Rainbow.Types as T
+import Data.Text.Encoding
+import System.Process
+import Text.Read
+import System.Exit
+import Control.Monad
+import Control.Exception
+import qualified System.IO as IO
+
+single :: Char -> [ByteString] -> [ByteString]
+single c = ((BS8.singleton c):)
+
+escape :: [ByteString] -> [ByteString]
+escape = single '\x1B'
+
+csi :: [ByteString] -> [ByteString]
+csi = escape . single '['
+
+sgr :: ([ByteString] -> [ByteString]) -> [ByteString] -> [ByteString]
+sgr sq = csi . sq . single 'm'
+
+params :: Show a => [a] -> [ByteString] -> [ByteString]
+params cs = ((intersperse ";" . map (BS8.pack . show) $ cs) ++)
+
+sgrSingle :: Word -> [ByteString] -> [ByteString]
+sgrSingle w = sgr $ params [w]
+
+sgrDouble :: Word -> Word -> [ByteString] -> [ByteString]
+sgrDouble x y = sgr $ params [x, y]
+
+normalDefault :: [ByteString] -> [ByteString]
+normalDefault = sgrSingle 0
+
+bold :: [ByteString] -> [ByteString]
+bold = sgrSingle 1
+
+faint :: [ByteString] -> [ByteString]
+faint = sgrSingle 2
+
+italic :: [ByteString] -> [ByteString]
+italic = sgrSingle 3
+
+underline :: [ByteString] -> [ByteString]
+underline = sgrSingle 4
+
+blink :: [ByteString] -> [ByteString]
+blink = sgrSingle 5
+
+-- Yes, blink is 5, inverse is 7; 6 is skipped.  In ISO 6429 6 blinks
+-- at a different rate.
+
+inverse :: [ByteString] -> [ByteString]
+inverse = sgrSingle 7
+
+invisible :: [ByteString] -> [ByteString]
+invisible = sgrSingle 8
+
+strikeout :: [ByteString] -> [ByteString]
+strikeout = sgrSingle 9
+
+foreBlack :: [ByteString] -> [ByteString]
+foreBlack = sgrSingle 30
+
+foreRed :: [ByteString] -> [ByteString]
+foreRed = sgrSingle 31
+
+foreGreen :: [ByteString] -> [ByteString]
+foreGreen = sgrSingle 32
+
+foreYellow :: [ByteString] -> [ByteString]
+foreYellow = sgrSingle 33
+
+foreBlue :: [ByteString] -> [ByteString]
+foreBlue = sgrSingle 34
+
+foreMagenta :: [ByteString] -> [ByteString]
+foreMagenta = sgrSingle 35
+
+foreCyan :: [ByteString] -> [ByteString]
+foreCyan = sgrSingle 36
+
+foreWhite :: [ByteString] -> [ByteString]
+foreWhite = sgrSingle 37
+
+-- code 3 8 is skipped
+
+foreDefault :: [ByteString] -> [ByteString]
+foreDefault = sgrSingle 39
+
+backBlack :: [ByteString] -> [ByteString]
+backBlack = sgrSingle 40
+
+backRed :: [ByteString] -> [ByteString]
+backRed = sgrSingle 41
+
+backGreen :: [ByteString] -> [ByteString]
+backGreen = sgrSingle 42
+
+backYellow :: [ByteString] -> [ByteString]
+backYellow = sgrSingle 43
+
+backBlue :: [ByteString] -> [ByteString]
+backBlue = sgrSingle 44
+
+backMagenta :: [ByteString] -> [ByteString]
+backMagenta = sgrSingle 45
+
+backCyan :: [ByteString] -> [ByteString]
+backCyan = sgrSingle 46
+
+backWhite :: [ByteString] -> [ByteString]
+backWhite = sgrSingle 47
+
+-- code 4 8 is skipped
+
+backDefault :: [ByteString] -> [ByteString]
+backDefault = sgrSingle 49
+
+fore256 :: Word8 -> [ByteString] -> [ByteString]
+fore256 c = sgr $ params [38,5,c]
+
+back256 :: Word8 -> [ByteString] -> [ByteString]
+back256 c = sgr $ params [48,5,c]
+
+foreColor8 :: Color8 -> [ByteString] -> [ByteString]
+foreColor8 (Color8 maym8) = case maym8 of
+  Nothing -> id
+  Just m8 -> case m8 of
+    E0 -> foreBlack
+    E1 -> foreRed
+    E2 -> foreGreen
+    E3 -> foreYellow
+    E4 -> foreBlue
+    E5 -> foreMagenta
+    E6 -> foreCyan
+    E7 -> foreWhite
+
+backColor8 :: Color8 -> [ByteString] -> [ByteString]
+backColor8 (Color8 maym8) = case maym8 of
+  Nothing -> id
+  Just m8 -> case m8 of
+    E0 -> backBlack
+    E1 -> backRed
+    E2 -> backGreen
+    E3 -> backYellow
+    E4 -> backBlue
+    E5 -> backMagenta
+    E6 -> backCyan
+    E7 -> backWhite
+
+foreColor256 :: Color256 -> [ByteString] -> [ByteString]
+foreColor256 (Color256 mayW8) = case mayW8 of
+  Nothing -> id
+  Just w8 -> fore256 w8
+
+backColor256 :: Color256 -> [ByteString] -> [ByteString]
+backColor256 (Color256 mayW8) = case mayW8 of
+  Nothing -> id
+  Just w8 -> back256 w8
+
+styleCommon :: StyleCommon -> [ByteString] -> [ByteString]
+styleCommon (StyleCommon bld fnt ita und bli ivr isb stk)
+  = effect bold bld
+  . effect faint fnt
+  . effect italic ita
+  . effect underline und
+  . effect blink bli
+  . effect inverse ivr
+  . effect invisible isb
+  . effect strikeout stk
+  where
+    effect on = maybe id (\x -> if x then on else id)
+      . getLast
+
+style8 :: Style8 -> [ByteString] -> [ByteString]
+style8 (Style8 f8 b8 sc)
+  = effect foreColor8 f8
+  . effect backColor8 b8
+  . styleCommon sc
+  where
+    effect on = maybe id on . getLast
+
+style256 :: Style256 -> [ByteString] -> [ByteString]
+style256 (Style256 f256 b256 sc)
+  = effect foreColor256 f256
+  . effect backColor256 b256
+  . styleCommon sc
+  where
+    effect on = maybe id on . getLast
+
+textSpec8 :: TextSpec -> [ByteString] -> [ByteString]
+textSpec8 = style8 . T.style8
+
+textSpec256 :: TextSpec -> [ByteString] -> [ByteString]
+textSpec256 = style256 . T.style256
+
+-- | Convert a 'T.Chunk' to a list of 'ByteString'; do not show any
+-- colors.  When applied to a 'T.Chunk', this function returns a
+-- difference list.
+toByteStringsColors0 :: T.Chunk -> [ByteString] -> [ByteString]
+toByteStringsColors0 c = ((map encodeUtf8 . T.chunkTexts $ c) ++)
+
+-- | Convert a 'T.Chunk' to a list of 'ByteString'; show eight
+-- colors.  When applied to a 'T.Chunk', this function returns a
+-- difference list.
+toByteStringsColors8 :: T.Chunk -> [ByteString] -> [ByteString]
+toByteStringsColors8 c
+  = normalDefault
+  . textSpec8 (T.chunkTextSpec c)
+  . ((map encodeUtf8 . T.chunkTexts $ c) ++)
+  . normalDefault
+
+-- | Convert a 'T.Chunk' to a list of 'ByteString'; show 256
+-- colors.  When applied to a 'T.Chunk', this function returns a
+-- difference list.
+toByteStringsColors256 :: T.Chunk -> [ByteString] -> [ByteString]
+toByteStringsColors256 c
+  = normalDefault
+  . textSpec256 (T.chunkTextSpec c)
+  . ((map encodeUtf8 . T.chunkTexts $ c) ++)
+  . normalDefault
+
+
+-- | Spawns a subprocess to read the output of @tput colors@.  If this
+-- says there are at least 256 colors are available, returns
+-- 'toByteStringsColors256'.  Otherwise, if there are at least 8
+-- colors available, returns 'toByteStringsColors8'.  Otherwise,
+-- returns 'toByteStringsColors0'.
+--
+-- If any IO exceptions arise during this process, they are discarded
+-- and 'toByteStringsColors0' is returned.
+byteStringMakerFromEnvironment
+  :: IO (T.Chunk -> [ByteString] -> [ByteString])
+byteStringMakerFromEnvironment
+  = catcher (fmap f $ readProcessWithExitCode "tput" ["colors"] "")
+  where
+    f (code, stdOut, _) = maybe toByteStringsColors0 id $ do
+      case code of
+        ExitFailure _ -> mzero
+        _ -> return ()
+      numColors <- readMaybe stdOut
+      return $ numColorsToFunc numColors
+    numColorsToFunc i
+      | i >= (256 :: Int) = toByteStringsColors256
+      | i >= 8 = toByteStringsColors8
+      | otherwise = toByteStringsColors0
+
+    catcher act = fmap g (try act)
+      where
+        g (Left e) = toByteStringsColors0
+          where _types = e :: IOException
+        g (Right good) = good
+
+-- | Like 'byteStringMakerFromEnvironment' but also consults a
+-- provided 'Handle'.  If the 'Handle' is not a terminal,
+-- 'toByteStringsColors0' is returned.  Otherwise, the value of
+-- 'byteStringMakerFromEnvironment' is returned.
+byteStringMakerFromHandle
+  :: IO.Handle
+  -> IO (T.Chunk -> [ByteString] -> [ByteString])
+byteStringMakerFromHandle h = IO.hIsTerminalDevice h >>= f
+  where
+    f isTerm | isTerm = byteStringMakerFromEnvironment
+             | otherwise = return toByteStringsColors0
+          
+
+-- | Convert a list of 'T.Chunk' to a list of 'ByteString'.  The
+-- length of the returned list may be longer than the length of the
+-- input list.
+--
+-- So, for example, to print a bunch of chunks to standard output
+-- using 256 colors:
+--
+-- > {-# LANGUAGE OverloadedStrings #-}
+-- > module PrintMyChunks where
+-- >
+-- > import qualified Data.ByteString as BS
+-- > import Rainbow
+-- >
+-- > myChunks :: [Chunk]
+-- > myChunks = [ "Roses" <> fore red, "\n", "Violets" <> fore blue, "\n" ]
+-- >
+-- > myPrintedChunks :: IO ()
+-- > myPrintedChunks = mapM_ BS.putStr
+-- >                 . chunksToByteStrings toByteStringsColors256
+-- >                 $ myChunks
+--
+-- To use the highest number of colors that this terminal supports:
+--
+-- > myPrintedChunks' :: IO ()
+-- > myPrintedChunks' = do
+-- >   printer <- byteStringMakerFromEnvironment
+-- >   mapM_ BS.putStr
+-- >     . chunksToByteStrings printer
+-- >     $ myChunks
+
+chunksToByteStrings
+  :: (T.Chunk -> [ByteString] -> [ByteString])
+  -- ^ Function that converts 'T.Chunk' to 'ByteString'.  This
+  -- function, when applied to a 'T.Chunk', returns a difference list.
+  -> [T.Chunk]
+  -> [ByteString]
+chunksToByteStrings mk = ($ []) . foldr (.) id . map mk
+
+-- Quick and dirty I/O functions
+
+-- | Writes a 'Chunk' to standard output.  Spawns a child process to
+-- read the output of @tput colors@ to determine how many colors to
+-- use, for every single chunk.  Therefore, this is not going to win
+-- any speed awards.  You are better off using 'chunksToByteStrings'
+-- and the functions in "Data.ByteString" to print your 'Chunk's if
+-- you are printing a lot of them.
+putChunk :: T.Chunk -> IO ()
+putChunk ck = do
+  mkr <- byteStringMakerFromEnvironment
+  mapM_ BS.putStr . chunksToByteStrings mkr $ [ck]
+
+-- | Writes a 'Chunk' to standard output, and appends a newline.
+-- Spawns a child process to read the output of @tput colors@ to
+-- determine how many colors to use, for every single chunk.
+-- Therefore, this is not going to win any speed awards.  You are
+-- better off using 'chunksToByteStrings' and the functions in
+-- "Data.ByteString" to print your 'Chunk's if you are printing a lot
+-- of them.
+putChunkLn :: T.Chunk -> IO ()
+putChunkLn ck = putChunk ck >> putStrLn ""
diff --git a/lib/Rainbow/Types.hs b/lib/Rainbow/Types.hs
--- a/lib/Rainbow/Types.hs
+++ b/lib/Rainbow/Types.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE DeriveGeneric, DeriveDataTypeable #-}
+
 -- | The innards of Rainbow.  Ordinarily you should not need this
 -- module; instead, just import "Rainbow", which
 -- re-exports the most useful names from this module.
@@ -9,55 +11,11 @@
 import qualified Data.String as Str
 import Data.Monoid
 import Data.Text (Text)
-import Data.Maybe (fromMaybe)
 import qualified Data.Text as X
 import qualified Data.Text.Lazy as XL
-import qualified System.Console.Terminfo as T
-import System.IO as IO
-import System.Environment as Env
 import Data.Word (Word8)
-
---
--- Terminal definitions
---
-
--- | Which terminal definition to use.
-data Term
-  = Dumb
-  -- ^ Using this terminal should always succeed. This suppresses all
-  -- colors. Uesful if output is not going to a TTY, or if you just do
-  -- not like colors.
-
-  | TermName String
-  -- ^ Use the terminal with this given name. You might get this from
-  -- the TERM environment variable, or set it explicitly. A runtime
-  -- error will result if the terminfo database does not have a
-  -- definition for this terminal. If this terminal supports 256
-  -- colors, then 256 colors are used. If this terminal supports less
-  -- than 256 colors, but at least 8 colors, then 8 colors are
-  -- used. Otherwise, no colors are used.
-  deriving (Eq, Show)
-
--- | Gets the terminal definition from the environment. If the
--- environment does not have a TERM veriable, use 'Dumb'.
-termFromEnv :: IO Term
-termFromEnv = do
-  t <- fmap (lookup "TERM") Env.getEnvironment
-  return $ maybe Dumb TermName t
-
--- | Gets the terminal definition from the environment and a handle.
--- If the handle is not a terminal, 'Dumb' is returned.  Otherwise,
--- the terminal is obtained from the environment.
-smartTermFromEnv
-  :: IO.Handle
-  -- ^ Check this handle to see if it is a terminal (typically you
-  -- will use stdout).
-
-  -> IO Term
-smartTermFromEnv h = IO.hIsTerminalDevice h >>= f
-  where
-    f isTerm | isTerm = termFromEnv
-             | otherwise = return Dumb
+import GHC.Generics
+import Data.Typeable
 
 -- For Background8, Background256, Foreground8, Foreground256: the
 -- Last wraps a Maybe (Terminfo Color). If the inner Maybe is Nothing,
@@ -82,7 +40,7 @@
   | E5
   | E6
   | E7
-  deriving (Eq, Ord, Show, Bounded, Enum)
+  deriving (Eq, Ord, Show, Bounded, Enum, Generic, Typeable)
 
 enum8toWord8 :: Enum8 -> Word8
 enum8toWord8 e = case e of
@@ -102,11 +60,7 @@
   { unColor8 :: Maybe Enum8
   -- ^ Nothing indicates to use the default color for the terminal;
   -- otherwise, use the corresponding Terminfo 'T.Color'.
-  } deriving (Eq, Ord, Show)
-
-color8toTerminfo :: Color8 -> Maybe T.Color
-color8toTerminfo = fmap (T.ColorNumber . fromIntegral . enum8toWord8)
-  . unColor8
+  } deriving (Eq, Ord, Show, Generic, Typeable)
 
 -- | Color for an 256-color terminal.  Does not affect 8-color
 -- terminals.
@@ -115,11 +69,7 @@
   { unColor256 :: Maybe Word8
   -- ^ Nothing indicates to use the default color for the terminal;
   -- otherwise, use the corresponding Terminfo 'T.Color'.
-  } deriving (Eq, Ord, Show)
-
-color256toTerminfo :: Color256 -> Maybe T.Color
-color256toTerminfo = fmap (T.ColorNumber . fromIntegral)
-  . unColor256
+  } deriving (Eq, Ord, Show, Generic, Typeable)
 
 -- | Any color for an 8-color terminal can also be used in a
 -- 256-color terminal.
@@ -136,17 +86,25 @@
 -- depending on how many colors a terminal has.
 data StyleCommon = StyleCommon
   { scBold :: Last Bool
+  , scFaint :: Last Bool
+  , scItalic :: Last Bool
   , scUnderline :: Last Bool
-  , scFlash :: Last Bool
+  , scBlink :: Last Bool
   , scInverse :: Last Bool
-  } deriving (Show, Eq, Ord)
+  , scInvisible :: Last Bool
+  , scStrikeout :: Last Bool
+  } deriving (Show, Eq, Ord, Generic, Typeable)
 
 
 instance Monoid StyleCommon where
   mempty = StyleCommon (Last Nothing) (Last Nothing)
                        (Last Nothing) (Last Nothing)
-  mappend (StyleCommon b1 u1 f1 i1) (StyleCommon b2 u2 f2 i2)
-    = StyleCommon (b1 <> b2) (u1 <> u2) (f1 <> f2) (i1 <> i2)
+                       (Last Nothing) (Last Nothing)
+                       (Last Nothing) (Last Nothing)
+  mappend (StyleCommon x1 x2 x3 x4 x5 x6 x7 x8)
+          (StyleCommon y1 y2 y3 y4 y5 y6 y7 y8)
+    = StyleCommon (x1 <> y1) (x2 <> y2) (x3 <> y3) (x4 <> y4)
+                  (x5 <> y5) (x6 <> y6) (x7 <> y7) (x8 <> y8)
 
 -- | Describes text appearance (foreground and background colors, as
 -- well as other attributes such as bold) for an 8 color terminal.
@@ -154,7 +112,7 @@
   { foreground8 :: Foreground8
   , background8 :: Background8
   , common8 :: StyleCommon
-  } deriving (Show, Eq, Ord)
+  } deriving (Show, Eq, Ord, Generic, Typeable)
 
 
 instance Monoid Style8 where
@@ -168,7 +126,7 @@
   { foreground256 :: Foreground256
   , background256 :: Background256
   , common256 :: StyleCommon
-  } deriving (Show, Eq, Ord)
+  } deriving (Show, Eq, Ord, Generic, Typeable)
 
 
 instance Monoid Style256 where
@@ -185,7 +143,7 @@
 data TextSpec = TextSpec
   { style8 :: Style8
   , style256 :: Style256
-  } deriving (Show, Eq, Ord)
+  } deriving (Show, Eq, Ord, Generic, Typeable)
 
 
 instance Monoid TextSpec where
@@ -202,173 +160,118 @@
 -- underlined, etc. The chunk knows what foreground and background
 -- colors and what attributes to use for both an 8 color terminal and
 -- a 256 color terminal.
---
--- The text is held as a list of strict 'Text'.
 
 data Chunk = Chunk
-  { textSpec :: TextSpec
-  , text :: [Text]
-  } deriving (Eq, Show, Ord)
-
+  { chunkTextSpec :: TextSpec
+    -- ^ Specifies all the effects (such as bold, underlining,
+    -- colors, etc) that apply to this chunk, with different effects for
+    -- 8 and 256 color terminals; and
+    --
+  , chunkTexts :: [Text]
+    -- The text that is in this chunk.  When printing the
+    -- 'Chunk', first all colors and effects on the terminal are reset.
+    -- Then, the effects in the 'TextSpec' are applied, and then the
+    -- 'Text's are printed by encoding them to UTF-8.  Then, all the
+    -- colors and effects on the terminal are again reset.
+    --
+    -- Each text in this list is a strict 'X.Text'; though there is no
+    -- provision for lazy 'X.Text', you can get the same effect as a lazy
+    -- 'X.Text' by using a list of strict 'X.Text'.  'chunkFromLazyText'
+    -- 'Text' by using a list of strict 'and 'chunkFromLazyTexts' do
+    -- 'Text' by using a list of strict 'this for you.
+  } deriving (Eq, Show, Ord, Generic, Typeable)
+  
 
 instance Str.IsString Chunk where
   fromString s = Chunk mempty [(X.pack s)]
 
 -- | Creates a 'Chunk' from a strict 'X.Text' with default colors
 -- and no special effects.
-fromText :: Text -> Chunk
-fromText = Chunk mempty . (:[])
+chunkFromText :: X.Text -> Chunk
+chunkFromText = Chunk mempty . (:[])
 
+-- | Creates a 'Chunk' from a list of strict 'X.Text' with default
+-- colors and no special effects.
+chunkFromTexts :: [X.Text] -> Chunk
+chunkFromTexts = Chunk mempty
+
 -- | Creates a 'Chunk' from a lazy 'XL.Text' with default colors and
 -- no special effects.
-fromLazyText :: XL.Text -> Chunk
-fromLazyText = Chunk mempty . XL.toChunks
+chunkFromLazyText :: XL.Text -> Chunk
+chunkFromLazyText = Chunk mempty . XL.toChunks
 
+-- | Creates a 'Chunk' from a list of lazy 'XL.Text' with default
+-- colors and no special effects.
+chunkFromLazyTexts :: [XL.Text] -> Chunk
+chunkFromLazyTexts = Chunk mempty . concatMap XL.toChunks
+
 instance Monoid Chunk where
   mempty = Chunk mempty mempty
   mappend (Chunk s1 t1) (Chunk s2 t2) = Chunk (s1 <> s2) (t1 <> t2)
 
 
-defaultColors :: T.Terminal -> T.TermOutput
-defaultColors term =
-  fromMaybe mempty (T.getCapability term T.restoreDefaultColors)
-
-
-commonAttrs :: T.Terminal -> StyleCommon -> T.TermOutput
-commonAttrs t s =
-  let a = T.Attributes
-        { T.standoutAttr = False
-        , T.underlineAttr = fromMaybe False
-          . getLast . scUnderline $ s
-        , T.reverseAttr = fromMaybe False
-          . getLast . scInverse $ s
-        , T.blinkAttr = fromMaybe False
-          . getLast . scFlash $ s
-        , T.dimAttr = False
-        , T.boldAttr = fromMaybe False
-          . getLast . scBold $ s
-        , T.invisibleAttr = False
-        , T.protectedAttr = False
-        }
-  in case T.getCapability t (T.setAttributes) of
-      Nothing -> error $ "Rainbow: commonAttrs: "
-                 ++ "capability failed; should never happen"
-      Just f -> f a
-
-
--- | Gets the right set of terminal codes to apply the desired
--- highlighting, bold, underlining, etc. Be sure to apply the
--- attributes first (bold, underlining, etc) and then the
--- colors. Setting the colors first and then the attributes seems to
--- reset the colors, giving blank output.
-getTermCodes
-  :: T.Terminal
-  -> TextSpec
-  -> T.TermOutput
-getTermCodes t ts = fromMaybe mempty $ do
-  cols <- T.getCapability t T.termColors
-  let TextSpec s8 s256 = ts
-      Style8 f8 b8 c8 = s8
-      Style256 f256 b256 c256 = s256
-  setFg <- T.getCapability t T.setForegroundColor
-  setBg <- T.getCapability t T.setBackgroundColor
-  (fg, bg, cm) <- case () of
-    _ | cols >= 256 -> Just $ ( fmap color256toTerminfo $ getLast f256
-                              , fmap color256toTerminfo $ getLast b256
-                              , c256)
-      | cols >= 8 -> Just ( fmap color8toTerminfo $ getLast f8
-                          , fmap color8toTerminfo $ getLast b8
-                          , c8)
-      | otherwise -> Nothing
-  let oFg = maybe mempty (maybe mempty setFg) fg
-      oBg = maybe mempty (maybe mempty setBg) bg
-      oCm = commonAttrs t cm
-  return $ mconcat [oCm, oFg, oBg]
-
-
-hPrintChunk :: IO.Handle -> T.Terminal -> Chunk -> IO ()
-hPrintChunk h t (Chunk ts xs) =
-  T.hRunTermOutput h t
-  . mconcat
-  $ defaultColors t : codes : (map (T.termText . X.unpack) $ xs)
-  where
-    codes = getTermCodes t ts
-
--- | Sends a list of chunks to the given handle for printing. Sets up
--- the terminal (this only needs to be done once.) Lazily processes
--- the list of Chunk. See 'putChunks' for notes on how many colors
--- are used.
-hPutChunks :: IO.Handle -> Term -> [Chunk] -> IO ()
-hPutChunks h t cs = do
-  let setup = case t of
-        Dumb -> T.setupTerm "dumb"
-        TermName s -> T.setupTerm s
-  term <- setup
-  mapM_ (hPrintChunk h term) cs
-  T.hRunTermOutput h term (defaultColors term)
-  T.hRunTermOutput h term
-    $ case T.getCapability term T.allAttributesOff of
-        Nothing -> error $ "Rainbow.putChunks: error: "
-                   ++ "allAttributesOff failed"
-        Just s -> s
-
--- | Sends a list of chunks to standard output for printing. Sets up
--- the terminal (this only needs to be done once.) Lazily processes
--- the list of Chunk.
---
--- Which colors are used depends upon the 'Term'. If it is 'Dumb',
--- then no colors are used on output. If the 'Term' is specified with
--- 'TermName', the UNIX terminfo library is used to determine how many
--- colors the terminal supports. If it supports at least 256 colors,
--- then 256 colors are used. If it supports at least 8 colors but less
--- than 256 colors, then 8 colors are used. Otherwise, no colors are
--- used. A runtime error will occur if the 'TermName' is not found in
--- the system terminal database.
-putChunks :: Term -> [Chunk] -> IO ()
-putChunks = hPutChunks IO.stdout
-
--- | Print one chunk at a time, to a handle
-hPutChunk :: IO.Handle -> Chunk -> IO ()
-hPutChunk h c = do
-  t <- termFromEnv
-  hPutChunks h t [c]
-
--- | Print one chunk at a time, to standard output
-putChunk :: Chunk -> IO ()
-putChunk = hPutChunk IO.stdout
-
--- | Print one chunk at a time, to a handle, append a newline
-hPutChunkLn :: IO.Handle -> Chunk -> IO ()
-hPutChunkLn h c = hPutChunk h c >> IO.hPutStr h "\n"
-
--- | Print one chunk at a time, to standard output, append a newline
-putChunkLn :: Chunk -> IO ()
-putChunkLn c = putChunk c >> putStr "\n"
+-- 8-color effects
 
 bold8 :: Chunk
 bold8 = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
         scBold = Last (Just True) }}}}
   where
     x = mempty
 
 bold8off :: Chunk
 bold8off = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
         scBold = Last (Just False) }}}}
   where
     x = mempty
 
+faint8 :: Chunk
+faint8 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scFaint = Last (Just True) }}}}
+  where
+    x = mempty
 
+faint8off :: Chunk
+faint8off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scFaint = Last (Just False) }}}}
+  where
+    x = mempty
+
+italic8 :: Chunk
+italic8 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scItalic = Last (Just True) }}}}
+  where
+    x = mempty
+
+italic8off :: Chunk
+italic8off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scItalic = Last (Just False) }}}}
+  where
+    x = mempty
+
+
 underline8 :: Chunk
 underline8 = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
         scUnderline = Last (Just True) }}}}
   where
     x = mempty
@@ -376,128 +279,245 @@
 
 underline8off :: Chunk
 underline8off = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
         scUnderline = Last (Just False) }}}}
   where
     x = mempty
 
-flash8 :: Chunk
-flash8 = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
-        scFlash = Last (Just True) }}}}
+blink8 :: Chunk
+blink8 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scBlink = Last (Just True) }}}}
   where
     x = mempty
 
-flash8off :: Chunk
-flash8off = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
-        scFlash = Last (Just False) }}}}
+blink8off :: Chunk
+blink8off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scBlink = Last (Just False) }}}}
   where
     x = mempty
 
 
 inverse8 :: Chunk
 inverse8 = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
         scInverse = Last (Just True) }}}}
   where
     x = mempty
 
 inverse8off :: Chunk
 inverse8off = x {
-  textSpec = (textSpec x) {
-    style8 = (style8 (textSpec x)) {
-      common8 = (common8 (style8 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
         scInverse = Last (Just False) }}}}
   where
     x = mempty
 
 
-underline256 :: Chunk
-underline256 = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
-        scUnderline = Last (Just True) }}}}
+invisible8 :: Chunk
+invisible8 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scInvisible = Last (Just True) }}}}
   where
     x = mempty
 
+invisible8off :: Chunk
+invisible8off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scInvisible = Last (Just False) }}}}
+  where
+    x = mempty
 
-underline256off :: Chunk
-underline256off = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
-        scUnderline = Last (Just False) }}}}
+
+strikeout8 :: Chunk
+strikeout8 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scStrikeout = Last (Just True) }}}}
   where
     x = mempty
 
+strikeout8off :: Chunk
+strikeout8off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style8 = (style8 (chunkTextSpec x)) {
+      common8 = (common8 (style8 (chunkTextSpec x))) {
+        scStrikeout = Last (Just False) }}}}
+  where
+    x = mempty
+
+
+-- 256 color effects
+
 bold256 :: Chunk
 bold256 = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
         scBold = Last (Just True) }}}}
   where
     x = mempty
 
 bold256off :: Chunk
 bold256off = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
         scBold = Last (Just False) }}}}
   where
     x = mempty
 
 
+faint256 :: Chunk
+faint256 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scFaint = Last (Just True) }}}}
+  where
+    x = mempty
+
+faint256off :: Chunk
+faint256off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scFaint = Last (Just False) }}}}
+  where
+    x = mempty
+
+
+italic256 :: Chunk
+italic256 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scItalic = Last (Just True) }}}}
+  where
+    x = mempty
+
+italic256off :: Chunk
+italic256off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scItalic = Last (Just False) }}}}
+  where
+    x = mempty
+
+
+underline256 :: Chunk
+underline256 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scUnderline = Last (Just True) }}}}
+  where
+    x = mempty
+
+
+underline256off :: Chunk
+underline256off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scUnderline = Last (Just False) }}}}
+  where
+    x = mempty
+
+blink256 :: Chunk
+blink256 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scBlink = Last (Just True) }}}}
+  where
+    x = mempty
+
+
+blink256off :: Chunk
+blink256off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scBlink = Last (Just False) }}}}
+  where
+    x = mempty
+
+
 inverse256 :: Chunk
 inverse256 = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
         scInverse = Last (Just True) }}}}
   where
     x = mempty
 
 inverse256off :: Chunk
 inverse256off = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
         scInverse = Last (Just False) }}}}
   where
     x = mempty
 
 
-flash256 :: Chunk
-flash256 = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
-        scFlash = Last (Just True) }}}}
+invisible256 :: Chunk
+invisible256 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scInvisible = Last (Just True) }}}}
   where
     x = mempty
 
+invisible256off :: Chunk
+invisible256off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scInvisible = Last (Just False) }}}}
+  where
+    x = mempty
 
-flash256off :: Chunk
-flash256off = x {
-  textSpec = (textSpec x) {
-    style256 = (style256 (textSpec x)) {
-      common256 = (common256 (style256 (textSpec x))) {
-        scFlash = Last (Just False) }}}}
+
+strikeout256 :: Chunk
+strikeout256 = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scStrikeout = Last (Just True) }}}}
   where
     x = mempty
 
+strikeout256off :: Chunk
+strikeout256off = x {
+  chunkTextSpec = (chunkTextSpec x) {
+    style256 = (style256 (chunkTextSpec x)) {
+      common256 = (common256 (style256 (chunkTextSpec x))) {
+        scStrikeout = Last (Just False) }}}}
+  where
+    x = mempty
 
+
+
 --
 -- All
 --
@@ -518,21 +538,45 @@
 boldOff :: Chunk
 boldOff = bold8off <> bold256off
 
-inverse :: Chunk
-inverse = inverse8 <> inverse256
+faint :: Chunk
+faint = faint8 <> faint256
 
-inverseOff :: Chunk
-inverseOff = inverse8off <> inverse256off
+faintOff :: Chunk
+faintOff = faint8off <> faint256off
 
-flash :: Chunk
-flash = flash8 <> flash256
+italic :: Chunk
+italic = italic8 <> italic256
 
-flashOff :: Chunk
-flashOff = flash8off <> flash256off
+italicOff :: Chunk
+italicOff = italic8off <> italic256off
 
 underline :: Chunk
 underline = underline8 <> underline256
 
 underlineOff :: Chunk
 underlineOff = underline8off <> underline256off
+
+blink :: Chunk
+blink = blink8 <> blink256
+
+blinkOff :: Chunk
+blinkOff = blink8off <> blink256off
+
+inverse :: Chunk
+inverse = inverse8 <> inverse256
+
+inverseOff :: Chunk
+inverseOff = inverse8off <> inverse256off
+
+invisible :: Chunk
+invisible = invisible8 <> invisible256
+
+invisibleOff :: Chunk
+invisibleOff = invisible8off <> invisible256off
+
+strikeout :: Chunk
+strikeout = strikeout8 <> strikeout256
+
+strikeoutOff :: Chunk
+strikeoutOff = strikeout8off <> strikeout256off
 
diff --git a/rainbow.cabal b/rainbow.cabal
--- a/rainbow.cabal
+++ b/rainbow.cabal
@@ -3,11 +3,11 @@
 -- http://www.github.com/massysett/cartel
 --
 -- Script name used to generate: genCabal.hs
--- Generated on: 2015-02-17 14:13:13.981663 EST
+-- Generated on: 2015-03-22 11:22:55.854238 EDT
 -- Cartel library version: 0.14.2.0
 
 name: rainbow
-version: 0.20.4.0
+version: 0.22.0.0
 cabal-version: >= 1.16
 license: BSD3
 license-file: LICENSE
@@ -24,12 +24,6 @@
   such as bold, underlining, etc. You pair each Text with a description
   of how it should appear. Rainbow works with both 8-color and 256-color
   terminals.
-  .
-  rainbow uses the terminfo package which, in turn, needs the full C
-  library for ncurses installed, including the development
-  headers. Before installing terminfo, you may need to install the
-  ncurses headers (for instance, on Debian systems, install the
-  libncurses5-dev package.)
 category: System
 tested-with:
   GHC == 7.6.3
@@ -39,17 +33,120 @@
   exposed-modules:
     Rainbow
     Rainbow.Colors
+    Rainbow.Translate
     Rainbow.Types
   default-language: Haskell2010
   ghc-options:
     -Wall
   build-depends:
       base >= 4.5.0.0 && < 4.8.0.0
-    , terminfo >= 0.3.2 && < 0.5.0.0
     , text >= 0.11.2.0 && < 1.3.0.0
+    , bytestring >= 0.10 && < 0.11
+    , process >= 1.2 && < 1.3
   hs-source-dirs:
     lib
 
 source-repository head
   type: git
   location: https://github.com/massysett/rainbow.git
+
+Test-Suite rainbow-instances
+  type: exitcode-stdio-1.0
+  main-is: rainbow-instances.hs
+  other-modules:
+    Rainbow.QuickCheck
+    Rainbow
+    Rainbow.Colors
+    Rainbow.Translate
+    Rainbow.Types
+  hs-source-dirs:
+    tests
+  build-depends:
+      QuickCheck >= 2.7 && < 2.9
+  default-language: Haskell2010
+  ghc-options:
+    -Wall
+  build-depends:
+      base >= 4.5.0.0 && < 4.8.0.0
+    , text >= 0.11.2.0 && < 1.3.0.0
+    , bytestring >= 0.10 && < 0.11
+    , process >= 1.2 && < 1.3
+  hs-source-dirs:
+    lib
+
+Executable test8color
+  main-is: test8color.hs
+  if flag(visual)
+    buildable: True
+    other-modules:
+      Rainbow
+      Rainbow.Colors
+      Rainbow.Translate
+      Rainbow.Types
+    hs-source-dirs:
+      tests
+    default-language: Haskell2010
+    ghc-options:
+      -Wall
+    build-depends:
+        base >= 4.5.0.0 && < 4.8.0.0
+      , text >= 0.11.2.0 && < 1.3.0.0
+      , bytestring >= 0.10 && < 0.11
+      , process >= 1.2 && < 1.3
+    hs-source-dirs:
+      lib
+  else
+    buildable: False
+
+Executable test256color
+  main-is: test256color.hs
+  if flag(visual)
+    buildable: True
+    other-modules:
+      Rainbow
+      Rainbow.Colors
+      Rainbow.Translate
+      Rainbow.Types
+    hs-source-dirs:
+      tests
+    default-language: Haskell2010
+    ghc-options:
+      -Wall
+    build-depends:
+        base >= 4.5.0.0 && < 4.8.0.0
+      , text >= 0.11.2.0 && < 1.3.0.0
+      , bytestring >= 0.10 && < 0.11
+      , process >= 1.2 && < 1.3
+    hs-source-dirs:
+      lib
+  else
+    buildable: False
+
+Executable colorTest
+  main-is: colorTest.hs
+  if flag(visual)
+    buildable: True
+    other-modules:
+      Rainbow
+      Rainbow.Colors
+      Rainbow.Translate
+      Rainbow.Types
+    hs-source-dirs:
+      tests
+    default-language: Haskell2010
+    ghc-options:
+      -Wall
+    build-depends:
+        base >= 4.5.0.0 && < 4.8.0.0
+      , text >= 0.11.2.0 && < 1.3.0.0
+      , bytestring >= 0.10 && < 0.11
+      , process >= 1.2 && < 1.3
+    hs-source-dirs:
+      lib
+  else
+    buildable: False
+
+Flag visual
+  description: builds visual tests
+  default: False
+  manual: True
diff --git a/tests/Rainbow/QuickCheck.hs b/tests/Rainbow/QuickCheck.hs
new file mode 100644
--- /dev/null
+++ b/tests/Rainbow/QuickCheck.hs
@@ -0,0 +1,144 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# LANGUAGE FlexibleInstances, DeriveGeneric, StandaloneDeriving #-}
+
+-- | QuickCheck instances for all of Rainbow.  Currently Rainbow does
+-- not use these instances itself; they are only here for
+-- cut-and-paste for other libraries that may need them.  There is an
+-- executable in Rainbow that is built solely to make sure this module
+-- compiles without any errors.
+--
+-- To use these instances, just drop them into your own project
+-- somewhere.  They are not packaged as a library because there are
+-- orphan instances.
+
+module Rainbow.QuickCheck where
+
+import Control.Applicative
+import Test.QuickCheck
+import Rainbow.Colors
+import Rainbow.Types
+import Data.Monoid
+import Control.Monad
+import qualified Data.Text as X
+
+varInt :: Int -> Gen b -> Gen b
+varInt = variant
+
+instance Arbitrary Enum8 where
+  arbitrary = elements [E0, E1, E2, E3, E4, E5, E6, E7]
+  shrink = genericShrink
+
+instance CoArbitrary Enum8 where
+  coarbitrary x = case x of
+    E0 -> varInt 0
+    E1 -> varInt 1
+    E2 -> varInt 2
+    E3 -> varInt 3
+    E4 -> varInt 4
+    E5 -> varInt 5
+    E6 -> varInt 6
+    E7 -> varInt 7
+
+instance Arbitrary Color8 where
+  arbitrary = fmap Color8 arbitrary
+  shrink = genericShrink
+
+instance CoArbitrary Color8 where
+  coarbitrary (Color8 Nothing) = varInt 0
+  coarbitrary (Color8 (Just e)) = varInt 1 . coarbitrary e
+
+instance Arbitrary Color256 where
+  arbitrary = fmap Color256 arbitrary
+  shrink = genericShrink
+
+instance CoArbitrary Color256 where
+  coarbitrary (Color256 Nothing) = varInt 0
+  coarbitrary (Color256 (Just w)) = varInt 1 . coarbitrary w
+
+instance Arbitrary (Last Color8) where
+  arbitrary = fmap Last arbitrary
+
+instance CoArbitrary (Last Color8) where
+  coarbitrary (Last Nothing) = varInt 0
+  coarbitrary (Last (Just c)) = varInt 1 . coarbitrary c
+
+instance Arbitrary (Last Color256) where
+  arbitrary = fmap Last arbitrary
+
+instance CoArbitrary (Last Color256) where
+  coarbitrary (Last Nothing) = varInt 0
+  coarbitrary (Last (Just c)) = varInt 1 . coarbitrary c
+
+instance Arbitrary (Last Bool) where
+  arbitrary = fmap Last arbitrary
+
+instance CoArbitrary (Last Bool) where
+  coarbitrary (Last Nothing) = varInt 0
+  coarbitrary (Last (Just b)) = varInt 1 . coarbitrary b
+
+instance Arbitrary StyleCommon where
+  arbitrary
+    = StyleCommon <$> g <*> g <*> g <*> g <*> g <*> g <*> g <*> g
+    where
+      g = fmap Last arbitrary
+
+instance CoArbitrary StyleCommon where
+  coarbitrary (StyleCommon x0 x1 x2 x3 x4 x5 x6 x7)
+    = coarbitrary x0
+    . coarbitrary x1
+    . coarbitrary x2
+    . coarbitrary x3
+    . coarbitrary x4
+    . coarbitrary x5
+    . coarbitrary x6
+    . coarbitrary x7
+    
+
+instance Arbitrary Style256 where
+  arbitrary = liftM3 Style256 arbitrary arbitrary arbitrary
+
+instance CoArbitrary Style256 where
+  coarbitrary (Style256 x0 x1 x2)
+    = coarbitrary x0
+    . coarbitrary x1
+    . coarbitrary x2
+
+instance Arbitrary Style8 where
+  arbitrary = liftM3 Style8 arbitrary arbitrary arbitrary
+
+instance CoArbitrary Style8 where
+  coarbitrary (Style8 x0 x1 x2)
+    = coarbitrary x0
+    . coarbitrary x1
+    . coarbitrary x2
+
+instance Arbitrary TextSpec where
+  arbitrary = liftM2 TextSpec arbitrary arbitrary
+  shrink = genericShrink
+
+instance CoArbitrary TextSpec where
+  coarbitrary (TextSpec x0 x1)
+    = coarbitrary x0
+    . coarbitrary x1
+
+instance Arbitrary X.Text where
+  arbitrary = fmap X.pack arbitrary
+  shrink = map X.pack . shrink . X.unpack
+
+instance Arbitrary Chunk where
+  arbitrary = liftM2 Chunk arbitrary
+    (listOf (fmap X.pack (listOf (elements ['a'..'z']))))
+  shrink = genericShrink
+
+instance CoArbitrary Chunk where
+  coarbitrary (Chunk ts txts) = coarbitrary ts
+    . coarbitrary (map X.unpack txts)
+
+instance Arbitrary Radiant where
+  arbitrary = liftM2 Radiant arbitrary arbitrary
+  shrink = genericShrink
+
+instance CoArbitrary Radiant where
+  coarbitrary (Radiant x0 x1)
+    = coarbitrary x0
+    . coarbitrary x1
diff --git a/tests/colorTest.hs b/tests/colorTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/colorTest.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Rainbow
+import qualified Data.Text as X
+import qualified Data.ByteString as BS
+
+colors8 :: [(Text, Color8)]
+colors8 =
+  [ ("(no color)", noColor8)
+  , ("black", black8)
+  , ("red", red8)
+  , ("green", green8)
+  , ("yellow", yellow8)
+  , ("blue", blue8)
+  , ("magenta", magenta8)
+  , ("cyan", cyan8)
+  , ("white", white8)
+  ]
+
+colors256 :: [(Text, Color256)]
+colors256
+  = ("(no color)", Color256 Nothing) : map mkColor [minBound..maxBound]
+  where
+    mkColor w = (X.pack . show $ w, Color256 . Just $ w)
+
+colorChunks8ByForeground :: [Chunk]
+colorChunks8ByForeground = do
+  (fgColorName, fgColor) <- colors8
+  (bgColorName, bgColor) <- colors8
+  let lbl = "foreground " <> fgColorName <> " background " <> bgColorName
+  return $ chunkFromText lbl <> fore fgColor <> back bgColor <> "\n"
+
+colorChunks8ByBackground :: [Chunk]
+colorChunks8ByBackground = do
+  (bgColorName, bgColor) <- colors8
+  (fgColorName, fgColor) <- colors8
+  let lbl = "background " <> bgColorName <> " foreground " <> fgColorName
+  return $ chunkFromText lbl <> fore fgColor <> back bgColor <> "\n"
+
+colorChunks256ByForeground :: [Chunk]
+colorChunks256ByForeground = do
+  (fgColorName, fgColor) <- colors256
+  (bgColorName, bgColor) <- colors256
+  let lbl = "foreground " <> fgColorName <> " background " <> bgColorName
+  return $ chunkFromText lbl <> fore fgColor <> back bgColor <> "\n"
+
+colorChunks256ByBackground :: [Chunk]
+colorChunks256ByBackground = do
+  (bgColorName, bgColor) <- colors256
+  (fgColorName, fgColor) <- colors256
+  let lbl = "background " <> bgColorName <> " foreground " <> fgColorName
+  return $ chunkFromText lbl <> fore fgColor <> back bgColor <> "\n"
+
+sep :: String -> IO ()
+sep s = do
+  putStrLn ""
+  putStrLn ""
+  putStrLn $ replicate 40 '='
+  putStrLn s
+
+main :: IO ()
+main = do
+  sep "8 Colors - sorted by foreground color"
+  mapM_ BS.putStr . chunksToByteStrings toByteStringsColors8
+    $ colorChunks8ByForeground
+  sep "8 Colors - sorted by background color"
+  mapM_ BS.putStr . chunksToByteStrings toByteStringsColors8
+    $ colorChunks8ByBackground
+  sep "256 Colors - sorted by foreground color"
+  mapM_ BS.putStr . chunksToByteStrings toByteStringsColors256
+    $ colorChunks256ByForeground
+  sep "256 Colors - sorted by background color"
+  mapM_ BS.putStr . chunksToByteStrings toByteStringsColors256
+    $ colorChunks256ByBackground
diff --git a/tests/rainbow-instances.hs b/tests/rainbow-instances.hs
new file mode 100644
--- /dev/null
+++ b/tests/rainbow-instances.hs
@@ -0,0 +1,10 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
+
+-- | This program exists solely to import Rainbow.QuickCheck to make
+-- sure it compiles.
+module Main where
+
+import Rainbow.QuickCheck
+
+main :: IO ()
+main = return ()
diff --git a/tests/test256color.hs b/tests/test256color.hs
new file mode 100644
--- /dev/null
+++ b/tests/test256color.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Control.Arrow (second)
+import Rainbow
+import qualified Data.Text as X
+import qualified Data.ByteString as BS
+
+effects :: [(Text, Chunk)]
+effects =
+  [ ("bold", bold256)
+  , ("faint", faint256)
+  , ("italic", italic256)
+  , ("underline", underline256)
+  , ("blink", blink256)
+  , ("inverse", inverse256)
+  , ("invisible", invisible256)
+  , ("strikeout", strikeout256)
+  ]
+
+colors :: [(Text, Color256)]
+colors = ("(no color)", Color256 Nothing) : map mkColor [minBound..maxBound]
+  where
+    mkColor w = (X.pack . show $ w, Color256 . Just $ w)
+
+maybeEffects :: [(Text, Maybe Chunk)]
+maybeEffects = ("(no effect)", Nothing)
+  : map (second Just) effects
+
+{-
+-- From
+-- http://stackoverflow.com/a/22577148/1017252
+combinations :: Int -> [a] -> [[a]]
+combinations k xs = combinations' (length xs) k xs
+  where combinations' n k' l@(y:ys)
+          | k' == 0   = [[]]
+          | k' >= n   = [l]
+          | null l    = []
+          | otherwise = map (y :) (combinations' (n - 1) (k' - 1) ys)
+                            ++ combinations' (n - 1) k' ys 
+-}
+
+colorsAndEffects :: [Chunk]
+colorsAndEffects = do
+  (fgColorName, fgColor) <- colors
+  (bgColorName, bgColor) <- colors
+  (effectName, mayEffect) <- maybeEffects
+  let lbl = "foreground " <> fgColorName <> " background " <> bgColorName
+          <> " effect " <> effectName
+  return $ chunkFromText lbl <>  fore fgColor
+         <>  back bgColor
+         <> maybe mempty id mayEffect
+         <> "\n"
+
+main :: IO ()
+main = do
+  mapM_ BS.putStr . chunksToByteStrings toByteStringsColors256
+    $ colorsAndEffects
diff --git a/tests/test8color.hs b/tests/test8color.hs
new file mode 100644
--- /dev/null
+++ b/tests/test8color.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Control.Arrow (second)
+import Rainbow
+import qualified Data.ByteString as BS
+
+effects :: [(Text, Chunk)]
+effects =
+  [ ("bold", bold8)
+  , ("faint", faint8)
+  , ("italic", italic8)
+  , ("underline", underline8)
+  , ("blink", blink8)
+  , ("inverse", inverse8)
+  , ("invisible", invisible8)
+  , ("strikeout", strikeout8)
+  ]
+
+colors :: [(Text, Color8)]
+colors =
+  [ ("(no color)", noColor8)
+  , ("black", black8)
+  , ("red", red8)
+  , ("green", green8)
+  , ("yellow", yellow8)
+  , ("blue", blue8)
+  , ("magenta", magenta8)
+  , ("cyan", cyan8)
+  , ("white", white8)
+  ]
+
+maybeEffects :: [(Text, Maybe Chunk)]
+maybeEffects = ("(no effect)", Nothing)
+  : map (second Just) effects
+
+{-
+-- From
+-- http://stackoverflow.com/a/22577148/1017252
+combinations :: Int -> [a] -> [[a]]
+combinations k xs = combinations' (length xs) k xs
+  where combinations' n k' l@(y:ys)
+          | k' == 0   = [[]]
+          | k' >= n   = [l]
+          | null l    = []
+          | otherwise = map (y :) (combinations' (n - 1) (k' - 1) ys)
+                            ++ combinations' (n - 1) k' ys 
+-}
+
+colorsAndEffects :: [Chunk]
+colorsAndEffects = do
+  (fgColorName, fgColor) <- colors
+  (bgColorName, bgColor) <- colors
+  (effectName, mayEffect) <- maybeEffects
+  let lbl = "foreground " <> fgColorName <> " background " <> bgColorName
+          <> " effect " <> effectName
+  return $ chunkFromText lbl <> fore fgColor
+         <> back bgColor
+         <> maybe mempty id mayEffect
+         <> chunkFromText "\n"
+
+main :: IO ()
+main = do
+  mapM_ BS.putStr . chunksToByteStrings toByteStringsColors8
+    $ colorsAndEffects
