|
2 | 2 | {-# LANGUAGE DuplicateRecordFields #-}
|
3 | 3 | {-# LANGUAGE LambdaCase #-}
|
4 | 4 | {-# LANGUAGE OverloadedStrings #-}
|
| 5 | +{-# LANGUAGE RecordWildCards #-} |
5 | 6 | {-# LANGUAGE TypeFamilies #-}
|
6 | 7 |
|
7 | 8 | module Ide.Plugin.Cabal (descriptor, Log (..)) where
|
8 | 9 |
|
9 | 10 | import Control.Concurrent.Strict
|
10 | 11 | import Control.DeepSeq
|
11 |
| -import Control.Lens ((^.)) |
| 12 | +import Control.Lens ((^.)) |
12 | 13 | import Control.Monad.Extra
|
13 | 14 | import Control.Monad.IO.Class
|
14 | 15 | import Control.Monad.Trans.Class
|
15 |
| -import Control.Monad.Trans.Maybe (runMaybeT) |
16 |
| -import qualified Data.ByteString as BS |
| 16 | +import Control.Monad.Trans.Maybe (runMaybeT) |
| 17 | +import qualified Data.ByteString as BS |
17 | 18 | import Data.Hashable
|
18 |
| -import Data.HashMap.Strict (HashMap) |
19 |
| -import qualified Data.HashMap.Strict as HashMap |
20 |
| -import qualified Data.List.NonEmpty as NE |
21 |
| -import qualified Data.Maybe as Maybe |
22 |
| -import qualified Data.Text as T |
23 |
| -import qualified Data.Text.Encoding as Encoding |
| 19 | +import Data.HashMap.Strict (HashMap) |
| 20 | +import qualified Data.HashMap.Strict as HashMap |
| 21 | +import Data.List (find) |
| 22 | +import qualified Data.List.NonEmpty as NE |
| 23 | +import qualified Data.Maybe as Maybe |
| 24 | +import qualified Data.Text as T |
| 25 | +import qualified Data.Text.Encoding as Encoding |
24 | 26 | import Data.Typeable
|
25 |
| -import Development.IDE as D |
26 |
| -import Development.IDE.Core.Shake (restartShakeSession) |
27 |
| -import qualified Development.IDE.Core.Shake as Shake |
28 |
| -import Development.IDE.Graph (Key, alwaysRerun) |
29 |
| -import qualified Development.IDE.Plugin.Completions.Logic as Ghcide |
30 |
| -import Development.IDE.Types.Shake (toKey) |
31 |
| -import qualified Distribution.Fields as Syntax |
32 |
| -import qualified Distribution.Parsec.Position as Syntax |
| 27 | +import Development.IDE as D |
| 28 | +import Development.IDE.Core.Shake (restartShakeSession) |
| 29 | +import qualified Development.IDE.Core.Shake as Shake |
| 30 | +import Development.IDE.Graph (Key, |
| 31 | + alwaysRerun) |
| 32 | +import qualified Development.IDE.Plugin.Completions.Logic as Ghcide |
| 33 | +import Development.IDE.Types.Shake (toKey) |
| 34 | +import qualified Distribution.Fields as Syntax |
| 35 | +import qualified Distribution.Parsec.Position as Syntax |
33 | 36 | import GHC.Generics
|
34 |
| -import qualified Ide.Plugin.Cabal.Completion.Completer.Types as CompleterTypes |
35 |
| -import qualified Ide.Plugin.Cabal.Completion.Completions as Completions |
36 |
| -import Ide.Plugin.Cabal.Completion.Types (ParseCabalCommonSections (ParseCabalCommonSections), |
37 |
| - ParseCabalFields (..), |
38 |
| - ParseCabalFile (..)) |
39 |
| -import qualified Ide.Plugin.Cabal.Completion.Types as Types |
40 |
| -import qualified Ide.Plugin.Cabal.Diagnostics as Diagnostics |
41 |
| -import qualified Ide.Plugin.Cabal.FieldSuggest as FieldSuggest |
42 |
| -import qualified Ide.Plugin.Cabal.LicenseSuggest as LicenseSuggest |
43 |
| -import Ide.Plugin.Cabal.Orphans () |
| 37 | +import Ide.Plugin.Cabal.Completion.CabalFields as CabalFields |
| 38 | +import qualified Ide.Plugin.Cabal.Completion.Completer.Types as CompleterTypes |
| 39 | +import qualified Ide.Plugin.Cabal.Completion.Completions as Completions |
| 40 | +import Ide.Plugin.Cabal.Completion.Types (ParseCabalCommonSections (ParseCabalCommonSections), |
| 41 | + ParseCabalFields (..), |
| 42 | + ParseCabalFile (..)) |
| 43 | +import qualified Ide.Plugin.Cabal.Completion.Types as Types |
| 44 | +import qualified Ide.Plugin.Cabal.Diagnostics as Diagnostics |
| 45 | +import qualified Ide.Plugin.Cabal.FieldSuggest as FieldSuggest |
| 46 | +import qualified Ide.Plugin.Cabal.LicenseSuggest as LicenseSuggest |
| 47 | +import Ide.Plugin.Cabal.Orphans () |
44 | 48 | import Ide.Plugin.Cabal.Outline
|
45 |
| -import qualified Ide.Plugin.Cabal.Parse as Parse |
| 49 | +import qualified Ide.Plugin.Cabal.Parse as Parse |
46 | 50 | import Ide.Types
|
47 |
| -import qualified Language.LSP.Protocol.Lens as JL |
48 |
| -import qualified Language.LSP.Protocol.Message as LSP |
| 51 | +import qualified Language.LSP.Protocol.Lens as JL |
| 52 | +import qualified Language.LSP.Protocol.Message as LSP |
49 | 53 | import Language.LSP.Protocol.Types
|
50 |
| -import qualified Language.LSP.VFS as VFS |
51 |
| -import Data.List (find) |
52 |
| -import Ide.Plugin.Cabal.Completion.CabalFields as CabalFields |
53 |
| - |
54 |
| -import Debug.Trace |
| 54 | +import qualified Language.LSP.VFS as VFS |
| 55 | + |
| 56 | +import Debug.Trace |
| 57 | +import Distribution.PackageDescription (Benchmark (..), |
| 58 | + BuildInfo (..), |
| 59 | + Executable (..), |
| 60 | + ForeignLib (..), |
| 61 | + Library (..), |
| 62 | + LibraryName (LMainLibName, LSubLibName), |
| 63 | + PackageDescription (..), |
| 64 | + TestSuite (..), |
| 65 | + library, |
| 66 | + unUnqualComponentName) |
| 67 | +import Distribution.PackageDescription.Configuration (flattenPackageDescription) |
55 | 68 |
|
56 | 69 | data Log
|
57 | 70 | = LogModificationTime NormalizedFilePath FileVersion
|
@@ -297,31 +310,86 @@ gotoDefinition ideState _ msgParam = do
|
297 | 310 | pure $ InR $ InR Null
|
298 | 311 | Just filePath -> do
|
299 | 312 | mCabalFields <- liftIO $ runAction "cabal-plugin.commonSections" ideState $ use ParseCabalFields $ toNormalizedFilePath filePath
|
300 |
| - let mModuleNames = CabalFields.getModulesNames <$> mCabalFields |
301 |
| - let mModuleSections = CabalFields.getSectionsWithModules <$> mCabalFields |
302 |
| - traceShowM ("mModuleNames", mModuleNames) |
303 |
| - traceShowM ("mModuleSections", mModuleSections) |
304 | 313 |
|
305 | 314 | let mCursorText = CabalFields.findTextWord cursor =<< mCabalFields
|
306 | 315 | case mCursorText of
|
307 | 316 | Nothing ->
|
308 | 317 | pure $ InR $ InR Null
|
309 | 318 | Just cursorText -> do
|
310 | 319 | mCommonSections <- liftIO $ runAction "cabal-plugin.commonSections" ideState $ use ParseCabalCommonSections $ toNormalizedFilePath filePath
|
311 |
| - let mCommonSection = find (filterSectionArgName cursorText) =<< mCommonSections |
| 320 | + let mCommonSection = find (isSectionArgName cursorText) =<< mCommonSections |
312 | 321 | case mCommonSection of
|
313 |
| - Nothing -> |
314 |
| - pure $ InR $ InR Null |
315 | 322 | Just commonSection -> do
|
316 | 323 | pure $ InL $ Definition $ InL $ Location uri $ CabalFields.getFieldLSPRange commonSection
|
| 324 | + Nothing -> do |
| 325 | + let mModuleNames = CabalFields.getModulesNames <$> mCabalFields |
| 326 | + mModuleName = find (isModuleName cursorText) =<< mModuleNames |
| 327 | + case mModuleName of |
| 328 | + Nothing -> traceShowM ("NOT A MODULE") |
| 329 | + Just (mBuildTargetNames, moduleName) -> do |
| 330 | + traceShowM ("IS A MODULE", moduleName, "at", mBuildTargetNames) |
| 331 | + mGPD <- liftIO $ runAction "cabal.GPD" ideState $ useWithStale ParseCabalFile $ toNormalizedFilePath filePath |
| 332 | + case mGPD of |
| 333 | + Nothing -> traceShowM ("failed to get GPD") |
| 334 | + Just (gpd, _) -> do |
| 335 | + let debug = map (lookupBuildTargetPackageDescription |
| 336 | + (flattenPackageDescription gpd)) |
| 337 | + mBuildTargetNames |
| 338 | + traceShowM ("debug is", debug) |
| 339 | + let buildInfos = foldMap (lookupBuildTargetPackageDescription |
| 340 | + (flattenPackageDescription gpd)) |
| 341 | + mBuildTargetNames |
| 342 | + traceShowM ("buildInfos is", buildInfos) |
| 343 | + traceShowM ("Found hsSourceDirs", map hsSourceDirs buildInfos) |
| 344 | + pure $ InR $ InR Null |
317 | 345 | where
|
318 | 346 | cursor = Types.lspPositionToCabalPosition (msgParam ^. JL.position)
|
319 | 347 | uri = msgParam ^. JL.textDocument . JL.uri
|
320 |
| - filterSectionArgName name (Syntax.Section _ sectionArgName _) = name == CabalFields.onelineSectionArgs sectionArgName |
321 |
| - filterSectionArgName _ _ = False |
322 |
| - |
323 |
| - |
324 |
| - |
| 348 | + isSectionArgName name (Syntax.Section _ sectionArgName _) = name == CabalFields.onelineSectionArgs sectionArgName |
| 349 | + isSectionArgName _ _ = False |
| 350 | + isModuleName name (_, moduleName) = name == moduleName |
| 351 | + |
| 352 | + lookupBuildTargetPackageDescription :: PackageDescription -> Maybe T.Text -> [BuildInfo] |
| 353 | + lookupBuildTargetPackageDescription (PackageDescription {..}) Nothing = |
| 354 | + case library of |
| 355 | + Nothing -> error "Target is a main library but no main library was found" |
| 356 | + Just (Library {libBuildInfo}) -> [libBuildInfo] |
| 357 | + lookupBuildTargetPackageDescription (PackageDescription {..}) (Just buildTargetName) = |
| 358 | + Maybe.catMaybes $ |
| 359 | + map (\exec -> executableNameLookup exec buildTargetName) executables <> |
| 360 | + map (\lib -> subLibraryNameLookup lib buildTargetName) subLibraries <> |
| 361 | + map (\lib -> foreignLibsNameLookup lib buildTargetName) foreignLibs <> |
| 362 | + map (\test -> testSuiteNameLookup test buildTargetName) testSuites <> |
| 363 | + map (\bench -> benchmarkNameLookup bench buildTargetName) benchmarks |
| 364 | + where |
| 365 | + executableNameLookup :: Executable -> T.Text -> Maybe BuildInfo |
| 366 | + executableNameLookup (Executable {exeName, buildInfo}) buildTargetName = |
| 367 | + if T.pack (unUnqualComponentName exeName) == buildTargetName |
| 368 | + then Just buildInfo |
| 369 | + else Nothing |
| 370 | + subLibraryNameLookup :: Library -> T.Text -> Maybe BuildInfo |
| 371 | + subLibraryNameLookup (Library {libName, libBuildInfo}) buildTargetName = |
| 372 | + case libName of |
| 373 | + (LSubLibName name) -> |
| 374 | + if T.pack (unUnqualComponentName name) == buildTargetName |
| 375 | + then Just libBuildInfo |
| 376 | + else Nothing |
| 377 | + LMainLibName -> Nothing |
| 378 | + foreignLibsNameLookup :: ForeignLib -> T.Text -> Maybe BuildInfo |
| 379 | + foreignLibsNameLookup (ForeignLib {foreignLibName, foreignLibBuildInfo}) buildTargetName = |
| 380 | + if T.pack (unUnqualComponentName foreignLibName) == buildTargetName |
| 381 | + then Just foreignLibBuildInfo |
| 382 | + else Nothing |
| 383 | + testSuiteNameLookup :: TestSuite -> T.Text -> Maybe BuildInfo |
| 384 | + testSuiteNameLookup (TestSuite {testName, testBuildInfo}) buildTargetName = |
| 385 | + if T.pack (unUnqualComponentName testName) == buildTargetName |
| 386 | + then Just testBuildInfo |
| 387 | + else Nothing |
| 388 | + benchmarkNameLookup :: Benchmark -> T.Text -> Maybe BuildInfo |
| 389 | + benchmarkNameLookup (Benchmark {benchmarkName, benchmarkBuildInfo}) buildTargetName = |
| 390 | + if T.pack (unUnqualComponentName benchmarkName) == buildTargetName |
| 391 | + then Just benchmarkBuildInfo |
| 392 | + else Nothing |
325 | 393 | -- ----------------------------------------------------------------
|
326 | 394 | -- Cabal file of Interest rules and global variable
|
327 | 395 | -- ----------------------------------------------------------------
|
|
0 commit comments