@@ -67,7 +67,7 @@ data AddParams = AddParams
6767 { rootDirParam :: FilePath -- ^ The root directory.
6868 , fileParam :: ModulePath -- ^ A path to a module inside the
6969 -- library/executable/test-suite you want to
70- -- add the package to. May be a realtive oir
70+ -- add the package to. May be a relative or
7171 -- absolute path, thus, must be normalised.
7272 , packageParam :: Package -- ^ The name of the package to add.
7373 }
@@ -76,7 +76,7 @@ data AddParams = AddParams
7676-- | FilePath to a cabal package description file.
7777type CabalFilePath = FilePath
7878-- | FilePath to a package.yaml package description file.
79- type PackageYamlFilePath = FilePath
79+ type HpackFilePath = FilePath
8080-- | FilePath to a module within the project.
8181-- May be used to establish what component the dependency shall be added to.
8282type ModulePath = FilePath
@@ -88,8 +88,14 @@ type Package = T.Text
8888-- Supported are `*.cabal` and `package.yaml` specifications.
8989-- Moreover, may fail with an IOException in case of a filesystem problem.
9090addCmd :: CommandFunc AddParams J. WorkspaceEdit
91- addCmd = CmdSync $ \ ( AddParams rootDir modulePath pkg) -> do
91+ addCmd = CmdSync addCmd'
9292
93+ -- | Add a package to the project's dependencies.
94+ -- May fail if no project dependency specification can be found.
95+ -- Supported are `*.cabal` and `package.yaml` specifications.
96+ -- Moreover, may fail with an IOException in case of a filesystem problem.
97+ addCmd' :: AddParams -> IdeGhcM (IdeResult J. WorkspaceEdit )
98+ addCmd' (AddParams rootDir modulePath pkg) = do
9399 packageType <- liftIO $ findPackageType rootDir
94100 fileMap <- GM. mkRevRedirMapFunc
95101
@@ -105,9 +111,10 @@ addCmd = CmdSync $ \(AddParams rootDir modulePath pkg) -> do
105111 liftToGhc $ editHpackPackage absFp relModulePath pkg
106112 NoPackage -> return $ IdeResultFail (IdeError PluginError " No package.yaml or .cabal found" Null )
107113
108- data PackageType = CabalPackage FilePath -- ^ Location of Cabal File.
109- | HpackPackage FilePath -- ^ Location of `package.yaml`
114+ data PackageType = CabalPackage FilePath -- ^ Location of Cabal File. May be relative.
115+ | HpackPackage FilePath -- ^ Location of `package.yaml`. May be relative.
110116 | NoPackage -- ^ No package format has been found.
117+ deriving (Show , Eq )
111118
112119-- | Find the package type the project with the given root uses.
113120-- Might have weird results if there is more than one cabal package specification
@@ -129,12 +136,13 @@ findPackageType rootDir = do
129136 return $ fromMaybe NoPackage $ asum [HpackPackage <$> mHpack, CabalPackage <$> mCabal]
130137
131138-- | Edit a hpack package to add the given package to the package.yaml.
139+ -- If package.yaml is not in an expected format, will fail fatally.
132140--
133141-- Currently does not preserve format.
134142-- Keep an eye out on this other GSOC project!
135143-- https://github.com/wisn/format-preserving-yaml
136- editHpackPackage :: PackageYamlFilePath -- ^ Path to the package.yaml file
137- -- containing the package description.
144+ editHpackPackage :: HpackFilePath -- ^ Path to the package.yaml file
145+ -- containing the package description.
138146 -> ModulePath -- ^ Path to the module where the command has
139147 -- been issued in.
140148 -- Used to find out what component the
@@ -148,19 +156,29 @@ editHpackPackage fp modulePath pkgName = do
148156
149157 case Y. decodeThrow contents :: Maybe Object of
150158 Just obj -> do
159+ -- Map over all major components, such as "executable", "executables",
160+ -- "tests" and "benchmarks". Note, that "library" is a major component,
161+ -- but its structure is different and can not be mapped over in the same way.
162+ --
163+ -- Only adds the package if the declared "source-dirs" field is part of the
164+ -- module path, or if no "source-dirs" is declared.
151165 let compsMapped = mapComponentTypes (ensureObject $ mapComponents (ensureObject $ mapCompDependencies addDep)) obj
152166
153- let addDepToMainLib = fromMaybe True $ do
154- Object lib <- HM. lookup " library " compsMapped
155- sourceDirs <- HM. lookup " source-dirs " lib
156- return $ isInSourceDir sourceDirs
167+ -- Is there a global "dependencies" yaml object?
168+ let addDepToMainDep = fromMaybe False $ do
169+ Array _ <- HM. lookup " dependencies " compsMapped
170+ return True
157171
158- let newPkg = if addDepToMainLib
159- then mapMainDependencies addDep compsMapped
160- else compsMapped
172+ -- Either add the package to only the top-level "dependencies",
173+ -- or to all main components of which the given module is part of.
174+ let newPkg
175+ | addDepToMainDep = mapMainDependencies addDep obj
176+ -- Map over the library component at last, since it has different structure.
177+ | otherwise = mapLibraryDependency addDep compsMapped
161178
162- newPkgText = T. decodeUtf8 $ Y. encode newPkg
179+ let newPkgText = T. decodeUtf8 $ Y. encode newPkg
163180
181+ -- Construct the WorkSpaceEdit
164182 let numOldLines = length $ T. lines $ T. decodeUtf8 contents
165183 range = J. Range (J. Position 0 0 ) (J. Position numOldLines 0 )
166184 textEdit = J. TextEdit range newPkgText
@@ -179,10 +197,18 @@ editHpackPackage fp modulePath pkgName = do
179197
180198 mapMainDependencies :: (Value -> Value ) -> Object -> Object
181199 mapMainDependencies f o =
182- let g " dependencies" = f
200+ let g :: T. Text -> Value -> Value
201+ g " dependencies" = f
183202 g _ = id
184203 in HM. mapWithKey g o
185204
205+ mapLibraryDependency :: (Value -> Value ) -> Object -> Object
206+ mapLibraryDependency f o =
207+ let g :: T. Text -> Value -> Value
208+ g " library" (Y. Object o') = Y. Object (mapCompDependencies f o')
209+ g _ x = x
210+ in HM. mapWithKey g o
211+
186212 mapComponentTypes :: (Value -> Value ) -> Object -> Object
187213 mapComponentTypes f o =
188214 let g " executables" = f
0 commit comments