From e4a2fe26415eba5cf7920c08acd0313b1c75d1f4 Mon Sep 17 00:00:00 2001 From: delthas Date: Tue, 18 Oct 2022 17:27:20 +0200 Subject: Clear highlights from MARKREAD when only NotifyNone lines are left Previously, we did not clear buffers highlight statuses on MARKREAD if there was any unread line after it. This meant that if we received a plain message, than a join message, and some other device sent us a read marker for the plain message, we would still highlight the buffer. But we should not: a join message should not highlight the buffer. This is a recurrent use case because some clients do not display join mesasges and therefore do not send read markers for it. This updates the logic to actually store the notify level (in the line) and uses it to reset the highlight status when only NotifyNone messages (or no messages) are left. --- app.go | 43 ++++++++++++++++++++++++------------------- commands.go | 30 +++++++++++++++--------------- ui/buffers.go | 22 ++++++++++++++-------- ui/ui.go | 4 ++-- window.go | 6 +++--- 5 files changed, 58 insertions(+), 47 deletions(-) diff --git a/app.go b/app.go index 073bf6a..532c719 100644 --- a/app.go +++ b/app.go @@ -626,10 +626,11 @@ func (app *App) handleKeyEvent(ev *tcell.EventKey) { input := app.win.InputEnter() err := app.handleInput(buffer, input) if err != nil { - app.win.AddLine(netID, buffer, ui.NotifyUnread, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: time.Now(), Head: "!!", HeadColor: tcell.ColorRed, + Notify: ui.NotifyUnread, Body: ui.PlainSprintf("%q: %s", input, err), }) } @@ -715,9 +716,10 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { // Mutate IRC state ev, err := s.HandleMessage(msg) if err != nil { - app.win.AddLine(netID, "", ui.NotifyUnread, ui.Line{ + app.win.AddLine(netID, "", ui.Line{ Head: "!!", HeadColor: tcell.ColorRed, + Notify: ui.NotifyUnread, Body: ui.PlainSprintf("Received corrupt message %q: %s", msg.String(), err), }) return @@ -742,7 +744,7 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { if s.Nick() != app.cfg.Nick { body = fmt.Sprintf("Connected to the server as %s", s.Nick()) } - app.win.AddLine(netID, "", ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, "", ui.Line{ At: msg.TimeOrNow(), Head: "--", Body: ui.PlainString(body), @@ -770,7 +772,7 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { case irc.UserNickEvent: line := app.formatEvent(ev) for _, c := range s.ChannelsSharedWith(ev.User) { - app.win.AddLine(netID, c, ui.NotifyNone, line) + app.win.AddLine(netID, c, line) } case irc.SelfJoinEvent: i, added := app.win.AddBuffer(netID, "", ev.Channel) @@ -801,26 +803,26 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { } case irc.UserJoinEvent: line := app.formatEvent(ev) - app.win.AddLine(netID, ev.Channel, ui.NotifyNone, line) + app.win.AddLine(netID, ev.Channel, line) case irc.SelfPartEvent: app.win.RemoveBuffer(netID, ev.Channel) delete(app.messageBounds, boundKey{netID, ev.Channel}) case irc.UserPartEvent: line := app.formatEvent(ev) - app.win.AddLine(netID, ev.Channel, ui.NotifyNone, line) + app.win.AddLine(netID, ev.Channel, line) case irc.UserQuitEvent: line := app.formatEvent(ev) for _, c := range ev.Channels { - app.win.AddLine(netID, c, ui.NotifyNone, line) + app.win.AddLine(netID, c, line) } case irc.TopicChangeEvent: line := app.formatEvent(ev) - app.win.AddLine(netID, ev.Channel, ui.NotifyUnread, line) + app.win.AddLine(netID, ev.Channel, line) topic := ui.IRCString(ev.Topic).String() app.win.SetTopic(netID, ev.Channel, topic) case irc.ModeChangeEvent: line := app.formatEvent(ev) - app.win.AddLine(netID, ev.Channel, ui.NotifyNone, line) + app.win.AddLine(netID, ev.Channel, line) case irc.InviteEvent: var buffer string var notify ui.NotifyType @@ -838,16 +840,17 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { notify = ui.NotifyUnread body = fmt.Sprintf("%s invited %s to join this channel", ev.Inviter, ev.Invitee) } - app.win.AddLine(netID, buffer, notify, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: msg.TimeOrNow(), Head: "--", HeadColor: tcell.ColorGray, + Notify: notify, Body: ui.Styled(body, tcell.StyleDefault.Foreground(tcell.ColorGray)), Highlight: notify == ui.NotifyHighlight, Readable: true, }) case irc.MessageEvent: - buffer, line, notification := app.formatMessage(s, ev) + buffer, line := app.formatMessage(s, ev) if line.IsZero() { break } @@ -861,8 +864,8 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { Before(msg.TimeOrNow()) } } - app.win.AddLine(netID, buffer, notification, line) - if notification == ui.NotifyHighlight { + app.win.AddLine(netID, buffer, line) + if line.Notify == ui.NotifyHighlight { app.notifyHighlight(buffer, ev.User, line.Body.String()) } if !s.IsChannel(msg.Params[0]) && !s.IsMe(ev.User) { @@ -910,7 +913,7 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { var line ui.Line switch ev := m.(type) { case irc.MessageEvent: - _, line, _ = app.formatMessage(s, ev) + _, line = app.formatMessage(s, ev) default: line = app.formatEvent(ev) } @@ -944,7 +947,7 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { app.win.OpenOverlay() lines := make([]ui.Line, 0, len(ev.Messages)) for _, m := range ev.Messages { - _, line, _ := app.formatMessage(s, m) + _, line := app.formatMessage(s, m) if line.IsZero() { continue } @@ -1229,6 +1232,7 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { At: ev.Time, Head: "--", HeadColor: tcell.ColorGray, + Notify: ui.NotifyUnread, Body: ui.Styled(body, tcell.StyleDefault.Foreground(tcell.ColorGray)), Readable: true, } @@ -1254,9 +1258,8 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { // // It computes three things: // - which buffer the message must be added to, -// - the UI line, -// - what kind of notification senpai should send. -func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer string, line ui.Line, notification ui.NotifyType) { +// - the UI line. +func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer string, line ui.Line) { isFromSelf := s.IsMe(ev.User) isToSelf := s.IsMe(ev.Target) isHighlight := ev.TargetIsChannel && app.isHighlight(s, ev.Content) @@ -1292,6 +1295,7 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin buffer = ev.Target } + var notification ui.NotifyType hlLine := ev.TargetIsChannel && isHighlight && !isFromSelf if isFromSelf { notification = ui.NotifyNone @@ -1332,6 +1336,7 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin At: ev.Time, Head: head, HeadColor: headColor, + Notify: notification, Body: body.StyledString(), Highlight: hlLine, Readable: true, @@ -1477,7 +1482,7 @@ func (app *App) printTopic(netID, buffer string) (ok bool) { } else { body = fmt.Sprintf("Topic (by %s, %s): %s", who, at.Local().Format("Mon Jan 2 15:04:05"), topic) } - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: time.Now(), Head: "--", HeadColor: tcell.ColorGray, diff --git a/commands.go b/commands.go index 9113485..132f914 100644 --- a/commands.go +++ b/commands.go @@ -198,7 +198,7 @@ func noCommand(app *App, content string) error { s.PrivMsg(buffer, content) if !s.HasCapability("echo-message") { - buffer, line, _ := app.formatMessage(s, irc.MessageEvent{ + buffer, line := app.formatMessage(s, irc.MessageEvent{ User: s.Nick(), Target: buffer, TargetIsChannel: s.IsChannel(buffer), @@ -206,7 +206,7 @@ func noCommand(app *App, content string) error { Content: content, Time: time.Now(), }) - app.win.AddLine(netID, buffer, ui.NotifyNone, line) + app.win.AddLine(netID, buffer, line) } return nil @@ -239,15 +239,15 @@ func commandDoHelp(app *App, args []string) (err error) { sb.SetStyle(tcell.StyleDefault) sb.WriteByte(' ') sb.WriteString(cmd.Usage) - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: t, Body: sb.StyledString(), }) - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: t, Body: ui.PlainSprintf(" %s", cmd.Desc), }) - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: t, }) } @@ -261,7 +261,7 @@ func commandDoHelp(app *App, args []string) (err error) { } if len(args) == 0 { - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: t, Head: "--", Body: ui.PlainString("Available commands:"), @@ -274,7 +274,7 @@ func commandDoHelp(app *App, args []string) (err error) { addLineCommands(cmdNames) } else { search := strings.ToUpper(args[0]) - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: t, Head: "--", Body: ui.PlainSprintf("Commands that match \"%s\":", search), @@ -288,7 +288,7 @@ func commandDoHelp(app *App, args []string) (err error) { cmdNames = append(cmdNames, cmdName) } if len(cmdNames) == 0 { - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: t, Body: ui.PlainSprintf(" no command matches %q", args[0]), }) @@ -326,7 +326,7 @@ func commandDoMe(app *App, args []string) (err error) { content := fmt.Sprintf("\x01ACTION %s\x01", args[0]) s.PrivMsg(buffer, content) if !s.HasCapability("echo-message") { - buffer, line, _ := app.formatMessage(s, irc.MessageEvent{ + buffer, line := app.formatMessage(s, irc.MessageEvent{ User: s.Nick(), Target: buffer, TargetIsChannel: s.IsChannel(buffer), @@ -334,7 +334,7 @@ func commandDoMe(app *App, args []string) (err error) { Content: content, Time: time.Now(), }) - app.win.AddLine(netID, buffer, ui.NotifyNone, line) + app.win.AddLine(netID, buffer, line) } return nil } @@ -368,7 +368,7 @@ func commandDoNames(app *App, args []string) (err error) { } body := sb.StyledString() // TODO remove last space - app.win.AddLine(netID, buffer, ui.NotifyNone, ui.Line{ + app.win.AddLine(netID, buffer, ui.Line{ At: time.Now(), Head: "--", HeadColor: tcell.ColorGray, @@ -491,7 +491,7 @@ func commandDoR(app *App, args []string) (err error) { } s.PrivMsg(app.lastQuery, args[0]) if !s.HasCapability("echo-message") { - buffer, line, _ := app.formatMessage(s, irc.MessageEvent{ + buffer, line := app.formatMessage(s, irc.MessageEvent{ User: s.Nick(), Target: app.lastQuery, TargetIsChannel: s.IsChannel(app.lastQuery), @@ -499,7 +499,7 @@ func commandDoR(app *App, args []string) (err error) { Content: args[0], Time: time.Now(), }) - app.win.AddLine(app.lastQueryNet, buffer, ui.NotifyNone, line) + app.win.AddLine(app.lastQueryNet, buffer, line) } return nil } @@ -696,7 +696,7 @@ func commandSendMessage(app *App, target string, content string) error { } s.PrivMsg(target, content) if !s.HasCapability("echo-message") { - buffer, line, _ := app.formatMessage(s, irc.MessageEvent{ + buffer, line := app.formatMessage(s, irc.MessageEvent{ User: s.Nick(), Target: target, TargetIsChannel: s.IsChannel(target), @@ -711,7 +711,7 @@ func commandSendMessage(app *App, target string, content string) error { app.win.AddBuffer(netID, "", buffer) } - app.win.AddLine(netID, buffer, ui.NotifyNone, line) + app.win.AddLine(netID, buffer, line) } return nil } diff --git a/ui/buffers.go b/ui/buffers.go index 0e398de..b11e734 100644 --- a/ui/buffers.go +++ b/ui/buffers.go @@ -33,6 +33,7 @@ type Line struct { Head string Body StyledString HeadColor tcell.Color + Notify NotifyType Highlight bool Readable bool Mergeable bool @@ -366,7 +367,7 @@ func (bs *BufferList) mergeLine(former *Line, addition Line) (keepLine bool) { return true } -func (bs *BufferList) AddLine(netID, title string, notify NotifyType, line Line) { +func (bs *BufferList) AddLine(netID, title string, line Line) { _, b := bs.at(netID, title) if b == nil { return @@ -394,10 +395,10 @@ func (bs *BufferList) AddLine(netID, title string, notify NotifyType, line Line) } } - if notify != NotifyNone && b != current { + if line.Notify != NotifyNone && b != current { b.unread = true } - if notify == NotifyHighlight && b != current { + if line.Notify == NotifyHighlight && b != current { b.highlights++ } } @@ -443,16 +444,21 @@ func (bs *BufferList) SetRead(netID, title string, timestamp time.Time) { if b == nil { return } + clearRead := true for i := len(b.lines) - 1; i >= 0; i-- { line := &b.lines[i] - if line.Readable { - if !line.At.After(timestamp) { - b.highlights = 0 - b.unread = false - } + if !line.At.After(timestamp) { + break + } + if line.Readable && line.Notify != NotifyNone { + clearRead = false break } } + if clearRead { + b.highlights = 0 + b.unread = false + } if b.read.Before(timestamp) { b.read = timestamp } diff --git a/ui/ui.go b/ui/ui.go index 1a0da91..859f32a 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -270,8 +270,8 @@ func (ui *UI) RemoveNetworkBuffers(netID string) { ui.memberOffset = 0 } -func (ui *UI) AddLine(netID, buffer string, notify NotifyType, line Line) { - ui.bs.AddLine(netID, buffer, notify, line) +func (ui *UI) AddLine(netID, buffer string, line Line) { + ui.bs.AddLine(netID, buffer, line) } func (ui *UI) AddLines(netID, buffer string, before, after []Line) { diff --git a/window.go b/window.go index 5cdfd8b..76e703d 100644 --- a/window.go +++ b/window.go @@ -11,7 +11,7 @@ const welcomeMessage = "senpai dev build. Enter /help for a list of commands." func (app *App) initWindow() { app.win.AddBuffer("", "(home)", "") - app.win.AddLine("", "", ui.NotifyNone, ui.Line{ + app.win.AddLine("", "", ui.Line{ Head: "--", Body: ui.PlainString(welcomeMessage), At: time.Now(), @@ -39,9 +39,9 @@ func (app *App) queueStatusLine(netID string, line ui.Line) { func (app *App) addStatusLine(netID string, line ui.Line) { currentNetID, buffer := app.win.CurrentBuffer() if currentNetID == netID && buffer != "" { - app.win.AddLine(netID, buffer, ui.NotifyNone, line) + app.win.AddLine(netID, buffer, line) } - app.win.AddLine(netID, "", ui.NotifyNone, line) + app.win.AddLine(netID, "", line) } func (app *App) setStatus() { -- cgit v1.2.3