@@ -43,8 +43,6 @@ import qualified Data.Map as Map
43
43
import Language.LSP.VFS (VirtualFile )
44
44
import qualified Data.Text.Utf16.Rope as Rope
45
45
import qualified Data.List as List
46
- import qualified Language.LSP.Types.Lens as Map
47
- import Development.IDE.GHC.Compat (getContext )
48
46
import Debug.Trace
49
47
import qualified Data.List.Extra as Extra
50
48
data Log
@@ -186,56 +184,68 @@ completion _ide _ complParams = do
186
184
result Nothing _ = J. List []
187
185
result (Just pfix) cnts
188
186
| pos ^. JL. line == 0 = J. List [buildCompletion (fst cabalVersionKeyword)]
189
- | Just ctx@ (Stanza s kwContext) <- context =
190
- case (Map. lookup s stanzaKeywordMap) of
191
- Nothing ->
192
- case kwContext of
193
- None ->
194
- J. List $
195
- makeCompletionItems pfix topLevelKeywords
196
- KeyWord kw -> J. List $ makeCompletionItems pfix (getPossibleValuesForKeyWord kw ctx)
197
- Just m ->
198
- case kwContext of
199
- None -> J. List $ (makeCompletionItems pfix (Map. keys m)) ++ (makeCompletionItems pfix $ Map. keys stanzaKeywordMap)
200
- KeyWord kw -> J. List $ makeCompletionItems pfix (getPossibleValuesForKeyWord kw ctx)
201
- | Just ctx@ (TopLevel kwContext) <- context =
202
- case kwContext of
203
- None -> J. List $ makeCompletionItems pfix topLevelKeywords
204
- KeyWord kw -> J. List $ makeCompletionItems pfix (getPossibleValuesForKeyWord kw ctx)
187
+ | Just ctx <- context = J. List $ makeCompletionItems pfix (getCompletionsForContext ctx)
205
188
| otherwise = J. List []
206
189
where
207
190
pos = VFS. cursorPos pfix
208
- topLevelKeywords = Map. keys cabalKeywords ++ Map. keys stanzaKeywordMap
209
- context = findCurrentContext pos (cnts ^. VFS. file_text)
210
-
211
- getPossibleValuesForKeyWord :: T. Text -> Context -> [T. Text ]
212
- getPossibleValuesForKeyWord kw (TopLevel _) =
191
+ context = getContext pos (Rope. lines $ cnts ^. VFS. file_text)
192
+
193
+ -- | Takes a context and returns all possible completions within that context
194
+ getCompletionsForContext :: Context -> [T. Text ]
195
+ -- if we are in the top level of the cabal file and not in a keyword context,
196
+ -- we can write any toplevel keywords or a stanza declaration
197
+ getCompletionsForContext (TopLevel , None ) =
198
+ Map. keys cabalKeywords ++ Map. keys stanzaKeywordMap
199
+ -- if we are in a keyword context in the toplevel,
200
+ -- we look up that keyword in the toplevel context and can complete its possible values
201
+ getCompletionsForContext (TopLevel , KeyWord kw) =
213
202
case Map. lookup kw cabalKeywords of
214
203
Nothing -> []
215
204
Just l -> l
216
- getPossibleValuesForKeyWord kw (Stanza s _) =
205
+ -- if we are in a stanza and not in a keyword context,
206
+ -- we can write any of the stanza's keywords or a stanza declaration
207
+ getCompletionsForContext (Stanza s, None ) =
208
+ case Map. lookup s stanzaKeywordMap of
209
+ Nothing -> []
210
+ Just l -> Map. keys l ++ Map. keys stanzaKeywordMap
211
+ -- if we are in a stanza's keyword's context we can complete possible values of that keyword
212
+ getCompletionsForContext (Stanza s, KeyWord kw) =
217
213
case Map. lookup s stanzaKeywordMap of
218
214
Nothing -> []
219
215
Just m -> case Map. lookup kw m of
220
216
Nothing -> []
221
217
Just l -> l
222
218
223
- findCurrentContext :: Position -> Rope. Rope -> Maybe Context
224
- findCurrentContext pos rope =
225
- case outerContext of
226
- TopLevel _ -> TopLevel <$> getKeyWordContext cabalKeywords
227
- Stanza s _ ->
228
- case traceShowId (Map. lookup (traceShowId s) stanzaKeywordMap) of
229
- Nothing -> pure $ Stanza s None
230
- Just m -> traceShowId $ Stanza s <$> getKeyWordContext m
231
- where
232
- outerContext = findCurrentLevel (getPreviousLines pos rope) None
233
- currentLine = traceShowId $ (Rope. lines rope) Extra. !? (fromIntegral $ pos ^. JL. line)
234
- getKeyWordContext keywords = do
219
+ -- | Takes a position and a list of lines (representing a file)
220
+ -- and returns the context of the current position
221
+ -- can return Nothing if an error occurs
222
+ getContext :: Position -> [T. Text ] -> Maybe Context
223
+ getContext pos ls =
224
+ case lvlContext of
225
+ TopLevel -> do
226
+ kwContext <- getKeyWordContext pos ls cabalKeywords
227
+ pure (TopLevel , kwContext)
228
+ Stanza s ->
229
+ case Map. lookup (traceShowId s) stanzaKeywordMap of
230
+ Nothing -> do
231
+ pure (Stanza s, None )
232
+ Just m -> do
233
+ kwContext <- getKeyWordContext pos ls m
234
+ pure (Stanza s, kwContext)
235
+ where
236
+ lvlContext = findCurrentLevel (ls)
237
+
238
+ -- | Takes a position, a list of lines (representing a file) and a map of keywords as keys
239
+ -- and returns a keyword context if there is a keyword from the map before the current position
240
+ -- in the given line list
241
+ getKeyWordContext :: Position -> [T. Text ] -> Map T. Text a -> Maybe KeyWordContext
242
+ getKeyWordContext pos ls keywords = do
235
243
curLine <- fmap T. stripStart currentLine
236
- case List. find (\ kw -> traceShowId kw `T.isPrefixOf` curLine) (traceShowId $ Map. keys keywords) of
244
+ case List. find (`T.isPrefixOf` curLine) (Map. keys keywords) of
237
245
Nothing -> Just None
238
246
Just kw -> Just $ KeyWord kw
247
+ where
248
+ currentLine = ls Extra. !? (fromIntegral $ pos ^. JL. line)
239
249
240
250
-- | Takes info about the current cursor position and a set of possible keywords
241
251
-- and creates completion suggestions that fit the current input from the given list
@@ -248,11 +258,11 @@ makeCompletionItems pfix l =
248
258
-- | Parse the given set of lines (starting before current cursor position
249
259
-- up to the start of the file) to find the nearest stanza declaration,
250
260
-- if none is found we are in the top level
251
- findCurrentLevel :: [T. Text ] -> KeyWordContext -> Context
252
- findCurrentLevel [] kwContext = TopLevel kwContext
253
- findCurrentLevel (cur : xs) kwContext
254
- | Just s <- stanza = Stanza s kwContext
255
- | otherwise = findCurrentLevel xs kwContext
261
+ findCurrentLevel :: [T. Text ] -> LevelContext
262
+ findCurrentLevel [] = TopLevel
263
+ findCurrentLevel (cur : xs)
264
+ | Just s <- stanza = Stanza s
265
+ | otherwise = findCurrentLevel xs
256
266
where
257
267
stanza = List. find (`T.isPrefixOf` cur) (Map. keys stanzaKeywordMap)
258
268
@@ -264,19 +274,25 @@ getPreviousLines pos rope = reverse $ take (fromIntegral currentLine) allLines
264
274
allLines = Rope. lines rope
265
275
currentLine = pos ^. JL. line
266
276
267
- data Context
268
- = TopLevel KeyWordContext
269
- -- ^ top level context in a cabal file such as 'author'
270
- | Stanza T. Text KeyWordContext
271
- -- ^ nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
277
+ -- | The context a cursor can be in within a cabal file,
278
+ -- we can be in stanzas or the toplevel,
279
+ -- and additionally we can be in a context where we have already written a keyword
280
+ -- but no value for it yet
281
+ type Context = (LevelContext , KeyWordContext )
282
+
283
+ data LevelContext
284
+ = TopLevel
285
+ -- ^ Top level context in a cabal file such as 'author'
286
+ | Stanza T. Text
287
+ -- ^ Nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
272
288
deriving (Eq , Show )
273
289
274
290
-- | Keyword context in cabal file
275
291
data KeyWordContext
276
292
= KeyWord T. Text
277
- -- ^ we are in a line with the given keyword before our cursor
293
+ -- ^ We are in a line with the given keyword before our cursor
278
294
| None
279
- -- ^ we are in a line with no keyword context
295
+ -- ^ We are in a line with no keyword context
280
296
deriving (Eq , Show )
281
297
282
298
-- | Keyword for cabal version required to be the top line in a cabal file
0 commit comments