@@ -20,26 +20,20 @@ import qualified Data.ByteString as BS
20
20
import Data.Hashable
21
21
import Data.HashMap.Strict (HashMap )
22
22
import qualified Data.HashMap.Strict as HashMap
23
- import qualified Data.List as List
24
- import qualified Data.List.Extra as Extra
25
23
import qualified Data.List.NonEmpty as NE
26
- import Data.Map (Map )
27
- import qualified Data.Map as Map
28
- import qualified Data.Text as T
29
24
import qualified Data.Text.Encoding as Encoding
30
25
import qualified Data.Text.Utf16.Rope as Rope
31
26
import Data.Typeable
32
- import Debug.Trace
33
27
import Development.IDE as D
34
28
import Development.IDE.Core.Shake (restartShakeSession )
35
29
import qualified Development.IDE.Core.Shake as Shake
36
30
import Development.IDE.Graph (alwaysRerun )
37
31
import Distribution.Compat.Lens ((^.) )
38
32
import GHC.Generics
33
+ import Ide.Plugin.Cabal.Completions
39
34
import qualified Ide.Plugin.Cabal.Diagnostics as Diagnostics
40
35
import qualified Ide.Plugin.Cabal.LicenseSuggest as LicenseSuggest
41
36
import qualified Ide.Plugin.Cabal.Parse as Parse
42
- import Ide.Plugin.Config (Config )
43
37
import Ide.Types
44
38
import qualified Language.LSP.Server as LSP
45
39
import Language.LSP.Types
@@ -48,7 +42,6 @@ import qualified Language.LSP.Types as LSP
48
42
import qualified Language.LSP.Types.Lens as JL
49
43
import Language.LSP.VFS (VirtualFile )
50
44
import qualified Language.LSP.VFS as VFS
51
- import qualified Text.Fuzzy.Parallel as Fuzzy
52
45
53
46
54
47
data Log
@@ -288,7 +281,7 @@ completion _ide _ complParams = do
288
281
result :: Maybe VFS. PosPrefixInfo -> VirtualFile -> J. List CompletionItem
289
282
result Nothing _ = J. List []
290
283
result (Just pfix) cnts
291
- | pos ^. JL. line == 0 = case traceShowId $ context of
284
+ | pos ^. JL. line == 0 = case context of
292
285
Just (_, kw)
293
286
| KeyWord _ <- kw -> J. List $ map buildCompletion $ snd cabalVersionKeyword
294
287
_ -> J. List [buildCompletion (fst cabalVersionKeyword)]
@@ -297,272 +290,3 @@ completion _ide _ complParams = do
297
290
where
298
291
pos = VFS. cursorPos pfix
299
292
context = getContext pos (Rope. lines $ cnts ^. VFS. file_text)
300
-
301
- -- | Takes a context and returns all possible completions within that context
302
- getCompletionsForContext :: Context -> [T. Text ]
303
- -- if we are in the top level of the cabal file and not in a keyword context,
304
- -- we can write any toplevel keywords or a stanza declaration
305
- getCompletionsForContext (TopLevel , None ) =
306
- Map. keys cabalKeywords ++ Map. keys stanzaKeywordMap
307
- -- if we are in a keyword context in the toplevel,
308
- -- we look up that keyword in the toplevel context and can complete its possible values
309
- getCompletionsForContext (TopLevel , KeyWord kw) =
310
- case Map. lookup kw cabalKeywords of
311
- Nothing -> []
312
- Just l -> l
313
- -- if we are in a stanza and not in a keyword context,
314
- -- we can write any of the stanza's keywords or a stanza declaration
315
- getCompletionsForContext (Stanza s, None ) =
316
- case Map. lookup s stanzaKeywordMap of
317
- Nothing -> []
318
- Just l -> Map. keys l ++ Map. keys stanzaKeywordMap
319
- -- if we are in a stanza's keyword's context we can complete possible values of that keyword
320
- getCompletionsForContext (Stanza s, KeyWord kw) =
321
- case Map. lookup s stanzaKeywordMap of
322
- Nothing -> []
323
- Just m -> case Map. lookup kw m of
324
- Nothing -> []
325
- Just l -> l
326
-
327
- -- | Takes a position and a list of lines (representing a file)
328
- -- and returns the context of the current position
329
- -- can return Nothing if an error occurs
330
- getContext :: Position -> [T. Text ] -> Maybe Context
331
- getContext pos ls =
332
- case lvlContext of
333
- TopLevel -> do
334
- kwContext <- getKeyWordContext pos ls (uncurry Map. insert cabalVersionKeyword cabalKeywords)
335
- pure (TopLevel , kwContext)
336
- Stanza s ->
337
- case Map. lookup (traceShowId s) stanzaKeywordMap of
338
- Nothing -> do
339
- pure (Stanza s, None )
340
- Just m -> do
341
- kwContext <- getKeyWordContext pos ls m
342
- pure (Stanza s, kwContext)
343
- where
344
- lvlContext = findCurrentLevel (getPreviousLines pos ls)
345
-
346
- -- | Takes a position, a list of lines (representing a file) and a map of keywords as keys
347
- -- and returns a keyword context if there is a keyword from the map before the current position
348
- -- in the given line list
349
- getKeyWordContext :: Position -> [T. Text ] -> Map T. Text a -> Maybe KeyWordContext
350
- getKeyWordContext pos ls keywords = do
351
- curLine <- fmap T. stripStart currentLine
352
- case List. find (`T.isPrefixOf` curLine) (Map. keys keywords) of
353
- Nothing -> Just None
354
- Just kw -> Just $ KeyWord kw
355
- where
356
- currentLine = ls Extra. !? (fromIntegral $ pos ^. JL. line)
357
-
358
- -- | Takes info about the current cursor position and a set of possible keywords
359
- -- and creates completion suggestions that fit the current input from the given list
360
- makeCompletionItems :: VFS. PosPrefixInfo -> [T. Text ] -> [CompletionItem ]
361
- makeCompletionItems pfix l =
362
- map
363
- (buildCompletion . Fuzzy. original)
364
- (Fuzzy. simpleFilter 1000 10 (VFS. prefixText pfix) l)
365
-
366
- -- | Parse the given set of lines (starting before current cursor position
367
- -- up to the start of the file) to find the nearest stanza declaration,
368
- -- if none is found we are in the top level
369
- findCurrentLevel :: [T. Text ] -> LevelContext
370
- findCurrentLevel [] = TopLevel
371
- findCurrentLevel (cur : xs)
372
- | Just s <- stanza = Stanza s
373
- | otherwise = findCurrentLevel xs
374
- where
375
- stanza = List. find (`T.isPrefixOf` cur) (Map. keys stanzaKeywordMap)
376
-
377
- -- | Get all lines before the given cursor position in the given file
378
- -- and reverse them since we want to traverse starting from our current position
379
- getPreviousLines :: Position -> [T. Text ] -> [T. Text ]
380
- getPreviousLines pos ls = reverse $ take (fromIntegral currentLine) ls
381
- where
382
- currentLine = pos ^. JL. line
383
-
384
- -- | The context a cursor can be in within a cabal file,
385
- -- we can be in stanzas or the toplevel,
386
- -- and additionally we can be in a context where we have already written a keyword
387
- -- but no value for it yet
388
- type Context = (LevelContext , KeyWordContext )
389
-
390
- data LevelContext
391
- = TopLevel
392
- -- ^ Top level context in a cabal file such as 'author'
393
- | Stanza T. Text
394
- -- ^ Nested context in a cabal file, such as 'library', which has nested keywords, specific to the stanza
395
- deriving (Eq , Show )
396
-
397
- -- | Keyword context in cabal file
398
- data KeyWordContext
399
- = KeyWord T. Text
400
- -- ^ We are in a line with the given keyword before our cursor
401
- | None
402
- -- ^ We are in a line with no keyword context
403
- deriving (Eq , Show )
404
-
405
- -- | Keyword for cabal version required to be the top line in a cabal file
406
- cabalVersionKeyword :: (T. Text ,[T. Text ])
407
- cabalVersionKeyword = (" cabal-version:" , [" 2.0" , " 2.2" , " 2.4" , " 3.0" ])
408
-
409
-
410
- -- todo: we could add file path completion for file path fields
411
- -- we could add descriptions of field values and then show them when inside the field's context
412
- -- | Top level keywords of a cabal file
413
- cabalKeywords :: Map T. Text [T. Text ]
414
- cabalKeywords =
415
- Map. fromList [
416
- (" name:" , [] ),
417
- (" version:" , [] ),
418
- (" build-type:" , [" Simple" , " Custom" ]),
419
- (" license:" , [" NONE" ]),
420
- (" license-file:" , [] ),
421
- (" license-files:" ,[] ),
422
- (" copyright:" , [] ),
423
- (" author:" , [] ),
424
- (" maintainer:" ,[] ),
425
- (" stability:" ,[] ),
426
- (" homepage:" ,[] ),
427
- (" bug-reports:" ,[] ),
428
- (" package-url:" ,[] ),
429
- (" synopsis:" ,[] ),
430
- (" description:" ,[] ),
431
- (" category:" ,[] ),
432
- (" tested-with:" ,[" GHC" ]),
433
- (" data-files:" , [] ),
434
- (" data-dir:" , [] ),
435
- (" data-dir:" , [] ),
436
- (" extra-source-files:" , [] ),
437
- (" extra-doc-files:" , [] ),
438
- (" extra-tmp-files:" , [] )
439
- ]
440
-
441
- -- | Map, containing all stanzas in a cabal file as keys and lists of their possible nested keywords as values
442
- stanzaKeywordMap :: Map T. Text (Map T. Text [T. Text ])
443
- stanzaKeywordMap =
444
- Map. fromList
445
- [ ( " library" ,
446
- Map. fromList $
447
- [ (" exposed-modules:" , [] ),
448
- (" virtual-modules:" , [] ),
449
- (" exposed:" , [" True" , " False" ]),
450
- (" visibility:" , [" private" , " public" ]),
451
- (" reexported-modules:" , [] ),
452
- (" signatures:" , [] )
453
- ]
454
- ++ libExecTestBenchCommons
455
- ),
456
- ( " executable" ,
457
- Map. fromList $
458
- [ (" main-is:" , [] ),
459
- (" scope:" , [" public" , " private" ])
460
- ]
461
- ++ libExecTestBenchCommons
462
- ),
463
- ( " test-suite" ,
464
- Map. fromList $
465
- [ (" type:" , [" exitcode-stdio-1.0" ]),
466
- (" main-is:" , [] )
467
- ]
468
- ++ libExecTestBenchCommons
469
- ),
470
- ( " benchmark" ,
471
- Map. fromList $
472
- [ (" type:" , [] ),
473
- (" main-is:" , [] )
474
- ]
475
- ++ libExecTestBenchCommons
476
- ),
477
- ( " foreign-library" ,
478
- Map. fromList
479
- [ (" type:" , [] ),
480
- (" options:" , [] ),
481
- (" mod-def-file:" , [] ),
482
- (" lib-def-file:" , [] ),
483
- (" lib-version-info:" , [] ),
484
- (" lib-version-linux:" , [] )
485
- ]
486
- ),
487
- ( " flag" ,
488
- Map. fromList
489
- [ (" description:" , [] ),
490
- (" default:" , [" True" , " False" ]),
491
- (" manual:" , [" False" , " True" ]),
492
- (" lib-def-file:" , [] ),
493
- (" lib-version-info:" , [] ),
494
- (" lib-version-linux:" , [] )
495
- ]
496
- )
497
- ]
498
- where
499
- libExecTestBenchCommons =
500
- [ (" build-depends:" , [] ),
501
- (" other-modules:" , [] ),
502
- (" hs-source-dir:" , [" ." ]),
503
- (" hs-source-dirs:" , [" ." ]),
504
- (" default-extensions:" , [] ),
505
- (" other-extensions:" , [] ),
506
- (" default-language:" , [] ),
507
- (" build-tool-depends:" , [] ),
508
- (" buildable:" , [" True" , " False" ]),
509
- -- todo maybe there is a list of possible ghc options somewhere
510
- (" ghc-options:" , [] ),
511
- (" ghc-prof-options:" , [] ),
512
- (" ghc-shared-options:" , [] ),
513
- (" ghcjs-options:" , [] ),
514
- (" ghcjs-prof-options:" , [] ),
515
- (" ghcjs-shared-options:" , [] ),
516
- (" includes:" , [] ),
517
- (" install-includes:" , [] ),
518
- (" include-dirs:" , [] ),
519
- (" c-sources:" , [] ),
520
- (" cxx-sources:" , [] ),
521
- (" asm-sources:" , [] ),
522
- (" cmm-sources:" , [] ),
523
- (" js-sources:" , [] ),
524
- (" extra-libraries:" , [] ),
525
- (" extra-ghci-libraries:" , [] ),
526
- (" extra-bundled-libraries:" , [] ),
527
- (" extra-lib-dirs:" , [] ),
528
- (" cc-options:" , [] ),
529
- (" cpp-options:" , [] ),
530
- (" cxx-options:" , [] ),
531
- (" cmm-options:" , [] ),
532
- (" asm-options:" , [] ),
533
- (" ld-options:" , [] ),
534
- (" pkgconfig-depends:" , [] ),
535
- (" frameworks:" , [] ),
536
- (" extra-framework-dirs:" , [] ),
537
- (" mixins:" , [] )
538
- ]
539
-
540
- -- cabalFlagKeywords :: [(T.Text, T.Text)]
541
- -- cabalFlagKeywords =
542
- -- [
543
- -- ("flag", "name"),
544
- -- ("description:", "freeform"),
545
- -- ("default:", "boolean"),
546
- -- ("manual:", "boolean")
547
- -- ]
548
-
549
- -- cabalStanzaKeywords :: [(T.Text, T.Text)]
550
- -- cabalStanzaKeywords =
551
- -- [
552
- -- ("common", "name"),
553
- -- ("import:", "token-list")
554
- -- ]
555
-
556
- -- cabalSourceRepoKeywords :: [(T.Text, T.Text)]
557
- -- cabalSourceRepoKeywords =
558
- -- [
559
- -- ("source-repository", ""),
560
- -- ("type:", "token"),
561
- -- ("location:", "URL")
562
- -- ]
563
-
564
- buildCompletion :: T. Text -> J. CompletionItem
565
- buildCompletion label =
566
- J. CompletionItem label (Just J. CiKeyword ) Nothing Nothing
567
- Nothing Nothing Nothing Nothing Nothing Nothing Nothing
568
- Nothing Nothing Nothing Nothing Nothing Nothing
0 commit comments