8 điểm bởi GN⁺ 2026-03-12 | 5 bình luận | Chia sẻ qua WhatsApp
  • những giới hạn của trình soạn thảo Howl hiện tại (ngừng phát triển, tìm kiếm chậm, không tương thích SSH, không hỗ trợ terminal), tác giả đã tự phát triển một trình soạn thảo văn bản TUI mới
  • Đã thử 13 trình soạn thảo như Helix, VS Code, Vim, Neovim, Emacs... nhưng không có trình nào mang lại cảm giác thao tác (Fingerspitzengefühl) như mong muốn
  • Ban đầu chỉ triển khai tập chức năng tối thiểu phù hợp cá nhân, còn hiệu năng, Unicode, hỗ trợ đa ngôn ngữ... được để lại phía sau và mở rộng dần
  • Trong quá trình phát triển, tác giả tự triển khai engine regex riêng, trình duyệt tệp, rendering dựa trên TUI, tích hợp terminal buffer...
  • Đã áp dụng nhiều kỹ thuật tối ưu hiệu năng cho tìm kiếm toàn dự án, tô sáng cú pháp, xử lý cache, phân phối công việc đa luồng...
  • Kết quả là tác giả hoàn thiện được một công cụ khớp hoàn hảo với workflow của riêng mình, đồng thời tìm lại năng suất và niềm vui khi lập trình

Giới hạn của trình soạn thảo cũ và quá trình tìm kiếm lựa chọn thay thế

  • Các vấn đề của trình soạn thảo Howl đã dùng khoảng 10 năm là động lực khiến tác giả bắt tay tự phát triển
    • Dự án đã ngừng phát triển suốt nhiều năm nên tác giả phải tự duy trì fork, nhưng vì được viết bằng MoonScript nên khó sửa sâu
    • Hiệu năng tìm kiếm tệp trên toàn dự án không đủ tốt, khiến luồng làm việc thường xuyên bị ngắt quãng
    • Vì là trình soạn thảo GUI nên không thể dùng từ xa qua kết nối SSH
    • Không có terminal tích hợp, nên khi chạy lệnh bên ngoài không thể tương tác trực tiếp, và hầu hết mã escape ANSI cũng không được hỗ trợ
  • Đã thử 13 trình soạn thảo gồm Helix, VS Code, Sublime Text, Vim, Zed, Neovim, Emacs, Geany, Micro, Lite XL, Lapce, GNOME Builder, Kakoune
    • Mỗi cái đều có ưu điểm riêng, nhưng không đáp ứng được cảm giác thao tác (Fingerspitzengefühl) mà tác giả muốn
    • Helix là trình được dùng lâu nhất, nhưng sau một tháng thì mất hứng thú

Chiến lược phát triển ban đầu

  • Ở giai đoạn khởi đầu, tác giả giới hạn phạm vi ở mức tối thiểu
    • Loại bỏ các tính năng phục vụ người dùng khác ngoài bản thân, mọi cấu hình đều được hardcode
    • Tạm hoãn tối ưu hiệu năng và bắt đầu với buffer dựa trên String
    • Không theo đuổi hỗ trợ đầy đủ cho Unicode grapheme; chỉ cần ký hiệu £ chiếm một cột là đủ
    • Tô sáng cú pháp chỉ hỗ trợ một vài ngôn ngữ thường dùng, còn lại thay bằng tô sáng dựa trên bộ phân tách chung
  • Ở lần thử thứ hai, tác giả xây dựng trước một framework TUI đơn giản, nhưng về sau phần lớn đã bị gỡ bỏ để chuyển sang cách tiếp cận trực tiếp và chi tiết hơn

Thực hành dogfooding

  • Khi trình soạn thảo đạt ngưỡng chức năng tối thiểu: mở, chỉnh sửa và lưu được một tệp, tác giả bắt đầu ba thói quen
    • Dùng chính trình soạn thảo tự làm thay cho nano để ép bản thân sử dụng, từ sửa tệp hệ thống đến ghi chú
    • Mỗi khi phát hiện thiếu tính năng, lỗi, hành vi lạ hay giới hạn, đều ghi lại vào README.md của dự án
    • Những vấn đề gây khó chịu rõ rệt thì sửa ngay lập tức
  • Ba thói quen này khiến lượng thời gian làm dự án tăng từ 1 giờ mỗi tháng lên vài giờ mỗi tuần
  • Trong tổng khoảng 10.000 dòng mã, gần như toàn bộ được viết trong 6 tháng gần đây

