git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Felipe Contreras <felipe.contreras@gmail.com>
To: git@vger.kernel.org
Cc: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
	"Jeff King" <peff@peff.net>, "Junio C Hamano" <gitster@pobox.com>,
	"Felipe Contreras" <felipe.contreras@gmail.com>
Subject: [PATCH v8] help: add option to colorize man pages under less
Date: Fri, 25 Jun 2021 21:50:40 -0500	[thread overview]
Message-ID: <20210626025040.104428-1-felipe.contreras@gmail.com> (raw)
In-Reply-To: <20210523054454.1188757-1-felipe.contreras@gmail.com>

We already colorize tools traditionally not colorized by default--like
diff and grep. Let's do the same for man, but only if `color.man` is
explicitly set to "true".

Unlike other `color.*` output, this colorization is not enabled when
`color.ui` is true; the user needs to explicitly set the
`color.man` variable to `true.

When it was proposed to treat `color.man` like any other `color.*`
variable, some thought that git opting to add color for an external
program such as man(1) was a step too far [1]--even if the user invoked
it via the "git help <topic>" wrapper. So let's make this explicitly
opt-in for now.

As noted in the documentation we're leaving ourselves an out to turn
this on by default in the future, for example putting it under the
feature.experimental umbrella. We probably won't, but let's not promise
users that `color.man` will forever be a special-case.

As for what this actually does, the effect of having this enabled is
that a documentation blurb like (some parts elided with "[...]"):

	NAME
	----
	git-config - Get and set [...]

	SYNOPSIS
	--------
	[...]
	'git config' [<file-option>] [...]
	[...]
	The `--type=<type>` option instructs 'git config' to ensure [...]

Will have "NAME" and "SYNOPSIS" shown as RED BOLD instead of BOLD,
"git config" and other '-quoted parts in BLUE UNDERLINE instead of
UNDERLINE, and `--type=<type>` and other `-quoted parts in RED BOLD
instead of BOLD. The "standout" setting is then used for the user's
own search bar (invoked with "/") and prompt. See [2] for more
examples

Normally check_auto_color() would check the value of `color.pager`, but
in this particular case it's not git the one executing the pager, but
man. Therefore we need to check pager_use_color ourselves.

We do not need to support `color.man` being set to `always`; the `git
help` command is always run for a tty (it would be very strange for a
user to do `git help $page > output`, but in fact, that works anyway,
we don't even need to check if stdout is a tty, but just to be
consistent we do). So it's simply a boolean in our case.

So, in order for this change to have any effect:

 1. color.man=true must be set in the config
 2. The user must use less
 3. Not have the same LESS_TERMCAP variables set (we call setenv(3) with overwrite=0)
 4. Not have color.pager disabled
 5. Not have git with stdout directed to a file

1. https://lore.kernel.org/git/87tun1qp91.fsf@evledraar.gmail.com/
2. https://unix.stackexchange.com/questions/119/colors-in-man-pages/147

Suggested-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---

This a reroll of Ævar's v7 with comments from Jeff King so that
color.ui=never doesn't disable color.man, and the documentation was
updated accordingly.

Additinally I removed one call to colorize_man() in exec_man_cmd() which
is not meant for the man command (although it could be used for that).

Plus a bunch of style changes to the commit message.

