@@ -50,6 +50,7 @@ import Language.LSP.VFS (VirtualFile)
50
50
import qualified Language.LSP.VFS as VFS
51
51
import qualified Text.Fuzzy.Parallel as Fuzzy
52
52
53
+
53
54
data Log
54
55
= LogModificationTime NormalizedFilePath FileVersion
55
56
| LogShake Shake. Log
@@ -288,56 +289,68 @@ completion _ide _ complParams = do
288
289
result Nothing _ = J. List []
289
290
result (Just pfix) cnts
290
291
| pos ^. JL. line == 0 = J. List [buildCompletion (fst cabalVersionKeyword)]
291
- | Just ctx@ (Stanza s kwContext) <- context =
292
- case (Map. lookup s stanzaKeywordMap) of
293
- Nothing ->
294
- case kwContext of
295
- None ->
296
- J. List $
297
- makeCompletionItems pfix topLevelKeywords
298
- KeyWord kw -> J. List $ makeCompletionItems pfix (getPossibleValuesForKeyWord kw ctx)
299
- Just m ->
300
- case kwContext of
301
- None -> J. List $ (makeCompletionItems pfix (Map. keys m)) ++ (makeCompletionItems pfix $ Map. keys stanzaKeywordMap)
302
- KeyWord kw -> J. List $ makeCompletionItems pfix (getPossibleValuesForKeyWord kw ctx)
303
- | Just ctx@ (TopLevel kwContext) <- context =
304
- case kwContext of
305
- None -> J. List $ makeCompletionItems pfix topLevelKeywords
306
- KeyWord kw -> J. List $ makeCompletionItems pfix (getPossibleValuesForKeyWord kw ctx)
292
+ | Just ctx <- context = J. List $ makeCompletionItems pfix (getCompletionsForContext ctx)
307
293
| otherwise = J. List []
308
294
where
309
295
pos = VFS. cursorPos pfix
310
- topLevelKeywords = Map. keys cabalKeywords ++ Map. keys stanzaKeywordMap
311
- context = findCurrentContext pos (cnts ^. VFS. file_text)
312
-
313
- getPossibleValuesForKeyWord :: T. Text -> Context -> [T. Text ]
314
- getPossibleValuesForKeyWord kw (TopLevel _) =
296
+ context = getContext pos (Rope. lines $ cnts ^. VFS. file_text)
297
+
298
+ -- | Takes a context and returns all possible completions within that context
299
+ getCompletionsForContext :: Context -> [T. Text ]
300
+ -- if we are in the top level of the cabal file and not in a keyword context,
301
+ -- we can write any toplevel keywords or a stanza declaration
302
+ getCompletionsForContext (TopLevel , None ) =
303
+ Map. keys cabalKeywords ++ Map. keys stanzaKeywordMap
304
+ -- if we are in a keyword context in the toplevel,
305
+ -- we look up that keyword in the toplevel context and can complete its possible values
306
+ getCompletionsForContext (TopLevel , KeyWord kw) =
315
307
case Map. lookup kw cabalKeywords of
316
308
Nothing -> []
317
309
Just l -> l
318
- getPossibleValuesForKeyWord kw (Stanza s _) =
310
+ -- if we are in a stanza and not in a keyword context,
311
+ -- we can write any of the stanza's keywords or a stanza declaration
312
+ getCompletionsForContext (Stanza s, None ) =
313
+ case Map. lookup s stanzaKeywordMap of
314
+ Nothing -> []
315
+ Just l -> Map. keys l ++ Map. keys stanzaKeywordMap
316
+ -- if we are in a stanza's keyword's context we can complete possible values of that keyword
317
+ getCompletionsForContext (Stanza s, KeyWord kw) =
319
318
case Map. lookup s stanzaKeywordMap of
320
319
Nothing -> []
321
320
Just m -> case Map. lookup kw m of
322
321
Nothing -> []
323
322
Just l -> l
324
323
325
- findCurrentContext :: Position -> Rope. Rope -> Maybe Context
326
- findCurrentContext pos rope =
327
- case outerContext of
328
- TopLevel _ -> TopLevel <$> getKeyWordContext cabalKeywords
329
- Stanza s _ ->
330
- case traceShowId (Map. lookup (traceShowId s) stanzaKeywordMap) of
331
- Nothing -> pure $ Stanza s None
332
- Just m -> traceShowId $ Stanza s <$> getKeyWordContext m
333
- where
334
- outerContext = findCurrentLevel (getPreviousLines pos rope) None
335
- currentLine = traceShowId $ (Rope. lines rope) Extra. !? (fromIntegral $ pos ^. JL. line)
336
- getKeyWordContext keywords = do
324
+ -- | Takes a position and a list of lines (representing a file)
325
+ -- and returns the context of the current position
326
+ -- can return Nothing if an error occurs
327
+ getContext :: Position -> [T. Text ] -> Maybe Context
328
+ getContext pos ls =
329
+ case lvlContext of
330
+ TopLevel -> do
331
+ kwContext <- getKeyWordContext pos ls cabalKeywords
332
+ pure (TopLevel , kwContext)
333
+ Stanza s ->
334
+ case Map. lookup (traceShowId s) stanzaKeywordMap of
335
+ Nothing -> do
336
+ pure (Stanza s, None )
337
+ Just m -> do
338
+ kwContext <- getKeyWordContext pos ls m
339
+ pure (Stanza s, kwContext)
340
+ where
341
+ lvlContext = findCurrentLevel (ls)
342
+
343
+ -- | Takes a position, a list of lines (representing a file) and a map of keywords as keys
344
+ -- and returns a keyword context if there is a keyword from the map before the current position
345
+ -- in the given line list
346
+ getKeyWordContext :: Position -> [T. Text ] -> Map T. Text a -> Maybe KeyWordContext
347
+ getKeyWordContext pos ls keywords = do
337
348
curLine <- fmap T. stripStart currentLine
338
- case List. find (\ kw -> traceShowId kw `T.isPrefixOf` curLine) (traceShowId $ Map. keys keywords) of
349
+ case List. find (`T.isPrefixOf` curLine) (Map. keys keywords) of
339
350
Nothing -> Just None
340
351
Just kw -> Just $ KeyWord kw
352
+ where
353
+ currentLine = ls Extra. !? (fromIntegral $ pos ^. JL. line)
341
354
342
355
-- | Takes info about the current cursor position and a set of possible keywords
343
356
-- and creates completion suggestions that fit the current input from the given list
@@ -350,11 +363,11 @@ makeCompletionItems pfix l =
350
363
-- | Parse the given set of lines (starting before current cursor position
351
364
-- up to the start of the file) to find the nearest stanza declaration,
352
365
-- if none is found we are in the top level
353
- findCurrentLevel :: [T. Text ] -> KeyWordContext -> Context
354
- findCurrentLevel [] kwContext = TopLevel kwContext
355
- findCurrentLevel (cur : xs) kwContext
356
- | Just s <- stanza = Stanza s kwContext
357
- | otherwise = findCurrentLevel xs kwContext
366
+ findCurrentLevel :: [T. Text ] -> LevelContext
367
+ findCurrentLevel [] = TopLevel
368
+ findCurrentLevel (cur : xs)
369
+ | Just s <- stanza = Stanza s
370
+ | otherwise = findCurrentLevel xs
358
371
where
359
372
stanza = List. find (`T.isPrefixOf` cur) (Map. keys stanzaKeywordMap)
360
373
@@ -366,19 +379,25 @@ getPreviousLines pos rope = reverse $ take (fromIntegral currentLine) allLines
366
379
allLines = Rope. lines rope
367
380
currentLine = pos ^. JL. line
368
381
369
- data Context
370
- = TopLevel KeyWordContext
371
- -- ^ top level context in a cabal file such as 'author'
372
- | Stanza T. Text KeyWordContext
373
- -- ^ nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
382
+ -- | The context a cursor can be in within a cabal file,
383
+ -- we can be in stanzas or the toplevel,
384
+ -- and additionally we can be in a context where we have already written a keyword
385
+ -- but no value for it yet
386
+ type Context = (LevelContext , KeyWordContext )
387
+
388
+ data LevelContext
389
+ = TopLevel
390
+ -- ^ Top level context in a cabal file such as 'author'
391
+ | Stanza T. Text
392
+ -- ^ Nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
374
393
deriving (Eq , Show )
375
394
376
395
-- | Keyword context in cabal file
377
396
data KeyWordContext
378
397
= KeyWord T. Text
379
- -- ^ we are in a line with the given keyword before our cursor
398
+ -- ^ We are in a line with the given keyword before our cursor
380
399
| None
381
- -- ^ we are in a line with no keyword context
400
+ -- ^ We are in a line with no keyword context
382
401
deriving (Eq , Show )
383
402
384
403
-- | Keyword for cabal version required to be the top line in a cabal file
0 commit comments