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 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 ((</>) )
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
83
77
84
78
data Log
85
79
= LogModificationTime NormalizedFilePath FileVersion
@@ -141,13 +135,13 @@ descriptor recorder plId =
141
135
pluginHandlers =
142
136
mconcat
143
137
[ mkPluginHandler LSP. SMethod_TextDocumentCodeAction licenseSuggestCodeAction
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
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
151
145
],
152
146
pluginNotificationHandlers =
153
147
mconcat
@@ -241,21 +235,21 @@ cabalRules recorder plId = do
241
235
)
242
236
fields
243
237
pure ([] , Just commonSections)
244
-
238
+
245
239
define (cmapWithPrio LogShake recorder) $ \ ParsePlanJson file -> do
246
240
(_, planSrc) <- use_ GetFileContents file
247
-
241
+
248
242
contents <- case planSrc of
249
243
Just sources -> pure $ Encoding. encodeUtf8 $ Rope. toText sources
250
- Nothing -> do liftIO $ BS. readFile $ fromNormalizedFilePath file
251
-
244
+ Nothing -> do liftIO $ BS. readFile $ fromNormalizedFilePath file
245
+
252
246
pure ([] , installPlan <$> A. decodeStrict contents)
253
-
247
+
254
248
define (cmapWithPrio LogShake recorder) $ \ BuildDependencyVersionMapping file -> do
255
- deps <- use_ ParsePlanJson file
256
-
249
+ deps <- use_ ParsePlanJson file
250
+
257
251
let versionMapping = Map. fromList $ map (\ d -> (_pkgName d, _pkgVersion d)) deps
258
-
252
+
259
253
pure ([] , Just versionMapping)
260
254
261
255
define (cmapWithPrio LogShake recorder) $ \ ParseCabalFile file -> do
@@ -428,7 +422,7 @@ hover ide _ msgParam = do
428
422
429
423
getMatch :: (T. Text , T. Text , T. Text , [T. Text ]) -> Maybe T. Text
430
424
getMatch (_, _, _, [dependency]) = Just dependency
431
- getMatch (_, _, _, _) = Nothing -- impossible case
425
+ getMatch (_, _, _, _) = Nothing -- impossible case
432
426
documentationText :: T. Text -> T. Text
433
427
documentationText package = " [Documentation](https://hackage.haskell.org/package/" <> package <> " )"
434
428
@@ -437,42 +431,42 @@ hover ide _ msgParam = do
437
431
-- ----------------------------------------------------------------
438
432
439
433
lens :: PluginMethodHandler IdeState LSP. Method_TextDocumentCodeLens
440
- lens state _plId clp = do
434
+ lens state _plId clp = do
441
435
if not $ isInlayHintsSupported state
442
436
then do
443
437
let uri = clp ^. JL. textDocument . JL. uri
444
438
445
439
nfp <- getNormalizedFilePathE uri
446
440
cabalFields <- runActionE " cabal.cabal-lens" state $ useE ParseCabalFields nfp
447
-
441
+
448
442
let positionedDeps = concatMap parseDeps cabalFields
449
443
450
444
let rfp = rootDir state
451
445
let planJson = toNormalizedFilePath $ rfp </> planJsonPath
452
446
planDeps <- runActionE " cabal.cabal-lens" state $ useE BuildDependencyVersionMapping planJson
453
447
454
- let lenses = Maybe. mapMaybe
455
- (\ (Positioned pos name) -> getCodeLens . Positioned pos . Dependency name <$> Map. lookup name planDeps)
448
+ let lenses = Maybe. mapMaybe
449
+ (\ (Positioned pos name) -> getCodeLens . Positioned pos . Dependency name <$> Map. lookup name planDeps)
456
450
positionedDeps
457
-
451
+
458
452
pure $ InL lenses
459
453
else
460
454
pure $ InL []
461
455
where
462
456
getCodeLens :: Positioned SimpleDependency -> CodeLens
463
- getCodeLens (Positioned pos (Dependency _ v)) =
457
+ getCodeLens (Positioned pos (Dependency _ v)) =
464
458
let cPos = Types. cabalPositionToLSPPosition pos
465
- in CodeLens
459
+ in CodeLens
466
460
{ _range = Range cPos cPos
467
- , _command = Just $ mkActionlessCommand v
468
- , _data_ = Nothing
461
+ , _command = Just $ mkActionlessCommand v
462
+ , _data_ = Nothing
469
463
}
470
-
464
+
471
465
mkActionlessCommand :: T. Text -> Command
472
466
mkActionlessCommand t = Command
473
467
{ _title = t
474
468
, _command = " "
475
- , _arguments = Nothing
469
+ , _arguments = Nothing
476
470
}
477
471
478
472
-- ----------------------------------------------------------------
@@ -481,8 +475,8 @@ lens state _plId clp = do
481
475
482
476
-- | Handler for inlay hints
483
477
hint :: PluginMethodHandler IdeState LSP. Method_TextDocumentInlayHint
484
- hint state _plId clp =
485
- if isInlayHintsSupported state
478
+ hint state _plId clp =
479
+ if isInlayHintsSupported state
486
480
then do
487
481
let uri = clp ^. JL. textDocument . JL. uri
488
482
@@ -494,26 +488,26 @@ hint state _plId clp =
494
488
let planJson = toNormalizedFilePath $ rfp </> planJsonPath
495
489
planDeps <- runActionE " cabal.cabal-lens" state $ useE BuildDependencyVersionMapping planJson
496
490
497
- let lenses = Maybe. mapMaybe
498
- (\ (Positioned pos name) -> getInlayHint . Positioned pos . Dependency name <$> Map. lookup name planDeps)
491
+ let lenses = Maybe. mapMaybe
492
+ (\ (Positioned pos name) -> getInlayHint . Positioned pos . Dependency name <$> Map. lookup name planDeps)
499
493
positionedDeps
500
494
501
495
pure $ InL lenses
502
- else
496
+ else
503
497
pure $ InL []
504
- where
498
+ where
505
499
getInlayHint :: Positioned SimpleDependency -> InlayHint
506
- getInlayHint (Positioned pos (Dependency _ v)) = InlayHint
500
+ getInlayHint (Positioned pos (Dependency _ v)) = InlayHint
507
501
{ _position = Types. cabalPositionToLSPPosition pos
508
502
, _label = InL v
509
503
, _kind = Nothing
510
- , _textEdits = Nothing
511
- , _tooltip = Nothing
512
- , _paddingLeft = Nothing
513
- , _paddingRight = Nothing
504
+ , _textEdits = Nothing
505
+ , _tooltip = Nothing
506
+ , _paddingLeft = Nothing
507
+ , _paddingRight = Nothing
514
508
, _data_ = Nothing
515
509
}
516
-
510
+
517
511
isInlayHintsSupported :: IdeState -> Bool
518
512
isInlayHintsSupported ideState =
519
513
let clientCaps = Shake. clientCapabilities $ shakeExtras ideState
@@ -563,10 +557,10 @@ ofInterestRules recorder = do
563
557
res = (Just fp, Just foi)
564
558
return res
565
559
where
566
- summarize NotCabalFOI = BS. singleton 0
567
- summarize (IsCabalFOI OnDisk ) = BS. singleton 1
560
+ summarize NotCabalFOI = BS. singleton 0
561
+ summarize (IsCabalFOI OnDisk ) = BS. singleton 1
568
562
summarize (IsCabalFOI (Modified False )) = BS. singleton 2
569
- summarize (IsCabalFOI (Modified True )) = BS. singleton 3
563
+ summarize (IsCabalFOI (Modified True )) = BS. singleton 3
570
564
571
565
getCabalFilesOfInterestUntracked :: Action (HashMap NormalizedFilePath FileOfInterestStatus )
572
566
getCabalFilesOfInterestUntracked = do
@@ -640,7 +634,7 @@ computeCompletionsAt recorder ide prefInfo fp fields = do
640
634
stanzaName =
641
635
case fst ctx of
642
636
Types. Stanza _ name -> name
643
- _ -> Nothing
637
+ _ -> Nothing
644
638
}
645
639
completions <- completer completerRecorder completerData
646
640
pure completions
0 commit comments