@@ -15,13 +15,14 @@ import Control.Lens hiding (aside)
15
15
import Control.Monad.Except
16
16
import Control.Monad.Trans.Except
17
17
import Data.List (isPrefixOf , isSuffixOf )
18
+ import Data.List.NonEmpty (NonEmpty )
18
19
import Data.Map qualified as Map
19
- import Data.Semialign qualified as Align
20
20
import Data.Text qualified as Text
21
21
import Data.Text.IO qualified as Text
22
- import Data.These (These (.. ))
23
22
import Data.Vector qualified as Vector
24
23
import System.FilePath (takeFileName )
24
+ import Text.Numeral (defaultInflection )
25
+ import Text.Numeral.Language.ENG qualified as Numeral
25
26
import Text.Regex.TDFA ((=~) )
26
27
import Unison.Codebase (Codebase )
27
28
import Unison.Codebase.Branch (Branch0 )
@@ -83,35 +84,45 @@ parseInput codebase projPath currentProjectRoot numberedArgs patterns segments =
83
84
case segments of
84
85
[] -> throwE " "
85
86
command : args -> case Map. lookup command patterns of
86
- Just pat@ (InputPattern {parse , help}) -> do
87
+ Just pat@ (InputPattern {params , help, parse }) -> do
87
88
let expandedNumbers :: InputPattern. Arguments
88
89
expandedNumbers =
89
90
foldMap (\ arg -> maybe [Left arg] (fmap pure ) $ expandNumber numberedArgs arg) args
90
- lift (fzfResolve codebase projPath getCurrentBranch0 pat expandedNumbers) >>= \ case
91
- Left (NoFZFResolverForArgumentType _argDesc) -> throwError help
92
- Left (NoFZFOptions argDesc) -> throwError (noCompletionsMessage argDesc)
93
- Left FZFCancelled -> pure Nothing
94
- Right resolvedArgs -> do
95
- parsedInput <-
96
- except
97
- . first
98
- ( \ msg ->
99
- P. warnCallout $
100
- P. wrap " Sorry, I wasn’t sure how to process your request:"
101
- <> P. newline
102
- <> P. newline
103
- <> P. indentN 2 msg
104
- <> P. newline
105
- <> P. newline
106
- <> P. wrap
107
- ( " You can run"
108
- <> IPs. makeExample IPs. help [fromString command]
109
- <> " for more information on using"
110
- <> IPs. makeExampleEOS pat []
111
- )
112
- )
113
- $ parse resolvedArgs
114
- pure $ Just (Left command : resolvedArgs, parsedInput)
91
+ lift (fzfResolve codebase projPath getCurrentBranch0 params expandedNumbers)
92
+ >>= either
93
+ ( \ case
94
+ NoFZFResolverForArgumentType _argDesc -> throwError help
95
+ NoFZFOptions argDesc -> throwError (noCompletionsMessage argDesc)
96
+ FZFCancelled -> pure Nothing
97
+ FZFOversaturated extraArgs -> do
98
+ let showNum n = fromMaybe (tShow n) $ Numeral. us_cardinal defaultInflection n
99
+ maxCount <- maybe (throwError . P. text $ " Internal error: fuzzy finder complained that there are " <> showNum (length extraArgs) <> " too many arguments provided, but the command apparently allows an unbounded number of arguments." ) pure $ InputPattern. maxArgs params
100
+ let foundCount = showNum $ maxCount + length extraArgs
101
+ throwError . P. text $
102
+ " I expected no more than " <> showNum maxCount <> " arguments, but received " <> foundCount <> " ."
103
+ )
104
+ ( \ resolvedArgs -> do
105
+ parsedInput <-
106
+ except
107
+ . first
108
+ ( \ msg ->
109
+ P. warnCallout $
110
+ P. wrap " Sorry, I wasn’t sure how to process your request:"
111
+ <> P. newline
112
+ <> P. newline
113
+ <> P. indentN 2 msg
114
+ <> P. newline
115
+ <> P. newline
116
+ <> P. wrap
117
+ ( " You can run"
118
+ <> IPs. makeExample IPs. help [fromString command]
119
+ <> " for more information on using"
120
+ <> IPs. makeExampleEOS pat []
121
+ )
122
+ )
123
+ $ parse resolvedArgs
124
+ pure $ Just (Left command : resolvedArgs, parsedInput)
125
+ )
115
126
Nothing ->
116
127
throwE
117
128
. warn
@@ -151,50 +162,62 @@ expandNumber numberedArgs s =
151
162
_ -> Nothing
152
163
153
164
data FZFResolveFailure
154
- = NoFZFResolverForArgumentType InputPattern. ArgumentDescription
155
- | NoFZFOptions Text {- argument description -}
165
+ = NoFZFResolverForArgumentType InputPattern. ParameterDescription
166
+ | NoFZFOptions
167
+ -- | argument description
168
+ Text
156
169
| FZFCancelled
170
+ | -- | More arguments were provided than the command supports.
171
+ FZFOversaturated
172
+ -- | The arguments that couldn’t be assigned to a parameter.
173
+ (NonEmpty InputPattern. Argument )
157
174
158
- fzfResolve :: Codebase IO Symbol Ann -> PP. ProjectPath -> (IO (Branch0 IO )) -> InputPattern -> InputPattern. Arguments -> IO (Either FZFResolveFailure InputPattern. Arguments )
159
- fzfResolve codebase ppCtx getCurrentBranch pat args = runExceptT do
175
+ fzfResolve ::
176
+ Codebase IO Symbol Ann ->
177
+ PP. ProjectPath ->
178
+ (IO (Branch0 IO )) ->
179
+ InputPattern. Parameters ->
180
+ InputPattern. Arguments ->
181
+ IO (Either FZFResolveFailure InputPattern. Arguments )
182
+ fzfResolve codebase ppCtx getCurrentBranch params args = runExceptT do
160
183
-- We resolve args in two steps, first we check that all arguments that will require a fzf
161
184
-- resolver have one, and only if so do we prompt the user to actually do a fuzzy search.
162
185
-- Otherwise, we might ask the user to perform a search only to realize we don't have a resolver
163
186
-- for a later arg.
164
- argumentResolvers :: [ExceptT FZFResolveFailure IO InputPattern. Arguments ] <-
165
- ( Align. align ( InputPattern. args pat) args)
166
- & traverse \ case
167
- This (argName, opt, InputPattern. ArgumentType {fzfResolver})
168
- | opt == InputPattern. Required || opt == InputPattern. OnePlus ->
169
- case fzfResolver of
170
- Nothing -> throwError $ NoFZFResolverForArgumentType argName
171
- Just fzfResolver -> pure $ fuzzyFillArg opt argName fzfResolver
172
- | otherwise -> pure $ pure []
173
- That arg -> pure $ pure [arg]
174
- These _ arg -> pure $ pure [arg]
187
+ let argumentResolvers :: [ExceptT FZFResolveFailure IO InputPattern. Arguments ] =
188
+ either
189
+ ( pure . throwError . FZFOversaturated )
190
+ ( \ ( InputPattern. Parameters {requiredParams, trailingParams}, args) ->
191
+ args
192
+ <> map (meh False ) requiredParams
193
+ <> case trailingParams of
194
+ InputPattern. Optional _ _ -> mempty
195
+ InputPattern. OnePlus p -> pure $ meh True p
196
+ )
197
+ $ InputPattern. foldArgs ( \ (_, _) arg acc -> pure [arg] : acc) mempty params args
175
198
argumentResolvers & foldMapM id
176
199
where
177
- fuzzyFillArg :: InputPattern. IsOptional -> Text -> InputPattern. FZFResolver -> ExceptT FZFResolveFailure IO InputPattern. Arguments
178
- fuzzyFillArg opt argDesc InputPattern. FZFResolver {getOptions} = do
200
+ meh :: Bool -> InputPattern. Parameter -> ExceptT FZFResolveFailure IO InputPattern. Arguments
201
+ meh allowMulti (argName, InputPattern. ParameterType {fzfResolver}) =
202
+ maybe
203
+ (throwError $ NoFZFResolverForArgumentType argName)
204
+ (fuzzyFillArg allowMulti argName)
205
+ fzfResolver
206
+
207
+ fuzzyFillArg :: Bool -> Text -> InputPattern. FZFResolver -> ExceptT FZFResolveFailure IO InputPattern. Arguments
208
+ fuzzyFillArg allowMulti argDesc InputPattern. FZFResolver {getOptions} = do
179
209
currentBranch <- Branch. withoutTransitiveLibs <$> liftIO getCurrentBranch
180
210
options <- liftIO $ getOptions codebase ppCtx currentBranch
181
- when (null options) $ throwError $ NoFZFOptions argDesc
211
+ when (null options) . throwError $ NoFZFOptions argDesc
182
212
liftIO $ Text. putStrLn (FZFResolvers. fuzzySelectHeader argDesc)
183
213
results <-
184
- liftIO (Fuzzy. fuzzySelect Fuzzy. defaultOptions {Fuzzy. allowMultiSelect = multiSelectForOptional opt } id options)
214
+ liftIO (Fuzzy. fuzzySelect Fuzzy. defaultOptions {Fuzzy. allowMultiSelect = allowMulti } id options)
185
215
`whenNothingM` throwError FZFCancelled
186
216
-- If the user triggered the fuzzy finder, but selected nothing, abort the command rather than continuing execution
187
217
-- with no arguments.
188
218
if null results
189
219
then throwError FZFCancelled
190
220
else pure (Left . Text. unpack <$> results)
191
221
192
- multiSelectForOptional :: InputPattern. IsOptional -> Bool
193
- multiSelectForOptional = \ case
194
- InputPattern. Required -> False
195
- InputPattern. Optional -> False
196
- InputPattern. OnePlus -> True
197
- InputPattern. ZeroPlus -> True
198
-
199
222
prompt :: String
200
223
prompt = " > "
0 commit comments