{-# LANGUAGE ExplicitNamespaces #-}

module Futhark.LSP.InlayHint (getInlayHints) where

import Data.Function ((&))
import Data.Loc (Pos (Pos))
import Data.Text (Text)
import Futhark.LSP.State (State)
import Futhark.LSP.Tool (bindingsInRange)
import Futhark.LSP.TypeAscription (TypeAscription (..), missingAscriptions)
import Futhark.Util.Pretty (prettyText)
import Language.LSP.Protocol.Types
  ( InlayHint (..),
    InlayHintKind (InlayHintKind_Type),
    Position (..),
    Range,
    type (|?) (InL),
  )

getInlayHints :: Range -> State -> FilePath -> [InlayHint]
getInlayHints :: Range -> State -> FilePath -> [InlayHint]
getInlayHints Range
range State
state FilePath
filepath =
  [BoundTo]
-> ([(VName, BoundTo)] -> [BoundTo])
-> Maybe [(VName, BoundTo)]
-> [BoundTo]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
    []
    (((VName, BoundTo) -> BoundTo) -> [(VName, BoundTo)] -> [BoundTo]
forall a b. (a -> b) -> [a] -> [b]
map (VName, BoundTo) -> BoundTo
forall a b. (a, b) -> b
snd)
    (Range -> State -> FilePath -> Maybe [(VName, BoundTo)]
bindingsInRange Range
range State
state FilePath
filepath)
    [BoundTo] -> ([BoundTo] -> [TypeAscription]) -> [TypeAscription]
forall a b. a -> (a -> b) -> b
& (BoundTo -> [TypeAscription]) -> [BoundTo] -> [TypeAscription]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BoundTo -> [TypeAscription]
missingAscriptions
    [TypeAscription]
-> ([TypeAscription] -> [InlayHint]) -> [InlayHint]
forall a b. a -> (a -> b) -> b
& (TypeAscription -> [InlayHint]) -> [TypeAscription] -> [InlayHint]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TypeAscription -> [InlayHint]
inlayHint
  where
    inlayHint :: TypeAscription -> [InlayHint]
    inlayHint :: TypeAscription -> [InlayHint]
inlayHint (TypeAscLet StructType
typName Pos
pos) =
      [Text -> Pos -> InlayHint
bareHint (Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StructType -> Text
forall a. Pretty a => a -> Text
prettyText StructType
typName) Pos
pos]
    inlayHint (TypeAscParam Pos
s StructType
tname Pos
pos) =
      [Pos -> InlayHint
startHint Pos
s, Text -> Pos -> InlayHint
bareHint (Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> StructType -> Text
forall a. Pretty a => a -> Text
prettyText StructType
tname Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")") Pos
pos]
    inlayHint (TypeAscReturn ResRetType
typName Pos
pos) =
      [Text -> Pos -> InlayHint
bareHint (Text
" : " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ResRetType -> Text
forall a. Pretty a => a -> Text
prettyText ResRetType
typName) Pos
pos]
    inlayHint (TypeAscType TypeParamBase VName
typName Pos
pos) =
      [Text -> Pos -> InlayHint
bareHint (Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> TypeParamBase VName -> Text
forall a. Pretty a => a -> Text
prettyText TypeParamBase VName
typName) Pos
pos]

    startHint :: Pos -> InlayHint
    startHint :: Pos -> InlayHint
startHint (Pos FilePath
_ Int
l Int
c Int
_) =
      InlayHint
        { _position :: Position
_position =
            UInt -> UInt -> Position
Position (Int -> UInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
l UInt -> UInt -> UInt
forall a. Num a => a -> a -> a
- UInt
1) (Int -> UInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c UInt -> UInt -> UInt
forall a. Num a => a -> a -> a
- UInt
1),
          _label :: Text |? [InlayHintLabelPart]
_label = Text -> Text |? [InlayHintLabelPart]
forall a b. a -> a |? b
InL Text
"(",
          _kind :: Maybe InlayHintKind
_kind = InlayHintKind -> Maybe InlayHintKind
forall a. a -> Maybe a
Just InlayHintKind
InlayHintKind_Type,
          _textEdits :: Maybe [TextEdit]
_textEdits = Maybe [TextEdit]
forall a. Maybe a
Nothing,
          _tooltip :: Maybe (Text |? MarkupContent)
_tooltip = Maybe (Text |? MarkupContent)
forall a. Maybe a
Nothing,
          _paddingLeft :: Maybe Bool
_paddingLeft = Maybe Bool
forall a. Maybe a
Nothing,
          _paddingRight :: Maybe Bool
_paddingRight = Maybe Bool
forall a. Maybe a
Nothing,
          _data_ :: Maybe Value
_data_ = Maybe Value
forall a. Maybe a
Nothing
        }

    bareHint :: Text -> Pos -> InlayHint
    bareHint :: Text -> Pos -> InlayHint
bareHint Text
tname (Pos FilePath
_ Int
l Int
c Int
_) =
      InlayHint
        { _position :: Position
_position =
            UInt -> UInt -> Position
Position (Int -> UInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
l UInt -> UInt -> UInt
forall a. Num a => a -> a -> a
- UInt
1) (Int -> UInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c UInt -> UInt -> UInt
forall a. Num a => a -> a -> a
- UInt
1),
          _label :: Text |? [InlayHintLabelPart]
_label = Text -> Text |? [InlayHintLabelPart]
forall a b. a -> a |? b
InL Text
tname,
          _kind :: Maybe InlayHintKind
_kind = InlayHintKind -> Maybe InlayHintKind
forall a. a -> Maybe a
Just InlayHintKind
InlayHintKind_Type,
          _textEdits :: Maybe [TextEdit]
_textEdits = Maybe [TextEdit]
forall a. Maybe a
Nothing,
          _tooltip :: Maybe (Text |? MarkupContent)
_tooltip = Maybe (Text |? MarkupContent)
forall a. Maybe a
Nothing,
          _paddingLeft :: Maybe Bool
_paddingLeft = Maybe Bool
forall a. Maybe a
Nothing,
          _paddingRight :: Maybe Bool
_paddingRight = Maybe Bool
forall a. Maybe a
Nothing,
          _data_ :: Maybe Value
_data_ = Maybe Value
forall a. Maybe a
Nothing
        }