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 /ui | |
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
Diffstat (limited to 'ui')
-rw-r--r-- | ui/buffers.go | 6 | ||||
-rw-r--r-- | ui/style.go | 65 |
2 files changed, 71 insertions, 0 deletions
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' } |