Range-diff against v7:
1:  167f5c8b39 ! 1:  1b3f7ee1aa help: colorize man pages if man.color=true under less(1)
    @@ Metadata
     Author: Felipe Contreras <felipe.contreras@gmail.com>
     
      ## Commit message ##
    -    help: colorize man pages if man.color=true under less(1)
    +    help: add option to colorize man pages under less
     
    -    We already colorize tools traditionally not colorized by default, like
    +    We already colorize tools traditionally not colorized by default--like
         diff and grep. Let's do the same for man, but only if `color.man` is
         explicitly set to "true".
     
    -    Unlike other `color.*` output this colorization is not enabled by
    -    `color.ui` being true, the user needs to explicitly set the
    +    Unlike other `color.*` output, this colorization is not enabled when
    +    `color.ui` is true; the user needs to explicitly set the
         `color.man` variable to `true.
     
         When it was proposed to treat `color.man` like any other `color.*`
    -    variable some thought that git opting in coloring for an external
    -    program such as man(1) was a step too far[1], even if the user invoked
    -    it via the "git help <topic>" wrapper.
    +    variable, some thought that git opting to add color for an external
    +    program such as man(1) was a step too far [1]--even if the user invoked
    +    it via the "git help <topic>" wrapper. So let's make this explicitly
    +    opt-in for now.
     
    -    So let's make this explicitly opt-in for now. As noted in the
    -    documentation we're leaving ourselves an out to turn this on by
    -    default in the future, or e.g. putting it under the
    -    feature.experimental umbrella. We probably won't, but let's not
    -    promise users that `color.man` will forever be a special-case.
    +    As noted in the documentation we're leaving ourselves an out to turn
    +    this on by default in the future, for example putting it under the
    +    feature.experimental umbrella. We probably won't, but let's not promise
    +    users that `color.man` will forever be a special-case.
     
    -    As for what this actually does the effect of having this enabled is
    +    As for what this actually does, the effect of having this enabled is
         that a documentation blurb like (some parts elided with "[...]"):
     
                 NAME
    @@ Commit message
                 [...]
                 The `--type=<type>` option instructs 'git config' to ensure [...]
     
    -    Will have "NAME" and "SECTION" shown as BOLD RED instead of BOLD, "git
    -    config" and other '-quoted parts in BLUE UNDERLINE instead of
    +    Will have "NAME" and "SYNOPSIS" shown as RED BOLD instead of BOLD,
    +    "git config" and other '-quoted parts in BLUE UNDERLINE instead of
         UNDERLINE, and `--type=<type>` and other `-quoted parts in RED BOLD
    -    instead of BOLD. The "Standout" setting is then used for the user's
    +    instead of BOLD. The "standout" setting is then used for the user's
         own search bar (invoked with "/") and prompt. See [2] for more
         examples
     
    @@ Commit message
         in this particular case it's not git the one executing the pager, but
         man. Therefore we need to check pager_use_color ourselves.
     
    -    We do not need to support `color.man` being set to `always`; The `git
    +    We do not need to support `color.man` being set to `always`; the `git
         help` command is always run for a tty (it would be very strange for a
         user to do `git help $page > output`, but in fact, that works anyway,
         we don't even need to check if stdout is a tty, but just to be
    @@ Commit message
          1. color.man=true must be set in the config
          2. The user must use less
          3. Not have the same LESS_TERMCAP variables set (we call setenv(3) with overwrite=0)
    -     4. Have color.ui enabled
    -     5. Not have color.pager disabled
    -     6. Not have git with stdout directed to a file
    +     4. Not have color.pager disabled
    +     5. Not have git with stdout directed to a file
     
         1. https://lore.kernel.org/git/87tun1qp91.fsf@evledraar.gmail.com/
         2. https://unix.stackexchange.com/questions/119/colors-in-man-pages/147
     
         Suggested-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
    -    Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
    +    Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
     
      ## Documentation/config/color.txt ##
     @@ Documentation/config/color.txt: color.interactive.<slot>::
    @@ Documentation/config/color.txt: color.interactive.<slot>::
      	interactive commands.
      
     +color.man::
    -+	This flag can be used to enable the automatic colorizaton of man
    ++	This flag can be used to enable the automatic colorization of man
     +	pages when using the less pager, `false` by default. When set to
    -+	`true` it's activated only when `color.ui` allows it, and if
    -+	`color.pager` enable (which it is by default).
    ++	`true` it's activated only if `color.pager` is enabled (which it
    ++	is by default).
     +
      color.pager::
      	A boolean to specify whether `auto` color modes should colorize
    @@ builtin/help.c: static void exec_man_konqueror(const char *path, const char *pag
      
     +static void colorize_man(void)
     +{
    -+	if (!man_color || !want_color(GIT_COLOR_UNKNOWN) || !pager_use_color)
    ++	if (!man_color || !pager_use_color)
     +		return;
     +
     +	/* Disable groff colors */
    @@ builtin/help.c: static void exec_man_konqueror(const char *path, const char *pag
      	execlp(path, "man", page, (char *)NULL);
      	warning_errno(_("failed to exec '%s'"), path);
      }
    -@@ builtin/help.c: static void exec_man_man(const char *path, const char *page)
    - static void exec_man_cmd(const char *cmd, const char *page)
    - {
    - 	struct strbuf shell_cmd = STRBUF_INIT;
    -+	colorize_man();
    - 	strbuf_addf(&shell_cmd, "%s %s", cmd, page);
    - 	execl(SHELL_PATH, SHELL_PATH, "-c", shell_cmd.buf, (char *)NULL);
    - 	warning(_("failed to exec '%s'"), cmd);
     @@ builtin/help.c: static int git_help_config(const char *var, const char *value, void *cb)
      	}
      	if (starts_with(var, "man."))

 Documentation/config/color.txt | 11 +++++++++++
 builtin/help.c                 | 31 ++++++++++++++++++++++++++++++-
 color.h                        |  1 +
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/Documentation/config/color.txt b/Documentation/config/color.txt
index e05d520a86..8511af1f1d 100644
--- a/Documentation/config/color.txt
+++ b/Documentation/config/color.txt
@@ -126,6 +126,12 @@ color.interactive.<slot>::
 	or `error`, for four distinct types of normal output from
 	interactive commands.
 
+color.man::
+	This flag can be used to enable the automatic colorization of man
+	pages when using the less pager, `false` by default. When set to
+	`true` it's activated only if `color.pager` is enabled (which it
+	is by default).
+
 color.pager::
 	A boolean to specify whether `auto` color modes should colorize
 	output going to the pager. Defaults to true; set this to false
@@ -200,3 +206,8 @@ color.ui::
 	output not intended for machine consumption to use color, to
 	`true` or `auto` (this is the default since Git 1.8.4) if you
 	want such output to use color when written to the terminal.
++
+When set to `true` certain other `color.*` variables may still not be
+turned on unless explicitly enabled. Currently this only applies to
+`color.man`, see above. Such opt-in variables may be moved under the
+default `color.ui` umbrella in the future.
diff --git a/builtin/help.c b/builtin/help.c
index bb339f0fc8..150dd05fdb 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -11,6 +11,7 @@
 #include "config-list.h"
 #include "help.h"
 #include "alias.h"
+#include "color.h"
 
 #ifndef DEFAULT_HELP_FORMAT
 #define DEFAULT_HELP_FORMAT "man"
@@ -34,6 +35,7 @@ enum help_format {
 	HELP_FORMAT_WEB
 };
 
+static int man_color;
 static const char *html_path;
 
 static int show_all = 0;
@@ -253,10 +255,33 @@ static void exec_man_konqueror(const char *path, const char *page)
 	}
 }
 
+static void colorize_man(void)
+{
+	if (!man_color || !pager_use_color)
+		return;
+
+	/* Disable groff colors */
+	setenv("GROFF_NO_SGR", "1", 0);
+
+	/* Bold */
+	setenv("LESS_TERMCAP_md", GIT_COLOR_BOLD_RED, 0);
+	setenv("LESS_TERMCAP_me", GIT_COLOR_RESET, 0);
+
+	/* Underline */
+	setenv("LESS_TERMCAP_us", GIT_COLOR_BLUE GIT_COLOR_UNDERLINE, 0);
+	setenv("LESS_TERMCAP_ue", GIT_COLOR_RESET, 0);
+
+	/* Standout */
+	setenv("LESS_TERMCAP_so", GIT_COLOR_CYAN GIT_COLOR_REVERSE, 0);
+	setenv("LESS_TERMCAP_se", GIT_COLOR_RESET, 0);
+}
+
 static void exec_man_man(const char *path, const char *page)
 {
 	if (!path)
 		path = "man";
+
+	colorize_man();
 	execlp(path, "man", page, (char *)NULL);
 	warning_errno(_("failed to exec '%s'"), path);
 }
@@ -371,8 +396,12 @@ static int git_help_config(const char *var, const char *value, void *cb)
 	}
 	if (starts_with(var, "man."))
 		return add_man_viewer_info(var, value);
+	if (!strcmp(var, "color.man")) {
+		man_color = git_config_bool(var, value);
+		return 0;
+	}
 
-	return git_default_config(var, value, cb);
+	return git_color_default_config(var, value, cb);
 }
 
 static struct cmdnames main_cmds, other_cmds;
diff --git a/color.h b/color.h
index 98894d6a17..d012add4e8 100644
--- a/color.h
+++ b/color.h
@@ -51,6 +51,7 @@ struct strbuf;
 #define GIT_COLOR_FAINT		"\033[2m"
 #define GIT_COLOR_FAINT_ITALIC	"\033[2;3m"
 #define GIT_COLOR_REVERSE	"\033[7m"
+#define GIT_COLOR_UNDERLINE	"\033[4m"
 
 /* A special value meaning "no color selected" */
 #define GIT_COLOR_NIL "NIL"
-- 
2.32.0


  parent reply	other threads:[~2021-06-26  2:50 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-23  5:44 [PATCH v6] help: colorize man pages Felipe Contreras
2021-05-24 13:13 ` Phillip Wood
2021-05-24 16:56   ` Felipe Contreras
2021-06-08 12:35 ` Ævar Arnfjörð Bjarmason
2021-06-08 13:57   ` Junio C Hamano
2021-06-08 17:48     ` Felipe Contreras
2021-06-21  8:34     ` [PATCH v7] help: colorize man pages if man.color=true under less(1) Ævar Arnfjörð Bjarmason
2021-06-21 10:17       ` Phillip Wood
2021-06-21 10:28       ` Junio C Hamano
2021-06-21 18:41         ` Felipe Contreras
2021-06-21 19:08         ` Ævar Arnfjörð Bjarmason
2021-06-23 23:58           ` Jeff King
2021-06-24  1:03             ` Felipe Contreras
2021-06-28 17:37             ` Junio C Hamano
2021-06-28 18:05               ` Felipe Contreras
2021-06-21 15:59       ` Felipe Contreras
2021-06-24  0:08       ` Jeff King
2021-06-29  1:42         ` Junio C Hamano
2021-06-29  1:48           ` Felipe Contreras
2021-06-24  1:44 ` [PATCH v6] help: colorize man pages Felipe Contreras
2021-06-26  2:50 ` Felipe Contreras [this message]
2021-06-26 14:49   ` [PATCH v8] help: add option to colorize man pages under less Ævar Arnfjörð Bjarmason

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210626025040.104428-1-felipe.contreras@gmail.com \
    --to=felipe.contreras@gmail.com \
    --cc=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).