-- This is a simple program using ANSI escape sequences to create a program
-- which uses direct cursor addressing and input/output.
--
-- People are often quite surprised the first time they see a program like
-- this written in a functional language.
-- Basic screen control codes:
-- Choose whichever of the following lines is suitable for your system:
--partain: cls = "\ESC[2J" -- for PC with ANSI.SYS
cls = "\^L" -- for Sun window
goto x y = '\ESC':'[':(show y ++(';':show x ++ "H"))
at (x,y) s = goto x y ++ s
home = goto 1 1
highlight s = "\ESC[7m"++s++"\ESC[0m"
-- Some general purpose functions for interactive programs:
type Interact = String -> String
end :: Interact
end cs = ""
readChar, peekChar :: Interact -> (Char -> Interact) -> Interact
readChar eof use [] = eof []
readChar eof use (c:cs) = use c cs
peekChar eof use [] = eof [] -- like readChar, but character is
peekChar eof use cs@(c:_) = use c cs -- not removed from input stream
pressAnyKey :: Interact -> Interact
pressAnyKey prog = readChar prog (\c -> prog)
unreadChar :: Char -> Interact -> Interact
unreadChar c prog cs = prog (c:cs)
writeChar :: Char -> Interact -> Interact
writeChar c prog cs = c : prog cs
writeString :: String -> Interact -> Interact
writeString s prog cs = s ++ prog cs
writes :: [String] -> Interact -> Interact
writes ss = writeString (concat ss)
ringBell :: Interact -> Interact
ringBell = writeChar '\BEL'
-- Screen oriented input/output functions:
type Pos = (Int,Int)
clearScreen = writeString cls
writeAt (x,y) s = writeString (goto x y ++ s)
moveTo (x,y) = writeString (goto x y)
readAt :: Pos -> -- Start coordinates
Int -> -- Maximum input length
(String -> Interact) -> -- How to use entered string
Interact
readAt (x,y) l use = writeAt (x,y) (copy l '_') (moveTo (x,y) (loop 0 ""))
where loop n s = readChar (return s) (\c ->
case c of '\BS' -> delete n s
'\DEL' -> delete n s
'\n' -> return s
c | n < l -> writeChar c (loop (n+1) (c:s))
| otherwise -> ringBell (loop n s))
delete n s = if n>0 then writeString "\BS_\BS" (loop (n-1) (tail s))
else ringBell (loop 0 "")
return s = use (reverse s)
defReadAt :: Pos -> -- Start coordinates
Int -> -- Maximum input length
String -> -- Default string value
(String -> Interact) -> -- How to use entered string
Interact
defReadAt (x,y) l def use
= writeAt (x,y) (take l (def++repeat '_')) (
readChar (use def) (\c ->
if c=='\n' then use def
else unreadChar c (readAt (x,y) l use)))
promptReadAt (x,y) l prompt use
= writeAt (x,y) prompt (readAt (x+length prompt,y) l use)
defPromptReadAt (x,y) l prompt def use
= writeAt (x,y) prompt (
defReadAt (x+length prompt,y) l def use)
-- A sample program:
-- Enter the expression `run program' in Hugs to try this program out
program = writes [ cls,
at (17,5) (highlight "Demonstration program"),
at (48,5) "Version 1.0",
at (17,7) "This program illustrates a simple approach",
at (17,8) "to screen-based interactive programs using",
at (17,9) "the Hugs functional programming system.",
at (17,11) "Please press any key to continue ..."
]
(pressAnyKey
(promptReadAt (17,15) 18 "Please enter your name: " (\name ->
(let reply = "Hello " ++ name ++ "!" in
writeAt (40-(length reply`div` 2),18) reply
(moveTo (1,23)
(writeString "I'm waiting...\n"
(pressAnyKey
end)))))))
-- added by partain
main = interact program
copy :: Int -> a -> [a]
copy n x = take n (repeat x)
-- End of file
|