...

Source file src/github.com/MakeNowJust/heredoc/heredoc.go

Documentation: github.com/MakeNowJust/heredoc

     1  // Copyright (c) 2014-2019 TSUYUSATO Kitsune
     2  // This software is released under the MIT License.
     3  // http://opensource.org/licenses/mit-license.php
     4  
     5  // Package heredoc provides creation of here-documents from raw strings.
     6  //
     7  // Golang supports raw-string syntax.
     8  //
     9  //     doc := `
    10  //     	Foo
    11  //     	Bar
    12  //     `
    13  //
    14  // But raw-string cannot recognize indentation. Thus such content is an indented string, equivalent to
    15  //
    16  //     "\n\tFoo\n\tBar\n"
    17  //
    18  // I dont't want this!
    19  //
    20  // However this problem is solved by package heredoc.
    21  //
    22  //     doc := heredoc.Doc(`
    23  //     	Foo
    24  //     	Bar
    25  //     `)
    26  //
    27  // Is equivalent to
    28  //
    29  //     "Foo\nBar\n"
    30  package heredoc
    31  
    32  import (
    33  	"fmt"
    34  	"strings"
    35  	"unicode"
    36  )
    37  
    38  const maxInt = int(^uint(0) >> 1)
    39  
    40  // Doc returns un-indented string as here-document.
    41  func Doc(raw string) string {
    42  	skipFirstLine := false
    43  	if len(raw) > 0 && raw[0] == '\n' {
    44  		raw = raw[1:]
    45  	} else {
    46  		skipFirstLine = true
    47  	}
    48  
    49  	lines := strings.Split(raw, "\n")
    50  
    51  	minIndentSize := getMinIndent(lines, skipFirstLine)
    52  	lines = removeIndentation(lines, minIndentSize, skipFirstLine)
    53  
    54  	return strings.Join(lines, "\n")
    55  }
    56  
    57  // getMinIndent calculates the minimum indentation in lines, excluding empty lines.
    58  func getMinIndent(lines []string, skipFirstLine bool) int {
    59  	minIndentSize := maxInt
    60  
    61  	for i, line := range lines {
    62  		if i == 0 && skipFirstLine {
    63  			continue
    64  		}
    65  
    66  		indentSize := 0
    67  		for _, r := range []rune(line) {
    68  			if unicode.IsSpace(r) {
    69  				indentSize += 1
    70  			} else {
    71  				break
    72  			}
    73  		}
    74  
    75  		if len(line) == indentSize {
    76  			if i == len(lines)-1 && indentSize < minIndentSize {
    77  				lines[i] = ""
    78  			}
    79  		} else if indentSize < minIndentSize {
    80  			minIndentSize = indentSize
    81  		}
    82  	}
    83  	return minIndentSize
    84  }
    85  
    86  // removeIndentation removes n characters from the front of each line in lines.
    87  // Skips first line if skipFirstLine is true, skips empty lines.
    88  func removeIndentation(lines []string, n int, skipFirstLine bool) []string {
    89  	for i, line := range lines {
    90  		if i == 0 && skipFirstLine {
    91  			continue
    92  		}
    93  
    94  		if len(lines[i]) >= n {
    95  			lines[i] = line[n:]
    96  		}
    97  	}
    98  	return lines
    99  }
   100  
   101  // Docf returns unindented and formatted string as here-document.
   102  // Formatting is done as for fmt.Printf().
   103  func Docf(raw string, args ...interface{}) string {
   104  	return fmt.Sprintf(Doc(raw), args...)
   105  }
   106  

View as plain text