package cardsim import ( "fmt" "strings" ) // Message is an opaque interface representing a displayable message. // Using an interface here allows for implementation of new message display // and formatting features without rewriting all existing callers. type Message interface { fmt.Stringer } // Titled desccribes any type that returns a Message as a title, given a Player // (which it may ignore). type Titled[C StatsCollection] interface { Title(*Player[C]) Message } type stringMessage string func (s stringMessage) String() string { return string(s) } // MsgStr returns a Message representing a fixed string. func MsgStr(s string) Message { return stringMessage(s) } // Msgf is a Sprintf-like function that produces a Message equivalent to the // one created by MsgStr. func Msgf(f string, args ...any) Message { return stringMessage(fmt.Sprintf(f, args...)) } // ErrorMessage returns a Message representing an Error. // This is preferred over Msgf for errors, since future versions of the library // may perform special message formatting for errors. func ErrorMessage(e error) Message { if e == nil { return nil } if IsSeriousError(e) { return MultiMessage{MsgStr("SERIOUS ERROR:"), Msgf("%v", e)} } return MultiMessage{MsgStr("Warning:"), Msgf("%v", e)} } // A SpecialMessage is a specific, uniquely identifiable message. type SpecialMessage struct { msg Message } // String implements Message. func (s *SpecialMessage) String() string { if s == nil { return "" } return s.msg.String() } // Messages that various display surfaces or other components may have a special interpretation of // and identify specifically. These are largely sentinel values. Nil is a paragraph break. var ( SectionBreak = &SpecialMessage{MsgStr(" -------------------------------------------------------------------- ")} ChapterBreak = &SpecialMessage{MsgStr(" ==================================================================== ")} ) // IsSpecialMessage returns whether a provided Message is a specific SpecialMessage. func IsSpecialMessage(m Message, s *SpecialMessage) bool { if m == nil { return s == nil } if s2, ok := m.(*SpecialMessage); ok { return s == s2 } return false } // MultiMessage is a sequence of messages treated like one message. type MultiMessage []Message func (m MultiMessage) String() string { s := make([]string, len(m)) for i, msg := range m { if msg == nil { s[i] = "" continue } s[i] = msg.String() continue } return strings.Join(s, "\n") }