module Development.IDE.Plugin.Plugins.Diagnostic (
  matchVariableNotInScope,
  matchRegexUnifySpaces,
  unifySpaces,
  matchFoundHole,
  matchFoundHoleIncludeUnderscore,
  )
  where

import           Data.Bifunctor  (Bifunctor (..))
import qualified Data.Text       as T
import           Text.Regex.TDFA ((=~~))

unifySpaces :: T.Text -> T.Text
unifySpaces :: Text -> Text
unifySpaces    = [Text] -> Text
T.unwords ([Text] -> Text) -> (Text -> [Text]) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.words

-- | Returns Just (the submatches) for the first capture, or Nothing.
matchRegex :: T.Text -> T.Text -> Maybe [T.Text]
matchRegex :: Text -> Text -> Maybe [Text]
matchRegex Text
message Text
regex = case Text
message Text -> Text -> Maybe (Text, Text, Text, [Text])
forall source source1 target (m :: * -> *).
(RegexMaker Regex CompOption ExecOption source,
 RegexContext Regex source1 target, MonadFail m) =>
source1 -> source -> m target
=~~ Text
regex of
    Just (Text
_ :: T.Text, Text
_ :: T.Text, Text
_ :: T.Text, [Text]
bindings) -> [Text] -> Maybe [Text]
forall a. a -> Maybe a
Just [Text]
bindings
    Maybe (Text, Text, Text, [Text])
Nothing                                                -> Maybe [Text]
forall a. Maybe a
Nothing

-- | 'matchRegex' combined with 'unifySpaces'
matchRegexUnifySpaces :: T.Text -> T.Text -> Maybe [T.Text]
matchRegexUnifySpaces :: Text -> Text -> Maybe [Text]
matchRegexUnifySpaces Text
message = Text -> Text -> Maybe [Text]
matchRegex (Text -> Text
unifySpaces Text
message)

matchFoundHole :: T.Text -> Maybe (T.Text, T.Text)
matchFoundHole :: Text -> Maybe (Text, Text)
matchFoundHole Text
message
  | Just [Text
name, Text
typ] <- Text -> Text -> Maybe [Text]
matchRegexUnifySpaces Text
message Text
"Found hole: _([^ ]+) :: ([^*•]+) Or perhaps" =
      (Text, Text) -> Maybe (Text, Text)
forall a. a -> Maybe a
Just (Text
name, Text
typ)
  | Bool
otherwise = Maybe (Text, Text)
forall a. Maybe a
Nothing

matchFoundHoleIncludeUnderscore :: T.Text -> Maybe (T.Text, T.Text)
matchFoundHoleIncludeUnderscore :: Text -> Maybe (Text, Text)
matchFoundHoleIncludeUnderscore Text
message = (Text -> Text) -> (Text, Text) -> (Text, Text)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Text
"_" <>) ((Text, Text) -> (Text, Text))
-> Maybe (Text, Text) -> Maybe (Text, Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Maybe (Text, Text)
matchFoundHole Text
message

matchVariableNotInScope :: T.Text -> Maybe (T.Text, Maybe T.Text)
matchVariableNotInScope :: Text -> Maybe (Text, Maybe Text)
matchVariableNotInScope Text
message
  --     * Variable not in scope:
  --         suggestAcion :: Maybe T.Text -> Range -> Range
  --     * Variable not in scope:
  --         suggestAcion
  | Just (Text
name, Text
typ) <- Text -> Maybe (Text, Text)
matchVariableNotInScopeTyped Text
message = (Text, Maybe Text) -> Maybe (Text, Maybe Text)
forall a. a -> Maybe a
Just (Text
name, Text -> Maybe Text
forall a. a -> Maybe a
Just Text
typ)
  | Just Text
name <- Text -> Maybe Text
matchVariableNotInScopeUntyped Text
message = (Text, Maybe Text) -> Maybe (Text, Maybe Text)
forall a. a -> Maybe a
Just (Text
name, Maybe Text
forall a. Maybe a
Nothing)
  | Bool
otherwise = Maybe (Text, Maybe Text)
forall a. Maybe a
Nothing
  where
    matchVariableNotInScopeTyped :: Text -> Maybe (Text, Text)
matchVariableNotInScopeTyped Text
message
      | Just [Text
name, Text
typ0] <- Text -> Text -> Maybe [Text]
matchRegexUnifySpaces Text
message Text
"Variable not in scope: ([^ ]+) :: ([^*•]+)"
      , -- When some name in scope is similar to not-in-scope variable, the type is followed by
        -- "Suggested fix: Perhaps use ..."
        Text
typ:[Text]
_ <- HasCallStack => Text -> Text -> [Text]
Text -> Text -> [Text]
T.splitOn Text
" Suggested fix:" Text
typ0 =
          (Text, Text) -> Maybe (Text, Text)
forall a. a -> Maybe a
Just (Text
name, Text
typ)
      | Bool
otherwise = Maybe (Text, Text)
forall a. Maybe a
Nothing
    matchVariableNotInScopeUntyped :: Text -> Maybe Text
matchVariableNotInScopeUntyped Text
message
      | Just [Text
name] <- Text -> Text -> Maybe [Text]
matchRegexUnifySpaces Text
message Text
"Variable not in scope: ([^ ]+)" =
          Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name
      | Bool
otherwise = Maybe Text
forall a. Maybe a
Nothing