Bagaimana cara memulai XTerm dengan prompt di bagian bawah?

12

Saat memulai XTerm prompt dimulai pada baris pertama terminal. Saat menjalankan perintah, prompt bergerak ke bawah hingga mencapai bagian bawah, dan sejak saat itu tetap ada di sana (bahkan tidak Shift- Page Downatau mouse dapat mengubahnya). Alih-alih memiliki awal masa terminal menjadi "khusus" prompt harus selalu di bagian bawah terminal. Harap dicatat bahwa saya memiliki prompt multi-line .

Tentu saja, itu seharusnya berfungsi seperti sebelumnya (dapat diubah ukurannya, digulir, tidak ada baris baru yang tidak perlu dalam output, dan tidak ada output yang menghilang secara misterius), jadi PROMPT_COMMAND='echo;echo;...'atau serupa bukanlah pilihan. Solusinya idealnya tidak harus spesifik-shell.

Edit: The solusi saat ini , saat bekerja dalam kasus sederhana, memiliki beberapa masalah:

  • Ini spesifik Bash . Solusi ideal harus portabel untuk cangkang lain.
  • Hal gagal jika proses lainnya memodifikasiPS1 . Salah satu contohnya adalah virtualenv, yang menambahkan (virtualenv)pada awal dari PS1, yang kemudian selalu menghilang tepat di atas flip.
  • Ctrl- lsekarang menghapus halaman terakhir sejarah.

Apakah ada cara untuk menghindari masalah ini, selain dari forking XTerm?

l0b0
sumber
Entah bagaimana, kita perlu memperkenalkan karakter kosong di buffer scrollbar Xterm.
SHW
3
Sebenarnya, prompt dapat dengan mudah dipindahkan kembali ke atas kapan saja dengan menjalankan clearperintah.
werediver
@ SHW Saya berharap ada pengaturan untuk ini daripada hack. Peretasan terminal memiliki kecenderungan untuk memperkenalkan bug yang sangat halus dalam pengalaman saya.
l0b0
@werediver Tapi saya tidak pernah ingin berada di atas.
l0b0
1
Karena hanya shell yang tahu kapan ia mengeluarkan prompt, solusi apa pun harus dalam konteks shell. Bahkan forking XTerm tidak akan membantu karena XTerm tidak tahu apakah yang diminta untuk output adalah prompt atau tidak. Untuk terminal, prompt shell hanyalah urutan karakter lain, tidak berbeda dari urutan karakter lain yang mungkin diterimanya.
celtschk

Jawaban:

11

Jika menggunakan bash, yang berikut ini harus melakukan trik:

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

Atau (kurang efisien karena menjalankan satu tputperintah sebelum setiap prompt, tetapi berfungsi setelah jendela terminal diubah ukurannya):

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

Untuk mencegah tputperubahan kode keluar, Anda dapat secara eksplisit menyimpan dan meresetnya:

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

Perhatikan bahwa variabelnya retvaladalah lokal; itu tidak mempengaruhi retvalvariabel apa pun yang mungkin telah Anda tetapkan di shell.

Karena sebagian besar cupkemampuan terminal adalah sama \e[y;xH, Anda juga dapat melakukan hardcode:

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

Jika Anda ingin aman dari pengaturan ulang PS1 nanti, Anda juga dapat menggunakan PROMPT_COMMANDvariabel. Jika diatur, dijalankan sebagai perintah sebelum prompt ditampilkan. Jadi efeknya juga bisa dicapai oleh

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

Tentu saja, walaupun pengaturan ulang PS1tidak akan memengaruhi ini, beberapa perangkat lunak lain mungkin juga berubah PROMPT_COMMAND.

celtschk
sumber
Bagaimana tputberbeda dari banyak echoperintah? (Bertanya karena penasaran)
SHW
@ l0b0, mungkin tidak pantas mendapat jawaban terpisah. Saya harap celtschk tidak akan keberatan saya mengedit jawabannya.
Stéphane Chazelas
'\[$(tput cup "$LINES")\]' bekerja dengan indah . Terima kasih!
l0b0
Ada masalah dengan tput: Tampaknya reset $exit_code. Diperbaiki dengan menggunakan \[\e[$LINES;1H\].
l0b0
1
@ l0b0: Sekarang saya telah menambahkan versi menggunakan tputyang mempertahankan kode keluar.
celtschk
4

Sebagai sedikit penyederhanaan dari jawaban sebelumnya, saya merasa lebih mudah untuk hanya menjalankan:

tput cup $LINES

di awal .bashrcatau .zshrc. Itu hanya melakukan pekerjaan.

Pro:

  • itu hanya mencetak sekali, saat Anda memulai shell Anda

Cons:

  • ketika membersihkan layar dengan ^ L, itu tidak mencetak dan alias clearuntuk clear; tput ...tidak membantu;
  • bergerak cepat di tempat lain saat terminal diubah ukurannya
phil pirozhkov
sumber
2

Jawaban menggunakan $LINEStidak perlu portabel. Seperti yang dilakukan dalam resize, Anda hanya dapat meminta xtermuntuk mengatur posisi ke nomor baris besar yang sewenang-wenang, misalnya,

tput cup 9999 0

(dengan asumsi bahwa Anda memiliki jendela lebih kecil dari 10 ribu baris, mengabaikan scrollback ).

Karena string tidak akan berubah sebagai efek samping dari mengubah ukuran jendela, Anda dapat menghitung ini sekali, dan menempelkannya ke string-cepat Anda sebagai konstanta, misalnya,

TPUT_END=$(tput cup 9999 0)

dan kemudian

PS1="${TPUT_END} myprompt: "

sesuai dengan preferensi Anda.

Adapun proses lain memodifikasi PS1: Anda harus menghitung ulang PS1setelah perubahan itu, untuk memastikan bahwa itu terlihat seperti yang Anda inginkan. Tetapi tidak ada cukup detail dalam pertanyaan untuk menunjukkan di mana harus melakukan perubahan.

Dan akhirnya: perilaku untuk penyelesaian tab tidak cocok dengan perubahan semacam ini, karena asumsi bash.

Thomas Dickey
sumber
Apa yang Anda maksud dengan "perilaku untuk penyelesaian-tab tidak sesuai dengan perubahan semacam ini"?
l0b0
Saya pikir maksud Anda PS1="${TPUT_END} myprompt: ", atau bahkanPS1="${TPUT_END}${PS1}"
l0b0
Untuk yang terakhir - benar (salah ketik memikirkan makefiles). Untuk yang pertama, ada dalam pikiran saya bahwa mengedit perintah bash bergantung pada kemampuan untuk mencetak ulang baris (dengan prompt), dan bahwa Anda bisa mendapatkan beberapa perilaku aneh ketika ini digabungkan dengan menggulir karena penyelesaian perintah.
Thomas Dickey