summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authordelthas <delthas@dille.cc>2021-10-31 19:10:39 +0100
committerHubert Hirtz <hubert@hirtz.pm>2021-10-31 19:57:01 +0100
commitcd28b242ff84f85e6536af9ee6343308de5885d3 (patch)
treef741db49302f67f9aa6c7b9df021394581ecb8aa /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.go6
-rw-r--r--ui/style.go65
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'
}