1 // Copyright 2016 The Tcell Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use file except in compliance with the License. 5 // You may obtain a copy of the license at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package views 16 17 import ( 18 "unicode" 19 20 "github.com/gdamore/tcell/v2" 21 ) 22 23 // SimpleStyledText is a form of Text that offers highlighting of the text 24 // using simple in-line markup. Its intention is to make it easier to mark 25 // up hot // keys for menubars, etc. 26 type SimpleStyledText struct { 27 styles map[rune]tcell.Style 28 markup []rune 29 Text 30 } 31 32 // SetMarkup sets the text used for the string. It applies markup as follows 33 // (modeled on tcsh style prompt markup): 34 // 35 // * %% - emit a single % in current style 36 // * %N - normal style 37 // * %A - alternate style 38 // * %S - start standout (reverse) style 39 // * %B - start bold style 40 // * %U - start underline style 41 // 42 // Other styles can be set using %<rune>, if styles are registered. 43 // Upper case characters and punctuation are reserved for use by the system. 44 // Lower case are available for use by the user. (Users may define mappings 45 // for upper case letters to override system defined styles.) 46 // 47 // Note that for simplicity, combining styles is not supported. By default 48 // the alternate style is the same as standout (reverse) mode. 49 // 50 // Arguably we could have used Markdown syntax instead, but properly doing all 51 // of Markdown is not trivial, and these escape sequences make it clearer that 52 // we are not even attempting to do that. 53 func (t *SimpleStyledText) SetMarkup(s string) { 54 55 markup := []rune(s) 56 styl := make([]tcell.Style, 0, len(markup)) 57 text := make([]rune, 0, len(markup)) 58 59 style := t.styles['N'] 60 61 esc := false 62 for _, r := range markup { 63 if esc { 64 esc = false 65 switch r { 66 case '%': 67 text = append(text, '%') 68 styl = append(styl, style) 69 default: 70 style = t.styles[r] 71 } 72 continue 73 } 74 switch r { 75 case '%': 76 esc = true 77 continue 78 default: 79 text = append(text, r) 80 styl = append(styl, style) 81 } 82 } 83 84 t.Text.SetText(string(text)) 85 for i, s := range styl { 86 t.SetStyleAt(i, s) 87 } 88 t.markup = markup 89 } 90 91 // Registers a style for the given rune. This style will be used for 92 // text marked with %<r>. See SetMarkup() for more detail. Note that 93 // this must be done before using any of the styles with SetMarkup(). 94 // Only letters may be used when registering styles, and be advised that 95 // the system may have predefined uses for upper case letters. 96 func (t *SimpleStyledText) RegisterStyle(r rune, style tcell.Style) { 97 if r == 'N' { 98 t.Text.SetStyle(style) 99 } 100 if unicode.IsLetter(r) { 101 t.styles[r] = style 102 } 103 } 104 105 // LookupStyle returns the style registered for the given rune. 106 // Returns tcell.StyleDefault if no style was previously registered 107 // for the rune. 108 func (t *SimpleStyledText) LookupStyle(r rune) tcell.Style { 109 return t.styles[r] 110 } 111 112 // Markup returns the text that was set, including markup. 113 func (t *SimpleStyledText) Markup() string { 114 return string(t.markup) 115 } 116 117 // NewSimpleStyledText creates an empty Text. 118 func NewSimpleStyledText() *SimpleStyledText { 119 ss := &SimpleStyledText{} 120 // Create map and establish default styles. 121 ss.styles = make(map[rune]tcell.Style) 122 ss.styles['N'] = tcell.StyleDefault 123 ss.styles['S'] = tcell.StyleDefault.Reverse(true) 124 ss.styles['U'] = tcell.StyleDefault.Underline(true) 125 ss.styles['B'] = tcell.StyleDefault.Bold(true) 126 return ss 127 } 128