Jak uruchomić XTerm z pytaniem u dołu?

12

Podczas uruchamiania XTerm monit zaczyna się od pierwszej linii terminala. Podczas uruchamiania poleceń wiersz przesuwa się w dół, aż osiągnie dno, i od tego momentu pozostaje tam (nawet Shift- Page Downlub mysz może to zmienić). Zamiast tego, aby czas życia terminala był „specjalny”, monit powinien zawsze znajdować się na dole terminala. Pamiętaj, że mam monit wieloliniowy .

Oczywiście, w przeciwnym razie powinien działać jak poprzednio (zmiana rozmiaru, przewijanie, brak zbędnych znaków nowej linii i brak wyjścia w tajemniczy sposób znikający), więc PROMPT_COMMAND='echo;echo;...'nie ma takiej opcji. Rozwiązanie idealnie nie powinno być specyficzne dla powłoki.

Edit: obecne rozwiązanie , pracując w prostych przypadkach, ma kilka problemów:

  • Jest specyficzny dla Bash . Idealne rozwiązanie powinno być przenośne na inne powłoki.
  • Nie powiedzie się, jeśli zmodyfikują się inne procesyPS1 . Jednym z przykładów jest virtualenv, który dodaje (virtualenv)na początku dnia PS1, który następnie znika zawsze tuż powyżej krotnie.
  • Ctrl- lteraz usuwa ostatnią stronę historii.

Czy istnieje sposób na uniknięcie tych problemów, poza rozwidleniem XTerm?

l0b0
źródło
W jakiś sposób musimy wprowadzić puste znaki w buforze paska przewijania Xterm.
SHW
3
W rzeczywistości monit można łatwo w dowolnym momencie przenieść z powrotem na górę, wykonując clearpolecenie.
werediver
@ SHW Miałem nadzieję, że było to ustawienie zamiast hackowania. Hacki terminalowe mają tendencję do wprowadzania bardzo subtelnych błędów w moim doświadczeniu.
l0b0
@ respondiver Ale nigdy nie chcę, żeby był na topie.
l0b0
1
Ponieważ tylko powłoka wie, kiedy wyświetla monit, każde rozwiązanie musi znajdować się w kontekście powłoki. Nawet rozwidlenie XTerma nie pomoże, ponieważ XTerm nie wie, czy to, o co jest proszony, jest pytaniem, czy nie. W przypadku terminala monit powłoki jest po prostu kolejną sekwencją znaków, niczym nie różniącą się od żadnej innej sekwencji znaków, jaką może otrzymać.
celtschk

Odpowiedzi:

11

Jeśli używasz bash, następujące czynności powinny załatwić sprawę:

TOLASTLINE=$(tput cup "$LINES")
PS1="\[$TOLASTLINE\]$PS1"

Lub (mniej wydajne, ponieważ uruchamia jedno tputpolecenie przed każdym monitem, ale działa po zmianie rozmiaru okna terminala):

PS1='\[$(tput cup "$LINES")\]'$PS1

Aby zapobiec tputzmianie kodu wyjścia, możesz go jawnie zapisać i zresetować:

PS1='\[$(retval=$?;tput cup "$LINES";exit $retval)\]'$PS1

Zauważ, że zmienna retvaljest lokalna; nie wpływa na żadną retvalzmienną, którą mógłbyś zdefiniować w powłoce.

Ponieważ większość terminali cupjest taka sama \e[y;xH, możesz również kodować na stałe:

PS1='\[\e[$LINES;1H\]'$PS1

Jeśli chcesz, aby był bezpieczny przed późniejszym resetowaniem PS1, możesz również użyć PROMPT_COMMANDzmiennej. Jeśli jest ustawiony, jest uruchamiany jako polecenie przed wyświetleniem monitu. Tak więc efekt można również osiągnąć przez

PROMPT_COMMAND='(retval=$?;tput cup "$LINES";exit $retval)'

Oczywiście, chociaż resetowanie PS1nie wpłynie na to, niektóre inne programy również mogą się zmienić PROMPT_COMMAND.

celtschk
źródło
Czym tputróżnią się od wielu echopoleceń? (Pytanie z ciekawości)
SHW
@ l0b0, prawdopodobnie nie zasługuje na osobną odpowiedź. Mam nadzieję, że celtschk nie będzie miał nic przeciwko, że zredagowałem jego / jej odpowiedź.
Stéphane Chazelas
'\[$(tput cup "$LINES")\]' działa pięknie . Dzięki!
l0b0
Wystąpił problem z tput: Wygląda na to, że się resetuje $exit_code. Naprawiono za pomocą \[\e[$LINES;1H\].
l0b0
1
@ l0b0: Dodałem teraz wersję, tputktóra zachowuje kod wyjścia.
celtschk
4

Dla uproszczenia poprzedniej odpowiedzi łatwiej mi było uruchomić:

tput cup $LINES

na początku .bashrclub .zshrc. Po prostu działa.

Plusy:

  • drukuje się tylko raz, po uruchomieniu powłoki

Cons:

  • podczas czyszczenia ekranu za pomocą ^ L nie jest drukowane, a aliasing cleardo clear; tput ...nie pomaga;
  • monit przesuwa się w inne miejsce, gdy rozmiar terminala zostanie zmieniony
phil pirozhkov
źródło
2

Użyte odpowiedzi $LINESsą niepotrzebnie nieprzenośne. Po zakończeniu resizemożesz po prostu poprosić xtermo ustawienie pozycji na dowolnie dużą liczbę wierszy, np.

tput cup 9999 0

(zakładając, że masz okno mniejsze niż 10 tysięcy linii, bez względu na przewijanie ).

Ponieważ ciąg nie zmieni się jako efekt uboczny zmiany rozmiaru okna, możesz to raz obliczyć i wkleić jako ciąg zachęty, np.

TPUT_END=$(tput cup 9999 0)

i później

PS1="${TPUT_END} myprompt: "

zgodnie z twoimi preferencjami.

Jeśli chodzi o inne modyfikujące procesy PS1: PS1po tych zmianach będziesz musiał ponownie obliczyć , aby upewnić się, że będzie wyglądał tak, jak chcesz. Ale pytanie nie zawiera wystarczającej ilości szczegółów, aby wskazać, gdzie wprowadzić zmiany.

I na koniec: zachowanie przy uzupełnianiu tabulatorów nie łączy się z tego rodzaju zmianą, z powodu założeń bash.

Thomas Dickey
źródło
Co rozumiesz przez „zachowanie uzupełniania tabulatorów nie łączy się z tego rodzaju zmianą”?
l0b0
Myślę, że masz na myśli PS1="${TPUT_END} myprompt: ", a nawetPS1="${TPUT_END}${PS1}"
l0b0
Dla tych ostatnich - racja (literówka z myślenia o makefile). Po pierwsze, mam na myśli, że edycja poleceń bash polega na możliwości ponownego wydrukowania linii (z pytaniem) i że możesz uzyskać dziwne zachowanie, gdy łączy się to z przewijaniem z powodu zakończenia poleceń.
Thomas Dickey,