Skip to content

Commit f29ab97

Browse files
committed
send rich text
1 parent 84129f4 commit f29ab97

File tree

9 files changed

+734
-41
lines changed

9 files changed

+734
-41
lines changed

pkg/connector/handlematrix.go

+22-20
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ func (c *GChatClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Mat
4040
}
4141

4242
var annotations []*proto.Annotation
43-
var messageInfo *proto.MessageInfo
43+
messageInfo := &proto.MessageInfo{
44+
AcceptFormatAnnotations: true,
45+
}
4446

4547
if msg.Content.MsgType.IsMedia() {
4648
data, err := c.userLogin.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, msg.Content.File)
@@ -68,35 +70,35 @@ func (c *GChatClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Mat
6870
if msg.ThreadRoot != nil {
6971
topicId = string(msg.ThreadRoot.ID)
7072
}
71-
messageInfo = &proto.MessageInfo{
72-
AcceptFormatAnnotations: true,
73-
ReplyTo: &proto.SendReplyTarget{
74-
Id: &proto.MessageId{
75-
ParentId: &proto.MessageParentId{
76-
Parent: &proto.MessageParentId_TopicId{
77-
TopicId: &proto.TopicId{
78-
GroupId: groupId,
79-
TopicId: topicId,
80-
},
73+
messageInfo.ReplyTo = &proto.SendReplyTarget{
74+
Id: &proto.MessageId{
75+
ParentId: &proto.MessageParentId{
76+
Parent: &proto.MessageParentId_TopicId{
77+
TopicId: &proto.TopicId{
78+
GroupId: groupId,
79+
TopicId: topicId,
8180
},
8281
},
83-
MessageId: replyToId,
8482
},
85-
CreateTime: msg.ReplyTo.Timestamp.UnixMicro(),
83+
MessageId: replyToId,
8684
},
85+
CreateTime: msg.ReplyTo.Timestamp.UnixMicro(),
8786
}
8887
}
8988

9089
var msgID string
9190
var timestamp int64
9291

92+
textBody := msg.Content.Body
93+
text, entities := c.msgConv.ToGChat(ctx, msg.Content)
94+
95+
if entities != nil {
96+
textBody = text
97+
annotations = entities
98+
}
99+
93100
if msg.ThreadRoot != nil {
94101
threadId := string(msg.ThreadRoot.ID)
95-
if messageInfo == nil {
96-
messageInfo = &proto.MessageInfo{
97-
AcceptFormatAnnotations: true,
98-
}
99-
}
100102
req := &proto.CreateMessageRequest{
101103
ParentId: &proto.MessageParentId{
102104
Parent: &proto.MessageParentId_TopicId{
@@ -107,7 +109,7 @@ func (c *GChatClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Mat
107109
},
108110
},
109111
LocalId: string(msg.Event.ID),
110-
TextBody: msg.Content.Body,
112+
TextBody: textBody,
111113
Annotations: annotations,
112114
MessageInfo: messageInfo,
113115
}
@@ -120,7 +122,7 @@ func (c *GChatClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Mat
120122
} else {
121123
req := &proto.CreateTopicRequest{
122124
GroupId: groupId,
123-
TextBody: msg.Content.Body,
125+
TextBody: textBody,
124126
Annotations: annotations,
125127
MessageInfo: messageInfo,
126128
}

pkg/msgconv/from-matrix.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package msgconv
2+
3+
import (
4+
"context"
5+
6+
"maunium.net/go/mautrix/event"
7+
8+
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
9+
"go.mau.fi/mautrix-googlechat/pkg/msgconv/matrixfmt"
10+
)
11+
12+
func (mc *MessageConverter) ToGChat(
13+
ctx context.Context,
14+
content *event.MessageEventContent,
15+
) (string, []*proto.Annotation) {
16+
parser := &matrixfmt.HTMLParser{}
17+
body, annotations := matrixfmt.Parse(ctx, parser, content)
18+
return body, annotations
19+
}

pkg/msgconv/gchatfmt/convert_test.go

+5-21
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,7 @@ import (
1010
"go.mau.fi/mautrix-googlechat/pkg/msgconv/gchatfmt"
1111
)
1212

13-
func makeAnnotation(start, length int32, format proto.FormatMetadata_FormatType) *proto.Annotation {
14-
return &proto.Annotation{
15-
Type: proto.AnnotationType_FORMAT_DATA,
16-
StartIndex: start,
17-
Length: length,
18-
ChipRenderType: proto.Annotation_DO_NOT_RENDER,
19-
Metadata: &proto.Annotation_FormatMetadata{
20-
FormatMetadata: &proto.FormatMetadata{
21-
FormatType: format,
22-
},
23-
},
24-
}
25-
}
26-
2713
func TestParse(t *testing.T) {
28-
assert.Equal(t, 1, 1)
29-
3014
tests := []struct {
3115
name string
3216
ins string
@@ -43,10 +27,10 @@ func TestParse(t *testing.T) {
4327
name: "bold italic strike underline",
4428
ins: "a b i s u z",
4529
ine: []*proto.Annotation{
46-
makeAnnotation(2, 1, proto.FormatMetadata_BOLD),
47-
makeAnnotation(4, 1, proto.FormatMetadata_ITALIC),
48-
makeAnnotation(6, 1, proto.FormatMetadata_STRIKE),
49-
makeAnnotation(8, 1, proto.FormatMetadata_UNDERLINE),
30+
gchatfmt.MakeAnnotation(2, 1, proto.FormatMetadata_BOLD),
31+
gchatfmt.MakeAnnotation(4, 1, proto.FormatMetadata_ITALIC),
32+
gchatfmt.MakeAnnotation(6, 1, proto.FormatMetadata_STRIKE),
33+
gchatfmt.MakeAnnotation(8, 1, proto.FormatMetadata_UNDERLINE),
5034
},
5135
body: "a b i s u z",
5236
html: "a <strong>b</strong> <em>i</em> <del>s</del> <u>u</u> z",
@@ -55,7 +39,7 @@ func TestParse(t *testing.T) {
5539
name: "emoji",
5640
ins: "🎆 a b z",
5741
ine: []*proto.Annotation{
58-
makeAnnotation(5, 1, proto.FormatMetadata_BOLD),
42+
gchatfmt.MakeAnnotation(5, 1, proto.FormatMetadata_BOLD),
5943
},
6044
body: "🎆 a b z",
6145
html: "🎆 a <strong>b</strong> z",

pkg/msgconv/gchatfmt/utils.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package gchatfmt
2+
3+
import "go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
4+
5+
func MakeAnnotation(start, length int32, format proto.FormatMetadata_FormatType) *proto.Annotation {
6+
return &proto.Annotation{
7+
Type: proto.AnnotationType_FORMAT_DATA,
8+
StartIndex: start,
9+
Length: length,
10+
ChipRenderType: proto.Annotation_DO_NOT_RENDER,
11+
Metadata: &proto.Annotation_FormatMetadata{
12+
FormatMetadata: &proto.FormatMetadata{
13+
FormatType: format,
14+
},
15+
},
16+
}
17+
18+
}

pkg/msgconv/matrixfmt/convert.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package matrixfmt
2+
3+
import (
4+
"context"
5+
6+
"maunium.net/go/mautrix/event"
7+
8+
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
9+
)
10+
11+
func Parse(ctx context.Context, parser *HTMLParser, content *event.MessageEventContent) (string, []*proto.Annotation) {
12+
if content.Format != event.FormatHTML {
13+
return content.Body, nil
14+
}
15+
parseCtx := NewContext(ctx)
16+
parseCtx.AllowedMentions = content.Mentions
17+
parsed := parser.Parse(content.FormattedBody, parseCtx)
18+
if parsed == nil {
19+
return "", nil
20+
}
21+
var bodyRanges []*proto.Annotation
22+
if len(parsed.Entities) > 0 {
23+
bodyRanges = make([]*proto.Annotation, len(parsed.Entities))
24+
for i, ent := range parsed.Entities {
25+
bodyRanges[i] = ent.Proto()
26+
}
27+
}
28+
return parsed.String.String(), bodyRanges
29+
}

pkg/msgconv/matrixfmt/convert_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package matrixfmt_test
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"maunium.net/go/mautrix/event"
10+
11+
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
12+
"go.mau.fi/mautrix-googlechat/pkg/msgconv/gchatfmt"
13+
"go.mau.fi/mautrix-googlechat/pkg/msgconv/matrixfmt"
14+
)
15+
16+
func TestParse(t *testing.T) {
17+
tests := []struct {
18+
name string
19+
in string
20+
out string
21+
ent []*proto.Annotation
22+
}{
23+
{name: "Plain", in: "Hello, World!", out: "Hello, World!"},
24+
{name: "Bold", in: "a <strong>b</strong> c", out: "a b c",
25+
ent: []*proto.Annotation{
26+
gchatfmt.MakeAnnotation(2, 1, proto.FormatMetadata_BOLD),
27+
},
28+
},
29+
}
30+
31+
parser := &matrixfmt.HTMLParser{}
32+
matrixfmt.DebugLog = func(format string, args ...any) {
33+
fmt.Printf(format, args...)
34+
}
35+
36+
for _, test := range tests {
37+
t.Run(test.name, func(t *testing.T) {
38+
parsed, entities := matrixfmt.Parse(context.TODO(), parser, &event.MessageEventContent{
39+
Format: event.FormatHTML,
40+
FormattedBody: test.in,
41+
})
42+
assert.Equal(t, test.out, parsed)
43+
assert.Equal(t, test.ent, entities)
44+
})
45+
}
46+
}

0 commit comments

Comments
 (0)