Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 801f064

Browse files
authored
Merge pull request #1224 from fendor/document-package
Add Documentation for Package Plugin
2 parents 50cb42f + a9ea9a5 commit 801f064

File tree

1 file changed

+72
-21
lines changed

1 file changed

+72
-21
lines changed

src/Haskell/Ide/Engine/Plugin/Package.hs

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,29 @@ packageDescriptor plId = PluginDescriptor
6464
}
6565

6666
data AddParams = AddParams
67-
{ rootDirParam :: FilePath -- ^ The root directory.
68-
, fileParam :: FilePath -- ^ A path to a module inside the
69-
-- library/executable/test-suite you want to
70-
-- add the package to.
71-
, packageParam :: T.Text -- ^ The name of the package to add.
67+
{ rootDirParam :: FilePath -- ^ The root directory.
68+
, fileParam :: ModulePath -- ^ A path to a module inside the
69+
-- library/executable/test-suite you want to
70+
-- add the package to. May be a realtive oir
71+
-- absolute path, thus, must be normalised.
72+
, packageParam :: Package -- ^ The name of the package to add.
7273
}
7374
deriving (Eq, Show, Read, Generic, ToJSON, FromJSON)
7475

76+
-- | FilePath to a cabal package description file.
77+
type CabalFilePath = FilePath
78+
-- | FilePath to a package.yaml package description file.
79+
type PackageYamlFilePath = FilePath
80+
-- | FilePath to a module within the project.
81+
-- May be used to establish what component the dependency shall be added to.
82+
type ModulePath = FilePath
83+
-- | Name of the Package to add.
84+
type Package = T.Text
85+
86+
-- | Add a package to the project's dependencies.
87+
-- May fail if no project dependency specification can be found.
88+
-- Supported are `*.cabal` and `package.yaml` specifications.
89+
-- Moreover, may fail with an IOException in case of a filesystem problem.
7590
addCmd :: CommandFunc AddParams J.WorkspaceEdit
7691
addCmd = CmdSync $ \(AddParams rootDir modulePath pkg) -> do
7792

@@ -83,30 +98,49 @@ addCmd = CmdSync $ \(AddParams rootDir modulePath pkg) -> do
8398
absFp <- liftIO $ canonicalizePath relFp
8499
let relModulePath = makeRelative (takeDirectory absFp) modulePath
85100

86-
liftToGhc $ editCabalPackage absFp relModulePath (T.unpack pkg) fileMap
101+
liftToGhc $ editCabalPackage absFp relModulePath pkg fileMap
87102
HpackPackage relFp -> do
88103
absFp <- liftIO $ canonicalizePath relFp
89104
let relModulePath = makeRelative (takeDirectory absFp) modulePath
90105
liftToGhc $ editHpackPackage absFp relModulePath pkg
91106
NoPackage -> return $ IdeResultFail (IdeError PluginError "No package.yaml or .cabal found" Null)
92107

93-
data PackageType = CabalPackage FilePath
94-
| HpackPackage FilePath
95-
| NoPackage
96-
108+
data PackageType = CabalPackage FilePath -- ^ Location of Cabal File.
109+
| HpackPackage FilePath -- ^ Location of `package.yaml`
110+
| NoPackage -- ^ No package format has been found.
111+
112+
-- | Find the package type the project with the given root uses.
113+
-- Might have weird results if there is more than one cabal package specification
114+
-- in the root directory.
115+
-- The `package.yaml` is preferred in case both files are present.
116+
-- May fail with various IOException's, for example if the given
117+
-- directory does not exist, a Hardware Failure happens or
118+
-- the permissions deny it.
119+
-- However, normally this command should succeeed without any exceptions.
97120
findPackageType :: FilePath -> IO PackageType
98121
findPackageType rootDir = do
99122
files <- getDirectoryContents rootDir
123+
-- Search for all files that have '.cabal' as a file ending,
124+
-- since that is the format of the cabal file. May be more to one or zero.
100125
let mCabal = listToMaybe $ filter (isExtensionOf "cabal") files
101126

102127
mHpack <- findFile [rootDir] "package.yaml"
103128

104129
return $ fromMaybe NoPackage $ asum [HpackPackage <$> mHpack, CabalPackage <$> mCabal]
105130

131+
-- | Edit a hpack package to add the given package to the package.yaml.
132+
--
106133
-- Currently does not preserve format.
107134
-- Keep an eye out on this other GSOC project!
108135
-- https://github.com/wisn/format-preserving-yaml
109-
editHpackPackage :: FilePath -> FilePath -> T.Text -> IdeM (IdeResult WorkspaceEdit)
136+
editHpackPackage :: PackageYamlFilePath -- ^ Path to the package.yaml file
137+
-- containing the package description.
138+
-> ModulePath -- ^ Path to the module where the command has
139+
-- been issued in.
140+
-- Used to find out what component the
141+
-- dependency shall be added to.
142+
-> Package -- ^ Name of the package to add as a dependency.
143+
-> IdeM (IdeResult WorkspaceEdit)
110144
editHpackPackage fp modulePath pkgName = do
111145
contents <- liftIO $ B.readFile fp
112146

@@ -186,9 +220,16 @@ editHpackPackage fp modulePath pkgName = do
186220
addDep (Array deps) = Array $ fromList (String pkgName:GHC.Exts.toList deps)
187221
addDep _ = error "Not an array in addDep"
188222

189-
190-
-- | Takes a cabal file and a path to a module in the dependency you want to edit.
191-
editCabalPackage :: FilePath -> FilePath -> String -> (FilePath -> FilePath) -> IdeM (IdeResult J.WorkspaceEdit)
223+
-- | Takes a cabal file and a path to a module in the project and a package name to add
224+
-- to the cabal file. Reverse file map is needed to find the correct file in the project.
225+
-- May fail with an IOException if the Cabal file is invalid.
226+
editCabalPackage :: CabalFilePath -- ^ Path to the cabal file to add the dependency to.
227+
-> ModulePath -- ^ Path to the module that wants to add the package.
228+
-- Used to find out what component the
229+
-- dependency shall be added to.
230+
-> Package -- ^ Name of the package added as a dependency.
231+
-> (FilePath -> FilePath) -- ^ Reverse File for computing file diffs.
232+
-> IdeM (IdeResult J.WorkspaceEdit)
192233
editCabalPackage file modulePath pkgName fileMap = do
193234

194235
package <- liftIO $ readGenericPackageDescription normal file
@@ -204,7 +245,6 @@ editCabalPackage file modulePath pkgName fileMap = do
204245

205246
IdeResultOk <$> makeAdditiveDiffResult file newContents fileMap
206247

207-
208248
where
209249

210250
applyLens :: L.HasBuildInfo a => Lens' GenericPackageDescription [(b, CondTree v c a)]
@@ -218,7 +258,7 @@ editCabalPackage file modulePath pkgName fileMap = do
218258
updateTree = mapIfHasModule modulePath (addDep pkgName)
219259

220260

221-
mapIfHasModule :: L.HasBuildInfo a => FilePath -> (a -> a) -> CondTree v c a -> CondTree v c a
261+
mapIfHasModule :: L.HasBuildInfo a => ModulePath -> (a -> a) -> CondTree v c a -> CondTree v c a
222262
mapIfHasModule modFp f = mapTreeData g
223263
where g x
224264
| null (sourceDirs x) = f x
@@ -227,18 +267,26 @@ editCabalPackage file modulePath pkgName fileMap = do
227267
hasThisModule = any (`isPrefixOf` modFp) . sourceDirs
228268
sourceDirs x = x ^. L.buildInfo . L.hsSourceDirs
229269

230-
addDep :: L.HasBuildInfo a => String -> a -> a
270+
-- | Add the given package name to the cabal file.
271+
-- Package is appended to the dependency list.
272+
addDep :: L.HasBuildInfo a => Package -> a -> a
231273
addDep dep x = L.buildInfo . L.targetBuildDepends .~ newDeps $ x
232274
where oldDeps = x ^. L.buildInfo . L.targetBuildDepends
233275
-- Add it to the bottom of the dependencies list
234-
newDeps = oldDeps ++ [Dependency (mkPackageName dep) anyVersion]
276+
-- TODO: we could sort the depencies and then insert it,
277+
-- or insert it in order iff the list is already sorted.
278+
newDeps = oldDeps ++ [Dependency (mkPackageName (T.unpack dep)) anyVersion]
235279

280+
-- | Provide a code action to add a package to the local package.yaml or cabal file.
281+
-- Reads from diagnostics the unknown import module path and searches for it on Hoogle.
282+
-- If found, offer a code action to add the package to the local package description.
236283
codeActionProvider :: CodeActionProvider
237284
codeActionProvider plId docId _ context = do
238285
mRootDir <- getRootPath
239286
let J.List diags = context ^. J.diagnostics
240287
pkgs = mapMaybe getAddablePackages diags
241288

289+
-- Search for packages that define the given module.
242290
res <- mapM (bimapM return Hoogle.searchPackages) pkgs
243291
actions <- catMaybes <$> mapM (uncurry (mkAddPackageAction mRootDir)) (concatPkgs res)
244292

@@ -247,7 +295,8 @@ codeActionProvider plId docId _ context = do
247295
where
248296
concatPkgs = concatMap (\(d, ts) -> map (d,) ts)
249297

250-
mkAddPackageAction :: Maybe FilePath -> J.Diagnostic -> T.Text -> IdeM (Maybe J.CodeAction)
298+
-- | Create the Add Package Action with the given diagnostics and the found package name.
299+
mkAddPackageAction :: Maybe FilePath -> J.Diagnostic -> Package -> IdeM (Maybe J.CodeAction)
251300
mkAddPackageAction mRootDir diag pkgName = case (mRootDir, J.uriToFilePath (docId ^. J.uri)) of
252301
(Just rootDir, Just docFp) -> do
253302
let title = "Add " <> pkgName <> " as a dependency"
@@ -256,18 +305,20 @@ codeActionProvider plId docId _ context = do
256305
return $ Just (J.CodeAction title (Just J.CodeActionQuickFix) (Just (J.List [diag])) Nothing (Just cmd))
257306
_ -> return Nothing
258307

259-
getAddablePackages :: J.Diagnostic -> Maybe (J.Diagnostic, T.Text)
308+
getAddablePackages :: J.Diagnostic -> Maybe (J.Diagnostic, Package)
260309
getAddablePackages diag@(J.Diagnostic _ _ _ (Just "ghcmod") msg _) = (diag,) <$> extractModuleName msg
261310
getAddablePackages _ = Nothing
262311

263-
extractModuleName :: T.Text -> Maybe T.Text
312+
-- | Extract a module name from an error message.
313+
extractModuleName :: T.Text -> Maybe Package
264314
extractModuleName msg
265315
| T.isPrefixOf "Could not find module " msg = Just $ T.tail $ T.init nameAndQuotes
266316
| T.isPrefixOf "Could not load module " msg = Just $ T.tail $ T.init nameAndQuotes
267317
| otherwise = Nothing
268318
where line = head $ T.lines msg
269319
nameAndQuotes = T.dropWhileEnd (/= '') $ T.dropWhile (/= '') line
270320

321+
-- Example error messages
271322
{- GHC 8.6.2 error message is
272323
273324
"Could not load module \8216Data.Text\8217\n" ++

0 commit comments

Comments
 (0)