    {-# LINE 1 "System/Console/Editline.hsc" #-}
    -----------------------------------------------------------------------------
    {-# LINE 2 "System/Console/Editline.hsc" #-}
    -- |
    -- Module      :  System.Console.Editline
    -- Copyright   :  (c) 2008, Judah Jacobson
    -- License     :  BSD3
    --
    -- Maintainer  :  judah.jacobson@gmail.com
    -- Stability   :  experimental
    -- Portability :  non-portable (requires libedit)
    --
    -- A Haskell binding to the editline library.  For more information about that
    -- library, see <http://www.thrysoee.dk/editline/>.
    --
    -- The following example illustrates using this library to write a loop that will
    -- process input until it reaches EOF or a Ctrl-D is typed.
    --
    -- @
    --editlineLoop :: IO ()
    -- editlineLoop = do
    --    prog <- System.Environment.getProgName
    --    el <- elInit prog
    --    setPrompt el (return \"input: \")
    --    setEditor el Vi
    --    let loop = do
    --         maybeLine <- elGets el
    --         case maybeLine of
    --             Nothing -> return () -- ctrl-D
    --             Just line -> do
    --                 let line\' = init line -- remove trailing \'\\n\'
    --                 putStrLn $ \"User input: \" ++ show line\'
    --                 loop
    --    loop
    -- @
    --
    module System.Console.Editline(
                                EditLine(),
                                elInit,
                                reset,
                                elGets,
                                setPrompt,
                                Editor(..),
                                setEditor
                                ) where

    import Foreign.C
    import Foreign.ForeignPtr
    import Foreign.Ptr
    import Foreign.Marshal
    import Foreign.Storable (peek)
    import Control.Monad

    {-# LINE 53 "System/Console/Editline.hsc" #-}

    data EDITLINE
    newtype EditLine = EditLine (ForeignPtr EDITLINE)

    withEditLine :: EditLine -> (Ptr EDITLINE -> IO a) -> IO a
    withEditLine (EditLine fp) = withForeignPtr fp

    -- | Initialize the line editor.
    elInit :: String -- ^ The name of the calling program; used when reading the
                     -- @editrc@ file to determine which settings to use.
                -> IO EditLine
    elInit prog = do
        el <- withCString prog el_init_from_term
        fmap EditLine $ newForeignPtr el_end el

    foreign import ccall el_init_from_term :: CString -> IO (Ptr EDITLINE)

    foreign import ccall "&" el_end :: FunPtr (Ptr EDITLINE -> IO ())

    -- | Reset the terminal and the parser.  This should be called after an error which
    -- may have upset the terminal's state.
    reset :: EditLine -> IO ()
    reset el = withEditLine el el_reset

    foreign import ccall el_reset :: Ptr EDITLINE -> IO ()

    -- | Read a line of input from the terminal.  Returns Nothing if no characters
    -- were read or if an error occured.
    elGets :: EditLine -> IO (Maybe String)
    elGets el = withEditLine el $ \el_p -> alloca $ \count_p -> do
        result <- el_gets el_p count_p
        count <- fmap fromEnum $ peek count_p
        if result == nullPtr
            then return Nothing
            else fmap Just $ peekCStringLen (result, count)

    foreign import ccall el_gets :: Ptr EDITLINE -> Ptr CInt -> IO CString

    foreign import ccall el_set_prompt :: Ptr EDITLINE -> FunPtr PromptFunc -> IO CInt

    -- | Set a function that will determine the prompt string.
    setPrompt :: EditLine -> IO String -> IO ()
    setPrompt el f = withEditLine el $ \el_p -> do
        -- Set new function
        f_ptr <- mkPromptFunc $ \_ -> f >>= newCString
        el_set_prompt el_p f_ptr
        return ()

    type PromptFunc = Ptr EDITLINE -> IO CString
    foreign import ccall "wrapper" mkPromptFunc :: PromptFunc -> IO (FunPtr PromptFunc)

    data Editor = Vi | Emacs
    editorString :: Editor -> String
    editorString Vi = "vi"
    editorString Emacs = "emacs"

    -- | Set the editor keymap mode.
    setEditor :: EditLine -> Editor -> IO ()
    setEditor el editor = withEditLine el $ \el_p ->
                            withCString (editorString editor) $ \ed_str ->
                                el_set_editor el_p ed_str >> return ()

    foreign import ccall el_set_editor :: Ptr EDITLINE -> CString -> IO CInt