@@ -1,4 +1,3 @@
1−{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE FlexibleInstances #-}
1{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE CPP #-}
3{-# LANGUAGE CPP #-}
@@ -15,7 +14,7 @@ module Graphics.Vty.Output.TerminfoBased
17import Control.Monad (when)
16import Control.Monad (when)
18−import Data.Bits (shiftL)
17+import Data.Bits (shiftL, (.&.))
19import qualified Data.ByteString as BS
18import qualified Data.ByteString as BS
20import Data.ByteString.Internal (toForeignPtr)
19import Data.ByteString.Internal (toForeignPtr)
21import Data.Terminfo.Parse
20import Data.Terminfo.Parse
@@ -26,9 +25,8 @@ import Graphics.Vty.Image (DisplayRegion)
26import Graphics.Vty.DisplayAttributes
25import Graphics.Vty.DisplayAttributes
27import Graphics.Vty.Output.Interface
26import Graphics.Vty.Output.Interface
29−import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable)
28+import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable, writeWord8)
31−import Data.Bits ((.&.))
32import Data.IORef
30import Data.IORef
33import Data.Maybe (isJust, isNothing, fromJust)
31import Data.Maybe (isJust, isNothing, fromJust)
34import Data.Word
32import Data.Word
@@ -51,7 +49,6 @@ data TerminfoCaps = TerminfoCaps
51 , cup :: CapExpression
49 , cup :: CapExpression
52 , cnorm :: Maybe CapExpression
50 , cnorm :: Maybe CapExpression
53 , civis :: Maybe CapExpression
51 , civis :: Maybe CapExpression
54− , supportsNoColors :: Bool
55 , useAltColorMap :: Bool
52 , useAltColorMap :: Bool
56 , setForeColor :: CapExpression
53 , setForeColor :: CapExpression
57 , setBackColor :: CapExpression
54 , setBackColor :: CapExpression
@@ -106,28 +103,28 @@ sendCapToTerminal t cap capParams = do
107-- * Providing independent string capabilities for all display
104-- * Providing independent string capabilities for all display
108-- attributes.
105-- attributes.
109−reserveTerminal :: String -> Fd -> IO Output
106+reserveTerminal :: String -> Fd -> ColorMode -> IO Output
110−reserveTerminal termName outFd = do
107+reserveTerminal termName outFd colorMode = do
111 ti <- Terminfo.setupTerm termName
108 ti <- Terminfo.setupTerm termName
112 -- assumes set foreground always implies set background exists.
109 -- assumes set foreground always implies set background exists.
113 -- if set foreground is not set then all color changing style
110 -- if set foreground is not set then all color changing style
114 -- attributes are filtered.
111 -- attributes are filtered.
115 msetaf <- probeCap ti "setaf"
112 msetaf <- probeCap ti "setaf"
116 msetf <- probeCap ti "setf"
113 msetf <- probeCap ti "setf"
117− let (noColors, useAlt, setForeCap)
114+ let (useAlt, setForeCap)
118 = case msetaf of
115 = case msetaf of
119− Just setaf -> (False, False, setaf)
116+ Just setaf -> (False, setaf)
120 Nothing -> case msetf of
117 Nothing -> case msetf of
121− Just setf -> (False, True, setf)
118+ Just setf -> (True, setf)
122− Nothing -> (True, True, error $ "no fore color support for terminal " ++ termName)
119+ Nothing -> (True, error $ "no fore color support for terminal " ++ termName)
123 msetab <- probeCap ti "setab"
120 msetab <- probeCap ti "setab"
124 msetb <- probeCap ti "setb"
121 msetb <- probeCap ti "setb"
125− let set_back_cap
122+ let setBackCap
126 = case msetab of
123 = case msetab of
127 Nothing -> case msetb of
125 Nothing -> case msetb of
128 Just setb -> setb
126 Just setb -> setb
129 Nothing -> error $ "no back color support for terminal " ++ termName
127 Nothing -> error $ "no back color support for terminal " ++ termName
132 hyperlinkModeStatus <- newIORef False
129 hyperlinkModeStatus <- newIORef False
133 newAssumedStateRef <- newIORef initialAssumedState
130 newAssumedStateRef <- newIORef initialAssumedState
@@ -153,10 +150,9 @@ reserveTerminal termName outFd = do
153 <*> requireCap ti "cup"
150 <*> requireCap ti "cup"
154 <*> probeCap ti "cnorm"
151 <*> probeCap ti "cnorm"
155 <*> probeCap ti "civis"
152 <*> probeCap ti "civis"
157 <*> pure useAlt
153 <*> pure useAlt
158 <*> pure setForeCap
154 <*> pure setForeCap
159− <*> pure set_back_cap
155+ <*> pure setBackCap
160 <*> requireCap ti "sgr0"
156 <*> requireCap ti "sgr0"
161 <*> requireCap ti "clear"
157 <*> requireCap ti "clear"
162 <*> requireCap ti "el"
158 <*> requireCap ti "el"
@@ -196,17 +192,12 @@ reserveTerminal termName outFd = do
196 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
192 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
197 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
193 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
198 ++ " Please report this bug to vty project."
194 ++ " Please report this bug to vty project."
200− = case supportsNoColors terminfoCaps of
201− False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
205 , supportsCursorVisibility = isJust $ civis terminfoCaps
195 , supportsCursorVisibility = isJust $ civis terminfoCaps
206 , supportsMode = terminfoModeSupported
196 , supportsMode = terminfoModeSupported
207 , setMode = terminfoSetMode
197 , setMode = terminfoSetMode
208 , getModeStatus = terminfoModeStatus
198 , getModeStatus = terminfoModeStatus
209 , assumedStateRef = newAssumedStateRef
199 , assumedStateRef = newAssumedStateRef
200+ , outputColorMode = colorMode
210 -- I think fix would help assure tActual is the only
201 -- I think fix would help assure tActual is the only
211 -- reference. I was having issues tho.
202 -- reference. I was having issues tho.
212 , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
203 , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
@@ -304,7 +295,7 @@ writeURLEscapes NoLinkChange =
304-- | Portably setting the display attributes is a giant pain in the ass.
295-- | Portably setting the display attributes is a giant pain in the ass.
306-- If the terminal supports the sgr capability (which sets the on/off
297-- If the terminal supports the sgr capability (which sets the on/off
307−-- state of each style directly ; and, for no good reason, resets the
298+-- state of each style directly; and, for no good reason, resets the
308-- colors to the default) this procedure is used:
299-- colors to the default) this procedure is used:
310-- 0. set the style attributes. This resets the fore and back color.
301-- 0. set the style attributes. This resets the fore and back color.
@@ -343,9 +334,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
343 -- The only way to reset either color, portably, to the default
334 -- The only way to reset either color, portably, to the default
344 -- is to use either the set state capability or the set default
335 -- is to use either the set state capability or the set default
345 -- capability.
336 -- capability.
346− True -> do
337+ True -> do
347 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
338 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
348− (fixedStyle attr )
339+ (fixedStyle attr)
349 (styleToApplySeq $ fixedStyle attr) of
340 (styleToApplySeq $ fixedStyle attr) of
350 -- only way to reset a color to the defaults
341 -- only way to reset a color to the defaults
351 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
342 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
@@ -355,8 +346,7 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
355 setColors
346 setColors
356 -- implicitly resets the colors to the defaults
347 -- implicitly resets the colors to the defaults
357 SetState state -> writeCapExpr (fromJust $ setAttrStates
348 SetState state -> writeCapExpr (fromJust $ setAttrStates
358− $ displayAttrCaps
349+ $ displayAttrCaps terminfoCaps
361 (sgrArgsForState state)
351 (sgrArgsForState state)
362 `mappend` setItalics
352 `mappend` setItalics
@@ -379,9 +369,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
379 -- applied states.
369 -- applied states.
380 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
370 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
381 `mappend`
371 `mappend`
382− writeColorDiff setForeColor (foreColorDiff diffs)
372+ writeColorDiff Foreground (foreColorDiff diffs)
383 `mappend`
373 `mappend`
384− writeColorDiff setBackColor (backColorDiff diffs)
374+ writeColorDiff Background (backColorDiff diffs)
385 -- implicitly resets the colors to the defaults
375 -- implicitly resets the colors to the defaults
386 SetState state -> writeCapExpr (fromJust $ setAttrStates
376 SetState state -> writeCapExpr (fromJust $ setAttrStates
387 $ displayAttrCaps terminfoCaps
377 $ displayAttrCaps terminfoCaps
@@ -413,29 +403,65 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
413 | otherwise = mempty
403 | otherwise = mempty
414 setColors =
404 setColors =
415 (case fixedForeColor attr of
405 (case fixedForeColor attr of
416− Just c -> writeCapExpr (setForeColor terminfoCaps)
406+ Just c -> writeColor Foreground c
417− [toEnum $ colorMap c]
418 Nothing -> mempty)
407 Nothing -> mempty)
419 `mappend`
408 `mappend`
420 (case fixedBackColor attr of
409 (case fixedBackColor attr of
421− Just c -> writeCapExpr (setBackColor terminfoCaps)
410+ Just c -> writeColor Background c
422− [toEnum $ colorMap c]
423 Nothing -> mempty)
411 Nothing -> mempty)
424− writeColorDiff _f NoColorChange
412+ writeColorDiff _side NoColorChange
426− writeColorDiff _f ColorToDefault
414+ writeColorDiff _side ColorToDefault
427 = error "ColorToDefault is not a possible case for applyColorDiffs"
415 = error "ColorToDefault is not a possible case for applyColorDiffs"
428− writeColorDiff f (SetColor c)
416+ writeColorDiff side (SetColor c)
419+ writeColor side (RGBColor r g b) =
420+ case outputColorMode (contextDevice dc) of
422+ hardcodeColor side (r, g, b)
424+ error "clampColor should remove rgb colors in standard mode"
429− = writeCapExpr (f terminfoCaps) [toEnum $ colorMap c]
426+ writeCapExpr (setSideColor side terminfoCaps) [toEnum $ colorMap c]
428+-- a color can either be in the foreground or the background
429+data ColorSide = Foreground | Background
431+-- get the capability for drawing a color on a specific side
432+setSideColor :: ColorSide -> TerminfoCaps -> CapExpression
433+setSideColor Foreground = setForeColor
434+setSideColor Background = setBackColor
436+hardcodeColor :: ColorSide -> (Word8, Word8, Word8) -> Write
437+hardcodeColor side (r, g, b) =
438+ -- hardcoded color codes are formatted as "\x1b[{side};2;{r};{g};{b}m"
439+ mconcat [ writeStr "\x1b[", sideCode, delimiter, writeChar '2', delimiter
440+ , writeColor r, delimiter, writeColor g, delimiter, writeColor b
443+ writeChar = writeWord8 . fromIntegral . fromEnum
444+ writeStr = mconcat . map writeChar
445+ writeColor = writeStr . show
446+ delimiter = writeChar ';'
447+ -- 38/48 are used to set whether we should write to the
448+ -- foreground/background. I really don't want to know why.
449+ sideCode = case side of
450+ Foreground -> writeStr "38"
451+ Background -> writeStr "48"
431-- | The color table used by a terminal is a 16 color set followed by a
453-- | The color table used by a terminal is a 16 color set followed by a
432-- 240 color set that might not be supported by the terminal.
454-- 240 color set that might not be supported by the terminal.
434−-- This takes a Color which clearly identifies which pallete to use and
456+-- This takes a Color which clearly identifies which palette to use and
435−-- computes the index into the full 256 color pallete.
457+-- computes the index into the full 256 color palette.
436ansiColorIndex :: Color -> Int
458ansiColorIndex :: Color -> Int
437ansiColorIndex (ISOColor v) = fromEnum v
459ansiColorIndex (ISOColor v) = fromEnum v
438ansiColorIndex (Color240 v) = 16 + fromEnum v
460ansiColorIndex (Color240 v) = 16 + fromEnum v
461+ansiColorIndex (RGBColor _ _ _) =
462+ error $ unlines [ "Attempted to create color index from rgb color."
463+ , "This is currently unsupported, and shouldn't ever happen"
440-- | For terminals without setaf/setab
466-- | For terminals without setaf/setab
@@ -452,6 +478,10 @@ altColorIndex (ISOColor 6) = 3
452altColorIndex (ISOColor 7) = 7
478altColorIndex (ISOColor 7) = 7
453altColorIndex (ISOColor v) = fromEnum v
479altColorIndex (ISOColor v) = fromEnum v
454altColorIndex (Color240 v) = 16 + fromEnum v
480altColorIndex (Color240 v) = 16 + fromEnum v
481+altColorIndex (RGBColor _ _ _) =
482+ error $ unlines [ "Attempted to create color index from rgb color."
483+ , "This is currently unsupported, and shouldn't ever happen"
456{- | The sequence of terminfo caps to apply a given style are determined
486{- | The sequence of terminfo caps to apply a given style are determined
457 - according to these rules.
487 - according to these rules.