forked from commercialhaskell/stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCompletion.hs
More file actions
116 lines (108 loc) · 4.25 KB
/
Completion.hs
File metadata and controls
116 lines (108 loc) · 4.25 KB
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
module Stack.Options.Completion
( ghcOptsCompleter
, targetCompleter
, flagCompleter
, projectExeCompleter
) where
import Data.Char (isSpace)
import Data.List (isPrefixOf)
import qualified Data.Map as Map
import Data.Maybe
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Distribution.PackageDescription as C
import qualified Distribution.Types.UnqualComponentName as C
import Options.Applicative
import Options.Applicative.Builder.Extra
import Stack.Config (getLocalPackages)
import Stack.Options.GlobalParser (globalOptsFromMonoid)
import Stack.Runners (loadConfigWithOpts)
import Stack.Prelude hiding (lift)
import Stack.Setup
import Stack.Types.Config
import Stack.Types.FlagName
import Stack.Types.NamedComponent
import Stack.Types.PackageName
import System.Process (readProcess)
import Language.Haskell.TH.Syntax (runIO, lift)
ghcOptsCompleter :: Completer
ghcOptsCompleter = mkCompleter $ \inputRaw -> return $
let input = unescapeBashArg inputRaw
(curArgReversed, otherArgsReversed) = break isSpace (reverse input)
curArg = reverse curArgReversed
otherArgs = reverse otherArgsReversed
in if null curArg then [] else
map (otherArgs ++) $
filter (curArg `isPrefixOf`)
-- Technically, we should be consulting the user's current ghc,
-- but that would require loading up a BuildConfig.
$(runIO (readProcess "ghc" ["--show-options"] "") >>= lift . lines)
-- TODO: Ideally this would pay attention to --stack-yaml, may require
-- changes to optparse-applicative.
buildConfigCompleter
:: (String -> RIO EnvConfig [String])
-> Completer
buildConfigCompleter inner = mkCompleter $ \inputRaw -> do
let input = unescapeBashArg inputRaw
case input of
-- If it looks like a flag, skip this more costly completion.
('-': _) -> return []
_ -> do
let go = (globalOptsFromMonoid False mempty)
{ globalLogLevel = LevelOther "silent" }
loadConfigWithOpts go $ \lc -> do
bconfig <- liftIO $ lcLoadBuildConfig lc (globalCompiler go)
envConfig <- runRIO bconfig (setupEnv Nothing)
runRIO envConfig (inner input)
targetCompleter :: Completer
targetCompleter = buildConfigCompleter $ \input ->
filter (input `isPrefixOf`)
. concatMap allComponentNames
. Map.toList
. lpProject
<$> getLocalPackages
where
allComponentNames (name, lpv) =
map (T.unpack . renderPkgComponent . (name,)) (Set.toList (lpvComponents lpv))
flagCompleter :: Completer
flagCompleter = buildConfigCompleter $ \input -> do
lpvs <- fmap lpProject getLocalPackages
bconfig <- view buildConfigL
let wildcardFlags
= nubOrd
$ concatMap (\(name, lpv) ->
map (\fl -> "*:" ++ flagString name fl) (C.genPackageFlags (lpvGPD lpv)))
$ Map.toList lpvs
normalFlags
= concatMap (\(name, lpv) ->
map (\fl -> packageNameString name ++ ":" ++ flagString name fl)
(C.genPackageFlags (lpvGPD lpv)))
$ Map.toList lpvs
flagString name fl =
let flname = C.unFlagName $ C.flagName fl
in (if flagEnabled name fl then "-" else "") ++ flname
flagEnabled name fl =
fromMaybe (C.flagDefault fl) $
Map.lookup (fromCabalFlagName (C.flagName fl)) $
Map.findWithDefault Map.empty name (bcFlags bconfig)
return $ filter (input `isPrefixOf`) $
case input of
('*' : ':' : _) -> wildcardFlags
('*' : _) -> wildcardFlags
_ -> normalFlags
projectExeCompleter :: Completer
projectExeCompleter = buildConfigCompleter $ \input ->
filter (input `isPrefixOf`)
. nubOrd
. concatMap
(\(_, lpv) -> map
(C.unUnqualComponentName . fst)
(C.condExecutables (lpvGPD lpv))
)
. Map.toList
. lpProject
<$> getLocalPackages