Greater customization of GHCi prompt
authorniksaz <nikitasazanovich@gmail.com>
Sun, 1 May 2016 11:34:45 +0000 (13:34 +0200)
committerBen Gamari <ben@smart-cactus.org>
Sun, 1 May 2016 21:29:49 +0000 (23:29 +0200)
This patch is trying to redesign the :set prompt option to take not a
String but a Haskell function, like [String] -> Int -> IO String, where
[String] is the list of the names of the currently loaded modules and
Int is the line number. Currently you may set prompt function with
**:set promt-function [String] -> Int -> IO String** option and old
version is also available - :set prompt String.

So, it looks like I've almost completed this patch:

1) Now we have a lot of escape sequences - 13 to be exact. Most of them
   are similar to bash prompt escape sequences. Thus they are quite handy.

2) We may use the special escape sequence to call shell functions, for
   example "%call(ls -l -a)".

3) We may use :set prompt-function to set PFunction to handle prompt.
   It is just [String] -> Int -> IO String.

Reviewers: erikd, austin, mpickering, bgamari

Reviewed By: mpickering, bgamari

Subscribers: mpickering, thomie

Differential Revision: https://phabricator.haskell.org/D2084

GHC Trac Issues: #5850

docs/users_guide/ghci.rst
ghc/GHCi/UI.hs
ghc/GHCi/UI/Monad.hs
testsuite/tests/ghci/scripts/all.T
testsuite/tests/ghci/scripts/ghci060.script [new file with mode: 0644]
testsuite/tests/ghci/scripts/ghci060.stderr [new file with mode: 0644]
testsuite/tests/ghci/scripts/ghci061.hs [new file with mode: 0644]
testsuite/tests/ghci/scripts/ghci061.script [new file with mode: 0644]
testsuite/tests/ghci/scripts/ghci061.stderr [new file with mode: 0644]

index a29f94c..5404701 100644 (file)
@@ -2469,17 +2469,51 @@ commonly used commands.
        single: GHCi prompt; setting
 
     Sets the string to be used as the prompt in GHCi. Inside ⟨prompt⟩,
-    the sequence ``%s`` is replaced by the names of the modules
-    currently in scope, ``%l`` is replaced by the line number (as
-    referenced in compiler messages) of the current prompt, and ``%%``
-    is replaced by ``%``. If ⟨prompt⟩ starts with ``"`` then it is parsed as
-    a Haskell String; otherwise it is treated as a literal string.
-
-.. ghci-cmd:: :set prompt2; ⟨prompt⟩
+    the next sequences are replaced:
+    
+    - ``%s`` by the names of the modules currently in scope.     
+    - ``%l`` by the line number (as referenced in compiler messages) of the
+      current prompt.
+    - ``%d`` by the date in "Weekday Month Date" format (e.g., "Tue May 26") .
+    - ``%t`` by the current time in 24-hour HH:MM:SS format.
+    - ``%T`` by the current time in 12-hour HH:MM:SS format. 
+    - ``%@`` by the current time in 12-hour am/pm format. 
+    - ``%A`` by the current time in 24-hour HH:MM format. 
+    - ``%u`` by the username of the current user. 
+    - ``%w`` by the current working directory.
+    - ``%o`` by the operating system.
+    - ``%a`` by the machine architecture. 
+    - ``%N`` by the compiler name.
+    - ``%V`` by the compiler version.
+    - ``%call(cmd [args])`` by the result of calling ``cmd args``.     
+    - ``%%`` by ``%``. 
+
+    If ⟨prompt⟩ starts with ``"`` then it is parsed as a Haskell String;
+    otherwise it is treated as a literal string.
+
+.. ghci-cmd:: :set prompt-cont; ⟨prompt⟩
 
     Sets the string to be used as the continuation prompt (used when
     using the :ghci-cmd:`:{` command) in GHCi.
 
