@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Repl
34 ( Flags(..)
@@ -8,16 +9,18 @@ module Repl
89
910import Prelude hiding (lines, read)
1011import Control.Applicative ((<|>))
11−import Control.Monad.RWS (lift, liftIO)
12−import qualified Control.Monad.RWS as RWS
12+import Control.Monad.Trans (lift, liftIO)
13+import qualified Control.Monad.State.Strict as State
14+import qualified Data.ByteString as BS
1315import qualified Data.ByteString.Builder as B
16+import qualified Data.ByteString.Char8 as BSC
1417import qualified Data.ByteString.Lazy as LBS
18+import qualified Data.ByteString.UTF8 as BS_UTF8
19+import qualified Data.Char as Char
1520import qualified Data.List as List
1621import qualified Data.Map as Map
1722import Data.Monoid ((<>))
18−import qualified Data.Name as Name
19−import qualified Data.Text as Text
20−import qualified Data.Text.Encoding as Text
23+import qualified Data.Name as N
2124import qualified System.Console.Haskeline as Repl
2225import qualified System.Directory as Dir
2326import qualified System.Exit as Exit
@@ -25,16 +28,31 @@ import System.FilePath ((</>))
2528import qualified System.IO as IO
2629import qualified System.Process as Proc
2730
28−import qualified Elm.Compiler as Elm (version)
29−import qualified Elm.Project as Project
31+import qualified AST.Source as Src
32+import qualified Build
33+import qualified Elm.Constraint as C
34+import qualified Elm.Details as Details
35+import qualified Elm.Licenses as Licenses
36+import qualified Elm.ModuleName as ModuleName
37+import qualified Elm.Outline as Outline
3038import qualified Elm.Package as Pkg
31−import qualified Elm.PerUserCache as PerUserCache
32−import qualified Parse.Repl as Elm
39+import qualified Elm.Version as V
40+import qualified Generate
41+import qualified Parse.Expression as PE
42+import qualified Parse.Declaration as PD
43+import qualified Parse.Module as PM
44+import qualified Parse.Primitives as P
45+import Parse.Primitives (Row, Col)
46+import qualified Reporting
47+import qualified Reporting.Annotation as A
3348import Reporting.Doc ((<+>))
3449import qualified Reporting.Doc as D
50+import qualified Reporting.Error.Syntax as ES
51+import qualified Reporting.Exit as Exit
52+import qualified Reporting.Render.Code as Code
53+import qualified Reporting.Report as Report
3554import qualified Reporting.Task as Task
36−import qualified Reporting.Progress.Repl as Repl
37−import qualified Reporting.Render.Type.Localizer as L
55+import qualified Stuff
3856
3957
4058
@@ -43,174 +61,249 @@ import qualified Reporting.Render.Type.Localizer as L
4361
4462data Flags =
4563 Flags
46− { _interpreter :: Maybe FilePath
64+ { _maybeInterpreter :: Maybe FilePath
4765 , _noColors :: Bool
4866 }
4967
5068
5169run :: () -> Flags -> IO ()
52−run () (Flags maybeAlternateInterpreter noColors) =
53− do interpreter <- getInterpreter maybeAlternateInterpreter
54− _ <- Project.getRootWithReplFallback
55− printWelcomeMessage
70+run () flags =
71+ do printWelcomeMessage
5672 settings <- initSettings
57− let manager = Repl.runInputT settings (Repl.withInterrupt loop)
58− (exitCode,_,_) <- RWS.runRWST manager (interpreter, noColors) initialState
73+ env <- initEnv flags
74+ let looper = Repl.runInputT settings (Repl.withInterrupt (loop env initialState))
75+ exitCode <- State.evalStateT looper initialState
5976 Exit.exitWith exitCode
6077
6178
62−type Runner =
63− RWS.RWST (FilePath, Bool) () State IO
64−
65−
66−
67−-- LOOP
68−
69−
70−loop :: Repl.InputT Runner Exit.ExitCode
71−loop =
72− do input <- Repl.handleInterrupt (return Skip) read
73− maybe loop return =<< lift (eval input)
7479
80+-- WELCOME
7581
7682
77−-- READ
83+printWelcomeMessage :: IO ()
84+printWelcomeMessage =
85+ let
86+ vsn = V.toChars V.compiler
87+ title = "Elm" <+> D.fromChars vsn
88+ dashes = replicate (70 - length vsn) '-'
89+ in
90+ D.toAnsi IO.stdout $
91+ D.vcat
92+ [ D.black "----" <+> D.dullcyan title <+> D.black (D.fromChars dashes)
93+ , D.black $ D.fromChars $ "Say :help for help and :exit to exit! More at " <> D.makeLink "repl"
94+ , D.black "--------------------------------------------------------------------------------"
95+ , D.empty
96+ ]
7897
7998
80−read :: Repl.InputT Runner Input
81−read =
82− readHelp "> " []
8399
100+-- ENV
84101
85−readHelp :: String -> [String] -> Repl.InputT Runner Input
86−readHelp starter lines =
87− do input <- Repl.getInputLine starter
88− case input of
89− Nothing ->
90− return Exit
91102
92− Just line ->
93− if not (null line) && last line == '\\'
94− then readHelp "| " (init line : lines)
95− else return $ toInput $ List.intercalate "\n " $ reverse (line : lines)
103+data Env =
104+ Env
105+ { _root :: FilePath
106+ , _interpreter :: FilePath
107+ , _ansi :: Bool
108+ }
96109
97110
111+initEnv :: Flags -> IO Env
112+initEnv (Flags maybeAlternateInterpreter noColors) =
113+ do root <- getRoot
114+ interpreter <- getInterpreter maybeAlternateInterpreter
115+ return $ Env root interpreter (not noColors)
98116
99−-- EVAL
100117
101118
102−eval :: Input -> Runner (Maybe Exit.ExitCode)
103−eval input =
104− case input of
105− Skip ->
106− return Nothing
119+-- LOOP
107120
108− Exit ->
109− return (Just Exit.ExitSuccess)
110121
111− Reset ->
112− do RWS.put initialState
113− report "<reset>"
122+data Outcome
123+ = Loop State
124+ | End Exit.ExitCode
114125
115− Help info ->
116− report (helpMessage info)
117126
118− Code entry ->
119− Repl.handleInterrupt (report "<cancelled>") $
120− do state@(State _ imports types defs tricks localizer) <- RWS.get
121− case entry of
122− Elm.Import name alias exposing src ->
123− interpret None $
124− state
125− { _imports = Map.insert name src imports
126− , _localizer = L.replAdd name alias exposing localizer
127− }
127+type M =
128+ State.StateT State IO
128129
129− Elm.Type name src ->
130− interpret None $ state { _types = Map.insert name src types }
131130
132− Elm.Def (Just name) src ->
133− interpret (Def name) $ state { _defs = Map.insert name src defs }
131+loop :: Env -> State -> Repl.InputT M Exit.ExitCode
132+loop env state =
133+ do input <- Repl.handleInterrupt (return Skip) read
134+ outcome <- liftIO (eval env state input)
135+ case outcome of
136+ Loop state ->
137+ do lift (State.put state)
138+ loop env state
134139
135− Elm.Def Nothing src ->
136− interpret None $ state { _tricks = src : tricks }
140+ End exitCode ->
141+ return exitCode
137142
138− Elm.Other src ->
139− interpret (Expr src) state
140143
141− Elm.Annotation ->
142− report "I cannot handle type annotations."
143144
144− Elm.Port ->
145− report "I cannot handle port declarations."
145+-- READ
146146
147147
148−report :: String -> Runner (Maybe a)
149−report msg =
150− do liftIO (putStrLn msg)
151− return Nothing
148+data Input
149+ = Import ModuleName.Raw BS.ByteString
150+ | Type N.Name BS.ByteString
151+ | Port
152+ | Decl N.Name BS.ByteString
153+ | Expr BS.ByteString
154+ --
155+ | Reset
156+ | Exit
157+ | Skip
158+ | Help (Maybe String)
152159
153160
154−data Output = None | Def Name.Name | Expr Text.Text
161+read :: Repl.InputT M Input
162+read =
163+ do line <- Repl.getInputLine "> "
164+ case line of
165+ Nothing ->
166+ return Exit
155167
168+ Just chars ->
169+ case categorize chars of
170+ Done input -> return input
171+ Continue -> readMore chars
156172
157−interpret :: Output -> State -> Runner (Maybe a)
158−interpret def state =
159− do noColors <- RWS.asks snd
160− result <- liftIO $ Task.try Repl.reporter $ compile noColors def state
161173
162− case result of
174+readMore :: [Char] -> Repl.InputT M Input
175+readMore previousLines =
176+ do input <- Repl.getInputLineWithInitial "| " (" ","")
177+ case input of
163178 Nothing ->
164− return ()
179+ return Skip
165180
166− Just maybePath ->
167− do RWS.put (state { _count = _count state + 1 })
168− maybe (return ()) interpretHelp maybePath
181+ Just chars ->
182+ let
183+ allLines = previousLines ++ '\n' : chars
184+ in
185+ case categorize allLines of
186+ Done input -> return input
187+ Continue -> readMore allLines
169188
170− return Nothing
171189
172190
173−interpretHelp :: FilePath -> Runner ()
174−interpretHelp path =
175− do interpreter <- RWS.asks fst
176− let proc = (Proc.proc interpreter [path]) { Proc.std_in = Proc.CreatePipe }
177− liftIO $ Proc.withCreateProcess proc $ \_ _ _ handle ->
178− do _ <- Proc.waitForProcess handle
179− Dir.removeFile path
191+-- CATEGORIZE INPUT
180192
181193
194+data CategorizedInput
195+ = Done Input
196+ | Continue
182197
183−-- INPUT
184198
199+categorize :: [Char] -> CategorizedInput
200+categorize chars
201+ | all (==' ') chars = Done Skip
202+ | startsWithColon chars = Done (toCommand chars)
203+ | startsWithKeyword "import" chars = attemptImport chars
204+ | otherwise = attemptDeclOrExpr chars
185205
186−data Input
187− = Skip
188− | Exit
189− | Reset
190− | Help (Maybe String)
191− | Code Elm.Entry
192206
207+attemptImport :: [Char] -> CategorizedInput
208+attemptImport chars =
209+ let
210+ src = BS_UTF8.fromString (chars ++ "\n")
211+ parser = P.specialize (\_ _ _ -> ()) PM.chompImport
212+ in
213+ case P.fromByteString parser (\_ _ -> ()) src of
214+ Right (Src.Import (A.At _ name) _ _) ->
215+ Done (Import name src)
193216
194−toInput :: String -> Input
195−toInput string =
196− case dropWhile (==' ') string of
197− ":exit" ->
198− Exit
217+ Left () ->
218+ if endsWithBlankLine chars
219+ then Done (Import "ERR" src)
220+ else Continue
199221
200− ":help" ->
201− Help Nothing
202222
203− ":reset" ->
204− Reset
223+attemptDeclOrExpr :: [Char] -> CategorizedInput
224+attemptDeclOrExpr chars =
225+ let
226+ src = BS_UTF8.fromString (chars ++ "\n")
227+ exprParser = P.specialize (toExprPosition src) PE.expression
228+ declParser = P.specialize (toDeclPosition src) PD.declaration
229+ in
230+ case P.fromByteString declParser (,) src of
231+ Right (decl, _) ->
232+ case decl of
233+ PD.Value _ (A.At _ (Src.Value (A.At _ name) _ _ _)) -> Done (Decl name src)
234+ PD.Union _ (A.At _ (Src.Union (A.At _ name) _ _ )) -> Done (Type name src)
235+ PD.Alias _ (A.At _ (Src.Alias (A.At _ name) _ _ )) -> Done (Type name src)
236+ PD.Port _ _ -> Done Port
237+
238+ Left declPosition
239+ | startsWithKeyword "type" chars ->
240+ if endsWithBlankLine chars
241+ then Done (Type "ERR" src)
242+ else Continue
243+
244+ | startsWithKeyword "port" chars ->
245+ Done Port
246+
247+ | otherwise ->
248+ case P.fromByteString exprParser (,) src of
249+ Right _ ->
250+ Done (Expr src)
251+
252+ Left exprPosition ->
253+ if endsWithBlankLine chars
254+ then Done (if declPosition <= exprPosition then Expr src else Decl "ERR" src)
255+ else Continue
256+
257+
258+endsWithBlankLine :: [Char] -> Bool
259+endsWithBlankLine chars =
260+ case reverse (List.lines chars) of
261+ [] -> False
262+ cs:_ -> all (==' ') cs
263+
264+
265+startsWithColon :: [Char] -> Bool
266+startsWithColon chars =
267+ case dropWhile (==' ') chars of
268+ [] -> False
269+ c:_ -> c == ':'
270+
271+
272+toCommand :: [Char] -> Input
273+toCommand chars =
274+ case drop 1 $ dropWhile (==' ') chars of
275+ "reset" -> Reset
276+ "exit" -> Exit
277+ "quit" -> Exit
278+ "help" -> Help Nothing
279+ rest -> Help (Just (takeWhile (/=' ') rest))
280+
281+
282+startsWithKeyword :: [Char] -> [Char] -> Bool
283+startsWithKeyword keyword line =
284+ List.isPrefixOf keyword line &&
285+ case drop (length keyword) line of
286+ [] -> True
287+ c:_ -> not (Char.isAlphaNum c)
288+
289+
290+toExprPosition :: BS.ByteString -> ES.Expr -> Row -> Col -> (Row, Col)
291+toExprPosition src expr row col =
292+ let
293+ decl = ES.DeclDef N.replValueToPrint (ES.DeclDefBody expr row col) row col
294+ in
295+ toDeclPosition src decl row col
205296
206− ':' : rest ->
207− Help (Just (takeWhile (/=' ') rest))
208297
209− "" ->
210− Skip
298+toDeclPosition :: BS.ByteString -> ES.Decl -> Row -> Col -> (Row, Col)
299+toDeclPosition src decl r c =
300+ let
301+ err = ES.ParseError (ES.Declarations decl r c)
302+ report = ES.toReport (Code.toSource src) err
211303
212− _ ->
213− Code (Elm.parseEntry string)
304+ (Report.Report _ (A.Region (A.Position row col) _) _ _) = report
305+ in
306+ (row, col)
214307
215308
216309
@@ -219,132 +312,156 @@ toInput string =
219312
220313data State =
221314 State
222− { _count :: !Int
223− , _imports :: Map.Map Name.Name Text.Text
224− , _types :: Map.Map Name.Name Text.Text
225− , _defs :: Map.Map Name.Name Text.Text
226− , _tricks :: [Text.Text]
227− , _localizer :: L.Localizer
315+ { _imports :: Map.Map N.Name B.Builder
316+ , _types :: Map.Map N.Name B.Builder
317+ , _decls :: Map.Map N.Name B.Builder
228318 }
229319
230320
231321initialState :: State
232322initialState =
233− State 0 Map.empty Map.empty Map.empty [] L.replEmpty
323+ State Map.empty Map.empty Map.empty
234324
235325
236−compile :: Bool -> Output -> State -> Task.Task (Maybe FilePath)
237−compile noColors output (State count imports types defs tricks localizer) =
238− let
239− header =
240− "module " <> Name.toBuilder Name.replModule <> " exposing (..)\n\n"
241326
242− elmSourceCode =
243− (<>) header $
244− addLines imports $ addLines types $ addLines defs $
245− List.foldr (<>) mempty (map Text.encodeUtf8Builder tricks)
327+-- EVAL
246328
247− compileForRepl builder maybeName =
248− Project.compileForRepl noColors localizer (LBS.toStrict (B.toLazyByteString builder)) maybeName
249− in
250− case output of
251− None ->
252− if Map.null types && Map.null defs && null tricks then
253− compileForRepl (elmSourceCode <> "unit = ()") Nothing
254− else
255− compileForRepl elmSourceCode Nothing
256329
257− Def name ->
258− compileForRepl elmSourceCode (Just name)
330+eval :: Env -> State -> Input -> IO Outcome
331+eval env state@(State imports types decls) input =
332+ Repl.handleInterrupt (putStrLn "<cancelled>" >> return (Loop state)) $
333+ case input of
334+ Skip ->
335+ return (Loop state)
259336
260− Expr expr ->
261− let
262− name = Name.fromReplCount count
263− text = Text.replace "\n" "\n " expr
264− def = Name.toBuilder name <> " =\n " <> Text.encodeUtf8Builder text <> "\n"
265− in
266− compileForRepl (elmSourceCode <> def) (Just name)
337+ Exit ->
338+ return (End Exit.ExitSuccess)
267339
340+ Reset ->
341+ do putStrLn "<reset>"
342+ return (Loop initialState)
268343
269−addLines :: Map.Map Name.Name Text.Text -> B.Builder -> B.Builder
270−addLines dict builder =
271− Map.foldr (\text b -> Text.encodeUtf8Builder text <> "\n" <> b) builder dict
344+ Help maybeUnknownCommand ->
345+ do putStrLn (toHelpMessage maybeUnknownCommand)
346+ return (Loop state)
272347
348+ Import name src ->
349+ do let newState = state { _imports = Map.insert name (B.byteString src) imports }
350+ Loop <$> attemptEval env state newState OutputNothing
273351
352+ Type name src ->
353+ do let newState = state { _types = Map.insert name (B.byteString src) types }
354+ Loop <$> attemptEval env state newState OutputNothing
274355
275−-- SETTINGS
356+ Port ->
357+ do putStrLn "I cannot handle port declarations."
358+ return (Loop state)
276359
360+ Decl name src ->
361+ do let newState = state { _decls = Map.insert name (B.byteString src) decls }
362+ Loop <$> attemptEval env state newState (OutputDecl name)
277363
278−initSettings :: IO (Repl.Settings Runner)
279−initSettings =
280− do cache <- PerUserCache.getReplRoot
281− return $
282− Repl.Settings
283− { Repl.historyFile = Just (cache </> "history")
284− , Repl.autoAddHistory = True
285− , Repl.complete = Repl.completeWord Nothing " \n" lookupCompletions
286− }
364+ Expr src ->
365+ Loop <$> attemptEval env state state (OutputExpr src)
287366
288367
289−lookupCompletions :: String -> Runner [Repl.Completion]
290−lookupCompletions string =
291− do (State _ imports types defs _ _) <- RWS.get
292− return $
293− addMatches string False defs $
294− addMatches string False types $
295− addMatches string True imports $
296− addMatches string False commands []
297368
369+-- ATTEMPT EVAL
298370
299−commands :: Map.Map Name.Name ()
300−commands =
301− Map.fromList [ (":exit", ()), (":quit", ()), (":reset", ()), (":help", ()) ]
302371
372+data Output
373+ = OutputNothing
374+ | OutputDecl N.Name
375+ | OutputExpr BS.ByteString
303376
304−addMatches :: String -> Bool -> Map.Map Name.Name v -> [Repl.Completion] -> [Repl.Completion]
305−addMatches string isFinished dict completions =
306− Map.foldrWithKey (addMatch string isFinished) completions dict
307377
378+attemptEval :: Env -> State -> State -> Output -> IO State
379+attemptEval (Env root interpreter ansi) oldState newState output =
380+ do result <- Task.run $
381+ do details <-
382+ Task.eio Exit.ReplBadDetails $
383+ Details.load Reporting.silent root
308384
309−addMatch :: String -> Bool -> Name.Name -> v -> [Repl.Completion] -> [Repl.Completion]
310−addMatch string isFinished name _ completions =
311− let suggestion = Name.toString name in
312− if List.isPrefixOf string suggestion then
313− Repl.Completion suggestion suggestion isFinished : completions
314− else
315− completions
385+ artifacts <-
386+ Task.eio id $
387+ Build.fromRepl root details (toByteString newState output)
316388
389+ traverse (Task.mapError Exit.ReplBadGenerate . Generate.repl root details ansi artifacts) (toPrintName output)
317390
391+ case result of
392+ Left exit ->
393+ do Exit.toStderr (Exit.replToReport exit)
394+ return oldState
318395
319−-- WELCOME
396+ Right Nothing ->
397+ return newState
320398
399+ Right (Just javascript) ->
400+ do exitCode <- interpret interpreter javascript
401+ case exitCode of
402+ Exit.ExitSuccess -> return newState
403+ Exit.ExitFailure _ -> return oldState
321404
322−printWelcomeMessage :: IO ()
323−printWelcomeMessage =
405+
406+interpret :: FilePath -> B.Builder -> IO Exit.ExitCode
407+interpret interpreter javascript =
324408 let
325− title = "Elm" <+> D.fromString elmVersion
326− dashes = replicate (70 - length elmVersion) '-'
409+ createProcess = (Proc.proc interpreter []) { Proc.std_in = Proc.CreatePipe }
327410 in
328− D.toAnsi IO.stdout $
329− D.vcat
330− [ D.black "----" <+> D.dullcyan title <+> D.black (D.fromString dashes)
331− , D.black $ D.fromString $ "Say :help for help and :exit to exit! More at " <> D.makeLink "repl"
332− , D.black "--------------------------------------------------------------------------------"
333− , D.empty
411+ Proc.withCreateProcess createProcess $ \(Just stdin) _ _ handle ->
412+ do B.hPutBuilder stdin javascript
413+ IO.hClose stdin
414+ Proc.waitForProcess handle
415+
416+
417+
418+-- TO BYTESTRING
419+
420+
421+toByteString :: State -> Output -> BS.ByteString
422+toByteString (State imports types decls) output =
423+ LBS.toStrict $ B.toLazyByteString $
424+ mconcat
425+ [ "module ", N.toBuilder N.replModule, " exposing (..)\n"
426+ , Map.foldr mappend mempty imports
427+ , Map.foldr mappend mempty types
428+ , Map.foldr mappend mempty decls
429+ , outputToBuilder output
334430 ]
335431
336432
337−elmVersion :: String
338−elmVersion =
339− Pkg.versionToString Elm.version
433+outputToBuilder :: Output -> B.Builder
434+outputToBuilder output =
435+ case output of
436+ OutputNothing ->
437+ mempty
438+
439+ OutputDecl _ ->
440+ mempty
441+
442+ OutputExpr expr ->
443+ N.toBuilder N.replValueToPrint <> " ="
444+ <> foldr (\line rest -> "\n " <> B.byteString line <> rest) "\n" (BSC.lines expr)
445+
446+
447+
448+-- TO PRINT NAME
449+
450+
451+toPrintName :: Output -> Maybe N.Name
452+toPrintName output =
453+ case output of
454+ OutputNothing -> Nothing
455+ OutputDecl name -> Just name
456+ OutputExpr _ -> Just N.replValueToPrint
340457
341458
342459
343460-- HELP MESSAGES
344461
345462
346−helpMessage :: Maybe String -> String
347−helpMessage maybeBadCommand =
463+toHelpMessage :: Maybe String -> String
464+toHelpMessage maybeBadCommand =
348465 case maybeBadCommand of
349466 Nothing ->
350467 genericHelpMessage
@@ -365,6 +482,35 @@ genericHelpMessage =
365482
366483
367484
485+-- GET ROOT
486+
487+
488+getRoot :: IO FilePath
489+getRoot =
490+ do maybeRoot <- Stuff.findRoot
491+ case maybeRoot of
492+ Just root ->
493+ return root
494+
495+ Nothing ->
496+ do cache <- Stuff.getReplCache
497+ let root = cache </> "tmp"
498+ Dir.createDirectoryIfMissing True (root </> "src")
499+ Outline.write root $ Outline.Pkg $
500+ Outline.PkgOutline
501+ Pkg.dummyName
502+ Outline.defaultSummary
503+ Licenses.bsd3
504+ V.one
505+ (Outline.ExposedList [])
506+ (Map.singleton Pkg.core C.anything)
507+ Map.empty
508+ C.defaultElm
509+
510+ return root
511+
512+
513+
368514-- GET INTERPRETER
369515
370516
@@ -399,3 +545,54 @@ exeNotFound name =
399545 ++ "I could not find executable `" ++ name ++ "` on your PATH though!\n\n"
400546 ++ "You can install node.js from <http://nodejs.org/>. If it is already installed\n"
401547 ++ "but has a different name, use the --interpreter flag."
548+
549+
550+
551+-- SETTINGS
552+
553+
554+initSettings :: IO (Repl.Settings M)
555+initSettings =
556+ do cache <- Stuff.getReplCache
557+ return $
558+ Repl.Settings
559+ { Repl.historyFile = Just (cache </> "history")
560+ , Repl.autoAddHistory = True
561+ , Repl.complete = Repl.completeWord Nothing " \n" lookupCompletions
562+ }
563+
564+
565+lookupCompletions :: String -> M [Repl.Completion]
566+lookupCompletions string =
567+ do (State imports types decls) <- State.get
568+ return $
569+ addMatches string False decls $
570+ addMatches string False types $
571+ addMatches string True imports $
572+ addMatches string False commands []
573+
574+
575+commands :: Map.Map N.Name ()
576+commands =
577+ Map.fromList
578+ [ (":exit", ())
579+ , (":quit", ())
580+ , (":reset", ())
581+ , (":help", ())
582+ ]
583+
584+
585+addMatches :: String -> Bool -> Map.Map N.Name v -> [Repl.Completion] -> [Repl.Completion]
586+addMatches string isFinished dict completions =
587+ Map.foldrWithKey (addMatch string isFinished) completions dict
588+
589+
590+addMatch :: String -> Bool -> N.Name -> v -> [Repl.Completion] -> [Repl.Completion]
591+addMatch string isFinished name _ completions =
592+ let
593+ suggestion = N.toChars name
594+ in
595+ if List.isPrefixOf string suggestion then
596+ Repl.Completion suggestion suggestion isFinished : completions
597+ else
598+ completions