packages feed

ghci-quickfix 0.1.0.0 → 0.1.1.0

raw patch · 4 files changed

+44/−29 lines, 4 filesdep ~basedep ~ghcPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, ghc

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for ghci-quickfix +## 0.1.1.0 -- 2026-05-13++* Support GHC 9.14+* Drop support for 9.6+* Sort errors in quickfix file by order of emission+ ## 0.1.0.0 -- 2026-01-09  * First version. Released on an unsuspecting world.
ghci-quickfix.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               ghci-quickfix-version:            0.1.0.0+version:            0.1.1.0 synopsis:           GHC plugin that writes errors to a file for use with quickfix description:        GHC plugin that writes errors to a file for use with vim/nvim's quickfix system license:            BSD-3-Clause@@ -12,7 +12,7 @@ build-type:         Simple extra-doc-files:    CHANGELOG.md                     README.md-tested-with: GHC == 9.12.1, GHC == 9.10.1, GHC == 9.8.1, GHC == 9.6.1+tested-with: GHC == 9.14.1, GHC == 9.12.1, GHC == 9.10.1, GHC == 9.8.1 -- extra-source-files:  source-repository head@@ -27,8 +27,8 @@     exposed-modules:  GhciQuickfix     other-modules: GhciQuickfix.GhcFacade     -- other-extensions:-    build-depends:    base < 4.23,-                      ghc >= 9.6 && < 9.13,+    build-depends:    base < 4.24,+                      ghc >= 9.8 && < 9.15,                       text,                       async >= 2.2 && < 3,                       stm-containers >= 1.2 && < 1.3,@@ -47,7 +47,7 @@     type:             exitcode-stdio-1.0     hs-source-dirs:   test     main-is:          Main.hs-    ghc-options: -threaded -with-rtsopts=-N+    -- ghc-options: -threaded -rtsopts -with-rtsopts=-N     build-depends:         base,         ghci-quickfix,
src/GhciQuickfix.hs view
@@ -18,9 +18,10 @@ import           Data.Either (partitionEithers) import           Data.Foldable import           Data.IORef-import           Data.List (stripPrefix)+import qualified Data.List as List import           Data.Maybe import           Data.Monoid (First(..))+import qualified Data.Ord as Ord import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Text.IO as TIO@@ -32,7 +33,11 @@  import qualified GhciQuickfix.GhcFacade as Ghc -type ErrMap = SM.Map FilePath [T.Text]+-- | STM Map is used to avoid contention between modules compiled in parrallel,+-- although it isn't clear if it actually helps since contention will still+-- happen with the STVars used in the same transaction.+-- The Int paired with the errors is used for ordering.+type ErrMap = SM.Map FilePath (Int, [T.Text])  plugin :: Ghc.Plugin plugin = Ghc.defaultPlugin@@ -54,7 +59,11 @@       writeTVar updated False       DF.foldM (F.generalize F.list) (SM.unfoldlM errMap)     prunedMsgs <- pruneDeletedFiles msgs errMap-    TIO.writeFile (fromMaybe "errors.err" mErrFilePath) $ T.unlines prunedMsgs+    TIO.writeFile (fromMaybe "errors.err" mErrFilePath)+      . T.unlines . foldMap snd+      -- Sort in reverse so that the first error in the list is the last one to+      -- be emitted by the compiler+      $ List.sortOn Ord.Down prunedMsgs     threadDelay 200_000 -- 200ms  parseFilePathModifier :: [Ghc.CommandLineOption] -> IO (Either String [T.Text -> T.Text])@@ -73,13 +82,13 @@     mPat <- Env.lookupEnv "GHCI_QUICKFIX_PATH_REPLACE"     pure $ parseReplacement "GHCI_QUICKFIX_PATH_REPLACE environment variable" <$> mPat   getModifier opt = do-    pat <- stripPrefix "--quickfix-path-replace=" opt+    pat <- List.stripPrefix "--quickfix-path-replace=" opt     Just $ parseReplacement "--quickfix-path-replace argument" pat  parseQuickfixFilePath :: [Ghc.CommandLineOption] -> IO (Maybe FilePath) parseQuickfixFilePath opts = do   envPath <- Env.lookupEnv "GHCI_QUICKFIX_FILE"-  pure $ getFirst $ foldMap (First . stripPrefix "--quickfix-file=") opts <> First envPath+  pure $ getFirst $ foldMap (First . List.stripPrefix "--quickfix-file=") opts <> First envPath  parseIncludeParserErrors :: [Ghc.CommandLineOption] -> IO Bool parseIncludeParserErrors opts = do@@ -102,14 +111,15 @@       Right filePathMods -> do         errMap <- SM.newIO         errsUpdated <- newTVarIO False+        counter <- newTVarIO 0         quickfixFilePath <- parseQuickfixFilePath opts         void . Async.async $ writeQuickfixLoop quickfixFilePath errMap errsUpdated         includeParserErrors <- parseIncludeParserErrors opts-        pure hscEnv { Ghc.hsc_hooks = modifyHooks includeParserErrors filePathMods (Ghc.hsc_hooks hscEnv) errMap errsUpdated }+        pure hscEnv { Ghc.hsc_hooks = modifyHooks includeParserErrors filePathMods (Ghc.hsc_hooks hscEnv) errMap errsUpdated counter }   else     pure hscEnv   where-    modifyHooks includeParserErrors filePathMods hooks (errMap :: ErrMap) (errsUpdated :: TVar Bool) =+    modifyHooks includeParserErrors filePathMods hooks (errMap :: ErrMap) (errsUpdated :: TVar Bool) (counter :: TVar Int) =       let runPhaseOrExistingHook :: Ghc.TPhase res -> IO res           runPhaseOrExistingHook = maybe Ghc.runPhase (\(Ghc.PhaseHook h) -> h)             $ Ghc.runPhaseHook hooks@@ -122,7 +132,7 @@             dsWarnVar <- newIORef mempty             try (runPhaseOrExistingHook $ addDsLogHook (logHookHack dsWarnVar hscEnv) phase) >>= \case               Left err@(Ghc.SourceError msgs) -> do-                handleMessages includeParserErrors filePathMods errMap errsUpdated msgs+                handleMessages includeParserErrors filePathMods errMap errsUpdated counter msgs                 throw err               Right res -> do                 dsWarns <- readIORef dsWarnVar@@ -137,7 +147,7 @@                         Just _ -> do                           SM.delete (Ghc.ms_hspp_file modSummary) errMap                           writeTVar errsUpdated True-                    else handleMessages includeParserErrors filePathMods errMap errsUpdated $+                    else handleMessages includeParserErrors filePathMods errMap errsUpdated counter $                       if length tcWarnings == length dsWarns                       then tcWarnings -- has preferred formatting                       else dsWarns@@ -192,8 +202,15 @@     <> severity <> ": " <> msg  -- | Update state given all diagnostics for a module-handleMessages :: Bool -> [T.Text -> T.Text] -> ErrMap -> TVar Bool -> Ghc.Messages Ghc.GhcMessage -> IO ()-handleMessages includeParserErrors filePathMods errMap errsUpdated messages = do+handleMessages+  :: Bool+  -> [T.Text -> T.Text]+  -> ErrMap+  -> TVar Bool+  -> TVar Int+  -> Ghc.Messages Ghc.GhcMessage+  -> IO ()+handleMessages includeParserErrors filePathMods errMap errsUpdated counter messages = do   let envelopes = Ghc.getMessages messages       isParseError = \case         Ghc.GhcPsMessage{} -> True@@ -207,11 +224,12 @@           (First . fmap Ghc.unpackFS . Ghc.srcSpanFileName_maybe . Ghc.errMsgSpan)           $ Ghc.getMessages messages   for_ mFile $ \file -> atomically $ do-    SM.insert errs file errMap+    n <- stateTVar counter (\x -> let !nx = x + 1 in (x, nx))+    SM.insert (n, errs) file errMap     writeTVar errsUpdated True  -- | Remove errors for files that no longer exist-pruneDeletedFiles :: [(FilePath, [T.Text])] -> ErrMap -> IO [T.Text]+pruneDeletedFiles :: [(FilePath, (Int, [T.Text]))] -> ErrMap -> IO [(Int, [T.Text])] pruneDeletedFiles errs errMap = do   let files = fst <$> errs   deletedFiles <- fmap catMaybes $@@ -220,7 +238,7 @@         True -> pure Nothing         False -> pure (Just file)   atomically $ traverse_ (`SM.delete` errMap) deletedFiles-  pure . foldMap snd $ filter (not . (`elem` deletedFiles) . fst) errs+  pure . fmap snd $ filter (not . (`elem` deletedFiles) . fst) errs  -- | Currently no good way to get warnings from desugarer, so a log action hook -- is used to get the raw SDoc. Note: unfortunately this will also capture@@ -236,13 +254,7 @@                 , Ghc.diagHints = []                 }             diagOpts = Ghc.initDiagOpts $ Ghc.hsc_dflags hscEnv-            mkUnknownDiag =-#if MIN_VERSION_ghc(9,8,0)-              Ghc.UnknownDiagnostic id-#else-              Ghc.UnknownDiagnostic-#endif-            ghcMessage = Ghc.GhcDsMessage . Ghc.DsUnknownMessage $ mkUnknownDiag diag+            ghcMessage = Ghc.GhcDsMessage . Ghc.DsUnknownMessage $ Ghc.mkUnknownDiagnostic diag             warn = Ghc.mkMsgEnvelope diagOpts srcSpan Ghc.neverQualify ghcMessage         modifyIORef dsWarnVar (Ghc.addMessage warn)     _ -> pure ()
src/GhciQuickfix/GhcFacade.hs view
@@ -22,6 +22,3 @@ import           GHC.Utils.Logger as Ghc import           GHC.Driver.Config.Diagnostic as Ghc import           GHC.HsToCore.Errors.Types as Ghc-#if !MIN_VERSION_ghc(9,8,0)-import           GHC.Tc.Errors.Ppr as Ghc-#endif