Cara menampilkan karakter kontrol (^ C, ^ D, ^ [, ...) berbeda di shell

13

Ketika Anda mengetik karakter kontrol di shell mereka ditampilkan menggunakan apa yang disebut "notasi caret". Escape misalnya dituliskan ^[dalam notasi tanda sisipan.

Saya ingin menyesuaikan bash shell saya agar terlihat keren. Misalnya saya telah mengubah PS1dan PS2menjadi berwarna. Saya sekarang ingin mengontrol karakter untuk mendapatkan penampilan yang unik juga untuk membuatnya lebih dapat dibedakan dari karakter biasa.

$ # Here I type CTRL-C to abort the command.
$ blahblah^C
          ^^ I want these two characters to be displayed differently

Apakah ada cara untuk membuat karakter kontrol shell highlight saya berbeda?

Apakah mungkin membuatnya menampilkannya dalam huruf tebal atau membuatnya muncul dalam warna berbeda dari teks biasa?

Saya menggunakan bash shell di sini tetapi saya tidak memberi tag pada pertanyaan bashkarena mungkin ada solusi yang berlaku untuk banyak shell yang berbeda.

Perhatikan bahwa saya tidak tahu pada level apa penyorotan karakter kontrol terjadi. Saya pertama kali berpikir itu ada di shell itu sendiri. Sekarang saya telah mendengar bahwa itu adalah readline yang mengontrol bagaimana karakter kontrol di shell seperti bash . Jadi pertanyaannya sekarang ditandai dengan readlinedan saya masih mencari jawaban.

wefwefa3
sumber
menurut Anda mengapa cangkang menyoroti mereka? untuk bashitu readlinemenangani hal-hal itu, dan bagi kebanyakan orang lain itu adalah driver tty.
mikeserv
Saya tidak tahu. Itu sebabnya saya menulis catatan itu. Itu hanya dugaan saya karena aplikasi lain suka vidan lesssering menyorot karakter kontrol berbeda dari teks biasa. Saya akan mengedit pertanyaan dengan informasi ini. Terima kasih!
wefwefa3
itu masuk akal. hal semacam itu lebih sulit untuk shell karena jenisnya merupakan prioritas kedua. dengan editor, seluruh pekerjaan mereka adalah menyediakan antarmuka layar <> file, tetapi shell adalah penerjemah perintah untuk bahasa yang ditafsirkan terlebih dahulu dan editor baris kedua (atau tidak sama sekali) .
mikeserv
Readline digunakan oleh program lain, tetapi juga merupakan bagian dari bash: ini adalah perpustakaan yang terhubung dengannya. Dan kerang hari ini, terutama bash, melakukan cukup banyak hal yang dapat Anda pikirkan.
alexis
Cukup gunakan zshyang melakukan itu di luar kotak.
Stéphane Chazelas

Jawaban:

20

Ketika Anda menekan Ctrl+X, emulator terminal Anda menulis byte 0x18 ke sisi master dari pasangan pseudo-terminal.

Apa yang terjadi selanjutnya tergantung pada bagaimana disiplin garis tty (modul perangkat lunak di kernel yang berada di antara sisi master (di bawah kendali emulator) dan sisi budak (yang aplikasi yang berjalan di terminal berinteraksi dengan)) dikonfigurasi.

Perintah untuk mengonfigurasi disiplin garis tty adalah sttyperintah.

Ketika menjalankan aplikasi bodoh seperti catitu tidak menyadari dan tidak peduli apakah stdinnya adalah terminal atau tidak, terminal berada dalam mode kanonik default di mana disiplin garis tty mengimplementasikan editor garis kasar .

Beberapa aplikasi interaktif yang memerlukan lebih dari itu editor garis kasar biasanya mengubah pengaturan tersebut saat start-up dan mengembalikannya saat meninggalkan. Kerang modern, pada prompt mereka adalah contoh dari aplikasi tersebut. Mereka menerapkan editor baris yang lebih maju.

Biasanya, saat Anda memasukkan baris perintah, shell menempatkan disiplin garis tty dalam mode itu, dan ketika Anda menekan enter untuk menjalankan perintah saat ini, shell mengembalikan mode tty normal (seperti yang berlaku sebelum mengeluarkan prompt).

Jika Anda menjalankan stty -aperintah, Anda akan melihat pengaturan saat ini digunakan untuk aplikasi bodoh . Anda mungkin melihat icanon, echodan echoctlpengaturan diaktifkan.

Artinya adalah:

  • icanon: editor garis kasar diaktifkan.
  • echo: karakter yang Anda ketikkan (yang ditulis emulator terminal ke sisi master) digaungkan kembali (tersedia untuk dibaca oleh emulator terminal).
  • echoctl: Bukannya menggema asis, karakter kontrol bergema sebagai ^X.

Jadi, katakanlah Anda mengetik A B Backspace-aka-Ctrl+H/? C Ctrl+X Backspace Return.

Emulator terminal Anda akan mengirimkan: AB\bC\x18\b\r. Disiplin garis akan menggema kembali :,AB\b \bC^X\b \b\b \b\r\n dan aplikasi yang membaca input dari sisi slave ( /dev/pts/x) akan membaca AC\n.

Semua aplikasi melihat adalah AC\n, dan hanya ketika Anda menekan Entersehingga tidak dapat mengontrol output untuk ^Xsana.

Anda akan melihat bahwa untuk echo , yang pertama ^H( ^?dengan beberapa terminal, lihat erasepengaturan) mengakibatkan \b \bdikirim kembali ke terminal. Itulah urutan untuk memindahkan kursor ke belakang, menimpa dengan spasi, memindahkan kursor kembali, sedangkan yang kedua ^Hmenghasilkan \b \b\b \buntuk menghapus dua karakter ^dan Xkarakter.

The ^X(0x18) sendiri sedang diterjemahkan ke ^dan Xuntuk output. Seperti B, itu tidak berhasil masuk ke aplikasi, karena kami menghapusnya dengan Backspace.

\r(alias ^M) diterjemahkan ke \r\n( ^M^J) untuk gema, dan \n( ^J) untuk aplikasi.

Jadi, apa saja pilihan kami untuk aplikasi bodoh itu :

  • nonaktifkan echo( stty -echo). Itu secara efektif mengubah cara karakter kontrol digaungkan, dengan ... tidak menggema apa pun. Bukan solusi.
  • nonaktifkan echoctl. Itu mengubah cara kontrol karakter (selain ^H, ^M... dan yang lainnya digunakan oleh editor baris) digaungkan. Mereka kemudian didengungkan apa adanya. Misalnya, karakter ESC dikirim sebagai byte \e( ^[/ 0x1b) (yang dikenali sebagai permulaan urutan escape oleh terminal), ^GAnda mengirim \a(BEL, membuat terminal Anda berbunyi) ... Bukan pilihan .
  • nonaktifkan editor baris kasar ( stty -icanon). Tidak benar-benar pilihan karena aplikasi kasar akan menjadi jauh lebih tidak dapat digunakan.
  • edit kode kernel untuk mengubah perilaku disiplin tty line sehingga gema dari karakter kontrol mengirim \e[7m^X\e[mbukan hanya ^X(di sini \e[7mbiasanya memungkinkan membalikkan video di sebagian besar terminal).

Sebuah opsi bisa menggunakan pembungkus seperti rlwrapitu adalah hack kotor untuk menambahkan editor garis mewah ke aplikasi bodoh. Wrapper yang berlaku mencoba untuk mengganti read()s sederhana dari perangkat terminal untuk panggilan ke editor baris readline (yang mengubah mode disiplin garis tty).

Lebih jauh lagi, Anda bahkan dapat mencoba solusi seperti ini yang membajak semua input dari terminal untuk melalui editor baris zsh (yang kebetulan menyorot ^Xdalam video terbalik) mengandalkan :execfitur layar GNU .

Sekarang untuk aplikasi yang mengimplementasikan editor baris mereka sendiri, terserah kepada mereka untuk memutuskan bagaimana gema dilakukan. bashmenggunakan readline untuk apa yang tidak memiliki dukungan untuk mengkustomisasi bagaimana karakter kontrol digaungkan.

Untuk zsh, lihat:

info --index-search='highlighting, special characters' zsh

zshtidak menyorot karakter yang tidak dapat dicetak secara default. Anda dapat menyesuaikan sorotan dengan misalnya:

zle_highlight=(special:fg=white,bg=red)

Untuk warna putih pada highlight merah untuk karakter khusus tersebut.

Representasi teks dari karakter tersebut tidak dapat disesuaikan.

Dalam UTF-8 lokal, 0x18 akan diberikan sebagai ^X, \u378, \U7fffffff(dua poin kode unicode belum ditetapkan) sebagai <0378>, <7FFFFFFF>, \u200b(a dicetak karakter tidak-benar-benar unicode) sebagai <200B>.

\x80di lokal iso8859-1 akan diterjemahkan sebagai ^�... dll.

Stéphane Chazelas
sumber
3

Saya biasanya memiliki kode ini di file .bashrc saya:

function get_exit_status()
{
        local code=$?
        if [ $code -ne 0 ]
        then
                printf $'\001\033[31m\002'"($code)"$'\001\033[0m\002'" "
        fi
}

dan kemudian saya memanggil fungsi ini di PS1 saya

PS1='\u@\h \w $(get_exit_status)'

Dengan ini, jika Anda menekan ^ C Anda akan melihatnya di prompt Anda

I@mycomputer ~ ^C
I@mycomputer ~ (130)

Semua kode status keluar yang bukan "0" akan diminta.

berujung
sumber
$? memperluas untuk keluar status di PS1 misalnya PS1 = '$? \ u @ \ h \ w'
teknopaul