packages feed

hls-class-plugin-2.1.0.0: src/Ide/Plugin/Class/Types.hs

{-# LANGUAGE DeriveAnyClass   #-}
{-# LANGUAGE DeriveGeneric    #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase       #-}
{-# LANGUAGE TypeFamilies     #-}
{-# LANGUAGE ViewPatterns     #-}

module Ide.Plugin.Class.Types where

import           Control.DeepSeq               (rwhnf)
import           Control.Monad.Extra           (whenMaybe)
import           Control.Monad.IO.Class        (liftIO)
import           Data.Aeson
import           Data.Maybe                    (catMaybes)
import qualified Data.Text                     as T
import           Development.IDE
import qualified Development.IDE.Core.Shake    as Shake
import           Development.IDE.GHC.Compat    hiding ((<+>))
import           Development.IDE.Graph.Classes
import           GHC.Generics
import           Ide.Plugin.Class.Utils
import           Ide.Types
import           Language.LSP.Protocol.Types   (VersionedTextDocumentIdentifier)

typeLensCommandId :: CommandId
typeLensCommandId = "classplugin.typelens"

codeActionCommandId :: CommandId
codeActionCommandId = "classplugin.codeaction"

-- | Default indent size for inserting
defaultIndent :: Int
defaultIndent = 2

data AddMinimalMethodsParams = AddMinimalMethodsParams
    { verTxtDocId :: VersionedTextDocumentIdentifier
    , range       :: Range
    , methodGroup :: [(T.Text, T.Text)]
    -- ^ (name text, signature text)
    , withSig     :: Bool
    }
    deriving (Show, Eq, Generic, ToJSON, FromJSON)

data GetInstanceBindTypeSigs = GetInstanceBindTypeSigs
    deriving (Generic, Show, Eq, Ord, Hashable, NFData)

data InstanceBindTypeSig = InstanceBindTypeSig
    { bindName     :: Name
    , bindRendered :: !T.Text
    , bindDefSpan  :: Maybe SrcSpan
    -- ^SrcSpan for the bind definition
    }

newtype InstanceBindTypeSigsResult =
    InstanceBindTypeSigsResult [InstanceBindTypeSig]

instance Show InstanceBindTypeSigsResult where
    show _ = "<InstanceBindTypeSigs>"

instance NFData InstanceBindTypeSigsResult where
    rnf = rwhnf

type instance RuleResult GetInstanceBindTypeSigs = InstanceBindTypeSigsResult

data Log
  = LogImplementedMethods Class [T.Text]
  | LogShake Shake.Log

instance Pretty Log where
  pretty = \case
    LogImplementedMethods cls methods ->
      pretty ("Detected implemented methods for class" :: String)
        <+> pretty (show (getOccString cls) <> ":") -- 'show' is used here to add quotes around the class name
        <+> pretty methods
    LogShake log -> pretty log

data BindInfo = BindInfo
    { bindSpan     :: SrcSpan
      -- ^ SrcSpan of the whole binding
    , bindNameSpan :: SrcSpan
      -- ^ SrcSpan of the binding name
    }

rules :: Recorder (WithPriority Log) -> Rules ()
rules recorder = do
    define (cmapWithPrio LogShake recorder) $ \GetInstanceBindTypeSigs nfp -> do
        tmr <- use TypeCheck nfp
        hsc <- use GhcSession nfp
        result <- liftIO $ instanceBindType (hscEnv <$> hsc) (tmrTypechecked <$> tmr)
        pure ([], result)
    where
        instanceBindType :: Maybe HscEnv -> Maybe TcGblEnv -> IO (Maybe InstanceBindTypeSigsResult)
        instanceBindType (Just hsc) (Just gblEnv) = do
            let binds = collectHsBindsBinders $ tcg_binds gblEnv
            (_, maybe [] catMaybes -> instanceBinds) <-
                initTcWithGbl hsc gblEnv ghostSpan $ traverse bindToSig binds
            pure $ Just $ InstanceBindTypeSigsResult instanceBinds
            where
                rdrEnv = tcg_rdr_env gblEnv
                showDoc ty = showSDocForUser' hsc (mkPrintUnqualifiedDefault hsc rdrEnv) (pprSigmaType ty)

                bindToSig id = do
                    let name = idName id
                    whenMaybe (isBindingName name) $ do
                        env <- tcInitTidyEnv
                        let (_, ty) = tidyOpenType env (idType id)
                        pure $ InstanceBindTypeSig name
                                (prettyBindingNameString (printOutputable name) <> " :: " <> T.pack (showDoc ty))
                                Nothing
        instanceBindType _ _ = pure Nothing