@@ -47,6 +47,12 @@ data Mode = Mouse
4747 | Focus
4848 -- ^ Focus-in/focus-out events (whether the terminal is
4949 -- configured to provide events on focus change)
50+ | Hyperlink
51+ -- ^ Hyperlink mode via the 'withURL' attribute modifier (see
52+ -- https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda).
53+ -- Note that this may not work gracefully in all terminal
54+ -- emulators so be sure to test this mode with the terminals
55+ -- you intend to support.
5056 deriving (Eq, Read, Show)
5157
5258-- | The Vty terminal output interface.
@@ -133,9 +139,9 @@ data DisplayContext = DisplayContext
133139 -- to support this the currently applied display attributes are
134140 -- required. In addition it may be possible to optimize the state
135141 -- changes based off the currently applied display attributes.
136− , writeSetAttr :: FixedAttr -> Attr -> DisplayAttrDiff -> Write
142+ , writeSetAttr :: Bool -> FixedAttr -> Attr -> DisplayAttrDiff -> Write
137143 -- | Reset the display attributes to the default display attributes.
138− , writeDefaultAttr :: Write
144+ , writeDefaultAttr :: Bool -> Write
139145 , writeRowEnd :: Write
140146 -- | See `Graphics.Vty.Output.XTermColor.inlineHack`
141147 , inlineHack :: IO ()
@@ -159,6 +165,7 @@ writeUtf8Text = writeByteString
159165-- 5. The cursor is then shown and positioned or kept hidden.
160166outputPicture :: MonadIO m => DisplayContext -> Picture -> m ()
161167outputPicture dc pic = liftIO $ do
168+ urlsEnabled <- getModeStatus (contextDevice dc) Hyperlink
162169 as <- readIORef (assumedStateRef $ contextDevice dc)
163170 let manipCursor = supportsCursorVisibility (contextDevice dc)
164171 r = contextRegion dc
@@ -174,7 +181,7 @@ outputPicture dc pic = liftIO $ do
174181 (Vector.toList ops)
175182 -- build the Write corresponding to the output image
176183 out = (if manipCursor then writeHideCursor dc else mempty)
177− `mappend` writeOutputOps dc initialAttr diffs ops
184+ `mappend` writeOutputOps urlsEnabled dc initialAttr diffs ops
178185 `mappend`
179186 (let (w,h) = contextRegion dc
180187 clampX = max 0 . min (w-1)
@@ -197,15 +204,15 @@ outputPicture dc pic = liftIO $ do
197204 let as' = as { prevOutputOps = Just ops }
198205 writeIORef (assumedStateRef $ contextDevice dc) as'
199206
200−writeOutputOps :: DisplayContext -> FixedAttr -> [Bool] -> DisplayOps -> Write
201−writeOutputOps dc initialAttr diffs ops =
207+writeOutputOps :: Bool -> DisplayContext -> FixedAttr -> [Bool] -> DisplayOps -> Write
208+writeOutputOps urlsEnabled dc initialAttr diffs ops =
202209 let (_, out, _) = Vector.foldl' writeOutputOps'
203210 (0, mempty, diffs)
204211 ops
205212 in out
206213 where
207214 writeOutputOps' (y, out, True : diffs') spanOps
208− = let spanOut = writeSpanOps dc y initialAttr spanOps
215+ = let spanOut = writeSpanOps urlsEnabled dc y initialAttr spanOps
209216 out' = out `mappend` spanOut
210217 in (y+1, out', diffs')
211218 writeOutputOps' (y, out, False : diffs') _spanOps
@@ -213,27 +220,27 @@ writeOutputOps dc initialAttr diffs ops =
213220 writeOutputOps' (_y, _out, []) _spanOps
214221 = error "vty - output spans without a corresponding diff."
215222
216−writeSpanOps :: DisplayContext -> Int -> FixedAttr -> SpanOps -> Write
217−writeSpanOps dc y initialAttr spanOps =
223+writeSpanOps :: Bool -> DisplayContext -> Int -> FixedAttr -> SpanOps -> Write
224+writeSpanOps urlsEnabled dc y initialAttr spanOps =
218225 -- The first operation is to set the cursor to the start of the row
219− let start = writeMoveCursor dc 0 y `mappend` writeDefaultAttr dc
226+ let start = writeMoveCursor dc 0 y `mappend` writeDefaultAttr dc urlsEnabled
220227 -- then the span ops are serialized in the order specified
221− in fst $ Vector.foldl' (\(out, fattr) op -> case writeSpanOp dc op fattr of
228+ in fst $ Vector.foldl' (\(out, fattr) op -> case writeSpanOp urlsEnabled dc op fattr of
222229 (opOut, fattr') -> (out `mappend` opOut, fattr')
223230 )
224231 (start, initialAttr)
225232 spanOps
226233
227−writeSpanOp :: DisplayContext -> SpanOp -> FixedAttr -> (Write, FixedAttr)
228−writeSpanOp dc (TextSpan attr _ _ str) fattr =
234+writeSpanOp :: Bool -> DisplayContext -> SpanOp -> FixedAttr -> (Write, FixedAttr)
235+writeSpanOp urlsEnabled dc (TextSpan attr _ _ str) fattr =
229236 let attr' = limitAttrForDisplay (contextDevice dc) attr
230237 fattr' = fixDisplayAttr fattr attr'
231238 diffs = displayAttrDiffs fattr fattr'
232− out = writeSetAttr dc fattr attr' diffs
239+ out = writeSetAttr dc urlsEnabled fattr attr' diffs
233240 `mappend` writeUtf8Text (T.encodeUtf8 $ TL.toStrict str)
234241 in (out, fattr')
235−writeSpanOp _dc (Skip _) _fattr = error "writeSpanOp for Skip"
236−writeSpanOp dc (RowEnd _) fattr = (writeDefaultAttr dc `mappend` writeRowEnd dc, fattr)
242+writeSpanOp _ _ (Skip _) _fattr = error "writeSpanOp for Skip"
243+writeSpanOp urlsEnabled dc (RowEnd _) fattr = (writeDefaultAttr dc urlsEnabled `mappend` writeRowEnd dc, fattr)
237244
238245-- | The cursor position is given in X,Y character offsets. Due to
239246-- multi-column characters this needs to be translated to column, row