Điều khiển con trỏ

  • Điều khiển con trỏ là một trong những phần khó triển khai nhất
    • Các tổ hợp phím như ctrl + shift + left nghe có vẻ hiển nhiên với người dùng, nhưng logic bên dưới lại phức tạp
  • Lời khuyên cốt lõi là triển khai đầu vào cấp cao thành tổ hợp các thao tác nguyên thủy
    • Ví dụ: backspace theo từng từ có thể tách thành di chuyển con trỏ theo từ + chọn vùng + xóa
  • Khi triển khai undo/redo, ba thao tác này phải được gom thành một nhóm thì kết quả mới trực quan
  • Tác giả cũng hiểu hơn vì sao các modal editor lại phơi bày trực tiếp những thao tác nguyên thủy này cho người dùng

Trình duyệt tệp

  • Trình duyệt tệp của Howl là lý do quyết định khiến tác giả khó chuyển sang editor khác
    • Bộ lọc mờ cập nhật tức thì rất xuất sắc, đến mức thường chỉ cần gõ 1–2 phím là tìm được tệp muốn mở
    • Nếu tệp chưa tồn tại thì có thể tạo ngay tại chỗ
    • Khi nhập ~/, nó sẽ tự chuyển sang thư mục home
    • Có thể xem bản xem trước của tệp sắp mở ngay trong vùng chỉnh sửa chính
  • Tác giả không hài lòng với cách các editor khác giải quyết bài toán mở tệp bằng phụ thuộc chuột, hộp thoại GTK mặc định, đoán tên tệp...
  • Khi tự triển khai, tác giả thấy không cần đến những cách phức tạp như Levenshtein distance, chỉ ba tiêu chí đơn giản là đủ
    • bắt đầu bằng chuỗi lọc hay không
    • chứa chuỗi lọc hay không
    • Thời gian sửa đổi/truy cập gần đây nhất
  • Cho phép so khớp không phân biệt hoa thường, nhưng nếu khớp đúng hoa thường thì được tăng hạng nhẹ
  • Ngay cả trong dự án có hàng chục nghìn tệp, sau 2 lần gõ vẫn có khoảng 95% xác suất tệp cần tìm nằm trong top 2

Engine regex

  • Regex được dùng ở ba nơi: tìm kiếm toàn dự án, tô sáng cú pháp và tìm trong buffer
  • Lý do tác giả tự triển khai thay vì dùng crate regex-automata hiện có
    • Cần xử lý các edge case phụ thuộc ngữ cảnh như cú pháp raw string của Rust
    • Bản thân dự án cũng là bài tập để tự xây stack riêng và hiểu sâu nó
  • Phiên bản đầu tiên dùng crate parser chumsky để phân tích cú pháp regex, rồi duyệt AST cho từng ký tự, nên rất chậm
  • Sau đó tác giả tối ưu dần từng bước
    • Trình tối ưu một lượt: biến các nhóm khớp ký tự lặp lại thành một nút String duy nhất để tìm chuỗi chính xác
    • Trích xuất tiền tố chung: ví dụ với hel[(lo)p], phát hiện tiền tố chung hel để chỉ thử khớp tại những vị trí đó, giúp tăng tốc lớn cho tìm kiếm toàn dự án
    • Viết lại AST walker thành threaded code VM dựa trên lời gọi động của Rust
    • Chuyển threaded code VM sang dạng CPS (Continuation-Passing Style), để mỗi lệnh VM tail-call sang lệnh tiếp theo và tận dụng tối ưu của trình biên dịch
    • Bọc lại lời gọi hàm động chậm của Rust để tránh vtable lookup, giúp phần codegen của nhiều lệnh regex rút xuống chỉ còn vài lệnh máy
    • Triển khai càng nhiều lệnh regex càng tốt ở mức byte thay vì Unicode codepoint; nhờ thiết kế UTF-8 nên các kỹ thuật tối ưu cho ASCII vẫn hiệu quả cả với codepoint nhiều byte
  • Tác giả cũng thử biên dịch thành chuỗi jump LUT, nhưng benchmark cho thấy chỉ nhanh hơn 20–30% so với threaded code trong khi mất đi nhiều độ linh hoạt, nên không chọn
  • Kết quả cuối cùng: với cú pháp tô sáng phức tạp nhất cho Rust, một tệp binding tự sinh 50.000 dòng có thể được tô sáng toàn bộ từ trạng thái lạnh trong dưới 10 mili giây

