-
Notifications
You must be signed in to change notification settings - Fork 0
/
Completer.hs
85 lines (69 loc) · 2.22 KB
/
Completer.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
module Completer where
import System.Console.Haskeline
import System.Directory
import System.Environment
import Control.Monad
import Data.Maybe
import Data.List
import SubUtils
import Export
import Exec (builtins)
import Parse
import Data.Char
readLine :: String -> IO (Maybe String)
readLine prompt = runInputT settings (handleInterrupt lineIn $ withInterrupt $ lineIn)
where
lineIn :: InputT IO (Maybe String)
lineIn = getInputLine prompt
settings :: Settings IO
settings = setComplete comp defaultSettings
comp :: CompletionFunc IO
comp = completeWordWithPrev Nothing " " completer
completer :: String -> String -> IO [Completion]
completer prior word = case compType prior of
Exec -> compExec word
File -> compFile word
data CompType = Exec | File
compType :: String -> CompType
compType "" = Exec
compType w = let
lw = last . words $ w
thenExecWords = infixes ++ ["sudo","="]
in
if last lw == '(' || lw `elem` thenExecWords then Exec else File
compExec :: String -> IO [Completion]
compExec word = do
execs <- executables
let execs1 = execs ++ names --exports
let execs2 = execs1 ++ builtins
let (sym,_) = break isAlpha word
let opts = filter (isPrefix word) (map (sym ++ ) execs2)
return $ map simpleCompletion opts
compFile :: String -> IO [Completion]
compFile w = do
w' <- deTildify w
cs <- listFiles w'
tildifyComps cs
tildifyComps :: [Completion] -> IO [Completion]
tildifyComps = mapM liftTildify
liftTildify :: Completion -> IO Completion
liftTildify c = do
let r = replacement c
r' <- tildify r
return c{replacement=r'}
executables :: IO [String]
executables = do
maybePath <- lookupEnv "PATH"
let path = concat . map splitPath . maybeToList $ maybePath
goodPaths <- fmap concat $ mapM executablesIn path
let execNames = map (last . splitSlash) goodPaths
return $ map head . group . sort $ execNames
executablesIn :: String -> IO [String]
executablesIn path = do
valid <- doesDirectoryExist path
files <- if valid then listDirectory path else return []
let paths = [ path ++ "/" ++ file | file <- files ]
realPaths <- filterM doesFileExist paths
filterM isExecutable realPaths
isExecutable :: String -> IO Bool
isExecutable string = fmap executable $ getPermissions string