+.. ghci-cmd:: :set prompt-function; <prompt-function>
+
+    .. index::
+       single: GHCi prompt function; setting
+
+    Sets the function to be used for the prompt displaying in GHCi. The 
+    function should be of the type ``[String] -> Int -> IO String``. This 
+    function is called each time the prompt is being made. The first argument
+    stands for the names of the modules currently in scope(the name of the 
+    "topmost" module  will begin with a ``*``; see  :ref:`ghci-scope` for 
+    more information). The second arguments is the line number (as referenced
+    in compiler  messages) of the current prompt.
+
+.. ghci-cmd:: :set prompt-cont-function; <prompt-function>
+
+   Sets the function to be used for the continuation prompt (used when
+   using the :ghci-cmd:`:{` command) displaying in GHCi.
+
 .. ghci-cmd:: :set stop; ⟨num⟩ ⟨cmd⟩
 
     Set a command to be executed when a breakpoint is hit, or a new item
index a335aea..c04bf2d 100644 (file)
@@ -96,6 +96,9 @@ import Data.List ( find, group, intercalate, intersperse, isPrefixOf, nub,
                    partition, sort, sortBy )
 import Data.Maybe
 import qualified Data.Map as M
+import Data.Time.LocalTime ( getZonedTime )
+import Data.Time.Format ( formatTime, defaultTimeLocale )
+import Data.Version ( showVersion )
 
 import Exception hiding (catch)
 import Foreign
@@ -105,6 +108,7 @@ import System.Directory
 import System.Environment
 import System.Exit ( exitWith, ExitCode(..) )
 import System.FilePath
+import System.Info
 import System.IO
 import System.IO.Error
 import System.IO.Unsafe ( unsafePerformIO )
@@ -113,6 +117,8 @@ import Text.Printf
 import Text.Read ( readMaybe )
 import Text.Read.Lex (isSymbolChar)
 
+import Unsafe.Coerce
+
 #ifndef mingw32_HOST_OS
 import System.Posix hiding ( getEnv )
 #else
@@ -129,8 +135,8 @@ data GhciSettings = GhciSettings {
         availableCommands :: [Command],
         shortHelpText     :: String,
         fullHelpText      :: String,
-        defPrompt         :: String,
-        defPrompt2        :: String
+        defPrompt         :: PromptFunction,
+        defPromptCont     :: PromptFunction
     }
 
 defaultGhciSettings :: GhciSettings
@@ -139,7 +145,7 @@ defaultGhciSettings =
         availableCommands = ghciCommands,
         shortHelpText     = defShortHelpText,
         defPrompt         = default_prompt,
-        defPrompt2        = default_prompt2,
+        defPromptCont     = default_prompt_cont,
         fullHelpText      = defFullHelpText
     }
 
@@ -328,7 +334,10 @@ defFullHelpText =
   "   :set args <arg> ...         set the arguments returned by System.getArgs\n" ++
   "   :set prog <progname>        set the value returned by System.getProgName\n" ++
   "   :set prompt <prompt>        set the prompt used in GHCi\n" ++
-  "   :set prompt2 <prompt>       set the continuation prompt used in GHCi\n" ++
+  "   :set prompt-cont <prompt>   set the continuation prompt used in GHCi\n" ++
+  "   :set prompt-function <expr> set the function to handle the prompt\n" ++
+  "   :set prompt-cont-function <expr>" ++
+                     "set the function to handle the continuation prompt\n" ++
   "   :set editor <cmd>           set the command used for :edit\n" ++
   "   :set stop [<n>] <cmd>       set the command to run when a breakpoint is hit\n" ++
   "   :unset <option> ...         unset options\n" ++
@@ -357,7 +366,7 @@ defFullHelpText =
   "   :show paths                 show the currently active search paths\n" ++
   "   :show language              show the currently active language flags\n" ++
   "   :show <setting>             show value of <setting>, which is one of\n" ++
-  "                                  [args, prog, prompt, editor, stop]\n" ++
+  "                                  [args, prog, editor, stop]\n" ++
   "   :showi language             show language flags for interactive evaluation\n" ++
   "\n"
 
@@ -372,12 +381,14 @@ findEditor = do
         return ""
 #endif
 
