@@ -1,3 +1,4 @@
1+{-# LANGUAGE RecordWildCards #-}
1{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE CPP #-}
4{-# LANGUAGE CPP #-}
@@ -14,7 +15,7 @@ module Graphics.Vty.Output.TerminfoBased
16import Control.Monad (when)
17import Control.Monad (when)
17−import Data.Bits (shiftL, (.&.))
18+import Data.Bits (shiftL)
18import qualified Data.ByteString as BS
19import qualified Data.ByteString as BS
19import Data.ByteString.Internal (toForeignPtr)
20import Data.ByteString.Internal (toForeignPtr)
20import Data.Terminfo.Parse
21import Data.Terminfo.Parse
@@ -25,8 +26,9 @@ import Graphics.Vty.Image (DisplayRegion)
25import Graphics.Vty.DisplayAttributes
26import Graphics.Vty.DisplayAttributes
26import Graphics.Vty.Output.Interface
27import Graphics.Vty.Output.Interface
28−import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable, writeWord8)
29+import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable)
31+import Data.Bits ((.&.))
30import Data.IORef
32import Data.IORef
31import Data.Maybe (isJust, isNothing, fromJust)
33import Data.Maybe (isJust, isNothing, fromJust)
32import Data.Word
34import Data.Word
@@ -49,6 +51,7 @@ data TerminfoCaps = TerminfoCaps
49 , cup :: CapExpression
51 , cup :: CapExpression
50 , cnorm :: Maybe CapExpression
52 , cnorm :: Maybe CapExpression
51 , civis :: Maybe CapExpression
53 , civis :: Maybe CapExpression
54+ , supportsNoColors :: Bool
52 , useAltColorMap :: Bool
55 , useAltColorMap :: Bool
53 , setForeColor :: CapExpression
56 , setForeColor :: CapExpression
54 , setBackColor :: CapExpression
57 , setBackColor :: CapExpression
@@ -65,8 +68,6 @@ data DisplayAttrCaps = DisplayAttrCaps
65 , exitStandout :: Maybe CapExpression
68 , exitStandout :: Maybe CapExpression
66 , enterItalic :: Maybe CapExpression
69 , enterItalic :: Maybe CapExpression
67 , exitItalic :: Maybe CapExpression
70 , exitItalic :: Maybe CapExpression
68− , enterStrikethrough :: Maybe CapExpression
69− , exitStrikethrough :: Maybe CapExpression
70 , enterUnderline :: Maybe CapExpression
71 , enterUnderline :: Maybe CapExpression
71 , exitUnderline :: Maybe CapExpression
72 , exitUnderline :: Maybe CapExpression
72 , enterReverseVideo :: Maybe CapExpression
73 , enterReverseVideo :: Maybe CapExpression
@@ -103,28 +104,28 @@ sendCapToTerminal t cap capParams = do
104-- * Providing independent string capabilities for all display
105-- * Providing independent string capabilities for all display
105-- attributes.
106-- attributes.
106−reserveTerminal :: String -> Fd -> ColorMode -> IO Output
107+reserveTerminal :: String -> Fd -> IO Output
107−reserveTerminal termName outFd colorMode = do
108+reserveTerminal termName outFd = do
108 ti <- Terminfo.setupTerm termName
109 ti <- Terminfo.setupTerm termName
109 -- assumes set foreground always implies set background exists.
110 -- assumes set foreground always implies set background exists.
110 -- if set foreground is not set then all color changing style
111 -- if set foreground is not set then all color changing style
111 -- attributes are filtered.
112 -- attributes are filtered.
112 msetaf <- probeCap ti "setaf"
113 msetaf <- probeCap ti "setaf"
113 msetf <- probeCap ti "setf"
114 msetf <- probeCap ti "setf"
114− let (useAlt, setForeCap)
115+ let (noColors, useAlt, setForeCap)
115 = case msetaf of
116 = case msetaf of
116− Just setaf -> (False, setaf)
117+ Just setaf -> (False, False, setaf)
117 Nothing -> case msetf of
118 Nothing -> case msetf of
118− Just setf -> (True, setf)
119+ Just setf -> (False, True, setf)
119− Nothing -> (True, error $ "no fore color support for terminal " ++ termName)
120+ Nothing -> (True, True, error $ "no fore color support for terminal " ++ termName)
120 msetab <- probeCap ti "setab"
121 msetab <- probeCap ti "setab"
121 msetb <- probeCap ti "setb"
122 msetb <- probeCap ti "setb"
122− let setBackCap
123+ let set_back_cap
123 = case msetab of
124 = case msetab of
125 Nothing -> case msetb of
125 Nothing -> case msetb of
126 Just setb -> setb
126 Just setb -> setb
127 Nothing -> error $ "no back color support for terminal " ++ termName
127 Nothing -> error $ "no back color support for terminal " ++ termName
129 hyperlinkModeStatus <- newIORef False
130 hyperlinkModeStatus <- newIORef False
130 newAssumedStateRef <- newIORef initialAssumedState
131 newAssumedStateRef <- newIORef initialAssumedState
@@ -150,9 +151,10 @@ reserveTerminal termName outFd colorMode = do
150 <*> requireCap ti "cup"
151 <*> requireCap ti "cup"
151 <*> probeCap ti "cnorm"
152 <*> probeCap ti "cnorm"
152 <*> probeCap ti "civis"
153 <*> probeCap ti "civis"
153 <*> pure useAlt
155 <*> pure useAlt
154 <*> pure setForeCap
156 <*> pure setForeCap
155− <*> pure setBackCap
157+ <*> pure set_back_cap
156 <*> requireCap ti "sgr0"
158 <*> requireCap ti "sgr0"
157 <*> requireCap ti "clear"
159 <*> requireCap ti "clear"
158 <*> requireCap ti "el"
160 <*> requireCap ti "el"
@@ -164,10 +166,6 @@ reserveTerminal termName outFd colorMode = do
164 sendCap setDefaultAttr []
166 sendCap setDefaultAttr []
165 maybeSendCap cnorm []
167 maybeSendCap cnorm []
166 , supportsBell = return $ isJust $ ringBellAudio terminfoCaps
168 , supportsBell = return $ isJust $ ringBellAudio terminfoCaps
167− , supportsItalics = return $ (isJust $ enterItalic (displayAttrCaps terminfoCaps)) &&
168− (isJust $ exitItalic (displayAttrCaps terminfoCaps))
169− , supportsStrikethrough = return $ (isJust $ enterStrikethrough (displayAttrCaps terminfoCaps)) &&
170− (isJust $ exitStrikethrough (displayAttrCaps terminfoCaps))
171 , ringTerminalBell = maybeSendCap ringBellAudio []
169 , ringTerminalBell = maybeSendCap ringBellAudio []
172 , reserveDisplay = do
170 , reserveDisplay = do
173 -- If there is no support for smcup: Clear the screen
171 -- If there is no support for smcup: Clear the screen
@@ -192,15 +190,20 @@ reserveTerminal termName outFd colorMode = do
192 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
190 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
193 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
191 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
194 ++ " Please report this bug to vty project."
192 ++ " Please report this bug to vty project."
194+ = case supportsNoColors terminfoCaps of
195+ False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
195 , supportsCursorVisibility = isJust $ civis terminfoCaps
199 , supportsCursorVisibility = isJust $ civis terminfoCaps
196 , supportsMode = terminfoModeSupported
200 , supportsMode = terminfoModeSupported
197 , setMode = terminfoSetMode
201 , setMode = terminfoSetMode
198 , getModeStatus = terminfoModeStatus
202 , getModeStatus = terminfoModeStatus
199 , assumedStateRef = newAssumedStateRef
203 , assumedStateRef = newAssumedStateRef
200− , outputColorMode = colorMode
201 -- I think fix would help assure tActual is the only
204 -- I think fix would help assure tActual is the only
202 -- reference. I was having issues tho.
205 -- reference. I was having issues tho.
203− , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
206+ , mkDisplayContext = \tActual -> terminfoDisplayContext tActual terminfoCaps
205 sendCap s = sendCapToTerminal t (s terminfoCaps)
208 sendCap s = sendCapToTerminal t (s terminfoCaps)
206 maybeSendCap s = when (isJust $ s terminfoCaps) . sendCap (fromJust . s)
209 maybeSendCap s = when (isJust $ s terminfoCaps) . sendCap (fromJust . s)
@@ -232,8 +235,6 @@ currentDisplayAttrCaps ti
232 <*> probeCap ti "rmso"
235 <*> probeCap ti "rmso"
233 <*> probeCap ti "sitm"
236 <*> probeCap ti "sitm"
234 <*> probeCap ti "ritm"
237 <*> probeCap ti "ritm"
235− <*> probeCap ti "smxx"
236− <*> probeCap ti "rmxx"
237 <*> probeCap ti "smul"
238 <*> probeCap ti "smul"
238 <*> probeCap ti "rmul"
239 <*> probeCap ti "rmul"
239 <*> probeCap ti "rev"
240 <*> probeCap ti "rev"
@@ -269,11 +270,7 @@ terminfoDisplayContext tActual terminfoCaps r = return dc
269 , writeSetAttr = terminfoWriteSetAttr dc terminfoCaps
270 , writeSetAttr = terminfoWriteSetAttr dc terminfoCaps
270 , writeDefaultAttr = \urlsEnabled ->
271 , writeDefaultAttr = \urlsEnabled ->
271 writeCapExpr (setDefaultAttr terminfoCaps) [] `mappend`
272 writeCapExpr (setDefaultAttr terminfoCaps) [] `mappend`
272− (if urlsEnabled then writeURLEscapes EndLink else mempty) `mappend`
273+ (if urlsEnabled then writeURLEscapes EndLink else mempty)
273− (case exitStrikethrough $ displayAttrCaps terminfoCaps of
274− Just cap -> writeCapExpr cap []
277 , writeRowEnd = writeCapExpr (clearEol terminfoCaps) []
274 , writeRowEnd = writeCapExpr (clearEol terminfoCaps) []
278 , inlineHack = return ()
275 , inlineHack = return ()
@@ -295,7 +292,7 @@ writeURLEscapes NoLinkChange =
295-- | Portably setting the display attributes is a giant pain in the ass.
292-- | Portably setting the display attributes is a giant pain in the ass.
297-- If the terminal supports the sgr capability (which sets the on/off
294-- If the terminal supports the sgr capability (which sets the on/off
298−-- state of each style directly; and, for no good reason, resets the
295+-- state of each style directly ; and, for no good reason, resets the
299-- colors to the default) this procedure is used:
296-- colors to the default) this procedure is used:
301-- 0. set the style attributes. This resets the fore and back color.
298-- 0. set the style attributes. This resets the fore and back color.
@@ -334,9 +331,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
334 -- The only way to reset either color, portably, to the default
331 -- The only way to reset either color, portably, to the default
335 -- is to use either the set state capability or the set default
332 -- is to use either the set state capability or the set default
336 -- capability.
333 -- capability.
337− True -> do
334+ True -> do
338 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
335 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
339− (fixedStyle attr)
336+ (fixedStyle attr )
340 (styleToApplySeq $ fixedStyle attr) of
337 (styleToApplySeq $ fixedStyle attr) of
341 -- only way to reset a color to the defaults
338 -- only way to reset a color to the defaults
342 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
339 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
@@ -346,11 +343,11 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
346 setColors
343 setColors
347 -- implicitly resets the colors to the defaults
344 -- implicitly resets the colors to the defaults
348 SetState state -> writeCapExpr (fromJust $ setAttrStates
345 SetState state -> writeCapExpr (fromJust $ setAttrStates
349− $ displayAttrCaps terminfoCaps
346+ $ displayAttrCaps
351 (sgrArgsForState state)
349 (sgrArgsForState state)
352 `mappend` setItalics
350 `mappend` setItalics
353− `mappend` setStrikethrough
354 `mappend` setColors
351 `mappend` setColors
355 -- Otherwise the display colors are not changing or changing
352 -- Otherwise the display colors are not changing or changing
356 -- between two non-default points.
353 -- between two non-default points.
@@ -369,16 +366,15 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
369 -- applied states.
366 -- applied states.
370 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
367 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
371 `mappend`
368 `mappend`
372− writeColorDiff Foreground (foreColorDiff diffs)
369+ writeColorDiff setForeColor (foreColorDiff diffs)
373 `mappend`
370 `mappend`
374− writeColorDiff Background (backColorDiff diffs)
371+ writeColorDiff setBackColor (backColorDiff diffs)
375 -- implicitly resets the colors to the defaults
372 -- implicitly resets the colors to the defaults
376 SetState state -> writeCapExpr (fromJust $ setAttrStates
373 SetState state -> writeCapExpr (fromJust $ setAttrStates
377 $ displayAttrCaps terminfoCaps
374 $ displayAttrCaps terminfoCaps
379 (sgrArgsForState state)
376 (sgrArgsForState state)
380 `mappend` setItalics
377 `mappend` setItalics
381− `mappend` setStrikethrough
382 `mappend` setColors
378 `mappend` setColors
384 urlAttrs True = writeURLEscapes (urlDiff diffs)
380 urlAttrs True = writeURLEscapes (urlDiff diffs)
@@ -396,72 +392,31 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
396 , Just sitm <- enterItalic (displayAttrCaps terminfoCaps)
392 , Just sitm <- enterItalic (displayAttrCaps terminfoCaps)
397 = writeCapExpr sitm []
393 = writeCapExpr sitm []
398 | otherwise = mempty
394 | otherwise = mempty
400− | hasStyle (fixedStyle attr) strikethrough
401− , Just smxx <- enterStrikethrough (displayAttrCaps terminfoCaps)
402− = writeCapExpr smxx []
403− | otherwise = mempty
404 setColors =
395 setColors =
405 (case fixedForeColor attr of
396 (case fixedForeColor attr of
406− Just c -> writeColor Foreground c
397+ Just c -> writeCapExpr (setForeColor terminfoCaps)
398+ [toEnum $ colorMap c]
407 Nothing -> mempty)
399 Nothing -> mempty)
408 `mappend`
400 `mappend`
409 (case fixedBackColor attr of
401 (case fixedBackColor attr of
410− Just c -> writeColor Background c
402+ Just c -> writeCapExpr (setBackColor terminfoCaps)
403+ [toEnum $ colorMap c]
411 Nothing -> mempty)
404 Nothing -> mempty)
412− writeColorDiff _side NoColorChange
405+ writeColorDiff _f NoColorChange
414− writeColorDiff _side ColorToDefault
407+ writeColorDiff _f ColorToDefault
415 = error "ColorToDefault is not a possible case for applyColorDiffs"
408 = error "ColorToDefault is not a possible case for applyColorDiffs"
416− writeColorDiff side (SetColor c)
409+ writeColorDiff f (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"
426− writeCapExpr (setSideColor side terminfoCaps) [toEnum $ colorMap c]
410+ = writeCapExpr (f 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"
453-- | The color table used by a terminal is a 16 color set followed by a
412-- | The color table used by a terminal is a 16 color set followed by a
454-- 240 color set that might not be supported by the terminal.
413-- 240 color set that might not be supported by the terminal.
456−-- This takes a Color which clearly identifies which palette to use and
415+-- This takes a Color which clearly identifies which pallete to use and
457−-- computes the index into the full 256 color palette.
416+-- computes the index into the full 256 color pallete.
458ansiColorIndex :: Color -> Int
417ansiColorIndex :: Color -> Int
459ansiColorIndex (ISOColor v) = fromEnum v
418ansiColorIndex (ISOColor v) = fromEnum v
460ansiColorIndex (Color240 v) = 16 + fromEnum v
419ansiColorIndex (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"
466-- | For terminals without setaf/setab
421-- | For terminals without setaf/setab
@@ -478,10 +433,6 @@ altColorIndex (ISOColor 6) = 3
478altColorIndex (ISOColor 7) = 7
433altColorIndex (ISOColor 7) = 7
479altColorIndex (ISOColor v) = fromEnum v
434altColorIndex (ISOColor v) = fromEnum v
480altColorIndex (Color240 v) = 16 + fromEnum v
435altColorIndex (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"
486{- | The sequence of terminfo caps to apply a given style are determined
437{- | The sequence of terminfo caps to apply a given style are determined
487 - according to these rules.
438 - according to these rules.
@@ -509,7 +460,6 @@ data DisplayAttrState = DisplayAttrState
509 { applyStandout :: Bool
460 { applyStandout :: Bool
510 , applyUnderline :: Bool
461 , applyUnderline :: Bool
511 , applyItalic :: Bool
462 , applyItalic :: Bool
512− , applyStrikethrough :: Bool
513 , applyReverseVideo :: Bool
463 , applyReverseVideo :: Bool
514 , applyBlink :: Bool
464 , applyBlink :: Bool
515 , applyDim :: Bool
465 , applyDim :: Bool
@@ -546,8 +496,6 @@ reqDisplayCapSeqFor caps s diffs
546 -- set state cap then just use the set state cap.
496 -- set state cap then just use the set state cap.
547 ( True, True ) -> SetState $ stateForStyle s
497 ( True, True ) -> SetState $ stateForStyle s
549− noEnterExitCap ApplyStrikethrough = isNothing $ enterStrikethrough caps
550− noEnterExitCap RemoveStrikethrough = isNothing $ exitStrikethrough caps
551 noEnterExitCap ApplyItalic = isNothing $ enterItalic caps
499 noEnterExitCap ApplyItalic = isNothing $ enterItalic caps
552 noEnterExitCap RemoveItalic = isNothing $ exitItalic caps
500 noEnterExitCap RemoveItalic = isNothing $ exitItalic caps
553 noEnterExitCap ApplyStandout = isNothing $ enterStandout caps
501 noEnterExitCap ApplyStandout = isNothing $ enterStandout caps
@@ -562,8 +510,6 @@ reqDisplayCapSeqFor caps s diffs
562 noEnterExitCap RemoveDim = True
510 noEnterExitCap RemoveDim = True
563 noEnterExitCap ApplyBold = isNothing $ enterBoldMode caps
511 noEnterExitCap ApplyBold = isNothing $ enterBoldMode caps
564 noEnterExitCap RemoveBold = True
512 noEnterExitCap RemoveBold = True
565− enterExitCap ApplyStrikethrough = fromJust $ enterStrikethrough caps
566− enterExitCap RemoveStrikethrough = fromJust $ exitStrikethrough caps
567 enterExitCap ApplyItalic = fromJust $ enterItalic caps
513 enterExitCap ApplyItalic = fromJust $ enterItalic caps
568 enterExitCap RemoveItalic = fromJust $ exitItalic caps
514 enterExitCap RemoveItalic = fromJust $ exitItalic caps
569 enterExitCap ApplyStandout = fromJust $ enterStandout caps
515 enterExitCap ApplyStandout = fromJust $ enterStandout caps
@@ -580,7 +526,6 @@ stateForStyle s = DisplayAttrState
580 { applyStandout = isStyleSet standout
526 { applyStandout = isStyleSet standout
581 , applyUnderline = isStyleSet underline
527 , applyUnderline = isStyleSet underline
582 , applyItalic = isStyleSet italic
528 , applyItalic = isStyleSet italic
583− , applyStrikethrough = isStyleSet strikethrough
584 , applyReverseVideo = isStyleSet reverseVideo
529 , applyReverseVideo = isStyleSet reverseVideo
585 , applyBlink = isStyleSet blink
530 , applyBlink = isStyleSet blink
586 , applyDim = isStyleSet dim
531 , applyDim = isStyleSet dim
@@ -593,7 +538,6 @@ styleToApplySeq s = concat
593 [ applyIfRequired ApplyStandout standout
538 [ applyIfRequired ApplyStandout standout
594 , applyIfRequired ApplyUnderline underline
539 , applyIfRequired ApplyUnderline underline
595 , applyIfRequired ApplyItalic italic
540 , applyIfRequired ApplyItalic italic
596− , applyIfRequired ApplyStrikethrough strikethrough
597 , applyIfRequired ApplyReverseVideo reverseVideo
541 , applyIfRequired ApplyReverseVideo reverseVideo
598 , applyIfRequired ApplyBlink blink
542 , applyIfRequired ApplyBlink blink
599 , applyIfRequired ApplyDim dim
543 , applyIfRequired ApplyDim dim