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
112 lines (104 loc) · 3.97 KB
/
Completion.hs
File metadata and controls
112 lines (104 loc) · 3.97 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
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# 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.Constants (ghcShowOptionsOutput)
import Stack.Options.GlobalParser (globalOptsFromMonoid)
import Stack.Runners
import Stack.Prelude
import Stack.Types.Config
import Stack.Types.NamedComponent
import Stack.Types.SourceMap
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`) ghcShowOptionsOutput
-- 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
go' <- globalOptsFromMonoid False mempty
let go = go' { globalLogLevel = LevelOther "silent" }
withRunnerGlobal go $ withConfig NoReexec $ withDefaultEnvConfig $ inner input
targetCompleter :: Completer
targetCompleter = buildConfigCompleter $ \input -> do
packages <- view $ buildConfigL.to (smwProject . bcSMWanted)
comps <- for packages ppComponents
pure
$ filter (input `isPrefixOf`)
$ concatMap allComponentNames
$ Map.toList comps
where
allComponentNames (name, comps) =
map (T.unpack . renderPkgComponent . (name,)) (Set.toList comps)
flagCompleter :: Completer
flagCompleter = buildConfigCompleter $ \input -> do
bconfig <- view buildConfigL
gpds <- for (smwProject $ bcSMWanted bconfig) ppGPD
let wildcardFlags
= nubOrd
$ concatMap (\(name, gpd) ->
map (\fl -> "*:" ++ flagString name fl) (C.genPackageFlags gpd))
$ Map.toList gpds
normalFlags
= concatMap (\(name, gpd) ->
map (\fl -> packageNameString name ++ ":" ++ flagString name fl)
(C.genPackageFlags gpd))
$ Map.toList gpds
flagString name fl =
let flname = C.unFlagName $ C.flagName fl
in (if flagEnabled name fl then "-" else "") ++ flname
prjFlags =
case configProject (bcConfig bconfig) of
PCProject (p, _) -> projectFlags p
PCGlobalProject -> mempty
PCNoProject _ -> mempty
flagEnabled name fl =
fromMaybe (C.flagDefault fl) $
Map.lookup (C.flagName fl) $
Map.findWithDefault Map.empty name prjFlags
return $ filter (input `isPrefixOf`) $
case input of
('*' : ':' : _) -> wildcardFlags
('*' : _) -> wildcardFlags
_ -> normalFlags
projectExeCompleter :: Completer
projectExeCompleter = buildConfigCompleter $ \input -> do
packages <- view $ buildConfigL.to (smwProject . bcSMWanted)
gpds <- Map.traverseWithKey (const ppGPD) packages
pure
$ filter (input `isPrefixOf`)
$ nubOrd
$ concatMap
(\gpd -> map
(C.unUnqualComponentName . fst)
(C.condExecutables gpd)
)
gpds