commit 71a27cf6a0348f2c7b29c4cc9689458d891326c5
parent 04f49dbb2e48823cd56d657e646ed04d2706d11f
Author: Sean Enck <sean@ttypty.com>
Date: Sun, 3 Sep 2023 16:50:22 -0400
split detail and wordwrap externally
Diffstat:
16 files changed, 123 insertions(+), 80 deletions(-)
diff --git a/go.mod b/go.mod
@@ -5,6 +5,7 @@ go 1.19
require (
github.com/aymanbagabas/go-osc52 v1.2.2
github.com/hashicorp/go-envparse v0.1.0
+ github.com/muesli/reflow v0.3.0
github.com/pquerna/otp v1.4.0
github.com/tobischo/gokeepasslib/v3 v3.5.1
mvdan.cc/sh/v3 v3.7.0
@@ -14,6 +15,8 @@ require (
github.com/aead/argon2 v0.0.0-20180111183520-a87724528b07 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/boombuler/barcode v1.0.1 // indirect
+ github.com/mattn/go-runewidth v0.0.12 // indirect
+ github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/sys v0.11.0 // indirect
)
diff --git a/go.sum b/go.sum
@@ -15,10 +15,17 @@ github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdm
github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
diff --git a/internal/app/completions.go b/internal/app/completions.go
@@ -161,17 +161,17 @@ export %s=<unknown>
CompletionEnv: fmt.Sprintf("$%s", config.EnvironmentCompletionKey),
}
- using, err := readDoc("zsh")
+ using, err := readDoc("zsh.sh")
if err != nil {
return nil, err
}
if isBash {
- using, err = readDoc("bash")
+ using, err = readDoc("bash.sh")
if err != nil {
return nil, err
}
}
- shellScript, err := readDoc("shell")
+ shellScript, err := readDoc("shell.sh")
if err != nil {
return nil, err
}
diff --git a/internal/app/core.go b/internal/app/core.go
@@ -4,6 +4,7 @@ package app
import (
"bytes"
"embed"
+ "errors"
"fmt"
"io"
"os"
@@ -15,6 +16,7 @@ import (
"github.com/enckse/lockbox/internal/backend"
"github.com/enckse/lockbox/internal/config"
"github.com/enckse/lockbox/internal/platform"
+ "github.com/muesli/reflow/wordwrap"
)
const (
@@ -71,6 +73,8 @@ const (
JSONCommand = "json"
// ZshCommand is the command to generate zsh completions
ZshCommand = "zsh"
+ docDir = "doc"
+ textFile = ".txt"
)
//go:embed doc/*
@@ -207,14 +211,6 @@ func Usage(verbose bool, exe string) ([]string, error) {
usage := []string{fmt.Sprintf("%s usage:", exe)}
if verbose {
results = append(results, "")
- doc, err := readDoc("details")
- if err != nil {
- return nil, err
- }
- t, err := template.New("d").Parse(doc)
- if err != nil {
- return nil, err
- }
document := Documentation{
Executable: filepath.Base(exe),
MoveCommand: MoveCommand,
@@ -226,10 +222,32 @@ func Usage(verbose bool, exe string) ([]string, error) {
document.ReKey.Key = setDocFlag(config.ReKeyKeyFlag)
document.ReKey.KeyMode = setDocFlag(config.ReKeyKeyModeFlag)
document.ReKey.KeyFile = setDocFlag(config.ReKeyKeyModeFlag)
- var buf bytes.Buffer
- if err := t.Execute(&buf, document); err != nil {
+ files, err := docs.ReadDir(docDir)
+ if err != nil {
return nil, err
}
+ var buf bytes.Buffer
+ var env string
+ for _, f := range files {
+ n := f.Name()
+ if !strings.HasSuffix(n, textFile) {
+ continue
+ }
+ header := fmt.Sprintf("[%s]", strings.TrimSuffix(filepath.Base(n), textFile))
+ s, err := processDoc(header, n, document)
+ if err != nil {
+ return nil, err
+ }
+ if header == "[environment]" {
+ env = s
+ } else {
+ buf.WriteString(s)
+ }
+ }
+ if env == "" {
+ return nil, errors.New("no environment header configured")
+ }
+ buf.WriteString(env)
results = append(results, strings.Split(strings.TrimSpace(buf.String()), "\n")...)
results = append(results, "")
results = append(results, config.ListEnvironmentVariables()...)
@@ -237,12 +255,49 @@ func Usage(verbose bool, exe string) ([]string, error) {
return append(usage, results...), nil
}
+func processDoc(header, file string, doc Documentation) (string, error) {
+ b, err := readDoc(file)
+ if err != nil {
+ return "", err
+ }
+ t, err := template.New("d").Parse(string(b))
+ if err != nil {
+ return "", err
+ }
+ var buf bytes.Buffer
+ if err := t.Execute(&buf, doc); err != nil {
+ return "", err
+ }
+ var sections []string
+ var cur []string
+ for _, line := range strings.Split(strings.TrimSpace(buf.String()), "\n") {
+ trimmed := strings.TrimSpace(line)
+ if trimmed == "" {
+ if len(cur) > 0 {
+ sections = append(sections, strings.Join(cur, " "))
+ cur = []string{}
+ }
+ continue
+ }
+ cur = append(cur, line)
+ }
+ if len(cur) > 0 {
+ sections = append(sections, strings.Join(cur, " "))
+ }
+ var out bytes.Buffer
+ fmt.Fprintf(&out, "%s\n", header)
+ for _, s := range sections {
+ fmt.Fprintf(&out, "%s\n\n", wordwrap.String(s, 80))
+ }
+ return out.String(), nil
+}
+
func setDocFlag(f string) string {
return fmt.Sprintf("-%s=", f)
}
func readDoc(doc string) (string, error) {
- b, err := docs.ReadFile(filepath.Join("doc", doc))
+ b, err := docs.ReadFile(filepath.Join(docDir, doc))
if err != nil {
return "", err
}
diff --git a/internal/app/core_test.go b/internal/app/core_test.go
@@ -1,7 +1,6 @@
package app_test
import (
- "strings"
"testing"
"github.com/enckse/lockbox/internal/app"
@@ -13,14 +12,7 @@ func TestUsage(t *testing.T) {
t.Errorf("invalid usage, out of date? %d", len(u))
}
u, _ = app.Usage(true, "lb")
- if len(u) != 109 {
+ if len(u) != 108 {
t.Errorf("invalid verbose usage, out of date? %d", len(u))
}
- for _, usage := range u {
- for _, l := range strings.Split(usage, "\n") {
- if len(l) > 79 {
- t.Errorf("usage line > 79 (%d), line: %s", len(l), l)
- }
- }
- }
}
diff --git a/internal/app/doc/bash b/internal/app/doc/bash.sh
diff --git a/internal/app/doc/clipboard.txt b/internal/app/doc/clipboard.txt
@@ -0,0 +1,3 @@
+By default clipboard commands are detected via determing the platform and
+utilizing default commands to interact with (copy to/paste to) the clipboard.
+These settings can be overriden via environment variables.
diff --git a/internal/app/doc/completions.txt b/internal/app/doc/completions.txt
@@ -0,0 +1,5 @@
+Completions are available for certain shells and, by default, assume all
+features of `{{ $.Executable }}` are enabled and available. When changing certain environment
+flags it may be useful to change the completion profile to more closely match
+the restricted command options, run `{{ $.Executable }} <shell> {{ $.ShellHelpCommand }}` for information
+on how best to alter completion outputs.
diff --git a/internal/app/doc/database.txt b/internal/app/doc/database.txt
@@ -0,0 +1,8 @@
+While '{{ $.Executable }}' uses a kdbx file (version 4), it is opinionated about how to store
+data within the file. This means '{{ $.Executable }}' should be the only way a user normally
+interacts with or changes the underlying database. However as the file is a
+normal kdbx file format (e.g. can be opened in tools supporting the format) it
+is possible to use the database in those applications, just take caution when
+changing it outside of '{{ $.Executable }}' usage. If a database not normally used by '{{ $.Executable }}' is
+to be used by '{{ $.Executable }}', try using the various readonly settings to control
+interactions.
diff --git a/internal/app/doc/details b/internal/app/doc/details
@@ -1,57 +0,0 @@
-[database]
-While '{{ $.Executable }}' uses a kdbx file (version 4), it is opinionated about how to store
-data within the file. This means '{{ $.Executable }}' should be the only way a user normally
-interacts with or changes the underlying database. However as the file is a
-normal kdbx file format (e.g. can be opened in tools supporting the format) it
-is possible to use the database in those applications, just take caution when
-changing it outside of '{{ $.Executable }}' usage. If a database not normally used by '{{ $.Executable }}' is
-to be used by '{{ $.Executable }}', try using the various readonly settings to control
-interactions.
-
-[globs]
-The '{{ $.RemoveCommand }}' and '{{ $.MoveCommand }}' command can handle a simplistic glob if it is at the END
-of the path. This allows for bulk-removal of entries at multiple levels.
-Confirmation will still be required for removal (matching entries will be
-listed).
-
-For '{{ $.MoveCommand }}' the destination must NOT be an entry but the final destination
-location for all matched entries. Overwriting is not allowed by moving
-via glob and moving via globs can ONLY be done via leaf level globs.
-
-Examples:
-
-{{ $.Executable }} {{ $.RemoveCommand }} path/to/leaf/dir/*
-
-{{ $.Executable }} {{ $.RemoveCommand }} path/to/*
-
-{{ $.Executable }} {{ $.MoveCommand }} path/to/* new/path/
-
-[clipboard]
-By default clipboard commands are detected via determing the platform and
-utilizing default commands to interact with (copy to/paste to) the clipboard.
-These settings can be overriden via environment variables.
-
-[totp]
-By default '{{ $.Executable }}' tries to use some reasonable defaults to setup/manage oauth
-token inputs and displaying of code outputs. Many of these settings can be
-changed via environment variables.
-
-[rekey]
-The password store can have the key (and file) changed via the '{{ $.ReKeyCommand }}'
-subcommand. This command requires a '{{ $.ReKey.Store }}' value and some combination
-of '{{ $.ReKey.Key }}', '{{ $.ReKey.KeyMode }}', and '{{ $.ReKey.KeyFile }}' depending on the new database
-credential preferences. The settings correspond to the 'LOCKBOX_'
-settings normally used when running `{{ $.Executable }}`.
-
-Note that is an advanced feature and should be used with caution/backups/etc.
-
-[completions]
-Completions are available for certain shells and, by default, assume all
-features of `{{ $.Executable }}` are enabled and available. When changing certain environment
-flags it may be useful to change the completion profile to more closely match
-the restricted command options, run `{{ $.Executable }} <shell> {{ $.ShellHelpCommand }}` for information
-on how best to alter completion outputs.
-
-[environment variables]
-
-The following environment variables can alter how '{{ $.Executable }}' works.
diff --git a/internal/app/doc/environment.txt b/internal/app/doc/environment.txt
@@ -0,0 +1 @@
+The following environment variables can alter how '{{ $.Executable }}' works.
diff --git a/internal/app/doc/globs.txt b/internal/app/doc/globs.txt
@@ -0,0 +1,16 @@
+The '{{ $.RemoveCommand }}' and '{{ $.MoveCommand }}' command can handle a simplistic glob if it is at the END
+of the path. This allows for bulk-removal of entries at multiple levels.
+Confirmation will still be required for removal (matching entries will be
+listed).
+
+For '{{ $.MoveCommand }}' the destination must NOT be an entry but the final destination
+location for all matched entries. Overwriting is not allowed by moving
+via glob and moving via globs can ONLY be done via leaf level globs.
+
+Examples:
+
+{{ $.Executable }} {{ $.RemoveCommand }} path/to/leaf/dir/*
+
+{{ $.Executable }} {{ $.RemoveCommand }} path/to/*
+
+{{ $.Executable }} {{ $.MoveCommand }} path/to/* new/path/
diff --git a/internal/app/doc/rekey.txt b/internal/app/doc/rekey.txt
@@ -0,0 +1,7 @@
+The password store can have the key (and file) changed via the '{{ $.ReKeyCommand }}'
+subcommand. This command requires that '{{ $.ReKey.Store }}' is set and
+a combination of new key settings are configured via '{{ $.ReKey.Key }}', '{{ $.ReKey.KeyMode }}', and '{{ $.ReKey.KeyFile }}' depending on the new database
+credential preferences. The settings correspond to the 'LOCKBOX_'
+settings normally used when running `{{ $.Executable }}`.
+
+Note that is an advanced feature and should be used with caution/backups/etc.
diff --git a/internal/app/doc/shell b/internal/app/doc/shell.sh
diff --git a/internal/app/doc/totp.txt b/internal/app/doc/totp.txt
@@ -0,0 +1,3 @@
+By default '{{ $.Executable }}' tries to use some reasonable defaults to setup/manage oauth
+token inputs and displaying of code outputs. Many of these settings can be
+changed via environment variables.
diff --git a/internal/app/doc/zsh b/internal/app/doc/zsh.sh