From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id DE23E15800F for ; Sun, 19 Feb 2023 16:14:37 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 7B3E5E08EB; Sun, 19 Feb 2023 16:14:36 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 61119E08EB for ; Sun, 19 Feb 2023 16:14:36 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 790AB340EC9 for ; Sun, 19 Feb 2023 16:14:35 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 8BC7B8BC for ; Sun, 19 Feb 2023 16:14:32 +0000 (UTC) From: "Sam James" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Sam James" Message-ID: <1676823259.60775e89a1411c772def465ef9b901b3fe78e450.sam@gentoo> Subject: [gentoo-commits] proj/gentoo-functions:master commit in: / X-VCS-Repository: proj/gentoo-functions X-VCS-Files: functions.sh X-VCS-Directories: / X-VCS-Committer: sam X-VCS-Committer-Name: Sam James X-VCS-Revision: 60775e89a1411c772def465ef9b901b3fe78e450 X-VCS-Branch: master Date: Sun, 19 Feb 2023 16:14:32 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 961092be-0607-4a68-84dd-b3503279596c X-Archives-Hash: c7f6c06187fbbea9c2ba74802235bab6 commit: 60775e89a1411c772def465ef9b901b3fe78e450 Author: Kerin Millar plushkava net> AuthorDate: Sat Feb 18 16:55:17 2023 +0000 Commit: Sam James gentoo org> CommitDate: Sun Feb 19 16:14:19 2023 +0000 URL: https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=60775e89 Simplify ECMA-48 sequence definition and dial back on the use of tput(1) Up until very recently, functions.sh would not attempt to determine whether a given message was being printed to a terminal. Over the years, this has caused some deleterious effects, such as printing ECMA-48 CSI and SGR sequences to file descriptors that are not necessarily attached to a terminal. Another issue used to be that these sequences would be emitted to terminals identifying themselves as "dumb". Rather than tackle the underlying problems, the historical response has tended towards further entrenching the use of the ncurses implementation of tput(1). While it has its uses, the way in which it is employed is in no way portable. POSIX only guarantees the availability of the clear, init and reset operands. Presently, the colors operand is used as a heuristic to determine whether the ncurses implementation is available before proceeding to run a series of commands that will usually output ECMA-48 SGR sequences that are standard for all but ancient and/or obscure video terminals. Another present use of tput(1) is in generating the CUU1 and CUF sequences. In the overwhelming majority of cases, it will generate these as standard ECMA-48 CSI sequences. To put this in perspective, the DEC VT100, a video terminal released almost 45 years ago, supports these sequences. The ECMA-48 specification, itself, is almost as old. Unfortunately, reasoning with such matters tends towards a dichotomy. On the one hand, there is a camp that considers it a cardinal sin to attempt to emit an ANSI escape sequence without first having consulted a specific implementation of tput(1). On the other, there is the camp that points out that ECMA-48 sequences are highly portable and that video terminals from the 1970s and 1980s are largely obsolete. Here are two articles that present opposing points of view. https://mywiki.wooledge.org/BashFAQ/037 https://xn--rpa.cc/irl/term.html Of late, I find the arguments presented by the latter camp to be increasingly convincing. As such, the goal of this commit is twofold. Firstly, to implement an independent method for detecting a dumb terminal. To that end, a _has_dumb_terminal() function has been added, which simply checks the value of TERM. This, alone, determines whether the CUU1 and CUF sequences should be assigned, with tput(1) no longer being used to generate them. Secondly, to further dial back on the use of tput(1) by not using it to generate the SGR (colour) sequences. While I believe that nobody would notice if we were to do away with the use of tput(1) altogether, I have taken a nuanced approach by continuing to use it for detecting the number of available colours. To that end, a _has_monochrome_terminal() function has been implemented. This, alone, determines whether the SGR sequences should be assigned. The function works by first checking whether the terminal is dumb. If not, it tries to run "tput colors", before checking whether -1 colours are reported, for that is how the ncurses implementation reports the absence of colour support. The resulting code is simpler and more pleasing to read, with tput being run once, at most. Also, because there is no longer a requirement to handle the CSI sequences in a raw form, they are now declared as strings containing backslash-escape sequences, with printf %b being used to decode them. This has the advantage of not emitting the raw codes to STDERR while using xtrace for debugging. In the future, I think that it may well be possible to drop the function that detects a monochrome terminal and rely on dumb terminal detection instead but let's see how it goes. Signed-off-by: Kerin Millar plushkava.net> Signed-off-by: Sam James gentoo.org> functions.sh | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/functions.sh b/functions.sh index c287b24..53f3205 100644 --- a/functions.sh +++ b/functions.sh @@ -253,7 +253,7 @@ _eend() fi if [ "${is_tty}" -eq 1 ] && [ -n "${genfun_endcol}" ]; then - printf '%s %s\n' "${genfun_endcol}" "${msg}" + printf '%b %s\n' "${genfun_endcol}" "${msg}" else [ "${genfun_lastcall}" = ebegin ] || genfun_lastbegun_strlen=0 printf "%$(( cols - genfun_lastbegun_strlen - 7 ))s %s\n" '' "${msg}" @@ -474,6 +474,22 @@ is_identifier() esac ) +_has_dumb_terminal() { + ! case ${TERM} in *dumb*) false ;; esac +} + +_has_monochrome_terminal() { + local colors + + # The tput(1) invocation is not portable, though ncurses suffices. In + # this day and age, it is exceedingly unlikely that it will be needed. + if _has_dumb_terminal; then + true + elif colors=$(tput colors 2>/dev/null) && is_int "${colors}"; then + test "${colors}" -eq -1 + fi +} + # This is the main script, please add all functions above this point! # shellcheck disable=2034 RC_GOT_FUNCTIONS="yes" @@ -533,26 +549,20 @@ for _ in 1 2 3; do fi done -# Set an ECMA-48 CSI sequence, allowing for eend to line up the [ ok ] string. -{ - genfun_endcol="$(tput cuu1)" \ - && genfun_endcol="${genfun_endcol}$(tput cuf -- "$(( genfun_cols - 7 ))")" \ - || genfun_endcol="$(printf '\033[A\033[%dC' "$(( genfun_cols - 7 ))")" -} 2>/dev/null +if _has_dumb_terminal; then + unset -v genfun_endcol +else + # Set some ECMA-48 CSI sequences (CUU1 and CUF) for cursor positioning. + # These are standard and, conveniently, documented by console_codes(4). + genfun_endcol="\\033[A\\033[$(( genfun_cols - 7 ))C" +fi -# Setup the colors so our messages all look pretty -if yesno "${RC_NOCOLOR}"; then +if _has_monochrome_terminal || yesno "${RC_NOCOLOR}"; then unset -v BAD BRACKET GOOD HILITE NORMAL WARN -elif { hash tput && tput colors >/dev/null; } 2>/dev/null; then - genfun_bold=$(tput bold) genfun_norm=$(tput sgr0) - BAD="${genfun_norm}${genfun_bold}$(tput setaf 1)" - BRACKET="${genfun_norm}${genfun_bold}$(tput setaf 4)" - GOOD="${genfun_norm}${genfun_bold}$(tput setaf 2)" - HILITE="${genfun_norm}${genfun_bold}$(tput setaf 6)" - NORMAL="${genfun_norm}" - WARN="${genfun_norm}${genfun_bold}$(tput setaf 3)" - unset -v genfun_bold genfun_norm else + # Define some ECMA-48 SGR sequences for color support. These variables + # are public, in so far as users of the library may be expanding them. + # The sequences are also documented by console_codes(4). BAD=$(printf '\033[31;01m') BRACKET=$(printf '\033[34;01m') GOOD=$(printf '\033[32;01m')