|
3 | 3 |
|
4 | 4 | module Ide.Plugin.Cabal.Dependencies (dependencyVersionHints, dependencyVersionLens, dependencyHover) where
|
5 | 5 |
|
6 |
| -import Control.Lens ((^.)) |
| 6 | +import Control.Lens (to, (^.)) |
7 | 7 | import Data.Array ((!))
|
8 | 8 | import Data.ByteString (ByteString)
|
9 | 9 | import Data.List
|
@@ -32,71 +32,82 @@ import Text.Regex.TDFA (Regex, makeRegex,
|
32 | 32 | matchAllText)
|
33 | 33 |
|
34 | 34 | dependencyVersionLens :: [Syntax.Field Syntax.Position] -> HscEnv -> [CodeLens]
|
35 |
| -dependencyVersionLens cabalFields = (>>= foo) . groupBy (\(a,_,_) (b,_,_)-> (a ^. JL.start . JL.line) == (b ^. JL.start . JL.line)) . collectPackageDependencyVersions cabalFields |
| 35 | +dependencyVersionLens cabalFields = Maybe.catMaybes . (>>= foo) . groupBy (\a b-> (a ^. to range . JL.start . JL.line) == (b ^. to range . JL.start . JL.line)) . collectPackageDependencyVersions cabalFields |
36 | 36 | where
|
37 |
| - foo :: [(Range, T.Text, Version)] -> [CodeLens] |
| 37 | + foo :: [DependencyInfo] -> [Maybe CodeLens] |
38 | 38 | foo [] = []
|
39 | 39 | foo [single] = [mkCodeLens False single]
|
40 | 40 | foo multi = mkCodeLens True <$> multi
|
41 | 41 |
|
42 |
| - mkCodeLens :: Bool -> (Range, T.Text, Version) -> CodeLens |
43 |
| - mkCodeLens includePkgName (range, pkgName, dependencyVersion) = |
| 42 | + mkCodeLens :: Bool -> DependencyInfo -> Maybe CodeLens |
| 43 | + mkCodeLens includePkgName DependencyInfo{range, packageName, installedVersion = Just version} = |
44 | 44 | let dependencyText =
|
45 | 45 | if includePkgName
|
46 |
| - then pkgName <> " (" <> printVersion dependencyVersion <> ")" |
47 |
| - else printVersion dependencyVersion |
| 46 | + then packageName <> " (" <> printVersion version <> ")" |
| 47 | + else printVersion version |
48 | 48 | command = Command dependencyText mempty Nothing
|
49 |
| - in CodeLens |
| 49 | + in Just $ CodeLens |
50 | 50 | { _range = range
|
51 | 51 | , _command = Just command
|
52 | 52 | , _data_ = Nothing }
|
| 53 | + mkCodeLens _ _ = Nothing |
53 | 54 |
|
54 | 55 | dependencyVersionHints :: [Syntax.Field Syntax.Position] -> HscEnv -> [InlayHint]
|
55 |
| -dependencyVersionHints cabalFields = fmap mkHint . collectPackageDependencyVersions cabalFields |
| 56 | +dependencyVersionHints cabalFields = Maybe.mapMaybe mkHint . collectPackageDependencyVersions cabalFields |
56 | 57 | where
|
57 |
| - mkHint :: (Range, T.Text, Version) -> InlayHint |
58 |
| - mkHint (Range _ pos, _, dependencyVersion) = |
59 |
| - InlayHint { _position = pos |
60 |
| - , _label = InL $ " (" <> printVersion dependencyVersion <> ")" |
61 |
| - , _kind = Nothing |
62 |
| - , _textEdits = Nothing |
63 |
| - , _tooltip = Nothing |
64 |
| - , _paddingLeft = Nothing |
65 |
| - , _paddingRight = Nothing |
66 |
| - , _data_ = Nothing |
67 |
| - } |
| 58 | + mkHint :: DependencyInfo -> Maybe InlayHint |
| 59 | + mkHint (DependencyInfo range _ (Just installedVersion)) = |
| 60 | + Just $ |
| 61 | + InlayHint { _position = range ^. JL.end |
| 62 | + , _label = InL $ " (" <> printVersion installedVersion <> ")" |
| 63 | + , _kind = Nothing |
| 64 | + , _textEdits = Nothing |
| 65 | + , _tooltip = Nothing |
| 66 | + , _paddingLeft = Nothing |
| 67 | + , _paddingRight = Nothing |
| 68 | + , _data_ = Nothing |
| 69 | + } |
| 70 | + mkHint _ = Nothing |
68 | 71 |
|
69 | 72 | dependencyHover :: [Syntax.Field Syntax.Position] -> HscEnv -> Position -> Hover |? Null
|
70 | 73 | dependencyHover cabalFields hsc cursorPosition =
|
71 |
| - let hoveredDep = List.find (positionInRange cursorPosition . (\(x, _, _) -> x)) $ collectPackageDependencyVersions cabalFields hsc |
| 74 | + let hoveredDep = List.find (positionInRange cursorPosition . range) $ collectPackageDependencyVersions cabalFields hsc |
72 | 75 | in case hoveredDep of
|
73 |
| - Just (_, pkgName, version) -> foundHover (Nothing, [pkgName <> " (" <> printVersion version <> ")\n", documentationText (pkgName <> "-" <> printVersion version)]) |
| 76 | + Just (DependencyInfo {packageName, installedVersion}) -> |
| 77 | + let showVersion f = maybe T.empty (f . printVersion) installedVersion |
| 78 | + in foundHover (Nothing, [packageName <> showVersion (\v -> " (" <> v <> ")") <> "\n", documentationText (packageName <> showVersion ("-" <>))]) |
74 | 79 | Nothing -> InR Null
|
75 | 80 | where
|
76 | 81 | documentationText :: T.Text -> T.Text
|
77 | 82 | documentationText package = "[Documentation](https://hackage.haskell.org/package/" <> package <> ")"
|
78 | 83 |
|
79 |
| -collectPackageDependencyVersions :: [Syntax.Field Syntax.Position] -> HscEnv -> [(Range, T.Text, Version)] |
| 84 | +collectPackageDependencyVersions :: [Syntax.Field Syntax.Position] -> HscEnv -> [DependencyInfo] |
80 | 85 | collectPackageDependencyVersions cabalFields hscEnv = cabalFields >>= collectPackageVersions
|
81 | 86 | where
|
82 | 87 | lookupPackageVersion pkgName = Maybe.listToMaybe $ nonDetEltsUniqMap $ fmap unitPackageVersion $ filterUniqMap ((==) (T.unpack pkgName) . unitPackageNameString) $ getUnitInfoMap hscEnv
|
83 | 88 |
|
84 |
| - collectPackageVersions :: Syntax.Field Syntax.Position -> [(Range, T.Text, Version)] |
| 89 | + collectPackageVersions :: Syntax.Field Syntax.Position -> [DependencyInfo] |
85 | 90 | collectPackageVersions (Syntax.Field (Syntax.Name _ "build-depends") pos) = concatMap fieldLinePackageVersions pos
|
86 | 91 | collectPackageVersions (Syntax.Section _ _ fields) = concatMap collectPackageVersions fields
|
87 | 92 | collectPackageVersions _ = []
|
88 | 93 |
|
89 |
| - fieldLinePackageVersions :: Syntax.FieldLine Syntax.Position -> [(Range, T.Text, Version)] |
| 94 | + fieldLinePackageVersions :: Syntax.FieldLine Syntax.Position -> [DependencyInfo] |
90 | 95 | fieldLinePackageVersions (Syntax.FieldLine pos line) =
|
91 | 96 | let linePackageNameRegex :: Regex = makeRegex ("(^|,)[[:space:]]*([a-zA-Z-]+)" :: ByteString)
|
92 | 97 | packageNames = (\x -> x ! 2) <$> matchAllText linePackageNameRegex (Encoding.decodeUtf8Lenient line)
|
93 | 98 | versions = do
|
94 | 99 | (pkgName, (pkgIndex, pkgOffset)) <- packageNames
|
95 |
| - version <- Maybe.maybeToList $ lookupPackageVersion pkgName |
96 | 100 | let pkgPosStart = Types.cabalPositionToLSPPosition $ Syntax.Position (Syntax.positionRow pos) (Syntax.positionCol pos + pkgIndex)
|
97 | 101 | pkgPosEnd = Types.cabalPositionToLSPPosition $ Syntax.Position (Syntax.positionRow pos) (Syntax.positionCol pos + pkgIndex + pkgOffset)
|
98 |
| - pure (Range pkgPosStart pkgPosEnd, pkgName, version) |
| 102 | + version = lookupPackageVersion pkgName |
| 103 | + pure $ DependencyInfo (Range pkgPosStart pkgPosEnd) pkgName version |
99 | 104 | in versions
|
100 | 105 |
|
| 106 | +data DependencyInfo = DependencyInfo |
| 107 | + { range :: Range |
| 108 | + , packageName :: T.Text |
| 109 | + , installedVersion :: Maybe Version |
| 110 | + } |
| 111 | + |
101 | 112 | printVersion :: Version -> T.Text
|
102 | 113 | printVersion v = T.intercalate "." (fmap (T.pack . show) $ versionBranch v)
|
0 commit comments