@@ -1,3 +1,4 @@
1+{-# LANGUAGE RecordWildCards #-}
12{-# LANGUAGE FlexibleInstances #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE CPP #-}
@@ -9,12 +10,10 @@
910-- Copyright Corey O'Connor (coreyoconnor@gmail.com)
1011module Graphics.Vty.Output.TerminfoBased
1112 ( reserveTerminal
12− , setWindowSize
1313 )
1414where
1515
1616import Control.Monad (when)
17−import Data.Bits (shiftL, (.&.))
1817import qualified Data.ByteString as BS
1918import Data.ByteString.Internal (toForeignPtr)
2019import Data.Terminfo.Parse
@@ -25,8 +24,9 @@ import Graphics.Vty.Image (DisplayRegion)
2524import Graphics.Vty.DisplayAttributes
2625import Graphics.Vty.Output.Interface
2726
28−import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable, writeWord8)
27+import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable)
2928
29+import Data.Bits ((.&.))
3030import Data.IORef
3131import Data.Maybe (isJust, isNothing, fromJust)
3232import Data.Word
@@ -49,6 +49,7 @@ data TerminfoCaps = TerminfoCaps
4949 , cup :: CapExpression
5050 , cnorm :: Maybe CapExpression
5151 , civis :: Maybe CapExpression
52+ , supportsNoColors :: Bool
5253 , useAltColorMap :: Bool
5354 , setForeColor :: CapExpression
5455 , setBackColor :: CapExpression
@@ -65,8 +66,6 @@ data DisplayAttrCaps = DisplayAttrCaps
6566 , exitStandout :: Maybe CapExpression
6667 , enterItalic :: Maybe CapExpression
6768 , exitItalic :: Maybe CapExpression
68− , enterStrikethrough :: Maybe CapExpression
69− , exitStrikethrough :: Maybe CapExpression
7069 , enterUnderline :: Maybe CapExpression
7170 , exitUnderline :: Maybe CapExpression
7271 , enterReverseVideo :: Maybe CapExpression
@@ -103,28 +102,28 @@ sendCapToTerminal t cap capParams = do
103102--
104103-- * Providing independent string capabilities for all display
105104-- attributes.
106−reserveTerminal :: String -> Fd -> ColorMode -> IO Output
107−reserveTerminal termName outFd colorMode = do
105+reserveTerminal :: String -> Fd -> IO Output
106+reserveTerminal termName outFd = do
108107 ti <- Terminfo.setupTerm termName
109108 -- assumes set foreground always implies set background exists.
110109 -- if set foreground is not set then all color changing style
111110 -- attributes are filtered.
112111 msetaf <- probeCap ti "setaf"
113112 msetf <- probeCap ti "setf"
114− let (useAlt, setForeCap)
113+ let (noColors, useAlt, setForeCap)
115114 = case msetaf of
116− Just setaf -> (False, setaf)
115+ Just setaf -> (False, False, setaf)
117116 Nothing -> case msetf of
118− Just setf -> (True, setf)
119− Nothing -> (True, error $ "no fore color support for terminal " ++ termName)
117+ Just setf -> (False, True, setf)
118+ Nothing -> (True, True, error $ "no fore color support for terminal " ++ termName)
120119 msetab <- probeCap ti "setab"
121120 msetb <- probeCap ti "setb"
122− let setBackCap
121+ let set_back_cap
123122 = case msetab of
124− Just setab -> setab
125123 Nothing -> case msetb of
126124 Just setb -> setb
127125 Nothing -> error $ "no back color support for terminal " ++ termName
126+ Just setab -> setab
128127
129128 hyperlinkModeStatus <- newIORef False
130129 newAssumedStateRef <- newIORef initialAssumedState
@@ -150,9 +149,10 @@ reserveTerminal termName outFd colorMode = do
150149 <*> requireCap ti "cup"
151150 <*> probeCap ti "cnorm"
152151 <*> probeCap ti "civis"
152+ <*> pure noColors
153153 <*> pure useAlt
154154 <*> pure setForeCap
155− <*> pure setBackCap
155+ <*> pure set_back_cap
156156 <*> requireCap ti "sgr0"
157157 <*> requireCap ti "clear"
158158 <*> requireCap ti "el"
@@ -164,10 +164,6 @@ reserveTerminal termName outFd colorMode = do
164164 sendCap setDefaultAttr []
165165 maybeSendCap cnorm []
166166 , 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))
171167 , ringTerminalBell = maybeSendCap ringBellAudio []
172168 , reserveDisplay = do
173169 -- If there is no support for smcup: Clear the screen
@@ -178,8 +174,6 @@ reserveTerminal termName outFd colorMode = do
178174 , releaseDisplay = do
179175 maybeSendCap rmcup []
180176 maybeSendCap cnorm []
181− , setDisplayBounds = \(w, h) ->
182− setWindowSize outFd (w, h)
183177 , displayBounds = do
184178 rawSize <- getWindowSize outFd
185179 case rawSize of
@@ -192,15 +186,20 @@ reserveTerminal termName outFd colorMode = do
192186 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
193187 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
194188 ++ " Please report this bug to vty project."
189+ , contextColorCount
190+ = case supportsNoColors terminfoCaps of
191+ False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
192+ Nothing -> 8
193+ Just v -> toEnum v
194+ True -> 1
195195 , supportsCursorVisibility = isJust $ civis terminfoCaps
196196 , supportsMode = terminfoModeSupported
197197 , setMode = terminfoSetMode
198198 , getModeStatus = terminfoModeStatus
199199 , assumedStateRef = newAssumedStateRef
200− , outputColorMode = colorMode
201200 -- I think fix would help assure tActual is the only
202201 -- reference. I was having issues tho.
203− , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
202+ , mkDisplayContext = \tActual -> terminfoDisplayContext tActual terminfoCaps
204203 }
205204 sendCap s = sendCapToTerminal t (s terminfoCaps)
206205 maybeSendCap s = when (isJust $ s terminfoCaps) . sendCap (fromJust . s)
@@ -232,8 +231,6 @@ currentDisplayAttrCaps ti
232231 <*> probeCap ti "rmso"
233232 <*> probeCap ti "sitm"
234233 <*> probeCap ti "ritm"
235− <*> probeCap ti "smxx"
236− <*> probeCap ti "rmxx"
237234 <*> probeCap ti "smul"
238235 <*> probeCap ti "rmul"
239236 <*> probeCap ti "rev"
@@ -247,13 +244,6 @@ getWindowSize fd = do
247244 (a,b) <- (`divMod` 65536) `fmap` c_getWindowSize fd
248245 return (fromIntegral b, fromIntegral a)
249246
250−foreign import ccall "gwinsz.h vty_c_set_window_size" c_setWindowSize :: Fd -> CLong -> IO ()
251−
252−setWindowSize :: Fd -> (Int, Int) -> IO ()
253−setWindowSize fd (w, h) = do
254− let val = (h `shiftL` 16) + w
255− c_setWindowSize fd $ fromIntegral val
256−
257247terminfoDisplayContext :: Output -> TerminfoCaps -> DisplayRegion -> IO DisplayContext
258248terminfoDisplayContext tActual terminfoCaps r = return dc
259249 where dc = DisplayContext
@@ -269,11 +259,7 @@ terminfoDisplayContext tActual terminfoCaps r = return dc
269259 , writeSetAttr = terminfoWriteSetAttr dc terminfoCaps
270260 , writeDefaultAttr = \urlsEnabled ->
271261 writeCapExpr (setDefaultAttr terminfoCaps) [] `mappend`
272− (if urlsEnabled then writeURLEscapes EndLink else mempty) `mappend`
273− (case exitStrikethrough $ displayAttrCaps terminfoCaps of
274− Just cap -> writeCapExpr cap []
275− Nothing -> mempty
276− )
262+ (if urlsEnabled then writeURLEscapes EndLink else mempty)
277263 , writeRowEnd = writeCapExpr (clearEol terminfoCaps) []
278264 , inlineHack = return ()
279265 }
@@ -295,7 +281,7 @@ writeURLEscapes NoLinkChange =
295281-- | Portably setting the display attributes is a giant pain in the ass.
296282--
297283-- 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
284+-- state of each style directly ; and, for no good reason, resets the
299285-- colors to the default) this procedure is used:
300286--
301287-- 0. set the style attributes. This resets the fore and back color.
@@ -334,9 +320,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
334320 -- The only way to reset either color, portably, to the default
335321 -- is to use either the set state capability or the set default
336322 -- capability.
337− True -> do
323+ True -> do
338324 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
339− (fixedStyle attr)
325+ (fixedStyle attr )
340326 (styleToApplySeq $ fixedStyle attr) of
341327 -- only way to reset a color to the defaults
342328 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
@@ -346,11 +332,11 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
346332 setColors
347333 -- implicitly resets the colors to the defaults
348334 SetState state -> writeCapExpr (fromJust $ setAttrStates
349− $ displayAttrCaps terminfoCaps
335+ $ displayAttrCaps
336+ $ terminfoCaps
350337 )
351338 (sgrArgsForState state)
352339 `mappend` setItalics
353− `mappend` setStrikethrough
354340 `mappend` setColors
355341 -- Otherwise the display colors are not changing or changing
356342 -- between two non-default points.
@@ -369,16 +355,15 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
369355 -- applied states.
370356 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
371357 `mappend`
372− writeColorDiff Foreground (foreColorDiff diffs)
358+ writeColorDiff setForeColor (foreColorDiff diffs)
373359 `mappend`
374− writeColorDiff Background (backColorDiff diffs)
360+ writeColorDiff setBackColor (backColorDiff diffs)
375361 -- implicitly resets the colors to the defaults
376362 SetState state -> writeCapExpr (fromJust $ setAttrStates
377363 $ displayAttrCaps terminfoCaps
378364 )
379365 (sgrArgsForState state)
380366 `mappend` setItalics
381− `mappend` setStrikethrough
382367 `mappend` setColors
383368 where
384369 urlAttrs True = writeURLEscapes (urlDiff diffs)
@@ -396,72 +381,31 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
396381 , Just sitm <- enterItalic (displayAttrCaps terminfoCaps)
397382 = writeCapExpr sitm []
398383 | otherwise = mempty
399− setStrikethrough
400− | hasStyle (fixedStyle attr) strikethrough
401− , Just smxx <- enterStrikethrough (displayAttrCaps terminfoCaps)
402− = writeCapExpr smxx []
403− | otherwise = mempty
404384 setColors =
405385 (case fixedForeColor attr of
406− Just c -> writeColor Foreground c
386+ Just c -> writeCapExpr (setForeColor terminfoCaps)
387+ [toEnum $ colorMap c]
407388 Nothing -> mempty)
408389 `mappend`
409390 (case fixedBackColor attr of
410− Just c -> writeColor Background c
391+ Just c -> writeCapExpr (setBackColor terminfoCaps)
392+ [toEnum $ colorMap c]
411393 Nothing -> mempty)
412− writeColorDiff _side NoColorChange
394+ writeColorDiff _f NoColorChange
413395 = mempty
414− writeColorDiff _side ColorToDefault
396+ writeColorDiff _f ColorToDefault
415397 = error "ColorToDefault is not a possible case for applyColorDiffs"
416− writeColorDiff side (SetColor c)
417− = writeColor side c
418−
419− writeColor side (RGBColor r g b) =
420− case outputColorMode (contextDevice dc) of
421− FullColor ->
422− hardcodeColor side (r, g, b)
423− _ ->
424− error "clampColor should remove rgb colors in standard mode"
425− writeColor side c =
426− writeCapExpr (setSideColor side terminfoCaps) [toEnum $ colorMap c]
427−
428−-- a color can either be in the foreground or the background
429−data ColorSide = Foreground | Background
430−
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
435−
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
441− , writeChar 'm']
442− where
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"
398+ writeColorDiff f (SetColor c)
399+ = writeCapExpr (f terminfoCaps) [toEnum $ colorMap c]
452400
453401-- | The color table used by a terminal is a 16 color set followed by a
454402-- 240 color set that might not be supported by the terminal.
455403--
456−-- This takes a Color which clearly identifies which palette to use and
457−-- computes the index into the full 256 color palette.
404+-- This takes a Color which clearly identifies which pallete to use and
405+-- computes the index into the full 256 color pallete.
458406ansiColorIndex :: Color -> Int
459407ansiColorIndex (ISOColor v) = fromEnum v
460408ansiColorIndex (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"
464− ]
465409
466410-- | For terminals without setaf/setab
467411--
@@ -478,10 +422,6 @@ altColorIndex (ISOColor 6) = 3
478422altColorIndex (ISOColor 7) = 7
479423altColorIndex (ISOColor v) = fromEnum v
480424altColorIndex (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"
484− ]
485425
486426{- | The sequence of terminfo caps to apply a given style are determined
487427 - according to these rules.
@@ -509,7 +449,6 @@ data DisplayAttrState = DisplayAttrState
509449 { applyStandout :: Bool
510450 , applyUnderline :: Bool
511451 , applyItalic :: Bool
512− , applyStrikethrough :: Bool
513452 , applyReverseVideo :: Bool
514453 , applyBlink :: Bool
515454 , applyDim :: Bool
@@ -546,8 +485,6 @@ reqDisplayCapSeqFor caps s diffs
546485 -- set state cap then just use the set state cap.
547486 ( True, True ) -> SetState $ stateForStyle s
548487 where
549− noEnterExitCap ApplyStrikethrough = isNothing $ enterStrikethrough caps
550− noEnterExitCap RemoveStrikethrough = isNothing $ exitStrikethrough caps
551488 noEnterExitCap ApplyItalic = isNothing $ enterItalic caps
552489 noEnterExitCap RemoveItalic = isNothing $ exitItalic caps
553490 noEnterExitCap ApplyStandout = isNothing $ enterStandout caps
@@ -562,8 +499,6 @@ reqDisplayCapSeqFor caps s diffs
562499 noEnterExitCap RemoveDim = True
563500 noEnterExitCap ApplyBold = isNothing $ enterBoldMode caps
564501 noEnterExitCap RemoveBold = True
565− enterExitCap ApplyStrikethrough = fromJust $ enterStrikethrough caps
566− enterExitCap RemoveStrikethrough = fromJust $ exitStrikethrough caps
567502 enterExitCap ApplyItalic = fromJust $ enterItalic caps
568503 enterExitCap RemoveItalic = fromJust $ exitItalic caps
569504 enterExitCap ApplyStandout = fromJust $ enterStandout caps
@@ -580,7 +515,6 @@ stateForStyle s = DisplayAttrState
580515 { applyStandout = isStyleSet standout
581516 , applyUnderline = isStyleSet underline
582517 , applyItalic = isStyleSet italic
583− , applyStrikethrough = isStyleSet strikethrough
584518 , applyReverseVideo = isStyleSet reverseVideo
585519 , applyBlink = isStyleSet blink
586520 , applyDim = isStyleSet dim
@@ -593,7 +527,6 @@ styleToApplySeq s = concat
593527 [ applyIfRequired ApplyStandout standout
594528 , applyIfRequired ApplyUnderline underline
595529 , applyIfRequired ApplyItalic italic
596− , applyIfRequired ApplyStrikethrough strikethrough
597530 , applyIfRequired ApplyReverseVideo reverseVideo
598531 , applyIfRequired ApplyBlink blink
599532 , applyIfRequired ApplyDim dim