moins --quit-if-one-screen sans --no-init

31

Je suis sur un terminal qui prend en charge l'écran alternatif qui est utilisé par less, vim, etc. pour restaurer l'affichage précédent après avoir quitté. C'est une fonctionnalité intéressante, mais cela rompt vraiment le --quit-if-one-screencommutateur lesscar dans ce cas, moins de commutateurs vers l'écran alternatif, affiche ses données, comprend qu'il n'y a qu'un seul écran et quitte, emportant le contenu de l'écran alternatif avec lui.

La solution de contournement couramment suggérée consiste à utiliser le --no-initcommutateur pour éviter d'utiliser complètement l'écran alternatif. Cependant, cela est un peu laid parce que je ne veux l'utiliser en cas moins agit en fait comme un téléavertisseur. Par conséquent, je recherche une solution pour utiliser l'écran alternatif uniquement si less ne se termine pas automatiquement.

Je vais principalement l'utiliser comme pager de Git, donc un script shell wrapper qui ne fonctionne que moins au cas où il y aurait suffisamment de sortie serait bien aussi. Au moins s'il n'y a aucun moyen de le faire sans un.

ThiefMaster
la source
@thieMaster dans ce cas, comment définissez-vous un écran alternatif? J'essaie de nettoyer certaines balises et je n'ai vraiment pas de sens ici
Kiwy

Réponses:

14

Depuis moins de 530 (sorti en décembre 2017), less --quit-if-one-screenne passe pas à l'écran alternatif s'il lit moins d'un écran. Vous n'aurez donc pas ce problème si votre version de less est suffisamment récente.

Dans les versions antérieures, less doit décider d'utiliser ou non l'autre écran au démarrage. Vous ne pouvez pas reporter ce choix à la fin.

Vous pouvez appeler moins, le laisser utiliser l'écran alternatif et transférer le contenu sur l'écran principal si less se termine automatiquement. Cependant, je ne connais aucun moyen de détecter l'arrêt automatique.

D'un autre côté, ce n'est pas si difficile d'appeler cat pour des entrées courtes et moins pour des entrées plus grandes, même en préservant la mise en mémoire tampon afin que vous n'ayez pas à attendre que l'entrée entière commence à voir des choses en moins (le tampon peut être légèrement plus grand - vous ne verrez rien avant d'avoir au moins un écran de données - mais pas beaucoup plus).

#!/bin/sh
n=3  # number of screen lines that should remain visible in addition to the content
lines=
newline='
'
case $LINES in
  ''|*[!0-9]*) exec less;;
esac
while [ $n -lt $LINES ] && IFS= read -r line; do
  lines="$lines$newline$line"
done
if [ $n -eq $LINES ]; then
  { printf %s "$lines"; exec cat; } | exec less
else
  printf %s "$lines"
fi

Vous préférerez peut-être voir les lignes sur l'écran principal au fur et à mesure qu'elles apparaissent et passer à l'écran alternatif si les lignes provoquent un défilement.

#!/bin/sh
n=3  # number of screen lines that should remain visible in addition to the content
beginning=
newline='
'
# If we can't determine the terminal height, execute less directly
[ -n "$LINES" ] || LINES=$(tput lines) 2>/dev/null
case $LINES in
  ''|*[!0-9]*) exec less "$@";;
esac
# Read and display enough lines to fill most of the terminal
while [ $n -lt $LINES ] && IFS= read -r line; do
  beginning="$beginning$newline$line"
  printf '%s\n' -- "$line"
  n=$((n + 1))
done
# If the input is longer, run the pager
if [ $n -eq $LINES ]; then
  { printf %s "$beginning"; exec cat; } | exec less "$@"
