{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ViewPatterns #-}
module Unison.CommandLine.InputPattern
( InputPattern (..),
Argument,
ArgumentType (..),
ArgumentDescription,
Arguments,
argType,
FZFResolver (..),
IsOptional (..),
Visibility (..),
minArgs,
maxArgs,
unionSuggestions,
suggestionFallbacks,
)
where
import Control.Lens
import Data.List.Extra qualified as List
import System.Console.Haskeline qualified as Line
import Unison.Auth.HTTPClient (AuthenticatedHttpClient)
import Unison.Codebase (Codebase)
import Unison.Codebase.Editor.Input (Input (..))
import Unison.Codebase.Editor.StructuredArgument (StructuredArgument)
import Unison.Codebase.ProjectPath qualified as PP
import Unison.CommandLine.FZFResolvers (FZFResolver (..))
import Unison.Prelude
import Unison.Util.ColorText qualified as CT
import Unison.Util.Monoid (foldMapM)
import Unison.Util.Pretty qualified as P
data IsOptional
= Required
| Optional
| ZeroPlus
| OnePlus
deriving (Int -> IsOptional -> ShowS
[IsOptional] -> ShowS
IsOptional -> [Char]
(Int -> IsOptional -> ShowS)
-> (IsOptional -> [Char])
-> ([IsOptional] -> ShowS)
-> Show IsOptional
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> IsOptional -> ShowS
showsPrec :: Int -> IsOptional -> ShowS
$cshow :: IsOptional -> [Char]
show :: IsOptional -> [Char]
$cshowList :: [IsOptional] -> ShowS
showList :: [IsOptional] -> ShowS
Show, IsOptional -> IsOptional -> Bool
(IsOptional -> IsOptional -> Bool)
-> (IsOptional -> IsOptional -> Bool) -> Eq IsOptional
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: IsOptional -> IsOptional -> Bool
== :: IsOptional -> IsOptional -> Bool
$c/= :: IsOptional -> IsOptional -> Bool
/= :: IsOptional -> IsOptional -> Bool
Eq)
data Visibility = Hidden | Visible
deriving (Int -> Visibility -> ShowS
[Visibility] -> ShowS
Visibility -> [Char]
(Int -> Visibility -> ShowS)
-> (Visibility -> [Char])
-> ([Visibility] -> ShowS)
-> Show Visibility
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Visibility -> ShowS
showsPrec :: Int -> Visibility -> ShowS
$cshow :: Visibility -> [Char]
show :: Visibility -> [Char]
$cshowList :: [Visibility] -> ShowS
showList :: [Visibility] -> ShowS
Show, Visibility -> Visibility -> Bool
(Visibility -> Visibility -> Bool)
-> (Visibility -> Visibility -> Bool) -> Eq Visibility
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Visibility -> Visibility -> Bool
== :: Visibility -> Visibility -> Bool
$c/= :: Visibility -> Visibility -> Bool
/= :: Visibility -> Visibility -> Bool
Eq, Eq Visibility
Eq Visibility =>
(Visibility -> Visibility -> Ordering)
-> (Visibility -> Visibility -> Bool)
-> (Visibility -> Visibility -> Bool)
-> (Visibility -> Visibility -> Bool)
-> (Visibility -> Visibility -> Bool)
-> (Visibility -> Visibility -> Visibility)
-> (Visibility -> Visibility -> Visibility)
-> Ord Visibility
Visibility -> Visibility -> Bool
Visibility -> Visibility -> Ordering
Visibility -> Visibility -> Visibility
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Visibility -> Visibility -> Ordering
compare :: Visibility -> Visibility -> Ordering
$c< :: Visibility -> Visibility -> Bool
< :: Visibility -> Visibility -> Bool
$c<= :: Visibility -> Visibility -> Bool
<= :: Visibility -> Visibility -> Bool
$c> :: Visibility -> Visibility -> Bool
> :: Visibility -> Visibility -> Bool
$c>= :: Visibility -> Visibility -> Bool
>= :: Visibility -> Visibility -> Bool
$cmax :: Visibility -> Visibility -> Visibility
max :: Visibility -> Visibility -> Visibility
$cmin :: Visibility -> Visibility -> Visibility
min :: Visibility -> Visibility -> Visibility
Ord)
type Argument = Either String StructuredArgument
type Arguments = [Argument]
type ArgumentDescription = Text
data InputPattern = InputPattern
{ InputPattern -> [Char]
patternName :: String,
InputPattern -> [[Char]]
aliases :: [String],
InputPattern -> Visibility
visibility :: Visibility,
InputPattern -> [(ArgumentDescription, IsOptional, ArgumentType)]
args :: [(ArgumentDescription, IsOptional, ArgumentType)],
InputPattern -> Pretty ColorText
help :: P.Pretty CT.ColorText,
InputPattern -> Arguments -> Either (Pretty ColorText) Input
parse ::
Arguments ->
Either (P.Pretty CT.ColorText) Input
}
data ArgumentType = ArgumentType
{ ArgumentType -> [Char]
typeName :: String,
ArgumentType
-> forall (m :: * -> *) v a.
MonadIO m =>
[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
suggestions ::
forall m v a.
(MonadIO m) =>
String ->
Codebase m v a ->
AuthenticatedHttpClient ->
PP.ProjectPath ->
m [Line.Completion],
ArgumentType -> Maybe FZFResolver
fzfResolver :: Maybe FZFResolver
}
instance Show ArgumentType where
show :: ArgumentType -> [Char]
show ArgumentType
at = [Char]
"ArgumentType " [Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> ArgumentType -> [Char]
typeName ArgumentType
at
argInfo :: InputPattern -> Int -> Maybe (ArgumentDescription, ArgumentType)
argInfo :: InputPattern -> Int -> Maybe (ArgumentDescription, ArgumentType)
argInfo InputPattern {[(ArgumentDescription, IsOptional, ArgumentType)]
$sel:args:InputPattern :: InputPattern -> [(ArgumentDescription, IsOptional, ArgumentType)]
args :: [(ArgumentDescription, IsOptional, ArgumentType)]
args, [Char]
$sel:patternName:InputPattern :: InputPattern -> [Char]
patternName :: [Char]
patternName} Int
i = (Int, [(ArgumentDescription, IsOptional, ArgumentType)])
-> Maybe (ArgumentDescription, ArgumentType)
go (Int
i, [(ArgumentDescription, IsOptional, ArgumentType)]
args)
where
go :: (Int, [(Text, IsOptional, ArgumentType)]) -> Maybe (ArgumentDescription, ArgumentType)
go :: (Int, [(ArgumentDescription, IsOptional, ArgumentType)])
-> Maybe (ArgumentDescription, ArgumentType)
go (Int
_, []) = Maybe (ArgumentDescription, ArgumentType)
forall a. Maybe a
Nothing
go (Int
0, (ArgumentDescription
argName, IsOptional
_, ArgumentType
t) : [(ArgumentDescription, IsOptional, ArgumentType)]
_) = (ArgumentDescription, ArgumentType)
-> Maybe (ArgumentDescription, ArgumentType)
forall a. a -> Maybe a
Just (ArgumentDescription
argName, ArgumentType
t)
go (Int
_, [(ArgumentDescription
argName, IsOptional
ZeroPlus, ArgumentType
t)]) = (ArgumentDescription, ArgumentType)
-> Maybe (ArgumentDescription, ArgumentType)
forall a. a -> Maybe a
Just (ArgumentDescription
argName, ArgumentType
t)
go (Int
_, [(ArgumentDescription
argName, IsOptional
OnePlus, ArgumentType
t)]) = (ArgumentDescription, ArgumentType)
-> Maybe (ArgumentDescription, ArgumentType)
forall a. a -> Maybe a
Just (ArgumentDescription
argName, ArgumentType
t)
go (Int
n, (ArgumentDescription
_argName, IsOptional
o, ArgumentType
_) : [(ArgumentDescription, IsOptional, ArgumentType)]
argTypes)
| IsOptional
o IsOptional -> IsOptional -> Bool
forall a. Eq a => a -> a -> Bool
== IsOptional
Optional Bool -> Bool -> Bool
|| IsOptional
o IsOptional -> IsOptional -> Bool
forall a. Eq a => a -> a -> Bool
== IsOptional
Required = (Int, [(ArgumentDescription, IsOptional, ArgumentType)])
-> Maybe (ArgumentDescription, ArgumentType)
go (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, [(ArgumentDescription, IsOptional, ArgumentType)]
argTypes)
go (Int, [(ArgumentDescription, IsOptional, ArgumentType)])
args =
[Char] -> Maybe (ArgumentDescription, ArgumentType)
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe (ArgumentDescription, ArgumentType))
-> [Char] -> Maybe (ArgumentDescription, ArgumentType)
forall a b. (a -> b) -> a -> b
$
[Char]
"Input pattern "
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> ShowS
forall a. Show a => a -> [Char]
show [Char]
patternName
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Char]
" has an invalid argument list: "
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> (Int, [(ArgumentDescription, IsOptional, ArgumentType)]) -> [Char]
forall a. Show a => a -> [Char]
show (Int, [(ArgumentDescription, IsOptional, ArgumentType)])
args
argType :: InputPattern -> Int -> Maybe ArgumentType
argType :: InputPattern -> Int -> Maybe ArgumentType
argType InputPattern
ip Int
i = (ArgumentDescription, ArgumentType) -> ArgumentType
forall a b. (a, b) -> b
snd ((ArgumentDescription, ArgumentType) -> ArgumentType)
-> Maybe (ArgumentDescription, ArgumentType) -> Maybe ArgumentType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (InputPattern -> Int -> Maybe (ArgumentDescription, ArgumentType)
argInfo InputPattern
ip Int
i)
minArgs :: InputPattern -> Int
minArgs :: InputPattern -> Int
minArgs (InputPattern {[(ArgumentDescription, IsOptional, ArgumentType)]
$sel:args:InputPattern :: InputPattern -> [(ArgumentDescription, IsOptional, ArgumentType)]
args :: [(ArgumentDescription, IsOptional, ArgumentType)]
args, [Char]
$sel:patternName:InputPattern :: InputPattern -> [Char]
patternName :: [Char]
patternName}) =
[IsOptional] -> Int
go ([(ArgumentDescription, IsOptional, ArgumentType)]
args [(ArgumentDescription, IsOptional, ArgumentType)]
-> Getting
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)]
IsOptional
-> [IsOptional]
forall s a. s -> Getting (Endo [a]) s a -> [a]
^.. ((ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional])
(ArgumentDescription, IsOptional, ArgumentType))
-> [(ArgumentDescription, IsOptional, ArgumentType)]
-> Const
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)]
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold
Int
[(ArgumentDescription, IsOptional, ArgumentType)]
(ArgumentDescription, IsOptional, ArgumentType)
folded (((ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional])
(ArgumentDescription, IsOptional, ArgumentType))
-> [(ArgumentDescription, IsOptional, ArgumentType)]
-> Const
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)])
-> ((IsOptional -> Const (Endo [IsOptional]) IsOptional)
-> (ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional])
(ArgumentDescription, IsOptional, ArgumentType))
-> Getting
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)]
IsOptional
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IsOptional -> Const (Endo [IsOptional]) IsOptional)
-> (ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional]) (ArgumentDescription, IsOptional, ArgumentType)
forall s t a b. Field2 s t a b => Lens s t a b
Lens
(ArgumentDescription, IsOptional, ArgumentType)
(ArgumentDescription, IsOptional, ArgumentType)
IsOptional
IsOptional
_2)
where
go :: [IsOptional] -> Int
go [] = Int
0
go (IsOptional
Required : [IsOptional]
argTypes) = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [IsOptional] -> Int
go [IsOptional]
argTypes
go [IsOptional
_] = Int
0
go [IsOptional]
_ =
[Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char] -> Int) -> [Char] -> Int
forall a b. (a -> b) -> a -> b
$
[Char]
"Invalid args for InputPattern ("
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> ShowS
forall a. Show a => a -> [Char]
show [Char]
patternName
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Char]
"): "
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> [(ArgumentDescription, IsOptional, ArgumentType)] -> [Char]
forall a. Show a => a -> [Char]
show [(ArgumentDescription, IsOptional, ArgumentType)]
args
maxArgs :: InputPattern -> Maybe Int
maxArgs :: InputPattern -> Maybe Int
maxArgs (InputPattern {[(ArgumentDescription, IsOptional, ArgumentType)]
$sel:args:InputPattern :: InputPattern -> [(ArgumentDescription, IsOptional, ArgumentType)]
args :: [(ArgumentDescription, IsOptional, ArgumentType)]
args, [Char]
$sel:patternName:InputPattern :: InputPattern -> [Char]
patternName :: [Char]
patternName}) = [IsOptional] -> Maybe Int
go [IsOptional]
argTypes
where
argTypes :: [IsOptional]
argTypes = [(ArgumentDescription, IsOptional, ArgumentType)]
args [(ArgumentDescription, IsOptional, ArgumentType)]
-> Getting
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)]
IsOptional
-> [IsOptional]
forall s a. s -> Getting (Endo [a]) s a -> [a]
^.. ((ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional])
(ArgumentDescription, IsOptional, ArgumentType))
-> [(ArgumentDescription, IsOptional, ArgumentType)]
-> Const
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)]
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold
Int
[(ArgumentDescription, IsOptional, ArgumentType)]
(ArgumentDescription, IsOptional, ArgumentType)
folded (((ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional])
(ArgumentDescription, IsOptional, ArgumentType))
-> [(ArgumentDescription, IsOptional, ArgumentType)]
-> Const
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)])
-> ((IsOptional -> Const (Endo [IsOptional]) IsOptional)
-> (ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional])
(ArgumentDescription, IsOptional, ArgumentType))
-> Getting
(Endo [IsOptional])
[(ArgumentDescription, IsOptional, ArgumentType)]
IsOptional
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IsOptional -> Const (Endo [IsOptional]) IsOptional)
-> (ArgumentDescription, IsOptional, ArgumentType)
-> Const
(Endo [IsOptional]) (ArgumentDescription, IsOptional, ArgumentType)
forall s t a b. Field2 s t a b => Lens s t a b
Lens
(ArgumentDescription, IsOptional, ArgumentType)
(ArgumentDescription, IsOptional, ArgumentType)
IsOptional
IsOptional
_2
go :: [IsOptional] -> Maybe Int
go [] = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
0
go (IsOptional
Required : [IsOptional]
argTypes) = (Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+) (Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [IsOptional] -> Maybe Int
go [IsOptional]
argTypes
go [IsOptional
Optional] = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
0
go [IsOptional
_] = Maybe Int
forall a. Maybe a
Nothing
go [IsOptional]
_ =
[Char] -> Maybe Int
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe Int) -> [Char] -> Maybe Int
forall a b. (a -> b) -> a -> b
$
[Char]
"Invalid args for InputPattern ("
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> ShowS
forall a. Show a => a -> [Char]
show [Char]
patternName
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Char]
"): "
[Char] -> ShowS
forall a. Semigroup a => a -> a -> a
<> [IsOptional] -> [Char]
forall a. Show a => a -> [Char]
show [IsOptional]
argTypes
unionSuggestions ::
forall m v a.
(MonadIO m) =>
[ ( String ->
Codebase m v a ->
AuthenticatedHttpClient ->
PP.ProjectPath ->
m [Line.Completion]
)
] ->
( String ->
Codebase m v a ->
AuthenticatedHttpClient ->
PP.ProjectPath ->
m [Line.Completion]
)
unionSuggestions :: forall (m :: * -> *) v a.
MonadIO m =>
[[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> [Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
unionSuggestions [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
suggesters [Char]
inp Codebase m v a
codebase AuthenticatedHttpClient
httpClient ProjectPath
path = do
[[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
suggesters [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> ([[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> m [Completion])
-> m [Completion]
forall a b. a -> (a -> b) -> b
& (([Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion])
-> m [Completion])
-> [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> m [Completion]
forall (m :: * -> *) (f :: * -> *) b a.
(Monad m, Foldable f, Monoid b) =>
(a -> m b) -> f a -> m b
foldMapM \[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
suggester ->
[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
suggester [Char]
inp Codebase m v a
codebase AuthenticatedHttpClient
httpClient ProjectPath
path
m [Completion]
-> (m [Completion] -> m [Completion]) -> m [Completion]
forall a b. a -> (a -> b) -> b
& ([Completion] -> [Completion]) -> m [Completion] -> m [Completion]
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Completion] -> [Completion]
forall a. Ord a => [a] -> [a]
List.nubOrd
suggestionFallbacks ::
forall m v a.
(MonadIO m) =>
[ ( String ->
Codebase m v a ->
AuthenticatedHttpClient ->
PP.ProjectPath ->
m [Line.Completion]
)
] ->
( String ->
Codebase m v a ->
AuthenticatedHttpClient ->
PP.ProjectPath ->
m [Line.Completion]
)
suggestionFallbacks :: forall (m :: * -> *) v a.
MonadIO m =>
[[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> [Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
suggestionFallbacks [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
suggesters [Char]
inp Codebase m v a
codebase AuthenticatedHttpClient
httpClient ProjectPath
path = [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> m [Completion]
go [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
suggesters
where
go :: [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> m [Completion]
go ([Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
s : [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
rest) = do
[Completion]
suggestions <- [Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]
s [Char]
inp Codebase m v a
codebase AuthenticatedHttpClient
httpClient ProjectPath
path
if [Completion] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Completion]
suggestions
then [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
-> m [Completion]
go [[Char]
-> Codebase m v a
-> AuthenticatedHttpClient
-> ProjectPath
-> m [Completion]]
rest
else [Completion] -> m [Completion]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Completion]
suggestions
go [] = [Completion] -> m [Completion]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []