Skip to content

Commit

Permalink
Add workaround for bad relative paths
Browse files Browse the repository at this point in the history
cabal repl switches current directory for subpackages of
a project, resulting in error paths relative to some
subdirectory. This confuses downstream tooling.

Related cabal tickets are
haskell/cabal#5001
haskell/cabal#1842

Gated behind the newly added flag --force-absolute-paths
  • Loading branch information
lspitzner committed Feb 27, 2024
1 parent 19b0e91 commit 7a58535
Showing 1 changed file with 26 additions and 5 deletions.
31 changes: 26 additions & 5 deletions src/Ghcid.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Control.Exception
import System.IO.Error
import Control.Applicative
import Control.Monad.Extra
import Data.Char (isSpace)
import Data.List.Extra
import Data.Maybe
import Data.Ord
Expand Down Expand Up @@ -60,6 +61,7 @@ data Options = Options
,directory :: FilePath
,outputfile :: [FilePath]
,ignoreLoaded :: Bool
,forceAbsolutePaths :: Bool
,poll :: Maybe Seconds
,max_messages :: Maybe Int
,color :: ColorMode
Expand Down Expand Up @@ -99,6 +101,7 @@ options = cmdArgsMode $ Options
,directory = "." &= typDir &= name "C" &= help "Set the current directory"
,outputfile = [] &= typFile &= name "o" &= help "File to write the full output to"
,ignoreLoaded = False &= explicit &= name "ignore-loaded" &= help "Keep going if no files are loaded. Requires --reload to be set."
,forceAbsolutePaths = False &= explicit &= name "force-absolute-paths" &= help "Workaround for bad relative paths with cabal repl - replaces paths in messages with absolute ones when writing to an output file"
,poll = Nothing &= typ "SECONDS" &= opt "0.1" &= explicit &= name "poll" &= help "Use polling every N seconds (defaults to using notifiers)"
,max_messages = Nothing &= name "n" &= help "Maximum number of messages to print"
,color = Auto &= name "colour" &= name "color" &= opt Always &= typ "always/never/auto" &= help "Color output (defaults to when the terminal supports it)"
Expand Down Expand Up @@ -290,7 +293,7 @@ runGhcid session waiter termSize termOutput opts@Options{..} = do
outputFill currTime load evals msg = do
load <- pure $ case load of
Nothing -> []
Just (loadedCount, msgs) -> prettyOutput currTime loadedCount (filter isMessage msgs) evals
Just (loadedCount, msgs) -> prettyOutput False currTime loadedCount (filter isMessage msgs) evals
TermSize{..} <- termSize
let wrap = concatMap (wordWrapE termWidth (termWidth `div` 5) . Esc)
(msg, load, pad) <-
Expand Down Expand Up @@ -384,7 +387,7 @@ runGhcid session waiter termSize termOutput opts@Options{..} = do
if takeExtension file == ".json" then
showJSON [("loaded",map jString loaded),("messages",map jMessage $ filter isMessage messages)]
else
unlines $ map unescape $ prettyOutput currTime loadedCount (limitMessages ordMessages) evals
unlines $ map unescape $ prettyOutput forceAbsolutePaths currTime loadedCount (limitMessages ordMessages) evals
when (null loaded && not ignoreLoaded) $ do
putStrLn "No files loaded, nothing to wait for. Fix the last error and restart."
exitFailure
Expand Down Expand Up @@ -436,11 +439,29 @@ runGhcid session waiter termSize termOutput opts@Options{..} = do


-- | Given an available height, and a set of messages to display, show them as best you can.
prettyOutput :: String -> Int -> [Load] -> [EvalResult] -> [String]
prettyOutput currTime loadedCount [] evals =
-- The boolean determines whether file paths in the warning/error messages
-- will be replaced by absolute paths provided in the loadFile field.
-- False ~ "keep the exact output from ghci" and
-- True ~ "paths will be replaced by absolute paths to help downstream tooling"
prettyOutput :: Bool -> String -> Int -> [Load] -> [EvalResult] -> [String]
prettyOutput _replacePaths currTime loadedCount [] evals =
(allGoodMessage ++ " (" ++ show loadedCount ++ " module" ++ ['s' | loadedCount /= 1] ++ ", at " ++ currTime ++ ")")
: concatMap printEval evals
prettyOutput _ _ xs evals = concatMap loadMessage xs ++ concatMap printEval evals
prettyOutput replacePaths _ _ xs evals =
messageLines ++ concatMap printEval evals
where
messageLines =
[ case l of
_ | not replacePaths -> l
"" -> l
c : _ | isSpace c -> l
_ -> if "hs:" `isInfixOf` l
then loadFile x ++ dropWhile (/= ':') l
else l
| x <- xs
, l <- loadMessage x
]


printEval :: EvalResult -> [String]
printEval (EvalResult file (line, col) msg result) =
Expand Down

0 comments on commit 7a58535

Please sign in to comment.