fi
Gilles 'SO- arrête d'être méchant'
la source
5
"Moins doit décider s'il faut utiliser l'autre écran au démarrage. Vous ne pouvez pas reporter ce choix à la fin." - bien qu'il ne le fasse apparemment pas, mais ne pourrait pas simplement différer une sortie (telle que les commandes d'initialisation du terminal ou les données réelles) jusqu'à ce qu'il ait reçu X lignes. Si stdin est épuisé pendant que X <TERMINAL_LINES, il enverrait simplement tout sur stdout et quitterait, sinon il initialiserait l'écran alternatif et ferait ce qu'il est censé faire
ThiefMaster
1
J'ai fini par utiliser une version modifiée de votre premier exemple de code: gist.github.com/ThiefMaster/8331024 ($ LINES était vide lors de l'appel en tant que git-pager et je pense que vous avez oublié d'incrémenter $n)
ThiefMaster
@ThiefMaster Merci pour vos commentaires. Notez que vous devez mettre #!/bin/bashvotre script car vous utilisez une construction spécifique à bash, car il est que votre script ne fonctionnera pas sur des systèmes (tels que Ubuntu) où /bin/shn'est pas bash.
Gilles 'SO- arrête d'être méchant'
3
J'ai vraiment aimé cette idée et je l'ai développée un peu plus (avec plus de fonctionnalités): github.com/stefanheule/smartless
stefan
1
@ThiefMaster: lesspourrait également (mais pas) avoir un moyen facultatif de quitter là où il imprime le contenu actuel de l'écran après l' envoi de la chaîne non-init. Ainsi, vous pourriez avoir l'avantage que l'écran alternatif n'encombre pas le défilement, mais laisse toujours la partie pertinente de la page de manuel ou quoi que ce soit sur le terminal après avoir quitté.
Peter Cordes
9

GNU less v. 530 incorpore le patch Fedora mentionné par @ paul-antoine-arras et ne sortira plus la séquence d'initialisation du terminal lorsqu'il --quit-if-one-screenest utilisé et que l'entrée tient sur un seul écran.

eigengrau82
la source
4
Les utilisateurs Homebrew sur Mac OS peuvent obtenir ce comportement immédiatement en exécutant brew install lesset en s'assurant que $LESSF et omet X.
Ryan Patterson
Ceci est ma réponse préférée. J'ai immédiatement téléchargé Less 5.3.0 depuis GNU et l'ai compilé moi-même. Excellent indice!
iBug
5

Pour les entrées lentes, comme git log -Gregex, voulez-vous:

A) les lignes doivent apparaître sur l'écran principal au fur et à mesure qu'elles apparaissent, puis passer à l'écran alternatif une fois que le défilement est nécessaire (de sorte que la première $LINESsortie apparaîtra toujours dans votre défilement); si oui, allez avec la 2e des réponses de Gilles .

B) les lignes doivent apparaître sur l'écran secondaire, mais quittez l'écran secondaire et imprimez les lignes sur l'écran principal si le défilement s'avère inutile (donc aucune sortie n'apparaîtra dans votre défilement arrière si le défilement était requis); si oui, utilisez le script ci-dessous:

Il s'agit de teel'entrée d'un fichier temporaire, puis une fois lessqu'il est sorti, il catest du fichier temporaire s'il contient moins de lignes que la hauteur de l'écran:

#!/bin/bash

# Needed so less doesn't prevent trap from working.
set -m
# Keeps this script alive when Ctrl+C is pressed in less,
# so we still cat and rm $TMPFILE afterwards.
trap '' EXIT

TXTFILE=$(mktemp 2>/dev/null || mktemp -t 'tmp')

tee "$TXTFILE" | LESS=-FR command less "$@"

[[ -n $LINES ]] || LINES=$(tput lines)
[[ -n $COLUMNS ]] || COLUMNS=$(tput cols)
# Wrap lines before counting, unless you pass --chop-long-lines to less
# (the perl regex strips ANSI escapes).
if (( $(perl -pe 's/\e\[?.*?[\@-~]//g' "$TXTFILE" | fold -w "$COLUMNS" | wc -l) < $LINES )); then
    cat "$TXTFILE"
fi

rm "$TXTFILE"

Utilisez-le avec export PAGER='/path/to/script'. Cela devrait être suffisant pour l' gitutiliser, sauf si vous l'avez déjà remplacé core.pager.

Pour les améliorations possibles, voir également ma version légèrement plus étoffée de ce script à: https://github.com/johnmellor/scripts/blob/master/bin/least

John Mellor
la source
3

Cela a longtemps été résolu dans les distributions basées sur Red Hat en modifiant le comportement de l'option -F dans lessle code source: voir ce correctif du projet Fedora, dont la première version remonte à 2008. L'idée est simplement d'obtenir la hauteur de la (c'est-à-dire le nombre maximum de lignes pouvant être affichées simultanément) et d'omettre les séquences d'initialisation et de désinitialisation lorsque le fichier tient dans un seul écran. Ainsi, aucune option -X et -F ne peuvent être utilisées de manière cohérente quelle que soit la longueur du fichier.

parras
la source