@@ -24,9 +24,9 @@ import Development.IDE.GHC.Compat hiding (getContext)
2424import GHC.Generics (Generic )
2525import GHC.Hs (HasLoc )
2626
27- -- | A context of a declaration in the program
28- -- e.g. is the declaration a type declaration or a value declaration
29- -- Used for determining which code completions to show
27+ -- | A context of a declaration in the program e.g. is the declaration a
28+ -- type declaration or a value declaration. Used for determining which code
29+ -- completions to show.
3030data Context
3131 = TypeContext
3232 | ValueContext
@@ -53,22 +53,6 @@ data ContextGroup
5353 | DeclarationGroup
5454 deriving (Show , Eq , Ord )
5555
56- instance Pretty Context where
57- pretty = \ case
58- TypeContext -> " type context"
59- ValueContext -> " value context"
60- ImportContext mod -> " import context " <> pretty mod
61- ImportListContext mod -> " import explicit context " <> pretty mod
62- ImportHidingContext mod -> " import hiding context " <> pretty mod
63- TopContext cg -> " top context " <> pretty cg
64- DefaultContext -> " unknown context"
65-
66- instance Pretty ContextGroup where
67- pretty = \ case
68- HeaderGroup -> " header"
69- ImportGroup -> " imports"
70- DeclarationGroup -> " declarations"
71-
7256data GetContextMap = GetContextMap
7357 deriving (Eq , Show , Generic )
7458instance Hashable GetContextMap
@@ -101,26 +85,27 @@ groupedChunks n group getPos locate xs = ContextMap $ go xs
10185 , context
10286 } : go rest
10387
104- data ContextResult
105- = NoContext
106- | ContextResult Range Context
88+ -- | Used during context finding, combines into the tightest interval.
89+ -- As an intuition, the primary interface is through
90+ -- @Monoid (Position -> ContextResult)@.
91+ data ContextResult = NoContext | ContextResult Range Context
92+ instance Monoid ContextResult where mempty = NoContext
93+ instance Semigroup ContextResult where (<>) = tighten
10794
108- instance Semigroup ContextResult where
109- NoContext <> b = b
110- a <> NoContext = a
111- ar@ (ContextResult a _) <> br@ (ContextResult b _) = if a `dominates` b
112- then br
113- else ar
114-
115- instance Monoid ContextResult where
116- mempty = NoContext
95+ tighten :: ContextResult -> ContextResult -> ContextResult
96+ tighten NoContext b = b
97+ tighten a NoContext = a
98+ tighten ar@ (ContextResult a _) br@ (ContextResult b _) =
99+ if a `dominates` b then br else ar
117100
118101newtype ContextMap = ContextMap [ContextChunk ]
119102 deriving newtype (Monoid , Semigroup )
120103instance Show ContextMap where show _ = " <context map>"
121104instance NFData ContextMap where rnf = rwhnf
122105
123- -- | Build a 'ContextMap' from a parsed module.
106+ -- * Building
107+
108+ -- | Build a @ContextMap@ from a parsed module.
124109--
125110-- Walks module header, exports, imports, and top-level declarations
126111-- (one level into class bodies). Built once per file edit and cached
@@ -136,14 +121,6 @@ getContextMap pm =
136121rangeOf :: HasLoc a => a -> Maybe Range
137122rangeOf = srcSpanToRange . locA
138123
139- contextual :: HasLoc a => Context -> Bool -> Range -> a -> (ContextResult , Bool )
140- contextual context shouldStop query s =
141- let range = rangeOf s
142- in case range of
143- Nothing -> (mempty , True )
144- Just range | outside query range -> (mempty , True )
145- Just range -> (ContextResult range context, shouldStop)
146-
147124getImportContext :: LImportDecl GhcPs -> Range -> ContextResult
148125getImportContext imports query =
149126 everythingBut
@@ -158,6 +135,35 @@ getDeclContext declarations query =
158135 ((mempty , False ) `mkQ` sigQ query `extQ` bindQ query `extQ` declQ query)
159136 declarations
160137
138+ -- * Querying
139+
140+ -- | Look up the completion context at a given position.
141+ -- Returns the innermost (most specific) context that contains the position.
142+ --
143+ -- Only the 'ContextChunks' up to and including the chunk containing the
144+ -- query position are forced; later chunks remain as unevaluated thunks.
145+ getContext :: ContextMap -> PositionResult Position -> Context
146+ getContext (ContextMap chunks) query =
147+ case searchChunks True chunks of
148+ (groups, NoContext ) -> TopContext groups
149+ (_, ContextResult _ found) -> found
150+ where
151+ (qLo, qHi) = case query of
152+ PositionExact p -> (p, p)
153+ PositionRange l u -> (l, u)
154+
155+ searchChunks :: Bool -> [ContextChunk ] -> ([ContextGroup ], ContextResult )
156+ searchChunks _ [] = ([] , mempty )
157+ searchChunks firstChunk (Chunk cLo cHi group contextOf : rest)
158+ | -- query is past this chunk
159+ qLo > cHi = searchChunks False rest
160+ | -- query is before this chunk
161+ qHi < cLo = (if firstChunk then [HeaderGroup ] else [] , mempty )
162+ -- this chunk is relevant, emit the group and all relevant intervals
163+ | otherwise = ([group], contextOf (Range qLo qHi)) <> searchChunks False rest
164+
165+ -- * SYB queries types
166+
161167importQ :: Range -> LImportDecl GhcPs -> (ContextResult , Bool )
162168importQ query impDecl'@ (L _ impDecl) =
163169 let importModuleName = T. pack $ moduleNameString $ unLoc $ ideclName impDecl
@@ -190,33 +196,34 @@ sigQ = contextual TypeContext True
190196bindQ :: Range -> LHsBind GhcPs -> (ContextResult , Bool )
191197bindQ = contextual ValueContext False
192198
199+ contextual :: HasLoc a => Context -> Bool -> Range -> a -> (ContextResult , Bool )
200+ contextual context shouldStop query s =
201+ let range = rangeOf s
202+ in case range of
203+ Nothing -> (mempty , True )
204+ Just range | outside query range -> (mempty , True )
205+ Just range -> (ContextResult range context, shouldStop)
206+
207+ -- * Helpers
208+
193209dominates :: Range -> Range -> Bool
194210dominates (Range s e) (Range qs qe) = s <= qs && qe <= e
195211
196212outside :: Range -> Range -> Bool
197213outside (Range ps pe) (Range qs qe) = pe < qs || ps > qe
198214
199- -- | Look up the completion context at a given position.
200- -- Returns the innermost (most specific) context that contains the position.
201- --
202- -- Only the 'ContextChunks' up to and including the chunk containing the
203- -- query position are forced; later chunks remain as unevaluated thunks.
204- getContext :: ContextMap -> PositionResult Position -> Context
205- getContext (ContextMap chunks) query =
206- case searchChunks True chunks of
207- (groups, NoContext ) -> TopContext groups
208- (_, ContextResult _ found) -> found
209- where
210- (qLo, qHi) = case query of
211- PositionExact p -> (p, p)
212- PositionRange l u -> (l, u)
215+ instance Pretty Context where
216+ pretty = \ case
217+ TypeContext -> " type context"
218+ ValueContext -> " value context"
219+ ImportContext mod -> " import context " <> pretty mod
220+ ImportListContext mod -> " import explicit context " <> pretty mod
221+ ImportHidingContext mod -> " import hiding context " <> pretty mod
222+ TopContext cg -> " top context " <> pretty cg
223+ DefaultContext -> " unknown context"
213224
214- searchChunks :: Bool -> [ContextChunk ] -> ([ContextGroup ], ContextResult )
215- searchChunks _ [] = ([] , mempty )
216- searchChunks firstChunk (Chunk cLo cHi group contextOf : rest)
217- | -- query is past this chunk
218- qLo > cHi = searchChunks False rest
219- | -- query is before this chunk
220- qHi < cLo = (if firstChunk then [HeaderGroup ] else [] , mempty )
221- -- this chunk is relevant, emit the group and all relevant intervals
222- | otherwise = ([group], contextOf (Range qLo qHi)) <> searchChunks False rest
225+ instance Pretty ContextGroup where
226+ pretty = \ case
227+ HeaderGroup -> " header"
228+ ImportGroup -> " imports"
229+ DeclarationGroup -> " declarations"
0 commit comments