@@ -22,6 +22,7 @@ import Data.List (intercalate, isPrefixOf, nub, sortBy, sort)
22import Data.Maybe (mapMaybe)
22import Data.Maybe (mapMaybe)
23import Data.Traversable (traverse)
23import Data.Traversable (traverse)
24import Data.Version (showVersion)
24import Data.Version (showVersion)
25+import Data.Char (isSpace)
25import qualified Data.Map as M
26import qualified Data.Map as M
27import Control.Applicative
28import Control.Applicative
@@ -155,7 +156,9 @@ expandTilde p = return p
156helpMessage :: String
157helpMessage :: String
157helpMessage = "The following commands are available:\n\n " ++
158helpMessage = "The following commands are available:\n\n " ++
158− intercalate "\n " (map (intercalate " ") C.help)
159+ intercalate "\n " (map line C.help)
160+ where line :: (String, String, String) -> String
161+ line (cmd, arg, desc) = intercalate " " [cmd, arg, replicate (11 - length arg) ' ', desc]
161-- The welcome prologue.
164-- The welcome prologue.
@@ -182,18 +185,60 @@ quitMessage = "See ya!"
183-- Haskeline completions
186-- Haskeline completions
188+data CompletionContext = Command String | FilePath | Module | Identifier | Fixed [String] | Multiple [CompletionContext]
192+-- Decide what kind of completion we need based on input.
193+completionContext :: String -> Maybe CompletionContext
194+completionContext cmd@"" = Just $ Multiple [Command cmd, Identifier]
195+completionContext cmd@(':' : _ )
196+ | cmd `elem` C.commands || cmd == ":" = Just $ Command cmd
197+completionContext (':' : c : _) = case c of
200+ 'm' -> Just FilePath
204+ 's' -> Just $ Fixed ["import", "loaded"]
205+ 't' -> Just Identifier
206+ 'k' -> Just Identifier
208+completionContext _ = Just Identifier
186-- Loads module, function, and file completions.
211-- Loads module, function, and file completions.
188completion :: CompletionFunc (StateT PSCiState IO)
213completion :: CompletionFunc (StateT PSCiState IO)
189−completion = completeWord Nothing " \t\n\r" findCompletions
214+completion = completeWordWithPrev Nothing " \t\n\r" findCompletions
191− findCompletions :: String -> StateT PSCiState IO [Completion]
216+ findCompletions :: String -> String -> StateT PSCiState IO [Completion]
192− findCompletions st = do
217+ findCompletions prev word = do
193− ms <- map snd . psciLoadedModules <$> get
218+ let ctx = completionContext $ (dropWhile isSpace (reverse prev)) ++ word
194− files <- listFiles st
219+ completions <- case ctx of
195− let matches = filter (isPrefixOf st) (names ms)
220+ Nothing -> return []
221+ (Just c) -> (mapMaybe $ either (\cand -> if word `isPrefixOf` cand
222+ then Just $ simpleCompletion cand
224+ <$> getCompletion c word
196− return $ sortBy sorter $ map simpleCompletion matches ++ files
225+ return $ sortBy sorter completions
227+ getCompletion :: CompletionContext -> String -> StateT PSCiState IO [Either String Completion]
228+ getCompletion (Command s) _ = return $ (map Left) $ filter (isPrefixOf s) C.commands
229+ getCompletion FilePath f = (map Right) <$> listFiles f
230+ getCompletion Module _ = (map Left) <$> getModuleNames
231+ getCompletion Identifier _ = (map Left) <$> getIdentNames
232+ getCompletion (Fixed list) _ = return $ (map Left) list
233+ getCompletion (Multiple contexts) f = concat <$> mapM (flip getCompletion $ f) contexts
235+ getLoadedModules :: StateT PSCiState IO [P.Module]
236+ getLoadedModules = map snd . psciLoadedModules <$> get
237+ getModuleNames :: StateT PSCiState IO [String]
238+ getModuleNames = moduleNames <$> getLoadedModules
239+ getIdentNames :: StateT PSCiState IO [String]
240+ getIdentNames = identNames <$> getLoadedModules
197 getDeclName :: Maybe [P.DeclarationRef] -> P.Declaration -> Maybe P.Ident
242 getDeclName :: Maybe [P.DeclarationRef] -> P.Declaration -> Maybe P.Ident
198 getDeclName Nothing (P.ValueDeclaration ident _ _ _) = Just ident
243 getDeclName Nothing (P.ValueDeclaration ident _ _ _) = Just ident
199 getDeclName (Just exts) (P.ValueDeclaration ident _ _ _) | isExported = Just ident
244 getDeclName (Just exts) (P.ValueDeclaration ident _ _ _) | isExported = Just ident
@@ -204,15 +249,19 @@ completion = completeWord Nothing " \t\n\r" findCompletions
204 exports _ = False
249 exports _ = False
205 getDeclName exts (P.PositionedDeclaration _ d) = getDeclName exts d
250 getDeclName exts (P.PositionedDeclaration _ d) = getDeclName exts d
206 getDeclName _ _ = Nothing
251 getDeclName _ _ = Nothing
207− names :: [P.Module] -> [String]
253+ identNames :: [P.Module] -> [String]
208− names ms = nub [ show qual
254+ identNames ms = nub [ show qual
209− | P.Module moduleName ds exts <- ms
255+ | P.Module moduleName ds exts <- ms
210− , ident <- mapMaybe (getDeclName exts) ds
256+ , ident <- mapMaybe (getDeclName exts) ds
211− , qual <- [ P.Qualified Nothing ident
257+ , qual <- [ P.Qualified Nothing ident
212− , P.Qualified (Just moduleName) ident]
258+ , P.Qualified (Just moduleName) ident]
260+ moduleNames :: [P.Module] -> [String]
261+ moduleNames ms = nub [show moduleName | P.Module moduleName _ _ <- ms]
214 sorter :: Completion -> Completion -> Ordering
263 sorter :: Completion -> Completion -> Ordering
215− sorter (Completion _ d1 _) (Completion _ d2 _) = compare d1 d2
264+ sorter (Completion _ d1 _) (Completion _ d2 _) = if ":" `isPrefixOf` d1 then LT else compare d1 d2
217-- Compilation
266-- Compilation