diff options
Diffstat (limited to 'cmd/fscrypt/format.go')
| -rw-r--r-- | cmd/fscrypt/format.go | 98 |
1 files changed, 57 insertions, 41 deletions
diff --git a/cmd/fscrypt/format.go b/cmd/fscrypt/format.go index ef009d3..21253ad 100644 --- a/cmd/fscrypt/format.go +++ b/cmd/fscrypt/format.go @@ -25,12 +25,11 @@ import ( "bytes" "fmt" "os" - "regexp" "strings" "unicode/utf8" "github.com/urfave/cli" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" "github.com/google/fscrypt/util" ) @@ -65,8 +64,8 @@ func init() { flagPaddingLength = maxShortDisplay + 2*indentLength // We use the width of the terminal unless we cannot get the width. - width, _, err := terminal.GetSize(int(os.Stdout.Fd())) - if err != nil { + width, _, err := term.GetSize(int(os.Stdout.Fd())) + if err != nil || width <= 0 { lineLength = fallbackLineLength } else { lineLength = util.MinInt(width, maxLineLength) @@ -74,7 +73,7 @@ func init() { } -// Flags that conform to this interface can be used with an urfave/cli +// Flags that conform to this interface can be used with a urfave/cli // application and can be printed in the correct format. type prettyFlag interface { cli.Flag @@ -83,8 +82,10 @@ type prettyFlag interface { } // How a flag should appear on the command line. We have two formats: -// --name -// --name=ARG_NAME +// +// --name +// --name=ARG_NAME +// // The ARG_NAME appears if the prettyFlag's GetArgName() method returns a // non-empty string. The returned string from shortDisplay() does not include // any leading or trailing whitespace. @@ -97,22 +98,20 @@ func shortDisplay(f prettyFlag) string { // How our flags should appear when displaying their usage. An example would be: // -// --help Prints help screen for commands and subcommands. -// -// If a default is specified, this if appended to the usage. Example: +// --help Prints help screen for commands and subcommands. // -// --legacy Allow for support of older kernels with ext4 -// (before v4.8) and F2FS (before v4.6) filesystems. -// (default: true) +// If a default is specified, then it is appended to the usage. Example: // +// --time=TIME Calibrate passphrase hashing to take the +// specified amount of TIME (default: 1s) func longDisplay(f prettyFlag, defaultString ...string) string { usage := f.GetUsage() if len(defaultString) > 0 { usage += fmt.Sprintf(" (default: %v)", defaultString[0]) } - // We pad the the shortDisplay on the right with enough spaces to equal - // the longest flag's display + // We pad the shortDisplay on the right with enough spaces to equal the + // longest flag's display shortDisp := shortDisplay(f) length := utf8.RuneCountInString(shortDisp) shortDisp += strings.Repeat(" ", maxShortDisplay-length) @@ -120,41 +119,58 @@ func longDisplay(f prettyFlag, defaultString ...string) string { return indent + shortDisp + indent + wrapText(usage, flagPaddingLength) } -// Regex that determines if we are starting an ordered list -var listRegex = regexp.MustCompile(`^\([\d]+\)$`) - // Takes an input string text, and wraps the text so that each line begins with // padding spaces (except for the first line), ends with a newline (except the // last line), and each line has length less than lineLength. If the text -// contains a word which is too long, that word gets its own line. +// contains a word which is too long, that word gets its own line. Paragraphs +// and "code blocks" are preserved. func wrapText(text string, padding int) string { // We use a buffer to format the wrapped text so we get O(n) runtime var buffer bytes.Buffer - spaceLeft := 0 - maxTextLen := lineLength - padding + filled := 0 delimiter := strings.Repeat(" ", padding) - for i, word := range strings.Fields(text) { - wordLen := utf8.RuneCountInString(word) - switch { - case i == 0: - // No delimiter for the first line - buffer.WriteString(word) - spaceLeft = maxTextLen - wordLen - case listRegex.Match([]byte(word)): - // Add an additional line to separate list items. - buffer.WriteString("\n") - fallthrough - case wordLen+1 > spaceLeft: - // If no room left, write the word on the next line. + + for _, line := range strings.Split(text, "\n") { + words := strings.Fields(line) + + // Preserve empty lines (paragraph separators). + if len(words) == 0 { + if filled != 0 { + buffer.WriteString("\n") + } buffer.WriteString("\n") - buffer.WriteString(delimiter) - buffer.WriteString(word) - spaceLeft = maxTextLen - wordLen - default: - // Write word on this line - buffer.WriteByte(' ') + filled = 0 + continue + } + + codeBlock := (words[0] == ">") + if codeBlock { + words[0] = " " + if filled != 0 { + buffer.WriteString("\n") + filled = 0 + } + } + for _, word := range words { + wordLen := utf8.RuneCountInString(word) + // Write a newline if needed. + if filled != 0 && filled+1+wordLen > lineLength && !codeBlock { + buffer.WriteString("\n") + filled = 0 + } + // Write a delimiter or space if needed. + if filled == 0 { + if buffer.Len() != 0 { + buffer.WriteString(delimiter) + } + filled += padding + } else { + buffer.WriteByte(' ') + filled++ + } + // Write the word. buffer.WriteString(word) - spaceLeft -= 1 + wordLen + filled += wordLen } } |