Cache tô sáng cú pháp

  • Ban đầu, mỗi thay đổi đều khiến hệ thống tô sáng lại toàn bộ tệp, dẫn đến chậm với tệp lớn
  • Sau đó tác giả triển khai cache tô sáng token theo yêu cầu
    • Tô sáng token theo các chunk có kích thước tương đối đồng đều
    • Khi buffer bị thay đổi (damage), chỉ vô hiệu hóa chunk giao với vị trí đó hoặc các chunk phía sau
  • Ngay cả trong trường hợp bi quan nhất như sửa ở giữa một tệp lớn, trạng thái tô sáng trước vùng damage vẫn được giữ nguyên, còn phần bên dưới màn hình thì không bị xử lý nếu chưa được yêu cầu
  • Vì là cách tiếp cận theo nhu cầu (demand-driven), nó vẫn hoạt động đúng cả khi có nhiều panel cùng xem các phần khác nhau của một buffer

Tìm kiếm toàn dự án

  • Quy trình tìm kiếm gồm 4 bước
    • Đi ngược từ thư mục hiện tại để tìm thư mục .git/, từ đó xác định gốc dự án
    • Duyệt đệ quy mọi thư mục từ gốc dự án và so khớp mẫu tìm kiếm với nội dung tệp
    • Với mỗi kết quả dương tính, trích xuất đoạn tệp và áp dụng tô sáng cú pháp để tạo phần xem trước
    • Xếp hạng kết quả theo khoảng cách duyệt từ đường dẫn hiện tại; tệp càng gần thì ưu tiên càng cao
  • Có áp dụng các quy tắc lọc mặc định để tránh các thư mục build...
  • Hệ thống xử lý đa luồng, phân phối việc giữa các luồng bằng cơ chế work-stealing cơ bản
    • Tác giả đã giải quyết bài toán phát hiện kết thúc trong cấu trúc đặc biệt nơi mọi luồng vừa là consumer vừa là producer
    • Luồng đang chờ sẽ tăng một bộ đếm nguyên tử; khi bộ đếm đạt số worker và hàng đợi công việc rỗng thì toàn bộ tiến trình kết thúc
  • Nhờ tối ưu regex và tốc độ SSD hiện đại, việc tìm mẫu đơn giản trên codebase lớn như Veloren gần như hoàn tất ngay lập tức
  • Trên flamegraph, phần lớn thời gian rơi vào trạng thái IO-bound
  • Khả năng tìm kiếm codebase lớn với tốc độ ngang suy nghĩ ngay trong editor đóng góp rất lớn cho năng suất

Buffer giả lập terminal

  • Trong editor dựa trên panel, việc dùng một panel như cửa sổ terminal rất tiện lợi
  • Tác giả từng định tự viết parser ANSI, nhưng hỗ trợ các tính năng terminal hiện đại như OSC52 hay phần mở rộng bàn phím Kitty quá đồ sộ
  • Vì vậy tác giả dùng crate alacritty_terminal để tái sử dụng parser escape sequence và logic quản lý trạng thái terminal của Alacritty
  • Kết quả là có thể thay thế các chức năng cốt lõi của screen/tmux, đồng thời hỗ trợ escape sequence phong phú hơn

Tối ưu rendering

  • Dù dựa trên TUI, băng thông khi kết nối từ xa bằng thiết bị di động vẫn là yếu tố quan trọng
  • Double buffering: duy trì hai bản sao nội bộ của màn hình terminal
    • Khi vẽ lại, so sánh với frame trước đó và chỉ xuất ANSI escape sequence cho các ô thay đổi
    • Các sequence như di chuyển con trỏ hay đổi chế độ style cũng chỉ được xuất khi thực sự cần
  • Trên hầu hết terminal emulator (trừ Ghostty), việc cat một tệp lớn trong panel terminal của editor rồi đóng editor lại còn nhanh hơn chạy cat trực tiếp trong terminal của máy chủ
    • alacritty_terminal đã chặn chi phí xử lý byte stdout đối với terminal host

