package text
import (
"fmt"
"strconv"
"strings"
"unicode/utf8"
)
// Align denotes how text is to be aligned horizontally.
type Align int
// Align enumerations
const (
AlignDefault Align = iota // same as AlignLeft
AlignLeft // "left "
AlignCenter // " center "
AlignJustify // "justify it"
AlignRight // " right"
)
// Apply aligns the text as directed. For ex.:
// * AlignDefault.Apply("Jon Snow", 12) returns "Jon Snow "
// * AlignLeft.Apply("Jon Snow", 12) returns "Jon Snow "
// * AlignCenter.Apply("Jon Snow", 12) returns " Jon Snow "
// * AlignJustify.Apply("Jon Snow", 12) returns "Jon Snow"
// * AlignRight.Apply("Jon Snow", 12) returns " Jon Snow"
func (a Align) Apply(text string, maxLength int) string {
text = a.trimString(text)
sLen := utf8.RuneCountInString(text)
sLenWoE := RuneCount(text)
numEscChars := sLen - sLenWoE
// now, align the text
switch a {
case AlignDefault, AlignLeft:
return fmt.Sprintf("%-"+strconv.Itoa(maxLength+numEscChars)+"s", text)
case AlignCenter:
if sLenWoE < maxLength {
// left pad with half the number of spaces needed before using %text
return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s",
text+strings.Repeat(" ", int((maxLength-sLenWoE)/2)))
}
case AlignJustify:
return a.justifyText(text, sLenWoE, maxLength)
}
return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s", text)
}
// HTMLProperty returns the equivalent HTML horizontal-align tag property.
func (a Align) HTMLProperty() string {
switch a {
case AlignLeft:
return "align=\"left\""
case AlignCenter:
return "align=\"center\""
case AlignJustify:
return "align=\"justify\""
case AlignRight:
return "align=\"right\""
default:
return ""
}
}
// MarkdownProperty returns the equivalent Markdown horizontal-align separator.
func (a Align) MarkdownProperty() string {
switch a {
case AlignLeft:
return ":--- "
case AlignCenter:
return ":---:"
case AlignRight:
return " ---:"
default:
return " --- "
}
}
func (a Align) justifyText(text string, textLength int, maxLength int) string {
// split the text into individual words
wordsUnfiltered := strings.Split(text, " ")
words := Filter(wordsUnfiltered, func(item string) bool {
return item != ""
})
// empty string implies spaces for maxLength
if len(words) == 0 {
return strings.Repeat(" ", maxLength)
}
// get the number of spaces to insert into the text
numSpacesNeeded := maxLength - textLength + strings.Count(text, " ")
numSpacesNeededBetweenWords := 0
if len(words) > 1 {
numSpacesNeededBetweenWords = numSpacesNeeded / (len(words) - 1)
}
// create the output string word by word with spaces in between
var outText strings.Builder
outText.Grow(maxLength)
for idx, word := range words {
if idx > 0 {
// insert spaces only after the first word
if idx == len(words)-1 {
// insert all the remaining space before the last word
outText.WriteString(strings.Repeat(" ", numSpacesNeeded))
numSpacesNeeded = 0
} else {
// insert the determined number of spaces between each word
outText.WriteString(strings.Repeat(" ", numSpacesNeededBetweenWords))
// and reduce the number of spaces needed after this
numSpacesNeeded -= numSpacesNeededBetweenWords
}
}
outText.WriteString(word)
if idx == len(words)-1 && numSpacesNeeded > 0 {
outText.WriteString(strings.Repeat(" ", numSpacesNeeded))
}
}
return outText.String()
}
func (a Align) trimString(text string) string {
switch a {
case AlignDefault, AlignLeft:
if strings.HasSuffix(text, " ") {
return strings.TrimRight(text, " ")
}
case AlignRight:
if strings.HasPrefix(text, " ") {
return strings.TrimLeft(text, " ")
}
default:
if strings.HasPrefix(text, " ") || strings.HasSuffix(text, " ") {
return strings.Trim(text, " ")
}
}
return text
}
|
The pages are generated with Golds v0.3.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |