From cd06a27e20717cdfbcc6840328f67405acc7c9e7 Mon Sep 17 00:00:00 2001 From: citrons Date: Mon, 9 Jun 2025 14:45:51 -0500 Subject: jump to message --- client/channel_window.go | 142 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 23 deletions(-) (limited to 'client/channel_window.go') diff --git a/client/channel_window.go b/client/channel_window.go index 3239b47..3dc208d 100644 --- a/client/channel_window.go +++ b/client/channel_window.go @@ -15,6 +15,7 @@ import ( type channelLocation struct { id string + jumpTo string } type channelWindow struct { @@ -25,6 +26,8 @@ type channelWindow struct { replyingTo string loadingHistory bool endOfHistory bool + startOfHistory bool + jumpedTo buffer.Message } type channelMsg struct { @@ -41,7 +44,11 @@ func (cl channelLocation) CreateWindow() window.Window { } cw.messageCache = object.NewCache(cw) globalApp.cache.Watch(cl.id) - cw.loadMoreHistory() + if cl.jumpTo == "" { + cw.startOfHistory = true + } + cw.Buf.SetSnap(cw.startOfHistory) + cw.loadMoreHistory(false) return cw } @@ -72,14 +79,16 @@ func (cw *channelWindow) isGone(uid string) bool { } func (cw *channelWindow) put(msg proto.Object) { + if !cw.startOfHistory { + return + } if msg.Kind == "membership" { cw.endOfHistory = false + if cw.location.jumpTo != "" { + cw.startOfHistory = false + } } - cw.messageCache.Update(msg.Id, msg) - if !cw.messageCache.IsWatched(msg.Id) { - cw.messageCache.Watch(msg.Id) - } - cw.Buf.Add(channelMsg {msg, cw}) + cw.addMessage(msg, true) } func (cw *channelWindow) Location() window.Location { @@ -95,8 +104,12 @@ func (cw *channelWindow) Kill() { func (cw *channelWindow) Buffer() *buffer.Buffer { if cw.Buf.AtTop() { - cw.loadMoreHistory() + cw.loadMoreHistory(false) + } + if cw.Buf.AtBottom() { + cw.loadMoreHistory(true) } + cw.Buf.SetSnap(cw.startOfHistory) return &cw.Buf } @@ -124,6 +137,11 @@ func (cw *channelWindow) Send(text string) { msg := proto.Object {"m", "", fields} globalApp.Request(proto.NewCmd("p", cw.location.id, msg), cb) cw.In.SetText("") + if cw.location.jumpTo == "" { + cw.Buf.ScrollBottom() + } else { + globalApp.goTo(channelLocation {id: cw.location.id}) + } } func (cw *channelWindow) replyTo(id string) { @@ -151,37 +169,87 @@ func (cw *channelWindow) renameChannel(newName string) { }) } -func (cw *channelWindow) loadMoreHistory() { - if cw.loadingHistory || cw.endOfHistory { +func (cw *channelWindow) addMessage(m proto.Object, after bool) { + cw.messageCache.Update(m.Id, m) + if !cw.messageCache.IsWatched(m.Id) { + cw.messageCache.Watch(m.Id) + } + cmsg := channelMsg {m, cw} + if after { + cw.Buf.Add(cmsg) + } else { + cw.Buf.AddTop(cmsg) + } + if m.Id == cw.location.jumpTo { + cw.jumpedTo = cmsg + cw.Buf.ScrollTo(cmsg.Id()) + } +} + +func (cw *channelWindow) loadMoreHistory(after bool) { + if cw.loadingHistory { + return + } + if !after && cw.endOfHistory { + return + } + if after && cw.startOfHistory { return } cw.loadingHistory = true rq := proto.Object {Fields: make(map[string]string)} - top := cw.Buf.Top() - if top != nil { - rq.Kind = "before" - rq.Fields[""] = top.Msg().(channelMsg).Object.Id + var last *buffer.List + if !after { + last = cw.Buf.Top() } else { + last = cw.Buf.Bottom() + } + var lastId string + if last != nil { + lastId = last.Msg().(channelMsg).Object.Id + } + + switch { + case last == nil && cw.location.jumpTo != "": + rq.Kind = "around" + rq.Fields[""] = cw.location.jumpTo + case last == nil: rq.Kind = "latest" + case !after: + rq.Kind = "before" + rq.Fields[""] = lastId + case after: + rq.Kind = "after" + rq.Fields[""] = lastId } + cb := func(response proto.Command) { cw.loadingHistory = false switch response.Kind { case "history": if len(response.Args) == 0 { - cw.endOfHistory = true + if !after { + cw.endOfHistory = true + } else { + cw.startOfHistory = true + } } - for i := len(response.Args) - 1; i >= 0; i-- { - m := response.Args[i] - cw.messageCache.Update(m.Id, m) - if !cw.messageCache.IsWatched(m.Id) { - cw.messageCache.Watch(m.Id) + if !after { + for i := len(response.Args) - 1; i >= 0; i-- { + cw.addMessage(response.Args[i], after) + } + } else { + for i := 0; i < len(response.Args); i++ { + cw.addMessage(response.Args[i], after) } - cw.Buf.AddTop(channelMsg {m, cw}) } case "fail": - cw.endOfHistory = true + if !after { + cw.endOfHistory = true + } else { + cw.startOfHistory = true + } } } globalApp.Request(proto.NewCmd("history", cw.location.id, rq), cb) @@ -277,6 +345,12 @@ func (cw *channelWindow) userList(callback func(userListMsg)) { } func (cw *channelWindow) ShowStatusLine() { + if cw.location.jumpTo != "" { + tui.Text("viewing history", &tui.Style { + Fg: tui.Black, Bg: tui.White, Italic: true, + }) + tui.Text(": ", nil) + } ch := cw.getChannel() if ch == nil { return @@ -295,7 +369,7 @@ func (cw *channelWindow) ShowComposingReply() { Style: &tui.Style {Fg: 248, Bg: tui.Black}, }) tui.Text("> ", nil) - tui.Text(msg.Fields[""], nil) + tui.Text(strings.TrimSpace(msg.Fields[""]), nil) tui.Pop() if mouse.Pressed && mouse.Button == 0 { cw.replyingTo = "" @@ -304,6 +378,12 @@ func (cw *channelWindow) ShowComposingReply() { } } +func (cw *channelWindow) OnNavigate() { + if cw.jumpedTo != nil { + cw.Buf.ScrollTo(cw.jumpedTo.Id()) + } +} + func (m channelMsg) Id() string { return "buffer." + m.Object.Id } @@ -365,10 +445,17 @@ func (m channelMsg) showName(bg int32, uid string, abbreviate bool) { } func (m channelMsg) showReply(bg int32, replyTo *proto.Object) { - tui.Push(m.Id() + ".reply message", tui.Box { + mouse := tui.Push(m.Id() + ".reply message", tui.Box { Width: tui.Children, Height: 1, Dir: tui.Right, }) + if replyTo != nil && mouse.Button == 0 && mouse.Pressed { + globalApp.goTo(channelLocation { + id: m.window.location.id, jumpTo: replyTo.Id, + }) + globalApp.redraw = true + } + tui.Push("", tui.Box { Width: tui.TextSize, Height: 1, NoWrap: true, }) @@ -402,6 +489,13 @@ func (m channelMsg) showReply(bg int32, replyTo *proto.Object) { func (m channelMsg) Show(odd bool) { var bg int32 = colorDefault[odd] + if m.Object.Id == m.window.location.jumpTo { + bg = 17 + } + tui.Push("", tui.Box { + Width: tui.Fill, Height: tui.Children, + Style: &tui.Style {Bg: bg, Fg: tui.White}, + }) var ( isReply bool @@ -472,4 +566,6 @@ func (m channelMsg) Show(odd bool) { tui.Text("]", nil) tui.Pop() } + + tui.Pop() } -- cgit v1.2.3