diff options
-rw-r--r-- | app.go | 85 | ||||
-rw-r--r-- | config.go | 24 | ||||
-rw-r--r-- | ui/buffers.go | 18 | ||||
-rw-r--r-- | ui/ui.go | 33 | ||||
-rw-r--r-- | window.go | 16 |
5 files changed, 127 insertions, 49 deletions
@@ -144,8 +144,11 @@ func NewApp(cfg Config) (app *App, err error) { app.mergeLine(former, addition) }, Colors: ui.ConfigColors{ - Unread: cfg.Colors.Unread, - Nicks: cfg.Colors.Nicks, + Unread: cfg.Colors.Unread, + Nicks: cfg.Colors.Nicks, + ServerForeground: cfg.Colors.ServerForeground, + ChanForegroundInactive: cfg.Colors.ChanForegroundInactive, + ChanForegroundActive: cfg.Colors.ChanForegroundActive, }, }) if err != nil { @@ -347,8 +350,10 @@ func (app *App) ircLoop(netID string) { content: nil, } app.queueStatusLine(netID, ui.Line{ - Head: "!!", + Head: ":(", + HeadTag: ":(", HeadColor: tcell.ColorRed, + Temporary: true, Body: ui.PlainString("Connection lost"), }) } @@ -356,8 +361,11 @@ func (app *App) ircLoop(netID string) { func (app *App) connect(netID string) net.Conn { app.queueStatusLine(netID, ui.Line{ - Head: "--", - Body: ui.PlainSprintf("Connecting to %s...", app.cfg.Addr), + Head: "﹒﹒﹒", + HeadTag: "﹒﹒﹒", + HeadColor: tcell.ColorOrange, + Temporary: true, + Body: ui.PlainSprintf("Connecting to %s…", app.cfg.Addr), }) conn, err := app.tryConnect() if err == nil { @@ -365,7 +373,9 @@ func (app *App) connect(netID string) net.Conn { } app.queueStatusLine(netID, ui.Line{ Head: "!!", + HeadTag: "!!", HeadColor: tcell.ColorRed, + Temporary: true, Body: ui.PlainSprintf("Connection failed: %v", err), }) return nil @@ -751,10 +761,11 @@ 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.addStatusLine(netID, ui.Line{ - At: msg.TimeOrNow(), - Head: "--", - Body: ui.PlainString(body), + app.addTemporaryStatusLine(netID, ui.Line{ + At: msg.TimeOrNow(), + Head: ":)", + HeadColor: tcell.ColorGreen, + Body: ui.PlainString(body), }) for target := range app.monitor[s.NetID()] { // TODO: batch MONITOR + @@ -768,7 +779,7 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { body.AddStyle(0, textStyle) body.AddStyle(len(ev.FormerNick), arrowStyle) body.AddStyle(body.Len()-len(s.Nick()), textStyle) - app.addStatusLine(netID, ui.Line{ + app.addTemporaryStatusLine(netID, ui.Line{ At: msg.TimeOrNow(), Head: "--", HeadColor: tcell.ColorGray, @@ -991,32 +1002,55 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) { } if ev.Code == "372" { app.win.AddLine(netID, "", ui.Line{ - At: msg.TimeOrNow(), - Head: "MOTD --", - Body: ui.PlainString(ev.Message), + At: msg.TimeOrNow(), + Head: "MOTD", + HeadTag: "motd", + HeadColor: tcell.ColorWhiteSmoke, + Body: ui.PlainString(ev.Message), + }) + break + } + if ev.Code == "396" { + app.win.AddLine(netID, "", ui.Line{ + At: msg.TimeOrNow(), + Head: "server", + HeadTag: "server", + HeadColor: tcell.ColorGray, + Body: ui.PlainString(ev.Message), }) break } var head string var body string + headColor := tcell.ColorGray + statusLine := false switch ev.Severity { case irc.SeverityFail: head = "--" + headColor = tcell.ColorRed body = fmt.Sprintf("Error (code %s): %s", ev.Code, ev.Message) case irc.SeverityWarn: head = "--" + headColor = tcell.ColorYellow body = fmt.Sprintf("Warning (code %s): %s", ev.Code, ev.Message) case irc.SeverityNote: - head = ev.Code + " --" + head = ev.Code body = ev.Message default: panic("unreachable") } - app.addStatusLine(netID, ui.Line{ - At: msg.TimeOrNow(), - Head: head, - Body: ui.PlainString(body), - }) + line := ui.Line{ + At: msg.TimeOrNow(), + Head: head, + HeadTag: head, + HeadColor: headColor, + Body: ui.PlainString(body), + } + if statusLine { + app.addStatusLine(netID, line) + } else { + app.win.AddLine(netID, "", line) + } } } @@ -1091,7 +1125,7 @@ func (app *App) notifyHighlight(buffer, nick, content string) { // if default path unreachable, simple bail if app.cfg.OnHighlightPath != "" { body := fmt.Sprintf("Unable to find on-highlight command at path: %q", path) - app.addStatusLine(netID, ui.Line{ + app.addTemporaryStatusLine(netID, ui.Line{ At: time.Now(), Head: "!!", HeadColor: tcell.ColorRed, @@ -1323,7 +1357,8 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin head := ev.User headColor := tcell.ColorWhite if isAction || isNotice { - head = "*" + head = "﹡" + headColor = ui.IdentColor(app.cfg.Colors.Nicks, ev.User) } else { headColor = ui.IdentColor(app.cfg.Colors.Nicks, head) } @@ -1338,11 +1373,12 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin body.WriteStyledString(ui.IRCString(content)) } else if isAction { color := ui.IdentColor(app.cfg.Colors.Nicks, ev.User) - body.SetStyle(tcell.StyleDefault.Foreground(color)) + body.SetStyle(tcell.StyleDefault.Italic(true).Foreground(color)) body.WriteString(ev.User) - body.SetStyle(tcell.StyleDefault) + body.SetStyle(tcell.StyleDefault.Italic(true)) body.WriteString(" ") body.WriteStyledString(ui.IRCString(content)) + body.SetStyle(tcell.StyleDefault) } else { body.WriteStyledString(ui.IRCString(content)) } @@ -1350,6 +1386,7 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin line = ui.Line{ At: ev.Time, Head: head, + HeadTag: head, HeadColor: headColor, Notify: notification, Body: body.StyledString(), @@ -1496,6 +1533,7 @@ func (app *App) printTopic(netID, buffer string) (ok bool) { At: time.Now(), Head: "topic", HeadColor: tcell.ColorGray, + HeadTag: "topic", Body: ui.Styled(topic, tcell.StyleDefault.Foreground(tcell.ColorWhite)), }) if who != nil { @@ -1507,6 +1545,7 @@ func (app *App) printTopic(netID, buffer string) (ok bool) { At: time.Now(), Head: "—", HeadColor: tcell.ColorGray, + HeadTag: "topicby", Body: ui.Styled(body, tcell.StyleDefault.Foreground(tcell.ColorGray)), }) return true @@ -48,9 +48,12 @@ func parseColor(s string, c *tcell.Color) error { } type ConfigColors struct { - Prompt tcell.Color - Unread tcell.Color - Nicks ui.ColorScheme + Prompt tcell.Color + Unread tcell.Color + Nicks ui.ColorScheme + ServerForeground tcell.Color + ChanForegroundInactive tcell.Color + ChanForegroundActive tcell.Color } type Config struct { @@ -109,9 +112,12 @@ func Defaults() (cfg Config, err error) { MemberColEnabled: true, TextMaxWidth: 0, Colors: ConfigColors{ - Prompt: tcell.ColorDefault, - Unread: tcell.ColorDefault, - Nicks: ui.ColorSchemeBase, + Prompt: tcell.ColorDefault, + Unread: tcell.ColorDefault, + Nicks: ui.ColorSchemeBase, + ServerForeground: tcell.ColorDarkGray, + ChanForegroundInactive: tcell.ColorGray, + ChanForegroundActive: tcell.ColorWhite, }, Debug: false, } @@ -345,6 +351,12 @@ func unmarshal(filename string, cfg *Config) (err error) { cfg.Colors.Prompt = color case "unread": cfg.Colors.Unread = color + case "server": + cfg.Colors.ServerForeground = color + case "channel": + cfg.Colors.ChanForegroundInactive = color + case "channel-active": + cfg.Colors.ChanForegroundActive = color default: return fmt.Errorf("unknown directive %q", child.Name) } diff --git a/ui/buffers.go b/ui/buffers.go index 3a17b18..703fd1a 100644 --- a/ui/buffers.go +++ b/ui/buffers.go @@ -37,6 +37,7 @@ type Line struct { Highlight bool Readable bool Mergeable bool + Temporary bool Data interface{} splitPoints []point @@ -392,9 +393,12 @@ func (bs *BufferList) AddLine(netID, title string, line Line) { } else { if n != 0 { l := &b.lines[n-1] - if l.Head == line.Head || l.HeadTag == line.Head { + if l.Temporary { + b.lines = b.lines[:n-1] + } + if line.HeadTag == l.HeadTag || l.Head == line.Head || l.HeadTag == line.Head { line.HeadTag = line.Head - line.Head = "" + line.Head = "│" } } line.computeSplitPoints() @@ -435,9 +439,9 @@ func (bs *BufferList) AddLines(netID, title string, before, after []Line) { } if len(lines) > 0 { l := &lines[len(lines)-1] - if l.Head == line.Head || l.HeadTag == line.Head { + if line.HeadTag == l.HeadTag || l.Head == line.Head || l.HeadTag == line.Head { line.HeadTag = line.Head - line.Head = "" + line.Head = "│" } } lines = append(lines, line) @@ -595,6 +599,8 @@ func (bs *BufferList) DrawVerticalBufferList(screen tcell.Screen, x0, y0, width, st := tcell.StyleDefault if b.unread { st = st.Bold(true).Foreground(bs.colors.Unread) + } else { + st = st.Foreground(bs.colors.ChanForegroundInactive) } if bi == bs.current || bi == bs.clicked { st = st.Reverse(true) @@ -609,6 +615,7 @@ func (bs *BufferList) DrawVerticalBufferList(screen tcell.Screen, x0, y0, width, var title string if b.title == "" { title = b.netName + st.Foreground(bs.colors.ServerForeground) } else { if bi == bs.current || bi == bs.clicked { screen.SetContent(x, y, ' ', nil, tcell.StyleDefault.Reverse(true)) @@ -708,6 +715,7 @@ func (bs *BufferList) DrawHorizontalBufferList(screen tcell.Screen, x0, y0, widt break } st := tcell.StyleDefault + st = st.Foreground(bs.colors.ChanForegroundInactive) if b.unread { st = st.Bold(true).Foreground(bs.colors.Unread) } else if i == bs.current { @@ -719,7 +727,7 @@ func (bs *BufferList) DrawHorizontalBufferList(screen tcell.Screen, x0, y0, widt var title string if b.title == "" { - st = st.Dim(true) + st = st.Dim(true).Foreground(bs.colors.ServerForeground) title = b.netName } else { title = b.title @@ -11,21 +11,26 @@ import ( ) type Config struct { - NickColWidth int - ChanColWidth int - ChanColEnabled bool - MemberColWidth int - MemberColEnabled bool - TextMaxWidth int - AutoComplete func(cursorIdx int, text []rune) []Completion - Mouse bool - MergeLine func(former *Line, addition Line) - Colors ConfigColors + NickColWidth int + ChanColWidth int + ChanColEnabled bool + MemberColWidth int + MemberColEnabled bool + TextMaxWidth int + AutoComplete func(cursorIdx int, text []rune) []Completion + Mouse bool + MergeLine func(former *Line, addition Line) + Colors ConfigColors + HideMultiLineNickEnabled bool + HideMultiLineNickChar string } type ConfigColors struct { - Unread tcell.Color - Nicks ColorScheme + Unread tcell.Color + Nicks ColorScheme + ServerForeground tcell.Color + ChanForegroundInactive tcell.Color + ChanForegroundActive tcell.Color } type UI struct { @@ -58,6 +63,10 @@ func New(config Config) (ui *UI, err error) { ui.memberWidth = config.MemberColWidth } + if config.HideMultiLineNickEnabled && config.HideMultiLineNickChar == "" { + config.HideMultiLineNickChar = "│" + } + ui.screen, err = tcell.NewScreen() if err != nil { return @@ -44,6 +44,16 @@ func (app *App) addStatusLine(netID string, line ui.Line) { app.win.AddLine(netID, "", line) } +func (app *App) addTemporaryStatusLine(netID string, line ui.Line) { + currentNetID, buffer := app.win.CurrentBuffer() + if currentNetID == netID && buffer != "" { + currentLine := line + currentLine.Temporary = true + app.win.AddLine(netID, buffer, currentLine) + } + app.win.AddLine(netID, "", line) +} + func (app *App) setStatus() { netID, buffer := app.win.CurrentBuffer() s := app.sessions[netID] @@ -53,11 +63,11 @@ func (app *App) setStatus() { ts := s.Typings(buffer) status := "" if 3 < len(ts) { - status = "several people are typing..." + status = "several people are typing…" } else { - verb := " is typing..." + verb := " is typing…" if 1 < len(ts) { - verb = " are typing..." + verb = " are typing…" status = strings.Join(ts[:len(ts)-1], ", ") + " and " } if 0 < len(ts) { |