diff options
author | Phil Ruffwind <rf@rufflewind.com> | 2017-03-23 20:59:01 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2017-03-23 22:14:48 -0400 |
commit | adf27d614f8a48d8dcf2d4e2e7872f7b3f818364 (patch) | |
tree | 5dae7f8b6ed3caecfceaa220798967291904ed26 /compiler | |
parent | 90d9e977224f3bd71bd5d2cc70e16851541346d2 (diff) | |
download | haskell-adf27d614f8a48d8dcf2d4e2e7872f7b3f818364.tar.gz |
Allow colors to be customized
Allow customization of diagnostic colors through the GHC_COLORS
environment variable. Some color-related code have been refactored to
PprColour to reduce the circular dependence between DynFlags,
Outputable, ErrUtils. Some color functions that were part of Outputable
but were never used have been deleted.
Test Plan: validate
Reviewers: austin, hvr, bgamari, dfeuer
Reviewed By: bgamari, dfeuer
Subscribers: dfeuer, rwbarton, thomie, snowleopard
Differential Revision: https://phabricator.haskell.org/D3364
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ghc.cabal.in | 1 | ||||
-rw-r--r-- | compiler/ghc.mk | 1 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs | 28 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs-boot | 5 | ||||
-rw-r--r-- | compiler/main/ErrUtils.hs | 39 | ||||
-rw-r--r-- | compiler/utils/Outputable.hs | 87 | ||||
-rw-r--r-- | compiler/utils/PprColour.hs | 88 | ||||
-rw-r--r-- | compiler/utils/Util.hs | 15 |
8 files changed, 158 insertions, 106 deletions
diff --git a/compiler/ghc.cabal.in b/compiler/ghc.cabal.in index fc8dcd98bf..6054d8579a 100644 --- a/compiler/ghc.cabal.in +++ b/compiler/ghc.cabal.in @@ -501,6 +501,7 @@ Library Outputable Pair Panic + PprColour Pretty State Stream diff --git a/compiler/ghc.mk b/compiler/ghc.mk index 3f6e77ca4b..28b0001805 100644 --- a/compiler/ghc.mk +++ b/compiler/ghc.mk @@ -528,6 +528,7 @@ compiler_stage2_dll0_MODULES = \ PipelineMonad \ Platform \ PlatformConstants \ + PprColour \ PprCore \ PrelNames \ PrelRules \ diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index 057c2c0071..927d3c46a0 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -42,7 +42,6 @@ module DynFlags ( DynFlags(..), FlagSpec(..), HasDynFlags(..), ContainsDynFlags(..), - OverridingBool(..), overrideWith, RtsOptsEnabled(..), HscTarget(..), isObjectTarget, defaultObjectTarget, targetRetainsAllBindings, @@ -58,6 +57,7 @@ module DynFlags ( dynFlagDependencies, tablesNextToCode, mkTablesNextToCode, makeDynFlagsConsistent, + shouldUseColor, Way(..), mkBuildTag, wayRTSOnly, addWay', updateWays, wayGeneralFlags, wayUnsetGeneralFlags, @@ -170,6 +170,7 @@ import Config import CmdLineParser import Constants import Panic +import qualified PprColour as Col import Util import Maybes import MonadUtils @@ -207,7 +208,7 @@ import qualified Data.Set as Set import Data.Word import System.FilePath import System.Directory -import System.Environment (getEnv) +import System.Environment (getEnv, lookupEnv) import System.IO import System.IO.Error import Text.ParserCombinators.ReadP hiding (char) @@ -911,6 +912,7 @@ data DynFlags = DynFlags { useUnicode :: Bool, useColor :: OverridingBool, canUseColor :: Bool, + colScheme :: Col.Scheme, -- | what kind of {-# SCC #-} to add automatically profAuto :: ProfAuto, @@ -1291,16 +1293,8 @@ data DynLibLoader data RtsOptsEnabled = RtsOptsNone | RtsOptsSafeOnly | RtsOptsAll deriving (Show) -data OverridingBool - = Auto - | Always - | Never - deriving Show - -overrideWith :: Bool -> OverridingBool -> Bool -overrideWith b Auto = b -overrideWith _ Always = True -overrideWith _ Never = False +shouldUseColor :: DynFlags -> Bool +shouldUseColor dflags = overrideWith (canUseColor dflags) (useColor dflags) ----------------------------------------------------------------------------- -- Ways @@ -1505,6 +1499,13 @@ initDynFlags dflags = do return (str == str')) `catchIOError` \_ -> return False canUseColor <- stderrSupportsAnsiColors + maybeGhcColorsEnv <- lookupEnv "GHC_COLORS" + maybeGhcColoursEnv <- lookupEnv "GHC_COLOURS" + let adjustCols (Just env) = Col.parseScheme env + adjustCols Nothing = id + let (useColor', colScheme') = + (adjustCols maybeGhcColoursEnv . adjustCols maybeGhcColorsEnv) + (useColor dflags, colScheme dflags) return dflags{ canGenerateDynamicToo = refCanGenerateDynamicToo, nextTempSuffix = refNextTempSuffix, @@ -1514,7 +1515,9 @@ initDynFlags dflags = do generatedDumps = refGeneratedDumps, nextWrapperNum = wrapperNum, useUnicode = canUseUnicode, + useColor = useColor', canUseColor = canUseColor, + colScheme = colScheme', rtldInfo = refRtldInfo, rtccInfo = refRtccInfo } @@ -1680,6 +1683,7 @@ defaultDynFlags mySettings = useUnicode = False, useColor = Auto, canUseColor = False, + colScheme = Col.defaultScheme, profAuto = NoProfAuto, interactivePrint = Nothing, nextWrapperNum = panic "defaultDynFlags: No nextWrapperNum", diff --git a/compiler/main/DynFlags.hs-boot b/compiler/main/DynFlags.hs-boot index 14c039aca3..5fd80fcd82 100644 --- a/compiler/main/DynFlags.hs-boot +++ b/compiler/main/DynFlags.hs-boot @@ -4,7 +4,6 @@ module DynFlags where import Platform data DynFlags -data OverridingBool data DumpFlag targetPlatform :: DynFlags -> Platform @@ -13,8 +12,6 @@ pprCols :: DynFlags -> Int unsafeGlobalDynFlags :: DynFlags useUnicode :: DynFlags -> Bool useUnicodeSyntax :: DynFlags -> Bool -useColor :: DynFlags -> OverridingBool -canUseColor :: DynFlags -> Bool -overrideWith :: Bool -> OverridingBool -> Bool +shouldUseColor :: DynFlags -> Bool hasPprDebug :: DynFlags -> Bool hasNoDebugOutput :: DynFlags -> Bool diff --git a/compiler/main/ErrUtils.hs b/compiler/main/ErrUtils.hs index a9310c607c..180d18d8c9 100644 --- a/compiler/main/ErrUtils.hs +++ b/compiler/main/ErrUtils.hs @@ -60,6 +60,7 @@ import Bag import Exception import Outputable import Panic +import qualified PprColour as Col import SrcLoc import DynFlags import FastString (unpackFS) @@ -73,7 +74,6 @@ import Data.List import qualified Data.Set as Set import Data.IORef import Data.Maybe ( fromMaybe ) -import Data.Monoid ( mappend ) import Data.Ord import Data.Time import Control.Monad @@ -199,14 +199,22 @@ mkLocMessageAnn ann severity locn msg let locn' = if gopt Opt_ErrorSpans dflags then ppr locn else ppr (srcSpanStart locn) + + sevColour = getSeverityColour severity (colScheme dflags) + + -- Add optional information + optAnn = case ann of + Nothing -> text "" + Just i -> text " [" <> coloured sevColour (text i) <> text "]" + -- Add prefixes, like Foo.hs:34: warning: -- <the warning message> prefix = locn' <> colon <+> coloured sevColour sevText <> optAnn - in bold (hang prefix 4 msg) - where - sevColour = colBold `mappend` getSeverityColour severity + in coloured (Col.sMessage (colScheme dflags)) (hang prefix 4 msg) + + where sevText = case severity of SevWarning -> text "warning:" @@ -214,16 +222,11 @@ mkLocMessageAnn ann severity locn msg SevFatal -> text "fatal:" _ -> empty - -- Add optional information - optAnn = case ann of - Nothing -> text "" - Just i -> text " [" <> coloured sevColour (text i) <> text "]" - -getSeverityColour :: Severity -> PprColour -getSeverityColour SevWarning = colMagentaFg -getSeverityColour SevError = colRedFg -getSeverityColour SevFatal = colRedFg -getSeverityColour _ = mempty +getSeverityColour :: Severity -> Col.Scheme -> Col.PprColour +getSeverityColour SevWarning = Col.sWarning +getSeverityColour SevError = Col.sError +getSeverityColour SevFatal = Col.sFatal +getSeverityColour _ = const mempty getCaretDiagnostic :: Severity -> SrcSpan -> IO MsgDoc getCaretDiagnostic _ (UnhelpfulSpan _) = pure empty @@ -255,10 +258,6 @@ getCaretDiagnostic severity (RealSrcSpan span) = do fix '\0' = '\xfffd' fix c = c - sevColour = colBold `mappend` getSeverityColour severity - - marginColour = colBold `mappend` colBlueFg - row = srcSpanStartLine span rowStr = show row multiline = row /= srcSpanEndLine span @@ -267,6 +266,10 @@ getCaretDiagnostic severity (RealSrcSpan span) = do caretDiagnostic Nothing = empty caretDiagnostic (Just srcLineWithNewline) = + sdocWithDynFlags $ \ dflags -> + let sevColour = getSeverityColour severity (colScheme dflags) + marginColour = Col.sMargin (colScheme dflags) + in coloured marginColour (text marginSpace) <> text ("\n") <> coloured marginColour (text marginRow) <> diff --git a/compiler/utils/Outputable.hs b/compiler/utils/Outputable.hs index 8a2afbec79..403c5cef73 100644 --- a/compiler/utils/Outputable.hs +++ b/compiler/utils/Outputable.hs @@ -38,9 +38,7 @@ module Outputable ( speakNth, speakN, speakNOf, plural, isOrAre, doOrDoes, unicodeSyntax, - coloured, bold, keyword, PprColour, colReset, colBold, colBlackFg, - colRedFg, colGreenFg, colYellowFg, colBlueFg, colMagentaFg, colCyanFg, - colWhiteFg, colBinder, colCoerc, colDataCon, colType, + coloured, keyword, -- * Converting 'SDoc' into strings and outputing it printSDoc, printSDocLn, printForUser, printForUserPartWay, @@ -89,8 +87,7 @@ module Outputable ( import {-# SOURCE #-} DynFlags( DynFlags, hasPprDebug, hasNoDebugOutput, targetPlatform, pprUserLength, pprCols, useUnicode, useUnicodeSyntax, - useColor, canUseColor, overrideWith, - unsafeGlobalDynFlags ) + shouldUseColor, unsafeGlobalDynFlags ) import {-# SOURCE #-} Module( UnitId, Module, ModuleName, moduleName ) import {-# SOURCE #-} OccName( OccName ) @@ -99,6 +96,7 @@ import FastString import qualified Pretty import Util import Platform +import qualified PprColour as Col import Pretty ( Doc, Mode(..) ) import Panic import GHC.Serialized @@ -113,7 +111,6 @@ import Data.Int import qualified Data.IntMap as IM import Data.Set (Set) import qualified Data.Set as Set -import Data.Monoid (Monoid, mappend, mempty) import Data.String import Data.Word import System.IO ( Handle ) @@ -318,7 +315,7 @@ newtype SDoc = SDoc { runSDoc :: SDocContext -> Doc } data SDocContext = SDC { sdocStyle :: !PprStyle - , sdocLastColour :: !PprColour + , sdocLastColour :: !Col.PprColour -- ^ The most recently used colour. This allows nesting colours. , sdocDynFlags :: !DynFlags } @@ -329,7 +326,7 @@ instance IsString SDoc where initSDocContext :: DynFlags -> PprStyle -> SDocContext initSDocContext dflags sty = SDC { sdocStyle = sty - , sdocLastColour = colReset + , sdocLastColour = Col.colReset , sdocDynFlags = dflags } @@ -438,7 +435,8 @@ printSDoc :: Mode -> DynFlags -> Handle -> PprStyle -> SDoc -> IO () printSDoc mode dflags handle sty doc = Pretty.printDoc_ mode cols handle (runSDoc doc ctx) `finally` - Pretty.printDoc_ mode cols handle (runSDoc (coloured colReset empty) ctx) + Pretty.printDoc_ mode cols handle + (runSDoc (coloured Col.colReset empty) ctx) where cols = pprCols dflags ctx = initSDocContext dflags sty @@ -721,81 +719,26 @@ ppWhen False _ = empty ppUnless True _ = empty ppUnless False doc = doc --- | A colour\/style for use with 'coloured'. -newtype PprColour = PprColour String - --- | Allow colours to be combined (e.g. bold + red); --- In case of conflict, right side takes precedence. -instance Monoid PprColour where - mempty = PprColour mempty - PprColour s1 `mappend` PprColour s2 = PprColour (s1 `mappend` s2) - --- Colours - -colReset :: PprColour -colReset = PprColour "\27[0m" - -colBold :: PprColour -colBold = PprColour "\27[;1m" - -colBlackFg :: PprColour -colBlackFg = PprColour "\27[30m" - -colRedFg :: PprColour -colRedFg = PprColour "\27[31m" - -colGreenFg :: PprColour -colGreenFg = PprColour "\27[32m" - -colYellowFg :: PprColour -colYellowFg = PprColour "\27[33m" - -colBlueFg :: PprColour -colBlueFg = PprColour "\27[34m" - -colMagentaFg :: PprColour -colMagentaFg = PprColour "\27[35m" - -colCyanFg :: PprColour -colCyanFg = PprColour "\27[36m" - -colWhiteFg :: PprColour -colWhiteFg = PprColour "\27[37m" - -colBinder :: PprColour -colBinder = colGreenFg - -colCoerc :: PprColour -colCoerc = colBlueFg - -colDataCon :: PprColour -colDataCon = colRedFg - -colType :: PprColour -colType = colBlueFg - -- | Apply the given colour\/style for the argument. -- -- Only takes effect if colours are enabled. -coloured :: PprColour -> SDoc -> SDoc -coloured col@(PprColour c) sdoc = +coloured :: Col.PprColour -> SDoc -> SDoc +coloured col@(Col.PprColour c) sdoc = sdocWithDynFlags $ \dflags -> - if overrideWith (canUseColor dflags) (useColor dflags) - then SDoc $ \ctx@SDC{ sdocLastColour = PprColour lc } -> + if shouldUseColor dflags + then SDoc $ \ctx@SDC{ sdocLastColour = Col.PprColour lc } -> case ctx of SDC{ sdocStyle = PprUser _ _ Coloured } -> let ctx' = ctx{ sdocLastColour = col } in - Pretty.zeroWidthText c + Pretty.zeroWidthText (cReset ++ c) Pretty.<> runSDoc sdoc ctx' - Pretty.<> Pretty.zeroWidthText lc + Pretty.<> Pretty.zeroWidthText (cReset ++ lc) _ -> runSDoc sdoc ctx else sdoc - -bold :: SDoc -> SDoc -bold = coloured colBold + where Col.PprColour cReset = Col.colReset keyword :: SDoc -> SDoc -keyword = bold +keyword = coloured Col.colBold {- ************************************************************************ diff --git a/compiler/utils/PprColour.hs b/compiler/utils/PprColour.hs new file mode 100644 index 0000000000..1b97303b93 --- /dev/null +++ b/compiler/utils/PprColour.hs @@ -0,0 +1,88 @@ +module PprColour where +import Data.Maybe (fromMaybe) +import Util (OverridingBool(..), split) + +-- | A colour\/style for use with 'coloured'. +newtype PprColour = PprColour String + +-- | Allow colours to be combined (e.g. bold + red); +-- In case of conflict, right side takes precedence. +instance Monoid PprColour where + mempty = PprColour mempty + PprColour s1 `mappend` PprColour s2 = PprColour (s1 `mappend` s2) + +colCustom :: String -> PprColour +colCustom s = PprColour ("\27[" ++ s ++ "m") + +colReset :: PprColour +colReset = colCustom "0" + +colBold :: PprColour +colBold = colCustom ";1" + +colBlackFg :: PprColour +colBlackFg = colCustom "30" + +colRedFg :: PprColour +colRedFg = colCustom "31" + +colGreenFg :: PprColour +colGreenFg = colCustom "32" + +colYellowFg :: PprColour +colYellowFg = colCustom "33" + +colBlueFg :: PprColour +colBlueFg = colCustom "34" + +colMagentaFg :: PprColour +colMagentaFg = colCustom "35" + +colCyanFg :: PprColour +colCyanFg = colCustom "36" + +colWhiteFg :: PprColour +colWhiteFg = colCustom "37" + +data Scheme = + Scheme + { sMessage :: PprColour + , sWarning :: PprColour + , sError :: PprColour + , sFatal :: PprColour + , sMargin :: PprColour + } + +defaultScheme :: Scheme +defaultScheme = + Scheme + { sMessage = colBold + , sWarning = colBold `mappend` colMagentaFg + , sError = colBold `mappend` colRedFg + , sFatal = colBold `mappend` colRedFg + , sMargin = colBold `mappend` colBlueFg + } + +-- | Parse the colour scheme from a string (presumably from the @GHC_COLORS@ +-- environment variable). +parseScheme :: String -> (OverridingBool, Scheme) -> (OverridingBool, Scheme) +parseScheme "always" (_, cs) = (Always, cs) +parseScheme "auto" (_, cs) = (Auto, cs) +parseScheme "never" (_, cs) = (Never, cs) +parseScheme input (b, cs) = + ( b + , Scheme + { sMessage = fromMaybe (sMessage cs) (lookup "message" table) + , sWarning = fromMaybe (sWarning cs) (lookup "warning" table) + , sError = fromMaybe (sError cs) (lookup "error" table) + , sFatal = fromMaybe (sFatal cs) (lookup "fatal" table) + , sMargin = fromMaybe (sMargin cs) (lookup "margin" table) + } + ) + where + table = do + w <- split ':' input + let (k, v') = break (== '=') w + case v' of + '=' : v -> return (k, colCustom v) + _ -> [] diff --git a/compiler/utils/Util.hs b/compiler/utils/Util.hs index 30026c5016..65445e410c 100644 --- a/compiler/utils/Util.hs +++ b/compiler/utils/Util.hs @@ -129,6 +129,10 @@ module Util ( HasCallStack, HasDebugCallStack, prettyCurrentCallStack, + + -- * Utils for flags + OverridingBool(..), + overrideWith, ) where #include "HsVersions.h" @@ -1358,3 +1362,14 @@ prettyCurrentCallStack = GHC.Stack.showCallStack ?callStack prettyCurrentCallStack :: HasCallStack => String prettyCurrentCallStack = "Call stack unavailable" #endif + +data OverridingBool + = Auto + | Always + | Never + deriving Show + +overrideWith :: Bool -> OverridingBool -> Bool +overrideWith b Auto = b +overrideWith _ Always = True +overrideWith _ Never = False |