From 0754feb1e3b4bb6a880f90f3f8c54deba4ddc2f9 Mon Sep 17 00:00:00 2001 From: Tristan Cacqueray Date: Thu, 24 Aug 2023 12:12:59 +0000 Subject: [PATCH] Set the first multi-repl targets as the active unit When using the multi components repl, the last unit given to ghc is the active unit. This change uses the cabal repl argument order instead of relying on the 'listDirectory' ordering. --- cabal-install/src/Distribution/Client/CmdRepl.hs | 21 ++++++++++++++++++++- .../MultiRepl/EnabledClosure/cabal.test.hs | 10 ++-------- .../MultiRepl/EnabledSucc/cabal.test.hs | 8 ++------ doc/internal/multi-repl.md | 11 ++++++++++- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/cabal-install/src/Distribution/Client/CmdRepl.hs b/cabal-install/src/Distribution/Client/CmdRepl.hs index a8189f8e6..e243eb829 100644 --- a/cabal-install/src/Distribution/Client/CmdRepl.hs +++ b/cabal-install/src/Distribution/Client/CmdRepl.hs @@ -447,6 +447,25 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g -- unit files for components unit_files <- listDirectory dir + -- Order the unit files so that the find target becomes the active unit + let active_unit_fp :: Maybe FilePath + active_unit_fp = do + -- Get the first target selectors from the cli + activeTarget <- safeHead targetSelectors + -- Lookup the targets :: Map UnitId [(ComponentTarget, NonEmpty TargetSelector)] + unitId <- + Map.toList targets + -- Keep the UnitId matching the desired target selector + & find (\(_, xs) -> any (\(_, selectors) -> activeTarget `elem` selectors) xs) + & fmap fst + -- Convert to filename (adapted from 'storePackageDirectory') + pure (prettyShow unitId) + unit_files_ordered :: [FilePath] + unit_files_ordered = + let (active_unit_files, other_units) = partition (\fp -> Just fp == active_unit_fp) unit_files + in -- GHC considers the last unit passed to be the active one + other_units ++ active_unit_files + -- run ghc --interactive with runProgramInvocation verbosity $ programInvocation ghcProg' $ @@ -458,7 +477,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g , show (buildSettingNumJobs (buildSettings ctx)) ] : [ ["-unit", "@" ++ dir unit] - | unit <- unit_files + | unit <- unit_files_ordered , unit /= "paths" ] diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs index 54a0afeb9..7bfea13c2 100644 --- a/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs @@ -5,13 +5,7 @@ main = do skipUnlessGhcVersion ">= 9.4" -- Note: only the last package is interactive. -- this test should load pkg-b too. - res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-a", "pkg-c"] "" - - -- we should check that pkg-c is indeed loaded, - -- but currently the unit order is non-deterministic - -- Fix this when GHC has a way to change active unit. - -- TODO: ask for pkg-c unit, print Quu.quu + res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-c", "pkg-a"] "Quu.quu" assertOutputContains "- pkg-b-0 (interactive)" res - -- assertOutputContains "168" res - return () + assertOutputContains "168" res diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs index 640b25d0d..7ea2f71ea 100644 --- a/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs @@ -4,9 +4,5 @@ main = do cabalTest $ do skipUnlessGhcVersion ">= 9.4" skipIfWindows -- heisenbug, see #9103 - -- the package order is non-deterministic. - -- add Bar.Bar input to test that packages are trully loaded - -- when GHC gets support for switching active units - res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-a", "pkg-b"] "" - -- assertOutputContains "3735929054" res - return () + res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-b", "pkg-a"] "Bar.bar" + assertOutputContains "3735929054" res diff --git a/doc/internal/multi-repl.md b/doc/internal/multi-repl.md index 5f0f731e3..1e8987288 100644 --- a/doc/internal/multi-repl.md +++ b/doc/internal/multi-repl.md @@ -33,11 +33,12 @@ Here are some common targets which you can specify when using `cabal`. * `all`: Build all the locally defined components. * `exe:haskell-language-server`: Build the executable called `haskell-language-server` -* `lib:pkg-a lib:pkg-b`: Build the local libraries pkg-a and pkg-b. +* `lib:pkg-a lib:pkg-b`: Build the local libraries pkg-a and pkg-b. pkg-a will be the active unit. * `src/Main.hs`: Build the unit which `src/Main.hs` belongs to. After enabling multi-repl, passing a target specification to `cabal repl` which resolves to multiple units will load all those units into a single repl session. +The first "target" will be the active unit. For example: ``` @@ -203,6 +204,14 @@ At this time, the multi-repl is best used for interactive development situations you want to use the repl to obtain fast-feedback about your project. We have made sure that the multi-repl works with `ghcid` for example. +When evaluating code, make sure that the code is in the scope of the active unit, +which is the first target given on the command line. For example, to run the test suite +entrypoint, use: + +``` +ghcid --command "cabal repl --enable-multi-repl test:suite lib:pkg" --test Main.main +``` + # Conclusion Adding `cabal repl` support for multiple home units allows developers to easily -- 2.11.4.GIT