Kết luận: hãy tự làm công cụ của riêng mình

  • Trình soạn thảo do chính tác giả xây dựng giờ đã trở thành công cụ khớp hoàn hảo với workflow cá nhân
  • Tác giả phản đối quan niệm cho rằng tự làm editor hay công cụ riêng chỉ là đau khổ vô nghĩa
  • Có bốn lợi ích chính
    • Tùy biến hoàn hảo: chỉ làm đúng những gì mình muốn, không hơn không kém
    • Học được nhiều kỹ thuật đa dạng: hiểu sâu về regex, ANSI, pseudo-terminal (pty), thiết kế TUI, chi tiết của UTF-8... đều là kiến thức hữu ích rộng rãi
    • Tăng năng suất dài hạn: vì hiểu công cụ của mình một cách trọn vẹn và tích hợp các tính năng đúng với workflow cá nhân, nên giảm ma sát khi làm việc
    • Niềm vui thuần túy: việc giải những bài toán khép kín và cảm nhận kết quả ngay dưới đầu ngón tay đã khơi lại tình yêu với lập trình, đến mức sau nhiều năm tác giả có thể vừa code vừa mỉm cười, thậm chí bật cười một mình
  • Dù không phải là text editor, tác giả vẫn khuyên hãy tự làm công cụ của riêng mình, đừng giao phần khó cho “hộp thống kê” (AI...) mà hãy tận hưởng chính thử thách đó

5 bình luận

 
xguru 2026-03-12

Thật ra điều đáng ngạc nhiên nhất trong bài này là một từ.

Fingerspitzengefühl

Finger(ngón tay) + Spitzen(đầu mút) + Gefühl(cảm giác)

Tiếng Đức thật sự... ha... còn có cả một từ để chỉ cảm giác thao tác ở đầu ngón tay.

 
carnoxen 2026-03-12

"Finger" cũng là tiếng Đức nhỉ. Tôi cứ tưởng là tiếng Anh...

 
mhcoma 2026-03-13

Vì cùng một hệ ngữ nên họ chia sẻ khá nhiều từ vựng cơ bản.

 
yangeok 2026-03-12

