1
1
{-# LANGUAGE DeriveGeneric #-}
2
+ {-# LANGUAGE TupleSections #-}
2
3
{-# LANGUAGE LambdaCase #-}
3
4
{-# LANGUAGE NamedFieldPuns #-}
4
5
{-# LANGUAGE OverloadedStrings #-}
5
6
{-# LANGUAGE TypeFamilies #-}
6
- {-# OPTIONS_GHC -Wno-deprecations #-}
7
- {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
8
- {-# HLINT ignore "Use nubOrdOn" #-}
7
+ {-# OPTIONS_GHC -Wno-orphans #-}
8
+ {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
9
9
10
10
module Ide.Plugin.ExplicitFixity (descriptor ) where
11
11
12
12
import Control.DeepSeq
13
- import Control.Monad ( forM )
13
+ import Control.Monad.Trans.Maybe
14
14
import Control.Monad.IO.Class (MonadIO , liftIO )
15
- import Data.Coerce (coerce )
16
15
import Data.Either.Extra
17
16
import Data.Hashable
18
- import Data.List.Extra ( nubOn )
19
- import qualified Data.Map as M
17
+ import qualified Data.Map.Strict as M
18
+ import qualified Data.Set as S
20
19
import Data.Maybe
21
- import Data.Monoid
22
20
import qualified Data.Text as T
23
21
import Development.IDE hiding (pluginHandlers ,
24
22
pluginRules )
25
23
import Development.IDE.Core.PositionMapping (idDelta )
26
24
import Development.IDE.Core.Shake (addPersistentRule )
27
25
import qualified Development.IDE.Core.Shake as Shake
26
+ import Development.IDE.Spans.AtPoint
28
27
import Development.IDE.GHC.Compat
29
- import Development.IDE.GHC.Compat.Util (FastString )
30
28
import qualified Development.IDE.GHC.Compat.Util as Util
31
29
import Development.IDE.LSP.Notifications (ghcideNotificationsPluginPriority )
32
30
import GHC.Generics (Generic )
@@ -51,14 +49,14 @@ descriptor recorder = (defaultPluginDescriptor pluginId)
51
49
hover :: PluginMethodHandler IdeState TextDocumentHover
52
50
hover state _ (HoverParams (TextDocumentIdentifier uri) pos _) = pluginResponse $ do
53
51
nfp <- getNormalizedFilePath uri
54
- fixityTrees <- handleMaybeM " ExplicitFixity: Unable to get fixity"
55
- $ liftIO
56
- $ runAction " ExplicitFixity.GetFixity " state
57
- $ use GetFixity nfp
58
- -- We don't have much fixities on one position, so `nubOn` is acceptable.
59
- pure $ toHover $ nubOn snd $ findInTree fixityTrees pos fNodeFixty
52
+ handleMaybeM " ExplicitFixity: Unable to get fixity" $ liftIO $ runIdeAction " ExplicitFixity " (shakeExtras state) $ runMaybeT $ do
53
+ ( FixityMap fixmap, _) <- useE GetFixity nfp
54
+ ( HAR {hieAst}, mapping) <- useE GetHieAst nfp
55
+ let ns = getNamesAtPoint hieAst pos mapping
56
+ fs = mapMaybe ( \ n -> (n,) <$> M. lookup n fixmap) ns
57
+ pure $ toHover $ fs
60
58
where
61
- toHover :: [(T. Text , Fixity )] -> Maybe Hover
59
+ toHover :: [(Name , Fixity )] -> Maybe Hover
62
60
toHover [] = Nothing
63
61
toHover fixities =
64
62
let -- Splicing fixity info
@@ -67,44 +65,19 @@ hover state _ (HoverParams (TextDocumentIdentifier uri) pos _) = pluginResponse
67
65
contents' = " \n " <> sectionSeparator <> contents
68
66
in Just $ Hover (HoverContents $ unmarkedUpContent contents') Nothing
69
67
70
- fixityText :: (T. Text , Fixity ) -> T. Text
68
+ fixityText :: (Name , Fixity ) -> T. Text
71
69
fixityText (name, Fixity _ precedence direction) =
72
- printOutputable direction <> " " <> printOutputable precedence <> " `" <> name <> " `"
73
-
74
- -- | Transferred from ghc `selectSmallestContaining`
75
- selectSmallestContainingForFixityTree :: Span -> FixityTree -> Maybe FixityTree
76
- selectSmallestContainingForFixityTree sp node
77
- | sp `containsSpan` fNodeSpan node = Just node
78
- | fNodeSpan node `containsSpan` sp = getFirst $ mconcat
79
- [ foldMap (First . selectSmallestContainingForFixityTree sp) $ fNodeChildren node
80
- , First (Just node)
81
- ]
82
- | otherwise = Nothing
83
-
84
- -- | Transferred from ghcide `pointCommand`
85
- findInTree :: FixityTrees -> Position -> (FixityTree -> [a ]) -> [a ]
86
- findInTree tree pos k =
87
- concat $ M. elems $ flip M. mapWithKey tree $ \ fs ast ->
88
- maybe [] k (selectSmallestContainingForFixityTree (sp fs) ast)
89
- where
90
- sloc fs = mkRealSrcLoc fs (fromIntegral $ line+ 1 ) (fromIntegral $ cha+ 1 )
91
- sp fs = mkRealSrcSpan (sloc fs) (sloc fs)
92
- line = _line pos
93
- cha = _character pos
94
-
95
- data FixityTree = FNode
96
- { fNodeSpan :: Span
97
- , fNodeChildren :: [FixityTree ]
98
- , fNodeFixty :: [(T. Text , Fixity )]
99
- } deriving (Generic )
70
+ printOutputable direction <> " " <> printOutputable precedence <> " `" <> printOutputable name <> " `"
100
71
101
- instance NFData FixityTree where
102
- rnf = rwhnf
72
+ newtype FixityMap = FixityMap (M. Map Name Fixity )
73
+ instance Show FixityMap where
74
+ show _ = " FixityMap"
103
75
104
- instance Show FixityTree where
105
- show _ = " <FixityTree> "
76
+ instance NFData FixityMap where
77
+ rnf ( FixityMap xs) = rnf xs
106
78
107
- type FixityTrees = M. Map FastString FixityTree
79
+ instance NFData Fixity where
80
+ rnf = rwhnf
108
81
109
82
newtype Log = LogShake Shake. Log
110
83
@@ -117,53 +90,33 @@ data GetFixity = GetFixity deriving (Show, Eq, Generic)
117
90
instance Hashable GetFixity
118
91
instance NFData GetFixity
119
92
120
- type instance RuleResult GetFixity = FixityTrees
121
-
122
- fakeFixityTrees :: FixityTrees
123
- fakeFixityTrees = M. empty
124
-
125
- -- | Convert a HieASTs to FixityTrees with fixity info gathered
126
- hieAstsToFixitTrees :: MonadIO m => HscEnv -> TcGblEnv -> HieASTs a -> m FixityTrees
127
- hieAstsToFixitTrees hscEnv tcGblEnv ast =
128
- -- coerce to avoid compatibility issues.
129
- M. mapKeysWith const coerce <$>
130
- sequence (M. map (hieAstToFixtyTree hscEnv tcGblEnv) (getAsts ast))
93
+ type instance RuleResult GetFixity = FixityMap
131
94
132
95
-- | Convert a HieAST to FixityTree with fixity info gathered
133
- hieAstToFixtyTree :: MonadIO m => HscEnv -> TcGblEnv -> HieAST a -> m FixityTree
134
- hieAstToFixtyTree hscEnv tcGblEnv ast = case ast of
135
- (Node _ span [] ) -> FNode span [] <$> getFixities
136
- (Node _ span children) -> do
137
- fixities <- getFixities
138
- childrenFixities <- mapM (hieAstToFixtyTree hscEnv tcGblEnv) children
139
- pure $ FNode span childrenFixities fixities
140
- where
141
- -- Names at the current ast node
142
- names :: [Name ]
143
- names = mapMaybe eitherToMaybe $ M. keys $ getNodeIds ast
144
-
145
- getFixities :: MonadIO m => m [(T. Text , Fixity )]
146
- getFixities = liftIO
147
- $ fmap (filter ((/= defaultFixity) . snd ) . mapMaybe pickFixity)
148
- $ forM names $ \ name ->
149
- (,) (printOutputable name)
150
- . snd
151
- <$> Util. handleGhcException
152
- (const $ pure (emptyMessages, Nothing ))
153
- (initTcWithGbl hscEnv tcGblEnv (realSrcLocSpan $ mkRealSrcLoc " <dummy>" 1 1 ) (lookupFixityRn name))
154
-
155
- pickFixity :: (T. Text , Maybe Fixity ) -> Maybe (T. Text , Fixity )
156
- pickFixity (_, Nothing ) = Nothing
157
- pickFixity (name, Just f) = Just (name, f)
96
+ lookupFixities :: MonadIO m => HscEnv -> TcGblEnv -> S. Set Name -> m (M. Map Name Fixity )
97
+ lookupFixities hscEnv tcGblEnv names
98
+ = liftIO
99
+ $ fmap (fromMaybe M. empty . snd )
100
+ $ initTcWithGbl hscEnv tcGblEnv (realSrcLocSpan $ mkRealSrcLoc " <dummy>" 1 1 )
101
+ $ M. traverseMaybeWithKey (\ _ v -> v)
102
+ $ M. fromSet lookupFixity names
103
+ where
104
+ lookupFixity name = do
105
+ f <- Util. handleGhcException
106
+ (const $ pure Nothing )
107
+ (Just <$> lookupFixityRn name)
108
+ if f == Just defaultFixity
109
+ then pure Nothing
110
+ else pure f
158
111
159
112
fixityRule :: Recorder (WithPriority Log ) -> Rules ()
160
113
fixityRule recorder = do
161
114
define (cmapWithPrio LogShake recorder) $ \ GetFixity nfp -> do
162
- HAR {hieAst } <- use_ GetHieAst nfp
163
- env <- hscEnv <$> use_ GhcSession nfp
115
+ HAR {refMap } <- use_ GetHieAst nfp
116
+ env <- hscEnv <$> use_ GhcSessionDeps nfp -- deps necessary so that we can consult already loaded in ifaces instead of loading in duplicates
164
117
tcGblEnv <- tmrTypechecked <$> use_ TypeCheck nfp
165
- trees <- hieAstsToFixitTrees env tcGblEnv hieAst
166
- pure ([] , Just trees )
118
+ fs <- lookupFixities env tcGblEnv ( S. mapMonotonic ( \ ( Right n) -> n) $ S. filter isRight $ M. keysSet refMap)
119
+ pure ([] , Just ( FixityMap fs) )
167
120
168
121
-- Ensure that this plugin doesn't block on startup
169
- addPersistentRule GetFixity $ \ _ -> pure $ Just (fakeFixityTrees , idDelta, Nothing )
122
+ addPersistentRule GetFixity $ \ _ -> pure $ Just (FixityMap M. empty , idDelta, Nothing )
0 commit comments