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