@@ -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 #-}
@@ -10,10 +9,12 @@
10-- Copyright Corey O'Connor (coreyoconnor@gmail.com)
9-- Copyright Corey O'Connor (coreyoconnor@gmail.com)
11module Graphics.Vty.Output.TerminfoBased
10module Graphics.Vty.Output.TerminfoBased
12 ( reserveTerminal
11 ( reserveTerminal
16import Control.Monad (when)
16import Control.Monad (when)
17+import Data.Bits (shiftL, (.&.))
17import qualified Data.ByteString as BS
18import qualified Data.ByteString as BS
18import Data.ByteString.Internal (toForeignPtr)
19import Data.ByteString.Internal (toForeignPtr)
19import Data.Terminfo.Parse
20import Data.Terminfo.Parse
@@ -24,9 +25,8 @@ import Graphics.Vty.Image (DisplayRegion)
24import Graphics.Vty.DisplayAttributes
25import Graphics.Vty.DisplayAttributes
25import Graphics.Vty.Output.Interface
26import Graphics.Vty.Output.Interface
27−import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable)
28+import Blaze.ByteString.Builder (Write, writeToByteString, writeStorable, writeWord8)
29−import Data.Bits ((.&.))
30import Data.IORef
30import Data.IORef
31import Data.Maybe (isJust, isNothing, fromJust)
31import Data.Maybe (isJust, isNothing, fromJust)
32import Data.Word
32import Data.Word
@@ -49,7 +49,6 @@ data TerminfoCaps = TerminfoCaps
49 , cup :: CapExpression
49 , cup :: CapExpression
50 , cnorm :: Maybe CapExpression
50 , cnorm :: Maybe CapExpression
51 , civis :: Maybe CapExpression
51 , civis :: Maybe CapExpression
52− , supportsNoColors :: Bool
53 , useAltColorMap :: Bool
52 , useAltColorMap :: Bool
54 , setForeColor :: CapExpression
53 , setForeColor :: CapExpression
55 , setBackColor :: CapExpression
54 , setBackColor :: CapExpression
@@ -66,6 +65,8 @@ data DisplayAttrCaps = DisplayAttrCaps
66 , exitStandout :: Maybe CapExpression
65 , exitStandout :: Maybe CapExpression
67 , enterItalic :: Maybe CapExpression
66 , enterItalic :: Maybe CapExpression
68 , exitItalic :: Maybe CapExpression
67 , exitItalic :: Maybe CapExpression
68+ , enterStrikethrough :: Maybe CapExpression
69+ , exitStrikethrough :: Maybe CapExpression
69 , enterUnderline :: Maybe CapExpression
70 , enterUnderline :: Maybe CapExpression
70 , exitUnderline :: Maybe CapExpression
71 , exitUnderline :: Maybe CapExpression
71 , enterReverseVideo :: Maybe CapExpression
72 , enterReverseVideo :: Maybe CapExpression
@@ -102,28 +103,28 @@ sendCapToTerminal t cap capParams = do
103-- * Providing independent string capabilities for all display
104-- * Providing independent string capabilities for all display
104-- attributes.
105-- attributes.
105−reserveTerminal :: String -> Fd -> IO Output
106+reserveTerminal :: String -> Fd -> ColorMode -> IO Output
106−reserveTerminal termName outFd = do
107+reserveTerminal termName outFd colorMode = do
107 ti <- Terminfo.setupTerm termName
108 ti <- Terminfo.setupTerm termName
108 -- assumes set foreground always implies set background exists.
109 -- assumes set foreground always implies set background exists.
109 -- if set foreground is not set then all color changing style
110 -- if set foreground is not set then all color changing style
110 -- attributes are filtered.
111 -- attributes are filtered.
111 msetaf <- probeCap ti "setaf"
112 msetaf <- probeCap ti "setaf"
112 msetf <- probeCap ti "setf"
113 msetf <- probeCap ti "setf"
113− let (noColors, useAlt, setForeCap)
114+ let (useAlt, setForeCap)
114 = case msetaf of
115 = case msetaf of
115− Just setaf -> (False, False, setaf)
116+ Just setaf -> (False, setaf)
116 Nothing -> case msetf of
117 Nothing -> case msetf of
117− Just setf -> (False, True, setf)
118+ Just setf -> (True, setf)
118− Nothing -> (True, True, error $ "no fore color support for terminal " ++ termName)
119+ Nothing -> (True, error $ "no fore color support for terminal " ++ termName)
119 msetab <- probeCap ti "setab"
120 msetab <- probeCap ti "setab"
120 msetb <- probeCap ti "setb"
121 msetb <- probeCap ti "setb"
121− let set_back_cap
122+ let setBackCap
122 = case msetab of
123 = case msetab of
123 Nothing -> case msetb of
125 Nothing -> case msetb of
124 Just setb -> setb
126 Just setb -> setb
125 Nothing -> error $ "no back color support for terminal " ++ termName
127 Nothing -> error $ "no back color support for terminal " ++ termName
128 hyperlinkModeStatus <- newIORef False
129 hyperlinkModeStatus <- newIORef False
129 newAssumedStateRef <- newIORef initialAssumedState
130 newAssumedStateRef <- newIORef initialAssumedState
@@ -149,10 +150,9 @@ reserveTerminal termName outFd = do
149 <*> requireCap ti "cup"
150 <*> requireCap ti "cup"
150 <*> probeCap ti "cnorm"
151 <*> probeCap ti "cnorm"
151 <*> probeCap ti "civis"
152 <*> probeCap ti "civis"
153 <*> pure useAlt
153 <*> pure useAlt
154 <*> pure setForeCap
154 <*> pure setForeCap
155− <*> pure set_back_cap
155+ <*> pure setBackCap
156 <*> requireCap ti "sgr0"
156 <*> requireCap ti "sgr0"
157 <*> requireCap ti "clear"
157 <*> requireCap ti "clear"
158 <*> requireCap ti "el"
158 <*> requireCap ti "el"
@@ -164,6 +164,10 @@ reserveTerminal termName outFd = do
164 sendCap setDefaultAttr []
164 sendCap setDefaultAttr []
165 maybeSendCap cnorm []
165 maybeSendCap cnorm []
166 , supportsBell = return $ isJust $ ringBellAudio terminfoCaps
166 , 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))
167 , ringTerminalBell = maybeSendCap ringBellAudio []
171 , ringTerminalBell = maybeSendCap ringBellAudio []
168 , reserveDisplay = do
172 , reserveDisplay = do
169 -- If there is no support for smcup: Clear the screen
173 -- If there is no support for smcup: Clear the screen
@@ -174,6 +178,8 @@ reserveTerminal termName outFd = do
174 , releaseDisplay = do
178 , releaseDisplay = do
175 maybeSendCap rmcup []
179 maybeSendCap rmcup []
176 maybeSendCap cnorm []
180 maybeSendCap cnorm []
181+ , setDisplayBounds = \(w, h) ->
182+ setWindowSize outFd (w, h)
177 , displayBounds = do
183 , displayBounds = do
178 rawSize <- getWindowSize outFd
184 rawSize <- getWindowSize outFd
179 case rawSize of
185 case rawSize of
@@ -186,20 +192,15 @@ reserveTerminal termName outFd = do
186 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
192 when (toEnum len /= actualLen) $ fail $ "Graphics.Vty.Output: outputByteBuffer "
187 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
193 ++ "length mismatch. " ++ show len ++ " /= " ++ show actualLen
188 ++ " Please report this bug to vty project."
194 ++ " Please report this bug to vty project."
190− = case supportsNoColors terminfoCaps of
191− False -> case Terminfo.getCapability ti (Terminfo.tiGetNum "colors" ) of
195 , supportsCursorVisibility = isJust $ civis terminfoCaps
195 , supportsCursorVisibility = isJust $ civis terminfoCaps
196 , supportsMode = terminfoModeSupported
196 , supportsMode = terminfoModeSupported
197 , setMode = terminfoSetMode
197 , setMode = terminfoSetMode
198 , getModeStatus = terminfoModeStatus
198 , getModeStatus = terminfoModeStatus
199 , assumedStateRef = newAssumedStateRef
199 , assumedStateRef = newAssumedStateRef
200+ , outputColorMode = colorMode
200 -- I think fix would help assure tActual is the only
201 -- I think fix would help assure tActual is the only
201 -- reference. I was having issues tho.
202 -- reference. I was having issues tho.
202− , mkDisplayContext = \tActual -> terminfoDisplayContext tActual terminfoCaps
203+ , mkDisplayContext = (`terminfoDisplayContext` terminfoCaps)
204 sendCap s = sendCapToTerminal t (s terminfoCaps)
205 sendCap s = sendCapToTerminal t (s terminfoCaps)
205 maybeSendCap s = when (isJust $ s terminfoCaps) . sendCap (fromJust . s)
206 maybeSendCap s = when (isJust $ s terminfoCaps) . sendCap (fromJust . s)
@@ -231,6 +232,8 @@ currentDisplayAttrCaps ti
231 <*> probeCap ti "rmso"
232 <*> probeCap ti "rmso"
232 <*> probeCap ti "sitm"
233 <*> probeCap ti "sitm"
233 <*> probeCap ti "ritm"
234 <*> probeCap ti "ritm"
235+ <*> probeCap ti "smxx"
236+ <*> probeCap ti "rmxx"
234 <*> probeCap ti "smul"
237 <*> probeCap ti "smul"
235 <*> probeCap ti "rmul"
238 <*> probeCap ti "rmul"
236 <*> probeCap ti "rev"
239 <*> probeCap ti "rev"
@@ -244,6 +247,13 @@ getWindowSize fd = do
244 (a,b) <- (`divMod` 65536) `fmap` c_getWindowSize fd
247 (a,b) <- (`divMod` 65536) `fmap` c_getWindowSize fd
245 return (fromIntegral b, fromIntegral a)
248 return (fromIntegral b, fromIntegral a)
250+foreign import ccall "gwinsz.h vty_c_set_window_size" c_setWindowSize :: Fd -> CLong -> IO ()
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
247terminfoDisplayContext :: Output -> TerminfoCaps -> DisplayRegion -> IO DisplayContext
257terminfoDisplayContext :: Output -> TerminfoCaps -> DisplayRegion -> IO DisplayContext
248terminfoDisplayContext tActual terminfoCaps r = return dc
258terminfoDisplayContext tActual terminfoCaps r = return dc
249 where dc = DisplayContext
259 where dc = DisplayContext
@@ -259,7 +269,11 @@ terminfoDisplayContext tActual terminfoCaps r = return dc
259 , writeSetAttr = terminfoWriteSetAttr dc terminfoCaps
269 , writeSetAttr = terminfoWriteSetAttr dc terminfoCaps
260 , writeDefaultAttr = \urlsEnabled ->
270 , writeDefaultAttr = \urlsEnabled ->
261 writeCapExpr (setDefaultAttr terminfoCaps) [] `mappend`
271 writeCapExpr (setDefaultAttr terminfoCaps) [] `mappend`
262− (if urlsEnabled then writeURLEscapes EndLink else mempty)
272+ (if urlsEnabled then writeURLEscapes EndLink else mempty) `mappend`
273+ (case exitStrikethrough $ displayAttrCaps terminfoCaps of
274+ Just cap -> writeCapExpr cap []
263 , writeRowEnd = writeCapExpr (clearEol terminfoCaps) []
277 , writeRowEnd = writeCapExpr (clearEol terminfoCaps) []
264 , inlineHack = return ()
278 , inlineHack = return ()
@@ -281,7 +295,7 @@ writeURLEscapes NoLinkChange =
281-- | 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.
283-- 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
284−-- 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
285-- colors to the default) this procedure is used:
299-- colors to the default) this procedure is used:
287-- 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.
@@ -320,9 +334,9 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
320 -- The only way to reset either color, portably, to the default
334 -- The only way to reset either color, portably, to the default
321 -- 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
322 -- capability.
336 -- capability.
323− True -> do
337+ True -> do
324 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
338 case reqDisplayCapSeqFor (displayAttrCaps terminfoCaps)
325− (fixedStyle attr )
339+ (fixedStyle attr)
326 (styleToApplySeq $ fixedStyle attr) of
340 (styleToApplySeq $ fixedStyle attr) of
327 -- only way to reset a color to the defaults
341 -- only way to reset a color to the defaults
328 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
342 EnterExitSeq caps -> writeDefaultAttr dc urlsEnabled
@@ -332,11 +346,11 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
332 setColors
346 setColors
333 -- implicitly resets the colors to the defaults
347 -- implicitly resets the colors to the defaults
334 SetState state -> writeCapExpr (fromJust $ setAttrStates
348 SetState state -> writeCapExpr (fromJust $ setAttrStates
335− $ displayAttrCaps
349+ $ displayAttrCaps terminfoCaps
338 (sgrArgsForState state)
351 (sgrArgsForState state)
339 `mappend` setItalics
352 `mappend` setItalics
353+ `mappend` setStrikethrough
340 `mappend` setColors
354 `mappend` setColors
341 -- Otherwise the display colors are not changing or changing
355 -- Otherwise the display colors are not changing or changing
342 -- between two non-default points.
356 -- between two non-default points.
@@ -355,15 +369,16 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
355 -- applied states.
369 -- applied states.
356 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
370 EnterExitSeq caps -> foldMap (\cap -> writeCapExpr cap []) caps
357 `mappend`
371 `mappend`
358− writeColorDiff setForeColor (foreColorDiff diffs)
372+ writeColorDiff Foreground (foreColorDiff diffs)
359 `mappend`
373 `mappend`
360− writeColorDiff setBackColor (backColorDiff diffs)
374+ writeColorDiff Background (backColorDiff diffs)
361 -- implicitly resets the colors to the defaults
375 -- implicitly resets the colors to the defaults
362 SetState state -> writeCapExpr (fromJust $ setAttrStates
376 SetState state -> writeCapExpr (fromJust $ setAttrStates
363 $ displayAttrCaps terminfoCaps
377 $ displayAttrCaps terminfoCaps
365 (sgrArgsForState state)
379 (sgrArgsForState state)
366 `mappend` setItalics
380 `mappend` setItalics
381+ `mappend` setStrikethrough
367 `mappend` setColors
382 `mappend` setColors
369 urlAttrs True = writeURLEscapes (urlDiff diffs)
384 urlAttrs True = writeURLEscapes (urlDiff diffs)
@@ -381,31 +396,72 @@ terminfoWriteSetAttr dc terminfoCaps urlsEnabled prevAttr reqAttr diffs =
381 , Just sitm <- enterItalic (displayAttrCaps terminfoCaps)
396 , Just sitm <- enterItalic (displayAttrCaps terminfoCaps)
382 = writeCapExpr sitm []
397 = writeCapExpr sitm []
383 | otherwise = mempty
398 | otherwise = mempty
400+ | hasStyle (fixedStyle attr) strikethrough
401+ , Just smxx <- enterStrikethrough (displayAttrCaps terminfoCaps)
402+ = writeCapExpr smxx []
403+ | otherwise = mempty
384 setColors =
404 setColors =
385 (case fixedForeColor attr of
405 (case fixedForeColor attr of
386− Just c -> writeCapExpr (setForeColor terminfoCaps)
406+ Just c -> writeColor Foreground c
387− [toEnum $ colorMap c]
388 Nothing -> mempty)
407 Nothing -> mempty)
389 `mappend`
408 `mappend`
390 (case fixedBackColor attr of
409 (case fixedBackColor attr of
391− Just c -> writeCapExpr (setBackColor terminfoCaps)
410+ Just c -> writeColor Background c
392− [toEnum $ colorMap c]
393 Nothing -> mempty)
411 Nothing -> mempty)
394− writeColorDiff _f NoColorChange
412+ writeColorDiff _side NoColorChange
396− writeColorDiff _f ColorToDefault
414+ writeColorDiff _side ColorToDefault
397 = error "ColorToDefault is not a possible case for applyColorDiffs"
415 = error "ColorToDefault is not a possible case for applyColorDiffs"
398− 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"
399− = 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"
401-- | 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
402-- 240 color set that might not be supported by the terminal.
454-- 240 color set that might not be supported by the terminal.
404−-- 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
405−-- computes the index into the full 256 color pallete.
457+-- computes the index into the full 256 color palette.
406ansiColorIndex :: Color -> Int
458ansiColorIndex :: Color -> Int
407ansiColorIndex (ISOColor v) = fromEnum v
459ansiColorIndex (ISOColor v) = fromEnum v
408ansiColorIndex (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"
410-- | For terminals without setaf/setab
466-- | For terminals without setaf/setab
@@ -422,6 +478,10 @@ altColorIndex (ISOColor 6) = 3
422altColorIndex (ISOColor 7) = 7
478altColorIndex (ISOColor 7) = 7
423altColorIndex (ISOColor v) = fromEnum v
479altColorIndex (ISOColor v) = fromEnum v
424altColorIndex (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"
426{- | 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
427 - according to these rules.
487 - according to these rules.
@@ -449,6 +509,7 @@ data DisplayAttrState = DisplayAttrState
449 { applyStandout :: Bool
509 { applyStandout :: Bool
450 , applyUnderline :: Bool
510 , applyUnderline :: Bool
451 , applyItalic :: Bool
511 , applyItalic :: Bool
512+ , applyStrikethrough :: Bool
452 , applyReverseVideo :: Bool
513 , applyReverseVideo :: Bool
453 , applyBlink :: Bool
514 , applyBlink :: Bool
454 , applyDim :: Bool
515 , applyDim :: Bool
@@ -485,6 +546,8 @@ reqDisplayCapSeqFor caps s diffs
485 -- set state cap then just use the set state cap.
546 -- set state cap then just use the set state cap.
486 ( True, True ) -> SetState $ stateForStyle s
547 ( True, True ) -> SetState $ stateForStyle s
549+ noEnterExitCap ApplyStrikethrough = isNothing $ enterStrikethrough caps
550+ noEnterExitCap RemoveStrikethrough = isNothing $ exitStrikethrough caps
488 noEnterExitCap ApplyItalic = isNothing $ enterItalic caps
551 noEnterExitCap ApplyItalic = isNothing $ enterItalic caps
489 noEnterExitCap RemoveItalic = isNothing $ exitItalic caps
552 noEnterExitCap RemoveItalic = isNothing $ exitItalic caps
490 noEnterExitCap ApplyStandout = isNothing $ enterStandout caps
553 noEnterExitCap ApplyStandout = isNothing $ enterStandout caps
@@ -499,6 +562,8 @@ reqDisplayCapSeqFor caps s diffs
499 noEnterExitCap RemoveDim = True
562 noEnterExitCap RemoveDim = True
500 noEnterExitCap ApplyBold = isNothing $ enterBoldMode caps
563 noEnterExitCap ApplyBold = isNothing $ enterBoldMode caps
501 noEnterExitCap RemoveBold = True
564 noEnterExitCap RemoveBold = True
565+ enterExitCap ApplyStrikethrough = fromJust $ enterStrikethrough caps
566+ enterExitCap RemoveStrikethrough = fromJust $ exitStrikethrough caps
502 enterExitCap ApplyItalic = fromJust $ enterItalic caps
567 enterExitCap ApplyItalic = fromJust $ enterItalic caps
503 enterExitCap RemoveItalic = fromJust $ exitItalic caps
568 enterExitCap RemoveItalic = fromJust $ exitItalic caps
504 enterExitCap ApplyStandout = fromJust $ enterStandout caps
569 enterExitCap ApplyStandout = fromJust $ enterStandout caps
@@ -515,6 +580,7 @@ stateForStyle s = DisplayAttrState
515 { applyStandout = isStyleSet standout
580 { applyStandout = isStyleSet standout
516 , applyUnderline = isStyleSet underline
581 , applyUnderline = isStyleSet underline
517 , applyItalic = isStyleSet italic
582 , applyItalic = isStyleSet italic
583+ , applyStrikethrough = isStyleSet strikethrough
518 , applyReverseVideo = isStyleSet reverseVideo
584 , applyReverseVideo = isStyleSet reverseVideo
519 , applyBlink = isStyleSet blink
585 , applyBlink = isStyleSet blink
520 , applyDim = isStyleSet dim
586 , applyDim = isStyleSet dim
@@ -527,6 +593,7 @@ styleToApplySeq s = concat
527 [ applyIfRequired ApplyStandout standout
593 [ applyIfRequired ApplyStandout standout
528 , applyIfRequired ApplyUnderline underline
594 , applyIfRequired ApplyUnderline underline
529 , applyIfRequired ApplyItalic italic
595 , applyIfRequired ApplyItalic italic
596+ , applyIfRequired ApplyStrikethrough strikethrough
530 , applyIfRequired ApplyReverseVideo reverseVideo
597 , applyIfRequired ApplyReverseVideo reverseVideo
531 , applyIfRequired ApplyBlink blink
598 , applyIfRequired ApplyBlink blink
532 , applyIfRequired ApplyDim dim
599 , applyIfRequired ApplyDim dim