Bagaimana mencegah perlambatan ketika proses yang lebih rendah menghasilkan garis panjang?

14

Saya menggunakan Emacs dengan Geiser untuk meretas beberapa kode Skema. Saat saya bermain-main dalam REPL, saya terkadang mengevaluasi ekspresi yang menghasilkan banyak output, sering kali semuanya dalam satu baris.

Sebagai contoh, saya baru saja bermain dengan SRFI-41 (stream) dan membuat aliran karakter dari file besar; kemudian saya memaksa aliran dan Geiser mem-blost seluruh isi file sebagai aliran karakter ke buffer saya. Hampir seketika, Emacs terhenti karena semakin banyak karakter yang ditambahkan ke baris output, dan tidak peduli berapa lama saya terus menekan C-gatau C-c C-csaya tidak bisa membuat Emacs (atau Geiser) berhenti.

Ini memecah seluruh sesi Emacs saya karena Emacs sekarang benar-benar mengabaikan input saya, berpikir bahwa itu perlu memberikan prioritas untuk mencetak aliran karakter besar-besaran ini semua pada satu baris ke dalam buffer Geiser REPL yang tidak responsif.

Adakah yang bisa saya lakukan untuk melindungi sesi Emacs saya dari keingintahuan destruktif saya? (Mengapa Emacs menjadi sangat lambat ketika menampilkan garis yang sangat panjang?) Dapatkah saya menetapkan batas untuk garis yang panjang dan memberi tahu Emacs bahwa tidak apa-apa untuk tidak mencoba menampilkan garis yang sangat panjang?

rekado
sumber
2
Nah, pertanyaan saya bukan tentang menampilkan garis panjang per se; Saya ingin tahu bagaimana saya bisa menghindari hal semacam ini di tempat pertama (Emacs membaca baris dari proses yang lebih rendah, itu tidak dibaca dari file yang bisa saya perbaiki); dan ini tentang bagaimana saya bisa mencegah kehilangan sesi Emacs saya karena dedikasi Emacs ke satu buffer dinamis.
rekado
"Yah, pertanyaan saya bukan tentang menampilkan garis panjang" Maka mungkin Anda harus mengubah judul Anda. Mungkin Anda ingin memfilter output proses yang lebih rendah dan menambahkan baris baru setelah sejumlah karakter?
pengasuh
Sebenarnya, ini tidak ada hubungannya dengan garis panjang. yesdalam ansi-termmisalnya memiliki mirip (tapi tidak yang mengerikan) efek. Sebenarnya itu hanya volume teks yang memberi emacs jeda.
PythonNut
Penyisipan teks dalam buffer cukup cepat, operasi redisplay yang membuatnya tampak lebih lambat dari yang sebenarnya. Sejujurnya, menjalankan yesemulator terminal VTE memaksimalkan semua core CPU saya, jadi saya tidak akan menggunakannya sebagai contoh.
wasamasa

Jawaban:

12

Seperti yang sudah dijawab dalam komentar, Emacs menjadi sangat lambat dalam tampilan ulang untuk garis panjang adalah masalah yang terkenal . Memperbaikinya akan sangat bagus, tetapi perlu banyak pemikiran untuk dilakukan dengan benar. Saya punya ide tentang bagaimana hal itu dapat dilakukan berdasarkan bagian 6.3 dari dokumen ini (pada dasarnya, menyimpan informasi garis visual dalam buffer saat ini dan memperbaruinya pada penyisipan spasi putih, properti tampilan, perubahan jendela, dll., Kemudian gunakan informasi itu dalam tampilkan kembali kode untuk menghindari pemindaian untuk itu sepanjang waktu), tetapi saya tidak cukup akrab dengan internal C untuk melakukannya.

Namun ada beberapa solusi. Yang paling jelas adalah menyetel parameter yang terkait tampilan (seperti, mengaktifkan pemotongan garis visual dalam instance Emacs grafis, menggunakan Emacs non-grafis untuk melakukan hal itu secara otomatis, menonaktifkan fitur Bidi, dll.) Dan memproses ulang konten file yang Anda inginkan. sedang membaca. Yang kurang jelas adalah secara otomatis pasca-pemrosesan file, baik itu dengan benar-benar memotong baris mereka atau menambahkan properti teks yang membuat garis tampak lebih pendek daripada yang sebenarnya. Untuk mengubahnya menjadi jawaban yang lebih menarik, saya akan menyajikan peretasan yang sangat buruk dari opsi sebelumnya yang hanya akan bekerja untuk comintmode yang diarsipkan:

(defun my-comint-shorten-long-lines (text)
  (let* ((regexp "^\\(.\\{80\\}\\).*?$")
         (shortened-text (replace-regexp-in-string regexp "\\1" text)))
    (if (string= shortened-text text)
        text
      (propertize shortened-text 'help-echo text))))

(add-hook 'comint-preoutput-filter-functions 'my-comint-shorten-long-lines)

Ini mendefinisikan my-comint-shorten-long-lines, suatu fungsi yang mengambil string yang mungkin terdiri dari banyak baris dan menggunakan kekuatan ekspresi reguler untuk mengganti baris di dalamnya dengan panjang 80 karakter atau lebih dengan versi singkat yang menampilkan teks asli ketika melayang di atasnya. Ketika digunakan sebagai pengait di comint-preoutput-filter-functionsdalamnya akan menyaring semua comintoutput sebelum ditampilkan.

Namun, rendisi hack ini memiliki kelemahan yang cukup serius. Dalam mode yang memiliki fontifikasi dasar yang sedang berlangsung (seperti, M-x ielm), itu akan dengan senang hati memotong garis-garis yang merupakan bagian dari string dan akan dengan cara itu mengklasifikasikan semuanya sampai kutipan berikutnya sebagai string! Bukan itu yang kita inginkan dan dapat diperbaiki dengan sedikit penguasaan regex (tapi mungkin akan menerobos dalam REPL untuk bahasa seperti Python). Sementara kita melakukannya, mari kita sorot juga keluaran yang lebih pendek:

(defun my-comint-shorten-long-lines (text)
  (let* ((regexp "^\\(.\\{80\\}\\).*?\\(\"?\\)$")
         (shortened-text (replace-regexp-in-string regexp "\\1\\2" text)))
    (if (string= shortened-text text)
        text
      (propertize shortened-text 'font-lock-face 'shadow 'help-echo text))))

(add-hook 'comint-preoutput-filter-functions 'my-comint-shorten-long-lines)

Itu sedikit lebih baik, tetapi masih jelek. Melayang pada output seperti find /in M-x shelltidak menarik (idealnya kita hanya ingin menampilkan garis yang tidak tertutup, tidak semua output), deteksi string paling sederhana dan pemotongan dapat diindikasikan lebih baik dengan elips alih-alih mengklasifikasikan semuanya. Selain itu, bahkan tidak dijamin bahwa teks yang masuk tidak berubah menjadi kumpulan. Semua ini berteriak untuk melakukan langkah pemrosesan dalam buffer sementara, tetapi akan dibiarkan bagi pembaca sebagai latihan (atau penulis sebagai posting blog potensial).

wasamasa
sumber
4

Seperti ini terjadi dengan Python juga, solusi di python-mode.el, https://launchpad.net/python-mode , adalah terhubung ke proses secara langsung, bukan melalui comint-mode.

Mengandalkan start-processdan memproses-mengirim-string

Misalnya melihat fungsi py--start-fast-processdanpy--fast-send-string-intern

Andreas Röhler
sumber