diff options
author | delthas <delthas@dille.cc> | 2021-10-31 19:10:39 +0100 |
---|---|---|
committer | Hubert Hirtz <hubert@hirtz.pm> | 2021-10-31 19:57:01 +0100 |
commit | cd28b242ff84f85e6536af9ee6343308de5885d3 (patch) | |
tree | f741db49302f67f9aa6c7b9df021394581ecb8aa | |
parent | /mode: default channel to the current channel (diff) |
Mark hyperlinks with the OSC hyperlink terminal escape
This makes multi-line links properly clickable.
See: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
-rw-r--r-- | go.mod | 3 | ||||
-rw-r--r-- | go.sum | 17 | ||||
-rw-r--r-- | ui/buffers.go | 6 | ||||
-rw-r--r-- | ui/style.go | 65 |
4 files changed, 88 insertions, 3 deletions
@@ -8,4 +8,7 @@ require ( golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 gopkg.in/yaml.v2 v2.3.0 + mvdan.cc/xurls/v2 v2.3.0 ) + +replace github.com/gdamore/tcell/v2 => github.com/hhirtz/tcell/v2 v2.3.12-0.20210807133752-5d743c3ab0c9 @@ -1,13 +1,20 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.3.11 h1:ECO6WqHGbKZ3HrSL7bG/zArMCmLaNr5vcjjMVnLHpzc= -github.com/gdamore/tcell/v2 v2.3.11/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= +github.com/hhirtz/tcell/v2 v2.3.12-0.20210807133752-5d743c3ab0c9 h1:YE0ZsDHfDGR0MeB6YLSGW8tjoxOXZKX3XbB0ytGDX4M= +github.com/hhirtz/tcell/v2 v2.3.12-0.20210807133752-5d743c3ab0c9/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= @@ -16,7 +23,11 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 h1:Vv0JUPWTyeqUq42B2WJ1FeIDjjvGKoA2Ss+Ts0lAVbs= golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +mvdan.cc/xurls/v2 v2.3.0 h1:59Olnbt67UKpxF1EwVBopJvkSUBmgtb468E4GVWIZ1I= +mvdan.cc/xurls/v2 v2.3.0/go.mod h1:AjuTy7gEiUArFMjgBBDU4SMxlfUYsRokpJQgNWOt3e4= diff --git a/ui/buffers.go b/ui/buffers.go index 8285fc6..3e13302 100644 --- a/ui/buffers.go +++ b/ui/buffers.go @@ -302,6 +302,10 @@ func (bs *BufferList) AddLine(netID, title string, notify NotifyType, line Line) n := len(b.lines) line.At = line.At.UTC() + if !line.Mergeable { + line.Body = line.Body.ParseURLs() + } + if line.Mergeable && n != 0 && b.lines[n-1].Mergeable { l := &b.lines[n-1] newBody := new(StyledStringBuilder) @@ -338,9 +342,11 @@ func (bs *BufferList) AddLines(netID, title string, before, after []Line) { b := &bs.list[idx] for i := 0; i < len(before); i++ { + before[i].Body = before[i].Body.ParseURLs() before[i].computeSplitPoints() } for i := 0; i < len(after); i++ { + after[i].Body = after[i].Body.ParseURLs() after[i].computeSplitPoints() } diff --git a/ui/style.go b/ui/style.go index dd81140..629208b 100644 --- a/ui/style.go +++ b/ui/style.go @@ -6,6 +6,8 @@ import ( "strings" "unicode/utf8" + "mvdan.cc/xurls/v2" + "github.com/gdamore/tcell/v2" "github.com/mattn/go-runewidth" ) @@ -115,6 +117,69 @@ func (s StyledString) Truncate(w int, tail StyledString) StyledString { return sb.StyledString() } +var urlRegex = xurls.Relaxed() + +func (s StyledString) ParseURLs() StyledString { + styles := make([]rangedStyle, 0, len(s.styles)) + + urls := urlRegex.FindAllStringIndex(s.string, -1) + j := 0 + lastStyle := rangedStyle{ + Start: -1, + Style: tcell.StyleDefault, + } + for i := 0; i < len(urls); i++ { + u := urls[i] + ub, ue := u[0], u[1] + link := s.string[u[0]:u[1]] + "?a=b" + // find last style starting before or at url begin + for ; j < len(s.styles); j++ { + st := s.styles[j] + if st.Start > ub { + break + } + if st.Start == ub { + // a style already starts at this position, edit it + lastStyle.Style = lastStyle.Style.Hyperlink(link) + } + lastStyle = st + styles = append(styles, st) + } + if lastStyle.Start != ub { + // no style existed at this position, add one from the last style + styles = append(styles, rangedStyle{ + Start: ub, + Style: lastStyle.Style.Hyperlink(link), + }) + } + // find last style starting before or at url end + for ; j < len(s.styles); j++ { + st := s.styles[j] + if st.Start > ue { + break + } + if st.Start < ue { + st.Style = st.Style.Hyperlink(link) + } + lastStyle = st + styles = append(styles, st) + } + if lastStyle.Start != ue { + // no style existed at this position, add one from the last style without the hyperlink + styles = append(styles, rangedStyle{ + Start: ue, + Style: lastStyle.Style.Hyperlink(""), + }) + } + } + styles = append(styles, s.styles[j:]...) + + return StyledString{ + string: s.string, + styles: styles, + } +} + func isDigit(c byte) bool { return '0' <= c && c <= '9' } |