123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package explain
- import (
- "fmt"
- "io"
- "strings"
- )
- // Formatter helps you write with indentation, and can wrap text as needed.
- type Formatter struct {
- IndentLevel int
- Wrap int
- Writer io.Writer
- }
- // Indent creates a new Formatter that will indent the code by that much more.
- func (f Formatter) Indent(indent int) *Formatter {
- f.IndentLevel = f.IndentLevel + indent
- return &f
- }
- // Write writes a string with the indentation set for the
- // Formatter. This is not wrapping text.
- func (f *Formatter) Write(str string, a ...interface{}) error {
- // Don't indent empty lines
- if str == "" {
- _, err := io.WriteString(f.Writer, "\n")
- return err
- }
- indent := ""
- for i := 0; i < f.IndentLevel; i++ {
- indent = indent + " "
- }
- if len(a) > 0 {
- str = fmt.Sprintf(str, a...)
- }
- _, err := io.WriteString(f.Writer, indent+str+"\n")
- return err
- }
- // WriteWrapped writes a string with the indentation set for the
- // Formatter, and wraps as needed.
- func (f *Formatter) WriteWrapped(str string, a ...interface{}) error {
- if f.Wrap == 0 {
- return f.Write(str, a...)
- }
- text := fmt.Sprintf(str, a...)
- strs := wrapString(text, f.Wrap-f.IndentLevel)
- for _, substr := range strs {
- if err := f.Write(substr); err != nil {
- return err
- }
- }
- return nil
- }
- type line struct {
- wrap int
- words []string
- }
- func (l *line) String() string {
- return strings.Join(l.words, " ")
- }
- func (l *line) Empty() bool {
- return len(l.words) == 0
- }
- func (l *line) Len() int {
- return len(l.String())
- }
- // Add adds the word to the line, returns true if we could, false if we
- // didn't have enough room. It's always possible to add to an empty line.
- func (l *line) Add(word string) bool {
- newLine := line{
- wrap: l.wrap,
- words: append(l.words, word),
- }
- if newLine.Len() <= l.wrap || len(l.words) == 0 {
- l.words = newLine.words
- return true
- }
- return false
- }
- func wrapString(str string, wrap int) []string {
- words := strings.Fields(str)
- wrapped := []string{}
- l := line{wrap: wrap}
- for _, word := range words {
- if !l.Add(word) {
- wrapped = append(wrapped, l.String())
- l = line{wrap: wrap}
- if !l.Add(word) {
- panic("Couldn't add to empty line.")
- }
- }
- }
- if !l.Empty() {
- wrapped = append(wrapped, l.String())
- }
- return wrapped
- }
|