- การแก้ไขข้อความในบรรทัดคำสั่งดูเหมือนเป็นฟีเจอร์พื้นฐาน แต่แต่ละโปรแกรมจัดการอินพุตไม่เหมือนกัน ทำให้ ปุ่มเดียวกันอาจทำงานแตกต่างกันโดยสิ้นเชิง
- ประสบการณ์ป้อนข้อมูลในเทอร์มินัลโดยทั่วไปแบ่งได้เป็น 4 แนวทาง: ไม่มีระบบอินพุต, GNU readline, ไลบรารีทางเลือกอย่าง
libedit, และระบบอินพุตของตัวเอง
- ในเครื่องมือง่าย ๆ อย่าง
cat, nc, dash ปุ่มลูกศรอาจถูกพิมพ์ออกมาเป็น ^[[D แต่ฟีเจอร์ที่เทอร์มินัลมีให้ เช่น Ctrl+W, Ctrl+U, Ctrl+C, Ctrl+Z ยังใช้งานได้
- เครื่องมือที่ใช้ readline เช่น
bash, psql, irb, python3 มีประวัติคำสั่ง, ปุ่มลูกศร, การค้นหาด้วย Ctrl+R, การเลื่อนด้วย Ctrl+A/Ctrl+E และสามารถใช้ rlwrap เพื่อเพิ่มประสบการณ์คล้ายกันให้เครื่องมืออื่นได้
- หากแยกแยะระบบอินพุตที่ใช้อยู่ได้ ก็จะตัดสินได้เร็วขึ้นว่าทำไมปุ่มลูกศรหรือ
Ctrl+R จึงแสดงผลต่างกัน และเลือกดูเอกสารหรือใช้ทางเลี่ยงอย่าง rlwrap ได้ง่ายขึ้น
ประสบการณ์ป้อนข้อมูลที่เปลี่ยนไปตามแต่ละโปรแกรม
- วิธีป้อนและแก้ไขข้อความในเทอร์มินัลแตกต่างกันมากตามแต่ละโปรแกรม
- ประเภทหลัก ๆ แบ่งได้ดังนี้
cat, nc, git commit --interactive เป็นต้น ไม่รองรับปุ่มลูกศร จึงอาจเห็นสตริงอย่าง ^[[D^[[D^[[C^[[C^
irb, python3 บน Linux เป็นต้น ใช้ไลบรารี readline เพื่อให้ฟีเจอร์แก้ไขพื้นฐานอย่างประวัติคำสั่งและปุ่มลูกศร
- บางกรณีอย่าง
/usr/bin/python3 บน Mac ปุ่มลูกศรทำงานได้ แต่ไม่รองรับ Ctrl+left หรือการค้นหาย้อนหลังด้วย Ctrl+R
fish, ipython3, micro, vim เป็นต้น ใช้ระบบอินพุตของตัวเอง
โหมด 1: สถานะพื้นฐานที่ไม่มีระบบอินพุต
- หากโปรแกรมรับแค่ข้อความด้วยการเรียกอย่าง
fgets() และไม่ได้มีฟีเจอร์แก้ไขแยกต่างหาก ปุ่มลูกศรอาจถูกแสดงเป็น escape sequence แทนที่จะเป็นคำสั่งแก้ไข
- ตัวอย่างเช่น เมื่อกดลูกศรซ้ายใน
dash จะเห็น ^[[D ถูกพิมพ์ลงในเทอร์มินัลดังนี้
$ ls l-^[[D^[[D^[[D
- ถึงอย่างนั้น ฟังก์ชันควบคุมพื้นฐานที่เทอร์มินัลมีให้ก็ยังคงอยู่
- ป้อนข้อความ
- Backspace
Ctrl+W: ลบคำก่อนหน้า
Ctrl+U: ลบทั้งบรรทัด
Ctrl+C: interrupt โปรเซส
Ctrl+Z: พักโปรเซสชั่วคราว
- แม้อยู่ในสภาพแวดล้อมแบบนี้ การใช้
Ctrl+W ก็ช่วยลบเป็นคำได้โดยไม่ต้องกด Backspace หลายครั้ง
- สามารถตรวจสอบ control code ที่เทอร์มินัลรองรับได้ด้วย
stty -a
โหมด 2: เครื่องมือที่ใช้ readline
- readline เป็นไลบรารี GNU ที่ทำให้การป้อนข้อความสะดวกขึ้น และใช้ในเครื่องมือแบบโต้ตอบจำนวนมาก
- คีย์ลัด readline ที่ใช้บ่อยมีดังนี้
Ctrl+E หรือ End: ไปท้ายบรรทัด
Ctrl+A หรือ Home: ไปต้นบรรทัด
Ctrl+left/right arrow: เลื่อนไปข้างหน้าหรือถอยหลังทีละคำ
- ลูกศรขึ้น: ไปยังคำสั่งก่อนหน้า
Ctrl+R: ค้นหาประวัติ
Ctrl+W, Ctrl+U ของโหมดพื้นฐานก็ใช้ได้เช่นกัน แต่ใน readline Ctrl+U จะลบตั้งแต่เคอร์เซอร์ถึงต้นบรรทัด ไม่ใช่ลบทั้งบรรทัด
- การค้นหาประวัติด้วย
Ctrl+R ใน bash เป็นฟีเจอร์ที่ readline มีให้
psql, irb, python3 เป็นต้น ก็เป็นตัวอย่างของโปรแกรมที่ใช้ readline
- ดูรายการคำสั่งแก้ไขของ readline ทั้งหมดได้ใน คู่มือ readline
เพิ่ม rlwrap ให้เครื่องมือที่ไม่มี readline
- แม้โปรแกรมอย่าง
nc จะไม่รองรับ readline แต่หากรันด้วย rlwrap nc ก็จะใช้งานได้คล้ายโปรแกรมที่รองรับ readline
- rlwrap สามารถเพิ่มความสะดวกในการใช้งานเครื่องมือที่ไม่มี readline ได้อย่างมาก
- ตั้งค่า autocomplete แบบกำหนดเองได้ด้วย แต่ไม่ใช่สิ่งที่ได้ลองใช้งานจริง
เหตุผลที่เครื่องมือไม่ใช้ readline
- มีหลายเหตุผลที่เครื่องมือบางตัวไม่ใช้ readline
- โปรแกรมที่เรียบง่ายมากอย่าง
cat, nc อาจไม่อยากเพิ่ม dependency ที่ค่อนข้างใหญ่
- readline ไม่ใช่ LGPL แต่เป็น ไลเซนส์ GPL จึงอาจไม่เข้ากับไลเซนส์ของโปรแกรม
- หากโปรแกรมมีเพียงบางส่วนที่เป็นแบบโต้ตอบ และอินพุตใกล้เคียงกับตัวอักษรเดี่ยวอย่าง
y หรือ n การรองรับ readline อาจมีลำดับความสำคัญต่ำ
git มีฟีเจอร์แบบโต้ตอบอย่าง git add -p แต่เมื่อจำเป็นต้องป้อนข้อความยาว ๆ ที่มีความหมาย ก็มักจะเปิด text editor แทน
idris2 ไม่ใช้ readline เพื่อลด dependency ให้น้อยที่สุด และแนะนำให้ใช้ rlwrap หากต้องการฟีเจอร์โต้ตอบที่ดีกว่า
วิธีตรวจสอบว่าตอนนี้ใช้ readline อยู่หรือไม่
- วิธีตรวจสอบที่ง่ายที่สุดคือลองกด
Ctrl+R
- หากเห็นพรอมป์ต์ต่อไปนี้ ก็มีโอกาสสูงว่ากำลังใช้ readline
(reverse-i-search)`':
- ไลบรารีอื่นก็อาจใช้คำเดียวกันได้ จึงไม่ใช่วิธีแยกแยะที่แน่นอน แต่ยังไม่พบระบบอื่นที่ใช้คำว่า
reverse-i-search สำหรับการค้นหาประวัติ
คีย์ลัด readline กับ Emacs
- คีย์ลัด
Ctrl+A เพื่อไปต้นบรรทัด และ Ctrl+E เพื่อไปท้ายบรรทัด อาจถือได้ว่ามาจาก Emacs
- ใน Emacs,
Ctrl+A และ Ctrl+E ก็ทำงานเหมือนกับ readline
- ในทางกลับกัน
Ctrl+W, Ctrl+U ไม่ได้ทำงานเหมือนกันใน Emacs กับเทอร์มินัล
- อ่านประวัติเพิ่มเติมของโปรเจกต์ readline ได้ที่ ประวัติโปรเจกต์ Readline
โหมด 3: ไลบรารีอินพุตทางเลือกอย่าง libedit
/usr/bin/python3 บน Mac ใกล้เคียงกับสถานะกึ่งกลางที่รองรับฟีเจอร์ readline เพียงบางส่วน
- ตัวอย่างเช่น เมื่อกด
Ctrl+left arrow อาจไม่ได้เลื่อนทีละคำ แต่พิมพ์ ;5D ออกมาแทน
$ python3
>>> importt subprocess;5D
- ในการติดตั้ง Python ค่าเริ่มต้นของ Mac OS โมดูล Python
readline จริง ๆ แล้วอิงกับ libedit
- คาดว่าเป็นเพราะ readline ใช้ไลเซนส์ GPL
- สามารถตรวจสอบได้ว่า Python ตัวนั้นใช้ libedit หรือไม่ด้วยคำสั่งต่อไปนี้
$ python3 -c "import readline; print(readline.__doc__)"
Importing this module enables command line editing using libedit readline.
- Python ที่ติดตั้งบน Linux หรือผ่าน Homebrew โดยทั่วไปจะใช้ readline
- Python 3.13 มีแผนจะถอด dependency ต่อ readline และใช้ไลบรารีของตัวเอง ดังนั้นในอนาคตคำกล่าวว่า “Python ใช้ readline” อาจไม่ถูกต้องเสมอไป
โหมด 4: ระบบอินพุตของตัวเอง
- โปรแกรมบางตัวใช้ระบบแก้ไขข้อความของตัวเอง และบางครั้งก็มีฟีเจอร์หลากหลายกว่า readline
- ตัวอย่างที่ใช้ระบบอินพุตของตัวเองมีดังนี้
- text editor บนเทอร์มินัลส่วนใหญ่ เช่น
nano, micro, vim, emacs
- เชลล์อย่าง
fish
- line editor ของ
zsh อย่าง zle
- REPL อย่าง
ipython
- เครื่องมืออย่าง
atuin
- ในระบบเหล่านี้อาจพบฟีเจอร์ต่อไปนี้
- autocomplete ที่ปรับให้เข้ากับเครื่องมือมากขึ้น
- การจัดการประวัติที่ดีกว่า รวมถึง syntax highlighting
- คีย์ลัดมากขึ้น
ระบบอินพุตของตัวเองที่ได้รับแรงบันดาลใจจาก readline
- Atuin เป็นเครื่องมือค้นหาประวัติเชลล์ และแม้การทำอินพุตจะเป็น implementation ของตัวเอง แต่ก็ได้รับแรงบันดาลใจจาก readline
- Atuin ใช้ประโยชน์จากการที่ผู้ใช้คุ้นเคยกับ key binding ของ readline ทำให้ key binding เหล่านั้นทำงานได้แม้ไม่ได้ใช้ readline โดยตรง
- prompt_toolkit ที่ IPython ใช้ก็รองรับตัวเลือกหลายอย่าง รวมถึง key binding สไตล์ vi
- ค่าเริ่มต้นของ prompt_toolkit คือการรองรับ key binding สไตล์ readline
- คล้ายกับที่หลายโปรแกรมรองรับ key binding พื้นฐานแบบ vim เช่น
j สำหรับลง และ k สำหรับขึ้น
- ตัวอย่างเช่น Fastmail รองรับ
j, k แม้คีย์ลัดส่วนใหญ่จะไม่ได้เกี่ยวข้องกับ vim มากนัก
- ระบบอินพุตของตัวเองที่ได้รับแรงบันดาลใจจาก readline อาจเข้ากันกับ readline ได้ไม่สมบูรณ์ในรายละเอียดปลีกย่อย แต่สำหรับผู้ใช้ที่ใช้เพียงคีย์ลัดพื้นฐานไม่กี่อย่าง ก็อาจไม่ใช่ปัญหาใหญ่
- ระบบแบบนี้โดยทั่วไปอาจมี autocomplete ดีกว่าการใช้ readline อย่างเดียว
เชลล์ที่รองรับโหมด vi
bash, zsh, fish ล้วนรองรับ โหมด vi สำหรับการป้อนข้อความ
- ใน แบบสำรวจที่ไม่เป็นวิทยาศาสตร์ บน Mastodon มี 12% ตอบว่าใช้โหมด vi
- readline เองก็มีโหมด vi และการรองรับโหมด vi ของ
bash ทำงานผ่านสิ่งนี้
- โปรแกรมอื่น ๆ จำนวนมากที่ใช้ readline ก็อาจมีโหมด vi ได้เช่นกัน
ลำดับการวินิจฉัยสถานะอินพุต
- หากรู้ว่าใช้ระบบอินพุตแบบใด ก็จะคาดเดาพฤติกรรมของบรรทัดคำสั่งได้ง่ายขึ้น
- ที่พรอมป์ต์อินพุต สามารถพิจารณาตามลำดับต่อไปนี้
- หากปุ่มลูกศรไม่ทำงาน มีโอกาสสูงว่าไม่มีระบบอินพุต แต่ยังใช้
Ctrl+W, Ctrl+U ได้ และหากจำเป็นก็เพิ่ม rlwrap ได้
- หาก
Ctrl+R แสดง reverse-i-search มีโอกาสสูงว่าเป็น readline และสามารถใช้คีย์ลัด readline ที่คุ้นเคยกับฟีเจอร์ประวัติพื้นฐานได้
- หาก
Ctrl+R ทำงานอย่างอื่น มีโอกาสสูงว่าเป็นไลบรารีอินพุตของตัวเอง ซึ่งโดยรวมอาจทำงานคล้าย readline และหากจำเป็นก็ควรตรวจเอกสาร
- ยังมีความซับซ้อนเกี่ยวกับอินพุตอื่น ๆ ที่ไม่ได้กล่าวถึงที่นี่
- ปัญหาเกี่ยวกับ
ssh, tmux
- ตัวแปรสภาพแวดล้อม
TERM
- ความแตกต่างของการรองรับคัดลอก·วางในแต่ละเทอร์มินัล เช่น GNOME Terminal, iTerm, xterm
- Unicode
- ปัญหาอื่น ๆ อีกหลายอย่างเกี่ยวกับอินพุต
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
บทความของ Julia ดีเสมอ สิ่งที่ยังขาดไปคือ ถ้าใช้
sttyในเชลล์สคริปต์ ก็สามารถเปลี่ยนพฤติกรรมหลายอย่างของเทอร์มินัลได้ รวมถึงวิธีจัดการอินพุตด้วยการทดลองที่เคยทำด้วย
shและstty: https://gist.github.com/alganet/63f1dbc97b8fd35f7bb14ec30f79...ในเทอร์มินัลที่เข้ากันได้กับ VT100 (mintty, xterm, Terminal.app, vscode ฯลฯ) สามารถจับและตีความคีย์ผสมส่วนใหญ่ รวมถึงเจสเจอร์เมาส์ (กด/ลาก/ปล่อย) ได้จากภายในเชลล์
เดโมที่รันได้คือ
bash -c "$(curl -L https://git.io/fjToH)"จากนั้นลองกดปุ่มหรือขยับเมาส์ดู ออกด้วย Ctrl+W รองรับ zsh และ ksh ด้วย แต่ไม่รองรับ dash เป็นต้นที่ไม่มีread -rn1นอกจากนี้ ถ้า pipe โปรแกรมแบบโต้ตอบไปที่
cat -vเช่นvi | cat -vก็จะเห็น VT100 escape ที่โปรแกรมนั้นใช้ และได้เรียนรู้อะไรมากจากการดูว่า vi ทำอย่างไรstty saneก็ย้อนกลับได้เปิดเทอร์มินัล 3 หน้าต่าง แล้วรัน 1)
man ascii, 2)nc -lvp 9001 | xxd -c1, 3)stty raw -echo; nc -nv 127.0.0.1 9001จากนั้นในเทอร์มินัลที่ 3 ให้ลองสร้างค่าในคอลัมน์ “Hex” ทั้งหมดของ manpage ตามลำดับจะสังเกตได้ว่าค่าบางค่าอาจสร้างได้หลายวิธี และปุ่มอื่นบางปุ่มก็ส่ง payload หลายไบต์
sttyและ raw mode ได้ดี: https://viewsourcecode.org/snaptoken/kilo/, https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode...พารามิเตอร์และสัญลักษณ์ของ
sttyที่ดูเหมือนเวทมนตร์นั้นมาจาก control sequences ที่นิยามไว้เมื่อนานมาแล้ว มาตรฐานที่คลุมเครือจากยุค 1970 อย่าง ECMA-48 ก็มีคำศัพท์เข้าใจยากจำนวนมากที่แทบไม่ใช้กันแล้วในปัจจุบันตัวอย่างเช่น Select Graphic Rendition(SGR) โดยคร่าว ๆ ก็เหมือนแท็ก HTML เวอร์ชันยุค 1970 หากจะตั้งค่าสี foreground จะใช้รูปแบบประมาณ
ESC[38;2;R;G;BmTextESC[0mโดยESC[คือ CSI,mคือ SGR,38คือสี foreground,2คือปริภูมิสี RGB, และ0คือการรีเซ็ตสไตล์โครงสร้างที่พารามิเตอร์มาก่อนคำสั่งจึงรู้สึกเหมือนกลับด้านอยู่บ้าง เทอร์มินัลก็เหมือนเบราว์เซอร์ คือแต่ละตัวมีขอบเขตและวิธี implement ไม่เหมือนกัน และทุกวันนี้ก็ยังเป็นเช่นนั้น สีรองรับได้ค่อนข้างดี แต่ฟีเจอร์อื่นไม่ใช่แบบนั้น เช่น
SGR<7>บอกว่าเป็นโหมด “negative image” แต่ในมาตรฐานไม่ได้อธิบายละเอียด บางเทอร์มินัลจึงแสดงแบบกลับสี ขณะที่บางตัวจัดการอีกแบบ ทำให้ทุกวันนี้ยังเกิดปัญหาอยู่เมื่อกว่า 20 ปีก่อน เคยทำ state machine บน readline เพื่อให้ใช้เป็น editor หลายบรรทัดจริง ๆ ที่เลื่อนขึ้นลงได้ ไม่ใช่แค่บรรทัดเดียวที่ wrap
วิดีโอ: https://github.com/colmmacc/jot/raw/master/jot-demo.mp4
CVS repository ของ Unix terminal IM client ที่มีฟีเจอร์นี้: https://c-hey.redbrick.dcu.ie/src/c-hey_cvs_latest/
เวลาเลื่อนขึ้นลงระหว่างบรรทัดจะติดตามและวาดเคอร์เซอร์ใหม่ และเมื่อขนาดเทอร์มินัลเปลี่ยนก็จะดู SIGWINCH แล้ววาดใหม่ อยากเขียนใหม่ด้วย Rust แล้วปล่อยเป็นไลบรารีเล็ก ๆ แต่ไม่มีเวลา แปลกใจมาตลอดที่ไม่มีใครทำอะไรคล้ายกัน
หลัง
autoload -Uz zedแล้วใช้zedเพื่อแก้ไขไฟล์ชั่วคราวและส่งต่อให้git commit -Fก็จะเริ่ม inline editor ที่มีทุกฟีเจอร์ของ ZLE ได้ บันทึกแล้ว commit ด้วยC-x C-wและยกเลิกด้วยC-cข้อดีของ implementation พื้นฐานนี้คือ
zedเป็น ZLE widget ใหม่ จึงควบคุม keymap ได้เต็มที่ โหมด emacs หรือโหมด vi ใช้งานได้ทันที และยังปรับแต่งเพิ่มได้อีกถ้าเขียน ZLE widget เอง ก็สามารถเรียกจากใน line editor ได้โดยตรง ไม่ต้อง wrap คำสั่งเหมือนข้างต้น
https://github.com/zsh-users/zsh/blob/master/Functions/Misc/...
git commitเอฟเฟกต์แบบ “เครื่องพิมพ์ดีดอินไลน์” ก็ดูเท่สิ่งที่บทความยังไม่ได้พูดถึง ได้แก่ อักขระแบบกว้าง, ปัญหาที่การกดปุ่มเดียวกันถูกแทนด้วย ANSI escape sequence ที่ต่างกันเพราะโหมดคีย์บอร์ดต่างกัน, ความแตกต่างของสถานะ TTY เช่น local echo, และรายละเอียดปลีกย่อยที่ system call สำหรับเปลี่ยนสถานะ TTY แตกต่างกันไปตามระบบปฏิบัติการ
การรองรับ terminal emulation ก็ไม่เหมือนกัน ปัจจุบันโดยทั่วไปจะเลียนแบบ xterm แต่แม้ในกลุ่มนั้นก็ไม่มีใครตั้งเป้าให้เข้ากันได้ 100%
วิธีตรวจสอบความสามารถที่เทอร์มินัลมีให้ก็ยังขาดฉันทามติ บางฝั่งส่ง ANSI escape sequence แล้วรอคำตอบ บางฝั่งดู
$TERMและบางเทอร์มินัลประกาศตัวเองเป็น xterm แต่กลับไม่สนใจ sequence ของฟีเจอร์ VT และตั้ง environment variable อื่นแทน พูดตรง ๆ คือเละยิ่งกว่า user agent string เสียอีกทั้งหมดนี้ยังอยู่บนสมมติฐานว่าเป็นระบบ POSIX ถ้าเอา Windows เข้ามาปนด้วยก็จะน่าสนใจขึ้นอีกเท่าตัว
ถ้าตั้ง
$EDITORใน bash เป็นเอดิเตอร์ที่ชอบไว้ สามารถกด Ctrl-X Ctrl-E เพื่อส่งบรรทัดปัจจุบันไปยัง$EDITORได้ หลังจากแก้ไขคำสั่งแล้วบันทึกและออก คำสั่งก็จะถูกเรียกทำงานvได้เลยfcก็ทำสิ่งเดียวกันได้ แค่พิมพ์fcโดยไม่ต้องใช้ชุดปุ่ม Ctrlยังสามารถเปิดคำสั่งก่อนหน้าด้วยเอดิเตอร์เฉพาะ แทนที่จะใช้
$EDITORค่าเริ่มต้นได้ด้วย เช่น ถ้าEDITOR=viแต่อยากแก้คำสั่งล่าสุดด้วย ed ก็ใช้fc -e edในโหมด vi ยังมีวิธีสร้างเชลล์สคริปต์อย่างรวดเร็วจากประวัติคำสั่งได้ด้วย ถ้าคำสั่งที่ต้องการอยู่ลำดับที่ 15 ใน history ก็ทำได้ประมาณ
fc 15แล้วตามด้วยw1.sh,%d,wqEDITOR=nvimกับ copilot.vim ใน Neovim ให้เหมือน AI shell autocomplete อยู่ ใช้ได้ค่อนข้างดีเห็นจากที่นี่: https://twitter.com/arjie/status/1575201117595926530?s=46&t=...
ในมุมของมือใหม่ Linux สงสัยว่าทำไมแค่โปรแกรมอ่านข้อความด้วยอะไรอย่าง
fgets()ก็ได้ฟีเจอร์อย่าง backspace, Ctrl+W, Ctrl+U มาฟรี ๆเอกสารของ
fgets()บอกว่าอ่านจนเจอ newline หรือ EOF เลยสงสัยว่าหมายความว่าโดยค่าเริ่มต้นมันจะบล็อกจนผู้ใช้ป้อน newline และก่อนหน้านั้นเทอร์มินัลจะช่วยแก้ไข line buffer ด้วย backspace หรือ Ctrl+W/Ctrl+U ให้ใช่ไหมแต่ก็ไม่ได้รับประกันว่าโปรแกรมจะอ่านทั้งบรรทัดเสมอไป และอาจส่ง
countเป็น 2 เพื่ออ่านทีละอักขระได้ ถ้าอย่างนั้นเมื่อเกิด backspace ก็ไม่น่าจะ “ย้อนคืน” อักขระที่อ่านไปแล้วได้ เลยสงสัยว่ามีเวทมนตร์อะไรในบัฟเฟอร์ภายในของfgets()หรือในกรณีแบบนั้นฟีเจอร์แก้ไขบรรทัดจะพังhttps://en.cppreference.com/w/c/io/fgets
ที่ดูเหมือน buffer ตาม newline นั้นจริง ๆ เป็นเพราะเชลล์จัดการเอง ดังนั้นนักพัฒนาจึงใส่ฟีเจอร์ การจัดการ text buffer ได้ เช่น tab completion หรือการเติม sudo ไว้หน้าบรรทัด
อักขระบนหน้าจอก่อนกด Enter อยู่ในหน่วยความจำของเทอร์มินัลเท่านั้น และ system call
readของแอปพลิเคชันจะบล็อกอยู่ที่ file descriptor ของเทอร์มินัล เทอร์มินัลจะไม่เขียนข้อมูลจนกว่าบรรทัดจะเสร็จสมบูรณ์ตอนนั้นการแก้ไขบรรทัดที่กำลังพิมพ์ก็มักเป็นสิ่งที่เทอร์มินัลเองมีให้ การที่ตัวอักษรปรากฏบนหน้าจอก็เป็นฟีเจอร์ echo ของเทอร์มินัล และ backspace, delete, Ctrl+C สำหรับ SIGINT, Ctrl+D สำหรับ EOF ก็เช่นกัน
line editor และ text editor จะปิดฟีเจอร์เหล่านี้ แล้วตั้งเป็น raw mode ทุกอย่างที่พิมพ์จะถูกส่งไปยังแอปพลิเคชันทันทีเพื่อให้จัดการเอง ตัวอย่างที่พบบ่อยคือ password prompt ที่ปิดเฉพาะ echo เพื่อซ่อนอักขระ
line ending แบบ Unix ดั้งเดิม
\nจริง ๆ แล้วก็เป็นฟีเจอร์ของเทอร์มินัลเช่นกัน จากมุมของเทอร์มินัล\nแค่ย้ายเคอร์เซอร์ลงไปหนึ่งบรรทัด ดังนั้นถ้าจะกลับไปต้นบรรทัดต้องมี\rด้วย line ending ที่แท้จริงคือ\r\nและเทอร์มินัลจะแปลง\nเป็น\r\nให้แบบมองไม่เห็น สิ่งนี้ก็ปิดได้เช่นกันใน raw mode จะไม่ทำงานแบบนี้
helpของ VMS ไปยัง SunOS อุปสรรคแรกคือทำอย่างไรให้ ตอบสนองต่อการกดปุ่มแต่ละครั้ง โดยไม่ต้องรอ Enter/Returnหัวหน้าตั้งใจแทบไม่ช่วย และปล่อยให้หาคำตอบเองเกือบทั้งหมดในปี 1986 ที่ยังไม่มีเว็บและแทบไม่มีหนังสือ O’Reilly จนถึงทุกวันนี้ก็ยังขอบคุณการตัดสินใจนั้นตลอดมา
เชลล์ dash ก็รองรับโหมดแก้ไขได้หากคอมไพล์ด้วย libedit ฝั่ง Debian น่าจะไม่ได้ทำแบบนั้นเพราะปัญหาเรื่องพื้นที่ แต่ถ้าต้องการให้คนที่เริ่มจาก bash ภายหลังต้องเรียนรู้น้อยลง ก็ควรรองรับไว้
มาตรฐาน POSIX ก็ระบุ
set -o viเป็นส่วนขยายแบบเลือกได้ ถ้าเชลล์ที่อ้างว่าเข้ากันได้กับ POSIX นำโหมดแก้ไขนี้ไปใช้ ก็ต้องรองรับset -o vi“
[set -o] vi: อนุญาตให้แก้ไขบรรทัดคำสั่งของเชลล์โดยใช้เอดิเตอร์ vi ในตัว เมื่อเปิดโหมด vi แล้ว ต้องปิดโหมดแก้ไขบรรทัดคำสั่งอื่น ๆ ที่มีให้ในฐานะส่วนขยายของ implementation”https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...
ผม/ฉันคิดมาตลอดว่าเทอร์มินัลเป็นปัจจัยเดียวที่ทำให้ Linux ถูกตรึงไว้กับ ส่วนแบ่งตลาดต่ำกว่า 5% ไปตลอดกาล
ไม่ใช่แค่การป้อนข้อความที่เป็นปัญหา แต่ประสบการณ์ทั้งหมดมันซับซ้อน ประชากร 95% แค่อยากบินโดรน แต่กลับถูกยื่นห้องนักบิน Concorde ที่ไม่มีป้ายกำกับใด ๆ มาให้
https://qph.cf2.quoracdn.net/main-qimg-2566f4c91b894e4169d77..., https://media.thedroningcompany.com/images/tincy/WQZpC56vqMp...
การที่มีห้องนักบิน Concorde อยู่เบื้องหลัง Ubuntu และผม/ฉันสามารถเข้าถึงมันได้บนโน้ตบุ๊ก Ubuntu ที่ใช้ทำงาน กลับเป็นเรื่องที่น่าขอบคุณด้วยซ้ำ ถ้าไม่มีระดับการควบคุมแบบนั้นคงไม่ชอบ
ในทางกลับกัน โน้ตบุ๊กของแม่ก็เป็น Ubuntu และโน้ตบุ๊กของแฟนเป็น Manjaro ทั้งคู่ใช้งานได้ดีโดยแค่ “บินโดรน” ไม่เคยย่างเท้าเข้าไปในห้องนักบิน Concorde เลย แน่นอนว่าผม/ฉันใช้ Arch
เทอร์มินัลเป็นเครื่องมือของนักพัฒนาและผู้ดูแลระบบ ที่ดูเหมือนเป็นอย่างนั้นก็เพราะผู้ใช้ GNU/Linux บนเดสก์ท็อปส่วนใหญ่เป็นนักพัฒนาและผู้ดูแลระบบ ซึ่งเป็นแค่ไม่กี่เปอร์เซ็นต์ของประชากร
ที่ต้องจำชอร์ตคัตแปลก ๆ เยอะกลับเป็นเทอร์มินัลของ macOS ซึ่งทุกอย่างถูกทำให้ไม่เป็นธรรมชาติที่สุดเท่าที่จะทำได้
อาจเป็นความเห็นที่ไม่เป็นที่นิยม แต่ใน iTerm2 ผม/ฉันเปลี่ยนไปใช้พรีเซ็ต Natural text editing เพื่อให้ตรงกับชอร์ตคัตแก้ไขแบบดั้งเดิมของ macOS
เพราะภายในแอปเทอร์มินัล โดยปกติมันจะรีแมปกลับเป็น control sequence ให้ จึงมีข้อดีคือได้ฟังก์ชันนี้แทบทุกที่ โดยไม่ต้องไปเปลี่ยนหลายจุดหรือกังวลเรื่องการรองรับ readline
มันไม่สมบูรณ์แบบ บางครั้งมี sequence ที่ต้องป้อนเองถูกรีแมปไปด้วย แต่เพราะตรงกับ muscle memory เลยทำให้ใช้การแก้ไขคำสั่งบ่อยขึ้นมาก
https://pliszko.com/blog/post/2021-10-31-natural-text-editin...
ไม่อยากให้การแก้ไขข้อความในเทอร์มินัลทำงานแบบพิเศษแตกต่างออกไป
readline key binding พื้นฐานสามอย่างที่ถ้าผู้คนรู้แล้วชีวิตจะดีขึ้นคือ Ctrl+W, Ctrl+O, Ctrl+R
Ctrl+W ลบคำสุดท้าย ตามที่ Julia กล่าวถึงในบทความ
Ctrl+O รันบรรทัดที่ดึงมาจากประวัติ แล้วดึงบรรทัดถัดไปในประวัติขึ้นมาอีกครั้ง ถ้าเลื่อนไปยังคำสั่งแรกในประวัติแล้วกด Ctrl+O ห้าครั้ง ก็สามารถรันคำสั่งห้าคำสั่งตามลำดับได้
Ctrl+R ค้นหาย้อนกลับในประวัติขณะพิมพ์สตริงค้นหา กด Ctrl+R อีกครั้งเพื่อไปผลลัพธ์ก่อนหน้า และ Ctrl+S เพื่อเลื่อนไปข้างหน้าตามเวลา รันด้วย Enter หรือ Ctrl+O
ถ้าจะใช้คีย์ผสมนั้นกับฟังก์ชันค้นหาไปข้างหน้า ก็ต้องรู้ว่าทำไมมันไม่ทำงาน และต้องเต็มใจปิด XOFF ด้วย
ใน Windows Terminal นั้น Ctrl+C ทำงานได้ถูกต้องเสมอ ถ้ากำลังเลือกข้อความอยู่ก็จะคัดลอก และถ้าไม่ได้เลือกอยู่ก็จะฆ่าโปรเซสที่กำลังรันอยู่
แอปเทอร์มินัลบน Linux ไม่ใช้ Ctrl+C เพื่อคัดลอก แต่บังคับให้ใช้ Ctrl+Shift+C ส่วนการวาง ถ้ากด Ctrl+V ก็จะมีอักขระแปลก ๆ ถูกใส่เข้ามา และแอปอื่น ๆ ก็ใช้ Ctrl+V กันหมด เลยโดน muscle memory เล่นงานอยู่เรื่อย ๆ
เลยสงสัยว่ามีแอปเทอร์มินัลบน Linux ที่ทำงานเหมือน Windows Terminal และไม่ตีหลังมือเราว่า “ใช้เทเลไทป์ไม่เหมาะสม” บ้างไหม
วิธีนี้ใช้บัฟเฟอร์ Xorg แยกต่างหาก ดังนั้นหลังจากคัดลอกอะไรสักอย่างด้วย Ctrl+C แล้วไปเลือกข้อความอื่น Ctrl+V จะวางอันแรก ส่วนการคลิกกลางจะวางอันที่สอง
บน Windows หรือสมาร์ตโฟน บางทีก็น่าหงุดหงิดเวลาที่แค่เลือกอะไรไว้แล้วลืมกดอย่าง Ctrl+C
คิดว่าในบรรดาเทอร์มินัลบน Linux คงไม่มีตัวไหนที่ทำเหมือน Windows Terminal เพราะโปรแกรมที่กำลังรันอยู่ในเทอร์มินัลอาจอยากจัดการ Ctrl+C เองก็ได้ ตัวอย่างเช่นโปรแกรมแก้ไขข้อความ และตัวเทอร์มินัลเองก็ไม่รู้ด้วยซ้ำว่าตอนนี้มีโปรแกรมอะไรที่กำลังรันอยู่ เพราะการควบคุมงานเป็นหน้าที่ของเชลล์
map ctrl+c copy_or_interruptก็พอhttps://sw.kovidgoyal.net/kitty/actions/#action-copy_or_inte...