mniej - quit-if-one-screen bez --no-init

31

Jestem na terminalu, który obsługuje alternatywny ekran, którego używa less, vim itp., Aby przywrócić poprzedni ekran po wyjściu. To fajna funkcja, ale naprawdę psuje --quit-if-one-screenprzełącznik, lessponieważ w takim przypadku mniej przełącza się na alternatywny ekran, wyświetla jego dane, domyśla się, że jest tylko jeden ekran i wychodzi, zabierając ze sobą zawartość alternatywnego ekranu.

Często sugerowanym obejściem jest użycie --no-initprzełącznika, aby całkowicie uniknąć korzystania z alternatywnego ekranu. Jest to jednak dość brzydkie bo nie chcą go używać w przypadku mniej rzeczywiście działa jak pager. Dlatego szukam rozwiązania, aby użyć alternatywnego ekranu tylko wtedy, gdy less nie kończy się automatycznie.

Najczęściej używam tego jako pager Gita, więc skrypt powłoki, który działa mniej, na wypadek, gdyby było wystarczająco dużo danych wyjściowych, również byłby w porządku. Przynajmniej jeśli nie da się tego zrobić bez niego.

ThiefMaster
źródło
@thieMaster w tym przypadku, jak zdefiniować alternatywny ekran? Próbuję wyczyścić niektóre tagi i naprawdę nie rozumiem tutaj znaczenia
Kiwy

Odpowiedzi:

14

Ponieważ mniej 530 (wydanych w grudniu 2017 r.), less --quit-if-one-screenNie przełącza się na alternatywny ekran, jeśli odczytuje mniej niż jeden ekran. Więc nie będziesz mieć tego problemu, jeśli twoja wersja less jest wystarczająco aktualna.

We wcześniejszych wersjach mniej musi decydować, czy użyć alternatywnego ekranu podczas uruchamiania. Nie możesz odroczyć tego wyboru do momentu, w którym wygasa.

Możesz zadzwonić mniej, pozwolić użyć alternatywnego ekranu i przenieść zawartość na ekran główny, jeśli less kończy się automatycznie. Jednak nie znam sposobu na wykrycie automatycznego zakończenia.

Z drugiej strony, nie jest tak trudno wywołać cat dla krótkich danych wejściowych, a mniej dla większych danych wejściowych, nawet zachowując buforowanie, dzięki czemu nie musisz czekać, aż całe dane wejściowe zaczną widzieć mniej (bufor może być nieco większy - nic nie zobaczysz, dopóki nie będziesz mieć przynajmniej jednego ekranu danych - ale niewiele więcej).

#!/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

Możesz zobaczyć linie na ekranie głównym, gdy się pojawią, i przełącz się na ekran alternatywny, jeśli linie spowodują przewijanie.

#!/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- przestań być zły”
źródło
5
„Mniej musi zdecydować, czy użyć alternatywnego ekranu, gdy się zacznie. Nie możesz odroczyć tego wyboru, kiedy się skończy”. - chociaż najwyraźniej tego nie robi, ale nie mógł po prostu odroczyć żadnego wyjścia (takiego jak polecenia inicjalizacji terminala lub rzeczywiste dane), dopóki nie otrzyma X linii. Jeśli stdin zostanie wyczerpany, gdy X <TERMINAL_LINES, po prostu zrzuci wszystko na stdout i wyjdzie, w przeciwnym razie zainicjuje alternatywny ekran i zrobi to, co powinien
ThiefMaster
1
Skończyło się na zmodyfikowanej wersji twojego pierwszego przykładu kodu: gist.github.com/ThiefMaster/8331024 ($ LINES był pusty, gdy został wywołany jako git-pager i myślę, że zapomniałeś inkrementować $n)
ThiefMaster
@ ThiefMaster Dzięki za opinie. Zauważ, że powinieneś wstawić #!/bin/bashskrypt, ponieważ używasz konstrukcji specyficznej dla bash, ponieważ jest to skrypt, który nie będzie działał na systemach (takich jak Ubuntu), gdzie /bin/shnie jest bash.
Gilles „SO- przestań być zły”
3
Naprawdę podobał mi się ten pomysł i rozwinąłem go nieco dalej (z większą liczbą funkcji): github.com/stefanheule/smartless
stefan
1
@ ThiefMaster: lessmoże również (ale nie ma) opcjonalnego sposobu wyjścia z miejsca, w którym drukuje bieżącą zawartość ekranu po wysłaniu ciągu un-init. Możesz więc skorzystać z alternatywnego ekranu, który nie zaśmieca przewijania, ale po wyjściu pozostawia odpowiednią część strony podręcznika lub cokolwiek na terminalu.
Peter Cordes,
9

GNU less v. 530 zawiera łatkę Fedory, o której mowa w @ paul-antoine-arras, i nie będzie już wyświetlać sekwencji inicjalizacji terminala, gdy --quit-if-one-screenjest używana, a dane wejściowe mieszczą się na jednym ekranie.

eigengrau82
źródło
4
Użytkownicy Homebrew w systemie Mac OS mogą natychmiast uzyskać to zachowanie, uruchamiając brew install lessi upewniając się, że $LESSma F i pomija X.
Ryan Patterson
To moja ulubiona odpowiedź. Natychmiast pobrałem Less 5.3.0 z GNU i sam go skompilowałem. Świetna wskazówka!
iBug
5

W przypadku powolnych wejść, na przykład git log -Gregex, czy chcesz:

A) wiersze, które pojawią się na ekranie głównym, gdy się pojawią, a następnie przełącz się na ekran alternatywny, gdy przewijanie jest potrzebne (więc pierwszy $LINESwynik zawsze będzie pojawiał się w przewijaniu); jeśli tak, przejdź do drugiej odpowiedzi Gillesa .

B) linie do pojawienia się na alternatywnym ekranie, ale wyjdź z alternatywnego ekranu i wydrukuj linie na ekranie głównym, jeśli przewijanie okaże się niepotrzebne (więc przewijanie nie pojawi się, jeśli wymagane jest przewijanie); jeśli tak, użyj poniższego skryptu:

Jest teeto dane wejściowe do pliku tymczasowego, a po lesswyjściu catjest to plik tymczasowy, jeśli zawiera mniej linii niż wysokość ekranu:

#!/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"

Używaj go z export PAGER='/path/to/script'. To powinno wystarczyć, aby z gitniego skorzystać, chyba że już go zastąpiłeś core.pager.

Aby zapoznać się z możliwymi ulepszeniami, zobacz także moją nieco bardziej rozwiniętą wersję tego skryptu pod adresem : https://github.com/johnmellor/scripts/blob/master/bin/least

John Mellor
źródło
3

Od dawna rozwiązano to w dystrybucjach opartych na Red Hat, modyfikując zachowanie opcji -F w lesskodzie źródłowym: zobacz tę łatkę z Projektu Fedora, którego pierwsza wersja pochodzi z 2008 roku. Chodzi o to, aby uzyskać wysokość terminal (tj. maksymalna liczba wierszy, które mogą być wyświetlane jednocześnie) i aby pominąć sekwencje inicjalizacji i deinicjalizacji, gdy plik mieści się na jednym ekranie. Dlatego nie ma potrzeby używania opcji -X i opcji -F można używać konsekwentnie niezależnie od długości pliku.

parras
źródło