From a55ea42d7f5900bd5fc8fad047040c7865824f33 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 15 Jun 2019 01:11:51 +0300 Subject: Unbreak things --- ui/commands.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ui/commands.go') diff --git a/ui/commands.go b/ui/commands.go index 5bcba98..cd770b6 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -86,26 +86,26 @@ func cmdHeapProfile(cmd *Command) { func cmdRainbow(cmd *Command) { text := strings.Join(cmd.Args, " ") var html strings.Builder - fmt.Fprint(&html, "**🌈** ") + _, _ = fmt.Fprint(&html, "**🌈** ") for i, char := range text { if unicode.IsSpace(char) { html.WriteRune(char) continue } color := rainbow.GetInterpolatedColorFor(float64(i) / float64(len(text))).Hex() - fmt.Fprintf(&html, "%c", color, char) + _, _ = fmt.Fprintf(&html, "%c", color, char) } go cmd.Room.SendMessage("m.text", html.String()) cmd.UI.Render() } func cmdQuit(cmd *Command) { - cmd.Gomuks.Stop() + cmd.Gomuks.Stop(true) } func cmdClearCache(cmd *Command) { cmd.Config.Clear() - cmd.Gomuks.Stop() + cmd.Gomuks.Stop(false) } func cmdUnknownCommand(cmd *Command) { -- cgit v1.2.3-70-g09d2 From 160b035c4d5b88516cb4d1f4e26ec2e2e0262bcc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 15 Jun 2019 17:04:08 +0300 Subject: Unbreak more things --- .gitignore | 1 + gomuks.go | 6 +-- matrix/matrix.go | 29 ++++++++++--- matrix/rooms/room.go | 108 +++++++++++++++++++++++++++++++++------------- matrix/rooms/roomcache.go | 32 ++++++++++---- ui/command-processor.go | 1 + ui/commands.go | 52 ++++++++++++++++++++-- ui/message-view.go | 17 ++++++++ ui/room-list.go | 5 ++- ui/room-view.go | 23 ++++++++-- 10 files changed, 218 insertions(+), 56 deletions(-) (limited to 'ui/commands.go') diff --git a/.gitignore b/.gitignore index b8d8f8e..8bf7688 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ gomuks coverage.out coverage.html deb/usr +*.prof diff --git a/gomuks.go b/gomuks.go index 5b6ed92..1a8cec1 100644 --- a/gomuks.go +++ b/gomuks.go @@ -58,8 +58,6 @@ func NewGomuks(uiProvider ifc.UIProvider, configDir, cacheDir string) *Gomuks { // Save saves the active session and message history. func (gmx *Gomuks) Save() { gmx.config.SaveAll() - //debug.Print("Saving history...") - //gmx.ui.MainView().SaveAllHistory() } // StartAutosave calls Save() every minute until it receives a stop signal @@ -70,7 +68,9 @@ func (gmx *Gomuks) StartAutosave() { for { select { case <-ticker.C: - gmx.Save() + if gmx.config.AuthCache.InitialSyncDone { + gmx.Save() + } case val := <-gmx.stop: if val { return diff --git a/matrix/matrix.go b/matrix/matrix.go index de99801..8c19b24 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -221,7 +221,15 @@ func (c *Container) OnLogin() { c.syncer.InitDoneCallback = func() { debug.Print("Initial sync done") c.config.AuthCache.InitialSyncDone = true - c.config.SaveAuthCache() + debug.Print("Updating title caches") + for _, room := range c.config.Rooms.Map { + room.GetTitle() + } + debug.Print("Cleaning cached rooms from memory") + c.config.Rooms.ForceClean() + debug.Print("Saving all data") + c.config.SaveAll() + debug.Print("Adding rooms to UI") c.ui.MainView().SetRooms(c.config.Rooms) c.ui.Render() } @@ -294,17 +302,21 @@ func (c *Container) SendPreferencesToMatrix() { // HandleMessage is the event handler for the m.room.message timeline event. func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) { - if source&EventSourceLeave != 0 || source&EventSourceState != 0 { + room := c.GetOrCreateRoom(evt.RoomID) + if source&EventSourceLeave != 0 { + room.HasLeft = true + return + } else if source&EventSourceState != 0 { return } - room := c.GetOrCreateRoom(evt.RoomID) err := c.history.Append(room, []*mautrix.Event{evt}) if err != nil { debug.Printf("Failed to add event %s to history: %v", evt.ID, err) } - if !c.config.AuthCache.InitialSyncDone { + if !c.config.AuthCache.InitialSyncDone || !room.Loaded() { + room.LastReceivedMessage = time.Unix(evt.Timestamp/1000, evt.Timestamp%1000*1000) return } @@ -327,7 +339,7 @@ func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) { c.ui.Render() } } else { - debug.Printf("Parsing event %s type %s %v from %s in %s failed (ParseEvent() returned nil).", evt.ID, evt.Type, evt.Content.Raw, evt.Sender, evt.RoomID) + debug.Printf("Parsing event %s type %s %v from %s in %s failed (ParseEvent() returned nil).", evt.ID, evt.Type.String(), evt.Content.Raw, evt.Sender, evt.RoomID) } } @@ -335,6 +347,9 @@ func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) { func (c *Container) HandleMembership(source EventSource, evt *mautrix.Event) { isLeave := source&EventSourceLeave != 0 isTimeline := source&EventSourceTimeline != 0 + if isLeave { + c.GetOrCreateRoom(evt.RoomID).HasLeft = true + } isNonTimelineLeave := isLeave && !isTimeline if !c.config.AuthCache.InitialSyncDone && isNonTimelineLeave { return @@ -437,7 +452,7 @@ func (c *Container) parseDirectChatInfo(evt *mautrix.Event) map[*rooms.Room]bool continue } - room := c.GetRoom(roomID) + room := c.GetOrCreateRoom(roomID) if room != nil && !room.HasLeft { directChats[room] = true } @@ -473,7 +488,7 @@ func (c *Container) HandlePushRules(source EventSource, evt *mautrix.Event) { // HandleTag is the event handler for the m.tag account data event. func (c *Container) HandleTag(source EventSource, evt *mautrix.Event) { - room := c.config.GetRoom(evt.RoomID) + room := c.GetOrCreateRoom(evt.RoomID) newTags := make([]rooms.RoomTag, len(evt.Content.RoomTags)) index := 0 diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go index 87c3780..972a32a 100644 --- a/matrix/rooms/room.go +++ b/matrix/rooms/room.go @@ -115,6 +115,12 @@ type Room struct { cache *RoomCache // Lock for state and other room stuff. lock sync.RWMutex + // Function to call when room state is unloaded. + onUnload func() bool + // Function to call when room state is loaded. + onLoad func() bool + // Whether or not the room state has changed + changed bool // Room state cache linked list. prev *Room @@ -133,10 +139,13 @@ func (room *Room) Loaded() bool { } func (room *Room) Load() { + room.cache.TouchNode(room) if room.Loaded() { return } - room.cache.TouchNode(room) + if room.onLoad != nil && !room.onLoad() { + return + } room.lock.Lock() room.load() room.lock.Unlock() @@ -146,7 +155,7 @@ func (room *Room) load() { if room.Loaded() { return } - debug.Print("Loading state for room", room.ID) + debug.Print("Loading state for room", room.ID, "from disk") room.state = make(map[mautrix.EventType]map[string]*mautrix.Event) file, err := os.OpenFile(room.path, os.O_RDONLY, 0600) if err != nil { @@ -168,9 +177,17 @@ func (room *Room) load() { if err = dec.Decode(&room.state); err != nil { debug.Print("Failed to decode room state:", err) } + room.changed = false } -func (room *Room) Unload() { +func (room *Room) Touch() { + room.cache.TouchNode(room) +} + +func (room *Room) Unload() bool { + if room.onUnload != nil && !room.onUnload() { + return false + } debug.Print("Unloading", room.ID) room.Save() room.state = nil @@ -179,14 +196,27 @@ func (room *Room) Unload() { room.canonicalAliasCache = "" room.firstMemberCache = nil room.secondMemberCache = nil + return true +} + +func (room *Room) SetOnUnload(fn func() bool) { + room.onUnload = fn +} + +func (room *Room) SetOnLoad(fn func() bool) { + room.onLoad = fn } func (room *Room) Save() { if !room.Loaded() { - debug.Print("Failed to save room state: room not loaded") + debug.Print("Failed to save room", room.ID, "state: room not loaded") + return + } + if !room.changed { + debug.Print("Not saving", room.ID, "as state hasn't changed") return } - debug.Print("Saving state for room", room.ID) + debug.Print("Saving state for room", room.ID, "to disk") file, err := os.OpenFile(room.path, os.O_WRONLY|os.O_CREATE, 0600) if err != nil { debug.Print("Failed to open room state file for writing:", err) @@ -298,40 +328,51 @@ func (room *Room) UpdateState(event *mautrix.Event) { room.Load() room.lock.Lock() defer room.lock.Unlock() + room.changed = true _, exists := room.state[event.Type] if !exists { room.state[event.Type] = make(map[string]*mautrix.Event) } switch event.Type { case mautrix.StateRoomName: - room.NameCache = "" + room.NameCache = event.Content.Name + room.nameCacheSource = ExplicitRoomName case mautrix.StateCanonicalAlias: if room.nameCacheSource <= CanonicalAliasRoomName { - room.NameCache = "" + room.NameCache = event.Content.Alias + room.nameCacheSource = CanonicalAliasRoomName } - room.canonicalAliasCache = "" + room.canonicalAliasCache = event.Content.Alias case mautrix.StateAliases: if room.nameCacheSource <= AliasRoomName { room.NameCache = "" } room.aliasesCache = nil case mautrix.StateMember: - room.memberCache = nil - room.firstMemberCache = nil - room.secondMemberCache = nil + if room.memberCache != nil { + userID := event.GetStateKey() + if event.Content.Membership == mautrix.MembershipLeave || event.Content.Membership == mautrix.MembershipBan { + delete(room.memberCache, userID) + } else if event.Content.Membership == mautrix.MembershipInvite || event.Content.Membership == mautrix.MembershipJoin { + member := room.eventToMember(userID, &event.Content) + existingMember, ok := room.memberCache[userID] + if ok { + *existingMember = *member + } else { + room.memberCache[userID] = member + room.updateNthMemberCache(userID, member) + } + } + } if room.nameCacheSource <= MemberRoomName { room.NameCache = "" } case mautrix.StateTopic: - room.topicCache = "" + room.topicCache = event.Content.Topic } - stateKey := "" - if event.StateKey != nil { - stateKey = *event.StateKey - } if event.Type != mautrix.StateMember { - debug.Printf("Updating state %s#%s for %s", event.Type, stateKey, room.ID) + debug.Printf("Updating state %s#%s for %s", event.Type.String(), event.GetStateKey(), room.ID) } if event.StateKey == nil { @@ -477,6 +518,25 @@ func (room *Room) GetTitle() string { return room.NameCache } +func (room *Room) eventToMember(userID string, content *mautrix.Content) *mautrix.Member { + member := &content.Member + member.Membership = content.Membership + if len(member.Displayname) == 0 { + member.Displayname = userID + } + return member +} + +func (room *Room) updateNthMemberCache(userID string, member *mautrix.Member) { + if userID != room.SessionUserID { + if room.firstMemberCache == nil { + room.firstMemberCache = member + } else if room.secondMemberCache == nil { + room.secondMemberCache = member + } + } +} + // createMemberCache caches all member events into a easily processable MXID -> *Member map. func (room *Room) createMemberCache() map[string]*mautrix.Member { if len(room.memberCache) > 0 { @@ -489,20 +549,10 @@ func (room *Room) createMemberCache() map[string]*mautrix.Member { room.secondMemberCache = nil if events != nil { for userID, event := range events { - member := &event.Content.Member - member.Membership = event.Content.Membership - if len(member.Displayname) == 0 { - member.Displayname = userID - } - if userID != room.SessionUserID { - if room.firstMemberCache == nil { - room.firstMemberCache = member - } else if room.secondMemberCache == nil { - room.secondMemberCache = member - } - } + member := room.eventToMember(userID, &event.Content) if member.Membership == mautrix.MembershipJoin || member.Membership == mautrix.MembershipInvite { cache[userID] = member + room.updateNthMemberCache(userID, member) } } } diff --git a/matrix/rooms/roomcache.go b/matrix/rooms/roomcache.go index 03e3ad8..6fc400c 100644 --- a/matrix/rooms/roomcache.go +++ b/matrix/rooms/roomcache.go @@ -106,7 +106,7 @@ func (cache *RoomCache) LoadList() error { func (cache *RoomCache) SaveLoadedRooms() { cache.Lock() defer cache.Unlock() - cache.clean() + cache.clean(false) for node := cache.head; node != nil; node = node.prev { node.Save() } @@ -194,8 +194,7 @@ func (cache *RoomCache) GetOrCreate(roomID string) *Room { func (cache *RoomCache) get(roomID string) *Room { node, ok := cache.Map[roomID] - if ok && node != nil && node.Loaded() { - cache.touch(node) + if ok && node != nil { return node } return nil @@ -273,18 +272,29 @@ func (cache *RoomCache) llPush(node *Room) { cache.tail = node } cache.size++ - cache.clean() + cache.clean(false) +} + +func (cache *RoomCache) ForceClean() { + cache.Lock() + cache.clean(true) + cache.Unlock() } -func (cache *RoomCache) clean() { +func (cache *RoomCache) clean(force bool) { origSize := cache.size maxTS := time.Now().Unix() - cache.maxAge for cache.size > cache.maxSize { - if cache.tail.touch > maxTS { + if cache.tail.touch > maxTS && !force { break } - cache.tail.Unload() - cache.llPop(cache.tail) + ok := cache.tail.Unload() + node := cache.tail + cache.llPop(node) + if !ok { + debug.Print("Unload returned false, pushing node back") + cache.llPush(node) + } } if cleaned := origSize - cache.size; cleaned > 0 { debug.Print("Cleaned", cleaned, "rooms") @@ -295,7 +305,11 @@ func (cache *RoomCache) Unload(node *Room) { cache.Lock() defer cache.Unlock() cache.llPop(node) - node.Unload() + ok := node.Unload() + if !ok { + debug.Print("Unload returned false, pushing node back") + cache.llPush(node) + } } func (cache *RoomCache) newRoom(roomID string) *Room { diff --git a/ui/command-processor.go b/ui/command-processor.go index 96b1ada..65b704f 100644 --- a/ui/command-processor.go +++ b/ui/command-processor.go @@ -108,6 +108,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { "rainbow": cmdRainbow, "invite": cmdInvite, "hprof": cmdHeapProfile, + "cprof": cmdCPUProfile, }, } } diff --git a/ui/commands.go b/ui/commands.go index cd770b6..5d92969 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -21,8 +21,11 @@ import ( "fmt" "os" "runtime" + dbg "runtime/debug" "runtime/pprof" + "strconv" "strings" + "time" "unicode" "github.com/lucasb-eyer/go-colorful" @@ -71,15 +74,56 @@ var rainbow = GradientTable{ } func cmdHeapProfile(cmd *Command) { + dbg.FreeOSMemory() runtime.GC() - memProfile, err := os.Create("gomuks.prof") + memProfile, err := os.Create("gomuks.heap.prof") if err != nil { - debug.Print(err) + debug.Print("Failed to open gomuks.heap.prof:", err) + return } - defer memProfile.Close() + defer func() { + err := memProfile.Close() + if err != nil { + debug.Print("Failed to close gomuks.heap.prof:", err) + } + }() if err := pprof.WriteHeapProfile(memProfile); err != nil { - debug.Print(err) + debug.Print("Heap profile error:", err) + } +} + +func cmdCPUProfile(cmd *Command) { + if len(cmd.Args) == 0 { + cmd.Reply("Usage: /cprof ") + return + } + dur, err := strconv.Atoi(cmd.Args[0]) + if err != nil || dur < 0 { + cmd.Reply("Usage: /cprof ") + return } + cpuProfile, err := os.Create("gomuks.cpu.prof") + if err != nil { + debug.Print("Failed to open gomuks.cpu.prof:", err) + return + } + err = pprof.StartCPUProfile(cpuProfile) + if err != nil { + _ = cpuProfile.Close() + debug.Print("CPU profile error:", err) + return + } + cmd.Reply("Started CPU profiling for %d seconds", dur) + go func() { + time.Sleep(time.Duration(dur) * time.Second) + pprof.StopCPUProfile() + cmd.Reply("CPU profiling finished.") + + err := cpuProfile.Close() + if err != nil { + debug.Print("Failed to close gomuks.cpu.prof:", err) + } + }() } // TODO this command definitely belongs in a plugin once we have a plugin system. diff --git a/ui/message-view.go b/ui/message-view.go index eb7098c..81a6d7c 100644 --- a/ui/message-view.go +++ b/ui/message-view.go @@ -89,6 +89,23 @@ func NewMessageView(parent *RoomView) *MessageView { } } +func (view *MessageView) Unload() { + debug.Print("Unloading message view", view.parent.Room.ID) + view.messagesLock.Lock() + view.msgBufferLock.Lock() + view.messageIDLock.Lock() + view.messageIDs = make(map[string]*messages.UIMessage) + view.msgBuffer = make([]*messages.UIMessage, 0) + view.messages = make([]*messages.UIMessage, 0) + view.initialHistoryLoaded = false + view.ScrollOffset = 0 + view._widestSender = 5 + view.prevMsgCount = -1 + view.messagesLock.Unlock() + view.msgBufferLock.Unlock() + view.messageIDLock.Unlock() +} + func (view *MessageView) updateWidestSender(sender string) { if len(sender) > int(view._widestSender) { if len(sender) > view.MaxSenderWidth { diff --git a/ui/room-list.go b/ui/room-list.go index f0a9703..53337b6 100644 --- a/ui/room-list.go +++ b/ui/room-list.go @@ -423,8 +423,10 @@ func (list *RoomList) OnMouseEvent(event mauview.MouseEvent) bool { switch event.Buttons() { case tcell.WheelUp: list.AddScrollOffset(-WheelScrollOffsetDiff) + return true case tcell.WheelDown: list.AddScrollOffset(WheelScrollOffsetDiff) + return true case tcell.Button1: x, y := event.Position() return list.clickRoom(y, x, event.Modifiers() == tcell.ModCtrl) @@ -486,7 +488,8 @@ func (list *RoomList) clickRoom(line, column int, mod bool) bool { if trl.maxShown < 10 { trl.maxShown = 10 } - break + list.RUnlock() + return true } } // Tag footer diff --git a/ui/room-view.go b/ui/room-view.go index b37ebff..48943a7 100644 --- a/ui/room-view.go +++ b/ui/room-view.go @@ -93,6 +93,17 @@ func NewRoomView(parent *MainView, room *rooms.Room) *RoomView { config: parent.config, } view.content = NewMessageView(view) + view.Room.SetOnUnload(func() bool { + if view.parent.currentRoom == view { + return false + } + view.content.Unload() + return true + }) + view.Room.SetOnLoad(func() bool { + view.loadTyping() + return true + }) view.input. SetBackgroundColor(tcell.ColorDefault). @@ -270,14 +281,20 @@ func (view *RoomView) SetCompletions(completions []string) { view.completions.time = time.Now() } -func (view *RoomView) SetTyping(users []string) { - for index, user := range users { +func (view *RoomView) loadTyping() { + for index, user := range view.typing { member := view.Room.GetMember(user) if member != nil { - users[index] = member.Displayname + view.typing[index] = member.Displayname } } +} + +func (view *RoomView) SetTyping(users []string) { view.typing = users + if view.Room.Loaded() { + view.loadTyping() + } } type completion struct { -- cgit v1.2.3-70-g09d2 From 6bb932212cbadac6eed59ac153ebe041523f7570 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 15 Jun 2019 19:10:18 +0300 Subject: Add call trace command --- matrix/rooms/room.go | 2 -- ui/command-processor.go | 1 + ui/commands.go | 57 +++++++++++++++++++++++++------------------------ 3 files changed, 30 insertions(+), 30 deletions(-) (limited to 'ui/commands.go') diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go index ec8b0d9..a0918b1 100644 --- a/matrix/rooms/room.go +++ b/matrix/rooms/room.go @@ -34,8 +34,6 @@ import ( func init() { gob.Register(map[string]interface{}{}) gob.Register([]interface{}{}) - gob.Register(&Room{}) - gob.Register(0) } type RoomNameSource int diff --git a/ui/command-processor.go b/ui/command-processor.go index 65b704f..26644c5 100644 --- a/ui/command-processor.go +++ b/ui/command-processor.go @@ -109,6 +109,7 @@ func NewCommandProcessor(parent *MainView) *CommandProcessor { "invite": cmdInvite, "hprof": cmdHeapProfile, "cprof": cmdCPUProfile, + "trace": cmdTrace, }, } } diff --git a/ui/commands.go b/ui/commands.go index 5d92969..ab02735 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -19,10 +19,12 @@ package ui import ( "encoding/json" "fmt" + "io" "os" "runtime" dbg "runtime/debug" "runtime/pprof" + "runtime/trace" "strconv" "strings" "time" @@ -92,38 +94,37 @@ func cmdHeapProfile(cmd *Command) { } } -func cmdCPUProfile(cmd *Command) { +func runTimedProfile(cmd *Command, start func(writer io.Writer) error, stop func(), task, file string) { if len(cmd.Args) == 0 { - cmd.Reply("Usage: /cprof ") - return - } - dur, err := strconv.Atoi(cmd.Args[0]) - if err != nil || dur < 0 { - cmd.Reply("Usage: /cprof ") - return - } - cpuProfile, err := os.Create("gomuks.cpu.prof") - if err != nil { - debug.Print("Failed to open gomuks.cpu.prof:", err) - return - } - err = pprof.StartCPUProfile(cpuProfile) - if err != nil { + cmd.Reply("Usage: /%s ", cmd.Command) + } else if dur, err := strconv.Atoi(cmd.Args[0]); err != nil || dur < 0 { + cmd.Reply("Usage: /%s ", cmd.Command) + } else if cpuProfile, err := os.Create(file); err != nil { + debug.Printf("Failed to open %s: %v", file, err) + } else if err = start(cpuProfile); err != nil { _ = cpuProfile.Close() - debug.Print("CPU profile error:", err) - return + debug.Print(task, "error:", err) + } else { + cmd.Reply("Started %s for %d seconds", task, dur) + go func() { + time.Sleep(time.Duration(dur) * time.Second) + stop() + cmd.Reply("%s finished.", task) + + err := cpuProfile.Close() + if err != nil { + debug.Print("Failed to close gomuks.cpu.prof:", err) + } + }() } - cmd.Reply("Started CPU profiling for %d seconds", dur) - go func() { - time.Sleep(time.Duration(dur) * time.Second) - pprof.StopCPUProfile() - cmd.Reply("CPU profiling finished.") +} - err := cpuProfile.Close() - if err != nil { - debug.Print("Failed to close gomuks.cpu.prof:", err) - } - }() +func cmdCPUProfile(cmd *Command) { + runTimedProfile(cmd, pprof.StartCPUProfile, pprof.StopCPUProfile, "CPU profiling", "gomuks.cpu.prof") +} + +func cmdTrace(cmd *Command) { + runTimedProfile(cmd, trace.Start, trace.Stop, "Call tracing", "gomuks.trace") } // TODO this command definitely belongs in a plugin once we have a plugin system. -- cgit v1.2.3-70-g09d2 From 2b7d5d54011ffcc93511bf05f44163a4b7a1270c Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Jun 2019 14:29:03 +0300 Subject: Fix reply rendering infinite loop bug --- go.mod | 2 +- matrix/matrix.go | 7 +++++++ matrix/rooms/room.go | 6 +++--- ui/commands.go | 2 +- ui/message-view.go | 2 +- ui/messages/base.go | 4 +++- ui/messages/parser.go | 4 +--- 7 files changed, 17 insertions(+), 10 deletions(-) (limited to 'ui/commands.go') diff --git a/go.mod b/go.mod index c4cd3e1..94aa798 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( gopkg.in/russross/blackfriday.v2 v2.0.1 gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 gopkg.in/yaml.v2 v2.2.2 - maunium.net/go/mautrix v0.1.0-alpha.3.0.20190607192515-d505052a02ac + maunium.net/go/mautrix v0.1.0-alpha.3.0.20190616114735-e5bf3141e88e maunium.net/go/mauview v0.0.0-20190606152754-de9e0a754a5d maunium.net/go/tcell v0.0.0-20190606152714-9a88fc07b3ed ) diff --git a/matrix/matrix.go b/matrix/matrix.go index 1a75f96..cfd5614 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -29,7 +29,9 @@ import ( "path" "path/filepath" "regexp" + "runtime" "time" + dbg "runtime/debug" "maunium.net/go/mautrix" "maunium.net/go/mautrix/format" @@ -232,6 +234,11 @@ func (c *Container) OnLogin() { debug.Print("Adding rooms to UI") c.ui.MainView().SetRooms(c.config.Rooms) c.ui.Render() + // The initial sync can be a bit heavy, so we force run the GC here + // after cleaning up rooms from memory above. + debug.Print("Running GC") + runtime.GC() + dbg.FreeOSMemory() } c.client.Syncer = c.syncer diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go index a0918b1..be91065 100644 --- a/matrix/rooms/room.go +++ b/matrix/rooms/room.go @@ -148,6 +148,9 @@ func (room *Room) Load() { room.lock.Lock() room.load() room.lock.Unlock() + if room.postLoad != nil { + room.postLoad() + } } func (room *Room) load() { @@ -177,9 +180,6 @@ func (room *Room) load() { debug.Print("Failed to decode room state:", err) } room.changed = false - if room.postLoad != nil { - room.postLoad() - } } func (room *Room) Touch() { diff --git a/ui/commands.go b/ui/commands.go index ab02735..0b15d8e 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -76,8 +76,8 @@ var rainbow = GradientTable{ } func cmdHeapProfile(cmd *Command) { - dbg.FreeOSMemory() runtime.GC() + dbg.FreeOSMemory() memProfile, err := os.Create("gomuks.heap.prof") if err != nil { debug.Print("Failed to open gomuks.heap.prof:", err) diff --git a/ui/message-view.go b/ui/message-view.go index 81a6d7c..9aa38a1 100644 --- a/ui/message-view.go +++ b/ui/message-view.go @@ -143,7 +143,7 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction MessageDir view.replaceMessage(oldMsg, message) view.deleteMessageID(message.TxnID) direction = IgnoreMessage - } else if oldMsg = view.getMessageByID(message.Relation.EventID); oldMsg != nil { + } else if oldMsg = view.getMessageByID(message.Relation.GetReplaceID()); oldMsg != nil { direction = IgnoreMessage } diff --git a/ui/messages/base.go b/ui/messages/base.go index 123c5c1..ef495fb 100644 --- a/ui/messages/base.go +++ b/ui/messages/base.go @@ -241,6 +241,7 @@ func (msg *UIMessage) Draw(screen mauview.Screen) { func (msg *UIMessage) Clone() *UIMessage { clone := *msg + clone.ReplyTo = nil clone.Renderer = clone.Renderer.Clone() return &clone } @@ -253,7 +254,8 @@ func (msg *UIMessage) CalculateReplyBuffer(preferences config.UserPreferences, w } func (msg *UIMessage) CalculateBuffer(preferences config.UserPreferences, width int) { - msg.Renderer.CalculateBuffer(preferences, width-1, msg) + msg.Renderer.CalculateBuffer(preferences, width, msg) + msg.CalculateReplyBuffer(preferences, width) } func (msg *UIMessage) DrawReply(screen mauview.Screen) mauview.Screen { diff --git a/ui/messages/parser.go b/ui/messages/parser.go index 123f323..29f078c 100644 --- a/ui/messages/parser.go +++ b/ui/messages/parser.go @@ -49,9 +49,7 @@ func ParseEvent(matrix ifc.MatrixContainer, mainView ifc.MainView, room *rooms.R } if len(evt.Content.GetReplyTo()) > 0 { if replyToMsg := getCachedEvent(mainView, room.ID, evt.Content.GetReplyTo()); replyToMsg != nil { - replyToMsg = replyToMsg.Clone() - replyToMsg.ReplyTo = nil - msg.ReplyTo = replyToMsg + msg.ReplyTo = replyToMsg.Clone() } else if replyToEvt, _ := matrix.GetEvent(room, evt.Content.GetReplyTo()); replyToEvt != nil { if replyToMsg := directParseEvent(matrix, room, replyToEvt); replyToMsg != nil { msg.ReplyTo = replyToMsg -- cgit v1.2.3-70-g09d2