From b6ab19e92cd6903ba157481e7b8c17580a8f8d1d Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Tue, 25 May 2021 00:43:35 +0200 Subject: [PATCH 1/2] Use pager for docs and make pagers more configurable --- cmd/config.go | 50 +++++++++++++++-------------- cmd/diffcmd.go | 5 +-- cmd/docscmd.go | 9 +++++- completions/chezmoi-completion.bash | 8 +++++ docs/REFERENCE.md | 12 ++++++- 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/cmd/config.go b/cmd/config.go index 1a5133b7552..1be4d457f3f 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -58,6 +58,7 @@ type Config struct { Data map[string]interface{} `mapstructure:"data"` Template templateConfig `mapstructure:"template"` UseBuiltinGit *autoBool `mapstructure:"useBuiltinGit"` + Pager string `mapstructure:"pager"` // Global configuration, not settable in the config file. cpuProfile chezmoi.AbsPath @@ -96,6 +97,7 @@ type Config struct { Add addCmdConfig `mapstructure:"add"` CD cdCmdConfig `mapstructure:"cd"` Diff diffCmdConfig `mapstructure:"diff"` + Docs docsCmdConfig `mapstructure:"docs"` Edit editCmdConfig `mapstructure:"edit"` Git gitCmdConfig `mapstructure:"git"` Merge mergeCmdConfig `mapstructure:"merge"` @@ -200,6 +202,7 @@ func newConfig(options ...configOption) (*Config, error) { fileSystem: vfs.OSFS, homeDir: userHomeDir, Umask: chezmoi.Umask, + Pager: os.Getenv("PAGER"), Add: addCmdConfig{ exclude: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesNone), include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesAll), @@ -207,7 +210,6 @@ func newConfig(options ...configOption) (*Config, error) { }, Diff: diffCmdConfig{ Exclude: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesNone), - Pager: os.Getenv("PAGER"), include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesAll), }, Edit: editCmdConfig{ @@ -753,29 +755,7 @@ func (c *Config) diffFile(path chezmoi.RelPath, fromData []byte, fromMode fs.Fil if err := unifiedEncoder.Encode(diffPatch); err != nil { return err } - return c.diffPager(sb.String()) -} - -func (c *Config) diffPager(output string) error { - if c.noPager || c.Diff.Pager == "" { - return c.writeOutputString(output) - } - - // If the pager command contains any spaces, assume that it is a full - // shell command to be executed via the user's shell. Otherwise, execute - // it directly. - var pagerCmd *exec.Cmd - if strings.IndexFunc(c.Diff.Pager, unicode.IsSpace) != -1 { - shell, _ := shell.CurrentUserShell() - pagerCmd = exec.Command(shell, "-c", c.Diff.Pager) - } else { - //nolint:gosec - pagerCmd = exec.Command(c.Diff.Pager) - } - pagerCmd.Stdin = bytes.NewBufferString(output) - pagerCmd.Stdout = c.stdout - pagerCmd.Stderr = c.stderr - return pagerCmd.Run() + return c.pageOutputString(sb.String(), c.Diff.Pager) } func (c *Config) doPurge(purgeOptions *purgeOptions) error { @@ -1099,6 +1079,28 @@ func (c *Config) persistentPostRunRootE(cmd *cobra.Command, args []string) error return nil } +func (c *Config) pageOutputString(output, cmdPager string) error { + pager := firstNonEmptyString(cmdPager, c.Pager) + if c.noPager || pager == "" { + return c.writeOutputString(output) + } + + // If the pager command contains any spaces, assume that it is a full + // shell command to be executed via the user's shell. Otherwise, execute + // it directly. + var pagerCmd *exec.Cmd + if strings.IndexFunc(pager, unicode.IsSpace) != -1 { + shell, _ := shell.CurrentUserShell() + pagerCmd = exec.Command(shell, "-c", pager) + } else { + pagerCmd = exec.Command(pager) + } + pagerCmd.Stdin = bytes.NewBufferString(output) + pagerCmd.Stdout = c.stdout + pagerCmd.Stderr = c.stderr + return pagerCmd.Run() +} + func (c *Config) persistentPreRunRootE(cmd *cobra.Command, args []string) error { if c.cpuProfile != "" { f, err := os.Create(string(c.cpuProfile)) diff --git a/cmd/diffcmd.go b/cmd/diffcmd.go index 7f0ece0bd5d..fc8210845cf 100644 --- a/cmd/diffcmd.go +++ b/cmd/diffcmd.go @@ -10,9 +10,9 @@ import ( type diffCmdConfig struct { Exclude *chezmoi.EntryTypeSet `mapstructure:"exclude"` + Pager string `mapstructure:"pager"` include *chezmoi.EntryTypeSet recursive bool - Pager string `mapstructure:"pager"` } func (c *Config) newDiffCmd() *cobra.Command { @@ -31,6 +31,7 @@ func (c *Config) newDiffCmd() *cobra.Command { flags.VarP(c.Diff.Exclude, "exclude", "x", "exclude entry types") flags.VarP(c.Diff.include, "include", "i", "include entry types") flags.BoolVarP(&c.Diff.recursive, "recursive", "r", c.Diff.recursive, "recursive") + flags.StringVar(&c.Diff.Pager, "pager", c.Diff.Pager, "pager") return diffCmd } @@ -50,5 +51,5 @@ func (c *Config) runDiffCmd(cmd *cobra.Command, args []string) error { }); err != nil { return err } - return c.diffPager(sb.String()) + return c.pageOutputString(sb.String(), c.Diff.Pager) } diff --git a/cmd/docscmd.go b/cmd/docscmd.go index d4945dad546..be67d4c2f4c 100644 --- a/cmd/docscmd.go +++ b/cmd/docscmd.go @@ -14,6 +14,10 @@ import ( "github.com/twpayne/chezmoi/v2/docs" ) +type docsCmdConfig struct { + Pager string `mapstructure:"pager"` +} + func (c *Config) newDocsCmd() *cobra.Command { docsCmd := &cobra.Command{ Use: "docs [regexp]", @@ -27,6 +31,9 @@ func (c *Config) newDocsCmd() *cobra.Command { }, } + flags := docsCmd.Flags() + flags.StringVar(&c.Docs.Pager, "pager", c.Docs.Pager, "pager") + return docsCmd } @@ -96,5 +103,5 @@ func (c *Config) runDocsCmd(cmd *cobra.Command, args []string) error { return err } - return c.writeOutput(renderedData) + return c.pageOutputString(string(renderedData), c.Docs.Pager) } diff --git a/completions/chezmoi-completion.bash b/completions/chezmoi-completion.bash index 5880e2d9e66..36718f57449 100644 --- a/completions/chezmoi-completion.bash +++ b/completions/chezmoi-completion.bash @@ -1080,6 +1080,10 @@ _chezmoi_diff() local_nonpersistent_flags+=("--include") local_nonpersistent_flags+=("--include=") local_nonpersistent_flags+=("-i") + flags+=("--pager=") + two_word_flags+=("--pager") + local_nonpersistent_flags+=("--pager") + local_nonpersistent_flags+=("--pager=") flags+=("--recursive") flags+=("-r") local_nonpersistent_flags+=("--recursive") @@ -1152,6 +1156,10 @@ _chezmoi_docs() flags_with_completion=() flags_completion=() + flags+=("--pager=") + two_word_flags+=("--pager") + local_nonpersistent_flags+=("--pager") + local_nonpersistent_flags+=("--pager=") flags+=("--color=") two_word_flags+=("--color") flags+=("--config=") diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index 84875ff58dc..4945f88342a 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -271,6 +271,7 @@ The following configuration variables are available: | | `format` | string | `json` | Format for data output, either `json` or `yaml` | | | `remove` | bool | `false` | Remove targets | | | `sourceDir` | string | `~/.local/share/chezmoi` | Source directory | +| | `pager` | string | `$PAGER` | Default pager | | | `umask` | int | *from system* | Umask | | | `useBuiltinGit` | string | `auto` | Use builtin git if `git` command is not found in $PATH | | `add` | `templateSymlinks` | bool | `false` | Template symlinks to source and home dirs | @@ -287,7 +288,8 @@ The following configuration variables are available: | `cd` | `args` | []string | *none* | Extra args to shell in `cd` command | | | `command` | string | *none* | Shell to run in `cd` command | | `diff` | `exclude` | []string | *none* | Entry types to exclude from diff | -| | `pager` | string | `$PAGER` / `less` | Pager | +| | `pager` | string | *none* | Diff-specific pager | +| `docs` | `pager` | string | *none* | Docs-specific pager | | `edit` | `args` | []string | *none* | Extra args to edit command | | | `command` | string | `$EDITOR` / `$VISUAL` | Edit command | | `secret` | `command` | string | *none* | Generic secret command | @@ -775,6 +777,10 @@ Print the difference between the target state and the destination state for If a `diff.pager` command is set in the configuration file then the output will be piped into it. +#### `--pager` *pager* + +Pager to use for output. + #### `diff` examples ```console @@ -787,6 +793,10 @@ $ chezmoi diff ~/.bashrc Print the documentation page matching the regular expression *regexp*. Matching is case insensitive. If no pattern is given, print `REFERENCE.md`. +#### `--pager` *pager* + +Pager to use for output. + #### `docs` examples ```console From 56b36666b6f043c28b7365e20b66772bb8674561 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Tue, 25 May 2021 00:51:07 +0200 Subject: [PATCH 2/2] Add maximum width to docs output --- cmd/config.go | 3 +++ cmd/docscmd.go | 7 ++++++- completions/chezmoi-completion.bash | 4 ++++ docs/REFERENCE.md | 3 ++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cmd/config.go b/cmd/config.go index 1be4d457f3f..362131183bc 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -212,6 +212,9 @@ func newConfig(options ...configOption) (*Config, error) { Exclude: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesNone), include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesAll), }, + Docs: docsCmdConfig{ + MaxWidth: 80, + }, Edit: editCmdConfig{ exclude: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesNone), include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypeDirs | chezmoi.EntryTypeFiles | chezmoi.EntryTypeSymlinks | chezmoi.EntryTypeEncrypted), diff --git a/cmd/docscmd.go b/cmd/docscmd.go index be67d4c2f4c..c4a9186fb15 100644 --- a/cmd/docscmd.go +++ b/cmd/docscmd.go @@ -15,7 +15,8 @@ import ( ) type docsCmdConfig struct { - Pager string `mapstructure:"pager"` + MaxWidth int `mapstructure:"maxWidth"` + Pager string `mapstructure:"pager"` } func (c *Config) newDocsCmd() *cobra.Command { @@ -32,6 +33,7 @@ func (c *Config) newDocsCmd() *cobra.Command { } flags := docsCmd.Flags() + flags.IntVar(&c.Docs.MaxWidth, "max-width", c.Docs.MaxWidth, "maximum output width") flags.StringVar(&c.Docs.Pager, "pager", c.Docs.Pager, "pager") return docsCmd @@ -89,6 +91,9 @@ func (c *Config) runDocsCmd(cmd *cobra.Command, args []string) error { return err } } + if c.Docs.MaxWidth != 0 && width > c.Docs.MaxWidth { + width = c.Docs.MaxWidth + } tr, err := glamour.NewTermRenderer( glamour.WithStyles(glamour.ASCIIStyleConfig), diff --git a/completions/chezmoi-completion.bash b/completions/chezmoi-completion.bash index 36718f57449..bdb287b67e3 100644 --- a/completions/chezmoi-completion.bash +++ b/completions/chezmoi-completion.bash @@ -1156,6 +1156,10 @@ _chezmoi_docs() flags_with_completion=() flags_completion=() + flags+=("--max-width=") + two_word_flags+=("--max-width") + local_nonpersistent_flags+=("--max-width") + local_nonpersistent_flags+=("--max-width=") flags+=("--pager=") two_word_flags+=("--pager") local_nonpersistent_flags+=("--pager") diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index 4945f88342a..3912bd67a88 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -289,7 +289,8 @@ The following configuration variables are available: | | `command` | string | *none* | Shell to run in `cd` command | | `diff` | `exclude` | []string | *none* | Entry types to exclude from diff | | | `pager` | string | *none* | Diff-specific pager | -| `docs` | `pager` | string | *none* | Docs-specific pager | +| `docs` | `maxWidth` | int | 80 | Maximum width of output | +| | `pager` | string | *none* | Docs-specific pager | | `edit` | `args` | []string | *none* | Extra args to edit command | | | `command` | string | `$EDITOR` / `$VISUAL` | Edit command | | `secret` | `command` | string | *none* | Generic secret command |