-default_progname, default_prompt, default_prompt2, default_stop :: String
+default_progname, default_stop :: String
 default_progname = "<interactive>"
-default_prompt = "%s> "
-default_prompt2 = "%s| "
 default_stop = ""
 
+default_prompt, default_prompt_cont :: PromptFunction
+default_prompt = generatePromptFunctionFromString "%s> "
+default_prompt_cont = generatePromptFunctionFromString "%s| "
+
 default_args :: [String]
 default_args = []
 
@@ -438,8 +449,8 @@ interactiveUI config srcs maybe_exprs = do
         GHCiState{ progname           = default_progname,
                    args               = default_args,
                    evalWrapper        = eval_wrapper,
-                   prompt             = defPrompt config,
-                   prompt2            = defPrompt2 config,
+                   prompt             = default_prompt,
+                   prompt_cont        = default_prompt_cont,
                    stop               = default_stop,
                    editor             = default_editor,
                    options            = [],
@@ -689,8 +700,23 @@ fileLoop hdl = do
            incrementLineNo
            return (Just l')
 
-mkPrompt :: GHCi String
-mkPrompt = do
+formatCurrentTime :: String -> IO String
+formatCurrentTime format =
+  getZonedTime >>= return . (formatTime defaultTimeLocale format)
+
+getUserName :: IO String
+getUserName = do
+#ifdef mingw32_HOST_OS
+  getEnv "USERNAME"
+    `catchIO` \e -> do
+      putStrLn $ show e
+      return ""
+#else
+  getLoginName
+#endif
+
+getInfoForPrompt :: GHCi (SDoc, [String], Int)
+getInfoForPrompt = do
   st <- getGHCiState
   imports <- GHC.getContext
   resumes <- GHC.getResumeContext
@@ -707,30 +733,127 @@ mkPrompt = do
                         pan <- GHC.getHistorySpan hist
                         return (brackets (ppr (negate ix) <> char ':'
                                           <+> ppr pan) <> space)
+
   let
         dots | _:rs <- resumes, not (null rs) = text "... "
              | otherwise = empty
 
         rev_imports = reverse imports -- rightmost are the most recent
-        modules_bit =
-             hsep [ char '*' <> ppr m | IIModule m <- rev_imports ] <+>
-             hsep (map ppr [ myIdeclName d | IIDecl d <- rev_imports ])
 
-         --  use the 'as' name if there is one
         myIdeclName d | Just m <- ideclAs d = m
                       | otherwise           = unLoc (ideclName d)
 
-        deflt_prompt = dots <> context_bit <> modules_bit
+        modules_names =
+             ['*':(moduleNameString m) | IIModule m <- rev_imports] ++
+             [moduleNameString (myIdeclName d) | IIDecl d <- rev_imports]
+        line = 1 + line_number st
+
+  return (dots <> context_bit, modules_names, line)
 
-        f ('%':'l':xs) = ppr (1 + line_number st) <> f xs
-        f ('%':'s':xs) = deflt_prompt <> f xs
-        f ('%':'%':xs) = char '%' <> f xs
-        f (x:xs) = char x <> f xs
-        f [] = empty
+parseCallEscape :: String -> (String, String)
+parseCallEscape s
+  | not (all isSpace beforeOpen) = ("", "")
+  | null sinceOpen               = ("", "")
+  | null sinceClosed             = ("", "")
+  | null cmd                     = ("", "")
+  | otherwise                    = (cmd, tail sinceClosed)
+  where
+    (beforeOpen, sinceOpen) = span (/='(') s
+    (cmd, sinceClosed) = span (/=')') (tail sinceOpen)
+
+checkPromptStringForErrors :: String -> Maybe String
+checkPromptStringForErrors ('%':'c':'a':'l':'l':xs) =
+  case parseCallEscape xs of
+    ("", "") -> Just ("Incorrect %call syntax. " ++
+                      "Should be %call(a command and arguments).")
+    (_, afterClosed) -> checkPromptStringForErrors afterClosed
+checkPromptStringForErrors ('%':'%':xs) = checkPromptStringForErrors xs
+checkPromptStringForErrors (_:xs) = checkPromptStringForErrors xs
+checkPromptStringForErrors "" = Nothing
+
+generatePromptFunctionFromString :: String -> PromptFunction
+generatePromptFunctionFromString promptS = \_ _ -> do
+    (context, modules_names, line) <- getInfoForPrompt
+
+    let
+        processString :: String -> GHCi SDoc
+        processString ('%':'s':xs) =
+            liftM2 (<>) (return modules_list) (processString xs)
+            where
+              modules_list = context <> modules_bit
+              modules_bit = hsep $ map text modules_names
+        processString ('%':'l':xs) =
+            liftM2 (<>) (return $ ppr line) (processString xs)
+        processString ('%':'d':xs) =
+            liftM2 (<>) (liftM text formatted_time) (processString xs)
+            where
+              formatted_time = liftIO $ formatCurrentTime "%a %b %d"
+        processString ('%':'t':xs) =
+            liftM2 (<>) (liftM text formatted_time) (processString xs)
+            where
+              formatted_time = liftIO $ formatCurrentTime "%H:%M:%S"
+        processString ('%':'T':xs) = do
+            liftM2 (<>) (liftM text formatted_time) (processString xs)
+            where
+              formatted_time = liftIO $ formatCurrentTime "%I:%M:%S"
+        processString ('%':'@':xs) = do
+            liftM2 (<>) (liftM text formatted_time) (processString xs)
+            where
+              formatted_time = liftIO $ formatCurrentTime "%I:%M %P"
+        processString ('%':'A':xs) = do
+            liftM2 (<>) (liftM text formatted_time) (processString xs)
+            where
+              formatted_time = liftIO $ formatCurrentTime "%H:%M"
+        processString ('%':'u':xs) =
+            liftM2 (<>) (liftM text user_name) (processString xs)
+            where
+              user_name = liftIO $ getUserName
+        processString ('%':'w':xs) =
+            liftM2 (<>) (liftM text current_directory) (processString xs)
+            where
+              current_directory = liftIO $ getCurrentDirectory
+        processString ('%':'o':xs) =
+            liftM ((text os) <>) (processString xs)
+        processString ('%':'a':xs) =
+            liftM ((text arch) <>) (processString xs)
+        processString ('%':'N':xs) =
+            liftM ((text compilerName) <>) (processString xs)
+        processString ('%':'V':xs) =
+            liftM ((text $ showVersion compilerVersion) <>) (processString xs)
+        processString ('%':'c':'a':'l':'l':xs) = do
+            respond <- liftIO $ do
+                (code, out, err) <-
+                    readProcessWithExitCode
+                    (head list_words) (tail list_words) ""
+                    `catchIO` \e -> return (ExitFailure 1, "", show e)
+                case code of
+                    ExitSuccess -> return out
+                    _ -> do
+                        hPutStrLn stderr err
+                        return ""
+            liftM ((text respond) <>) (processString afterClosed)
+            where
+              (cmd, afterClosed) = parseCallEscape xs
+              list_words = words cmd
+        processString ('%':'%':xs) =
+            liftM ((char '%') <>) (processString xs)
+        processString (x:xs) =
+            liftM (char x <>) (processString xs)
+        processString "" =
+            return empty
+
+    processString promptS
 
+mkPrompt :: GHCi String
+mkPrompt = do
+  st <- getGHCiState
   dflags <- getDynFlags
-  return (showSDoc dflags (f (prompt st)))
+  (context, modules_names, line) <- getInfoForPrompt
 
+  prompt_string <- (prompt st) modules_names line
+  let prompt_doc = context <> prompt_string
+
+  return (showSDoc dflags prompt_doc)
 
 queryQueue :: GHCi (Maybe String)
 queryQueue = do
@@ -811,7 +934,7 @@ runOneCommand eh gCmd = do
     multiLineCmd q = do
       st <- getGHCiState
       let p = prompt st
-      setGHCiState st{ prompt = prompt2 st }
+      setGHCiState st{ prompt = prompt_cont st }
       mb_cmd <- collectCommand q "" `GHC.gfinally`
                 modifyGHCiState (\st' -> st' { prompt = p })
       return mb_cmd
@@ -904,7 +1027,7 @@ checkInputForLayout stmt getStmt = do
      _other              -> do
        st1 <- getGHCiState
        let p = prompt st1
-       setGHCiState st1{ prompt = prompt2 st1 }
+       setGHCiState st1{ prompt = prompt_cont st1 }
        mb_stmt <- ghciHandle (\ex -> case fromException ex of
                             Just UserInterrupt -> return Nothing
                             _ -> case fromException ex of
@@ -2276,8 +2399,18 @@ setCmd str
         case toArgs rest of
             Right [prog] -> setProg prog
             _ -> liftIO (hPutStrLn stderr "syntax: :set prog <progname>")
-    Right ("prompt",  rest) -> setPrompt  $ dropWhile isSpace rest
-    Right ("prompt2", rest) -> setPrompt2 $ dropWhile isSpace rest
+
+    Right ("prompt",           rest) ->
+        setPromptString setPrompt (dropWhile isSpace rest)
+                        "syntax: set prompt <string>"
+    Right ("prompt-function",  rest) ->
+        setPromptFunc setPrompt $ dropWhile isSpace rest
+    Right ("prompt-cont",          rest) ->
+        setPromptString setPromptCont (dropWhile isSpace rest)
+                        "syntax: :set prompt-cont <string>"
+    Right ("prompt-cont-function", rest) ->
+        setPromptFunc setPromptCont $ dropWhile isSpace rest
+
     Right ("editor",  rest) -> setEditor  $ dropWhile isSpace rest
     Right ("stop",    rest) -> setStop    $ dropWhile isSpace rest
     _ -> case toArgs str of
@@ -2371,30 +2504,47 @@ setStop str@(c:_) | isDigit c
        setGHCiState st{ breaks = new_breaks }
 setStop cmd = modifyGHCiState (\st -> st { stop = cmd })
 
-setPrompt :: String -> GHCi ()
-setPrompt = setPrompt_ f err
-  where
-    f v st = st { prompt = v }
-    err st = "syntax: :set prompt <prompt>, currently \"" ++ prompt st ++ "\""
+setPrompt :: PromptFunction -> GHCi ()
+setPrompt v = modifyGHCiState (\st -> st {prompt = v})
 
-setPrompt2 :: String -> GHCi ()
-setPrompt2 = setPrompt_ f err
-  where
-    f v st = st { prompt2 = v }
-    err st = "syntax: :set prompt2 <prompt>, currently \"" ++ prompt2 st ++ "\""
+setPromptCont :: PromptFunction -> GHCi ()
+setPromptCont v = modifyGHCiState (\st -> st {prompt_cont = v})
 
-setPrompt_ :: (String -> GHCiState -> GHCiState) -> (GHCiState -> String) -> String -> GHCi ()
-setPrompt_ f err value = do
-  st <- getGHCiState
+setPromptFunc :: (PromptFunction -> GHCi ()) -> String -> GHCi ()
+setPromptFunc fSetPrompt s = do
+    -- We explicitly annotate the type of the expression to ensure
+    -- that unsafeCoerce# is passed the exact type necessary rather
+    -- than a more general one
+    let exprStr = "(" ++ s ++ ") :: [String] -> Int -> IO String"
+    (HValue funValue) <- GHC.compileExpr exprStr
+    fSetPrompt (convertToPromptFunction $ unsafeCoerce funValue)
+    where
+      convertToPromptFunction :: ([String] -> Int -> IO String)
+                              -> PromptFunction
+      convertToPromptFunction func = (\mods line -> liftIO $
+                                       liftM text (func mods line))
+
+setPromptString :: (PromptFunction -> GHCi ()) -> String -> String -> GHCi ()
+setPromptString fSetPrompt value err = do
   if null value
-      then liftIO $ hPutStrLn stderr $ err st
-      else case value of
-           '\"' : _ -> case reads value of
-                       [(value', xs)] | all isSpace xs ->
-                           setGHCiState $ f value' st
-                       _ ->
-                           liftIO $ hPutStrLn stderr "Can't parse prompt string. Use Haskell syntax."
-           _ -> setGHCiState $ f value st
+    then liftIO $ hPutStrLn stderr $ err
+    else case value of
+           ('\"':_) ->
+             case reads value of
+               [(value', xs)] | all isSpace xs ->
+                 setParsedPromptString fSetPrompt value'
+               _ -> liftIO $ hPutStrLn stderr
+                             "Can't parse prompt string. Use Haskell syntax."
+           _ ->
+             setParsedPromptString fSetPrompt value
+
+setParsedPromptString :: (PromptFunction -> GHCi ()) ->  String -> GHCi ()
+setParsedPromptString fSetPrompt s = do
+  case (checkPromptStringForErrors s) of
+    Just err ->
+      liftIO $ hPutStrLn stderr err
+    Nothing ->
+      fSetPrompt $ generatePromptFunctionFromString s
 
 setOptions wds =
    do -- first, deal with the GHCi opts (+s, +t, etc.)
@@ -2480,8 +2630,8 @@ unsetOptions str
          defaulters =
            [ ("args"   , setArgs default_args)
            , ("prog"   , setProg default_progname)
-           , ("prompt" , setPrompt default_prompt)
-           , ("prompt2", setPrompt2 default_prompt2)
+           , ("prompt"     , setPrompt default_prompt)
+           , ("prompt-cont", setPromptCont default_prompt_cont)
            , ("editor" , liftIO findEditor >>= setEditor)
            , ("stop"   , setStop default_stop)
            ]
@@ -2559,8 +2709,6 @@ showCmd str = do
         cmds =
             [ action "args"       $ liftIO $ putStrLn (show (GhciMonad.args st))
             , action "prog"       $ liftIO $ putStrLn (show (progname st))
-            , action "prompt"     $ liftIO $ putStrLn (show (prompt st))
-            , action "prompt2"    $ liftIO $ putStrLn (show (prompt2 st))
             , action "editor"     $ liftIO $ putStrLn (show (editor st))
             , action "stop"       $ liftIO $ putStrLn (show (stop st))
             , action "imports"    $ showImports
@@ -2868,7 +3016,8 @@ listHomeModules w = do
 
 completeSetOptions = wrapCompleter flagWordBreakChars $ \w -> do
   return (filter (w `isPrefixOf`) opts)
-    where opts = "args":"prog":"prompt":"prompt2":"editor":"stop":flagList
+    where opts = "args":"prog":"prompt":"prompt-cont":"prompt-function":
+                 "prompt-cont-function":"editor":"stop":flagList
           flagList = map head $ group $ sort allNonDeprecatedFlags
 
 completeSeti = wrapCompleter flagWordBreakChars $ \w -> do
@@ -2877,7 +3026,7 @@ completeSeti = wrapCompleter flagWordBreakChars $ \w -> do
 
 completeShowOptions = wrapCompleter flagWordBreakChars $ \w -> do
   return (filter (w `isPrefixOf`) opts)
-    where opts = ["args", "prog", "prompt", "prompt2", "editor", "stop",
+    where opts = ["args", "prog", "editor", "stop",
                      "modules", "bindings", "linker", "breaks",
                      "context", "packages", "paths", "language", "imports"]
 
index 306fa21..260d92c 100644 (file)
@@ -15,6 +15,7 @@ module GHCi.UI.Monad (
         GHCiState(..), setGHCiState, getGHCiState, modifyGHCiState,
         GHCiOption(..), isOptionSet, setOption, unsetOption,
         Command(..),
+        PromptFunction,
         BreakLocation(..),
         TickArray,
         getDynFlags,
@@ -67,8 +68,8 @@ data GHCiState = GHCiState
         progname       :: String,
         args           :: [String],
         evalWrapper    :: ForeignHValue, -- ^ of type @IO a -> IO a@
-        prompt         :: String,
-        prompt2        :: String,
+        prompt         :: PromptFunction,
+        prompt_cont    :: PromptFunction,
         editor         :: String,
         stop           :: String,
         options        :: [GHCiOption],
@@ -137,6 +138,10 @@ data Command
      -- ^ 'CompletionFunc' for arguments
    }
 
+type PromptFunction = [String]
+                   -> Int
+                   -> GHCi SDoc
+
 data GHCiOption
         = ShowTiming            -- show time/allocs after evaluation
         | ShowType              -- show the type of expressions
index 2d21772..6e9e91b 100755 (executable)
@@ -92,6 +92,9 @@ test('ghci056',
 
 test('ghci057', extra_hc_opts('-fwarn-tabs'), ghci_script, ['ghci057.script'])
 
+test('ghci060', normal, ghci_script, ['ghci060.script'])
+test('ghci061', normal, ghci_script, ['ghci061.script'])
+
 test('T2452', normal, ghci_script, ['T2452.script'])
 test('T2766', normal, ghci_script, ['T2766.script'])
 
diff --git a/testsuite/tests/ghci/scripts/ghci060.script b/testsuite/tests/ghci/scripts/ghci060.script
new file mode 100644 (file)
index 0000000..853512e
--- /dev/null
@@ -0,0 +1,7 @@
+:set prompt "%call()> "
+:set prompt "%call(pwd) %call()"
+:set prompt "%callasfasfasfsaf(pwd)"
+:set prompt "%call(pwd"
+:set prompt "%a> "
+:set prompt-cont "%call()| "
+:set prompt-cont "%t| "
diff --git a/testsuite/tests/ghci/scripts/ghci060.stderr b/testsuite/tests/ghci/scripts/ghci060.stderr
new file mode 100644 (file)
index 0000000..8f77a03
--- /dev/null
@@ -0,0 +1,5 @@
+Incorrect %call syntax. Should be %call(a command and arguments).
+Incorrect %call syntax. Should be %call(a command and arguments).
+Incorrect %call syntax. Should be %call(a command and arguments).
+Incorrect %call syntax. Should be %call(a command and arguments).
+Incorrect %call syntax. Should be %call(a command and arguments).
diff --git a/testsuite/tests/ghci/scripts/ghci061.hs b/testsuite/tests/ghci/scripts/ghci061.hs
new file mode 100644 (file)
index 0000000..2779bb5
--- /dev/null
@@ -0,0 +1,5 @@
+two_args :: [String] -> IO String
+two_args _ = return "two_args> "
+
+three_args :: [String] -> Int -> IO String
+three_args _ _ = return $ "three_args> "
diff --git a/testsuite/tests/ghci/scripts/ghci061.script b/testsuite/tests/ghci/scripts/ghci061.script
new file mode 100644 (file)
index 0000000..2d96b16
--- /dev/null
@@ -0,0 +1,5 @@
+:l ghci061.hs
+:set prompt-function two_args
+:set prompt-function three_args
+:set prompt-cont-function two_args
+:set prompt-cont-function three_args
diff --git a/testsuite/tests/ghci/scripts/ghci061.stderr b/testsuite/tests/ghci/scripts/ghci061.stderr
new file mode 100644 (file)
index 0000000..1ba00c5
--- /dev/null
@@ -0,0 +1,16 @@
+
+<interactive>:1:2: error:
+    • Couldn't match type ‘IO String’ with ‘Int -> IO String’
+      Expected type: [String] -> Int -> IO String
+        Actual type: [String] -> IO String
+    • In the expression: (two_args) :: [String] -> Int -> IO String
+      In an equation for ‘_compileParsedExpr’:
+          _compileParsedExpr = (two_args) :: [String] -> Int -> IO String
+
+<interactive>:1:2: error:
+    • Couldn't match type ‘IO String’ with ‘Int -> IO String’
+      Expected type: [String] -> Int -> IO String
+        Actual type: [String] -> IO String
+    • In the expression: (two_args) :: [String] -> Int -> IO String
+      In an equation for ‘_compileParsedExpr’:
+          _compileParsedExpr = (two_args) :: [String] -> Int -> IO String