diff --git a/textRender.go b/textRender.go index 69c791a..2c58b70 100644 --- a/textRender.go +++ b/textRender.go @@ -8,13 +8,7 @@ import ( // TextRender adds common methods for rendering a text on screeen. type TextRender interface { NormalizedText(text string) string - RenderSequence(text string, lastColor, background Attribute) RenderedSubsequence -} - -type subSecequence struct { - start int - end int - color Attribute + RenderSequence(text string, lastColor, background Attribute) RenderedSequence } // MarkdownRegex is used by MarkdownTextRenderer to determine how to format the @@ -33,50 +27,61 @@ type MarkdownTextRenderer struct{} // NormalizedText returns the text the user will see (without colors). // It strips out all formatting option and only preserves plain text. func (r MarkdownTextRenderer) NormalizedText(text string) string { - lText := strings.ToLower(text) - indexes := markdownPattern.FindAllStringSubmatchIndex(lText, -1) - - // Interate through indexes in reverse order. - for i := len(indexes) - 1; i >= 0; i-- { - theIndex := indexes[i] - start, end := theIndex[0], theIndex[1] - contentStart, contentEnd := theIndex[2], theIndex[3] - - text = text[:start] + text[contentStart:contentEnd] + text[end:] - } - - return text + return r.RenderSequence(text, 0, 0).NormalizedText } -// RenderedSubsequence is a string sequence that is capable of returning the +/* +RenderSequence renders the sequence `text` using a markdown-like syntax: +`[hello](red) world` will become: `hello world` where hello is red. + +You may also specify other attributes such as bold text: +`[foo](YELLOW, BOLD)` will become `foo` in yellow, bold text. + + +For all available combinations, colors, and attribute, see: `StringToAttribute`. + +This method returns a RenderedSequence +*/ +func (r MarkdownTextRenderer) RenderSequence(text string, lastColor, background Attribute) RenderedSequence { + getMatch := func(s string) []int { + return markdownPattern.FindStringSubmatchIndex(strings.ToLower(s)) + } + + var sequences []ColorSubsequence + for match := getMatch(text); match != nil; match = getMatch(text) { + start, end := match[0], match[1] + colorStart, colorEnd := match[4], match[5] + contentStart, contentEnd := match[2], match[3] + + color := strings.ToUpper(text[colorStart:colorEnd]) + content := text[contentStart:contentEnd] + theSequence := ColorSubsequence{color, contentStart - 1, contentEnd - 1} + + sequences = append(sequences, theSequence) + text = text[:start] + content + text[end:] + } + + return RenderedSequence{text, lastColor, background, sequences} +} + +// RenderedSequence is a string sequence that is capable of returning the // Buffer used by termui for displaying the colorful string. -type RenderedSubsequence struct { - RawText string +type RenderedSequence struct { NormalizedText string LastColor Attribute BackgroundColor Attribute + Sequences []ColorSubsequence +} - sequences subSecequence +// A ColorSubsequence represents a color for the given text span. +type ColorSubsequence struct { + Color string // TODO: use attribute + Start int + End int } // Buffer returns the colorful formatted buffer and the last color that was // used. -func (s *RenderedSubsequence) Buffer(x, y int) ([]Point, Attribute) { - // var buffer []Point - // dx := 0 - // for _, r := range []rune(s.NormalizedText) { - // p := Point{ - // Ch: r, - // X: x + dx, - // Y: y, - // Fg: Attribute(rand.Intn(8)), - // Bg: background, - // } - // - // buffer = append(buffer, p) - // dx += charWidth(r) - // } - // - // return buffer +func (s *RenderedSequence) Buffer(x, y int) ([]Point, Attribute) { return nil, s.LastColor } diff --git a/textRender_test.go b/textRender_test.go index 3118211..8ab9151 100644 --- a/textRender_test.go +++ b/textRender_test.go @@ -6,15 +6,47 @@ import ( "github.com/stretchr/testify/assert" ) +func getMDRenderer() MarkdownTextRenderer { + return MarkdownTextRenderer{} +} + func TestMarkdownTextRenderer_NormalizedText(t *testing.T) { - renderer := MarkdownTextRenderer{} + renderer := getMDRenderer() got := renderer.NormalizedText("[ERROR](red,bold) Something went wrong") assert.Equal(t, got, "ERROR Something went wrong") - got = renderer.NormalizedText("[foo](g) hello [bar](green) world") + got = renderer.NormalizedText("[foo](red) hello [bar](green) world") assert.Equal(t, got, "foo hello bar world") got = renderer.NormalizedText("[foo](g) hello [bar]green (world)") assert.Equal(t, got, "foo hello [bar]green (world)") + + // FIXME: [[ERROR]](red,bold) test should normalize to: + // [ERROR] test +} + +func assertRenderSequence(t *testing.T, sequence RenderedSequence, last, background Attribute, text string, lenSequences int) { + assert.Equal(t, last, sequence.LastColor) + assert.Equal(t, background, sequence.BackgroundColor) + assert.Equal(t, text, sequence.NormalizedText) + assert.Equal(t, lenSequences, len(sequence.Sequences)) +} + +func assertColorSubsequence(t *testing.T, s ColorSubsequence, color string, start, end int) { + assert.Equal(t, ColorSubsequence{color, start, end}, s) +} + +func TestMarkdownTextRenderer_RenderSequence(t *testing.T) { + renderer := getMDRenderer() + + got := renderer.RenderSequence("[ERROR](red,bold) something went wrong", 3, 5) + assertRenderSequence(t, got, 3, 5, "ERROR something went wrong", 1) + assertColorSubsequence(t, got.Sequences[0], "RED,BOLD", 0, 5) + + got = renderer.RenderSequence("[foo](red) hello [bar](green) world", 7, 2) + assertRenderSequence(t, got, 3, 2, "foo hello bar world", 2) + + assertColorSubsequence(t, got.Sequences[0], "RED", 0, 3) + assertColorSubsequence(t, got.Sequences[1], "GREEN", 10, 13) }