1- {-# LANGUAGE DataKinds #-}
2- {-# LANGUAGE DerivingStrategies #-}
3- {-# LANGUAGE OverloadedLabels #-}
4- {-# LANGUAGE OverloadedRecordDot #-}
5- {-# LANGUAGE OverloadedStrings #-}
6- {-# LANGUAGE RecordWildCards #-}
7- {-# LANGUAGE TemplateHaskell #-}
8- {-# LANGUAGE TypeFamilies #-}
9- {-# LANGUAGE UnicodeSyntax #-}
10- {-# LANGUAGE ImpredicativeTypes #-}
11- {-# LANGUAGE LiberalTypeSynonyms #-}
12- {-# LANGUAGE BlockArguments #-}
13- {-# LANGUAGE MultiWayIf #-}
14- {-# LANGUAGE PatternSynonyms #-}
15- {-# LANGUAGE RequiredTypeArguments #-}
16- {-# LANGUAGE ViewPatterns #-}
1+ {-# LANGUAGE BlockArguments #-}
2+ {-# LANGUAGE DataKinds #-}
3+ {-# LANGUAGE DerivingStrategies #-}
4+ {-# LANGUAGE ImpredicativeTypes #-}
5+ {-# LANGUAGE LiberalTypeSynonyms #-}
6+ {-# LANGUAGE MultiWayIf #-}
7+ {-# LANGUAGE OverloadedLabels #-}
8+ {-# LANGUAGE OverloadedRecordDot #-}
9+ {-# LANGUAGE OverloadedStrings #-}
10+ {-# LANGUAGE PatternSynonyms #-}
11+ {-# LANGUAGE QuantifiedConstraints #-}
12+ {-# LANGUAGE RecordWildCards #-}
13+ {-# LANGUAGE TemplateHaskell #-}
14+ {-# LANGUAGE TypeFamilies #-}
15+ {-# LANGUAGE UnicodeSyntax #-}
16+ {-# LANGUAGE ViewPatterns #-}
1717
1818-- |
1919-- This module provides the core functionality of the plugin.
@@ -27,20 +27,28 @@ import Control.Monad.Except (ExceptT, liftEither,
2727import Control.Monad.IO.Class (MonadIO (.. ))
2828import Control.Monad.Trans (lift )
2929import Control.Monad.Trans.Except (runExceptT )
30+ import Control.Monad.Trans.Maybe
31+ import Data.Data (Data (.. ))
32+ import Data.List
3033import qualified Data.Map.Strict as M
34+ import Data.Maybe
35+ import Data.Semigroup (First (.. ))
3136import Data.Text (Text )
3237import qualified Data.Text as T
3338import Development.IDE (Action ,
3439 GetDocMap (GetDocMap ),
3540 GetHieAst (GetHieAst ),
41+ GetParsedModuleWithComments (.. ),
3642 HieAstResult (HAR , hieAst , hieModule , refMap ),
3743 IdeResult , IdeState ,
3844 Priority (.. ),
3945 Recorder , Rules ,
4046 WithPriority ,
4147 cmapWithPrio , define ,
4248 hieKind ,
43- toNormalizedUri , GetParsedModuleWithComments (.. ), srcSpanToRange )
49+ srcSpanToRange ,
50+ toNormalizedUri ,
51+ useWithStale )
4452import Development.IDE.Core.PluginUtils (runActionE , useE ,
4553 useWithStaleE )
4654import Development.IDE.Core.Rules (toIdeResult )
@@ -50,8 +58,9 @@ import Development.IDE.Core.Shake (ShakeExtras (..),
5058 getVirtualFile )
5159import Development.IDE.GHC.Compat hiding (Warning )
5260import Development.IDE.GHC.Compat.Util (mkFastString )
61+ import GHC.Parser.Annotation
5362import Ide.Logger (logWith )
54- import Ide.Plugin.Error (PluginError (PluginInternalError ),
63+ import Ide.Plugin.Error (PluginError (PluginInternalError , PluginRuleFailed ),
5564 handleMaybe ,
5665 handleMaybeM )
5766import Ide.Plugin.SemanticTokens.Mappings
@@ -63,24 +72,18 @@ import Ide.Types
6372import qualified Language.LSP.Protocol.Lens as L
6473import Language.LSP.Protocol.Message (MessageResult ,
6574 Method (Method_TextDocumentSemanticTokensFull , Method_TextDocumentSemanticTokensFullDelta ))
66- import Language.LSP.Protocol.Types (NormalizedUri ,
75+ import Language.LSP.Protocol.Types (NormalizedUri , Range ,
6776 SemanticTokens ,
6877 fromNormalizedUri ,
6978 getUri ,
70- type (|? ) (InL , InR ), Range )
79+ type (|? ) (InL , InR ))
7180import Prelude hiding (span )
7281import qualified StmContainers.Map as STM
73- import Type.Reflection
74- ( Typeable ,
75- type (:~~: )(HRefl ),
76- pattern App ,
77- eqTypeRep ,
78- typeOf ,
79- typeRep ,
80- withTypeable )
81- import Data.Data (Data (.. ))
82- import GHC.Parser.Annotation
83- import Data.Maybe
82+ import Type.Reflection (Typeable , eqTypeRep ,
83+ pattern App ,
84+ type (:~~: ) (HRefl ),
85+ typeOf , typeRep ,
86+ withTypeable )
8487
8588
8689$ mkSemanticConfigFunctions
@@ -94,9 +97,17 @@ computeSemanticTokens recorder pid _ nuri = do
9497 config <- lift $ useSemanticConfigAction pid
9598 logWith recorder Debug (LogConfig config)
9699 semanticId <- lift getAndIncreaseSemanticTokensId
97- (RangeHsSemanticTokenTypes {rangeSemanticList}, _mapping) <- useWithStaleE GetSemanticTokens nuri
98- (RangeHsSyntacticTokenTypes {rangeSyntacticList}, mapping) <- useWithStaleE GetSyntacticTokens nuri
99- withExceptT PluginInternalError $ liftEither $ rangeSemanticsSemanticTokens semanticId config mapping $ map (fmap HsSemanticTokenType ) rangeSemanticList <> map (fmap HsSyntacticTokenType ) rangeSyntacticList
100+
101+ (sortOn fst -> tokenList, First mapping) <- do
102+ rangesyntacticTypes <- lift $ useWithStale GetSyntacticTokens nuri
103+ rangesemanticTypes <- lift $ useWithStale GetSemanticTokens nuri
104+ let mk w u (toks, mapping) = (map (fmap w) $ u toks, First mapping)
105+ maybeToExceptT (PluginRuleFailed " no syntactic nor semantic tokens" ) $ hoistMaybe $
106+ (mk HsSyntacticTokenType rangeSyntacticList <$> rangesyntacticTypes)
107+ <> (mk HsSemanticTokenType rangeSemanticList <$> rangesemanticTypes)
108+
109+ -- NOTE: rangeSemanticsSemanticTokens actually assumes that the tokesn are in order. that means they have to be sorted by position
110+ withExceptT PluginInternalError $ liftEither $ rangeSemanticsSemanticTokens semanticId config mapping tokenList
100111
101112semanticTokensFull :: Recorder (WithPriority SemanticLog ) -> PluginMethodHandler IdeState 'Method_TextDocumentSemanticTokensFull
102113semanticTokensFull recorder state pid param = runActionE " SemanticTokens.semanticTokensFull" state computeSemanticTokensFull
@@ -153,35 +164,84 @@ getSemanticTokensRule recorder =
153164getSyntacticTokensRule :: Recorder (WithPriority SemanticLog ) -> Rules ()
154165getSyntacticTokensRule recorder =
155166 define (cmapWithPrio LogShake recorder) $ \ GetSyntacticTokens nfp -> handleError recorder $ do
156- (parsedModule, positionMapping ) <- withExceptT LogDependencyError $ useWithStaleE GetParsedModuleWithComments nfp
157- pure $ computeRangeHsSyntacticTokenTypeList parsedModule
158-
159- getLocated's :: forall l a . ( Data a , Typeable l ) => a -> [ GenLocated l ( forall r . ( forall b . Typeable b => b -> r ) -> r )]
160- getLocated's = mconcat . gmapQ \ y -> if
161- | App con rep <- typeOf y
162- , Just HRefl <- eqTypeRep con (typeRep @ ( GenLocated l ))
163- , L l a <- y
164- -> withTypeable rep $ L l ( \ k -> k a) : getLocated's y
165- | otherwise -> getLocated's y
166-
167- pattern IsA :: forall b t . ( Typeable b , Typeable t ) => forall . b ~ t => b -> t
168- pattern IsA x <- (( \ y -> (y, eqTypeRep (typeRep @ b ) (typeOf y))) -> (x, Just HRefl ) )
169-
170- mkFromLocatedNode :: GenLocated SrcSpanAnnA ( forall r . ( forall b . Typeable b => b -> r ) -> r ) -> Maybe ( Range , HsSyntacticTokenType )
171- mkFromLocatedNode ( L ann w) = w \ node -> case node of
172- IsA @ ( HsExpr GhcPs ) expr -> case expr of
173- HsLet {} -> let
174- mrange = srcSpanToRange $ getLoc ann
175- in (, TKeyword ) <$> mrange
176- _ -> Nothing
177- _ -> Nothing
167+ (parsedModule, _ ) <- withExceptT LogDependencyError $ useWithStaleE GetParsedModuleWithComments nfp
168+ let tokList = computeRangeHsSyntacticTokenTypeList parsedModule
169+ logWith recorder Debug $ LogSyntacticTokens tokList
170+ pure tokList
171+
172+ astTraversalWith :: forall b r . Data b => b -> ( forall a . Data a => a -> [ r ]) -> [ r ]
173+ astTraversalWith ast f = mconcat $ flip gmapQ ast \ y -> f y <> astTraversalWith y f
174+
175+ {-# inline extractTyToTy #-}
176+ extractTyToTy :: forall f a . ( Typeable f , Data a ) => a -> Maybe ( forall r . ( forall b . Typeable b => f b -> r ) -> r )
177+ extractTyToTy node
178+ | App conRep argRep <- typeOf node
179+ , Just HRefl <- eqTypeRep conRep (typeRep @ f )
180+ = Just $ withTypeable argRep $ ( \ k -> k node)
181+ | otherwise = Nothing
182+
183+ {-# inline extractTy #-}
184+ extractTy :: forall b a . ( Typeable b , Data a ) => a -> Maybe b
185+ extractTy node
186+ | Just HRefl <- eqTypeRep (typeRep @ b ) (typeOf node)
187+ = Just node
188+ | otherwise = Nothing
178189
179190computeRangeHsSyntacticTokenTypeList :: ParsedModule -> RangeHsSyntacticTokenTypes
180191computeRangeHsSyntacticTokenTypeList ParsedModule {pm_parsed_source} =
181- let locs = getLocated's @ SrcSpanAnnA pm_parsed_source
182- toks = mapMaybe mkFromLocatedNode locs
192+ let toks = astTraversalWith pm_parsed_source \ node -> mconcat
193+ [ maybeToList $ mkFromLocatable TKeyword . (\ k -> k \ x k' -> k' x) =<< extractTyToTy @ EpToken node
194+ -- FIXME: probably needs to be commented out for ghc > 9.10
195+ , maybeToList $ mkFromLocatable TKeyword . (\ x k -> k x) =<< extractTy @ AddEpAnn node
196+ , do
197+ EpAnnImportDecl i p s q pkg a <- maybeToList $ extractTy @ EpAnnImportDecl node
198+
199+ mapMaybe (mkFromLocatable TKeyword . (\ x k -> k x)) $ catMaybes $ [Just i, s, q, pkg, a] <> foldMap (\ (l, l') -> [Just l, Just l']) p
200+ , maybeToList $ mkFromLocatable TComment . (\ x k -> k x) =<< extractTy @ LEpaComment node
201+ , maybeToList do
202+ L loc expr <- extractTy @ (LHsExpr GhcPs ) node
203+ let fromSimple = flip mkFromLocatable \ k -> k loc
204+ case expr of
205+ HsOverLabel {} -> fromSimple TStringLit
206+ HsOverLit _ (OverLit _ lit) -> fromSimple case lit of
207+ HsIntegral {} -> TNumberLit
208+ HsFractional {} -> TNumberLit
209+
210+ HsIsString {} -> TStringLit
211+ HsLit _ lit -> fromSimple case lit of
212+ HsChar {} -> TCharLit
213+ HsCharPrim {} -> TCharLit
214+
215+ HsInt {} -> TNumberLit
216+ HsInteger {} -> TNumberLit
217+ HsIntPrim {} -> TNumberLit
218+ HsWordPrim {} -> TNumberLit
219+ HsWord8Prim {} -> TNumberLit
220+ HsWord16Prim {} -> TNumberLit
221+ HsWord32Prim {} -> TNumberLit
222+ HsWord64Prim {} -> TNumberLit
223+ HsInt8Prim {} -> TNumberLit
224+ HsInt16Prim {} -> TNumberLit
225+ HsInt32Prim {} -> TNumberLit
226+ HsInt64Prim {} -> TNumberLit
227+ HsFloatPrim {} -> TNumberLit
228+ HsDoublePrim {} -> TNumberLit
229+ HsRat {} -> TNumberLit
230+
231+ HsString {} -> TStringLit
232+ HsStringPrim {} -> TStringLit
233+ HsRecSel {} -> fromSimple TRecordSelector
234+ _ -> Nothing
235+ ]
183236 in RangeHsSyntacticTokenTypes toks
184237
238+ {-# inline mkFromLocatable #-}
239+ mkFromLocatable
240+ :: HsSyntacticTokenType
241+ -> (forall r . (forall a . HasSrcSpan a => a -> r ) -> r )
242+ -> Maybe (Range , HsSyntacticTokenType )
243+ mkFromLocatable tt w = w \ tok -> let mrange = srcSpanToRange $ getLoc tok in fmap (, tt) mrange
244+
185245-- taken from /haskell-language-server/plugins/hls-code-range-plugin/src/Ide/Plugin/CodeRange/Rules.hs
186246
187247-- | Handle error in 'Action'. Returns an 'IdeResult' with no value and no diagnostics on error. (but writes log)
0 commit comments