import System.IO
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Data.Char
main = do
hSetBuffering stdin NoBuffering
hSetBuffering stdout NoBuffering
hSetEcho stdin False
tvar <- newTVarIO ""
forkIO (render tvar)
forkIO (correcter tvar)
forever $ do
c <- getChar
atomically $ do
s <- readTVar tvar
writeTVar tvar (s ++ [c])
correcter :: TVar String -> IO ()
correcter tvar = loop ""
where
loop current = do
new <- atomically $ do
s <- readTVar tvar
when (s == current) retry
let s' = correct s
when (s' == s) retry
writeTVar tvar s'
return s'
loop new
render :: TVar String -> IO ()
render tvar = loop ""
where
printit current s = do
putStr (replicate (length current) '\8')
putStr s
loop current = do
new <- atomically $ do
s <- readTVar tvar
when (s == current) retry
return s
printit current new
loop new
-- This function applies an arbitrary function to the input string.
-- It could do all kinds of funky stuff, but right now all it does is
-- capitalise the first character after a full stop.
--
correct :: String -> String
correct s = go s
where
go "" = ""
go ('.':' ':c:s) | isLower c = '.':' ': toUpper c: go s
go (c:cs) = c : go cs