chat.Color->chat.Style, highlighting works.
authorAndrey Petrov <andrey.petrov@shazow.net>
Sat, 17 Jan 2015 21:26:26 +0000 (13:26 -0800)
committerAndrey Petrov <andrey.petrov@shazow.net>
Sat, 17 Jan 2015 21:26:26 +0000 (13:26 -0800)
chat/message.go
chat/theme.go
chat/user.go
host.go

index 2a804a9b458f72adc91480246a1385345184cb4e..c98805cc74a466d57fa6677ba812bd09cc899043 100644 (file)
@@ -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 {
index dbf9e82c918032422a11dbb06959b09e52d0e716..5e7af3cd77fd2e0c0fc30d0446234014f7d8db99 100644 (file)
@@ -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",
index b7ab4a88b50802c1d97d13fe4f1b1b2b7f1808ff..b82c8300820f2b8de10213db2cda8fa48192e8c0 100644 (file)
@@ -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 5747310f83b17c732fbe667bd98998952a4b4fdc..bc74851c2ac113412731f3b26a5ed0b1dafcc5e8 100644 (file)
--- 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())
                }
        }