Đúng là tiếng Đức có thể kết hợp từ gần như vô hạn mà haha

 
GN⁺ 2026-03-12
Ý kiến Hacker News
  • Đọc rất vui từ đầu đến cuối. Tôi còn khuyên bạn bè hãy thử tự làm trình soạn thảo văn bản của riêng mình
    Tôi đã dùng trình soạn thảo của mình tên là ‘Left’ gần 10 năm nay. Lúc đầu nó chưa hoàn hảo, nhưng tôi đã cải tiến nó bằng cách dùng Left để sửa chính Left. Niềm vui khi mỗi sáng mở công cụ do chính tay mình làm ra đủ để đền đáp gấp 20 lần thời gian bỏ vào đó

    • Tôi cũng đã dùng trình soạn thảo cá nhân hơn 10 năm rồi. Trải qua cả ngày với một công cụ vừa khít với mình thật sự rất dễ chịu
    • Tôi đã dùng trình soạn thảo ‘aoeui’ của mình suốt 19 năm. Đây là một trong những lựa chọn ảnh hưởng lớn nhất tới năng suất của tôi
    • Tôi tò mò không biết những tính năng nào là quan trọng nhất. Cũng muốn biết nó có được thiết kế để hỗ trợ nhiều workflow khác nhau không
  • Có câu rằng: “Trong đời nên một lần xây nhà, trồng cây và làm một trình soạn thảo.” Tôi bắt đầu từ điều cuối cùng
    Đó là câu xuất hiện trong Vip, một trình soạn thảo kiểu Vi dựa trên PicoLisp

  • Tôi cũng đã thử tự làm trình soạn thảo văn bản từ đầu. Vì nhiều tính năng nên tôi tận dụng mạnh các công cụ bên ngoài như LSP, tree-sitter, fzf.
    Nó được thiết kế theo phong cách suckless, để có thể tùy biến đơn giản chỉ bằng cách sửa mã nguồn.
    Vài tuần đầu đầy rẫy bug, nhưng càng sửa thì nó càng ổn định hơn. Có thể xem dự án hat của tôi

    • Đúng vậy. Cảm giác thật đáng tự hào khi những chỉnh sửa và cải tiến trong quá khứ dồn lại thành gia tốc năng suất trong tương lai
  • Có ai có thể gợi ý một thư viện chỉnh sửa văn bản đáng dùng không?
    GUI là bắt buộc nên phải xử lý cả font renderer lẫn graphics context.
    Chỉ dành cho console thì tôi không dùng được, mà nếu chỉ làm GUI thì lại không có chức năng chỉnh sửa, nên tôi cần cả hai.
    Ngạc nhiên là rất khó tìm một thư viện thuần API đáp ứng được các yêu cầu như vậy.
    Phần lớn либо là trình soạn thảo hoàn chỉnh, либо ở mức framework khổng lồ.
    Tôi chỉ cần một engine chỉnh sửa cơ bản có thể xử lý tệp văn bản lớn thật nhanh

    • Tôi khá bất ngờ vì trình giả lập terminal bây giờ mạnh đến mức nào. Clipboard, sự kiện chuột, theo dõi focus, thông báo... gần như đều có cả.
      Với công cụ như trolley, còn có thể bọc nó lại để trông như UI native dựa trên ghostty
    • Nhiều trình soạn thảo GUI gọn nhẹ được xây trên Scintilla. Nó hỗ trợ GTK, Windows, Mac. Tuy vậy, tính năng khá nhiều nên có thể hơi quá mức nếu chỉ muốn dùng như một API đơn giản
    • stb_textedit.h, nhưng tôi không khuyến nghị. Nó có khá nhiều hạn chế, như xử lý UTF-8 hay nhận diện ranh giới từ.
      Thay vào đó, kết hợp SDL với SDL_ttf là một lựa chọn khá ổn. SDL3_ttf cũng cải thiện phần xử lý chuỗi
    • Tùy nền tảng, nhưng nếu mục tiêu không phải là render GUI thì raylib có thể là một lựa chọn thay thế tốt
  • Tôi đã thử triển khai lại trình soạn thảo “kilo” của antirez.
    Mã nguồn gốctutorial đều rất tốt, nên đây là một dự án tuyệt vời để học chế độ terminal và những nền tảng cơ bản của ngôn ngữ C

  • Tôi nhớ hồi những năm 90 từng tự làm trình soạn thảo cho các file COBOL và ASM.
    Nó có tô sáng cú pháp, buffering nhanh, thậm chí cả screensaver.
    Chạy trên Pentium 120, mà trong ký ức của tôi còn nhanh hơn VSCode bây giờ cả nghìn lần

    • Tôi cũng từng làm một trình soạn thảo bằng VB6. Trên trang marketing năm 2002 có liệt kê các tính năng như “template không giới hạn, in màu, tìm/thay thế bằng regex, hoàn thành mã”.
      Hồi đó tôi còn viết toàn bộ thẻ HTML bằng chữ in hoa
    • Mỗi lần mở VSCode trên laptop cũ là tôi thấy xót vì nó quá chậm. Tôi thuộc thế hệ vim, nhưng giờ lại thấy khó mà khuyên người mới dùng nó
    • Nhân tiện, Borland Turbo Pascal và Turbo C cũng từng hỗ trợ mở nhiều file cùng lúc
  • Đây là trình soạn thảo zte mà tác giả bài viết đã làm

  • Câu “hãy cưỡng lại cám dỗ đẩy phần khó vào một hộp thống kê” thật sự rất ấn tượng

  • Tôi cũng dùng trình soạn thảo tự làm của mình. Người khác thì không mấy quan tâm, nhưng giá trị tôi nhận được từ công cụ do chính mình tạo ra là rất lớn

    • Tôi cũng dùng một trình soạn thảo viết bằng chính ngôn ngữ lập trình của mình. May là chưa cần phải tự làm luôn cả hệ điều hành
    • Tôi đã sửa một trình soạn thảo sẵn có cho hợp ý mình. Nó có cả tính năng nạp ảnh và scripting, cũng như tô màu cho các thẻ HTML khớp nhau.
      Thậm chí còn có một tính năng ‘trình duyệt’ đơn giản để mở link bằng F5
    • Bạn lại không để link kìa :(
    • Tôi cũng dùng trình soạn thảo của riêng mình. Mỗi lần bạn bè nhìn màn hình rồi hỏi “cái gì vậy?” là tôi lại thấy rất khoái
  • Josh Barretto là thiên tài đã làm bản port Super Mario 64 lên GBA. Nếu là trình soạn thảo của anh ấy thì tôi rất sẵn lòng thử