aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTulir Asokan <tulir@maunium.net>2018-09-05 10:55:48 +0300
committerTulir Asokan <tulir@maunium.net>2018-09-05 10:55:48 +0300
commitcfb2cc057c32330be0ca0a68cfbd245cb2b8e31b (patch)
treef0d02d40d41091fd052582fe1fe701c80decf0d7
parent68db26bcace31297471641fe95f8882e301f5699 (diff)
Update to latest gomatrix. Things are broken
-rw-r--r--Gopkg.lock40
-rw-r--r--interface/matrix.go6
-rw-r--r--interface/ui.go8
-rw-r--r--matrix/matrix.go69
-rw-r--r--matrix/pushrules/condition.go19
-rw-r--r--matrix/pushrules/pushrules.go16
-rw-r--r--matrix/pushrules/rule.go3
-rw-r--r--matrix/rooms/member.go63
-rw-r--r--matrix/rooms/member_test.go17
-rw-r--r--matrix/rooms/room.go65
-rw-r--r--matrix/sync.go17
-rw-r--r--ui/commands.go5
-rw-r--r--ui/messages/base.go9
-rw-r--r--ui/messages/expandedtextmessage.go3
-rw-r--r--ui/messages/imagemessage.go3
-rw-r--r--ui/messages/parser/htmlparser.go9
-rw-r--r--ui/messages/parser/parser.go48
-rw-r--r--ui/messages/textmessage.go5
-rw-r--r--ui/room-view.go31
-rw-r--r--ui/view-main.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/LICENSE2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/bypass.go187
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/bypasssafe.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/common.go2
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/dump.go10
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/format.go4
-rw-r--r--vendor/github.com/disintegration/imaging/effects.go36
-rw-r--r--vendor/github.com/disintegration/imaging/helpers.go272
-rw-r--r--vendor/github.com/disintegration/imaging/io.go463
-rw-r--r--vendor/github.com/disintegration/imaging/tools.go34
-rw-r--r--vendor/github.com/lucasb-eyer/go-colorful/README.md33
-rw-r--r--vendor/github.com/lucasb-eyer/go-colorful/colors.go7
-rw-r--r--vendor/github.com/mattn/go-runewidth/runewidth.go14
-rw-r--r--vendor/github.com/renstrom/fuzzysearch/LICENSE2
-rw-r--r--vendor/github.com/renstrom/fuzzysearch/fuzzy/fuzzy.go5
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_format.go139
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl1
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_forward.go278
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl1
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertions.go214
-rw-r--r--vendor/github.com/stretchr/testify/assert/http_assertions.go22
-rw-r--r--vendor/github.com/zyedidia/clipboard/LICENSE4
-rw-r--r--vendor/github.com/zyedidia/clipboard/README.md4
-rw-r--r--vendor/golang.org/x/image/bmp/writer.go122
-rw-r--r--vendor/golang.org/x/net/html/parse.go103
-rw-r--r--vendor/gopkg.in/toast.v1/toast.go5
-rw-r--r--vendor/maunium.net/go/gomatrix/client.go145
-rw-r--r--vendor/maunium.net/go/gomatrix/events.go455
-rw-r--r--vendor/maunium.net/go/gomatrix/reply.go96
-rw-r--r--vendor/maunium.net/go/gomatrix/requests.go8
-rw-r--r--vendor/maunium.net/go/gomatrix/responses.go2
-rw-r--r--vendor/maunium.net/go/gomatrix/room.go20
-rw-r--r--vendor/maunium.net/go/gomatrix/sync.go15
-rw-r--r--vendor/maunium.net/go/maulogger/LICENSE21
-rw-r--r--vendor/maunium.net/go/maulogger/README.md6
-rw-r--r--vendor/maunium.net/go/maulogger/logger.go219
56 files changed, 2461 insertions, 930 deletions
diff --git a/Gopkg.lock b/Gopkg.lock
index 86d61b9..25c518f 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -4,14 +4,14 @@
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
- revision = "346938d642f2ec3594ed81d874461961cd0faa76"
- version = "v1.1.0"
+ revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
+ version = "v1.1.1"
[[projects]]
name = "github.com/disintegration/imaging"
packages = ["."]
- revision = "bbcee2f5c9d5e94ca42c8b50ec847fec64a6c134"
- version = "v1.4.2"
+ revision = "0bd5694c78c9c3d9a3cd06a706a8f3c59296a9ac"
+ version = "v1.5.0"
[[projects]]
branch = "master"
@@ -26,16 +26,16 @@
version = "v1.5.1"
[[projects]]
- branch = "master"
name = "github.com/lucasb-eyer/go-colorful"
packages = ["."]
- revision = "8abd3beca3a7f5039809449d6013a0254ac22bb1"
+ revision = "345fbb3dbcdb252d9985ee899a84963c0fa24c82"
+ version = "v1.0"
[[projects]]
name = "github.com/mattn/go-runewidth"
packages = ["."]
- revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
- version = "v0.0.2"
+ revision = "ce7b0b5c7b45a81508558cd1dba6bb1e4ddb51bb"
+ version = "v0.0.3"
[[projects]]
branch = "master"
@@ -50,10 +50,10 @@
version = "v1.0.0"
[[projects]]
- branch = "master"
name = "github.com/renstrom/fuzzysearch"
packages = ["fuzzy"]
- revision = "500e0fce37a81072d9bf4ec1bf5d32f52c807282"
+ revision = "b18e754edff4833912ef4dce9eaca885bd3f0de1"
+ version = "v1.0.1"
[[projects]]
branch = "master"
@@ -64,14 +64,14 @@
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert"]
- revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
- version = "v1.2.1"
+ revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
+ version = "v1.2.2"
[[projects]]
branch = "master"
name = "github.com/zyedidia/clipboard"
packages = ["."]
- revision = "4611e809d8b1a3051c11d11f4b610c44df73fa38"
+ revision = "bd31d747117d04b4e25b61f73e1ea4faeea3c56a"
[[projects]]
branch = "master"
@@ -85,7 +85,7 @@
"vp8l",
"webp"
]
- revision = "f315e440302883054d0c2bd85486878cb4f8572c"
+ revision = "c73c2afc3b812cdd6385de5a50616511c4a3d458"
[[projects]]
branch = "master"
@@ -94,7 +94,7 @@
"html",
"html/atom"
]
- revision = "dfa909b99c79129e1100513e5cd36307665e5723"
+ revision = "8a410e7b638dca158bf9e766925842f6651ff828"
[[projects]]
name = "golang.org/x/text"
@@ -118,7 +118,7 @@
branch = "v1"
name = "gopkg.in/toast.v1"
packages = ["."]
- revision = "b700e246b8b6d3e13554091e540e1019e26389f1"
+ revision = "0a84660828b24d25b35525c9a1f1f51267f8da91"
[[projects]]
name = "gopkg.in/yaml.v2"
@@ -130,7 +130,13 @@
branch = "master"
name = "maunium.net/go/gomatrix"
packages = ["."]
- revision = "b491397f18b90e34ef54b8b3598666564b90b01a"
+ revision = "d651abc3ecb4bbd85a6b17b710632e73ddbbc6aa"
+
+[[projects]]
+ name = "maunium.net/go/maulogger"
+ packages = ["."]
+ revision = "64f0aa33b6c51313e15575257db71dec44fe7988"
+ version = "v1.0"
[[projects]]
branch = "master"
diff --git a/interface/matrix.go b/interface/matrix.go
index 08b3d61..0538df9 100644
--- a/interface/matrix.go
+++ b/interface/matrix.go
@@ -33,14 +33,14 @@ type MatrixContainer interface {
Logout()
SendPreferencesToMatrix()
- SendMessage(roomID, msgtype, message string) (string, error)
- SendMarkdownMessage(roomID, msgtype, message string) (string, error)
+ SendMessage(roomID string, msgtype gomatrix.MessageType, message string) (string, error)
+ SendMarkdownMessage(roomID string, msgtype gomatrix.MessageType, message string) (string, error)
SendTyping(roomID string, typing bool)
MarkRead(roomID, eventID string)
JoinRoom(roomID, server string) (*rooms.Room, error)
LeaveRoom(roomID string) error
- GetHistory(roomID, prevBatch string, limit int) ([]gomatrix.Event, string, error)
+ GetHistory(roomID, prevBatch string, limit int) ([]*gomatrix.Event, string, error)
GetRoom(roomID string) *rooms.Room
Download(mxcURL string) ([]byte, string, string, error)
diff --git a/interface/ui.go b/interface/ui.go
index b106229..929dc65 100644
--- a/interface/ui.go
+++ b/interface/ui.go
@@ -73,8 +73,8 @@ type RoomView interface {
SetTyping(users []string)
UpdateUserList()
- NewMessage(id, sender, msgtype, text string, timestamp time.Time) Message
- NewTempMessage(msgtype, text string) Message
+ NewMessage(id, sender string, msgtype gomatrix.MessageType, text string, timestamp time.Time) Message
+ NewTempMessage(msgtype gomatrix.MessageType, text string) Message
AddMessage(message Message, direction MessageDirection)
AddServiceMessage(message string)
}
@@ -111,8 +111,8 @@ type Message interface {
SetID(id string)
ID() string
- SetType(msgtype string)
- Type() string
+ SetType(msgtype gomatrix.MessageType)
+ Type() gomatrix.MessageType
NotificationContent() string
diff --git a/matrix/matrix.go b/matrix/matrix.go
index 9b90ffe..060becd 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -175,6 +175,8 @@ func (c *Container) PushRules() *pushrules.PushRuleset {
return c.config.PushRules
}
+var AccountDataGomuksPreferences = gomatrix.NewEventType("net.maunium.gomuks.preferences")
+
// OnLogin initializes the syncer and updates the room list.
func (c *Container) OnLogin() {
c.ui.OnLogin()
@@ -183,14 +185,14 @@ func (c *Container) OnLogin() {
debug.Print("Initializing syncer")
c.syncer = NewGomuksSyncer(c.config)
- c.syncer.OnEventType("m.room.message", c.HandleMessage)
- c.syncer.OnEventType("m.room.member", c.HandleMembership)
- c.syncer.OnEventType("m.receipt", c.HandleReadReceipt)
- c.syncer.OnEventType("m.typing", c.HandleTyping)
- c.syncer.OnEventType("m.direct", c.HandleDirectChatInfo)
- c.syncer.OnEventType("m.push_rules", c.HandlePushRules)
- c.syncer.OnEventType("m.tag", c.HandleTag)
- c.syncer.OnEventType("net.maunium.gomuks.preferences", c.HandlePreferences)
+ c.syncer.OnEventType(gomatrix.EventMessage, c.HandleMessage)
+ c.syncer.OnEventType(gomatrix.StateMember, c.HandleMembership)
+ c.syncer.OnEventType(gomatrix.EphemeralEventReceipt, c.HandleReadReceipt)
+ c.syncer.OnEventType(gomatrix.EphemeralEventTyping, c.HandleTyping)
+ c.syncer.OnEventType(gomatrix.AccountDataDirectChats, c.HandleDirectChatInfo)
+ c.syncer.OnEventType(gomatrix.AccountDataPushRules, c.HandlePushRules)
+ c.syncer.OnEventType(gomatrix.AccountDataRoomTags, c.HandleTag)
+ c.syncer.OnEventType(AccountDataGomuksPreferences, c.HandlePreferences)
c.syncer.InitDoneCallback = func() {
c.config.AuthCache.InitialSyncDone = true
c.config.SaveAuthCache()
@@ -301,10 +303,10 @@ func (c *Container) HandleMembership(source EventSource, evt *gomatrix.Event) {
}
func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
- membership, _ := evt.Content["membership"].(string)
- prevMembership := "leave"
+ membership := evt.Content.Membership
+ prevMembership := gomatrix.MembershipLeave
if evt.Unsigned.PrevContent != nil {
- prevMembership, _ = evt.Unsigned.PrevContent["membership"].(string)
+ prevMembership = evt.Unsigned.PrevContent.Membership
}
debug.Printf("Processing own membership change: %s->%s in %s", prevMembership, membership, evt.RoomID)
if membership == prevMembership {
@@ -326,7 +328,7 @@ func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) {
func (c *Container) parseReadReceipt(evt *gomatrix.Event) (largestTimestampEvent string) {
var largestTimestamp int64
- for eventID, rawContent := range evt.Content {
+ for eventID, rawContent := range evt.Content.Raw {
content, ok := rawContent.(map[string]interface{})
if !ok {
continue
@@ -368,7 +370,7 @@ func (c *Container) HandleReadReceipt(source EventSource, evt *gomatrix.Event) {
func (c *Container) parseDirectChatInfo(evt *gomatrix.Event) map[*rooms.Room]bool {
directChats := make(map[*rooms.Room]bool)
- for _, rawRoomIDList := range evt.Content {
+ for _, rawRoomIDList := range evt.Content.Raw {
roomIDList, ok := rawRoomIDList.([]interface{})
if !ok {
continue
@@ -416,15 +418,12 @@ func (c *Container) HandlePushRules(source EventSource, evt *gomatrix.Event) {
func (c *Container) HandleTag(source EventSource, evt *gomatrix.Event) {
room := c.config.GetRoom(evt.RoomID)
- tags, _ := evt.Content["tags"].(map[string]interface{})
- newTags := make([]rooms.RoomTag, len(tags))
+ newTags := make([]rooms.RoomTag, len(evt.Content.RoomTags))
index := 0
- for tag, infoifc := range tags {
- info, _ := infoifc.(map[string]interface{})
+ for tag, info := range evt.Content.RoomTags {
order := "0.5"
- rawOrder, ok := info["order"]
- if ok {
- order = fmt.Sprintf("%v", rawOrder)
+ if len(info.Order) > 0 {
+ order = info.Order
}
newTags[index] = rooms.RoomTag{
Tag: tag,
@@ -440,13 +439,7 @@ func (c *Container) HandleTag(source EventSource, evt *gomatrix.Event) {
// HandleTyping is the event handler for the m.typing event.
func (c *Container) HandleTyping(source EventSource, evt *gomatrix.Event) {
- users := evt.Content["user_ids"].([]interface{})
-
- strUsers := make([]string, len(users))
- for i, user := range users {
- strUsers[i] = user.(string)
- }
- c.ui.MainView().SetTyping(evt.RoomID, strUsers)
+ c.ui.MainView().SetTyping(evt.RoomID, evt.Content.TypingUserIDs)
}
func (c *Container) MarkRead(roomID, eventID string) {
@@ -455,11 +448,11 @@ func (c *Container) MarkRead(roomID, eventID string) {
}
// SendMessage sends a message with the given text to the given room.
-func (c *Container) SendMessage(roomID, msgtype, text string) (string, error) {
+func (c *Container) SendMessage(roomID string, msgtype gomatrix.MessageType, text string) (string, error) {
defer debug.Recover()
c.SendTyping(roomID, false)
- resp, err := c.client.SendMessageEvent(roomID, "m.room.message",
- gomatrix.TextMessage{MsgType: msgtype, Body: text})
+ resp, err := c.client.SendMessageEvent(roomID, gomatrix.EventMessage,
+ gomatrix.Content{MsgType: msgtype, Body: text})
if err != nil {
return "", err
}
@@ -498,7 +491,7 @@ var roomRegex = regexp.MustCompile("\\[.+?]\\(https://matrix.to/#/(#.+?:[^/]+?)\
//
// If the given text contains markdown formatting symbols, it will be rendered into HTML before sending.
// Otherwise, it will be sent as plain text.
-func (c *Container) SendMarkdownMessage(roomID, msgtype, text string) (string, error) {
+func (c *Container) SendMarkdownMessage(roomID string, msgtype gomatrix.MessageType, text string) (string, error) {
defer debug.Recover()
html := c.renderMarkdown(text)
@@ -511,12 +504,12 @@ func (c *Container) SendMarkdownMessage(roomID, msgtype, text string) (string, e
text = roomRegex.ReplaceAllString(text, "$1")
c.SendTyping(roomID, false)
- resp, err := c.client.SendMessageEvent(roomID, "m.room.message",
- map[string]interface{}{
- "msgtype": msgtype,
- "body": text,
- "format": "org.matrix.custom.html",
- "formatted_body": html,
+ resp, err := c.client.SendMessageEvent(roomID, gomatrix.EventMessage,
+ gomatrix.Content{
+ MsgType: msgtype,
+ Body: text,
+ Format: gomatrix.FormatHTML,
+ FormattedBody: html,
})
if err != nil {
return "", err
@@ -567,7 +560,7 @@ func (c *Container) LeaveRoom(roomID string) error {
}
// GetHistory fetches room history.
-func (c *Container) GetHistory(roomID, prevBatch string, limit int) ([]gomatrix.Event, string, error) {
+func (c *Container) GetHistory(roomID, prevBatch string, limit int) ([]*gomatrix.Event, string, error) {
resp, err := c.client.Messages(roomID, prevBatch, "", 'b', limit)
if err != nil {
return nil, "", err
diff --git a/matrix/pushrules/condition.go b/matrix/pushrules/condition.go
index 08958a3..22d59aa 100644
--- a/matrix/pushrules/condition.go
+++ b/matrix/pushrules/condition.go
@@ -23,14 +23,13 @@ import (
"maunium.net/go/gomatrix"
"maunium.net/go/gomuks/lib/glob"
- "maunium.net/go/gomuks/matrix/rooms"
)
// Room is an interface with the functions that are needed for processing room-specific push conditions
type Room interface {
- GetMember(mxid string) *rooms.Member
- GetMembers() map[string]*rooms.Member
- GetSessionOwner() *rooms.Member
+ GetMember(mxid string) *gomatrix.Member
+ GetMembers() map[string]*gomatrix.Member
+ GetSessionOwner() string
}
// PushCondKind is the type of a push condition.
@@ -89,7 +88,7 @@ func (cond *PushCondition) matchValue(room Room, event *gomatrix.Event) bool {
switch key {
case "type":
- return pattern.MatchString(event.Type)
+ return pattern.MatchString(event.Type.String())
case "sender":
return pattern.MatchString(event.Sender)
case "room_id":
@@ -100,7 +99,7 @@ func (cond *PushCondition) matchValue(room Room, event *gomatrix.Event) bool {
}
return pattern.MatchString(*event.StateKey)
case "content":
- val, _ := event.Content[subkey].(string)
+ val, _ := event.Content.Raw[subkey].(string)
return pattern.MatchString(val)
default:
return false
@@ -108,12 +107,12 @@ func (cond *PushCondition) matchValue(room Room, event *gomatrix.Event) bool {
}
func (cond *PushCondition) matchDisplayName(room Room, event *gomatrix.Event) bool {
- member := room.GetSessionOwner()
- if member == nil || member.UserID == event.Sender {
+ ownerID := room.GetSessionOwner()
+ if ownerID == event.Sender {
return false
}
- text, _ := event.Content["body"].(string)
- return strings.Contains(text, member.DisplayName)
+ member := room.GetMember(ownerID)
+ return strings.Contains(event.Content.Body, member.Displayname)
}
func (cond *PushCondition) matchMemberCount(room Room, event *gomatrix.Event) bool {
diff --git a/matrix/pushrules/pushrules.go b/matrix/pushrules/pushrules.go
index 876713b..b383c66 100644
--- a/matrix/pushrules/pushrules.go
+++ b/matrix/pushrules/pushrules.go
@@ -21,19 +21,17 @@ func GetScopedPushRules(client *gomatrix.Client, scope string) (resp *PushRulese
return
}
+type contentWithRuleset struct {
+ Ruleset *PushRuleset `json:"global"`
+}
+
// EventToPushRules converts a m.push_rules event to a PushRuleset by passing the data through JSON.
func EventToPushRules(event *gomatrix.Event) (*PushRuleset, error) {
- content, _ := event.Content["global"]
- raw, err := json.Marshal(content)
- if err != nil {
- return nil, err
- }
-
- ruleset := &PushRuleset{}
- err = json.Unmarshal(raw, ruleset)
+ content := &contentWithRuleset{}
+ err := json.Unmarshal(event.Content.VeryRaw, content)
if err != nil {
return nil, err
}
- return ruleset, nil
+ return content.Ruleset, nil
}
diff --git a/matrix/pushrules/rule.go b/matrix/pushrules/rule.go
index 5ede895..71f71e5 100644
--- a/matrix/pushrules/rule.go
+++ b/matrix/pushrules/rule.go
@@ -154,6 +154,5 @@ func (rule *PushRule) matchPattern(room Room, event *gomatrix.Event) bool {
if err != nil {
return false
}
- text, _ := event.Content["body"].(string)
- return pattern.MatchString(text)
+ return pattern.MatchString(event.Content.Body)
}
diff --git a/matrix/rooms/member.go b/matrix/rooms/member.go
deleted file mode 100644
index aee7533..0000000
--- a/matrix/rooms/member.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// gomuks - A terminal Matrix client written in Go.
-// Copyright (C) 2018 Tulir Asokan
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package rooms
-
-import (
- "maunium.net/go/gomatrix"
-)
-
-// Membership is an enum specifying the membership state of a room member.
-type Membership string
-
-// The allowed membership states as specified in spec section 10.5.5.
-const (
- MembershipJoin Membership = "join"
- MembershipLeave Membership = "leave"
- MembershipInvite Membership = "invite"
- MembershipBan Membership = "ban"
- MembershipKnock Membership = "knock"
-)
-
-// Member represents a member in a room.
-type Member struct {
- // The MXID of the member.
- UserID string `json:"-"`
- // The membership status. Defaults to leave.
- Membership Membership `json:"membership"`
- // The display name of the user. Defaults to the user ID.
- DisplayName string `json:"displayname"`
- // The avatar URL of the user. Defaults to an empty string.
- AvatarURL string `json:"avatar_url"`
-}
-
-// eventToRoomMember converts a m.room.member state event into a Member object.
-func eventToRoomMember(userID string, event *gomatrix.Event) *Member {
- membership, _ := event.Content["membership"].(string)
- avatarURL, _ := event.Content["avatar_url"].(string)
-
- displayName, _ := event.Content["displayname"].(string)
- if len(displayName) == 0 {
- displayName = userID
- }
-
- return &Member{
- UserID: userID,
- Membership: Membership(membership),
- DisplayName: displayName,
- AvatarURL: avatarURL,
- }
-}
diff --git a/matrix/rooms/member_test.go b/matrix/rooms/member_test.go
deleted file mode 100644
index c3a4cfe..0000000
--- a/matrix/rooms/member_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// gomuks - A terminal Matrix client written in Go.
-// Copyright (C) 2018 Tulir Asokan
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package rooms_test
diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go
index 598f0ea..bd233f8 100644
--- a/matrix/rooms/room.go
+++ b/matrix/rooms/room.go
@@ -82,10 +82,10 @@ type Room struct {
LastReceivedMessage time.Time
// MXID -> Member cache calculated from membership events.
- memberCache map[string]*Member
+ memberCache map[string]*gomatrix.Member
// The first non-SessionUserID member in the room. Calculated at
// the same time as memberCache.
- firstMemberCache *Member
+ firstMemberCache *gomatrix.Member
// The name of the room. Calculated from the state event name,
// canonical_alias or alias or the member cache.
nameCache string
@@ -222,25 +222,25 @@ func (room *Room) UpdateState(event *gomatrix.Event) {
room.State[event.Type] = make(map[string]*gomatrix.Event)
}
switch event.Type {
- case "m.room.name":
+ case gomatrix.StateRoomName:
room.nameCache = ""
- case "m.room.canonical_alias":
+ case gomatrix.StateCanonicalAlias:
if room.nameCacheSource >= CanonicalAliasRoomName {
room.nameCache = ""
}
room.canonicalAliasCache = ""
- case "m.room.aliases":
+ case gomatrix.StateAliases:
if room.nameCacheSource >= AliasRoomName {
room.nameCache = ""
}
room.aliasesCache = nil
- case "m.room.member":
+ case gomatrix.StateMember:
room.memberCache = nil
room.firstMemberCache = nil
if room.nameCacheSource >= MemberRoomName {
room.nameCache = ""
}
- case "m.room.topic":
+ case gomatrix.StateTopic:
room.topicCache = ""
}
@@ -248,7 +248,7 @@ func (room *Room) UpdateState(event *gomatrix.Event) {
if event.StateKey != nil {
stateKey = *event.StateKey
}
- if event.Type != "m.room.member" {
+ if event.Type != gomatrix.StateMember {
debug.Printf("Updating state %s#%s for %s", event.Type, stateKey, room.ID)
}
@@ -260,14 +260,14 @@ func (room *Room) UpdateState(event *gomatrix.Event) {
}
// GetStateEvent returns the state event for the given type/state_key combo, or nil.
-func (room *Room) GetStateEvent(eventType string, stateKey string) *gomatrix.Event {
+func (room *Room) GetStateEvent(eventType gomatrix.EventType, stateKey string) *gomatrix.Event {
stateEventMap, _ := room.State[eventType]
event, _ := stateEventMap[stateKey]
return event
}
// GetStateEvents returns the state events for the given type.
-func (room *Room) GetStateEvents(eventType string) map[string]*gomatrix.Event {
+func (room *Room) GetStateEvents(eventType gomatrix.EventType) map[string]*gomatrix.Event {
stateEventMap, _ := room.State[eventType]
return stateEventMap
}
@@ -275,9 +275,9 @@ func (room *Room) GetStateEvents(eventType string) map[string]*gomatrix.Event {
// GetTopic returns the topic of the room.
func (room *Room) GetTopic() string {
if len(room.topicCache) == 0 {
- topicEvt := room.GetStateEvent("m.room.topic", "")
+ topicEvt := room.GetStateEvent(gomatrix.StateTopic, "")
if topicEvt != nil {
- room.topicCache, _ = topicEvt.Content["topic"].(string)
+ room.topicCache = topicEvt.Content.Topic
}
}
return room.topicCache
@@ -285,9 +285,9 @@ func (room *Room) GetTopic() string {
func (room *Room) GetCanonicalAlias() string {
if len(room.canonicalAliasCache) == 0 {
- canonicalAliasEvt := room.GetStateEvent("m.room.canonical_alias", "")
+ canonicalAliasEvt := room.GetStateEvent(gomatrix.StateCanonicalAlias, "")
if canonicalAliasEvt != nil {
- room.canonicalAliasCache, _ = canonicalAliasEvt.Content["alias"].(string)
+ room.canonicalAliasCache = canonicalAliasEvt.Content.Alias
} else {
room.canonicalAliasCache = "-"
}
@@ -301,17 +301,10 @@ func (room *Room) GetCanonicalAlias() string {
// GetAliases returns the list of aliases that point to this room.
func (room *Room) GetAliases() []string {
if room.aliasesCache == nil {
- aliasEvents := room.GetStateEvents("m.room.aliases")
+ aliasEvents := room.GetStateEvents(gomatrix.StateAliases)
room.aliasesCache = []string{}
for _, event := range aliasEvents {
- aliases, _ := event.Content["aliases"].([]interface{})
-
- newAliases := make([]string, len(room.aliasesCache)+len(aliases))
- copy(newAliases, room.aliasesCache)
- for index, alias := range aliases {
- newAliases[len(room.aliasesCache)+index], _ = alias.(string)
- }
- room.aliasesCache = newAliases
+ room.aliasesCache = append(room.aliasesCache, event.Content.Aliases...)
}
}
return room.aliasesCache
@@ -319,9 +312,9 @@ func (room *Room) GetAliases() []string {
// updateNameFromNameEvent updates the room display name to be the name set in the name event.
func (room *Room) updateNameFromNameEvent() {
- nameEvt := room.GetStateEvent("m.room.name", "")
+ nameEvt := room.GetStateEvent(gomatrix.StateRoomName, "")
if nameEvt != nil {
- room.nameCache, _ = nameEvt.Content["name"].(string)
+ room.nameCache = nameEvt.Content.Name
}
}
@@ -353,9 +346,9 @@ func (room *Room) updateNameFromMembers() {
} else if room.firstMemberCache == nil {
room.nameCache = "Room"
} else if len(members) == 2 {
- room.nameCache = room.firstMemberCache.DisplayName
+ room.nameCache = room.firstMemberCache.Displayname
} else {
- firstMember := room.firstMemberCache.DisplayName
+ firstMember := room.firstMemberCache.Displayname
room.nameCache = fmt.Sprintf("%s and %d others", firstMember, len(members)-2)
}
}
@@ -391,18 +384,18 @@ func (room *Room) GetTitle() string {
}
// createMemberCache caches all member events into a easily processable MXID -> *Member map.
-func (room *Room) createMemberCache() map[string]*Member {
- cache := make(map[string]*Member)
- events := room.GetStateEvents("m.room.member")
+func (room *Room) createMemberCache() map[string]*gomatrix.Member {
+ cache := make(map[string]*gomatrix.Member)
+ events := room.GetStateEvents(gomatrix.StateMember)
room.firstMemberCache = nil
if events != nil {
for userID, event := range events {
- member := eventToRoomMember(userID, event)
+ member := &event.Content.Member
if room.firstMemberCache == nil && userID != room.SessionUserID {
room.firstMemberCache = member
}
if member.Membership != "leave" {
- cache[member.UserID] = member
+ cache[userID] = member
}
}
}
@@ -414,7 +407,7 @@ func (room *Room) createMemberCache() map[string]*Member {
//
// The members are returned from the cache.
// If the cache is empty, it is updated first.
-func (room *Room) GetMembers() map[string]*Member {
+func (room *Room) GetMembers() map[string]*gomatrix.Member {
if len(room.memberCache) == 0 || room.firstMemberCache == nil {
room.createMemberCache()
}
@@ -423,7 +416,7 @@ func (room *Room) GetMembers() map[string]*Member {
// GetMember returns the member with the given MXID.
// If the member doesn't exist, nil is returned.
-func (room *Room) GetMember(userID string) *Member {
+func (room *Room) GetMember(userID string) *gomatrix.Member {
if len(room.memberCache) == 0 {
room.createMemberCache()
}
@@ -432,8 +425,8 @@ func (room *Room) GetMember(userID string) *Member {
}
// GetSessionOwner returns the Member instance of the user whose session this room was created for.
-func (room *Room) GetSessionOwner() *Member {
- return room.GetMember(room.SessionUserID)
+func (room *Room) GetSessionOwner() string {
+ return room.SessionUserID
}
// NewRoom creates a new Room with the given ID
diff --git a/matrix/sync.go b/matrix/sync.go
index 2037fcd..6d5def7 100644
--- a/matrix/sync.go
+++ b/matrix/sync.go
@@ -51,7 +51,7 @@ type EventHandler func(source EventSource, event *gomatrix.Event)
// pattern to notify callers about incoming events. See GomuksSyncer.OnEventType for more information.
type GomuksSyncer struct {
Session SyncerSession
- listeners map[string][]EventHandler // event type to listeners array
+ listeners map[gomatrix.EventType][]EventHandler // event type to listeners array
FirstSyncDone bool
InitDoneCallback func()
}
@@ -60,7 +60,7 @@ type GomuksSyncer struct {
func NewGomuksSyncer(session SyncerSession) *GomuksSyncer {
return &GomuksSyncer{
Session: session,
- listeners: make(map[string][]EventHandler),
+ listeners: make(map[gomatrix.EventType][]EventHandler),
FirstSyncDone: false,
}
}
@@ -114,20 +114,11 @@ func (s *GomuksSyncer) processSyncEvents(room *rooms.Room, events []*gomatrix.Ev
}
}
-func isState(event *gomatrix.Event) bool {
- switch event.Type {
- case "m.room.member", "m.room.name", "m.room.topic", "m.room.aliases", "m.room.canonical_alias":
- return true
- default:
- return false
- }
-}
-
func (s *GomuksSyncer) processSyncEvent(room *rooms.Room, event *gomatrix.Event, source EventSource) {
if room != nil {
event.RoomID = room.ID
}
- if isState(event) {
+ if event.Type.Class == gomatrix.StateEventType {
room.UpdateState(event)
}
s.notifyListeners(source, event)
@@ -135,7 +126,7 @@ func (s *GomuksSyncer) processSyncEvent(room *rooms.Room, event *gomatrix.Event,
// OnEventType allows callers to be notified when there are new events for the given event type.
// There are no duplicate checks.
-func (s *GomuksSyncer) OnEventType(eventType string, callback EventHandler) {
+func (s *GomuksSyncer) OnEventType(eventType gomatrix.EventType, callback EventHandler) {
_, exists := s.listeners[eventType]
if !exists {
s.listeners[eventType] = []EventHandler{}
diff --git a/ui/commands.go b/ui/commands.go
index 2827666..b80fa07 100644
--- a/ui/commands.go
+++ b/ui/commands.go
@@ -19,6 +19,7 @@ package ui
import (
"encoding/json"
"fmt"
+ "maunium.net/go/gomatrix"
"strings"
"unicode"
@@ -132,7 +133,7 @@ func cmdSendEvent(cmd *Command) {
return
}
roomID := cmd.Args[0]
- eventType := cmd.Args[1]
+ eventType := gomatrix.NewEventType(cmd.Args[1])
rawContent := strings.Join(cmd.Args[2:], "")
debug.Print(roomID, eventType, rawContent)
@@ -161,7 +162,7 @@ func cmdSetState(cmd *Command) {
}
roomID := cmd.Args[0]
- eventType := cmd.Args[1]
+ eventType := gomatrix.NewEventType(cmd.Args[1])
stateKey := cmd.Args[2]
if stateKey == "-" {
stateKey = ""
diff --git a/ui/messages/base.go b/ui/messages/base.go
index 6049ae3..c9da389 100644
--- a/ui/messages/base.go
+++ b/ui/messages/base.go
@@ -18,6 +18,7 @@ package messages
import (
"encoding/gob"
+ "maunium.net/go/gomatrix"
"time"
"maunium.net/go/gomuks/config"
@@ -33,7 +34,7 @@ func init() {
type BaseMessage struct {
MsgID string
- MsgType string
+ MsgType gomatrix.MessageType
MsgSenderID string
MsgSender string
MsgSenderColor tcell.Color
@@ -47,7 +48,7 @@ type BaseMessage struct {
prevPrefs config.UserPreferences
}
-func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage {
+func newBaseMessage(id, sender, displayname string, msgtype gomatrix.MessageType, timestamp time.Time) BaseMessage {
return BaseMessage{
MsgSenderID: sender,
MsgSender: displayname,
@@ -194,11 +195,11 @@ func (msg *BaseMessage) SetID(id string) {
msg.MsgID = id
}
-func (msg *BaseMessage) Type() string {
+func (msg *BaseMessage) Type() gomatrix.MessageType {
return msg.MsgType
}
-func (msg *BaseMessage) SetType(msgtype string) {
+func (msg *BaseMessage) SetType(msgtype gomatrix.MessageType) {
msg.MsgType = msgtype
}
diff --git a/ui/messages/expandedtextmessage.go b/ui/messages/expandedtextmessage.go
index c69f3dc..2e77a24 100644
--- a/ui/messages/expandedtextmessage.go
+++ b/ui/messages/expandedtextmessage.go
@@ -18,6 +18,7 @@ package messages
import (
"encoding/gob"
+ "maunium.net/go/gomatrix"
"time"
"maunium.net/go/gomuks/config"
@@ -34,7 +35,7 @@ type ExpandedTextMessage struct {
}
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
-func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
+func NewExpandedTextMessage(id, sender, displayname string, msgtype gomatrix.MessageType, text tstring.TString, timestamp time.Time) UIMessage {
return &ExpandedTextMessage{
BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
MsgText: text,
diff --git a/ui/messages/imagemessage.go b/ui/messages/imagemessage.go
index dcbe1c5..a17c842 100644
--- a/ui/messages/imagemessage.go
+++ b/ui/messages/imagemessage.go
@@ -20,6 +20,7 @@ import (
"bytes"
"encoding/gob"
"fmt"
+ "maunium.net/go/gomatrix"
"time"
"image/color"
@@ -47,7 +48,7 @@ type ImageMessage struct {
}
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
-func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, body, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
+func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname string, msgtype gomatrix.MessageType, body, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
return &ImageMessage{
newBaseMessage(id, sender, displayname, msgtype, timestamp),
body,
diff --git a/ui/messages/parser/htmlparser.go b/ui/messages/parser/htmlparser.go
index c8b000e..bcde14d 100644
--- a/ui/messages/parser/htmlparser.go
+++ b/ui/messages/parser/htmlparser.go
@@ -22,6 +22,7 @@ import (
"regexp"
"strings"
+ "github.com/lucasb-eyer/go-colorful"
"golang.org/x/net/html"
"maunium.net/go/gomatrix"
"maunium.net/go/gomuks/matrix/rooms"
@@ -29,7 +30,6 @@ import (
"maunium.net/go/gomuks/ui/widget"
"maunium.net/go/tcell"
"strconv"
- "github.com/lucasb-eyer/go-colorful"
)
var matrixToURL = regexp.MustCompile("^(?:https?://)?(?:www\\.)?matrix\\.to/#/([#@!].*)")
@@ -173,7 +173,7 @@ func (parser *htmlParser) linkToTString(node *html.Node, stripLinebreak bool) ts
pillTarget := match[1]
if pillTarget[0] == '@' {
if member := parser.room.GetMember(pillTarget); member != nil {
- return tstring.NewColorTString(member.DisplayName, widget.GetHashColor(member.UserID))
+ return tstring.NewColorTString(member.Displayname, widget.GetHashColor(pillTarget))
}
}
return tstring.NewTString(pillTarget)
@@ -271,14 +271,13 @@ func (parser *htmlParser) Parse(htmlData string) tstring.TString {
// ParseHTMLMessage parses a HTML-formatted Matrix event into a UIMessage.
func ParseHTMLMessage(room *rooms.Room, evt *gomatrix.Event, senderDisplayname string) tstring.TString {
- htmlData, _ := evt.Content["formatted_body"].(string)
+ htmlData := evt.Content.FormattedBody
htmlData = strings.Replace(htmlData, "\t", " ", -1)
parser := htmlParser{room}
str := parser.Parse(htmlData)
- msgtype, _ := evt.Content["msgtype"].(string)
- if msgtype == "m.emote" {
+ if evt.Content.MsgType == gomatrix.MsgEmote {
str = tstring.Join([]tstring.TString{
tstring.NewTString("* "),
tstring.NewColorTString(senderDisplayname, widget.GetHashColor(evt.Sender)),
diff --git a/ui/messages/parser/parser.go b/ui/messages/parser/parser.go
index c84a7f4..1d7ced3 100644
--- a/ui/messages/parser/parser.go
+++ b/ui/messages/parser/parser.go
@@ -33,9 +33,9 @@ import (
func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Event) messages.UIMessage {
switch evt.Type {
- case "m.room.message":
+ case gomatrix.EventMessage:
return ParseMessage(matrix, room, evt)
- case "m.room.member":
+ case gomatrix.StateMember:
return ParseMembershipEvent(room, evt)
}
return nil
@@ -53,32 +53,28 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
displayname := evt.Sender
member := room.GetMember(evt.Sender)
if member != nil {
- displayname = member.DisplayName
+ displayname = member.Displayname
}
- msgtype, _ := evt.Content["msgtype"].(string)
- text, _ := evt.Content["body"].(string)
ts := unixToTime(evt.Timestamp)
- switch msgtype {
+ switch evt.Content.MsgType {
case "m.text", "m.notice", "m.emote":
- format, hasFormat := evt.Content["format"].(string)
- if hasFormat && format == "org.matrix.custom.html" {
+ if evt.Content.Format == gomatrix.FormatHTML {
text := ParseHTMLMessage(room, evt, displayname)
- return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
+ return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, evt.Content.MsgType, text, ts)
}
- text = strings.Replace(text, "\t", " ", -1)
- return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
+ evt.Content.Body = strings.Replace(evt.Content.Body, "\t", " ", -1)
+ return messages.NewTextMessage(evt.ID, evt.Sender, displayname, evt.Content.MsgType, evt.Content.Body, ts)
case "m.image":
- url, _ := evt.Content["url"].(string)
- data, hs, id, err := matrix.Download(url)
+ data, hs, id, err := matrix.Download(evt.Content.URL)
if err != nil {
- debug.Printf("Failed to download %s: %v", url, err)
+ debug.Printf("Failed to download %s: %v", evt.Content.URL, err)
}
- return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, text, hs, id, data, ts)
+ return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, evt.Content.MsgType, evt.Content.Body, hs, id, data, ts)
}
return nil
}
-func getMembershipChangeMessage(evt *gomatrix.Event, membership, prevMembership, senderDisplayname, displayname, prevDisplayname string) (sender string, text tstring.TString) {
+func getMembershipChangeMessage(evt *gomatrix.Event, membership, prevMembership gomatrix.Membership, senderDisplayname, displayname, prevDisplayname string) (sender string, text tstring.TString) {
switch membership {
case "invite":
sender = "---"
@@ -92,12 +88,11 @@ func getMembershipChangeMessage(evt *gomatrix.Event, membership, prevMembership,
case "leave":
sender = "<--"
if evt.Sender != *evt.StateKey {
- if prevMembership == "ban" {
+ if prevMembership == gomatrix.MembershipBan {
text = tstring.NewColorTString(fmt.Sprintf("%s unbanned %s", senderDisplayname, displayname), tcell.ColorGreen)
text.Colorize(len(senderDisplayname)+len(" unbanned "), len(displayname), widget.GetHashColor(*evt.StateKey))
} else {
- reason, _ := evt.Content["reason"].(string)
- text = tstring.NewColorTString(fmt.Sprintf("%s kicked %s: %s", senderDisplayname, displayname, reason), tcell.ColorRed)
+ text = tstring.NewColorTString(fmt.Sprintf("%s kicked %s: %s", senderDisplayname, displayname, evt.Content.Reason), tcell.ColorRed)
text.Colorize(len(senderDisplayname)+len(" kicked "), len(displayname), widget.GetHashColor(*evt.StateKey))
}
text.Colorize(0, len(senderDisplayname), widget.GetHashColor(evt.Sender))
@@ -109,8 +104,7 @@ func getMembershipChangeMessage(evt *gomatrix.Event, membership, prevMembership,
text.Colorize(0, len(displayname), widget.GetHashColor(*evt.StateKey))
}
case "ban":
- reason, _ := evt.Content["reason"].(string)
- text = tstring.NewColorTString(fmt.Sprintf("%s banned %s: %s", senderDisplayname, displayname, reason), tcell.ColorRed)
+ text = tstring.NewColorTString(fmt.Sprintf("%s banned %s: %s", senderDisplayname, displayname, evt.Content.Reason), tcell.ColorRed)
text.Colorize(len(senderDisplayname)+len(" banned "), len(displayname), widget.GetHashColor(*evt.StateKey))
text.Colorize(0, len(senderDisplayname), widget.GetHashColor(evt.Sender))
}
@@ -121,20 +115,20 @@ func getMembershipEventContent(room *rooms.Room, evt *gomatrix.Event) (sender st
member := room.GetMember(evt.Sender)
senderDisplayname := evt.Sender
if member != nil {
- senderDisplayname = member.DisplayName
+ senderDisplayname = member.Displayname
}
- membership, _ := evt.Content["membership"].(string)
- displayname, _ := evt.Content["displayname"].(string)
+ membership := evt.Content.Membership
+ displayname := evt.Content.Displayname
if len(displayname) == 0 {
displayname = *evt.StateKey
}
- prevMembership := "leave"
+ prevMembership := gomatrix.MembershipLeave
prevDisplayname := *evt.StateKey
if evt.Unsigned.PrevContent != nil {
- prevMembership, _ = evt.Unsigned.PrevContent["membership"].(string)
- prevDisplayname, _ = evt.Unsigned.PrevContent["displayname"].(string)
+ prevMembership = evt.Unsigned.PrevContent.Membership
+ prevDisplayname = evt.Unsigned.PrevContent.Displayname
if len(prevDisplayname) == 0 {
prevDisplayname = *evt.StateKey
}
diff --git a/ui/messages/textmessage.go b/ui/messages/textmessage.go
index d268688..d5ce324 100644
--- a/ui/messages/textmessage.go
+++ b/ui/messages/textmessage.go
@@ -19,6 +19,7 @@ package messages
import (
"encoding/gob"
"fmt"
+ "maunium.net/go/gomatrix"
"time"
"maunium.net/go/gomuks/config"
@@ -37,7 +38,7 @@ type TextMessage struct {
}
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
-func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage {
+func NewTextMessage(id, sender, displayname string, msgtype gomatrix.MessageType, text string, timestamp time.Time) UIMessage {
return &TextMessage{
BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
MsgText: text,
@@ -57,7 +58,7 @@ func (msg *TextMessage) getCache() tstring.TString {
return msg.cache
}
-func (msg *TextMessage) SetType(msgtype string) {
+func (msg *TextMessage) SetType(msgtype gomatrix.MessageType) {
msg.BaseMessage.SetType(msgtype)
msg.cache = nil
}
diff --git a/ui/room-view.go b/ui/room-view.go
index bb8f5ec..4b2cd48 100644
--- a/ui/room-view.go
+++ b/ui/room-view.go
@@ -18,6 +18,7 @@ package ui
import (
"fmt"
+ "maunium.net/go/gomatrix"
"path/filepath"
"sort"
"strconv"
@@ -242,7 +243,7 @@ func (view *RoomView) SetTyping(users []string) {
for index, user := range users {
member := view.Room.GetMember(user)
if member != nil {
- users[index] = member.DisplayName
+ users[index] = member.Displayname
}
}
view.typing = users
@@ -255,14 +256,14 @@ type completion struct {
func (view *RoomView) autocompleteUser(existingText string) (completions []completion) {
textWithoutPrefix := strings.TrimPrefix(existingText, "@")
- for _, user := range view.Room.GetMembers() {
- if user.DisplayName == textWithoutPrefix || user.UserID == existingText {
+ for userID, user := range view.Room.GetMembers() {
+ if user.Displayname == textWithoutPrefix || userID == existingText {
// Exact match, return that.
- return []completion{{user.DisplayName, user.UserID}}
+ return []completion{{user.Displayname, userID}}
}
- if strings.HasPrefix(user.DisplayName, textWithoutPrefix) || strings.HasPrefix(user.UserID, existingText) {
- completions = append(completions, completion{user.DisplayName, user.UserID})
+ if strings.HasPrefix(user.Displayname, textWithoutPrefix) || strings.HasPrefix(userID, existingText) {
+ completions = append(completions, completion{user.Displayname, userID})
}
}
return
@@ -330,12 +331,12 @@ func (view *RoomView) MxRoom() *rooms.Room {
func (view *RoomView) UpdateUserList() {
var joined strings.Builder
var invited strings.Builder
- for _, user := range view.Room.GetMembers() {
+ for userID, user := range view.Room.GetMembers() {
if user.Membership == "join" {
- joined.WriteString(widget.AddColor(user.DisplayName, widget.GetHashColorName(user.UserID)))
+ joined.WriteString(widget.AddColor(user.Displayname, widget.GetHashColorName(userID)))
joined.WriteRune('\n')
} else if user.Membership == "invite" {
- invited.WriteString(widget.AddColor(user.DisplayName, widget.GetHashColorName(user.UserID)))
+ invited.WriteString(widget.AddColor(user.Displayname, widget.GetHashColorName(userID)))
invited.WriteRune('\n')
}
}
@@ -346,26 +347,26 @@ func (view *RoomView) UpdateUserList() {
}
}
-func (view *RoomView) newUIMessage(id, sender, msgtype, text string, timestamp time.Time) messages.UIMessage {
+func (view *RoomView) newUIMessage(id, sender string, msgtype gomatrix.MessageType, text string, timestamp time.Time) messages.UIMessage {
member := view.Room.GetMember(sender)
displayname := sender
if member != nil {
- displayname = member.DisplayName
+ displayname = member.Displayname
}
msg := messages.NewTextMessage(id, sender, displayname, msgtype, text, timestamp)
return msg
}
-func (view *RoomView) NewMessage(id, sender, msgtype, text string, timestamp time.Time) ifc.Message {
+func (view *RoomView) NewMessage(id, sender string, msgtype gomatrix.MessageType, text string, timestamp time.Time) ifc.Message {
return view.newUIMessage(id, sender, msgtype, text, timestamp)
}
-func (view *RoomView) NewTempMessage(msgtype, text string) ifc.Message {
+func (view *RoomView) NewTempMessage(msgtype gomatrix.MessageType, text string) ifc.Message {
now := time.Now()
id := strconv.FormatInt(now.UnixNano(), 10)
sender := ""
- if ownerMember := view.Room.GetSessionOwner(); ownerMember != nil {
- sender = ownerMember.DisplayName
+ if ownerMember := view.Room.GetMember(view.Room.GetSessionOwner()); ownerMember != nil {
+ sender = ownerMember.Displayname
}
message := view.newUIMessage(id, sender, msgtype, text, now)
message.SetState(ifc.MessageStateSending)
diff --git a/ui/view-main.go b/ui/view-main.go
index f38043a..c5abb19 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -497,7 +497,7 @@ func (view *MainView) LoadHistory(room string) {
}
roomView.Room.PrevBatch = prevBatch
for _, evt := range history {
- message := view.ParseEvent(roomView, &evt)
+ message := view.ParseEvent(roomView, evt)
if message != nil {
roomView.AddMessage(message, ifc.PrependMessage)
}
diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE
index c836416..bc52e96 100644
--- a/vendor/github.com/davecgh/go-spew/LICENSE
+++ b/vendor/github.com/davecgh/go-spew/LICENSE
@@ -2,7 +2,7 @@ ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
-Permission to use, copy, modify, and distribute this software for any
+Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go
index 8a4a658..7929947 100644
--- a/vendor/github.com/davecgh/go-spew/spew/bypass.go
+++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go
@@ -16,7 +16,9 @@
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
-// +build !js,!appengine,!safe,!disableunsafe
+// Go versions prior to 1.4 are disabled because they use a different layout
+// for interfaces which make the implementation of unsafeReflectValue more complex.
+// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew
@@ -34,80 +36,49 @@ const (
ptrSize = unsafe.Sizeof((*byte)(nil))
)
+type flag uintptr
+
var (
- // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
- // internal reflect.Value fields. These values are valid before golang
- // commit ecccf07e7f9d which changed the format. The are also valid
- // after commit 82f48826c6c7 which changed the format again to mirror
- // the original format. Code in the init function updates these offsets
- // as necessary.
- offsetPtr = uintptr(ptrSize)
- offsetScalar = uintptr(0)
- offsetFlag = uintptr(ptrSize * 2)
-
- // flagKindWidth and flagKindShift indicate various bits that the
- // reflect package uses internally to track kind information.
- //
- // flagRO indicates whether or not the value field of a reflect.Value is
- // read-only.
- //
- // flagIndir indicates whether the value field of a reflect.Value is
- // the actual data or a pointer to the data.
- //
- // These values are valid before golang commit 90a7c3c86944 which
- // changed their positions. Code in the init function updates these
- // flags as necessary.
- flagKindWidth = uintptr(5)
- flagKindShift = uintptr(flagKindWidth - 1)
- flagRO = uintptr(1 << 0)
- flagIndir = uintptr(1 << 1)
+ // flagRO indicates whether the value field of a reflect.Value
+ // is read-only.
+ flagRO flag
+
+ // flagAddr indicates whether the address of the reflect.Value's
+ // value may be taken.
+ flagAddr flag
)
-func init() {
- // Older versions of reflect.Value stored small integers directly in the
- // ptr field (which is named val in the older versions). Versions
- // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
- // scalar for this purpose which unfortunately came before the flag
- // field, so the offset of the flag field is different for those
- // versions.
- //
- // This code constructs a new reflect.Value from a known small integer
- // and checks if the size of the reflect.Value struct indicates it has
- // the scalar field. When it does, the offsets are updated accordingly.
- vv := reflect.ValueOf(0xf00)
- if unsafe.Sizeof(vv) == (ptrSize * 4) {
- offsetScalar = ptrSize * 2
- offsetFlag = ptrSize * 3
- }
+// flagKindMask holds the bits that make up the kind
+// part of the flags field. In all the supported versions,
+// it is in the lower 5 bits.
+const flagKindMask = flag(0x1f)
- // Commit 90a7c3c86944 changed the flag positions such that the low
- // order bits are the kind. This code extracts the kind from the flags
- // field and ensures it's the correct type. When it's not, the flag
- // order has been changed to the newer format, so the flags are updated
- // accordingly.
- upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
- upfv := *(*uintptr)(upf)
- flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
- if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
- flagKindShift = 0
- flagRO = 1 << 5
- flagIndir = 1 << 6
-
- // Commit adf9b30e5594 modified the flags to separate the
- // flagRO flag into two bits which specifies whether or not the
- // field is embedded. This causes flagIndir to move over a bit
- // and means that flagRO is the combination of either of the
- // original flagRO bit and the new bit.
- //
- // This code detects the change by extracting what used to be
- // the indirect bit to ensure it's set. When it's not, the flag
- // order has been changed to the newer format, so the flags are
- // updated accordingly.
- if upfv&flagIndir == 0 {
- flagRO = 3 << 5
- flagIndir = 1 << 7
- }
+// Different versions of Go have used different
+// bit layouts for the flags type. This table
+// records the known combinations.
+var okFlags = []struct {
+ ro, addr flag
+}{{
+ // From Go 1.4 to 1.5
+ ro: 1 << 5,
+ addr: 1 << 7,
+}, {
+ // Up to Go tip.
+ ro: 1<<5 | 1<<6,
+ addr: 1 << 8,
+}}
+
+var flagValOffset = func() uintptr {
+ field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
+ if !ok {
+ panic("reflect.Value has no flag field")
}
+ return field.Offset
+}()
+
+// flagField returns a pointer to the flag field of a reflect.Value.
+func flagField(v *reflect.Value) *flag {
+ return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
@@ -119,34 +90,56 @@ func init() {
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
-func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
- indirects := 1
- vt := v.Type()
- upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
- rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
- if rvf&flagIndir != 0 {
- vt = reflect.PtrTo(v.Type())
- indirects++
- } else if offsetScalar != 0 {
- // The value is in the scalar field when it's not one of the
- // reference types.
- switch vt.Kind() {
- case reflect.Uintptr:
- case reflect.Chan:
- case reflect.Func:
- case reflect.Map:
- case reflect.Ptr:
- case reflect.UnsafePointer:
- default:
- upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
- offsetScalar)
- }
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+ if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
+ return v
}
+ flagFieldPtr := flagField(&v)
+ *flagFieldPtr &^= flagRO
+ *flagFieldPtr |= flagAddr
+ return v
+}
- pv := reflect.NewAt(vt, upv)
- rv = pv
- for i := 0; i < indirects; i++ {
- rv = rv.Elem()
+// Sanity checks against future reflect package changes
+// to the type or semantics of the Value.flag field.
+func init() {
+ field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
+ if !ok {
+ panic("reflect.Value has no flag field")
+ }
+ if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
+ panic("reflect.Value flag field has changed kind")
+ }
+ type t0 int
+ var t struct {
+ A t0
+ // t0 will have flagEmbedRO set.
+ t0
+ // a will have flagStickyRO set
+ a t0
+ }
+ vA := reflect.ValueOf(t).FieldByName("A")
+ va := reflect.ValueOf(t).FieldByName("a")
+ vt0 := reflect.ValueOf(t).FieldByName("t0")
+
+ // Infer flagRO from the difference between the flags
+ // for the (otherwise identical) fields in t.
+ flagPublic := *flagField(&vA)
+ flagWithRO := *flagField(&va) | *flagField(&vt0)
+ flagRO = flagPublic ^ flagWithRO
+
+ // Infer flagAddr from the difference between a value
+ // taken from a pointer and not.
+ vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
+ flagNoPtr := *flagField(&vA)
+ flagPtr := *flagField(&vPtrA)
+ flagAddr = flagNoPtr ^ flagPtr
+
+ // Check that the inferred flags tally with one of the known versions.
+ for _, f := range okFlags {
+ if flagRO == f.ro && flagAddr == f.addr {
+ return
+ }
}
- return rv
+ panic("reflect.Value read-only flag has changed semantics")
}
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
index 1fe3cf3..205c28d 100644
--- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
+++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
@@ -16,7 +16,7 @@
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
-// +build js appengine safe disableunsafe
+// +build js appengine safe disableunsafe !go1.4
package spew
diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go
index 7c519ff..1be8ce9 100644
--- a/vendor/github.com/davecgh/go-spew/spew/common.go
+++ b/vendor/github.com/davecgh/go-spew/spew/common.go
@@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
w.Write(closeParenBytes)
}
-// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
+// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go
index df1d582..f78d89f 100644
--- a/vendor/github.com/davecgh/go-spew/spew/dump.go
+++ b/vendor/github.com/davecgh/go-spew/spew/dump.go
@@ -35,16 +35,16 @@ var (
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
- cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
+ cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
- cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
+ cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
- cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
+ cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
)
// dumpState contains information about the state of a dump operation.
@@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
- case nilFound == true:
+ case nilFound:
d.w.Write(nilAngleBytes)
- case cycleFound == true:
+ case cycleFound:
d.w.Write(circularBytes)
default:
diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go
index c49875b..b04edb7 100644
--- a/vendor/github.com/davecgh/go-spew/spew/format.go
+++ b/vendor/github.com/davecgh/go-spew/spew/format.go
@@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
// Display dereferenced value.
switch {
- case nilFound == true:
+ case nilFound:
f.fs.Write(nilAngleBytes)
- case cycleFound == true:
+ case cycleFound:
f.fs.Write(circularShortBytes)
default:
diff --git a/vendor/github.com/disintegration/imaging/effects.go b/vendor/github.com/disintegration/imaging/effects.go
index b16781f..149cfeb 100644
--- a/vendor/github.com/disintegration/imaging/effects.go
+++ b/vendor/github.com/disintegration/imaging/effects.go
@@ -38,9 +38,13 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
parallel(0, src.h, func(ys <-chan int) {
scanLine := make([]uint8, src.w*4)
+ scanLineF := make([]float64, len(scanLine))
for y := range ys {
src.scan(0, y, src.w, y+1, scanLine)
- for x := 0; x < src.w; x++ {
+ for i, v := range scanLine {
+ scanLineF[i] = float64(v)
+ }
+ for x, idx := 0, 0; x < src.w; x, idx = x+1, idx+4 {
min := x - radius
if min < 0 {
min = 0
@@ -55,10 +59,10 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
i := ix * 4
weight := kernel[absint(x-ix)]
wsum += weight
- wa := float64(scanLine[i+3]) * weight
- r += float64(scanLine[i+0]) * wa
- g += float64(scanLine[i+1]) * wa
- b += float64(scanLine[i+2]) * wa
+ wa := scanLineF[i+3] * weight
+ r += scanLineF[i+0] * wa
+ g += scanLineF[i+1] * wa
+ b += scanLineF[i+2] * wa
a += wa
}
if a != 0 {
@@ -67,12 +71,12 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
b /= a
}
- j := y*dst.Stride + x*4
- dst.Pix[j+0] = clamp(r)
- dst.Pix[j+1] = clamp(g)
- dst.Pix[j+2] = clamp(b)
- dst.Pix[j+3] = clamp(a / wsum)
+ scanLine[idx+0] = clamp(r)
+ scanLine[idx+1] = clamp(g)
+ scanLine[idx+2] = clamp(b)
+ scanLine[idx+3] = clamp(a / wsum)
}
+ copy(dst.Pix[y*dst.Stride:], scanLine)
}
})
@@ -86,8 +90,12 @@ func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
parallel(0, src.w, func(xs <-chan int) {
scanLine := make([]uint8, src.h*4)
+ scanLineF := make([]float64, len(scanLine))
for x := range xs {
src.scan(x, 0, x+1, src.h, scanLine)
+ for i, v := range scanLine {
+ scanLineF[i] = float64(v)
+ }
for y := 0; y < src.h; y++ {
min := y - radius
if min < 0 {
@@ -103,10 +111,10 @@ func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
i := iy * 4
weight := kernel[absint(y-iy)]
wsum += weight
- wa := float64(scanLine[i+3]) * weight
- r += float64(scanLine[i+0]) * wa
- g += float64(scanLine[i+1]) * wa
- b += float64(scanLine[i+2]) * wa
+ wa := scanLineF[i+3] * weight
+ r += scanLineF[i+0] * wa
+ g += scanLineF[i+1] * wa
+ b += scanLineF[i+2] * wa
a += wa
}
if a != 0 {
diff --git a/vendor/github.com/disintegration/imaging/helpers.go b/vendor/github.com/disintegration/imaging/helpers.go
deleted file mode 100644
index dcb4d7e..0000000
--- a/vendor/github.com/disintegration/imaging/helpers.go
+++ /dev/null
@@ -1,272 +0,0 @@
-package imaging
-
-import (
- "bytes"
- "errors"
- "image"
- "image/color"
- "image/draw"
- "image/gif"
- "image/jpeg"
- "image/png"
- "io"
- "os"
- "path/filepath"
- "strings"
-
- "golang.org/x/image/bmp"
- "golang.org/x/image/tiff"
-)
-
-// Format is an image file format.
-type Format int
-
-// Image file formats.
-const (
- JPEG Format = iota
- PNG
- GIF
- TIFF
- BMP
-)
-
-func (f Format) String() string {
- switch f {
- case JPEG:
- return "JPEG"
- case PNG:
- return "PNG"
- case GIF:
- return "GIF"
- case TIFF:
- return "TIFF"
- case BMP:
- return "BMP"
- default:
- return "Unsupported"
- }
-}
-
-var formatFromExt = map[string]Format{
- ".jpg": JPEG,
- ".jpeg": JPEG,
- ".png": PNG,
- ".tif": TIFF,
- ".tiff": TIFF,
- ".bmp": BMP,
- ".gif": GIF,
-}
-
-// FormatFromFilename parses image format from filename extension:
-// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
-func FormatFromFilename(filename string) (Format, error) {
- ext := strings.ToLower(filepath.Ext(filename))
- if f, ok := formatFromExt[ext]; ok {
- return f, nil
- }
- return -1, ErrUnsupportedFormat
-}
-
-var (
- // ErrUnsupportedFormat means the given image format (or file extension) is unsupported.
- ErrUnsupportedFormat = errors.New("imaging: unsupported image format")
-)
-
-type fileSystem interface {
- Create(string) (io.WriteCloser, error)
- Open(string) (io.ReadCloser, error)
-}
-
-type localFS struct{}
-
-func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) }
-func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
-
-var fs fileSystem = localFS{}
-
-// Decode reads an image from r.
-func Decode(r io.Reader) (image.Image, error) {
- img, _, err := image.Decode(r)
- return img, err
-}
-
-// Open loads an image from file
-func Open(filename string) (image.Image, error) {
- file, err := fs.Open(filename)
- if err != nil {
- return nil, err
- }
- defer file.Close()
- return Decode(file)
-}
-
-type encodeConfig struct {
- jpegQuality int
- gifNumColors int
- gifQuantizer draw.Quantizer
- gifDrawer draw.Drawer
- pngCompressionLevel png.CompressionLevel
-}
-
-var defaultEncodeConfig = encodeConfig{
- jpegQuality: 95,
- gifNumColors: 256,
- gifQuantizer: nil,
- gifDrawer: nil,
- pngCompressionLevel: png.DefaultCompression,
-}
-
-// EncodeOption sets an optional parameter for the Encode and Save functions.
-type EncodeOption func(*encodeConfig)
-
-// JPEGQuality returns an EncodeOption that sets the output JPEG quality.
-// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95.
-func JPEGQuality(quality int) EncodeOption {
- return func(c *encodeConfig) {
- c.jpegQuality = quality
- }
-}
-
-// GIFNumColors returns an EncodeOption that sets the maximum number of colors
-// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256.
-func GIFNumColors(numColors int) EncodeOption {
- return func(c *encodeConfig) {
- c.gifNumColors = numColors
- }
-}
-
-// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
-// a palette of the GIF-encoded image.
-func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
- return func(c *encodeConfig) {
- c.gifQuantizer = quantizer
- }
-}
-
-// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
-// the source image to the desired palette of the GIF-encoded image.
-func GIFDrawer(drawer draw.Drawer) EncodeOption {
- return func(c *encodeConfig) {
- c.gifDrawer = drawer
- }
-}
-
-// PNGCompressionLevel returns an EncodeOption that sets the compression level
-// of the PNG-encoded image. Default is png.DefaultCompression.
-func PNGCompressionLevel(level png.CompressionLevel) EncodeOption {
- return func(c *encodeConfig) {
- c.pngCompressionLevel = level
- }
-}
-
-// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
-func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
- cfg := defaultEncodeConfig
- for _, option := range opts {
- option(&cfg)
- }
-
- var err error
- switch format {
- case JPEG:
- var rgba *image.RGBA
- if nrgba, ok := img.(*image.NRGBA); ok {
- if nrgba.Opaque() {
- rgba = &image.RGBA{
- Pix: nrgba.Pix,
- Stride: nrgba.Stride,
- Rect: nrgba.Rect,
- }
- }
- }
- if rgba != nil {
- err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality})
- } else {
- err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality})
- }
-
- case PNG:
- enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel}
- err = enc.Encode(w, img)
-
- case GIF:
- err = gif.Encode(w, img, &gif.Options{
- NumColors: cfg.gifNumColors,
- Quantizer: cfg.gifQuantizer,
- Drawer: cfg.gifDrawer,
- })
-
- case TIFF:
- err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
-
- case BMP:
- err = bmp.Encode(w, img)
-
- default:
- err = ErrUnsupportedFormat
- }
- return err
-}
-
-// Save saves the image to file with the specified filename.
-// The format is determined from the filename extension: "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
-//
-// Examples:
-//
-// // Save the image as PNG.
-// err := imaging.Save(img, "out.png")
-//
-// // Save the image as JPEG with optional quality parameter set to 80.
-// err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80))
-//
-func Save(img image.Image, filename string, opts ...EncodeOption) (err error) {
- f, err := FormatFromFilename(filename)
- if err != nil {
- return err
- }
- file, err := fs.Create(filename)
- if err != nil {
- return err
- }
-
- defer func() {
- cerr := file.Close()
- if err == nil {
- err = cerr
- }
- }()
-
- return Encode(file, img, f, opts...)
-}
-
-// New creates a new image with the specified width and height, and fills it with the specified color.
-func New(width, height int, fillColor color.Color) *image.NRGBA {
- if width <= 0 || height <= 0 {
- return &image.NRGBA{}
- }
-
- c := color.NRGBAModel.Convert(fillColor).(color.NRGBA)
- if (c == color.NRGBA{0, 0, 0, 0}) {
- return image.NewNRGBA(image.Rect(0, 0, width, height))
- }
-
- return &image.NRGBA{
- Pix: bytes.Repeat([]byte{c.R, c.G, c.B, c.A}, width*height),
- Stride: 4 * width,
- Rect: image.Rect(0, 0, width, height),
- }
-}
-
-// Clone returns a copy of the given image.
-func Clone(img image.Image) *image.NRGBA {
- src := newScanner(img)
- dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
- size := src.w * 4
- parallel(0, src.h, func(ys <-chan int) {
- for y := range ys {
- i := y * dst.Stride
- src.scan(0, y, src.w, y+1, dst.Pix[i:i+size])
- }
- })
- return dst
-}
diff --git a/vendor/github.com/disintegration/imaging/io.go b/vendor/github.com/disintegration/imaging/io.go
new file mode 100644
index 0000000..557bf2f
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/io.go
@@ -0,0 +1,463 @@
+package imaging
+
+import (
+ "encoding/binary"
+ "errors"
+ "image"
+ "image/draw"
+ "image/gif"
+ "image/jpeg"
+ "image/png"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/image/bmp"
+ "golang.org/x/image/tiff"
+)
+
+// Format is an image file format.
+type Format int
+
+// Image file formats.
+const (
+ JPEG Format = iota
+ PNG
+ GIF
+ TIFF
+ BMP
+)
+
+func (f Format) String() string {
+ switch f {
+ case JPEG:
+ return "JPEG"
+ case PNG:
+ return "PNG"
+ case GIF:
+ return "GIF"
+ case TIFF:
+ return "TIFF"
+ case BMP:
+ return "BMP"
+ default:
+ return "Unsupported"
+ }
+}
+
+var formatFromExt = map[string]Format{
+ "jpg": JPEG,
+ "jpeg": JPEG,
+ "png": PNG,
+ "tif": TIFF,
+ "tiff": TIFF,
+ "bmp": BMP,
+ "gif": GIF,
+}
+
+// FormatFromExtension parses image format from extension:
+// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
+func FormatFromExtension(ext string) (Format, error) {
+ if f, ok := formatFromExt[strings.ToLower(strings.TrimPrefix(ext, "."))]; ok {
+ return f, nil
+ }
+ return -1, ErrUnsupportedFormat
+}
+
+// FormatFromFilename parses image format from filename extension:
+// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
+func FormatFromFilename(filename string) (Format, error) {
+ ext := filepath.Ext(filename)
+ return FormatFromExtension(ext)
+}
+
+var (
+ // ErrUnsupportedFormat means the given image format (or file extension) is unsupported.
+ ErrUnsupportedFormat = errors.New("imaging: unsupported image format")
+)
+
+type fileSystem interface {
+ Create(string) (io.WriteCloser, error)
+ Open(string) (io.ReadCloser, error)
+}
+
+type localFS struct{}
+
+func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) }
+func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
+
+var fs fileSystem = localFS{}
+
+type decodeConfig struct {
+ autoOrientation bool
+}
+
+var defaultDecodeConfig = decodeConfig{
+ autoOrientation: false,
+}
+
+// DecodeOption sets an optional parameter for the Decode and Open functions.
+type DecodeOption func(*decodeConfig)
+
+// AutoOrientation returns a DecodeOption that sets the auto-orientation mode.
+// If auto-orientation is enabled, the image will be transformed after decoding
+// according to the EXIF orientation tag (if present). By default it's disabled.
+func AutoOrientation(enabled bool) DecodeOption {
+ return func(c *decodeConfig) {
+ c.autoOrientation = enabled
+ }
+}
+
+// Decode reads an image from r.
+func Decode(r io.Reader, opts ...DecodeOption) (image.Image, error) {
+ cfg := defaultDecodeConfig
+ for _, option := range opts {
+ option(&cfg)
+ }
+
+ if !cfg.autoOrientation {
+ img, _, err := image.Decode(r)
+ return img, err
+ }
+
+ var orient orientation
+ pr, pw := io.Pipe()
+ r = io.TeeReader(r, pw)
+ done := make(chan struct{})
+ go func() {
+ defer close(done)
+ orient = readOrientation(pr)
+ io.Copy(ioutil.Discard, pr)
+ }()
+
+ img, _, err := image.Decode(r)
+ pw.Close()
+ <-done
+ if err != nil {
+ return nil, err
+ }
+
+ return fixOrientation(img, orient), nil
+}
+
+// Open loads an image from file.
+//
+// Examples:
+//
+// // Load an image from file.
+// img, err := imaging.Open("test.jpg")
+//
+// // Load an image and transform it depending on the EXIF orientation tag (if present).
+// img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
+//
+func Open(filename string, opts ...DecodeOption) (image.Image, error) {
+ file, err := fs.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+ return Decode(file, opts...)
+}
+
+type encodeConfig struct {
+ jpegQuality int
+ gifNumColors int
+ gifQuantizer draw.Quantizer
+ gifDrawer draw.Drawer
+ pngCompressionLevel png.CompressionLevel
+}
+
+var defaultEncodeConfig = encodeConfig{
+ jpegQuality: 95,
+ gifNumColors: 256,
+ gifQuantizer: nil,
+ gifDrawer: nil,
+ pngCompressionLevel: png.DefaultCompression,
+}
+
+// EncodeOption sets an optional parameter for the Encode and Save functions.
+type EncodeOption func(*encodeConfig)
+
+// JPEGQuality returns an EncodeOption that sets the output JPEG quality.
+// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95.
+func JPEGQuality(quality int) EncodeOption {
+ return func(c *encodeConfig) {
+ c.jpegQuality = quality
+ }
+}
+
+// GIFNumColors returns an EncodeOption that sets the maximum number of colors
+// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256.
+func GIFNumColors(numColors int) EncodeOption {
+ return func(c *encodeConfig) {
+ c.gifNumColors = numColors
+ }
+}
+
+// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
+// a palette of the GIF-encoded image.
+func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
+ return func(c *encodeConfig) {
+ c.gifQuantizer = quantizer
+ }
+}
+
+// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
+// the source image to the desired palette of the GIF-encoded image.
+func GIFDrawer(drawer draw.Drawer) EncodeOption {
+ return func(c *encodeConfig) {
+ c.gifDrawer = drawer
+ }
+}
+
+// PNGCompressionLevel returns an EncodeOption that sets the compression level
+// of the PNG-encoded image. Default is png.DefaultCompression.
+func PNGCompressionLevel(level png.CompressionLevel) EncodeOption {
+ return func(c *encodeConfig) {
+ c.pngCompressionLevel = level
+ }
+}
+
+// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
+func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
+ cfg := defaultEncodeConfig
+ for _, option := range opts {
+ option(&cfg)
+ }
+
+ var err error
+ switch format {
+ case JPEG:
+ var rgba *image.RGBA
+ if nrgba, ok := img.(*image.NRGBA); ok {
+ if nrgba.Opaque() {
+ rgba = &image.RGBA{
+ Pix: nrgba.Pix,
+ Stride: nrgba.Stride,
+ Rect: nrgba.Rect,
+ }
+ }
+ }
+ if rgba != nil {
+ err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality})
+ } else {
+ err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality})
+ }
+
+ case PNG:
+ enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel}
+ err = enc.Encode(w, img)
+
+ case GIF:
+ err = gif.Encode(w, img, &gif.Options{
+ NumColors: cfg.gifNumColors,
+ Quantizer: cfg.gifQuantizer,
+ Drawer: cfg.gifDrawer,
+ })
+
+ case TIFF:
+ err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
+
+ case BMP:
+ err = bmp.Encode(w, img)
+
+ default:
+ err = ErrUnsupportedFormat
+ }
+ return err
+}
+
+// Save saves the image to file with the specified filename.
+// The format is determined from the filename extension:
+// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
+//
+// Examples:
+//
+// // Save the image as PNG.
+// err := imaging.Save(img, "out.png")
+//
+// // Save the image as JPEG with optional quality parameter set to 80.
+// err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80))
+//
+func Save(img image.Image, filename string, opts ...EncodeOption) (err error) {
+ f, err := FormatFromFilename(filename)
+ if err != nil {
+ return err
+ }
+ file, err := fs.Create(filename)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ cerr := file.Close()
+ if err == nil {
+ err = cerr
+ }
+ }()
+
+ return Encode(file, img, f, opts...)
+}
+
+// orientation is an EXIF flag that specifies the transformation
+// that should be applied to image to display it correctly.
+type orientation int
+
+const (
+ orientationUnspecified = 0
+ orientationNormal = 1
+ orientationFlipH = 2
+ orientationRotate180 = 3
+ orientationFlipV = 4
+ orientationTranspose = 5
+ orientationRotate270 = 6
+ orientationTransverse = 7
+ orientationRotate90 = 8
+)
+
+// readOrientation tries to read the orientation EXIF flag from image data in r.
+// If the EXIF data block is not found or the orientation flag is not found
+// or any other error occures while reading the data, it returns the
+// orientationUnspecified (0) value.
+func readOrientation(r io.Reader) orientation {
+ const (
+ markerSOI = 0xffd8
+ markerAPP1 = 0xffe1
+ exifHeader = 0x45786966
+ byteOrderBE = 0x4d4d
+ byteOrderLE = 0x4949
+ orientationTag = 0x0112
+ )
+
+ // Check if JPEG SOI marker is present.
+ var soi uint16
+ if err := binary.Read(r, binary.BigEndian, &soi); err != nil {
+ return orientationUnspecified
+ }
+ if soi != markerSOI {
+ return orientationUnspecified // Missing JPEG SOI marker.
+ }
+
+ // Find JPEG APP1 marker.
+ for {
+ var marker, size uint16
+ if err := binary.Read(r, binary.BigEndian, &marker); err != nil {
+ return orientationUnspecified
+ }
+ if err := binary.Read(r, binary.BigEndian, &size); err != nil {
+ return orientationUnspecified
+ }
+ if marker>>8 != 0xff {
+ return orientationUnspecified // Invalid JPEG marker.
+ }
+ if marker == markerAPP1 {
+ break
+ }
+ if size < 2 {
+ return orientationUnspecified // Invalid block size.
+ }
+ if _, err := io.CopyN(ioutil.Discard, r, int64(size-2)); err != nil {
+ return orientationUnspecified
+ }
+ }
+
+ // Check if EXIF header is present.
+ var header uint32
+ if err := binary.Read(r, binary.BigEndian, &header); err != nil {
+ return orientationUnspecified
+ }
+ if header != exifHeader {
+ return orientationUnspecified
+ }
+ if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil {
+ return orientationUnspecified
+ }
+
+ // Read byte order information.
+ var (
+ byteOrderTag uint16
+ byteOrder binary.ByteOrder
+ )
+ if err := binary.Read(r, binary.BigEndian, &byteOrderTag); err != nil {
+ return orientationUnspecified
+ }
+ switch byteOrderTag {
+ case byteOrderBE:
+ byteOrder = binary.BigEndian
+ case byteOrderLE:
+ byteOrder = binary.LittleEndian
+ default:
+ return orientationUnspecified // Invalid byte order flag.
+ }
+ if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil {
+ return orientationUnspecified
+ }
+
+ // Skip the EXIF offset.
+ var offset uint32
+ if err := binary.Read(r, byteOrder, &offset); err != nil {
+ return orientationUnspecified
+ }
+ if offset < 8 {
+ return orientationUnspecified // Invalid offset value.
+ }
+ if _, err := io.CopyN(ioutil.Discard, r, int64(offset-8)); err != nil {
+ return orientationUnspecified
+ }
+
+ // Read the number of tags.
+ var numTags uint16
+ if err := binary.Read(r, byteOrder, &numTags); err != nil {
+ return orientationUnspecified
+ }
+
+ // Find the orientation tag.
+ for i := 0; i < int(numTags); i++ {
+ var tag uint16
+ if err := binary.Read(r, byteOrder, &tag); err != nil {
+ return orientationUnspecified
+ }
+ if tag != orientationTag {
+ if _, err := io.CopyN(ioutil.Discard, r, 10); err != nil {
+ return orientationUnspecified
+ }
+ continue
+ }
+ if _, err := io.CopyN(ioutil.Discard, r, 6); err != nil {
+ return orientationUnspecified
+ }
+ var val uint16
+ if err := binary.Read(r, byteOrder, &val); err != nil {
+ return orientationUnspecified
+ }
+ if val < 1 || val > 8 {
+ return orientationUnspecified // Invalid tag value.
+ }
+ return orientation(val)
+ }
+ return orientationUnspecified // Missing orientation tag.
+}
+
+// fixOrientation applies a transform to img corresponding to the given orientation flag.
+func fixOrientation(img image.Image, o orientation) image.Image {
+ switch o {
+ case orientationNormal:
+ case orientationFlipH:
+ img = FlipH(img)
+ case orientationFlipV:
+ img = FlipV(img)
+ case orientationRotate90:
+ img = Rotate90(img)
+ case orientationRotate180:
+ img = Rotate180(img)
+ case orientationRotate270:
+ img = Rotate270(img)
+ case orientationTranspose:
+ img = Transpose(img)
+ case orientationTransverse:
+ img = Transverse(img)
+ }
+ return img
+}
diff --git a/vendor/github.com/disintegration/imaging/tools.go b/vendor/github.com/disintegration/imaging/tools.go
index fae1fa1..7887946 100644
--- a/vendor/github.com/disintegration/imaging/tools.go
+++ b/vendor/github.com/disintegration/imaging/tools.go
@@ -1,10 +1,44 @@
package imaging
import (
+ "bytes"
"image"
+ "image/color"
"math"
)
+// New creates a new image with the specified width and height, and fills it with the specified color.
+func New(width, height int, fillColor color.Color) *image.NRGBA {
+ if width <= 0 || height <= 0 {
+ return &image.NRGBA{}
+ }
+
+ c := color.NRGBAModel.Convert(fillColor).(color.NRGBA)
+ if (c == color.NRGBA{0, 0, 0, 0}) {
+ return image.NewNRGBA(image.Rect(0, 0, width, height))
+ }
+
+ return &image.NRGBA{
+ Pix: bytes.Repeat([]byte{c.R, c.G, c.B, c.A}, width*height),
+ Stride: 4 * width,
+ Rect: image.Rect(0, 0, width, height),
+ }
+}
+
+// Clone returns a copy of the given image.
+func Clone(img image.Image) *image.NRGBA {
+ src := newScanner(img)
+ dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
+ size := src.w * 4
+ parallel(0, src.h, func(ys <-chan int) {
+ for y := range ys {
+ i := y * dst.Stride
+ src.scan(0, y, src.w, y+1, dst.Pix[i:i+size])
+ }
+ })
+ return dst
+}
+
// Anchor is the anchor point for image alignment.
type Anchor int
diff --git a/vendor/github.com/lucasb-eyer/go-colorful/README.md b/vendor/github.com/lucasb-eyer/go-colorful/README.md
index c170435..8c89c38 100644
--- a/vendor/github.com/lucasb-eyer/go-colorful/README.md
+++ b/vendor/github.com/lucasb-eyer/go-colorful/README.md
@@ -124,17 +124,16 @@ Because a `colorful.Color` implements Go's `color.Color` interface (found in the
`image/color` package), it can be used anywhere that expects a `color.Color`.
Furthermore, you can convert anything that implements the `color.Color` interface
-into a `colorful.Color` using the `MakeColorful` function:
+into a `colorful.Color` using the `MakeColor` function:
```go
-c := colorful.MakeColor(color.Gray16{12345})
+c, ok := colorful.MakeColor(color.Gray16{12345})
```
-**Caveat:** Be aware that for this latter conversion (using `MakeColor`) hits a corner-case
-when alpha is exactly zero. Because `color.Color` uses pre-multiplied alpha colors,
-this means the RGB values are lost and it's impossible to recover them. The current
-implementation `panic()`s in that case, see [issue 21](https://github.com/lucasb-eyer/go-colorful/issues/21)
-for discussion and suggesting alternatives.
+**Caveat:** Be aware that this latter conversion (using `MakeColor`) hits a
+corner-case when alpha is exactly zero. Because `color.Color` uses pre-multiplied
+alpha colors, this means the RGB values are lost (set to 0) and it's impossible
+to recover them. In such a case `MakeColor` will return `false` as its second value.
### Comparing colors
In the RGB color space, the Euclidian distance between colors *doesn't* correspond
@@ -456,16 +455,26 @@ but that is outside the scope of this library.
Thanks to [@ZirconiumX](https://github.com/ZirconiumX) for starting this investigation,
see [issue #18](https://github.com/lucasb-eyer/go-colorful/issues/18) for details.
-### Q: `MakeColor` panics when alpha is zero!
-A: Because in that case, the conversion is undefined. See
-[issue 21](https://github.com/lucasb-eyer/go-colorful/issues/21)
-as well as the short caveat discussion in the ["The `color.Color` interface"](README.md#the-colorcolor-interface) section above.
+### Q: Why would `MakeColor` ever fail!?
+A: `MakeColor` fails when the alpha channel is zero. In that case, the
+conversion is undefined. See [issue 21](https://github.com/lucasb-eyer/go-colorful/issues/21)
+as well as the short caveat note in the ["The `color.Color` interface"](README.md#the-colorcolor-interface)
+section above.
Who?
====
This library has been developed by Lucas Beyer with contributions from
-Bastien Dejean (@baskerville) and Phil Kulak (@pkulak).
+Bastien Dejean (@baskerville), Phil Kulak (@pkulak) and Christian Muehlhaeuser (@muesli).
+
+Release Notes
+=============
+
+### Version 1.0
+- API Breaking change in `MakeColor`: instead of `panic`ing when alpha is zero, it now returns a secondary, boolean return value indicating success. See [the color.Color interface](https://github.com/lucasb-eyer/go-colorful#the-colorcolor-interface) section and [this FAQ entry](https://github.com/lucasb-eyer/go-colorful#q-why-would-makecolor-ever-fail) for details.
+
+### Version 0.9
+- Initial version number after having ignored versioning for a long time :)
License: MIT
============
diff --git a/vendor/github.com/lucasb-eyer/go-colorful/colors.go b/vendor/github.com/lucasb-eyer/go-colorful/colors.go
index 7469cf7..febf94c 100644
--- a/vendor/github.com/lucasb-eyer/go-colorful/colors.go
+++ b/vendor/github.com/lucasb-eyer/go-colorful/colors.go
@@ -22,8 +22,11 @@ func (col Color) RGBA() (r, g, b, a uint32) {
}
// Constructs a colorful.Color from something implementing color.Color
-func MakeColor(col color.Color) Color {
+func MakeColor(col color.Color) (Color, bool) {
r, g, b, a := col.RGBA()
+ if a == 0 {
+ return Color{0, 0, 0}, false
+ }
// Since color.Color is alpha pre-multiplied, we need to divide the
// RGB values by alpha again in order to get back the original RGB.
@@ -34,7 +37,7 @@ func MakeColor(col color.Color) Color {
b *= 0xffff
b /= a
- return Color{float64(r) / 65535.0, float64(g) / 65535.0, float64(b) / 65535.0}
+ return Color{float64(r) / 65535.0, float64(g) / 65535.0, float64(b) / 65535.0}, true
}
// Might come in handy sometimes to reduce boilerplate code.
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go
index 2164497..82568a1 100644
--- a/vendor/github.com/mattn/go-runewidth/runewidth.go
+++ b/vendor/github.com/mattn/go-runewidth/runewidth.go
@@ -1,13 +1,24 @@
package runewidth
+import "os"
+
var (
// EastAsianWidth will be set true if the current locale is CJK
- EastAsianWidth = IsEastAsian()
+ EastAsianWidth bool
// DefaultCondition is a condition in current locale
DefaultCondition = &Condition{EastAsianWidth}
)
+func init() {
+ env := os.Getenv("RUNEWIDTH_EASTASIAN")
+ if env == "" {
+ EastAsianWidth = IsEastAsian()
+ } else {
+ EastAsianWidth = env == "1"
+ }
+}
+
type interval struct {
first rune
last rune
@@ -55,6 +66,7 @@ var private = table{
var nonprint = table{
{0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
{0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
+ {0x2028, 0x2029},
{0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
}
diff --git a/vendor/github.com/renstrom/fuzzysearch/LICENSE b/vendor/github.com/renstrom/fuzzysearch/LICENSE
index 9cc7533..dee3d1d 100644
--- a/vendor/github.com/renstrom/fuzzysearch/LICENSE
+++ b/vendor/github.com/renstrom/fuzzysearch/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2015 Peter Renström
+Copyright (c) 2018 Peter Lithammer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/github.com/renstrom/fuzzysearch/fuzzy/fuzzy.go b/vendor/github.com/renstrom/fuzzysearch/fuzzy/fuzzy.go
index 76b1c6e..33d4898 100644
--- a/vendor/github.com/renstrom/fuzzysearch/fuzzy/fuzzy.go
+++ b/vendor/github.com/renstrom/fuzzysearch/fuzzy/fuzzy.go
@@ -112,10 +112,7 @@ Outer:
}
// Count up remaining char
- for len(target) > 0 {
- target = target[utf8.RuneLen(rune(target[0])):]
- runeDiff++
- }
+ runeDiff += utf8.RuneCountInString(target)
return runeDiff
}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go
index ae06a54..aa1c2b9 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_format.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go
@@ -13,6 +13,9 @@ import (
// Conditionf uses a Comparison to assert a complex condition.
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Condition(t, comp, append([]interface{}{msg}, args...)...)
}
@@ -23,11 +26,17 @@ func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bo
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
}
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return DirExists(t, path, append([]interface{}{msg}, args...)...)
}
@@ -37,6 +46,9 @@ func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
//
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
}
@@ -45,6 +57,9 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string
//
// assert.Emptyf(t, obj, "error message %s", "formatted")
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Empty(t, object, append([]interface{}{msg}, args...)...)
}
@@ -56,6 +71,9 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) boo
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
}
@@ -65,6 +83,9 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar
// actualObj, err := SomeFunction()
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
}
@@ -73,6 +94,9 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args
//
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
@@ -83,6 +107,9 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
// assert.Equal(t, expectedErrorf, err)
// }
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Error(t, err, append([]interface{}{msg}, args...)...)
}
@@ -90,16 +117,25 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Failf reports a failure through
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
}
// FailNowf fails test
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
}
@@ -107,31 +143,43 @@ func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}
//
// assert.Falsef(t, myBool, "error message %s", "formatted")
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return False(t, value, append([]interface{}{msg}, args...)...)
}
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return FileExists(t, path, append([]interface{}{msg}, args...)...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
-// assert.HTTPBodyContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
-// assert.HTTPBodyNotContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
@@ -141,6 +189,9 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
@@ -150,6 +201,9 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string,
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
@@ -159,6 +213,9 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
@@ -166,6 +223,9 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin
//
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
}
@@ -173,31 +233,49 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
//
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
}
// IsTypef asserts that the specified objects are of the same type.
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
}
@@ -205,6 +283,9 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin
//
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
@@ -213,6 +294,9 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
//
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Len(t, object, length, append([]interface{}{msg}, args...)...)
}
@@ -220,6 +304,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
//
// assert.Nilf(t, err, "error message %s", "formatted")
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Nil(t, object, append([]interface{}{msg}, args...)...)
}
@@ -230,6 +317,9 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool
// assert.Equal(t, expectedObj, actualObj)
// }
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NoError(t, err, append([]interface{}{msg}, args...)...)
}
@@ -240,6 +330,9 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
}
@@ -250,6 +343,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
// assert.Equal(t, "two", obj[1])
// }
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
}
@@ -260,6 +356,9 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{})
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
}
@@ -267,6 +366,9 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string,
//
// assert.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotNil(t, object, append([]interface{}{msg}, args...)...)
}
@@ -274,6 +376,9 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bo
//
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
}
@@ -282,6 +387,9 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
@@ -290,11 +398,17 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
//
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
}
// NotZerof asserts that i is not the zero value for its type.
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return NotZero(t, i, append([]interface{}{msg}, args...)...)
}
@@ -302,6 +416,9 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
//
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Panics(t, f, append([]interface{}{msg}, args...)...)
}
@@ -310,6 +427,9 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool
//
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
}
@@ -318,6 +438,9 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
@@ -326,6 +449,9 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
//
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
}
@@ -333,6 +459,9 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args
//
// assert.Truef(t, myBool, "error message %s", "formatted")
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return True(t, value, append([]interface{}{msg}, args...)...)
}
@@ -340,10 +469,16 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
//
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// Zerof asserts that i is the zero value for its type.
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
return Zero(t, i, append([]interface{}{msg}, args...)...)
}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
index c5cc66f..d2bb0b8 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
@@ -1,4 +1,5 @@
{{.CommentFormat}}
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
+ if h, ok := t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
index ffa5428..de39f79 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
@@ -13,11 +13,17 @@ import (
// Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Condition(a.t, comp, msgAndArgs...)
}
// Conditionf uses a Comparison to assert a complex condition.
func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Conditionf(a.t, comp, msg, args...)
}
@@ -28,6 +34,9 @@ func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}
// a.Contains(["Hello", "World"], "World")
// a.Contains({"Hello": "World"}, "Hello")
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Contains(a.t, s, contains, msgAndArgs...)
}
@@ -38,16 +47,25 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ..
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Containsf(a.t, s, contains, msg, args...)
}
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return DirExists(a.t, path, msgAndArgs...)
}
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return DirExistsf(a.t, path, msg, args...)
}
@@ -57,6 +75,9 @@ func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bo
//
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return ElementsMatch(a.t, listA, listB, msgAndArgs...)
}
@@ -66,6 +87,9 @@ func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndA
//
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return ElementsMatchf(a.t, listA, listB, msg, args...)
}
@@ -74,6 +98,9 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st
//
// a.Empty(obj)
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Empty(a.t, object, msgAndArgs...)
}
@@ -82,6 +109,9 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
//
// a.Emptyf(obj, "error message %s", "formatted")
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Emptyf(a.t, object, msg, args...)
}
@@ -93,6 +123,9 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{})
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Equal(a.t, expected, actual, msgAndArgs...)
}
@@ -102,6 +135,9 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs
// actualObj, err := SomeFunction()
// a.EqualError(err, expectedErrorString)
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return EqualError(a.t, theError, errString, msgAndArgs...)
}
@@ -111,6 +147,9 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...
// actualObj, err := SomeFunction()
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return EqualErrorf(a.t, theError, errString, msg, args...)
}
@@ -119,6 +158,9 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a
//
// a.EqualValues(uint32(123), int32(123))
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return EqualValues(a.t, expected, actual, msgAndArgs...)
}
@@ -127,6 +169,9 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
//
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return EqualValuesf(a.t, expected, actual, msg, args...)
}
@@ -138,6 +183,9 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Equalf(a.t, expected, actual, msg, args...)
}
@@ -148,6 +196,9 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
// assert.Equal(t, expectedError, err)
// }
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Error(a.t, err, msgAndArgs...)
}
@@ -158,6 +209,9 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
// assert.Equal(t, expectedErrorf, err)
// }
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Errorf(a.t, err, msg, args...)
}
@@ -165,6 +219,9 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
//
// a.Exactly(int32(123), int64(123))
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Exactly(a.t, expected, actual, msgAndArgs...)
}
@@ -172,26 +229,41 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg
//
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Exactlyf(a.t, expected, actual, msg, args...)
}
// Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Fail(a.t, failureMessage, msgAndArgs...)
}
// FailNow fails test
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return FailNow(a.t, failureMessage, msgAndArgs...)
}
// FailNowf fails test
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return FailNowf(a.t, failureMessage, msg, args...)
}
// Failf reports a failure through
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Failf(a.t, failureMessage, msg, args...)
}
@@ -199,6 +271,9 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{
//
// a.False(myBool)
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return False(a.t, value, msgAndArgs...)
}
@@ -206,56 +281,77 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
//
// a.Falsef(myBool, "error message %s", "formatted")
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Falsef(a.t, value, msg, args...)
}
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return FileExists(a.t, path, msgAndArgs...)
}
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return FileExistsf(a.t, path, msg, args...)
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
-// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
-// a.HTTPBodyContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
-// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
-// a.HTTPBodyNotContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
}
@@ -265,6 +361,9 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
}
@@ -274,6 +373,9 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
}
@@ -283,6 +385,9 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
}
@@ -292,6 +397,9 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
}
@@ -301,6 +409,9 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
}
@@ -310,6 +421,9 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
}
@@ -317,6 +431,9 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s
//
// a.Implements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Implements(a.t, interfaceObject, object, msgAndArgs...)
}
@@ -324,6 +441,9 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
//
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Implementsf(a.t, interfaceObject, object, msg, args...)
}
@@ -331,26 +451,41 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
//
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
}
@@ -358,36 +493,57 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
//
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InDeltaf(a.t, expected, actual, delta, msg, args...)
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
}
// IsType asserts that the specified objects are of the same type.
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return IsType(a.t, expectedType, object, msgAndArgs...)
}
// IsTypef asserts that the specified objects are of the same type.
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return IsTypef(a.t, expectedType, object, msg, args...)
}
@@ -395,6 +551,9 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s
//
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return JSONEq(a.t, expected, actual, msgAndArgs...)
}
@@ -402,6 +561,9 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf
//
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return JSONEqf(a.t, expected, actual, msg, args...)
}
@@ -410,6 +572,9 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
//
// a.Len(mySlice, 3)
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Len(a.t, object, length, msgAndArgs...)
}
@@ -418,6 +583,9 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface
//
// a.Lenf(mySlice, 3, "error message %s", "formatted")
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Lenf(a.t, object, length, msg, args...)
}
@@ -425,6 +593,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
//
// a.Nil(err)
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Nil(a.t, object, msgAndArgs...)
}
@@ -432,6 +603,9 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
//
// a.Nilf(err, "error message %s", "formatted")
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Nilf(a.t, object, msg, args...)
}
@@ -442,6 +616,9 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) b
// assert.Equal(t, expectedObj, actualObj)
// }
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NoError(a.t, err, msgAndArgs...)
}
@@ -452,6 +629,9 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
// assert.Equal(t, expectedObj, actualObj)
// }
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NoErrorf(a.t, err, msg, args...)
}
@@ -462,6 +642,9 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
// a.NotContains(["Hello", "World"], "Earth")
// a.NotContains({"Hello": "World"}, "Earth")
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotContains(a.t, s, contains, msgAndArgs...)
}
@@ -472,6 +655,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotContainsf(a.t, s, contains, msg, args...)
}
@@ -482,6 +668,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
// assert.Equal(t, "two", obj[1])
// }
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotEmpty(a.t, object, msgAndArgs...)
}
@@ -492,6 +681,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) boo
// assert.Equal(t, "two", obj[1])
// }
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotEmptyf(a.t, object, msg, args...)
}
@@ -502,6 +694,9 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotEqual(a.t, expected, actual, msgAndArgs...)
}
@@ -512,6 +707,9 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotEqualf(a.t, expected, actual, msg, args...)
}
@@ -519,6 +717,9 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
//
// a.NotNil(err)
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotNil(a.t, object, msgAndArgs...)
}
@@ -526,6 +727,9 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool
//
// a.NotNilf(err, "error message %s", "formatted")
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotNilf(a.t, object, msg, args...)
}
@@ -533,6 +737,9 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}
//
// a.NotPanics(func(){ RemainCalm() })
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotPanics(a.t, f, msgAndArgs...)
}
@@ -540,6 +747,9 @@ func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool
//
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotPanicsf(a.t, f, msg, args...)
}
@@ -548,6 +758,9 @@ func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
// a.NotRegexp("^start", "it's not starting")
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotRegexp(a.t, rx, str, msgAndArgs...)
}
@@ -556,6 +769,9 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotRegexpf(a.t, rx, str, msg, args...)
}
@@ -564,6 +780,9 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
//
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotSubset(a.t, list, subset, msgAndArgs...)
}
@@ -572,16 +791,25 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
//
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotSubsetf(a.t, list, subset, msg, args...)
}
// NotZero asserts that i is not the zero value for its type.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotZero(a.t, i, msgAndArgs...)
}
// NotZerof asserts that i is not the zero value for its type.
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return NotZerof(a.t, i, msg, args...)
}
@@ -589,6 +817,9 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bo
//
// a.Panics(func(){ GoCrazy() })
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Panics(a.t, f, msgAndArgs...)
}
@@ -597,6 +828,9 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
//
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return PanicsWithValue(a.t, expected, f, msgAndArgs...)
}
@@ -605,6 +839,9 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgA
//
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return PanicsWithValuef(a.t, expected, f, msg, args...)
}
@@ -612,6 +849,9 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg
//
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Panicsf(a.t, f, msg, args...)
}
@@ -620,6 +860,9 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b
// a.Regexp(regexp.MustCompile("start"), "it's starting")
// a.Regexp("start...$", "it's not starting")
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Regexp(a.t, rx, str, msgAndArgs...)
}
@@ -628,6 +871,9 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Regexpf(a.t, rx, str, msg, args...)
}
@@ -636,6 +882,9 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
//
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Subset(a.t, list, subset, msgAndArgs...)
}
@@ -644,6 +893,9 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
//
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Subsetf(a.t, list, subset, msg, args...)
}
@@ -651,6 +903,9 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a
//
// a.True(myBool)
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return True(a.t, value, msgAndArgs...)
}
@@ -658,6 +913,9 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
//
// a.Truef(myBool, "error message %s", "formatted")
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Truef(a.t, value, msg, args...)
}
@@ -665,6 +923,9 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
//
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
}
@@ -672,15 +933,24 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta
//
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
}
// Zero asserts that i is the zero value for its type.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Zero(a.t, i, msgAndArgs...)
}
// Zerof asserts that i is the zero value for its type.
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
+ if h, ok := a.t.(tHelper); ok {
+ h.Helper()
+ }
return Zerof(a.t, i, msg, args...)
}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
index 99f9acf..188bb9e 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
@@ -1,4 +1,5 @@
{{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
+ if h, ok := a.t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
}
diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go
index 47bda77..5bdec56 100644
--- a/vendor/github.com/stretchr/testify/assert/assertions.go
+++ b/vendor/github.com/stretchr/testify/assert/assertions.go
@@ -27,6 +27,22 @@ type TestingT interface {
Errorf(format string, args ...interface{})
}
+// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
+
+// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
+
+// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
+
+// ValuesAssertionFunc is a common function prototype when validating an error value. Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
+
// Comparison a custom function that returns true on success and false on failure
type Comparison func() (success bool)
@@ -38,21 +54,23 @@ type Comparison func() (success bool)
//
// This function does no assertion of any kind.
func ObjectsAreEqual(expected, actual interface{}) bool {
-
if expected == nil || actual == nil {
return expected == actual
}
- if exp, ok := expected.([]byte); ok {
- act, ok := actual.([]byte)
- if !ok {
- return false
- } else if exp == nil || act == nil {
- return exp == nil && act == nil
- }
- return bytes.Equal(exp, act)
+
+ exp, ok := expected.([]byte)
+ if !ok {
+ return reflect.DeepEqual(expected, actual)
}
- return reflect.DeepEqual(expected, actual)
+ act, ok := actual.([]byte)
+ if !ok {
+ return false
+ }
+ if exp == nil || act == nil {
+ return exp == nil && act == nil
+ }
+ return bytes.Equal(exp, act)
}
// ObjectsAreEqualValues gets whether two objects are equal, or if their
@@ -156,21 +174,6 @@ func isTest(name, prefix string) bool {
return !unicode.IsLower(rune)
}
-// getWhitespaceString returns a string that is long enough to overwrite the default
-// output from the go testing framework.
-func getWhitespaceString() string {
-
- _, file, line, ok := runtime.Caller(1)
- if !ok {
- return ""
- }
- parts := strings.Split(file, "/")
- file = parts[len(parts)-1]
-
- return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line)))
-
-}
-
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
if len(msgAndArgs) == 0 || msgAndArgs == nil {
return ""
@@ -195,7 +198,7 @@ func indentMessageLines(message string, longestLabelLen int) string {
// no need to align first line because it starts at the correct location (after the label)
if i != 0 {
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
- outBuf.WriteString("\n\r\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
+ outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
}
outBuf.WriteString(scanner.Text())
}
@@ -209,6 +212,9 @@ type failNower interface {
// FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
Fail(t, failureMessage, msgAndArgs...)
// We cannot extend TestingT with FailNow() and
@@ -227,8 +233,11 @@ func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool
// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
content := []labeledContent{
- {"Error Trace", strings.Join(CallerInfo(), "\n\r\t\t\t")},
+ {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
{"Error", failureMessage},
}
@@ -244,7 +253,7 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
content = append(content, labeledContent{"Messages", message})
}
- t.Errorf("%s", "\r"+getWhitespaceString()+labeledOutput(content...))
+ t.Errorf("\n%s", ""+labeledOutput(content...))
return false
}
@@ -256,7 +265,7 @@ type labeledContent struct {
// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
//
-// \r\t{{label}}:{{align_spaces}}\t{{content}}\n
+// \t{{label}}:{{align_spaces}}\t{{content}}\n
//
// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
@@ -272,7 +281,7 @@ func labeledOutput(content ...labeledContent) string {
}
var output string
for _, v := range content {
- output += "\r\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
+ output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
}
return output
}
@@ -281,6 +290,9 @@ func labeledOutput(content ...labeledContent) string {
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
interfaceType := reflect.TypeOf(interfaceObject).Elem()
if object == nil {
@@ -295,6 +307,9 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
@@ -311,6 +326,9 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
expected, actual, err), msgAndArgs...)
@@ -349,6 +367,9 @@ func formatUnequalValues(expected, actual interface{}) (e string, a string) {
//
// assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if !ObjectsAreEqualValues(expected, actual) {
diff := diff(expected, actual)
@@ -366,12 +387,15 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa
//
// assert.Exactly(t, int32(123), int64(123))
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
aType := reflect.TypeOf(expected)
bType := reflect.TypeOf(actual)
if aType != bType {
- return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...)
+ return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
}
return Equal(t, expected, actual, msgAndArgs...)
@@ -382,6 +406,9 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
//
// assert.NotNil(t, err)
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if !isNil(object) {
return true
}
@@ -407,6 +434,9 @@ func isNil(object interface{}) bool {
//
// assert.Nil(t, err)
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if isNil(object) {
return true
}
@@ -446,6 +476,9 @@ func isEmpty(object interface{}) bool {
//
// assert.Empty(t, obj)
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
pass := isEmpty(object)
if !pass {
@@ -463,6 +496,9 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
// assert.Equal(t, "two", obj[1])
// }
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
pass := !isEmpty(object)
if !pass {
@@ -490,6 +526,9 @@ func getLen(x interface{}) (ok bool, length int) {
//
// assert.Len(t, mySlice, 3)
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
ok, l := getLen(object)
if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
@@ -505,6 +544,14 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
//
// assert.True(t, myBool)
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
+ if h, ok := t.(interface {
+ Helper()
+ }); ok {
+ h.Helper()
+ }
if value != true {
return Fail(t, "Should be true", msgAndArgs...)
@@ -518,6 +565,9 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
//
// assert.False(t, myBool)
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if value != false {
return Fail(t, "Should be false", msgAndArgs...)
@@ -534,6 +584,9 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
expected, actual, err), msgAndArgs...)
@@ -592,6 +645,9 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
// assert.Contains(t, ["Hello", "World"], "World")
// assert.Contains(t, {"Hello": "World"}, "Hello")
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
ok, found := includeElement(s, contains)
if !ok {
@@ -612,6 +668,9 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
// assert.NotContains(t, ["Hello", "World"], "Earth")
// assert.NotContains(t, {"Hello": "World"}, "Earth")
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
ok, found := includeElement(s, contains)
if !ok {
@@ -630,6 +689,9 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
//
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if subset == nil {
return true // we consider nil to be equal to the nil set
}
@@ -671,6 +733,9 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
//
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if subset == nil {
return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...)
}
@@ -713,6 +778,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
//
// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if isEmpty(listA) && isEmpty(listB) {
return true
}
@@ -763,6 +831,9 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
result := comp()
if !result {
Fail(t, "Condition failed!", msgAndArgs...)
@@ -800,9 +871,12 @@ func didPanic(f PanicTestFunc) (bool, interface{}) {
//
// assert.Panics(t, func(){ GoCrazy() })
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
- return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+ return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
}
return true
@@ -813,13 +887,16 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
//
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
funcDidPanic, panicValue := didPanic(f)
if !funcDidPanic {
- return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+ return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
}
if panicValue != expected {
- return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%v\n\r\tPanic value:\t%v", f, expected, panicValue), msgAndArgs...)
+ return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
}
return true
@@ -829,9 +906,12 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr
//
// assert.NotPanics(t, func(){ RemainCalm() })
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
- return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
+ return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
}
return true
@@ -841,6 +921,9 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
//
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
dt := expected.Sub(actual)
if dt < -delta || dt > delta {
@@ -890,6 +973,9 @@ func toFloat(x interface{}) (float64, bool) {
//
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
af, aok := toFloat(expected)
bf, bok := toFloat(actual)
@@ -916,6 +1002,9 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs
// InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice {
@@ -937,6 +1026,9 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Map ||
reflect.TypeOf(expected).Kind() != reflect.Map {
@@ -994,6 +1086,9 @@ func calcRelativeError(expected, actual interface{}) (float64, error) {
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
actualEpsilon, err := calcRelativeError(expected, actual)
if err != nil {
return Fail(t, err.Error(), msgAndArgs...)
@@ -1008,6 +1103,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice {
@@ -1038,6 +1136,9 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
// assert.Equal(t, expectedObj, actualObj)
// }
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if err != nil {
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
}
@@ -1052,6 +1153,9 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
// assert.Equal(t, expectedError, err)
// }
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if err == nil {
return Fail(t, "An error is expected but got nil.", msgAndArgs...)
@@ -1066,6 +1170,9 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
// actualObj, err := SomeFunction()
// assert.EqualError(t, err, expectedErrorString)
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if !Error(t, theError, msgAndArgs...) {
return false
}
@@ -1099,6 +1206,9 @@ func matchRegexp(rx interface{}, str interface{}) bool {
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting")
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
match := matchRegexp(rx, str)
@@ -1114,6 +1224,9 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting")
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
match := matchRegexp(rx, str)
if match {
@@ -1126,6 +1239,9 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
// Zero asserts that i is the zero value for its type.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
}
@@ -1134,6 +1250,9 @@ func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
// NotZero asserts that i is not the zero value for its type.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
}
@@ -1142,6 +1261,9 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
info, err := os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
@@ -1157,6 +1279,9 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
info, err := os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
@@ -1174,6 +1299,9 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
var expectedJSONAsInterface, actualJSONAsInterface interface{}
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
@@ -1212,12 +1340,18 @@ func diff(expected interface{}, actual interface{}) string {
return ""
}
- if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
+ if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
return ""
}
- e := spewConfig.Sdump(expected)
- a := spewConfig.Sdump(actual)
+ var e, a string
+ if ek != reflect.String {
+ e = spewConfig.Sdump(expected)
+ a = spewConfig.Sdump(actual)
+ } else {
+ e = expected.(string)
+ a = actual.(string)
+ }
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e),
@@ -1254,3 +1388,7 @@ var spewConfig = spew.ConfigState{
DisableCapacities: true,
SortKeys: true,
}
+
+type tHelper interface {
+ Helper()
+}
diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go
index 3101e78..df46fa7 100644
--- a/vendor/github.com/stretchr/testify/assert/http_assertions.go
+++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go
@@ -12,10 +12,11 @@ import (
// an error if building a new request fails.
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
w := httptest.NewRecorder()
- req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
+ req, err := http.NewRequest(method, url, nil)
if err != nil {
return -1, err
}
+ req.URL.RawQuery = values.Encode()
handler(w, req)
return w.Code, nil
}
@@ -26,6 +27,9 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
@@ -46,6 +50,9 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
@@ -66,6 +73,9 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
@@ -95,10 +105,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
-// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
@@ -112,10 +125,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
-// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
+// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+ if h, ok := t.(tHelper); ok {
+ h.Helper()
+ }
body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
diff --git a/vendor/github.com/zyedidia/clipboard/LICENSE b/vendor/github.com/zyedidia/clipboard/LICENSE
index dee3257..bdec9a5 100644
--- a/vendor/github.com/zyedidia/clipboard/LICENSE
+++ b/vendor/github.com/zyedidia/clipboard/LICENSE
@@ -1,3 +1,7 @@
+Copyright (c) 2018 Zachary Yedidia. Modifications to atotto/clipboard.
+
+Original license:
+
Copyright (c) 2013 Ato Araki. All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/vendor/github.com/zyedidia/clipboard/README.md b/vendor/github.com/zyedidia/clipboard/README.md
index 6e2d15f..8691eb1 100644
--- a/vendor/github.com/zyedidia/clipboard/README.md
+++ b/vendor/github.com/zyedidia/clipboard/README.md
@@ -1,3 +1,7 @@
+# This is a fork of atotto/clipboard
+
+This fork is used for `zyedidia/micro` and has some modifications, namely: support for the primary clipboard on linux and support for an internal clipboard if the system clipboard is not available.
+
[![Build Status](https://travis-ci.org/atotto/clipboard.svg?branch=master)](https://travis-ci.org/atotto/clipboard) [![Build Status](https://drone.io/github.com/atotto/clipboard/status.png)](https://drone.io/github.com/atotto/clipboard/latest)
[![GoDoc](https://godoc.org/github.com/atotto/clipboard?status.svg)](http://godoc.org/github.com/atotto/clipboard)
diff --git a/vendor/golang.org/x/image/bmp/writer.go b/vendor/golang.org/x/image/bmp/writer.go
index 6947968..f07b39d 100644
--- a/vendor/golang.org/x/image/bmp/writer.go
+++ b/vendor/golang.org/x/image/bmp/writer.go
@@ -49,20 +49,91 @@ func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
return nil
}
-func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
+func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
buf := make([]byte, step)
- for y := dy - 1; y >= 0; y-- {
- min := y*stride + 0
- max := y*stride + dx*4
- off := 0
- for i := min; i < max; i += 4 {
- buf[off+2] = pix[i+0]
- buf[off+1] = pix[i+1]
- buf[off+0] = pix[i+2]
- off += 3
+ if opaque {
+ for y := dy - 1; y >= 0; y-- {
+ min := y*stride + 0
+ max := y*stride + dx*4
+ off := 0
+ for i := min; i < max; i += 4 {
+ buf[off+2] = pix[i+0]
+ buf[off+1] = pix[i+1]
+ buf[off+0] = pix[i+2]
+ off += 3
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
}
- if _, err := w.Write(buf); err != nil {
- return err
+ } else {
+ for y := dy - 1; y >= 0; y-- {
+ min := y*stride + 0
+ max := y*stride + dx*4
+ off := 0
+ for i := min; i < max; i += 4 {
+ a := uint32(pix[i+3])
+ if a == 0 {
+ buf[off+2] = 0
+ buf[off+1] = 0
+ buf[off+0] = 0
+ buf[off+3] = 0
+ off += 4
+ continue
+ } else if a == 0xff {
+ buf[off+2] = pix[i+0]
+ buf[off+1] = pix[i+1]
+ buf[off+0] = pix[i+2]
+ buf[off+3] = 0xff
+ off += 4
+ continue
+ }
+ buf[off+2] = uint8(((uint32(pix[i+0]) * 0xffff) / a) >> 8)
+ buf[off+1] = uint8(((uint32(pix[i+1]) * 0xffff) / a) >> 8)
+ buf[off+0] = uint8(((uint32(pix[i+2]) * 0xffff) / a) >> 8)
+ buf[off+3] = uint8(a)
+ off += 4
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func encodeNRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
+ buf := make([]byte, step)
+ if opaque {
+ for y := dy - 1; y >= 0; y-- {
+ min := y*stride + 0
+ max := y*stride + dx*4
+ off := 0
+ for i := min; i < max; i += 4 {
+ buf[off+2] = pix[i+0]
+ buf[off+1] = pix[i+1]
+ buf[off+0] = pix[i+2]
+ off += 3
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
+ }
+ } else {
+ for y := dy - 1; y >= 0; y-- {
+ min := y*stride + 0
+ max := y*stride + dx*4
+ off := 0
+ for i := min; i < max; i += 4 {
+ buf[off+2] = pix[i+0]
+ buf[off+1] = pix[i+1]
+ buf[off+0] = pix[i+2]
+ buf[off+3] = pix[i+3]
+ off += 4
+ }
+ if _, err := w.Write(buf); err != nil {
+ return err
+ }
}
}
return nil
@@ -105,6 +176,7 @@ func Encode(w io.Writer, m image.Image) error {
var step int
var palette []byte
+ var opaque bool
switch m := m.(type) {
case *image.Gray:
step = (d.X + 3) &^ 3
@@ -134,6 +206,28 @@ func Encode(w io.Writer, m image.Image) error {
h.fileSize += uint32(len(palette)) + h.imageSize
h.pixOffset += uint32(len(palette))
h.bpp = 8
+ case *image.RGBA:
+ opaque = m.Opaque()
+ if opaque {
+ step = (3*d.X + 3) &^ 3
+ h.bpp = 24
+ } else {
+ step = 4 * d.X
+ h.bpp = 32
+ }
+ h.imageSize = uint32(d.Y * step)
+ h.fileSize += h.imageSize
+ case *image.NRGBA:
+ opaque = m.Opaque()
+ if opaque {
+ step = (3*d.X + 3) &^ 3
+ h.bpp = 24
+ } else {
+ step = 4 * d.X
+ h.bpp = 32
+ }
+ h.imageSize = uint32(d.Y * step)
+ h.fileSize += h.imageSize
default:
step = (3*d.X + 3) &^ 3
h.imageSize = uint32(d.Y * step)
@@ -160,7 +254,9 @@ func Encode(w io.Writer, m image.Image) error {
case *image.Paletted:
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
case *image.RGBA:
- return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step)
+ return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
+ case *image.NRGBA:
+ return encodeNRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
}
return encode(w, m, step)
}
diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go
index d23e05e..4b1fa42 100644
--- a/vendor/golang.org/x/net/html/parse.go
+++ b/vendor/golang.org/x/net/html/parse.go
@@ -209,27 +209,6 @@ loop:
p.oe = p.oe[:i+1]
}
-// generateAllImpliedEndTags pops nodes off the stack of open elements as long as
-// the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rb,
-// rp, rt, rtc, span, tbody, td, tfoot, th, thead or tr.
-func (p *parser) generateAllImpliedEndTags() {
- var i int
- for i = len(p.oe) - 1; i >= 0; i-- {
- n := p.oe[i]
- if n.Type == ElementNode {
- switch n.DataAtom {
- // TODO: remove this divergence from the HTML5 spec
- case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb,
- a.Rp, a.Rt, a.Rtc, a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
- continue
- }
- }
- break
- }
-
- p.oe = p.oe[:i+1]
-}
-
// addChild adds a child node n to the top element, and pushes n onto the stack
// of open elements if it is an element node.
func (p *parser) addChild(n *Node) {
@@ -276,7 +255,7 @@ func (p *parser) fosterParent(n *Node) {
}
}
- if template != nil && (table == nil || j < i) {
+ if template != nil && (table == nil || j > i) {
template.AppendChild(n)
return
}
@@ -679,11 +658,16 @@ func inHeadIM(p *parser) bool {
if !p.oe.contains(a.Template) {
return true
}
- p.generateAllImpliedEndTags()
- if n := p.oe.top(); n.DataAtom != a.Template {
- return true
+ // TODO: remove this divergence from the HTML5 spec.
+ //
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
+ p.generateImpliedEndTags()
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
+ p.oe = p.oe[:i]
+ break
+ }
}
- p.popUntil(defaultScope, a.Template)
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
@@ -860,9 +844,13 @@ func inBodyIM(p *parser) bool {
// The newline, if any, will be dealt with by the TextToken case.
p.framesetOK = false
case a.Form:
- if p.oe.contains(a.Template) || p.form == nil {
- p.popUntil(buttonScope, a.P)
- p.addElement()
+ if p.form != nil && !p.oe.contains(a.Template) {
+ // Ignore the token
+ return true
+ }
+ p.popUntil(buttonScope, a.P)
+ p.addElement()
+ if !p.oe.contains(a.Template) {
p.form = p.top()
}
case a.Li:
@@ -1070,13 +1058,7 @@ func inBodyIM(p *parser) bool {
p.acknowledgeSelfClosingTag()
}
return true
- case a.Frame:
- // TODO: remove this divergence from the HTML5 spec.
- if p.oe.contains(a.Template) {
- p.addElement()
- return true
- }
- case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
+ case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
default:
p.reconstructActiveFormattingElements()
@@ -1098,12 +1080,13 @@ func inBodyIM(p *parser) bool {
p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form:
if p.oe.contains(a.Template) {
- if !p.oe.contains(a.Form) {
+ i := p.indexOfElementInScope(defaultScope, a.Form)
+ if i == -1 {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
- if p.tok.DataAtom == a.Form {
+ if p.oe[i].DataAtom != a.Form {
// Ignore the token.
return true
}
@@ -1346,9 +1329,6 @@ func textIM(p *parser) bool {
// Section 12.2.6.4.9.
func inTableIM(p *parser) bool {
switch p.tok.Type {
- case ErrorToken:
- // Stop parsing.
- return true
case TextToken:
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
switch p.oe.top().DataAtom {
@@ -1443,6 +1423,8 @@ func inTableIM(p *parser) bool {
case DoctypeToken:
// Ignore the token.
return true
+ case ErrorToken:
+ return inBodyIM(p)
}
p.fosterParenting = true
@@ -1545,6 +1527,8 @@ func inColumnGroupIM(p *parser) bool {
case a.Template:
return inHeadIM(p)
}
+ case ErrorToken:
+ return inBodyIM(p)
}
if p.oe.top().DataAtom != a.Colgroup {
return true
@@ -1709,9 +1693,6 @@ func inCellIM(p *parser) bool {
// Section 12.2.6.4.16.
func inSelectIM(p *parser) bool {
switch p.tok.Type {
- case ErrorToken:
- // Stop parsing.
- return true
case TextToken:
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
case StartTagToken:
@@ -1775,6 +1756,8 @@ func inSelectIM(p *parser) bool {
case DoctypeToken:
// Ignore the token.
return true
+ case ErrorToken:
+ return inBodyIM(p)
}
return true
@@ -1841,15 +1824,26 @@ func inTemplateIM(p *parser) bool {
// Ignore the token.
return true
}
+ case ErrorToken:
+ if !p.oe.contains(a.Template) {
+ // Ignore the token.
+ return true
+ }
+ // TODO: remove this divergence from the HTML5 spec.
+ //
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
+ p.generateImpliedEndTags()
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
+ p.oe = p.oe[:i]
+ break
+ }
+ }
+ p.clearActiveFormattingElements()
+ p.templateStack.pop()
+ p.resetInsertionMode()
+ return false
}
- if !p.oe.contains(a.Template) {
- // Ignore the token.
- return true
- }
- p.popUntil(defaultScope, a.Template)
- p.clearActiveFormattingElements()
- p.templateStack.pop()
- p.resetInsertionMode()
return false
}
@@ -1923,11 +1917,6 @@ func inFramesetIM(p *parser) bool {
p.acknowledgeSelfClosingTag()
case a.Noframes:
return inHeadIM(p)
- case a.Template:
- // TODO: remove this divergence from the HTML5 spec.
- //
- // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
- return inTemplateIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
diff --git a/vendor/gopkg.in/toast.v1/toast.go b/vendor/gopkg.in/toast.v1/toast.go
index 1782e5e..7ea32c9 100644
--- a/vendor/gopkg.in/toast.v1/toast.go
+++ b/vendor/gopkg.in/toast.v1/toast.go
@@ -11,6 +11,7 @@ import (
"text/template"
"github.com/nu7hatch/gouuid"
+ "syscall"
)
var toastTemplate *template.Template
@@ -347,7 +348,9 @@ func invokeTemporaryScript(content string) error {
if err != nil {
return err
}
- if err = exec.Command("PowerShell", "-ExecutionPolicy", "Bypass", "-File", file).Run(); err != nil {
+ cmd := exec.Command("PowerShell", "-ExecutionPolicy", "Bypass", "-File", file)
+ cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
+ if err = cmd.Run(); err != nil {
return err
}
return nil
diff --git a/vendor/maunium.net/go/gomatrix/client.go b/vendor/maunium.net/go/gomatrix/client.go
index 7725ac3..0806138 100644
--- a/vendor/maunium.net/go/gomatrix/client.go
+++ b/vendor/maunium.net/go/gomatrix/client.go
@@ -6,13 +6,16 @@ package gomatrix
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io"
"io/ioutil"
+ "maunium.net/go/maulogger"
"net/http"
"net/url"
"path"
"strconv"
+ "strings"
"sync"
"time"
)
@@ -26,6 +29,7 @@ type Client struct {
Client *http.Client // The underlying HTTP client which will be used to make HTTP requests.
Syncer Syncer // The thing which can process /sync responses
Store Storer // The thing which can store rooms/tokens/ids
+ Logger maulogger.Logger
// The ?user_id= query parameter for application services. This must be set *prior* to calling a method. If this is empty,
// no user_id parameter will be sent.
@@ -39,6 +43,7 @@ type Client struct {
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
type HTTPError struct {
WrappedError error
+ RespError *RespError
Message string
Code int
}
@@ -177,6 +182,14 @@ func (cli *Client) StopSync() {
cli.incrementSyncingID()
}
+func (cli *Client) LogRequest(req *http.Request, body string) {
+ if cli.Logger == nil {
+ return
+ }
+
+ cli.Logger.Debugfln("%s %s %s", req.Method, req.URL.Path, body)
+}
+
// MakeRequest makes a JSON HTTP request to the given URL.
// If "resBody" is not nil, the response body will be json.Unmarshalled into it.
//
@@ -186,12 +199,14 @@ func (cli *Client) StopSync() {
func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{}, resBody interface{}) ([]byte, error) {
var req *http.Request
var err error
+ logBody := "{}"
if reqBody != nil {
var jsonStr []byte
jsonStr, err = json.Marshal(reqBody)
if err != nil {
return nil, err
}
+ logBody = string(jsonStr)
req, err = http.NewRequest(method, httpURL, bytes.NewBuffer(jsonStr))
} else {
req, err = http.NewRequest(method, httpURL, nil)
@@ -201,6 +216,7 @@ func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{
return nil, err
}
req.Header.Set("Content-Type", "application/json")
+ cli.LogRequest(req, logBody)
res, err := cli.Client.Do(req)
if res != nil {
defer res.Body.Close()
@@ -211,9 +227,11 @@ func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{
contents, err := ioutil.ReadAll(res.Body)
if res.StatusCode/100 != 2 { // not 2xx
var wrap error
- var respErr RespError
- if _ = json.Unmarshal(contents, &respErr); respErr.ErrCode != "" {
+ respErr := &RespError{}
+ if _ = json.Unmarshal(contents, respErr); respErr.ErrCode != "" {
wrap = respErr
+ } else {
+ respErr = nil
}
// If we failed to decode as RespError, don't just drop the HTTP body, include it in the
@@ -227,6 +245,7 @@ func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{
Code: res.StatusCode,
Message: msg,
WrappedError: wrap,
+ RespError: respErr,
}
}
if err != nil {
@@ -342,7 +361,7 @@ func (cli *Client) RegisterDummy(req *ReqRegister) (*RespRegister, error) {
}
}
if res == nil {
- return nil, fmt.Errorf("registration failed: does this server support m.login.dummy?")
+ return nil, fmt.Errorf("registration failed: does this server support m.login.dummy? ")
}
return res, nil
}
@@ -442,17 +461,38 @@ func (cli *Client) SetAvatarURL(url string) (err error) {
// SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
-func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) {
+func (cli *Client) SendMessageEvent(roomID string, eventType EventType, contentJSON interface{}) (resp *RespSendEvent, err error) {
+ txnID := txnID()
+ urlPath := cli.BuildURL("rooms", roomID, "send", eventType.String(), txnID)
+ _, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
+ return
+}
+
+// SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
+// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
+func (cli *Client) SendMassagedMessageEvent(roomID string, eventType EventType, contentJSON interface{}, ts int64) (resp *RespSendEvent, err error) {
txnID := txnID()
- urlPath := cli.BuildURL("rooms", roomID, "send", eventType, txnID)
+ urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "send", eventType.String(), txnID}, map[string]string{
+ "ts": strconv.FormatInt(ts, 10),
+ })
_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
return
}
// SendStateEvent sends a state event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
-func (cli *Client) SendStateEvent(roomID, eventType, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
- urlPath := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
+func (cli *Client) SendStateEvent(roomID string, eventType EventType, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
+ urlPath := cli.BuildURL("rooms", roomID, "state", eventType.String(), stateKey)
+ _, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
+ return
+}
+
+// SendStateEvent sends a state event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
+// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
+func (cli *Client) SendMassagedStateEvent(roomID string, eventType EventType, stateKey string, contentJSON interface{}, ts int64) (resp *RespSendEvent, err error) {
+ urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "state", eventType.String(), stateKey}, map[string]string{
+ "ts": strconv.FormatInt(ts, 10),
+ })
_, err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
return
}
@@ -460,37 +500,39 @@ func (cli *Client) SendStateEvent(roomID, eventType, stateKey string, contentJSO
// SendText sends an m.room.message event into the given room with a msgtype of m.text
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-text
func (cli *Client) SendText(roomID, text string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- TextMessage{"m.text", text})
+ return cli.SendMessageEvent(roomID, EventMessage, Content{
+ MsgType: MsgText,
+ Body: text,
+ })
}
// SendImage sends an m.room.message event into the given room with a msgtype of m.image
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- ImageMessage{
- MsgType: "m.image",
- Body: body,
- URL: url,
- })
+ return cli.SendMessageEvent(roomID, EventMessage, Content{
+ MsgType: MsgImage,
+ Body: body,
+ URL: url,
+ })
}
// SendVideo sends an m.room.message event into the given room with a msgtype of m.video
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- VideoMessage{
- MsgType: "m.video",
- Body: body,
- URL: url,
- })
+ return cli.SendMessageEvent(roomID, EventMessage, Content{
+ MsgType: MsgVideo,
+ Body: body,
+ URL: url,
+ })
}
// SendNotice sends an m.room.message event into the given room with a msgtype of m.notice
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-notice
func (cli *Client) SendNotice(roomID, text string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- TextMessage{"m.notice", text})
+ return cli.SendMessageEvent(roomID, EventMessage, Content{
+ MsgType: MsgNotice,
+ Body: text,
+ })
}
// RedactEvent redacts the given event. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
@@ -569,11 +611,18 @@ func (cli *Client) UserTyping(roomID string, typing bool, timeout int64) (resp *
return
}
+func (cli *Client) SetPresence(status string) (err error) {
+ req := ReqPresence{Presence: status}
+ u := cli.BuildURL("presence", cli.UserID, "status")
+ _, err = cli.MakeRequest("PUT", u, req, nil)
+ return
+}
+
// StateEvent gets a single state event in a room. It will attempt to JSON unmarshal into the given "outContent" struct with
// the HTTP response body, or return an error.
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
-func (cli *Client) StateEvent(roomID, eventType, stateKey string, outContent interface{}) (err error) {
- u := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
+func (cli *Client) StateEvent(roomID string, eventType EventType, stateKey string, outContent interface{}) (err error) {
+ u := cli.BuildURL("rooms", roomID, "state", eventType.String(), stateKey)
_, err = cli.MakeRequest("GET", u, nil, outContent)
return
}
@@ -587,18 +636,48 @@ func (cli *Client) UploadLink(link string) (*RespMediaUpload, error) {
if err != nil {
return nil, err
}
- return cli.UploadToContentRepo(res.Body, res.Header.Get("Content-Type"), res.ContentLength)
+ return cli.Upload(res.Body, res.Header.Get("Content-Type"), res.ContentLength)
+}
+
+func (cli *Client) Download(mxcURL string) (io.ReadCloser, error) {
+ if !strings.HasPrefix(mxcURL, "mxc://") {
+ return nil, errors.New("invalid Matrix content URL")
+ }
+ parts := strings.Split(mxcURL[len("mxc://"):], "/")
+ if len(parts) != 2 {
+ return nil, errors.New("invalid Matrix content URL")
+ }
+ u := cli.BuildBaseURL("_matrix/media/r0/download", parts[0], parts[1])
+ resp, err := cli.Client.Get(u)
+ if err != nil {
+ return nil, err
+ }
+ return resp.Body, nil
+}
+
+func (cli *Client) DownloadBytes(mxcURL string) ([]byte, error) {
+ resp, err := cli.Download(mxcURL)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Close()
+ return ioutil.ReadAll(resp)
+}
+
+func (cli *Client) UploadBytes(data []byte, contentType string) (*RespMediaUpload, error) {
+ return cli.Upload(bytes.NewReader(data), contentType, int64(len(data)))
}
// UploadToContentRepo uploads the given bytes to the content repository and returns an MXC URI.
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
-func (cli *Client) UploadToContentRepo(content io.Reader, contentType string, contentLength int64) (*RespMediaUpload, error) {
+func (cli *Client) Upload(content io.Reader, contentType string, contentLength int64) (*RespMediaUpload, error) {
req, err := http.NewRequest("POST", cli.BuildBaseURL("_matrix/media/r0/upload"), content)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
req.ContentLength = contentLength
+ cli.LogRequest(req, fmt.Sprintf("%d bytes", contentLength))
res, err := cli.Client.Do(req)
if res != nil {
defer res.Body.Close()
@@ -666,6 +745,18 @@ func (cli *Client) Messages(roomID, from, to string, dir rune, limit int) (resp
return
}
+func (cli *Client) GetEvent(roomID, eventID string) (resp *Event, err error) {
+ urlPath := cli.BuildURL("rooms", roomID, "event", eventID)
+ _, err = cli.MakeRequest("GET", urlPath, nil, &resp)
+ return
+}
+
+func (cli *Client) MarkRead(roomID, eventID string) (err error) {
+ urlPath := cli.BuildURL("rooms", roomID, "receipt", "m.read", eventID)
+ _, err = cli.MakeRequest("POST", urlPath, struct{}{}, nil)
+ return
+}
+
// TurnServer returns turn server details and credentials for the client to use when initiating calls.
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-voip-turnserver
func (cli *Client) TurnServer() (resp *RespTurnServer, err error) {
diff --git a/vendor/maunium.net/go/gomatrix/events.go b/vendor/maunium.net/go/gomatrix/events.go
index 7233c7c..30166cd 100644
--- a/vendor/maunium.net/go/gomatrix/events.go
+++ b/vendor/maunium.net/go/gomatrix/events.go
@@ -1,110 +1,413 @@
package gomatrix
import (
- "html"
- "regexp"
+ "encoding/json"
+ "strings"
+ "sync"
+)
+
+type EventTypeClass int
+
+const (
+ // Normal message events
+ MessageEventType EventTypeClass = iota
+ // State events
+ StateEventType
+ // Ephemeral events
+ EphemeralEventType
+ // Account data events
+ AccountDataEventType
+ // Unknown events
+ UnknownEventType
+)
+
+type EventType struct {
+ Type string
+ Class EventTypeClass
+}
+
+func NewEventType(name string) EventType {
+ evtType := EventType{Type: name}
+ evtType.Class = evtType.GuessClass()
+ return evtType
+}
+
+func (et *EventType) IsState() bool {
+ return et.Class == StateEventType
+}
+
+func (et *EventType) IsEphemeral() bool {
+ return et.Class == EphemeralEventType
+}
+
+func (et *EventType) IsCustom() bool {
+ return !strings.HasPrefix(et.Type, "m.")
+}
+
+func (et *EventType) GuessClass() EventTypeClass {
+ switch et.Type {
+ case StateAliases.Type, StateCanonicalAlias.Type, StateCreate.Type, StateJoinRules.Type, StateMember.Type,
+ StatePowerLevels.Type, StateRoomName.Type, StateRoomAvatar.Type, StateTopic.Type, StatePinnedEvents.Type:
+ return StateEventType
+ case EphemeralEventReceipt.Type, EphemeralEventTyping.Type:
+ return EphemeralEventType
+ case AccountDataDirectChats.Type, AccountDataPushRules.Type, AccountDataRoomTags.Type:
+ return AccountDataEventType
+ case EventRedaction.Type, EventMessage.Type, EventSticker.Type:
+ return MessageEventType
+ default:
+ return UnknownEventType
+ }
+}
+
+func (et *EventType) UnmarshalJSON(data []byte) error {
+ err := json.Unmarshal(data, &et.Type)
+ if err != nil {
+ return err
+ }
+ et.Class = et.GuessClass()
+ return nil
+}
+
+func (et *EventType) MarshalJSON() ([]byte, error) {
+ return json.Marshal(&et.Type)
+}
+
+func (et *EventType) String() string {
+ return et.Type
+}
+
+// State events
+var (
+ StateAliases = EventType{"m.room.aliases", StateEventType}
+ StateCanonicalAlias = EventType{"m.room.canonical_alias", StateEventType}
+ StateCreate = EventType{"m.room.create", StateEventType}
+ StateJoinRules = EventType{"m.room.join_rules", StateEventType}
+ StateMember = EventType{"m.room.member", StateEventType}
+ StatePowerLevels = EventType{"m.room.power_levels", StateEventType}
+ StateRoomName = EventType{"m.room.name", StateEventType}
+ StateTopic = EventType{"m.room.topic", StateEventType}
+ StateRoomAvatar = EventType{"m.room.avatar", StateEventType}
+ StatePinnedEvents = EventType{"m.room.pinned_events", StateEventType}
+)
+
+// Message events
+var (
+ EventRedaction = EventType{"m.room.redaction", MessageEventType}
+ EventMessage = EventType{"m.room.message", MessageEventType}
+ EventSticker = EventType{"m.sticker", MessageEventType}
+)
+
+// Ephemeral events
+var (
+ EphemeralEventReceipt = EventType{"m.receipt", EphemeralEventType}
+ EphemeralEventTyping = EventType{"m.receipt", EphemeralEventType}
+)
+
+// Account data events
+var (
+ AccountDataDirectChats = EventType{"m.direct", AccountDataEventType}
+ AccountDataPushRules = EventType{"m.push_rules", AccountDataEventType}
+ AccountDataRoomTags = EventType{"m.tag", AccountDataEventType}
+)
+
+type MessageType string
+
+// Msgtypes
+const (
+ MsgText MessageType = "m.text"
+ MsgEmote = "m.emote"
+ MsgNotice = "m.notice"
+ MsgImage = "m.image"
+ MsgLocation = "m.location"
+ MsgVideo = "m.video"
+ MsgAudio = "m.audio"
+ MsgFile = "m.file"
+)
+
+type Format string
+
+// Message formats
+const (
+ FormatHTML Format = "org.matrix.custom.html"
)
// Event represents a single Matrix event.
type Event struct {
- StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
- Sender string `json:"sender"` // The user ID of the sender of the event
- Type string `json:"type"` // The event type
- Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
- ID string `json:"event_id"` // The unique ID of this event
- RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
- Content map[string]interface{} `json:"content"` // The JSON content of the event.
- Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
- Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
+ StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
+ Sender string `json:"sender"` // The user ID of the sender of the event
+ Type EventType `json:"type"` // The event type
+ Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
+ ID string `json:"event_id"` // The unique ID of this event
+ RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
+ Content Content `json:"content"` // The JSON content of the event.
+ Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
+ Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
+
+ InviteRoomState []StrippedState `json:"invite_room_state"`
+}
+
+func (evt *Event) GetStateKey() string {
+ if evt.StateKey != nil {
+ return *evt.StateKey
+ }
+ return ""
+}
+
+type StrippedState struct {
+ Content Content `json:"content"`
+ Type EventType `json:"type"`
+ StateKey string `json:"state_key"`
}
type Unsigned struct {
- PrevContent map[string]interface{} `json:"prev_content,omitempty"`
- PrevSender string `json:"prev_sender,omitempty"`
- ReplacesState string `json:"replaces_state,omitempty"`
- Age int64 `json:"age"`
+ PrevContent *Content `json:"prev_content,omitempty"`
+ PrevSender string `json:"prev_sender,omitempty"`
+ ReplacesState string `json:"replaces_state,omitempty"`
+ Age int64 `json:"age,omitempty"`
+}
+
+type Content struct {
+ VeryRaw json.RawMessage `json:"-"`
+ Raw map[string]interface{} `json:"-"`
+
+ MsgType MessageType `json:"msgtype,omitempty"`
+ Body string `json:"body,omitempty"`
+ Format Format `json:"format,omitempty"`
+ FormattedBody string `json:"formatted_body,omitempty"`
+
+ Info *FileInfo `json:"info,omitempty"`
+ URL string `json:"url,omitempty"`
+
+ // Membership key for easy access in m.room.member events
+ Membership Membership `json:"membership,omitempty"`
+
+ RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
+
+ PowerLevels
+ Member
+ Aliases []string `json:"aliases,omitempty"`
+ CanonicalAlias
+ RoomName
+ RoomTopic
+
+ RoomTags Tags `json:"tags,omitempty"`
+ TypingUserIDs []string `json:"user_ids,omitempty"`
}
-// Body returns the value of the "body" key in the event content if it is
-// present and is a string.
-func (event *Event) Body() (body string, ok bool) {
- value, exists := event.Content["body"]
- if !exists {
- return
+type serializableContent Content
+
+func (content *Content) UnmarshalJSON(data []byte) error {
+ content.VeryRaw = data
+ if err := json.Unmarshal(data, &content.Raw); err != nil {
+ return err
}
- body, ok = value.(string)
+ return json.Unmarshal(data, (*serializableContent)(content))
+}
+
+func (content *Content) UnmarshalPowerLevels() (pl PowerLevels, err error) {
+ err = json.Unmarshal(content.VeryRaw, &pl)
return
}
-// MessageType returns the value of the "msgtype" key in the event content if
-// it is present and is a string.
-func (event *Event) MessageType() (msgtype string, ok bool) {
- value, exists := event.Content["msgtype"]
- if !exists {
- return
- }
- msgtype, ok = value.(string)
+func (content *Content) UnmarshalMember() (m Member, err error) {
+ err = json.Unmarshal(content.VeryRaw, &m)
+ return
+}
+
+func (content *Content) UnmarshalCanonicalAlias() (ca CanonicalAlias, err error) {
+ err = json.Unmarshal(content.VeryRaw, &ca)
return
}
-// TextMessage is the contents of a Matrix formated message event.
-type TextMessage struct {
- MsgType string `json:"msgtype"`
- Body string `json:"body"`
+func (content *Content) GetInfo() *FileInfo {
+ if content.Info == nil {
+ content.Info = &FileInfo{}
+ }
+ return content.Info
}
-// ImageInfo contains info about an image - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
-type ImageInfo struct {
- Height uint `json:"h,omitempty"`
- Width uint `json:"w,omitempty"`
- Mimetype string `json:"mimetype,omitempty"`
- Size uint `json:"size,omitempty"`
+type Tags map[string]struct {
+ Order string `json:"order"`
}
-// VideoInfo contains info about a video - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
-type VideoInfo struct {
- Mimetype string `json:"mimetype,omitempty"`
- ThumbnailInfo ImageInfo `json:"thumbnail_info"`
- ThumbnailURL string `json:"thumbnail_url,omitempty"`
- Height uint `json:"h,omitempty"`
- Width uint `json:"w,omitempty"`
- Duration uint `json:"duration,omitempty"`
- Size uint `json:"size,omitempty"`
+type RoomName struct {
+ Name string `json:"name,omitempty"`
+}
+
+type RoomTopic struct {
+ Topic string `json:"topic,omitempty"`
+}
+
+// Membership is an enum specifying the membership state of a room member.
+type Membership string
+
+// The allowed membership states as specified in spec section 10.5.5.
+const (
+ MembershipJoin Membership = "join"
+ MembershipLeave Membership = "leave"
+ MembershipInvite Membership = "invite"
+ MembershipBan Membership = "ban"
+ MembershipKnock Membership = "knock"
+)
+
+type Member struct {
+ Membership Membership `json:"membership,omitempty"`
+ AvatarURL string `json:"avatar_url,omitempty"`
+ Displayname string `json:"displayname,omitempty"`
+ ThirdPartyInvite *ThirdPartyInvite `json:"third_party_invite,omitempty"`
+ Reason string `json:"reason,omitempty"`
+}
+
+type ThirdPartyInvite struct {
+ DisplayName string `json:"display_name"`
+ Signed struct {
+ Token string `json:"token"`
+ Signatures json.RawMessage `json:"signatures"`
+ MXID string `json:"mxid"`
+ }
+}
+
+type CanonicalAlias struct {
+ Alias string `json:"alias,omitempty"`
+}
+
+type PowerLevels struct {
+ usersLock sync.RWMutex `json:"-"`
+ Users map[string]int `json:"users,omitempty"`
+ UsersDefault int `json:"users_default,omitempty"`
+
+ eventsLock sync.RWMutex `json:"-"`
+ Events map[string]int `json:"events,omitempty"`
+ EventsDefault int `json:"events_default,omitempty"`
+
+ StateDefaultPtr *int `json:"state_default,omitempty"`
+
+ InvitePtr *int `json:"invite,omitempty"`
+ KickPtr *int `json:"kick,omitempty"`
+ BanPtr *int `json:"ban,omitempty"`
+ RedactPtr *int `json:"redact,omitempty"`
+}
+
+func (pl *PowerLevels) Invite() int {
+ if pl.InvitePtr != nil {
+ return *pl.InvitePtr
+ }
+ return 50
+}
+
+func (pl *PowerLevels) Kick() int {
+ if pl.KickPtr != nil {
+ return *pl.KickPtr
+ }
+ return 50
}
-// VideoMessage is an m.video - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
-type VideoMessage struct {
- MsgType string `json:"msgtype"`
- Body string `json:"body"`
- URL string `json:"url"`
- Info VideoInfo `json:"info"`
+func (pl *PowerLevels) Ban() int {
+ if pl.BanPtr != nil {
+ return *pl.BanPtr
+ }
+ return 50
+}
+
+func (pl *PowerLevels) Redact() int {
+ if pl.RedactPtr != nil {
+ return *pl.RedactPtr
+ }
+ return 50
+}
+
+func (pl *PowerLevels) StateDefault() int {
+ if pl.StateDefaultPtr != nil {
+ return *pl.StateDefaultPtr
+ }
+ return 50
+}
+
+func (pl *PowerLevels) GetUserLevel(userID string) int {
+ pl.usersLock.RLock()
+ defer pl.usersLock.RUnlock()
+ level, ok := pl.Users[userID]
+ if !ok {
+ return pl.UsersDefault
+ }
+ return level
+}
+
+func (pl *PowerLevels) SetUserLevel(userID string, level int) {
+ pl.usersLock.Lock()
+ defer pl.usersLock.Unlock()
+ if level == pl.UsersDefault {
+ delete(pl.Users, userID)
+ } else {
+ pl.Users[userID] = level
+ }
+}
+
+func (pl *PowerLevels) EnsureUserLevel(userID string, level int) bool {
+ existingLevel := pl.GetUserLevel(userID)
+ if existingLevel != level {
+ pl.SetUserLevel(userID, level)
+ return true
+ }
+ return false
}
-// ImageMessage is an m.image event
-type ImageMessage struct {
- MsgType string `json:"msgtype"`
- Body string `json:"body"`
- URL string `json:"url"`
- Info ImageInfo `json:"info"`
+func (pl *PowerLevels) GetEventLevel(eventType EventType) int {
+ pl.eventsLock.RLock()
+ defer pl.eventsLock.RUnlock()
+ level, ok := pl.Events[eventType.String()]
+ if !ok {
+ if eventType.IsState() {
+ return pl.StateDefault()
+ }
+ return pl.EventsDefault
+ }
+ return level
}
-// An HTMLMessage is the contents of a Matrix HTML formated message event.
-type HTMLMessage struct {
- Body string `json:"body"`
- MsgType string `json:"msgtype"`
- Format string `json:"format"`
- FormattedBody string `json:"formatted_body"`
+func (pl *PowerLevels) SetEventLevel(eventType EventType, level int) {
+ pl.eventsLock.Lock()
+ defer pl.eventsLock.Unlock()
+ if (eventType.IsState() && level == pl.StateDefault()) || (!eventType.IsState() && level == pl.EventsDefault) {
+ delete(pl.Events, eventType.String())
+ } else {
+ pl.Events[eventType.String()] = level
+ }
+}
+
+func (pl *PowerLevels) EnsureEventLevel(eventType EventType, level int) bool {
+ existingLevel := pl.GetEventLevel(eventType)
+ if existingLevel != level {
+ pl.SetEventLevel(eventType, level)
+ return true
+ }
+ return false
}
-var htmlRegex = regexp.MustCompile("<[^<]+?>")
+type FileInfo struct {
+ MimeType string `json:"mimetype,omitempty"`
+ ThumbnailInfo *FileInfo `json:"thumbnail_info,omitempty"`
+ ThumbnailURL string `json:"thumbnail_url,omitempty"`
+ Height int `json:"h,omitempty"`
+ Width int `json:"w,omitempty"`
+ Duration uint `json:"duration,omitempty"`
+ Size int `json:"size,omitempty"`
+}
-// GetHTMLMessage returns an HTMLMessage with the body set to a stripped version of the provided HTML, in addition
-// to the provided HTML.
-func GetHTMLMessage(msgtype, htmlText string) HTMLMessage {
- return HTMLMessage{
- Body: html.UnescapeString(htmlRegex.ReplaceAllLiteralString(htmlText, "")),
- MsgType: msgtype,
- Format: "org.matrix.custom.html",
- FormattedBody: htmlText,
+func (fileInfo *FileInfo) GetThumbnailInfo() *FileInfo {
+ if fileInfo.ThumbnailInfo == nil {
+ fileInfo.ThumbnailInfo = &FileInfo{}
}
+ return fileInfo.ThumbnailInfo
+}
+
+type RelatesTo struct {
+ InReplyTo InReplyTo `json:"m.in_reply_to,omitempty"`
+}
+
+type InReplyTo struct {
+ EventID string `json:"event_id,omitempty"`
+ // Not required, just for future-proofing
+ RoomID string `json:"room_id,omitempty"`
}
diff --git a/vendor/maunium.net/go/gomatrix/reply.go b/vendor/maunium.net/go/gomatrix/reply.go
new file mode 100644
index 0000000..6985421
--- /dev/null
+++ b/vendor/maunium.net/go/gomatrix/reply.go
@@ -0,0 +1,96 @@
+package gomatrix
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+
+ "golang.org/x/net/html"
+)
+
+var HTMLReplyFallbackRegex = regexp.MustCompile(`^<mx-reply>[\s\S]+?</mx-reply>`)
+
+func TrimReplyFallbackHTML(html string) string {
+ return HTMLReplyFallbackRegex.ReplaceAllString(html, "")
+}
+
+func TrimReplyFallbackText(text string) string {
+ if !strings.HasPrefix(text, "> ") || !strings.Contains(text, "\n") {
+ return text
+ }
+
+ lines := strings.Split(text, "\n")
+ for len(lines) > 0 && strings.HasPrefix(lines[0], "> ") {
+ lines = lines[1:]
+ }
+ return strings.TrimSpace(strings.Join(lines, "\n"))
+}
+
+func (content *Content) RemoveReplyFallback() {
+ if len(content.GetReplyTo()) > 0 {
+ if content.Format == FormatHTML {
+ content.FormattedBody = TrimReplyFallbackHTML(content.FormattedBody)
+ }
+ content.Body = TrimReplyFallbackText(content.Body)
+ }
+}
+
+func (content *Content) GetReplyTo() string {
+ if content.RelatesTo != nil {
+ return content.RelatesTo.InReplyTo.EventID
+ }
+ return ""
+}
+
+const ReplyFormat = `<mx-reply><blockquote>
+<a href="https://matrix.to/#/%s/%s">In reply to</a>
+<a href="https://matrix.to/#/%s">%s</a>
+%s
+</blockquote></mx-reply>
+`
+
+func (evt *Event) GenerateReplyFallbackHTML() string {
+ body := evt.Content.FormattedBody
+ if len(body) == 0 {
+ body = html.EscapeString(evt.Content.Body)
+ }
+
+ senderDisplayName := evt.Sender
+
+ return fmt.Sprintf(ReplyFormat, evt.RoomID, evt.ID, evt.Sender, senderDisplayName, body)
+}
+
+func (evt *Event) GenerateReplyFallbackText() string {
+ body := evt.Content.Body
+ lines := strings.Split(strings.TrimSpace(body), "\n")
+ firstLine, lines := lines[0], lines[1:]
+
+ senderDisplayName := evt.Sender
+
+ var fallbackText strings.Builder
+ fmt.Fprintf(&fallbackText, "> <%s> %s", senderDisplayName, firstLine)
+ for _, line := range lines {
+ fmt.Fprintf(&fallbackText, "\n> %s", line)
+ }
+ fallbackText.WriteString("\n\n")
+ return fallbackText.String()
+}
+
+func (content *Content) SetReply(inReplyTo *Event) {
+ if content.RelatesTo == nil {
+ content.RelatesTo = &RelatesTo{}
+ }
+ content.RelatesTo.InReplyTo = InReplyTo{
+ EventID: inReplyTo.ID,
+ RoomID: inReplyTo.RoomID,
+ }
+
+ if content.MsgType == MsgText || content.MsgType == MsgNotice {
+ if len(content.FormattedBody) == 0 || content.Format != FormatHTML {
+ content.FormattedBody = html.EscapeString(content.Body)
+ content.Format = FormatHTML
+ }
+ content.FormattedBody = inReplyTo.GenerateReplyFallbackHTML() + content.FormattedBody
+ content.Body = inReplyTo.GenerateReplyFallbackText() + content.Body
+ }
+}
diff --git a/vendor/maunium.net/go/gomatrix/requests.go b/vendor/maunium.net/go/gomatrix/requests.go
index af99a22..d8e10a6 100644
--- a/vendor/maunium.net/go/gomatrix/requests.go
+++ b/vendor/maunium.net/go/gomatrix/requests.go
@@ -31,7 +31,7 @@ type ReqCreateRoom struct {
Invite []string `json:"invite,omitempty"`
Invite3PID []ReqInvite3PID `json:"invite_3pid,omitempty"`
CreationContent map[string]interface{} `json:"creation_content,omitempty"`
- InitialState []Event `json:"initial_state,omitempty"`
+ InitialState []*Event `json:"initial_state,omitempty"`
Preset string `json:"preset,omitempty"`
IsDirect bool `json:"is_direct,omitempty"`
}
@@ -74,5 +74,9 @@ type ReqUnbanUser struct {
// ReqTyping is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
type ReqTyping struct {
Typing bool `json:"typing"`
- Timeout int64 `json:"timeout"`
+ Timeout int64 `json:"timeout,omitempty"`
}
+
+type ReqPresence struct {
+ Presence string `json:"presence"`
+} \ No newline at end of file
diff --git a/vendor/maunium.net/go/gomatrix/responses.go b/vendor/maunium.net/go/gomatrix/responses.go
index 6d43bd3..9524d62 100644
--- a/vendor/maunium.net/go/gomatrix/responses.go
+++ b/vendor/maunium.net/go/gomatrix/responses.go
@@ -64,7 +64,7 @@ type RespJoinedMembers struct {
// RespMessages is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
type RespMessages struct {
Start string `json:"start"`
- Chunk []Event `json:"chunk"`
+ Chunk []*Event `json:"chunk"`
End string `json:"end"`
}
diff --git a/vendor/maunium.net/go/gomatrix/room.go b/vendor/maunium.net/go/gomatrix/room.go
index c9b2351..80a91d8 100644
--- a/vendor/maunium.net/go/gomatrix/room.go
+++ b/vendor/maunium.net/go/gomatrix/room.go
@@ -3,7 +3,7 @@ package gomatrix
// Room represents a single Matrix room.
type Room struct {
ID string
- State map[string]map[string]*Event
+ State map[EventType]map[string]*Event
}
// UpdateState updates the room's current state with the given Event. This will clobber events based
@@ -17,7 +17,7 @@ func (room Room) UpdateState(event *Event) {
}
// GetStateEvent returns the state event for the given type/state_key combo, or nil.
-func (room Room) GetStateEvent(eventType string, stateKey string) *Event {
+func (room Room) GetStateEvent(eventType EventType, stateKey string) *Event {
stateEventMap, _ := room.State[eventType]
event, _ := stateEventMap[stateKey]
return event
@@ -25,17 +25,11 @@ func (room Room) GetStateEvent(eventType string, stateKey string) *Event {
// GetMembershipState returns the membership state of the given user ID in this room. If there is
// no entry for this member, 'leave' is returned for consistency with left users.
-func (room Room) GetMembershipState(userID string) string {
- state := "leave"
- event := room.GetStateEvent("m.room.member", userID)
+func (room Room) GetMembershipState(userID string) Membership {
+ state := MembershipLeave
+ event := room.GetStateEvent(StateMember, userID)
if event != nil {
- membershipState, found := event.Content["membership"]
- if found {
- mState, isString := membershipState.(string)
- if isString {
- state = mState
- }
- }
+ state = event.Content.Membership
}
return state
}
@@ -45,6 +39,6 @@ func NewRoom(roomID string) *Room {
// Init the State map and return a pointer to the Room
return &Room{
ID: roomID,
- State: make(map[string]map[string]*Event),
+ State: make(map[EventType]map[string]*Event),
}
}
diff --git a/vendor/maunium.net/go/gomatrix/sync.go b/vendor/maunium.net/go/gomatrix/sync.go
index e1233a4..09170d7 100644
--- a/vendor/maunium.net/go/gomatrix/sync.go
+++ b/vendor/maunium.net/go/gomatrix/sync.go
@@ -25,7 +25,7 @@ type Syncer interface {
type DefaultSyncer struct {
UserID string
Store Storer
- listeners map[string][]OnEventListener // event type to listeners array
+ listeners map[EventType][]OnEventListener // event type to listeners array
}
// OnEventListener can be used with DefaultSyncer.OnEventType to be informed of incoming events.
@@ -36,7 +36,7 @@ func NewDefaultSyncer(userID string, store Storer) *DefaultSyncer {
return &DefaultSyncer{
UserID: userID,
Store: store,
- listeners: make(map[string][]OnEventListener),
+ listeners: make(map[EventType][]OnEventListener),
}
}
@@ -88,7 +88,7 @@ func (s *DefaultSyncer) ProcessResponse(res *RespSync, since string) (err error)
// OnEventType allows callers to be notified when there are new events for the given event type.
// There are no duplicate checks.
-func (s *DefaultSyncer) OnEventType(eventType string, callback OnEventListener) {
+func (s *DefaultSyncer) OnEventType(eventType EventType, callback OnEventListener) {
_, exists := s.listeners[eventType]
if !exists {
s.listeners[eventType] = []OnEventListener{}
@@ -112,13 +112,8 @@ func (s *DefaultSyncer) shouldProcessResponse(resp *RespSync, since string) bool
for roomID, roomData := range resp.Rooms.Join {
for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
e := roomData.Timeline.Events[i]
- if e.Type == "m.room.member" && e.StateKey != nil && *e.StateKey == s.UserID {
- m := e.Content["membership"]
- mship, ok := m.(string)
- if !ok {
- continue
- }
- if mship == "join" {
+ if e.Type == StateMember && e.GetStateKey() == s.UserID {
+ if e.Content.Membership == "join" {
_, ok := resp.Rooms.Join[roomID]
if !ok {
continue
diff --git a/vendor/maunium.net/go/maulogger/LICENSE b/vendor/maunium.net/go/maulogger/LICENSE
new file mode 100644
index 0000000..c9739fb
--- /dev/null
+++ b/vendor/maunium.net/go/maulogger/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Tulir Asokan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/maunium.net/go/maulogger/README.md b/vendor/maunium.net/go/maulogger/README.md
new file mode 100644
index 0000000..68fe253
--- /dev/null
+++ b/vendor/maunium.net/go/maulogger/README.md
@@ -0,0 +1,6 @@
+# maulogger
+A logger in Go.
+
+Docs: [godoc.org/maunium.net/go/maulogger](https://godoc.org/maunium.net/go/maulogger)
+
+Go get: `go get maunium.net/go/maulogger`
diff --git a/vendor/maunium.net/go/maulogger/logger.go b/vendor/maunium.net/go/maulogger/logger.go
new file mode 100644
index 0000000..e887237
--- /dev/null
+++ b/vendor/maunium.net/go/maulogger/logger.go
@@ -0,0 +1,219 @@
+package maulog
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "time"
+)
+
+// Level is the severity level of a log entry.
+type Level struct {
+ Name string
+ Severity, Color int
+}
+
+// LogWriter writes to the log with an optional prefix
+type LogWriter struct {
+ Level Level
+ Prefix string
+}
+
+func (lw LogWriter) Write(p []byte) (n int, err error) {
+ log(lw.Level, fmt.Sprint(lw.Prefix, string(p)))
+ return len(p), nil
+}
+
+// GetColor gets the ANSI escape color code for the log level.
+func (lvl Level) GetColor() []byte {
+ if lvl.Color < 0 {
+ return []byte("")
+ }
+ return []byte(fmt.Sprintf("\x1b[%dm", lvl.Color))
+}
+
+// GetReset gets the ANSI escape reset code.
+func (lvl Level) GetReset() []byte {
+ if lvl.Color < 0 {
+ return []byte("")
+ }
+ return []byte("\x1b[0m")
+}
+
+var (
+ // Debug is the level for debug messages.
+ Debug = Level{Name: "DEBUG", Color: 36, Severity: 0}
+ // Info is the level for basic log messages.
+ Info = Level{Name: "INFO", Color: -1, Severity: 10}
+ // Warn is the level saying that something went wrong, but the program will continue operating mostly normally.
+ Warn = Level{Name: "WARN", Color: 33, Severity: 50}
+ // Error is the level saying that something went wrong and the program may not operate as expected, but will still continue.
+ Error = Level{Name: "ERROR", Color: 31, Severity: 100}
+ // Fatal is the level saying that something went wrong and the program will not operate normally.
+ Fatal = Level{Name: "FATAL", Color: 35, Severity: 9001}
+)
+
+// PrintLevel tells the first severity level at which messages should be printed to stdout
+var PrintLevel = 10
+
+// PrintDebug means PrintLevel = 0, kept for backwards compatibility
+var PrintDebug = false
+
+// FileTimeformat is the time format used in log file names.
+var FileTimeformat = "2006-01-02"
+
+// FileformatArgs is an undocumented integer.
+var FileformatArgs = 3
+
+// Fileformat is the format used for log file names.
+var Fileformat = func(now string, i int) string { return fmt.Sprintf("%[1]s-%02[2]d.log", now, i) }
+
+// Timeformat is the time format used in logging.
+var Timeformat = "15:04:05 02.01.2006"
+
+var writer *bufio.Writer
+var lines int
+
+// InitWithWriter initializes MauLogger with the given writer.
+func InitWithWriter(w *bufio.Writer) {
+ writer = w
+}
+
+// Init initializes MauLogger.
+func Init() {
+ // Find the next file name.
+ now := time.Now().Format(FileTimeformat)
+ i := 1
+ for ; ; i++ {
+ if _, err := os.Stat(Fileformat(now, i)); os.IsNotExist(err) {
+ break
+ }
+ if i == 99 {
+ i = 1
+ break
+ }
+ }
+ // Open the file
+ file, err := os.OpenFile(Fileformat(now, i), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0700)
+ if err != nil {
+ panic(err)
+ }
+ if file == nil {
+ panic(os.ErrInvalid)
+ }
+ // Create a writer
+ writer = bufio.NewWriter(file)
+}
+
+// Debugf formats and logs a debug message.
+func Debugf(message string, args ...interface{}) {
+ logln(Debug, fmt.Sprintf(message, args...))
+}
+
+// Printf formats and logs a string in the Info log level.
+func Printf(message string, args ...interface{}) {
+ Infof(message, args...)
+}
+
+// Infof formats and logs a string in the Info log level.
+func Infof(message string, args ...interface{}) {
+ logln(Info, fmt.Sprintf(message, args...))
+}
+
+// Warnf formats and logs a string in the Warn log level.
+func Warnf(message string, args ...interface{}) {
+ logln(Warn, fmt.Sprintf(message, args...))
+}
+
+// Errorf formats and logs a string in the Error log level.
+func Errorf(message string, args ...interface{}) {
+ logln(Error, fmt.Sprintf(message, args...))
+}
+
+// Fatalf formats and logs a string in the Fatal log level.
+func Fatalf(message string, args ...interface{}) {
+ logln(Fatal, fmt.Sprintf(message, args...))
+}
+
+// Logf formats and logs a message in the given log level.
+func Logf(level Level, message string, args ...interface{}) {
+ logln(level, fmt.Sprintf(message, args...))
+}
+
+// Debugln logs a debug message.
+func Debugln(args ...interface{}) {
+ log(Debug, fmt.Sprintln(args...))
+}
+
+// Println logs a string in the Info log level.
+func Println(args ...interface{}) {
+ Infoln(args...)
+}
+
+// Infoln logs a string in the Info log level.
+func Infoln(args ...interface{}) {
+ log(Info, fmt.Sprintln(args...))
+}
+
+// Warnln logs a string in the Warn log level.
+func Warnln(args ...interface{}) {
+ log(Warn, fmt.Sprintln(args...))
+}
+
+// Errorln logs a string in the Error log level.
+func Errorln(args ...interface{}) {
+ log(Error, fmt.Sprintln(args...))
+}
+
+// Fatalln logs a string in the Fatal log level.
+func Fatalln(args ...interface{}) {
+ log(Fatal, fmt.Sprintln(args...))
+}
+
+// Logln logs a message in the given log level.
+func Logln(level Level, args ...interface{}) {
+ log(level, fmt.Sprintln(args...))
+}
+
+func logln(level Level, message string) {
+ log(level, fmt.Sprintln(message))
+}
+
+func log(level Level, message string) {
+ // Prefix the message with the timestamp and log level.
+ msg := []byte(fmt.Sprintf("[%[1]s] [%[2]s] %[3]s", time.Now().Format(Timeformat), level.Name, message))
+
+ if writer != nil {
+ // Write it to the log file.
+ _, err := writer.Write(msg)
+ if err != nil {
+ panic(err)
+ }
+ lines++
+ // Flush the file if needed
+ if lines == 5 {
+ lines = 0
+ writer.Flush()
+ }
+ }
+
+ // Print to stdout using correct color
+ if level.Severity >= PrintLevel || PrintDebug {
+ if level.Severity >= Error.Severity {
+ os.Stderr.Write(level.GetColor())
+ os.Stderr.Write(msg)
+ os.Stderr.Write(level.GetReset())
+ } else {
+ os.Stdout.Write(level.GetColor())
+ os.Stdout.Write(msg)
+ os.Stdout.Write(level.GetReset())
+ }
+ }
+}
+
+// Shutdown cleans up the logger.
+func Shutdown() {
+ if writer != nil {
+ writer.Flush()
+ }
+}