packages feed

safe-coloured-text 0.3.0.2 → 0.6.0.0

raw patch · 5 files changed

Files

CHANGELOG.md view
@@ -1,6 +1,37 @@ # Changelog for safe-coloured-text -## [0.3.0.2] - 2024-03-26+## [0.6.0.0] - 2026-05-13++### Added++* `chunkStyleHyperlink :: !(Maybe Text)` field in `ChunkStyle` for OSC 8 hyperlink URLs+* `renderOsc8Open` and `renderOsc8Close` for emitting OSC 8 terminal hyperlink sequences+* `renderChunkBuilder` now emits OSC 8 sequences when `chunkStyleHyperlink` is set++## [0.5.0.0] - 2026-04-12++### Changed++* Separated styling from text: `Chunk` now has `chunkText` and `chunkStyle` fields+* New `ChunkStyle` type holds all styling attributes (italic, bold, colours, etc.)+* Styling field names now use `chunkStyle` prefix (e.g. `chunkStyleItalic`)+* Added `noStyle` constructor and `plainStyle`, `styleSGR` functions+* Renamed `chunkSGR` to `styleSGR`++## [0.4.0.0] - 2026-04-12++### Added++* Strikethrough support (`chunkStrikethrough`, `strikethrough`, SGR 9/29)+* Reverse video support (`chunkSwapForegroundBackground`, `swapForegroundBackground`, SGR 7/27)+* Concealed/hidden text support (`chunkConcealed`, `concealed`, SGR 8/28)+* Overline support (`chunkOverlined`, `overlined`, SGR 53/55)++### Fixed++* `chunkBlinking` is now rendered in `chunkSGR` (was stored but never emitted)++## [0.3.0.2] - 2024-06-23  ### Added 
safe-coloured-text.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.36.0.+-- This file has been generated from package.yaml by hpack version 0.38.3. -- -- see: https://github.com/sol/hpack  name:           safe-coloured-text-version:        0.3.0.2+version:        0.6.0.0 synopsis:       Safely output coloured text category:       User Interfaces homepage:       https://github.com/NorfairKing/safe-coloured-text#readme
src/Text/Colour.hs view
@@ -9,6 +9,8 @@   ( -- * Building chunks     chunk,     Chunk (..),+    ChunkStyle (..),+    noStyle,      -- ** Styling @@ -26,6 +28,10 @@     bold,     faint,     italic,+    strikethrough,+    swapForegroundBackground,+    concealed,+    overlined,     underline,     doubleUnderline,     noUnderline,
src/Text/Colour/Chunk.hs view
@@ -24,12 +24,7 @@  data Chunk = Chunk   { chunkText :: !Text,-    chunkItalic :: !(Maybe Bool),-    chunkConsoleIntensity :: !(Maybe ConsoleIntensity),-    chunkUnderlining :: !(Maybe Underlining),-    chunkBlinking :: !(Maybe Blinking),-    chunkForeground :: !(Maybe Colour),-    chunkBackground :: !(Maybe Colour)+    chunkStyle :: !ChunkStyle   }   deriving (Show, Eq, Generic) @@ -38,24 +33,53 @@ instance IsString Chunk where   fromString = chunk . fromString +data ChunkStyle = ChunkStyle+  { chunkStyleItalic :: !(Maybe Bool),+    chunkStyleStrikethrough :: !(Maybe Bool),+    chunkStyleSwapForegroundBackground :: !(Maybe Bool),+    chunkStyleConcealed :: !(Maybe Bool),+    chunkStyleOverlined :: !(Maybe Bool),+    chunkStyleConsoleIntensity :: !(Maybe ConsoleIntensity),+    chunkStyleUnderlining :: !(Maybe Underlining),+    chunkStyleBlinking :: !(Maybe Blinking),+    chunkStyleForeground :: !(Maybe Colour),+    chunkStyleBackground :: !(Maybe Colour),+    -- | OSC 8 hyperlink URL, if any.+    -- Rendered as @ESC]8;;\<url\>ESC\\@ before the text and @ESC]8;;ESC\\@ after.+    chunkStyleHyperlink :: !(Maybe Text)+  }+  deriving (Show, Eq, Generic)++instance Validity ChunkStyle+ -- TODO This is not correct because text-width is correct but it's a -- good place to put this so we can fix it later and it'll get fixed -- everywhere. chunkWidth :: Chunk -> Int chunkWidth = T.length . chunkText -plainChunk :: TerminalCapabilities -> Chunk -> Bool-plainChunk tc Chunk {..} =-  let Chunk _ _ _ _ _ _ _ = undefined+plainStyle :: TerminalCapabilities -> ChunkStyle -> Bool+plainStyle tc ChunkStyle {..} =+  let ChunkStyle _ _ _ _ _ _ _ _ _ _ _ = undefined    in and-        [ isNothing chunkItalic,-          isNothing chunkConsoleIntensity,-          isNothing chunkUnderlining,-          isNothing chunkBlinking,-          maybe True (plainColour tc) chunkForeground,-          maybe True (plainColour tc) chunkBackground+        [ isNothing chunkStyleItalic,+          isNothing chunkStyleStrikethrough,+          isNothing chunkStyleSwapForegroundBackground,+          isNothing chunkStyleConcealed,+          isNothing chunkStyleOverlined,+          isNothing chunkStyleConsoleIntensity,+          isNothing chunkStyleUnderlining,+          isNothing chunkStyleBlinking,+          maybe True (plainColour tc) chunkStyleForeground,+          maybe True (plainColour tc) chunkStyleBackground,+          isNothing chunkStyleHyperlink         ] +plainChunk :: TerminalCapabilities -> Chunk -> Bool+plainChunk tc Chunk {..} =+  let Chunk _ _ = undefined+   in plainStyle tc chunkStyle+ plainColour :: TerminalCapabilities -> Colour -> Bool plainColour tc = \case   Colour8 {} -> tc < With8Colours@@ -105,19 +129,40 @@     then LTB.fromText chunkText     else       mconcat-        [ renderCSI (SGR (chunkSGR tc c)),+        [ maybe mempty renderOsc8Open (chunkStyleHyperlink chunkStyle),+          renderCSI (SGR (styleSGR tc chunkStyle)),           LTB.fromText chunkText,-          renderCSI (SGR [Reset])+          renderCSI (SGR [Reset]),+          maybe mempty (const renderOsc8Close) (chunkStyleHyperlink chunkStyle)         ] -chunkSGR :: TerminalCapabilities -> Chunk -> [SGR]-chunkSGR tc Chunk {..} =+-- | Render an OSC 8 hyperlink open sequence: @ESC]8;;<url>ESC\@.+-- An empty URL renders the close sequence.+renderOsc8Open :: Text -> Text.Builder+renderOsc8Open url =+  mconcat+    [ LTB.fromText (T.pack "\ESC]8;;"),+      LTB.fromText url,+      LTB.fromText (T.pack "\ESC\\")+    ]++-- | Render an OSC 8 hyperlink close sequence: @ESC]8;;ESC\@.+renderOsc8Close :: Text.Builder+renderOsc8Close = LTB.fromText (T.pack "\ESC]8;;\ESC\\")++styleSGR :: TerminalCapabilities -> ChunkStyle -> [SGR]+styleSGR tc ChunkStyle {..} =   catMaybes-    [ SetItalic <$> chunkItalic,-      SetUnderlining <$> chunkUnderlining,-      SetConsoleIntensity <$> chunkConsoleIntensity,-      chunkForeground >>= colourSGR tc Foreground,-      chunkBackground >>= colourSGR tc Background+    [ SetItalic <$> chunkStyleItalic,+      SetStrikethrough <$> chunkStyleStrikethrough,+      SetSwapForegroundBackground <$> chunkStyleSwapForegroundBackground,+      SetConcealed <$> chunkStyleConcealed,+      SetOverlined <$> chunkStyleOverlined,+      SetUnderlining <$> chunkStyleUnderlining,+      SetBlinking <$> chunkStyleBlinking,+      SetConsoleIntensity <$> chunkStyleConsoleIntensity,+      chunkStyleForeground >>= colourSGR tc Foreground,+      chunkStyleBackground >>= colourSGR tc Background     ]  -- | Turn a text into a plain chunk, without any styling@@ -125,46 +170,70 @@ chunk t =   Chunk     { chunkText = t,-      chunkItalic = Nothing,-      chunkConsoleIntensity = Nothing,-      chunkUnderlining = Nothing,-      chunkBlinking = Nothing,-      chunkForeground = Nothing,-      chunkBackground = Nothing+      chunkStyle = noStyle     } +-- | The empty style, without any styling+noStyle :: ChunkStyle+noStyle =+  ChunkStyle+    { chunkStyleItalic = Nothing,+      chunkStyleStrikethrough = Nothing,+      chunkStyleSwapForegroundBackground = Nothing,+      chunkStyleConcealed = Nothing,+      chunkStyleOverlined = Nothing,+      chunkStyleConsoleIntensity = Nothing,+      chunkStyleUnderlining = Nothing,+      chunkStyleBlinking = Nothing,+      chunkStyleForeground = Nothing,+      chunkStyleBackground = Nothing,+      chunkStyleHyperlink = Nothing+    }+ fore :: Colour -> Chunk -> Chunk-fore col chu = chu {chunkForeground = Just col}+fore col chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleForeground = Just col}}  back :: Colour -> Chunk -> Chunk-back col chu = chu {chunkBackground = Just col}+back col chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleBackground = Just col}}  bold :: Chunk -> Chunk-bold chu = chu {chunkConsoleIntensity = Just BoldIntensity}+bold chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleConsoleIntensity = Just BoldIntensity}}  faint :: Chunk -> Chunk-faint chu = chu {chunkConsoleIntensity = Just FaintIntensity}+faint chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleConsoleIntensity = Just FaintIntensity}}  italic :: Chunk -> Chunk-italic chu = chu {chunkItalic = Just True}+italic chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleItalic = Just True}} +strikethrough :: Chunk -> Chunk+strikethrough chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleStrikethrough = Just True}}++swapForegroundBackground :: Chunk -> Chunk+swapForegroundBackground chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleSwapForegroundBackground = Just True}}++concealed :: Chunk -> Chunk+concealed chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleConcealed = Just True}}++overlined :: Chunk -> Chunk+overlined chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleOverlined = Just True}}+ underline :: Chunk -> Chunk-underline chu = chu {chunkUnderlining = Just SingleUnderline}+underline chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleUnderlining = Just SingleUnderline}}  doubleUnderline :: Chunk -> Chunk-doubleUnderline chu = chu {chunkUnderlining = Just DoubleUnderline}+doubleUnderline chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleUnderlining = Just DoubleUnderline}}  noUnderline :: Chunk -> Chunk-noUnderline chu = chu {chunkUnderlining = Just NoUnderline}+noUnderline chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleUnderlining = Just NoUnderline}}  slowBlinking :: Chunk -> Chunk-slowBlinking chu = chu {chunkBlinking = Just SlowBlinking}+slowBlinking chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleBlinking = Just SlowBlinking}}  rapidBlinking :: Chunk -> Chunk-rapidBlinking chu = chu {chunkBlinking = Just RapidBlinking}+rapidBlinking chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleBlinking = Just RapidBlinking}}  noBlinking :: Chunk -> Chunk-noBlinking chu = chu {chunkBlinking = Just NoBlinking}+noBlinking chu = chu {chunkStyle = (chunkStyle chu) {chunkStyleBlinking = Just NoBlinking}}  -- TODO consider allowing an 8-colour alternative to a given 256-colour data Colour
src/Text/Colour/Code.hs view
@@ -71,6 +71,10 @@ data SGR   = Reset   | SetItalic !Bool+  | SetStrikethrough !Bool+  | SetSwapForegroundBackground !Bool+  | SetConcealed !Bool+  | SetOverlined !Bool   | SetUnderlining !Underlining   | SetBlinking !Blinking   | SetConsoleIntensity !ConsoleIntensity@@ -95,6 +99,10 @@ sgrToCSIParams = \case   Reset -> [] -- [0] would be fine too   SetItalic b -> [if b then 3 else 23]+  SetStrikethrough b -> [if b then 9 else 29]+  SetSwapForegroundBackground b -> [if b then 7 else 27]+  SetConcealed b -> [if b then 8 else 28]+  SetOverlined b -> [if b then 53 else 55]   SetUnderlining u ->     [ case u of         SingleUnderline -> 4