From 838285ba43e6ad38cd6c74d2049a86ff3f14a56e Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Sat, 17 Jan 2015 13:26:26 -0800 Subject: [PATCH] chat.Color->chat.Style, highlighting works. --- chat/message.go | 12 +++++++++++- chat/theme.go | 48 +++++++++++++++++++++++++++++++++++------------- chat/user.go | 33 +++++++++++++++++++++++++++------ host.go | 2 ++ 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/chat/message.go b/chat/message.go index 2a804a9..c98805c 100644 --- a/chat/message.go +++ b/chat/message.go @@ -2,6 +2,7 @@ package chat import ( "fmt" + "regexp" "strings" "time" ) @@ -101,6 +102,15 @@ func (m *PublicMsg) Render(t *Theme) string { return fmt.Sprintf("%s: %s", t.ColorName(m.from), m.body) } +func (m *PublicMsg) RenderHighlighted(t *Theme, highlight *regexp.Regexp) string { + if highlight == nil || t == nil { + return m.Render(t) + } + + body := highlight.ReplaceAllString(m.body, t.Highlight("${1}")) + return fmt.Sprintf("%s: %s", t.ColorName(m.from), body) +} + func (m *PublicMsg) String() string { return fmt.Sprintf("%s: %s", m.from.Name(), m.body) } @@ -212,7 +222,7 @@ type CommandMsg struct { *PublicMsg command string args []string - room *Room + room *Room } func (m *CommandMsg) Command() string { diff --git a/chat/theme.go b/chat/theme.go index dbf9e82..5e7af3c 100644 --- a/chat/theme.go +++ b/chat/theme.go @@ -28,12 +28,24 @@ const ( Newline = "\r\n" ) -// Interface for Colors -type Color interface { +// Interface for Styles +type Style interface { String() string Format(string) string } +// General hardcoded style, mostly used as a crutch until we flesh out the +// framework to support backgrounds etc. +type style string + +func (c style) String() string { + return string(c) +} + +func (c style) Format(s string) string { + return c.String() + s + Reset +} + // 256 color type, for terminals who support it type Color256 uint8 @@ -62,12 +74,12 @@ func (c Color0) Format(s string) string { // Container for a collection of colors type Palette struct { - colors []Color + colors []Style size int } // Get a color by index, overflows are looped around. -func (p Palette) Get(i int) Color { +func (p Palette) Get(i int) Style { return p.colors[i%(p.size-1)] } @@ -85,10 +97,11 @@ func (p Palette) String() string { // Collection of settings for chat type Theme struct { - id string - sys Color - pm Color - names *Palette + id string + sys Style + pm Style + highlight Style + names *Palette } func (t Theme) Id() string { @@ -122,6 +135,14 @@ func (t Theme) ColorSys(s string) string { return t.sys.Format(s) } +// Highlight a matched string, usually name +func (t Theme) Highlight(s string) string { + if t.highlight == nil { + return s + } + return t.highlight.Format(s) +} + // List of initialzied themes var Themes []Theme @@ -131,7 +152,7 @@ var DefaultTheme *Theme func readableColors256() *Palette { size := 247 p := Palette{ - colors: make([]Color, size), + colors: make([]Style, size), size: size, } j := 0 @@ -151,10 +172,11 @@ func init() { Themes = []Theme{ Theme{ - id: "colors", - names: palette, - sys: palette.Get(8), // Grey - pm: palette.Get(7), // White + id: "colors", + names: palette, + sys: palette.Get(8), // Grey + pm: palette.Get(7), // White + highlight: style(Bold + "\033[48;5;11m\033[38;5;16m"), // Yellow highlight }, Theme{ id: "mono", diff --git a/chat/user.go b/chat/user.go index b7ab4a8..b82c830 100644 --- a/chat/user.go +++ b/chat/user.go @@ -2,13 +2,16 @@ package chat import ( "errors" + "fmt" "io" "math/rand" + "regexp" "sync" "time" ) const messageBuffer = 20 +const reHighlight = `\b(%s)\b` var ErrUserClosed = errors.New("user closed") @@ -100,9 +103,28 @@ func (u *User) ConsumeOne(out io.Writer) { u.HandleMsg(<-u.msg, out) } +// SetHighlight sets the highlighting regular expression to match string. +func (u *User) SetHighlight(s string) error { + re, err := regexp.Compile(fmt.Sprintf(reHighlight, s)) + if err != nil { + return err + } + u.Config.Highlight = re + return nil +} + +func (u User) render(m Message) string { + switch m := m.(type) { + case *PublicMsg: + return m.RenderHighlighted(u.Config.Theme, u.Config.Highlight) + Newline + default: + return m.Render(u.Config.Theme) + Newline + } +} + func (u *User) HandleMsg(m Message, out io.Writer) { - s := m.Render(u.Config.Theme) - _, err := out.Write([]byte(s + Newline)) + r := u.render(m) + _, err := out.Write([]byte(r)) if err != nil { logger.Printf("Write failed to %s, closing: %s", u.Name(), err) u.Close() @@ -127,7 +149,7 @@ func (u *User) Send(m Message) error { // Container for per-user configurations. type UserConfig struct { - Highlight bool + Highlight *regexp.Regexp Bell bool Quiet bool Theme *Theme @@ -138,9 +160,8 @@ var DefaultUserConfig *UserConfig func init() { DefaultUserConfig = &UserConfig{ - Highlight: true, - Bell: false, - Quiet: false, + Bell: true, + Quiet: false, } // TODO: Seed random? diff --git a/host.go b/host.go index 5747310..bc74851 100644 --- a/host.go +++ b/host.go @@ -92,6 +92,7 @@ func (h *Host) Connect(term *sshd.Terminal) { // Successfully joined. term.SetPrompt(GetPrompt(user)) + user.SetHighlight(user.Name()) h.count++ // Should the user be op'd on join? @@ -119,6 +120,7 @@ func (h *Host) Connect(term *sshd.Terminal) { // FIXME: This is hacky, how do we improve the API to allow for // this? Chat module shouldn't know about terminals. term.SetPrompt(GetPrompt(user)) + user.SetHighlight(user.Name()) } }