Skip to content

Commit 69d5fbf

Browse files
committed
Introduce Ide.Plugin.Cabal.Dependencies module
1 parent 5a07d07 commit 69d5fbf

File tree

3 files changed

+68
-42
lines changed

3 files changed

+68
-42
lines changed

haskell-language-server.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ library hls-cabal-plugin
242242
exposed-modules:
243243
Ide.Plugin.Cabal
244244
Ide.Plugin.Cabal.Diagnostics
245+
Ide.Plugin.Cabal.Dependencies
245246
Ide.Plugin.Cabal.Completion.CabalFields
246247
Ide.Plugin.Cabal.Completion.Completer.FilePath
247248
Ide.Plugin.Cabal.Completion.Completer.Module

plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{-# LANGUAGE LambdaCase #-}
44
{-# LANGUAGE OverloadedStrings #-}
55
{-# LANGUAGE TypeFamilies #-}
6-
{-# LANGUAGE ViewPatterns #-}
6+
{-# LANGUAGE ViewPatterns #-}
77

88
module Ide.Plugin.Cabal (descriptor, haskellInteractionDescriptor, Log (..)) where
99

@@ -56,6 +56,7 @@ import Ide.Plugin.Cabal.Completion.Types (ParseCabalCommon
5656
ParseCabalFile (..))
5757
import qualified Ide.Plugin.Cabal.Completion.Types as Types
5858
import Ide.Plugin.Cabal.Definition (gotoDefinition)
59+
import qualified Ide.Plugin.Cabal.Dependencies as Dependencies
5960
import qualified Ide.Plugin.Cabal.Diagnostics as Diagnostics
6061
import qualified Ide.Plugin.Cabal.FieldSuggest as FieldSuggest
6162
import qualified Ide.Plugin.Cabal.LicenseSuggest as LicenseSuggest
@@ -69,9 +70,6 @@ import qualified Language.LSP.Protocol.Message as LSP
6970
import Language.LSP.Protocol.Types
7071
import qualified Language.LSP.VFS as VFS
7172
import Text.Regex.TDFA
72-
import Development.IDE.GHC.Compat (getUnitInfoMap, unitPackageNameString, unitPackageVersion, filterUniqMap, nonDetEltsUniqMap)
73-
import Data.Version (Version(..))
74-
import qualified Data.Char as Char
7573

7674
data Log
7775
= LogModificationTime NormalizedFilePath FileVersion
@@ -385,44 +383,9 @@ hints :: PluginMethodHandler IdeState LSP.Method_TextDocumentInlayHint
385383
hints state _plId clp = do
386384
let uri = clp ^. JL.textDocument . JL.uri
387385
nfp <- getNormalizedFilePathE uri
388-
cabalFields <- runActionE "cabal.cabal-lens" state $ useE ParseCabalFields nfp
389-
(hscEnv -> hsc) <- runActionE "classplugin.codeAction.GhcSession" state $ useE GhcSession nfp
390-
let lookupVersion pkgName = Maybe.listToMaybe $ nonDetEltsUniqMap $ fmap unitPackageVersion $ filterUniqMap ((==) pkgName . unitPackageNameString) $ getUnitInfoMap hsc
391-
pure $ InL $ fmap hint $ collectPackageVersions (fmap printVersion . lookupVersion . T.unpack) =<< cabalFields
392-
where
393-
collectPackageVersions :: (T.Text -> Maybe T.Text) -> Syntax.Field Syntax.Position -> [(Syntax.Position, LicenseSuggest.Text)]
394-
collectPackageVersions lookupVersion (Syntax.Field (Syntax.Name _ "build-depends") pos) = concatMap (fieldLinePackageVersions lookupVersion) pos
395-
collectPackageVersions lookupVersion (Syntax.Section _ _ fields) = concatMap (collectPackageVersions lookupVersion) fields
396-
collectPackageVersions _ _ = []
397-
398-
fieldLinePackageVersions :: (T.Text -> Maybe T.Text) -> Syntax.FieldLine Syntax.Position -> [(Syntax.Position, LicenseSuggest.Text)]
399-
fieldLinePackageVersions lookupVersion (Syntax.FieldLine pos x) =
400-
let splitted = T.splitOn "," $ Encoding.decodeUtf8Lenient x
401-
calcStartPosition (prev, start) = T.length prev + 1 + start
402-
potentialPkgs = List.foldl' (\a b -> a <> [(b, Maybe.maybe 0 calcStartPosition $ Maybe.listToMaybe $ reverse a)]) [] splitted
403-
versions = do
404-
(pkg', pkgStartOffset) <- potentialPkgs
405-
let pkgName = T.takeWhile (not . Char.isSpace) . T.strip $ pkg'
406-
endOfPackage = T.length pkgName + (T.length $ T.takeWhile Char.isSpace pkg')
407-
version <- Maybe.maybeToList $ lookupVersion $ T.takeWhile (not . Char.isSpace) . T.strip $ pkg'
408-
pure (Syntax.Position (Syntax.positionRow pos) (Syntax.positionCol pos + pkgStartOffset + endOfPackage), version)
409-
in versions
410-
411-
printVersion v = T.intercalate "." (fmap (T.pack . show) $ versionBranch v)
412-
413-
hint :: (Syntax.Position, LicenseSuggest.Text) -> InlayHint
414-
hint (pos, foo) =
415-
let cPos = Types.cabalPositionToLSPPosition pos
416-
mkInlayHintLabelPart = InlayHintLabelPart (" (" <> foo <> ")") Nothing Nothing Nothing
417-
in InlayHint { _position = cPos
418-
, _label = InR $ pure mkInlayHintLabelPart
419-
, _kind = Nothing -- neither a type nor a parameter
420-
, _textEdits = Nothing -- same as CodeAction
421-
, _tooltip = Nothing
422-
, _paddingLeft = Nothing
423-
, _paddingRight = Nothing
424-
, _data_ = Nothing
425-
}
386+
cabalFields <- runActionE "cabal.cabal-hints" state $ useE ParseCabalFields nfp
387+
(hscEnv -> hsc) <- runActionE "cabal.cabal-hints" state $ useE GhcSession nfp
388+
pure $ InL $ Dependencies.dependencyVersionHints cabalFields hsc
426389

427390
-- | Handler for hover messages.
428391
--
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Ide.Plugin.Cabal.Dependencies (dependencyVersionHints, collectPackageDependencyVersions) where
3+
4+
import qualified Data.Char as Char
5+
import qualified Data.List as List
6+
import qualified Data.Maybe as Maybe
7+
import qualified Data.Text as T
8+
import qualified Data.Text.Encoding as Encoding
9+
import Data.Version (Version (..))
10+
import Development.IDE.GHC.Compat (HscEnv, filterUniqMap,
11+
getUnitInfoMap,
12+
nonDetEltsUniqMap,
13+
unitPackageNameString,
14+
unitPackageVersion)
15+
import qualified Distribution.Fields as Syntax
16+
import qualified Distribution.Parsec.Position as Syntax
17+
import qualified Ide.Plugin.Cabal.Completion.Types as Types
18+
import Language.LSP.Protocol.Types (InlayHint (..),
19+
InlayHintLabelPart (InlayHintLabelPart),
20+
type (|?) (..))
21+
22+
dependencyVersionHints :: [Syntax.Field Syntax.Position] -> HscEnv -> [InlayHint]
23+
dependencyVersionHints cabalFields = fmap mkHint . collectPackageDependencyVersions cabalFields
24+
where
25+
mkHint :: (Syntax.Position, Version) -> InlayHint
26+
mkHint (pos, dependencyVersion) =
27+
let mkInlayHintLabelPart = InlayHintLabelPart (" (" <> printVersion dependencyVersion <> ")") Nothing Nothing Nothing
28+
in InlayHint { _position = Types.cabalPositionToLSPPosition pos
29+
, _label = InR $ pure mkInlayHintLabelPart
30+
, _kind = Nothing
31+
, _textEdits = Nothing
32+
, _tooltip = Nothing
33+
, _paddingLeft = Nothing
34+
, _paddingRight = Nothing
35+
, _data_ = Nothing
36+
}
37+
38+
collectPackageDependencyVersions :: [Syntax.Field Syntax.Position] -> HscEnv -> [(Syntax.Position, Version)]
39+
collectPackageDependencyVersions cabalFields hscEnv = cabalFields >>= collectPackageVersions
40+
where
41+
lookupPackageVersion pkgName = Maybe.listToMaybe $ nonDetEltsUniqMap $ fmap unitPackageVersion $ filterUniqMap ((==) (T.unpack pkgName) . unitPackageNameString) $ getUnitInfoMap hscEnv
42+
43+
collectPackageVersions :: Syntax.Field Syntax.Position -> [(Syntax.Position, Version)]
44+
collectPackageVersions (Syntax.Field (Syntax.Name _ "build-depends") pos) = concatMap fieldLinePackageVersions pos
45+
collectPackageVersions (Syntax.Section _ _ fields) = concatMap collectPackageVersions fields
46+
collectPackageVersions _ = []
47+
48+
fieldLinePackageVersions :: Syntax.FieldLine Syntax.Position -> [(Syntax.Position, Version)]
49+
fieldLinePackageVersions (Syntax.FieldLine pos x) =
50+
let splitted = T.splitOn "," $ Encoding.decodeUtf8Lenient x
51+
calcStartPosition (prev, start) = T.length prev + 1 + start
52+
potentialPkgs = List.foldl' (\a b -> a <> [(b, Maybe.maybe 0 calcStartPosition $ Maybe.listToMaybe $ reverse a)]) [] splitted
53+
versions = do
54+
(pkg', pkgStartOffset) <- potentialPkgs
55+
let pkgName = T.takeWhile (not . Char.isSpace) . T.strip $ pkg'
56+
endOfPackage = T.length pkgName + (T.length $ T.takeWhile Char.isSpace pkg')
57+
version <- Maybe.maybeToList $ lookupPackageVersion $ T.takeWhile (not . Char.isSpace) . T.strip $ pkg'
58+
pure (Syntax.Position (Syntax.positionRow pos) (Syntax.positionCol pos + pkgStartOffset + endOfPackage), version)
59+
in versions
60+
61+
printVersion :: Version -> T.Text
62+
printVersion v = T.intercalate "." (fmap (T.pack . show) $ versionBranch v)

0 commit comments

Comments
 (0)