diff options
-rw-r--r-- | app.go | 88 | ||||
-rw-r--r-- | ui/buffers.go | 39 | ||||
-rw-r--r-- | ui/ui.go | 3 |
3 files changed, 112 insertions, 18 deletions
@@ -124,6 +124,9 @@ func NewApp(cfg Config) (app *App, err error) { return app.completions(cursorIdx, text) }, Mouse: mouse, + MergeLine: func(former *ui.Line, addition ui.Line) { + app.mergeLine(former, addition) + }, }) if err != nil { return @@ -955,13 +958,13 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { body.AddStyle(0, textStyle) body.AddStyle(len(ev.FormerNick), arrowStyle) body.AddStyle(body.Len()-len(ev.User), textStyle) - return ui.Line{ At: ev.Time, Head: "--", HeadColor: tcell.ColorGray, Body: body.StyledString(), Mergeable: true, + Data: []interface{}{ev}, } case irc.UserJoinEvent: var body ui.StyledStringBuilder @@ -976,6 +979,7 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { HeadColor: tcell.ColorGray, Body: body.StyledString(), Mergeable: true, + Data: []interface{}{ev}, } case irc.UserPartEvent: var body ui.StyledStringBuilder @@ -990,6 +994,7 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { HeadColor: tcell.ColorGray, Body: body.StyledString(), Mergeable: true, + Data: []interface{}{ev}, } case irc.UserQuitEvent: var body ui.StyledStringBuilder @@ -1004,6 +1009,7 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { HeadColor: tcell.ColorGray, Body: body.StyledString(), Mergeable: true, + Data: []interface{}{ev}, } case irc.TopicChangeEvent: topic := ui.IRCString(ev.Topic).String() @@ -1022,6 +1028,7 @@ func (app *App) formatEvent(ev irc.Event) ui.Line { HeadColor: tcell.ColorGray, Body: ui.Styled(body, tcell.StyleDefault.Foreground(tcell.ColorGray)), Mergeable: true, + Data: []interface{}{ev}, } default: return ui.Line{} @@ -1105,6 +1112,85 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin return } +func (app *App) mergeLine(former *ui.Line, addition ui.Line) { + partQuitUser := func(ev interface{}) string { + if ev, ok := ev.(irc.UserQuitEvent); ok { + return ev.User + } + if ev, ok := ev.(irc.UserPartEvent); ok { + return ev.User + } + panic("unreachable") + } + + changed := false +Outer: + for _, addedEvent := range addition.Data { + switch addedEvent := addedEvent.(type) { + case irc.UserNickEvent: + for i := len(former.Data) - 1; i >= 0; i-- { + switch ev := former.Data[i].(type) { + case irc.UserNickEvent: + if ev.User == addedEvent.FormerNick && ev.FormerNick == addedEvent.User { + former.Data = append(former.Data[:i], former.Data[i+1:]...) + changed = true + continue Outer + } + } + } + former.Data = append(former.Data, addedEvent) + case irc.UserJoinEvent: + for i := len(former.Data) - 1; i >= 0; i-- { + switch ev := former.Data[i].(type) { + case irc.UserPartEvent, irc.UserQuitEvent: + if partQuitUser(ev) == addedEvent.User { + former.Data = append(former.Data[:i], former.Data[i+1:]...) + changed = true + continue Outer + } + } + } + former.Data = append(former.Data, addedEvent) + case irc.UserQuitEvent, irc.UserPartEvent: + for i := len(former.Data) - 1; i >= 0; i-- { + switch ev := former.Data[i].(type) { + case irc.UserJoinEvent: + if ev.User == partQuitUser(addedEvent) { + former.Data = append(former.Data[:i], former.Data[i+1:]...) + changed = true + continue Outer + } + } + } + former.Data = append(former.Data, addedEvent) + //case irc.ModeChangeEvent: //TODO + default: + former.Data = append(former.Data, addedEvent) + } + } + if changed { + if len(former.Data) == 0 { + former.Body = ui.PlainString("") + return + } + var body ui.StyledStringBuilder + body.Grow(len(former.Body.String())) + body.WriteStyledString(app.formatEvent(former.Data[0]).Body) + for _, ev := range former.Data[1:] { + body.WriteString(" ") + body.WriteStyledString(app.formatEvent(ev).Body) + } + former.Body = body.StyledString() + } else { + var newBody ui.StyledStringBuilder + newBody.Grow(len(former.Body.String()) + 2 + len(addition.Body.String())) + newBody.WriteStyledString(former.Body) + newBody.WriteString(" ") + newBody.WriteStyledString(addition.Body) + former.Body = newBody.StyledString() + } +} + // updatePrompt changes the prompt text according to the application context. func (app *App) updatePrompt() { netID, buffer := app.win.CurrentBuffer() diff --git a/ui/buffers.go b/ui/buffers.go index d277491..aa5e9fe 100644 --- a/ui/buffers.go +++ b/ui/buffers.go @@ -33,6 +33,7 @@ type Line struct { HeadColor tcell.Color Highlight bool Mergeable bool + Data []interface{} splitPoints []point width int @@ -43,17 +44,6 @@ func (l *Line) IsZero() bool { return l.Body.string == "" } -func (l *Line) Merge(line Line) { - newBody := new(StyledStringBuilder) - newBody.Grow(len(l.Body.string) + 2 + len(line.Body.string)) - newBody.WriteStyledString(l.Body) - newBody.WriteString(" ") - newBody.WriteStyledString(line.Body) - l.Body = newBody.StyledString() - l.computeSplitPoints() - l.width = 0 -} - func (l *Line) computeSplitPoints() { if l.splitPoints == nil { l.splitPoints = []point{} @@ -209,14 +199,17 @@ type BufferList struct { tlHeight int showBufferNumbers bool + + doMergeLine func(former *Line, addition Line) } // NewBufferList returns a new BufferList. // Call Resize() once before using it. -func NewBufferList() BufferList { +func NewBufferList(mergeLine func(*Line, Line)) BufferList { return BufferList{ - list: []buffer{}, - clicked: -1, + list: []buffer{}, + clicked: -1, + doMergeLine: mergeLine, } } @@ -306,6 +299,16 @@ func (bs *BufferList) Remove(netID, title string) bool { return true } +func (bs *BufferList) mergeLine(former *Line, addition Line) (keepLine bool) { + bs.doMergeLine(former, addition) + if former.Body.string == "" { + return false + } + former.width = 0 + former.computeSplitPoints() + return true +} + func (bs *BufferList) AddLine(netID, title string, notify NotifyType, line Line) { idx := bs.idx(netID, title) if idx < 0 { @@ -322,7 +325,9 @@ func (bs *BufferList) AddLine(netID, title string, notify NotifyType, line Line) if line.Mergeable && n != 0 && b.lines[n-1].Mergeable { l := &b.lines[n-1] - l.Merge(line) + if !bs.mergeLine(l, line) { + b.lines = b.lines[:n-1] + } // TODO change b.scrollAmt if it's not 0 and bs.current is idx. } else { line.computeSplitPoints() @@ -353,7 +358,9 @@ func (bs *BufferList) AddLines(netID, title string, before, after []Line) { for _, line := range *buf { if line.Mergeable && len(lines) > 0 && lines[len(lines)-1].Mergeable { l := &lines[len(lines)-1] - l.Merge(line) + if !bs.mergeLine(l, line) { + lines = lines[:len(lines)-1] + } } else { if buf != &b.lines { line.Body = line.Body.ParseURLs() @@ -15,6 +15,7 @@ type Config struct { MemberColWidth int AutoComplete func(cursorIdx int, text []rune) []Completion Mouse bool + MergeLine func(former *Line, addition Line) } type UI struct { @@ -70,7 +71,7 @@ func New(config Config) (ui *UI, err error) { close(ui.Events) }() - ui.bs = NewBufferList() + ui.bs = NewBufferList(ui.config.MergeLine) ui.e = NewEditor(ui.config.AutoComplete) ui.Resize() |