--------------------------------------------------------------------------------

shell :: ShellDesc s -> s -> IO ()
shell sd s = void $ runShell sh sd s
    where
        sh :: Shell s ()
        sh = do
            io $ IO.hSetBuffering IO.stdin IO.NoBuffering
            io $ IO.hSetEcho IO.stdin False

            (sd, s) <- ST.get
            outputStrLn $ startText $ style sd
            roop

        roop :: Shell s ()
        roop = do
            (sd, s) <- ST.get

            m <- lift $ getInputLine $ prompt sd s
            case m of
                Nothing -> return ()
                Just (c:cs) | c == commandPrefix (style sd)
                        -> case words cs of
                            [] -> do
                                maybe (return ())
                                      ($ tail [])
                                      (lookup "help" $ commands sd)
                                roop
                            s:_ | s `isPrefixOf` "quit"
                               -> outputStrLn $ quitText $ style sd
                            xs -> do
                                maybe (outputStrLn "unknown command")
                                      (\(_,f) -> f $ tail xs)
                                      (find (\(s,_) -> head xs `isPrefixOf` s) (commands sd))
                                roop
                Just cs -> do
                    evalFunc sd cs
                    roop
shell :: ShellDesc s -> s -> IO ()
shell sd s = void $ runShell sh sd s
    where
        sh :: Shell s ()
        sh = do
            io $ IO.hSetBuffering IO.stdin IO.NoBuffering
            io $ IO.hSetEcho IO.stdin False

            (sd, s) <- ST.get
            outputStrLn $ startText $ style sd
            roop

        roop :: Shell s ()
        roop = do
            (sd, s) <- ST.get

            m <- lift $ getInputLine $ prompt sd s
            case m of
                Nothing -> return ()
                Just (c:cs) | c == commandPrefix (style sd)
                        -> case words cs of
                            [] -> do
                                maybe (return ())
                                      ($ tail [])
                                      (lookup "help" $ commands sd)
                                roop
                            s:_ | s `isPrefixOf` "quit"
                               -> outputStrLn $ quitText $ style sd
                            xs -> do
                                maybe (outputStrLn "unknown command")
                                      (\(_,f) -> f $ tail xs)
                                      (find (\(s,_) -> head xs `isPrefixOf` s) (commands sd))
                                roop
                Just cs -> do
                    evalFunc sd cs
                    roop
shell sd s = void $ runShell sh sd s
    where
        sh :: Shell s ()
        sh = do
            io $ IO.hSetBuffering IO.stdin IO.NoBuffering
            io $ IO.hSetEcho IO.stdin False

            (sd, s) <- ST.get
            outputStrLn $ startText $ style sd
            roop

        roop :: Shell s ()
        roop = do
            (sd, s) <- ST.get

            m <- lift $ getInputLine $ prompt sd s
            case m of
                Nothing -> return ()
                Just (c:cs) | c == commandPrefix (style sd)
                        -> case words cs of
                            [] -> do
                                maybe (return ())
                                      ($ tail [])
                                      (lookup "help" $ commands sd)
                                roop
                            s:_ | s `isPrefixOf` "quit"
                               -> outputStrLn $ quitText $ style sd
                            xs -> do
                                maybe (outputStrLn "unknown command")
                                      (\(_,f) -> f $ tail xs)
                                      (find (\(s,_) -> head xs `isPrefixOf` s) (commands sd))
                                roop
                Just cs -> do
                    evalFunc sd cs
                    roop