From 27c2f00b6bd9296024dc7f07e45778709ab30e7a Mon Sep 17 00:00:00 2001 From: Spencer Janssen Date: Tue, 16 Oct 2007 11:05:52 +0200 Subject: ShellPrompt: traverse $PATH once per invocation. Major speed improvement darcs-hash:20071016090552-a5988-eed1d245021b0284bcd5b90f1fdc93d59eb2dd7f.gz --- ShellPrompt.hs | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'ShellPrompt.hs') diff --git a/ShellPrompt.hs b/ShellPrompt.hs index 9ff06c3..5dfb445 100644 --- a/ShellPrompt.hs +++ b/ShellPrompt.hs @@ -52,31 +52,35 @@ data Shell = Shell instance XPrompt Shell where showXPrompt Shell = "Run: " - shellPrompt :: XPConfig -> X () -shellPrompt c = mkXPrompt Shell c getShellCompl spawn - -getShellCompl :: String -> IO [String] -getShellCompl s - | s /= "" && last s /= ' ' = do - f <- fmap lines $ runProcessWithInput "/bin/bash" [] ("compgen -A file " ++ s ++ "\n") - c <- commandCompletionFunction s - return . map escape . sort . (toList . fromList) $ f ++ c - | otherwise = return [] - -commandCompletionFunction :: String -> IO [String] -commandCompletionFunction str - | '/' `elem` str = return [] - | otherwise = do - p <- getEnv "PATH" `catch` const (return []) - let ds = split ':' p - fp d f = d ++ "/" ++ f - es <- forM ds $ \d -> do - exists <- doesDirectoryExist d - if exists - then getDirectoryContents d >>= filterM (isExecutable . fp d) - else return [] - return . filter (isPrefixOf str) . concat $ es +shellPrompt c = do + cmds <- io $ getCommands + mkXPrompt Shell c (getShellCompl cmds) spawn + +getShellCompl :: [String] -> String -> IO [String] +getShellCompl cmds s | s == "" || last s == ' ' = return [] + | otherwise = do + f <- fmap lines $ runProcessWithInput "/bin/bash" [] ("compgen -A file " ++ s ++ "\n") + return . map escape . uniqSort $ f ++ commandCompletionFunction cmds s + +uniqSort :: Ord a => [a] -> [a] +uniqSort = toList . fromList + +commandCompletionFunction :: [String] -> String -> [String] +commandCompletionFunction cmds str | '/' `elem` str = [] + | otherwise = filter (isPrefixOf str) cmds + +getCommands :: IO [String] +getCommands = do + p <- getEnv "PATH" `catch` const (return []) + let ds = split ':' p + fp d f = d ++ "/" ++ f + es <- forM ds $ \d -> do + exists <- doesDirectoryExist d + if exists + then getDirectoryContents d >>= filterM (isExecutable . fp d) + else return [] + return . uniqSort . concat $ es isExecutable :: FilePath ->IO Bool isExecutable f = do -- cgit v1.2.3