module DDC.Interface.Input
( InputInterface (..)
, InputState (..)
, Input (..)
, readInput
, inputLine)
where
import DDC.Interface.Source
import DDC.Data.ListUtils
import System.Directory
import Data.List
import Data.Char
data InputState command
= InputState
{
inputParseCommand :: String -> Maybe (command, String)
, inputMode :: Input
, inputCommand :: Maybe (Maybe command, Int)
, inputLineNumber :: Int
, inputAcc :: String }
data InputInterface
= InputInterfaceArgs
| InputInterfaceConsole
| InputInterfaceBatch FilePath
deriving (Eq, Show)
data Input
= InputLine
| InputBlock
| InputFile FilePath
deriving (Eq, Show)
readInput :: String -> (Input, String)
readInput ss
| isPrefixOf ".." ss
= (InputBlock, drop 2 ss)
| isPrefixOf "<" ss
, filePath <- dropWhile isSpace (drop 1 ss)
= (InputFile filePath, drop (length filePath) ss)
| otherwise
= (InputLine, ss)
inputLine
:: InputInterface
-> InputState c
-> String
-> IO ( InputState c
, Maybe (Source, Maybe c, String))
inputLine interface inputState chunk
| InputState readCmd mode mCommand lineNumber acc <- inputState
= do
let (cmd, lineStart, (input, rest))
= case mCommand of
Nothing
-> case readCmd chunk of
Just (cmd', rest') -> (Just cmd', lineNumber, readInput rest')
Nothing -> (Nothing, lineNumber, (InputLine, chunk))
Just (cmd', lineStart')
-> (cmd', lineStart', (mode, chunk))
let source
| InputFile filePath <- input
= SourceFile filePath
| otherwise
= case interface of
InputInterfaceArgs -> SourceArgs
InputInterfaceConsole -> SourceConsole lineStart
InputInterfaceBatch file -> SourceBatch file lineStart
case input of
InputLine
| not $ null rest
, last rest == '\\'
, Just initRest <- takeInit rest
-> return ( inputState
{ inputCommand = (Just (cmd, lineStart))
, inputLineNumber = lineNumber + 1
, inputAcc = acc ++ initRest ++ "\n" }
, Nothing)
| otherwise
-> return ( inputState
{ inputMode = InputLine
, inputCommand = Nothing
, inputLineNumber = lineNumber + 1
, inputAcc = [] }
, Just (source, cmd, acc ++ rest))
InputBlock
| isSuffixOf ";;" rest
-> do let rest' = take (length rest 2) rest
return ( inputState
{ inputMode = InputLine
, inputCommand = Nothing
, inputLineNumber = lineNumber + 1
, inputAcc = [] }
, Just (source, cmd, acc ++ rest'))
| otherwise
-> return ( inputState
{ inputMode = input
, inputCommand = Just (cmd, lineStart)
, inputLineNumber = lineNumber + 1
, inputAcc = acc ++ rest ++ "\n" }
, Nothing)
InputFile filePath
-> do exists <- doesFileExist filePath
if exists
then do
contents <- readFile filePath
return ( inputState
{ inputMode = InputLine
, inputCommand = Nothing
, inputLineNumber = lineNumber + 1
, inputAcc = [] }
, Just (source, cmd, contents))
else do
putStrLn "No such file."
return ( inputState
{ inputMode = InputLine
, inputCommand = Nothing
, inputLineNumber = lineNumber + 1
, inputAcc = [] }
, Nothing)