1
- {-# LANGUAGE DataKinds #-}
1
+ {-# LANGUAGE DataKinds #-}
2
2
{-# LANGUAGE DuplicateRecordFields #-}
3
- {-# LANGUAGE LambdaCase #-}
4
- {-# LANGUAGE OverloadedStrings #-}
5
- {-# LANGUAGE TypeFamilies #-}
3
+ {-# LANGUAGE LambdaCase #-}
4
+ {-# LANGUAGE OverloadedStrings #-}
5
+ {-# LANGUAGE TypeFamilies #-}
6
6
7
7
module Ide.Plugin.Cabal (descriptor , haskellInteractionDescriptor , Log (.. )) where
8
8
9
- import Control.Concurrent.Strict
10
- import Control.DeepSeq
11
- import Control.Lens ((^.) )
12
- import Control.Lens.Fold ((^?) )
13
- import Control.Lens.Prism (_Just )
14
- import Control.Monad.Extra
15
- import Control.Monad.IO.Class
16
- import Control.Monad.Trans.Class (lift )
17
- import Control.Monad.Trans.Maybe (runMaybeT )
18
- import qualified Data.Aeson as A
19
- import qualified Data.ByteString as BS
20
- import Data.Hashable
21
- import Data.HashMap.Strict (HashMap )
22
- import qualified Data.HashMap.Strict as HashMap
23
- import qualified Data.List.NonEmpty as NE
24
- import qualified Data.Map as Map
25
- import qualified Data.Maybe as Maybe
26
- import qualified Data.Text ()
27
- import qualified Data.Text as T
28
- import qualified Data.Text.Encoding as Encoding
29
- import Data.Text.Utf16.Rope.Mixed as Rope
30
- import Data.Typeable
31
- import Development.IDE as D
32
- import Development.IDE.Core.FileStore (getVersionedTextDoc )
33
- import Development.IDE.Core.PluginUtils
34
- import Development.IDE.Core.Shake (restartShakeSession )
35
- import qualified Development.IDE.Core.Shake as Shake
36
- import Development.IDE.Graph (Key ,
37
- alwaysRerun )
38
- import Development.IDE.LSP.HoverDefinition (foundHover )
39
- import qualified Development.IDE.Plugin.Completions.Logic as Ghcide
40
- import Development.IDE.Types.Shake (toKey )
41
- import qualified Distribution.Fields as Syntax
42
- import Distribution.Package (Dependency )
43
- import Distribution.PackageDescription (allBuildDepends ,
44
- depPkgName ,
45
- unPackageName )
46
- import Distribution.PackageDescription.Configuration (flattenPackageDescription )
47
- import qualified Distribution.Parsec.Position as Syntax
48
- import GHC.Generics
49
- import qualified Ide.Plugin.Cabal.CabalAdd as CabalAdd
50
- import Ide.Plugin.Cabal.Completion.CabalFields as CabalFields
51
- import qualified Ide.Plugin.Cabal.Completion.Completer.Types as CompleterTypes
52
- import qualified Ide.Plugin.Cabal.Completion.Completions as Completions
53
- import Ide.Plugin.Cabal.Completion.Types (BuildDependencyVersionMapping (.. ),
54
- ParseCabalCommonSections (ParseCabalCommonSections ),
55
- ParseCabalFields (.. ),
56
- ParseCabalFile (.. ),
57
- ParsePlanJson (.. ),
58
- Positioned (.. ),
59
- SimpleDependency (.. ))
60
- import qualified Ide.Plugin.Cabal.Completion.Types as Types
61
- import Ide.Plugin.Cabal.Definition (gotoDefinition )
62
- import Ide.Plugin.Cabal.Dependencies
63
- import qualified Ide.Plugin.Cabal.Diagnostics as Diagnostics
64
- import qualified Ide.Plugin.Cabal.FieldSuggest as FieldSuggest
65
- import qualified Ide.Plugin.Cabal.LicenseSuggest as LicenseSuggest
66
- import Ide.Plugin.Cabal.Orphans ()
67
- import Ide.Plugin.Cabal.Outline
68
- import qualified Ide.Plugin.Cabal.Parse as Parse
69
- import Ide.Plugin.Error
70
- import Ide.Types
71
- import qualified Language.LSP.Protocol.Lens as JL
72
- import qualified Language.LSP.Protocol.Message as LSP
73
- import Language.LSP.Protocol.Types
74
- import qualified Language.LSP.VFS as VFS
75
- import System.FilePath ((</>) )
76
- import Text.Regex.TDFA
9
+ import Control.Concurrent.Strict
10
+ import Control.DeepSeq
11
+ import Control.Lens ((^.) )
12
+ import Control.Lens.Fold ((^?) )
13
+ import Control.Lens.Prism (_Just )
14
+ import Control.Monad.Extra
15
+ import Control.Monad.IO.Class
16
+ import Control.Monad.Trans.Class (lift )
17
+ import Control.Monad.Trans.Maybe (runMaybeT )
18
+ import Data.ByteString qualified as BS
19
+ import Data.HashMap.Strict (HashMap )
20
+ import Data.HashMap.Strict qualified as HashMap
21
+ import Data.Map qualified as Map
22
+ import Data.Hashable
23
+ import Data.List.NonEmpty qualified as NE
24
+ import Data.Maybe qualified as Maybe
25
+ import Data.Text qualified ()
26
+ import Data.Text qualified as T
27
+ import Data.Text.Encoding qualified as Encoding
28
+ import Data.Text.Utf16.Rope.Mixed as Rope
29
+ import Data.Typeable
30
+ import Data.Aeson qualified as A
31
+ import Development.IDE as D
32
+ import Development.IDE.Core.FileStore (getVersionedTextDoc )
33
+ import Development.IDE.Core.PluginUtils
34
+ import Development.IDE.Core.Shake (restartShakeSession )
35
+ import Development.IDE.Core.Shake qualified as Shake
36
+ import Development.IDE.Graph
37
+ ( Key ,
38
+ alwaysRerun ,
39
+ )
40
+ import Development.IDE.LSP.HoverDefinition (foundHover )
41
+ import Development.IDE.Plugin.Completions.Logic qualified as Ghcide
42
+ import Development.IDE.Types.Shake (toKey )
43
+ import Distribution.Fields qualified as Syntax
44
+ import Distribution.Package (Dependency )
45
+ import Distribution.PackageDescription
46
+ ( allBuildDepends ,
47
+ depPkgName ,
48
+ unPackageName ,
49
+ )
50
+ import Distribution.PackageDescription.Configuration (flattenPackageDescription )
51
+ import Distribution.Parsec.Position qualified as Syntax
52
+ import GHC.Generics
53
+ import Ide.Plugin.Cabal.CabalAdd qualified as CabalAdd
54
+ import Ide.Plugin.Cabal.Completion.CabalFields as CabalFields
55
+ import Ide.Plugin.Cabal.Completion.Completer.Types qualified as CompleterTypes
56
+ import Ide.Plugin.Cabal.Completion.Completions qualified as Completions
57
+ import Ide.Plugin.Cabal.Completion.Types
58
+ ( ParseCabalCommonSections (ParseCabalCommonSections ),
59
+ ParseCabalFields (.. ),
60
+ ParseCabalFile (.. ),
61
+ ParsePlanJson (.. ),
62
+ BuildDependencyVersionMapping (.. ),
63
+ Positioned (.. ),
64
+ SimpleDependency (.. )
65
+ )
66
+ import Ide.Plugin.Cabal.Completion.Types qualified as Types
67
+ import Ide.Plugin.Cabal.Definition (gotoDefinition )
68
+ import Ide.Plugin.Cabal.Dependencies
69
+ import Ide.Plugin.Cabal.Diagnostics qualified as Diagnostics
70
+ import Ide.Plugin.Cabal.FieldSuggest qualified as FieldSuggest
71
+ import Ide.Plugin.Cabal.LicenseSuggest qualified as LicenseSuggest
72
+ import Ide.Plugin.Cabal.Orphans ()
73
+ import Ide.Plugin.Cabal.Outline
74
+ import Ide.Plugin.Cabal.Parse qualified as Parse
75
+ import Ide.Plugin.Error
76
+ import Ide.Types
77
+ import Language.LSP.Protocol.Lens qualified as JL
78
+ import Language.LSP.Protocol.Message qualified as LSP
79
+ import Language.LSP.Protocol.Types
80
+ import Language.LSP.VFS qualified as VFS
81
+ import Text.Regex.TDFA
82
+ import System.FilePath ((</>) )
77
83
78
84
data Log
79
85
= LogModificationTime NormalizedFilePath FileVersion
@@ -135,13 +141,13 @@ descriptor recorder plId =
135
141
pluginHandlers =
136
142
mconcat
137
143
[ mkPluginHandler LSP. SMethod_TextDocumentCodeAction licenseSuggestCodeAction
138
- , mkPluginHandler LSP. SMethod_TextDocumentCompletion $ completion recorder
139
- , mkPluginHandler LSP. SMethod_TextDocumentDocumentSymbol moduleOutline
140
- , mkPluginHandler LSP. SMethod_TextDocumentCodeAction $ fieldSuggestCodeAction recorder
141
- , mkPluginHandler LSP. SMethod_TextDocumentDefinition gotoDefinition
142
- , mkPluginHandler LSP. SMethod_TextDocumentHover hover
143
- , mkPluginHandler LSP. SMethod_TextDocumentInlayHint hint
144
- , mkPluginHandler LSP. SMethod_TextDocumentCodeLens lens
144
+ , mkPluginHandler LSP. SMethod_TextDocumentCompletion $ completion recorder
145
+ , mkPluginHandler LSP. SMethod_TextDocumentDocumentSymbol moduleOutline
146
+ , mkPluginHandler LSP. SMethod_TextDocumentCodeAction $ fieldSuggestCodeAction recorder
147
+ , mkPluginHandler LSP. SMethod_TextDocumentDefinition gotoDefinition
148
+ , mkPluginHandler LSP. SMethod_TextDocumentHover hover
149
+ , mkPluginHandler LSP. SMethod_TextDocumentInlayHint hint
150
+ , mkPluginHandler LSP. SMethod_TextDocumentCodeLens lens
145
151
],
146
152
pluginNotificationHandlers =
147
153
mconcat
@@ -235,21 +241,21 @@ cabalRules recorder plId = do
235
241
)
236
242
fields
237
243
pure ([] , Just commonSections)
238
-
244
+
239
245
define (cmapWithPrio LogShake recorder) $ \ ParsePlanJson file -> do
240
246
(_, planSrc) <- use_ GetFileContents file
241
-
247
+
242
248
contents <- case planSrc of
243
249
Just sources -> pure $ Encoding. encodeUtf8 $ Rope. toText sources
244
- Nothing -> do liftIO $ BS. readFile $ fromNormalizedFilePath file
245
-
250
+ Nothing -> do liftIO $ BS. readFile $ fromNormalizedFilePath file
251
+
246
252
pure ([] , installPlan <$> A. decodeStrict contents)
247
-
253
+
248
254
define (cmapWithPrio LogShake recorder) $ \ BuildDependencyVersionMapping file -> do
249
- deps <- use_ ParsePlanJson file
250
-
255
+ deps <- use_ ParsePlanJson file
256
+
251
257
let versionMapping = Map. fromList $ map (\ d -> (_pkgName d, _pkgVersion d)) deps
252
-
258
+
253
259
pure ([] , Just versionMapping)
254
260
255
261
define (cmapWithPrio LogShake recorder) $ \ ParseCabalFile file -> do
@@ -422,7 +428,7 @@ hover ide _ msgParam = do
422
428
423
429
getMatch :: (T. Text , T. Text , T. Text , [T. Text ]) -> Maybe T. Text
424
430
getMatch (_, _, _, [dependency]) = Just dependency
425
- getMatch (_, _, _, _) = Nothing -- impossible case
431
+ getMatch (_, _, _, _) = Nothing -- impossible case
426
432
documentationText :: T. Text -> T. Text
427
433
documentationText package = " [Documentation](https://hackage.haskell.org/package/" <> package <> " )"
428
434
@@ -431,42 +437,42 @@ hover ide _ msgParam = do
431
437
-- ----------------------------------------------------------------
432
438
433
439
lens :: PluginMethodHandler IdeState LSP. Method_TextDocumentCodeLens
434
- lens state _plId clp = do
440
+ lens state _plId clp = do
435
441
if not $ isInlayHintsSupported state
436
442
then do
437
443
let uri = clp ^. JL. textDocument . JL. uri
438
444
439
445
nfp <- getNormalizedFilePathE uri
440
446
cabalFields <- runActionE " cabal.cabal-lens" state $ useE ParseCabalFields nfp
441
-
447
+
442
448
let positionedDeps = concatMap parseDeps cabalFields
443
449
444
450
let rfp = rootDir state
445
451
let planJson = toNormalizedFilePath $ rfp </> planJsonPath
446
452
planDeps <- runActionE " cabal.cabal-lens" state $ useE BuildDependencyVersionMapping planJson
447
453
448
- let lenses = Maybe. mapMaybe
449
- (\ (Positioned pos name) -> getCodeLens . Positioned pos . Dependency name <$> Map. lookup name planDeps)
454
+ let lenses = Maybe. mapMaybe
455
+ (\ (Positioned pos name) -> getCodeLens . Positioned pos . Dependency name <$> Map. lookup name planDeps)
450
456
positionedDeps
451
-
457
+
452
458
pure $ InL lenses
453
459
else
454
460
pure $ InL []
455
461
where
456
462
getCodeLens :: Positioned SimpleDependency -> CodeLens
457
- getCodeLens (Positioned pos (Dependency _ v)) =
463
+ getCodeLens (Positioned pos (Dependency _ v)) =
458
464
let cPos = Types. cabalPositionToLSPPosition pos
459
- in CodeLens
465
+ in CodeLens
460
466
{ _range = Range cPos cPos
461
- , _command = Just $ mkActionlessCommand v
462
- , _data_ = Nothing
467
+ , _command = Just $ mkActionlessCommand v
468
+ , _data_ = Nothing
463
469
}
464
-
470
+
465
471
mkActionlessCommand :: T. Text -> Command
466
472
mkActionlessCommand t = Command
467
473
{ _title = t
468
474
, _command = " "
469
- , _arguments = Nothing
475
+ , _arguments = Nothing
470
476
}
471
477
472
478
-- ----------------------------------------------------------------
@@ -475,8 +481,8 @@ lens state _plId clp = do
475
481
476
482
-- | Handler for inlay hints
477
483
hint :: PluginMethodHandler IdeState LSP. Method_TextDocumentInlayHint
478
- hint state _plId clp =
479
- if isInlayHintsSupported state
484
+ hint state _plId clp =
485
+ if isInlayHintsSupported state
480
486
then do
481
487
let uri = clp ^. JL. textDocument . JL. uri
482
488
@@ -488,26 +494,26 @@ hint state _plId clp =
488
494
let planJson = toNormalizedFilePath $ rfp </> planJsonPath
489
495
planDeps <- runActionE " cabal.cabal-lens" state $ useE BuildDependencyVersionMapping planJson
490
496
491
- let lenses = Maybe. mapMaybe
492
- (\ (Positioned pos name) -> getInlayHint . Positioned pos . Dependency name <$> Map. lookup name planDeps)
497
+ let lenses = Maybe. mapMaybe
498
+ (\ (Positioned pos name) -> getInlayHint . Positioned pos . Dependency name <$> Map. lookup name planDeps)
493
499
positionedDeps
494
500
495
501
pure $ InL lenses
496
- else
502
+ else
497
503
pure $ InL []
498
- where
504
+ where
499
505
getInlayHint :: Positioned SimpleDependency -> InlayHint
500
- getInlayHint (Positioned pos (Dependency _ v)) = InlayHint
506
+ getInlayHint (Positioned pos (Dependency _ v)) = InlayHint
501
507
{ _position = Types. cabalPositionToLSPPosition pos
502
508
, _label = InL v
503
509
, _kind = Nothing
504
- , _textEdits = Nothing
505
- , _tooltip = Nothing
506
- , _paddingLeft = Nothing
507
- , _paddingRight = Nothing
510
+ , _textEdits = Nothing
511
+ , _tooltip = Nothing
512
+ , _paddingLeft = Nothing
513
+ , _paddingRight = Nothing
508
514
, _data_ = Nothing
509
515
}
510
-
516
+
511
517
isInlayHintsSupported :: IdeState -> Bool
512
518
isInlayHintsSupported ideState =
513
519
let clientCaps = Shake. clientCapabilities $ shakeExtras ideState
@@ -557,10 +563,10 @@ ofInterestRules recorder = do
557
563
res = (Just fp, Just foi)
558
564
return res
559
565
where
560
- summarize NotCabalFOI = BS. singleton 0
561
- summarize (IsCabalFOI OnDisk ) = BS. singleton 1
566
+ summarize NotCabalFOI = BS. singleton 0
567
+ summarize (IsCabalFOI OnDisk ) = BS. singleton 1
562
568
summarize (IsCabalFOI (Modified False )) = BS. singleton 2
563
- summarize (IsCabalFOI (Modified True )) = BS. singleton 3
569
+ summarize (IsCabalFOI (Modified True )) = BS. singleton 3
564
570
565
571
getCabalFilesOfInterestUntracked :: Action (HashMap NormalizedFilePath FileOfInterestStatus )
566
572
getCabalFilesOfInterestUntracked = do
@@ -634,7 +640,7 @@ computeCompletionsAt recorder ide prefInfo fp fields = do
634
640
stanzaName =
635
641
case fst ctx of
636
642
Types. Stanza _ name -> name
637
- _ -> Nothing
643
+ _ -> Nothing
638
644
}
639
645
completions <- completer completerRecorder completerData
640
646
pure completions
0 commit comments