- Chỉ ra độ phức tạp và những giới hạn của kiến trúc terminal hiện tại, đồng thời đưa ra khái niệm terminal thế hệ mới tích hợp lại theo cách mới giữa nhập liệu, xuất liệu và điều khiển tiến trình
- Lấy Jupyter Notebook làm hình mẫu để khám phá khả năng hiện thực hóa giao diện tương tác như render hình ảnh, chạy lại lệnh, đầu ra có thể chỉnh sửa và trình soạn thảo tích hợp
- Thông qua các trường hợp của Warp và iTerm2, bài viết giải thích cụ thể về tích hợp sâu giữa shell và terminal (shell integration), quản lý tiến trình chạy dài và chức năng tách/khôi phục phiên
- Dựa trên theo dõi luồng dữ liệu (dataflow tracking) và tính bền vững (persistence), bài viết hình dung các khả năng mở rộng như undo/redo cho lệnh, tự động chạy lại và terminal cộng tác
- Đề xuất chiến lược xây dựng theo từng bước để phát triển từ CLI mang tính giao dịch → phiên bền vững → RPC có cấu trúc → frontend kiểu Jupyter
Cấu trúc cơ bản của terminal
- Terminal gồm bốn thành phần: trình giả lập terminal, terminal ảo (PTY), shell, nhóm tiến trình
- Trình giả lập terminal là chương trình render cấu trúc lưới lên màn hình
- PTY là trạng thái bên trong kernel, chịu trách nhiệm chuyển đầu vào tới nhóm tiến trình và biến đổi tín hiệu (signal)
- Shell đóng vai trò một event loop: đọc đầu vào, phân tích cú pháp và tạo tiến trình
- Các tiến trình tương tác với những thành phần trên thông qua đầu vào và đầu ra
- Đầu vào không chỉ là văn bản đơn thuần mà còn bao gồm tín hiệu (signal), còn đầu ra gồm các chuỗi escape ANSI để biểu diễn định dạng
Hình dung về một terminal tốt hơn
- Terminal hiện tại có nhiều ràng buộc chức năng nên thiếu khả năng mở rộng và tính tương tác
- Jupyter Notebook cung cấp những khả năng mà trình giả lập VT100 truyền thống không làm được
- Render hình ảnh độ phân giải cao
- Nút “chạy lại từ đầu” để thay thế đầu ra cũ thay vì nối thêm đầu ra mới
- Một “view” cho phép viết lại tại chỗ mã nguồn và đầu ra (ví dụ: hiển thị Markdown ở dạng nguồn hoặc HTML đã render)
- Trình soạn thảo tích hợp có tô sáng cú pháp, tab, panel và hỗ trợ chuột
- Tuy nhiên, ý tưởng dùng shell làm kernel cho Jupyter Notebook gặp nhiều vấn đề
- Shell nhận lệnh theo từng khối nên tab completion, tô sáng cú pháp và gợi ý tự động không hoạt động
- Vấn đề xử lý tiến trình chạy lâu: Jupyter về cơ bản chạy cho tới khi một cell hoàn tất; có thể hủy nhưng không thể tạm dừng, tiếp tục, tương tác hay xem tiến trình đang chạy
- Nút “chạy lại cell” có thể gây vấn đề cho trạng thái máy tính, nhất là khi có các lệnh như
rm -rf
- Undo/redo không hoạt động
Nó sẽ hoạt động như thế nào?
-
Tích hợp shell (Shell Integration)
- Terminal Warp xây dựng tích hợp gốc giữa terminal và shell
- Terminal hiểu được thời điểm bắt đầu và kết thúc của từng lệnh, đầu ra và cả đầu vào của người dùng
- Được triển khai bằng tính năng tiêu chuẩn (DCS do người dùng định nghĩa)
- iTerm2 cũng có thể dùng mã escape OSC 133 theo cách tương tự
- Di chuyển giữa các lệnh bằng một phím tắt duy nhất
- Thông báo khi lệnh hoàn tất
- Khi đầu ra trôi khỏi màn hình, hiển thị lệnh hiện tại dưới dạng “overlay”
-
Quản lý tiến trình chạy dài
- Tương tác (interacting):
- Để tương tác với tiến trình chạy lâu cần giao tiếp hai chiều
- Ví dụ TUI:
top, gdb, vim
- Jupyter có thế mạnh ở thiết kế đầu ra tương tác có thể thay đổi và cập nhật
- Chức năng terminal được kỳ vọng: luôn có một “ô nhập tự do”
- Tiến trình tương tác chạy ở phía trên cửa sổ, còn phía dưới là ô nhập liệu
- Tạm dừng (suspending):
- Việc “tạm dừng” tiến trình được gọi là “điều khiển tác vụ (job control)”
- Terminal hiện đại được kỳ vọng sẽ hiển thị trực quan liên tục các tiến trình bị tạm dừng và chạy nền
- Tương tự cách IntelliJ hiển thị “Đang lập chỉ mục...” ở thanh công việc phía dưới
- Ngắt kết nối (disconnecting): có ba cách tiếp cận cho việc tách/khôi phục phiên
- Tmux / Zellij / Screen: chèn thêm một trình giả lập terminal giữa terminal emulator và chương trình. Server sở hữu PTY và render đầu ra, còn client hiển thị đầu ra trên terminal emulator thực. Có thể tách client, kết nối lại và cho nhiều client kết nối đồng thời. iTerm có thể hoạt động như một client riêng giao tiếp trực tiếp với server, bỏ qua tmux client
- Mosh: thay thế SSH. Hỗ trợ kết nối lại vào phiên terminal sau khi mạng bị gián đoạn. Chạy một state machine ở phía server và phát lại cho client các khác biệt tăng dần của viewport. Multiplexing và scrollback được kỳ vọng do terminal emulator xử lý. Vì client thực sự chạy ở phía mạng cục bộ nên chỉnh sửa dòng lệnh cục bộ diễn ra tức thì
- alden/shpool/dtach/abduco/diss: chỉ xử lý tách/tiếp tục phiên theo mô hình client/server, không bao gồm mạng hay scrollback, cũng không có trình giả lập terminal riêng. Đây là mức tách rời cao hơn so với tmux và mosh
-
Chạy lại và hoàn tác
- Giải pháp là theo dõi luồng dữ liệu
- pluto.jl hiện đã triển khai điều này bằng cách kết nối với trình biên dịch Julia
- Cập nhật theo thời gian thực các cell phụ thuộc vào cell trước đó
- Không cập nhật cell nếu phụ thuộc không thay đổi
- Một kiểu Jupyter giống bảng tính, chỉ chạy lại mã khi cần
- Có thể khái quát hóa thông qua tính bền trực giao (orthogonal persistence)
- Đưa tiến trình vào sandbox và theo dõi mọi I/O, từ đó ngăn những thứ “quá kỳ lạ” miễn là nó không giao tiếp với tiến trình khác bên trong sandbox
- Có thể coi tiến trình là hàm thuần của đầu vào, trong đó đầu vào là “toàn bộ hệ thống tệp, mọi biến môi trường và mọi thuộc tính tiến trình”
Các tính năng phái sinh
- Cần frontend Jupyter:
- Runbook (thực tế có thể xây chỉ với Jupyter và các primitive PTY)
- Tùy biến terminal bằng CSS thông thường mà không cần ngôn ngữ tùy chỉnh kỳ lạ hay mã màu ANSI
- Tìm kiếm lệnh theo đầu ra/dấu thời gian: hiện có thể tìm trong toàn bộ đầu ra của phiên hiện tại hoặc toàn bộ lịch sử nhập lệnh, nhưng không có bộ lọc thông minh và đầu ra không tồn tại xuyên suốt giữa các phiên
- Cần tích hợp shell:
- Dấu thời gian và thời lượng chạy của từng lệnh
- Chỉnh sửa dòng lệnh cục bộ ngay cả khi vượt qua ranh giới mạng
- IntelliSense cho lệnh shell mà không cần bấm tab, với render tích hợp trong terminal
- Cần theo dõi sandbox:
- Tất cả khả năng của theo dõi sandbox: terminal cộng tác, truy vấn các tệp bị lệnh sửa đổi, asciinema có thể chỉnh sửa khi chạy, theo dõi hệ thống build
- Mở rộng tìm kiếm thông minh để có thể tìm theo trạng thái đĩa tại thời điểm lệnh được chạy
- Mở rộng undo/redo theo mô hình phân nhánh tương tự git (emacs undo-tree đã hỗ trợ), đồng thời cung cấp nhiều “view” của cây tiến trình
- Nhờ mô hình undo-tree và sandboxing, có thể cấp cho LLM quyền truy cập dự án và chạy song song nhiều phiên cùng lúc mà không ghi đè trạng thái của nhau; có thể kiểm tra, chỉnh sửa kết quả công việc và lưu lại dưới dạng runbook để dùng sau
- Trong môi trường production, có thể có một terminal chỉ kiểm tra trạng thái hiện có mà không ảnh hưởng đến trạng thái máy
Chiến lược xây dựng theo từng bước
-
Giai đoạn 1: ngữ nghĩa giao dịch (transactional semantics)
- Khi thiết kế lại terminal, bắt đầu từ terminal emulator là cách tiếp cận sai
- Người dùng thường gắn bó với emulator của mình cùng các thiết lập cấu hình, giao diện và key binding
- Chi phí chuyển đổi emulator rất cao
- Bắt đầu từ lớp CLI mới là hướng đi đúng
- Chương trình CLI dễ cài đặt và chạy, chi phí chuyển đổi rất thấp
- Có thể dùng một lần mà không thay đổi toàn bộ workflow
- Viết một CLI hiện thực ngữ nghĩa giao dịch cho terminal
- Giao diện như
transaction [start|rollback|commit]
- Mọi thứ chạy sau
start đều có thể hoàn tác
- Chỉ riêng điều này cũng đủ để xây dựng cả một doanh nghiệp
-
Giai đoạn 2: Phiên bền vững (Persistent Sessions)
- Sau khi có ngữ nghĩa giao dịch, tách phần tính bền vững ra khỏi tmux và mosh
- Để có được tính bền vững cho PTY, cần áp dụng mô hình client/server
- Kernel mặc định giả định hai đầu của PTY luôn được kết nối
- Có thể hiện thực đơn giản bằng các lệnh như alden hoặc thư viện tương tự mà không ảnh hưởng tới terminal emulator hay các chương trình đang chạy trong phiên PTY
- Để có scrollback, server sẽ lưu trữ I/O vô thời hạn và phát lại khi client kết nối lại
- Terminal emulator cung cấp scrollback gốc như thể đó là đầu ra thông thường
- Có thể phát lại và tiếp tục từ điểm bắt đầu tùy ý
- Cần phân tích cú pháp mã escape ANSI nhưng hoàn toàn khả thi với đủ công sức
- Để tiếp tục kết nối mạng như mosh, dùng Eternal TCP (có thể xây trên QUIC để hiệu quả hơn)
- Tách riêng tính bền vững của PTY và tính bền vững của kết nối mạng
- Eternal TCP chỉ là tối ưu hóa thuần túy: có thể xây trên một script bash chạy vòng lặp
ssh host eternal-pty attach
- Tới thời điểm này, giống tmux, có thể kết nối nhiều client vào cùng một phiên terminal, còn quản lý cửa sổ vẫn do terminal emulator xử lý
- Nếu muốn quản lý cửa sổ tích hợp, terminal emulator có thể dùng giao thức tmux -CC như iTerm
- Mọi phần của giai đoạn này đều có thể làm song song, độc lập với ngữ nghĩa giao dịch, nhưng riêng chúng vẫn chưa đủ để xây dựng doanh nghiệp
-
Giai đoạn 3: RPC có cấu trúc
- Phụ thuộc vào mô hình client/server
- Khi server nằm giữa terminal emulator và client, có thể hiện thực các tính năng như gắn thẻ I/O bằng metadata
- Có thể thêm dấu thời gian cho mọi dữ liệu
- Có thể phân biệt đầu vào và đầu ra
- xterm.js hoạt động theo cách tương tự
- Khi kết hợp với tích hợp shell, có thể phân biệt ở tầng dữ liệu giữa shell prompt và đầu ra chương trình
- Có được nhật ký có cấu trúc của phiên terminal
- Phát lại nhật ký như một bản ghi tương tự asciinema
- Biến đổi shell prompt mà không cần chạy lại mọi lệnh
- Nhập vào Jupyter Notebook hoặc Atuin Desktop
- Lưu lệnh và chạy lại sau dưới dạng script
- Terminal trở thành dữ liệu
-
Giai đoạn 4: Frontend kiểu Jupyter
- Đây là giai đoạn đầu tiên thực sự động đến terminal emulator, và chủ ý để nó ở cuối
- Vì chi phí chuyển đổi là cao nhất
- Tận dụng mọi tính năng đã xây dựng để cung cấp một UI tốt
- CLI
transaction không còn cần thiết nữa, trừ khi muốn các giao dịch lồng nhau
- Toàn bộ phiên terminal mặc định sẽ bắt đầu như một giao dịch
- Vì đã kết hợp được mọi mảnh ghép nên có thể cung cấp tất cả các tính năng phái sinh đã nêu ở trên
Kết luận
- Kiến trúc này được kỳ vọng là táo bạo, đầy tham vọng và có thể mất tới khoảng 10 năm để xây xong toàn bộ
- Cần kiên nhẫn và tiến từng bước
- Hy vọng bài viết này sẽ truyền cảm hứng cho ai đó bắt tay xây dựng nó
1 bình luận
Ý kiến trên Hacker News
Đọc hết bài viết thì lúc đầu tôi thấy nó giống một danh sách mong muốn kiểu NIH hơn
Trong khi đã có nhiều phương án thay thế terminal, bài lại không hề nhắc đến
Ví dụ, Emacs là một VM dựa trên Lisp, rất dễ định nghĩa lại hàm và các lệnh thực chất là những hàm có chú thích. Đầu ra được quản lý bằng buffer, nhiều cửa sổ và frame có thể được sắp xếp theo dạng tile. Có thể dùng nguyên CLI (vterm, eat, v.v.) hoặc chuyển sang luồng REPL (shell-mode, eshell, v.v.). Nó cũng hỗ trợ đồ họa, dù không phải ngữ cảnh 2D hoàn chỉnh
Một ví dụ khác là Acme, khá giống Emacs nhưng là một môi trường văn bản tương tác nơi mọi văn bản đều có thể trở thành lệnh. Smalltalk cũng có triết lý tương tự, nhưng gần với IDE hơn
Tôi đã dùng GPTel trong Emacs để tự động cắt một file PDF giáo trình tiếng Latin cũ, rồi chuyển nó sang định dạng org-mode bằng OCR. Kết quả là khi chọn một từ thì có thể tra từ điển ngay, còn khi chọn một câu thì LLM sẽ phân tích ngữ pháp. Một trình soạn thảo văn bản từ thập niên 1970 đã biến thành nền tảng học tập của tương lai
Những nền tảng như Emacs, Jupyter hay VSCode rất mạnh, nhưng chúng là các nền tảng dựa trên tùy biến hơn là ứng dụng hoàn chỉnh.
Nếu thật sự là đổi mới, nó nên được phân phối theo cách có thể tái tạo dễ dàng dưới dạng container Docker hoặc file thực thi, thay vì cần cấu hình phức tạp
Tôi nghi ngờ việc khái niệm kế tiếp của terminal nhất thiết phải dựa trên văn bản
Terminal của tương lai có thể ở dạng API, hoặc hỗ trợ gọi từ xa qua xác thực OAuth. Đầu vào và đầu ra có thể không còn là văn bản CLI nữa.
Thay vào đó, có thể chuyển sang đầu vào/đầu ra dựa trên đối tượng, để lệnh và cấu trúc dữ liệu có thể được khám phá qua API.
Terminal là di sản của thập niên 70, và ngày nay hoàn toàn có thể có những lựa chọn tốt hơn
Nếu thêm đầu ra JSON thì có thể ghép pipeline với các công cụ như
jq.Nhờ triết lý “worse is better” coi sự đơn giản là ưu điểm, nó đã tiến hóa suốt hàng chục năm
Nếu truyền các đối tượng tự mô tả như PowerShell thì khả năng kết hợp sẽ mạnh hơn nhiều
Tôi có tổng hợp ví dụ liên quan trong bài blog của mình
Dòng chảy trực quan dựa trên lệnh dần biến mất, và bạn phải ghi nhớ cấu trúc API.
Nếu có tự động hoàn thành bằng AI và khả năng khám phá cấu trúc đối tượng, điểm yếu này có thể được bù đắp
https://www.nushell.sh/
Tuy vậy, một terminal tiến hóa dựa trên văn bản vẫn thú vị nếu có đề xuất cụ thể có thể hình dung được
Lý do terminal còn tồn tại đến giờ là vì khả năng tương thích và tự động hóa
Nó dễ script hơn GUI, và mọi thứ đều có thể tái tạo cũng như có thể tìm kiếm
Trước đây tôi thấy việc chuyển alt-screen của Neovim khá khó chịu, nhưng những chi tiết UX nhỏ như vậy cũng rất quan trọng
Khi lần đầu tiếp xúc với máy tính, và sau đó là khi học terminal, tôi đã phải lòng hai lần
Một số dự án liên quan gồm
18 tháng trước tôi đã thử một thí nghiệm tương tự trong Windows Terminal
Có ghi lại trong bình luận GitHub
Nhưng sau khi dùng Polyglot Notebooks, tôi chuyển hẳn vì thấy nó tự nhiên hơn nhiều
Đổi backend mệnh lệnh sang kernel Jupyter rồi dùng như một tài liệu tương tác kiểu notebook hiệu quả hơn hẳn
Trước đây tôi từng làm một dự án tên là TopShell, xây dựng shell + terminal dựa trên lập trình hàm
https://github.com/topshell-language/topshell#readme
Nó có tiềm năng, nhưng để trở thành một lựa chọn thay thế hoàn chỉnh thì vẫn còn rất nhiều việc phải làm
Tôi đang tìm một terminal có thể hiển thị hình ảnh hoặc video
Sẽ rất hay nếu có một terminal đơn giản hoạt động như trình duyệt.
Ví dụ như có thể mở tương tác ngay bằng lệnh kiểu
browser google.com/mapsfbi,omxplayer, v.v.)Đây là đề xuất mở rộng pseudo-terminal (PTY) bằng cách thêm kênh out-of-band dựa trên JSON-RPC
Các escape sequence hiện có có quá nhiều giới hạn.
Cách này cho phép chuyển đổi dần dần và tương thích ngược.
Có thể thương lượng tính năng như LSP hay MCP, còn kernel chỉ cần cung cấp kênh là đủ
Như vậy pipeline và redirect vẫn hoạt động nguyên vẹn, đồng thời vẫn giữ được đầu ra có màu