diff --git a/AC-Terminal.cabal b/AC-Terminal.cabal
new file mode 100644
--- /dev/null
+++ b/AC-Terminal.cabal
@@ -0,0 +1,36 @@
+Cabal-Version: >= 1.6
+Name:          AC-Terminal
+Version:       1.0
+Stability:     Stable
+Synopsis:      Trivial wrapper over ansi-terminal.
+
+Description:
+
+  This trivial package presents a simplified interface to
+  the most excellent @ansi-terminal@ package, exposing only
+  the functionallity that I personally use. It is very
+  limited, but very easy to use.
+  .
+  This package allows you to manipulate the text output
+  terminal (assuming your program has one). Specifically,
+  it supports colour changes and title changes (for
+  virtual terminals). Impressively, it (or rather, the
+  package it wraps) works on both Windows and Unix.
+  Under Windows, it uses native Win32 calls, while under
+  Unix it uses ANSI escape codes.
+
+Category:      Data, Math, Numerical
+License:       BSD3
+License-file:  License.txt
+Author:        Andrew Coppin
+Maintainer:    MathematicalOrchid@hotmail.com
+Build-Type:    Simple
+Tested-With:   GHC == 6.10.3
+
+Library
+  Exposed-modules:
+    System.Terminal.Core
+    System.Terminal.Utility
+    System.Terminal
+  Build-Depends:   base >= 4 && < 5, ansi-terminal >= 0.5
+  HS-Source-Dirs:  .
diff --git a/License.txt b/License.txt
new file mode 100644
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,10 @@
+Copyright (c) 2009, Andrew Coppin
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of Andrew Coppin nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/System/Terminal.hs b/System/Terminal.hs
new file mode 100644
--- /dev/null
+++ b/System/Terminal.hs
@@ -0,0 +1,9 @@
+module System.Terminal
+    (
+      module System.Terminal.Core,
+      module System.Terminal.Utility
+    )
+  where
+
+import System.Terminal.Core
+import System.Terminal.Utility
diff --git a/System/Terminal/Core.hs b/System/Terminal/Core.hs
new file mode 100644
--- /dev/null
+++ b/System/Terminal/Core.hs
@@ -0,0 +1,53 @@
+{- |
+  This module provides the basic features of the package.
+-}
+
+module System.Terminal.Core
+    (
+      Colour (..), set_colours, set_title
+    )
+  where
+
+import System.Console.ANSI as RAW
+
+-- | Possible terminal colours. (D for Dark, L for Light.)
+data Colour =
+    DBlack | DBlue | DGreen | DCyan | DRed | DMagenta | DYellow | DWhite |
+    LBlack | LBlue | LGreen | LCyan | LRed | LMagenta | LYellow | LWhite
+  deriving Enum
+
+decodeC :: Colour -> RAW.Color
+decodeC c =
+  [
+    RAW.Black,
+    RAW.Blue,
+    RAW.Green,
+    RAW.Cyan,
+    RAW.Red,
+    RAW.Magenta,
+    RAW.Yellow,
+    RAW.White
+  ]
+  !! (fromEnum c `mod` 8)
+
+decodeI :: Colour -> RAW.ColorIntensity
+decodeI c = if fromEnum c <= 7 then RAW.Dull else RAW.Vivid
+
+{- |
+  Set terminal forground and background colours.
+
+  Note that under Windows, the change in colour takes place
+  immediately. You may need to flush @stdout@ before calling
+  this function. (This is not necessary under Unix, but it's
+  probably good practise to do it for portability's sake.)
+-}
+set_colours :: Colour -> Colour -> IO ()
+set_colours f b = RAW.setSGR
+  [
+    RAW.SetColor RAW.Foreground (decodeI f) (decodeC f),
+    RAW.SetColor RAW.Background (decodeI b) (decodeC b)
+  ]
+
+-- | Change the title of the [virtual] terminal.
+set_title :: String -> IO ()
+set_title = RAW.setTitle
diff --git a/System/Terminal/Utility.hs b/System/Terminal/Utility.hs
new file mode 100644
--- /dev/null
+++ b/System/Terminal/Utility.hs
@@ -0,0 +1,137 @@
+{- |
+  This module provides various utilities and short-cuts.
+-}
+
+module System.Terminal.Utility where
+
+import Control.Exception (Exception (), throwIO)
+import System.IO
+
+import System.Terminal.Core
+
+-- * Setting colours
+
+-- | Set terminal foreground colour (background is set to black).
+set_colour :: Colour -> IO ()
+set_colour f = set_colours f DBlack
+
+-- | Set default terminal colours (DWhite on DBlack).
+set_colours_default :: IO ()
+set_colours_default = set_colours DWhite DBlack
+
+-- * Printing output
+
+-- | Set terminal [foreground] colour and then 'putStrLn' a string.
+putStrLnC :: Colour -> String -> IO ()
+putStrLnC c t = do
+  hFlush stdout
+  set_colour c
+  putStrLn t
+
+{- |
+  Write a pair of text strings on a single line, with different
+  [foreground] text colours.
+-}
+putPairLn :: (Colour, String) -> (Colour, String) -> IO ()
+putPairLn (c1, t1) (c2, t2) = do
+  hFlush stdout
+  set_colour c1
+  putStr t1
+  hFlush stdout
+  set_colour c2
+  putStrLn t2
+
+{- |
+  Print a single line of text, with a given character
+  highlighted in colour. Useful for, say, highlighting the
+  location of a syntax error in an expression.
+
+  The tuple consists of three colour pairs. Each pair is
+  a foreground\/background pair. The first pair applies to
+  the next before the nominated position, the second pair
+  applies to the nominated position itself, and the
+  third pair applies to any text after the nominated
+  position.
+
+  The nominated position is given by the 'Int' argument,
+  with 0 being the very first character of the string.
+  Note that if the position is off the end of the
+  string, a blank space will be added to the end of the
+  string and /that/ will be highlighted.
+
+  Note that no newline is written. If you want one, you
+  must output it yourself.
+-}
+highlight :: ((Colour, Colour), (Colour, Colour), (Colour, Colour)) -> Int -> String -> IO ()
+highlight ((f0, b0), (f1, b1), (f2, b2)) n msg = do
+  if (n < 0) then error "System.Terminal.Utility.highlight: negative index" else return ()
+  hFlush stdout
+  set_colours f0 b0
+  putStr (take n msg)
+  hFlush stdout
+  set_colours f1 b1
+  if (n < length msg)
+    then putChar (msg !! n)
+    else putChar ' '
+  hFlush stdout
+  set_colours f2 b2
+  putStr (drop (n+1) msg)
+
+{- |
+  A version of 'highlight' that outputs a newline after
+  the final character of text.
+-}
+highlightLN :: ((Colour, Colour), (Colour, Colour), (Colour, Colour)) -> Int -> String -> IO ()
+highlightLN cs n msg = do
+  highlight cs n msg
+  putChar '\n'
+
+-- * Handling exceptions and errors
+
+{- |
+  A default top-level exception handler, for exceptions that
+  fail to be caught before reaching the top level.
+
+  In a properly designed application, exceptions should be
+  anticipated, caught and handled in the correct place.
+  (E.g., if you try to open a file, you should anticipate
+  the possibility of an I\/O exception and catch\/process this
+  appropriately.) Thus an exception reaching the top-level
+  of the program would indicate a programming bug, and the
+  generated error message reflects this. On a crash, the text
+
+  > An internal program malfunction has occurred.
+  > Please report this as a bug to the program developers.
+
+  will be emitted on @stderr@, coloured bright yellow on a
+  bright red background. The exception is then re-thrown
+  (presumably halting the program).
+-}
+default_exception_handler :: Exception e => e -> IO x
+default_exception_handler e = do
+  hFlush stdout
+  hFlush stderr
+  set_colours LYellow LRed
+  hPutStrLn stderr "!!!"
+  hPutStrLn stderr ""
+  hPutStrLn stderr "An internal program malfunction has occurred."
+  hPutStrLn stderr "Please report this as a bug to the program developers."
+  hPutStrLn stderr ""
+  hFlush stderr
+  set_colours_default
+  throwIO e
+
+{- |
+  Take an 'IO' action, and run it with the
+  'default_exception_handler' installed. Typically you would
+  do something like
+
+  > main = with_default_exception_handler main2
+  >
+  > main2 = do ...
+
+  Now all unhandled exceptions in your program will cause a
+  suitable message to be written to @stderr@.
+-}
+with_default_exception_handler :: IO x -> IO x
+with_default_exception_handler act = catch act default_exception_handler
