refactor(ui,chat,markdown): use tview.MergeStyle and uniseg.StringWidth

This commit is contained in:
ayn2op 2026-06-04 19:27:16 -04:00
parent 3cbbce6aeb
commit c96474bc9c
7 changed files with 21 additions and 44 deletions

2
go.mod
View file

@ -11,7 +11,7 @@ require (
github.com/alecthomas/chroma/v2 v2.26.1
github.com/andybalholm/brotli v1.2.1
github.com/ayn2op/clipboard v0.0.0-20260308203959-c5ad7df3fc97
github.com/ayn2op/tview v0.0.0-20260604212409-7075d4e3251a
github.com/ayn2op/tview v0.0.0-20260604231822-b8038457d689
github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb
github.com/diamondburned/arikawa/v3 v3.6.1-0.20260518050745-b430932b3ee1
github.com/diamondburned/ningen/v3 v3.0.1-0.20260306213430-5a08d3a709b4

4
go.sum
View file

@ -14,8 +14,8 @@ github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eT
github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/ayn2op/clipboard v0.0.0-20260308203959-c5ad7df3fc97 h1:WujETUV+v0DEJyZgjeLzQvihWyL80c0Tg4qf0dDo+Io=
github.com/ayn2op/clipboard v0.0.0-20260308203959-c5ad7df3fc97/go.mod h1:3kFnpNCa3dF6WryzOMCDao7PfZ7DTCh+pievlfuwV80=
github.com/ayn2op/tview v0.0.0-20260604212409-7075d4e3251a h1:mJ6+hfFcQrzFy/rUZLJgkHQzIXuVIeXxiUtU/OQiJF4=
github.com/ayn2op/tview v0.0.0-20260604212409-7075d4e3251a/go.mod h1:W0lZFznN+hDXma+CT27czLM8/zbNOda6vsfVgHI1Sew=
github.com/ayn2op/tview v0.0.0-20260604231822-b8038457d689 h1:DyyBD32TNUy4qy3WEG+PBN7BsOT4/R/bmVe71PoztUo=
github.com/ayn2op/tview v0.0.0-20260604231822-b8038457d689/go.mod h1:W0lZFznN+hDXma+CT27czLM8/zbNOda6vsfVgHI1Sew=
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=

View file

@ -8,7 +8,6 @@ import (
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"github.com/ayn2op/discordo/internal/config"
"github.com/ayn2op/discordo/internal/ui"
"github.com/ayn2op/tview"
"github.com/diamondburned/ningen/v3/discordmd"
"github.com/gdamore/tcell/v3"
@ -78,14 +77,14 @@ func (r *Renderer) RenderLines(source []byte, node ast.Node, base tcell.Style) [
case *ast.AutoLink:
if entering {
url := string(node.URL(source))
style := ui.MergeStyle(currentStyle(), theme.URLStyle.Style).Url(url)
style := tview.MergeStyle(currentStyle(), theme.URLStyle.Style).Url(url)
builder.Write(url, style)
}
case *ast.Link:
if entering {
url := string(node.Destination)
linkDepth++
pushStyle(ui.MergeStyle(currentStyle(), theme.URLStyle.Style).Url(url))
pushStyle(tview.MergeStyle(currentStyle(), theme.URLStyle.Style).Url(url))
} else {
if linkDepth > 0 {
linkDepth--
@ -126,11 +125,11 @@ func (r *Renderer) RenderLines(source []byte, node ast.Node, base tcell.Style) [
}
case *discordmd.Mention:
if entering {
builder.Write(mentionText(node), ui.MergeStyle(currentStyle(), theme.MentionStyle.Style))
builder.Write(mentionText(node), tview.MergeStyle(currentStyle(), theme.MentionStyle.Style))
}
case *discordmd.Emoji:
if entering {
builder.Write(":"+node.Name+":", ui.MergeStyle(currentStyle(), theme.EmojiStyle.Style))
builder.Write(":"+node.Name+":", tview.MergeStyle(currentStyle(), theme.EmojiStyle.Style))
}
}
return ast.WalkContinue, nil

View file

@ -123,10 +123,10 @@ func (gt *guildsTree) channelNodeStyle(channel discord.Channel) tcell.Style {
recipient := channel.DMRecipients[0]
presence, err := gt.chat.state.Cabinet.Presence(discord.NullGuildID, recipient.ID)
if err != nil {
return ui.MergeStyle(gt.dmStatusStyle(discord.OfflineStatus), unread)
return tview.MergeStyle(gt.dmStatusStyle(discord.OfflineStatus), unread)
}
return ui.MergeStyle(gt.dmStatusStyle(presence.Status), unread)
return tview.MergeStyle(gt.dmStatusStyle(presence.Status), unread)
}
func (gt *guildsTree) dmStatusStyle(status discord.Status) tcell.Style {

View file

@ -6,6 +6,7 @@ import (
"github.com/ayn2op/tview"
"github.com/ayn2op/tview/list"
"github.com/gdamore/tcell/v3"
"github.com/rivo/uniseg"
)
type mentionsListItem struct {
@ -90,7 +91,7 @@ func (m *mentionsList) selectedInsertText() (string, bool) {
func (m *mentionsList) maxDisplayWidth() int {
width := 0
for _, item := range m.items {
width = max(width, tview.TaggedStringWidth(item.displayText))
width = max(width, uniseg.StringWidth(item.displayText))
}
return width
}

View file

@ -494,7 +494,7 @@ func (ml *messagesList) drawDefaultMessage(builder *tview.LineBuilder, message d
ml.drawEmbeds(builder, message, baseStyle, contentRoot, contentSource)
attachmentStyle := ui.MergeStyle(baseStyle, ml.cfg.Theme.MessagesList.AttachmentStyle.Style)
attachmentStyle := tview.MergeStyle(baseStyle, ml.cfg.Theme.MessagesList.AttachmentStyle.Style)
for _, a := range message.Attachments {
builder.NewLine()
if ml.cfg.ShowAttachmentLinks {
@ -527,7 +527,7 @@ func (ml *messagesList) drawEmbeds(builder *tview.LineBuilder, message discord.M
lineStyles := embedLineStyles(baseStyle, ml.cfg.Theme.MessagesList.Embeds)
defaultBarStyle := baseStyle.Dim(true)
prefixText := " ▎ "
prefixWidth := tview.TaggedStringWidth(prefixText)
prefixWidth := uniseg.StringWidth(prefixText)
_, _, innerWidth, _ := ml.InnerRect()
// Wrap against the current list viewport. This keeps embed wrapping stable even when sidebars/panes are resized.
wrapWidth := max(innerWidth-prefixWidth, 1)
@ -674,14 +674,14 @@ const (
func embedLineStyles(baseStyle tcell.Style, theme config.MessagesListEmbedsTheme) [8]tcell.Style {
styles := [8]tcell.Style{}
styles[embedLineProvider] = ui.MergeStyle(baseStyle, theme.ProviderStyle.Style)
styles[embedLineAuthor] = ui.MergeStyle(baseStyle, theme.AuthorStyle.Style)
styles[embedLineTitle] = ui.MergeStyle(baseStyle, theme.TitleStyle.Style)
styles[embedLineDescription] = ui.MergeStyle(baseStyle, theme.DescriptionStyle.Style)
styles[embedLineFieldName] = ui.MergeStyle(baseStyle, theme.FieldNameStyle.Style)
styles[embedLineFieldValue] = ui.MergeStyle(baseStyle, theme.FieldValueStyle.Style)
styles[embedLineFooter] = ui.MergeStyle(baseStyle, theme.FooterStyle.Style)
styles[embedLineURL] = ui.MergeStyle(baseStyle, theme.URLStyle.Style)
styles[embedLineProvider] = tview.MergeStyle(baseStyle, theme.ProviderStyle.Style)
styles[embedLineAuthor] = tview.MergeStyle(baseStyle, theme.AuthorStyle.Style)
styles[embedLineTitle] = tview.MergeStyle(baseStyle, theme.TitleStyle.Style)
styles[embedLineDescription] = tview.MergeStyle(baseStyle, theme.DescriptionStyle.Style)
styles[embedLineFieldName] = tview.MergeStyle(baseStyle, theme.FieldNameStyle.Style)
styles[embedLineFieldValue] = tview.MergeStyle(baseStyle, theme.FieldValueStyle.Style)
styles[embedLineFooter] = tview.MergeStyle(baseStyle, theme.FooterStyle.Style)
styles[embedLineURL] = tview.MergeStyle(baseStyle, theme.URLStyle.Style)
return styles
}

View file

@ -9,7 +9,6 @@ import (
"github.com/ayn2op/tview"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/ningen/v3"
"github.com/gdamore/tcell/v3"
)
// ConfigureBox configures the provided box according to the provided theme.
@ -131,25 +130,3 @@ func getMessageIDFromChannel(channel discord.Channel) discord.MessageID {
}
return discord.MessageID(channel.ID)
}
func MergeStyle(base, overlay tcell.Style) tcell.Style {
fg := overlay.GetForeground()
if fg == tcell.ColorDefault {
fg = base.GetForeground()
}
bg := overlay.GetBackground()
if bg == tcell.ColorDefault {
bg = base.GetBackground()
}
style := base.Foreground(fg).Background(bg)
style = style.Bold(base.HasBold() || overlay.HasBold())
style = style.Dim(base.HasDim() || overlay.HasDim())
style = style.Italic(base.HasItalic() || overlay.HasItalic())
style = style.Blink(base.HasBlink() || overlay.HasBlink())
style = style.Reverse(base.HasReverse() || overlay.HasReverse())
style = style.StrikeThrough(base.HasStrikeThrough() || overlay.HasStrikeThrough())
if base.HasUnderline() || overlay.HasUnderline() {
style = style.Underline(true)
}
return style
}