forked from GitHub/gf-core
199 lines
6.2 KiB
Haskell
199 lines
6.2 KiB
Haskell
----------------------------------------------------------------------
|
|
-- |
|
|
-- Module : CommandL
|
|
-- Maintainer : AR
|
|
-- Stability : (stable)
|
|
-- Portability : (portable)
|
|
--
|
|
-- > CVS $Date: 2005/08/17 15:13:55 $
|
|
-- > CVS $Author: aarne $
|
|
-- > CVS $Revision: 1.21 $
|
|
--
|
|
-- (Description of the module)
|
|
-----------------------------------------------------------------------------
|
|
|
|
module GF.Shell.CommandL where
|
|
|
|
import GF.Data.Operations
|
|
import GF.Infra.UseIO
|
|
|
|
import GF.Canon.CMacros
|
|
import GF.Grammar.Values (Tree)
|
|
|
|
import GF.UseGrammar.GetTree
|
|
import GF.Compile.ShellState
|
|
import GF.Infra.Option
|
|
import GF.UseGrammar.Session
|
|
import GF.Shell.Commands
|
|
import GF.Shell.PShell (wordsLits)
|
|
|
|
import Data.Char
|
|
import Data.List (intersperse)
|
|
import Control.Monad (foldM)
|
|
|
|
import GF.Text.UTF8
|
|
|
|
-- | a line-based shell
|
|
initEditLoop :: CEnv -> IO () -> IO ()
|
|
initEditLoop env resume = do
|
|
let env' = startEditEnv env
|
|
putStrLnFlush $ initEditMsg env'
|
|
let state = initSStateEnv env'
|
|
putStrLnFlush $ showCurrentState env' state
|
|
editLoop env' state resume
|
|
|
|
editLoop :: CEnv -> SState -> IO () -> IO ()
|
|
editLoop env state resume = do
|
|
putStrFlush "edit> "
|
|
c <- getCommand
|
|
if (isQuit c) then resume else do
|
|
(env',state') <- execCommand env c state
|
|
let package = case c of
|
|
CCEnvEmptyAndImport _ -> initEditMsgEmpty env'
|
|
_ -> showCurrentState env' state'
|
|
putStrLnFlush package
|
|
|
|
editLoop env' state' resume
|
|
|
|
-- | execute a command script and return a tree
|
|
execCommandHistory :: CEnv -> String -> IO (CEnv,Tree)
|
|
execCommandHistory env s = do
|
|
let env' = startEditEnv env
|
|
let state = initSStateEnv env'
|
|
(env',state') <- foldM exec (env,state) $ lines s
|
|
return $ (env',treeSState state')
|
|
|
|
where
|
|
|
|
exec (env,state) l = do
|
|
let c = pCommand l
|
|
execCommand env c state
|
|
|
|
|
|
|
|
getCommand :: IO Command
|
|
getCommand = do
|
|
s <- getLine
|
|
return $ pCommand s
|
|
|
|
-- | decodes UTF8 if u==False, i.e. if the grammar does not use UTF8;
|
|
-- used in the Java GUI, which always uses UTF8
|
|
getCommandUTF :: Bool -> IO [(String,Command)]
|
|
getCommandUTF u = do
|
|
s <- getLine
|
|
return $ pCommandMsgs $ if u then s else decodeUTF8 s
|
|
|
|
pCommandMsgs :: String -> [(String,Command)]
|
|
pCommandMsgs = map (pCommandMsg . unwords) . concatMap (chunks ";;" . words) . lines
|
|
|
|
pCommand :: String -> Command
|
|
pCommand = snd . pCommandMsg
|
|
|
|
|
|
pCommandMsg :: String -> (String,Command)
|
|
pCommandMsg s = (m,pCommandWords $ words c) where
|
|
(m,c) = case s of
|
|
'[':s2 -> let (a,b) = span (/=']') s2 in (a,drop 1 b)
|
|
_ -> ("",s)
|
|
pCommandWords s = case s of
|
|
"n" : cat : _ -> CNewCat cat
|
|
"t" : ws -> CNewTree $ unwords ws
|
|
"g" : ws -> CRefineWithTree $ unwords ws -- example: *g*ive
|
|
"p" : ws -> CRefineParse $ unwords ws
|
|
"rc": i : _ -> CRefineWithClip (readIntArg i)
|
|
">" : i : _ -> CAhead $ readIntArg i
|
|
">" : [] -> CAhead 1
|
|
"<" : i : _ -> CBack $ readIntArg i
|
|
"<" : [] -> CBack 1
|
|
">>" : _ -> CNextMeta
|
|
"<<" : _ -> CPrevMeta
|
|
"'" : _ -> CTop
|
|
"+" : _ -> CLast
|
|
"mp" : p -> CMovePosition (readIntList (unwords p))
|
|
"ct" : p:q:_ -> CCopyPosition (readIntList p) (readIntList q)
|
|
"r" : f : _ -> CRefineWithAtom f
|
|
"w" : f:i : _ -> CWrapWithFun (f, readIntArg i)
|
|
"ch": f : _ -> CChangeHead f
|
|
"ph": f:i : _ -> CPeelHead (f, readIntArg i)
|
|
"x" : ws -> CAlphaConvert $ unwords ws
|
|
"s" : i : _ -> CSelectCand (readIntArg i)
|
|
"f" : "unstructured" : _ -> CRemoveOption showStruct --- hmmm
|
|
"f" : "structured" : _ -> CAddOption showStruct --- hmmm
|
|
"f" : s : _ -> CAddOption (filterString s)
|
|
"u" : i : _ -> CUndo (readIntArg i)
|
|
"u" : _ -> CUndo 1
|
|
"d" : _ -> CDelete
|
|
"ac" : _ -> CAddClip
|
|
"pc": i : _ -> CRemoveClip (readIntArg i)
|
|
"c" : s : _ -> CTermCommand s
|
|
"a" : _ -> CRefineRandom --- *a*leatoire
|
|
"m" : _ -> CMenu
|
|
"ml" : s : _ -> changeMenuLanguage s
|
|
"ms" : s : _ -> changeMenuSize s
|
|
"mt" : s : _ -> changeMenuTyped s
|
|
"v" : _ -> CView
|
|
"q" : _ -> CQuit
|
|
"h" : _ -> CHelp initEditMsg
|
|
|
|
"i" : file: _ -> CCEnvImport file
|
|
"e" : [] -> CCEnvEmpty
|
|
"e" : file: _ -> CCEnvEmptyAndImport file
|
|
|
|
"open" : f: _ -> CCEnvOpenTerm f
|
|
"openstring": f: _ -> CCEnvOpenString f
|
|
|
|
"on" :lang: _ -> CCEnvOn lang
|
|
"off":lang: _ -> CCEnvOff lang
|
|
"pfile" :f:_ -> CCEnvRefineParse f
|
|
"tfile" :f:_ -> CCEnvRefineWithTree f
|
|
"save":l:f:_ -> CCEnvSave l f
|
|
|
|
-- openstring file
|
|
-- pfile file
|
|
-- tfile file
|
|
-- on lang
|
|
-- off lang
|
|
|
|
"gf": comm -> CCEnvGFShell (unwords comm)
|
|
|
|
[] -> CVoid
|
|
_ -> CError
|
|
|
|
-- | well, this lists the commands of the line-based editor
|
|
initEditMsg :: CEnv -> String
|
|
initEditMsg env = unlines $
|
|
"State-dependent editing commands are given in the menu:" :
|
|
" n [Cat] = new, r [Fun] = refine, w [Fun] [Int] = wrap,":
|
|
" ch [Fun] = change head, d = delete, s [Int] = select," :
|
|
" x [Var] [Var] = alpha convert." :
|
|
"Commands changing the environment:" :
|
|
" i [file] = import, e = empty." :
|
|
"Other commands:" :
|
|
" a = random, v = change view, u = undo, h = help, q = quit," :
|
|
" ml [Lang] = change menu language," :
|
|
" ms (short | long) = change menu command size," :
|
|
" mt (typed | untyped) = change menu item typing," :
|
|
" p [string] = refine by parsing, g [term] = refine by term," :
|
|
" > = down, < = up, ' = top, >> = next meta, << = previous meta." :
|
|
---- (" c [" ++ unwords (intersperse "|" allTermCommands) ++ "] = modify term") :
|
|
---- (" f [" ++ unwords (intersperse "|" allStringCommands) ++ "] = modify output") :
|
|
[]
|
|
|
|
initEditMsgEmpty :: CEnv -> String
|
|
initEditMsgEmpty env = initEditMsg env +++++ unlines (
|
|
"Start editing by n Cat selecting category\n\n" :
|
|
"-------------\n" :
|
|
["n" +++ cat | (_,cat) <- newCatMenu env]
|
|
)
|
|
|
|
showCurrentState :: CEnv -> SState -> String
|
|
showCurrentState env' state' =
|
|
unlines (tr ++ ["",""] ++ msg ++ ["",""] ++ map fst menu)
|
|
where (tr,msg,menu) = displaySStateIn env' state'
|
|
|
|
-- | to read position; borrowed from Prelude; should be elsewhere
|
|
readIntList :: String -> [Int]
|
|
readIntList s = case [x | (x,t) <- reads s, ("","") <- lex t] of
|
|
[x] -> x
|
|
_ -> []
|