@@ -21,13 +21,15 @@ import Data.Hashable
21
21
import Data.HashMap.Strict (HashMap )
22
22
import qualified Data.HashMap.Strict as HashMap
23
23
import qualified Data.List as List
24
+ import qualified Data.List.Extra as Extra
24
25
import qualified Data.List.NonEmpty as NE
25
26
import Data.Map (Map )
26
27
import qualified Data.Map as Map
27
28
import qualified Data.Text as T
28
29
import qualified Data.Text.Encoding as Encoding
29
30
import qualified Data.Text.Utf16.Rope as Rope
30
31
import Data.Typeable
32
+ import Debug.Trace
31
33
import Development.IDE as D
32
34
import Development.IDE.Core.Shake (restartShakeSession )
33
35
import qualified Development.IDE.Core.Shake as Shake
@@ -47,6 +49,7 @@ import qualified Language.LSP.Types.Lens as JL
47
49
import Language.LSP.VFS (VirtualFile )
48
50
import qualified Language.LSP.VFS as VFS
49
51
import qualified Text.Fuzzy.Parallel as Fuzzy
52
+
50
53
data Log
51
54
= LogModificationTime NormalizedFilePath FileVersion
52
55
| LogShake Shake. Log
@@ -284,18 +287,57 @@ completion _ide _ complParams = do
284
287
result :: Maybe VFS. PosPrefixInfo -> VirtualFile -> J. List CompletionItem
285
288
result Nothing _ = J. List []
286
289
result (Just pfix) cnts
287
- | (VFS. cursorPos pfix) ^. JL. line == 0 = J. List [buildCompletion cabalVersionKeyword]
288
- | Stanza s <- findCurrentLevel (getPreviousLines pfix cnts) =
289
- case (Map. lookup s stanzaKeywordMap) of
290
- Nothing ->
291
- J. List $
292
- makeCompletionItems pfix topLevelKeywords
293
- Just l -> J. List $ (makeCompletionItems pfix l) ++ (makeCompletionItems pfix $ Map. keys stanzaKeywordMap)
294
- | otherwise =
295
- J. List $
296
- makeCompletionItems pfix topLevelKeywords
297
- where
298
- topLevelKeywords = cabalKeywords ++ Map. keys stanzaKeywordMap
290
+ | 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)
307
+ | otherwise = J. List []
308
+ where
309
+ 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 _) =
315
+ case Map. lookup kw cabalKeywords of
316
+ Nothing -> []
317
+ Just l -> l
318
+ getPossibleValuesForKeyWord kw (Stanza s _) =
319
+ case Map. lookup s stanzaKeywordMap of
320
+ Nothing -> []
321
+ Just m -> case Map. lookup kw m of
322
+ Nothing -> []
323
+ Just l -> l
324
+
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
337
+ curLine <- fmap T. stripStart currentLine
338
+ case List. find (\ kw -> traceShowId kw `T.isPrefixOf` curLine) (traceShowId $ Map. keys keywords) of
339
+ Nothing -> Just None
340
+ Just kw -> Just $ KeyWord kw
299
341
300
342
-- | Takes info about the current cursor position and a set of possible keywords
301
343
-- and creates completion suggestions that fit the current input from the given list
@@ -308,79 +350,87 @@ makeCompletionItems pfix l =
308
350
-- | Parse the given set of lines (starting before current cursor position
309
351
-- up to the start of the file) to find the nearest stanza declaration,
310
352
-- if none is found we are in the top level
311
- findCurrentLevel :: [T. Text ] -> Context
312
- findCurrentLevel [] = TopLevel
313
- findCurrentLevel (cur : xs)
314
- | Just s <- stanza = Stanza s
315
- | otherwise = findCurrentLevel xs
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
316
358
where
317
359
stanza = List. find (`T.isPrefixOf` cur) (Map. keys stanzaKeywordMap)
318
360
319
361
-- | Get all lines before the given cursor position in the given file
320
362
-- and reverse them since we want to traverse starting from our current position
321
- getPreviousLines :: VFS. PosPrefixInfo -> VirtualFile -> [T. Text ]
322
- getPreviousLines pos cont = reverse $ take (fromIntegral currentLine) allLines
363
+ getPreviousLines :: Position -> Rope. Rope -> [T. Text ]
364
+ getPreviousLines pos rope = reverse $ take (fromIntegral currentLine) allLines
323
365
where
324
- allLines = Rope. lines $ cont ^. VFS. file_text
325
- currentLine = (VFS. cursorPos pos) ^. JL. line
326
-
366
+ allLines = Rope. lines rope
367
+ currentLine = pos ^. JL. line
327
368
328
369
data Context
329
- = TopLevel
370
+ = TopLevel KeyWordContext
330
371
-- ^ top level context in a cabal file such as 'author'
331
- | Stanza T. Text
372
+ | Stanza T. Text KeyWordContext
332
373
-- ^ nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
333
- deriving (Eq )
374
+ deriving (Eq , Show )
375
+
376
+ -- | Keyword context in cabal file
377
+ data KeyWordContext
378
+ = KeyWord T. Text
379
+ -- ^ we are in a line with the given keyword before our cursor
380
+ | None
381
+ -- ^ we are in a line with no keyword context
382
+ deriving (Eq , Show )
334
383
335
384
-- | Keyword for cabal version required to be the top line in a cabal file
336
- cabalVersionKeyword :: T. Text
337
- cabalVersionKeyword = " cabal-version:"
385
+ cabalVersionKeyword :: ( T. Text,[ T. Text ])
386
+ cabalVersionKeyword = ( " cabal-version:" , [] )
338
387
339
388
-- | Top level keywords of a cabal file
340
- cabalKeywords :: [T. Text ]
389
+ cabalKeywords :: Map T. Text [T. Text ]
341
390
cabalKeywords =
342
- [
343
- " name:" ,
344
- " version:" ,
345
- " build-type:" ,
346
- " license:" ,
347
- " license-file:" ,
348
- " license-files:" ,
349
- " copyright:" ,
350
- " author:" ,
351
- " maintainer:" ,
352
- " stability:" ,
353
- " homepage:" ,
354
- " bug-reports:" ,
355
- " package-url:" ,
356
- " synopsis:" ,
357
- " description:" ,
358
- " category:" ,
359
- " tested-with:" ,
360
- " data-files:" ,
361
- " data-dir:" ,
362
- " data-dir:" ,
363
- " extra-doc-files:" ,
364
- " extra-tmp-files:"
391
+ Map. fromList [
392
+ ( " name:" , [] ) ,
393
+ ( " version:" , [] ) ,
394
+ ( " build-type:" , [ " Simple " , " Custom " ]) ,
395
+ ( " license:" , [ " NONE " ]) ,
396
+ ( " license-file:" , [] ) ,
397
+ ( " license-files:" , [] ) ,
398
+ ( " copyright:" , [] ) ,
399
+ ( " author:" , [] )
400
+ -- "maintainer:",
401
+ -- "stability:",
402
+ -- "homepage:",
403
+ -- "bug-reports:",
404
+ -- "package-url:",
405
+ -- "synopsis:",
406
+ -- "description:",
407
+ -- "category:",
408
+ -- "tested-with:",
409
+ -- "data-files:",
410
+ -- "data-dir:",
411
+ -- "data-dir:",
412
+ -- "extra-doc-files:",
413
+ -- "extra-tmp-files:"
365
414
]
366
415
367
416
-- | Map, containing all stanzas in a cabal file as keys and lists of their possible nested keywords as values
368
- stanzaKeywordMap :: Map T. Text [T. Text ]
369
- stanzaKeywordMap = Map. fromList [(" library" , [
370
- " exposed-modules:" ,
371
- " virtual-modules:" ,
372
- " exposed:" ,
373
- " visibility:" ,
374
- " reexported-modules:" ,
375
- " signatures:"
376
- ])]
417
+ stanzaKeywordMap :: Map T. Text (Map T. Text [T. Text ])
418
+ stanzaKeywordMap = Map. fromList [(" library" , Map. fromList[
419
+ (" exposed-modules:" , [] ),
420
+ (" virtual-modules:" , [] ),
421
+ (" exposed:" , [" True" , " False" ]),
422
+ (" visibility:" , [" private" , " public" ]),
423
+ (" reexported-modules:" , [] ),
424
+ (" signatures:" , [] )
425
+ ]),
426
+ (" test-suite" , Map. fromList[] )
427
+ ]
377
428
378
429
379
430
-- TODO move out toplevel commands i.e. test-suite
380
431
-- cabalTestKeywords :: [T.Text]
381
432
-- cabalTestKeywords =
382
433
-- [
383
- -- "test-suite",
384
434
-- "type:",
385
435
-- "main-is:",
386
436
-- "test-module:",
0 commit comments