- Mevcut Howl editörünün sınırlamaları (geliştirmenin durması, yavaş arama, SSH uyumsuzluğu, terminal desteğinin olmaması) nedeniyle doğrudan yeni bir TUI metin editörü geliştirdi
- Helix, VS Code, Vim, Neovim, Emacs dahil 13 editörü denedi, ancak istediği kullanım hissini (Fingerspitzengefühl) veren bir editör bulamadı
- Başlangıçta yalnızca kişiye özel asgari işlevleri uyguladı; performans, Unicode ve çok dilli destek gibi konuları sonraya bırakarak kademeli biçimde genişletti
- Geliştirme sürecinde kendi regex motorunu, dosya tarayıcısını, TUI tabanlı render sistemini, terminal buffer entegrasyonunu doğrudan kendisi yazdı
- Proje genelinde arama, sözdizimi vurgulama, önbellekleme ve çok iş parçacıklı iş dağıtımı gibi alanlarda çok sayıda performans optimizasyon tekniği uyguladı
- Sonuç olarak kendi iş akışına kusursuz uyan bir aracı tamamladığını, bunun da üretkenliğini ve programlamadan aldığı keyfi geri getirdiğini söylüyor
Mevcut editörlerin sınırları ve alternatif arayışı
- Yaklaşık 10 yıl kullandığı Howl editörünün sorunları, onu doğrudan geliştirmeye yönelten neden oldu
- Geliştirme yıllardır durmuştu; bu yüzden kendi fork'unu sürdürüyordu, ancak MoonScript ile yazıldığı için derinlemesine değişiklik yapmak zordu
- Proje genelinde dosya arama performansı yetersizdi, bu da iş akışını bölüyordu
- Bir GUI editörü olduğu için SSH bağlantısı üzerinden uzaktan kullanılamıyordu
- Entegre terminali olmadığından harici komutları canlı etkileşimle çalıştırmak mümkün değildi ve ANSI escape kodlarının büyük kısmı desteklenmiyordu
- Helix, VS Code, Sublime Text, Vim, Zed, Neovim, Emacs, Geany, Micro, Lite XL, Lapce, GNOME Builder, Kakoune dahil 13 editörü denedi
- Her birinin güçlü yanları vardı, ancak istediği kullanım hissini (Fingerspitzengefühl) karşılamadı
- En uzun süre Helix kullandı, ancak bir ay sonra ilgisini kaybetti
İlk geliştirme stratejisi
- Başlangıç aşamasında kapsamı en aza indirdi
- Kendisi dışındaki kullanıcılar için özellikleri dışarıda bıraktı, tüm ayarları hardcode etti
- Performans optimizasyonunu erteleyip
String tabanlı buffer ile başladı
- Unicode grapheme'leri tam desteklemeyi dışarıda bıraktı;
£ simgesinin tek bir sütun kaplaması yeterli diye düşündü
- Sözdizimi vurgulama için esas kullandığı birkaç dili destekledi, diğerlerini ise genel ayırıcı tabanlı vurgulamayla karşıladı
- İkinci denemede önce basit bir TUI framework kurdu, ancak zamanla bunun çoğunu kaldırıp daha doğrudan ve daha ince ayarlı bir yaklaşıma geçti
Dogfooding pratiği
- Editör tek bir dosyayı açıp düzenleyebilen ve kaydedebilen asgari işlev eşiğine ulaştıktan sonra üç uygulama başlattı
nano yerine kendi editörünü kullanarak sistem dosyalarını düzenlerken veya not alırken kendini zorunlu olarak buna yönlendirdi
- Eksik özellikleri, bug'ları, garip davranışları ve sınırları fark ettikçe proje
README.md dosyasına kaydetti
- Sinir bozucu düzeydeki sorunları hemen düzeltti
- Bu üç uygulama sayesinde harcadığı süre ayda 1 saatten haftada birkaç saate çıktı
- Toplam yaklaşık 10.000 satır kodun neredeyse tamamı son 6 ay içinde yazıldı
İmleç kontrolü
- İmleç kontrolü uygulaması zor alanlardan biri
ctrl + shift + left gibi tuş kombinasyonlarının davranışı kullanıcıya doğal gelse de, bunun mantığını uygulamak karmaşık
- Temel tavsiye, yüksek seviyeli girdileri ilkel işlemlerin birleşimi olarak uygulamak
- Örneğin: kelime bazlı backspace → kelime bazlı imleç hareketi + aralık seçimi + silme olarak ayrıştırılabilir
- Undo/redo uygulanırken bu 3 işlemi tek bir grup halinde bağlamak sezgisel sonuçlar için gerekli
- Modal editörlerin bu tür ilkel işlemleri doğrudan kullanıcıya açmasının nedeni böylece anlaşılmış oldu
Dosya tarayıcısı
- Howl'un dosya tarayıcısı, başka editörlere geçememesinin belirleyici nedeniydi
- Anında güncellenen fuzzy filtre o kadar iyiydi ki çoğu zaman istenen dosya 1-2 tuş vuruşuyla bulunabiliyordu
- Dosya yoksa satır içinde oluşturulabiliyordu
~/ girildiğinde otomatik olarak home dizinine geçiyordu
- Ana düzenleme penceresinde açılacak dosyanın önizlemesi gösteriliyordu
- Diğer editörlerin dosya açma sorununu fareye bağımlılık, GTK varsayılan diyalogları, dosya adı tahmini gibi yollarla çözmesine karşı hoşnutsuzluk duydu
- Kendi uygulamasında Levenshtein distance gibi karmaşık yöntemler yerine üç basit ölçütün yeterli olduğunu gördü
- Filtre ifadesiyle başlayıp başlamaması
- Filtre ifadesini içerip içermemesi
- En son değiştirilme/erişim zamanı
- Büyük/küçük harf duyarsız eşleşmeye izin verirken, büyük/küçük harf tam uyuşuyorsa sıralamayı biraz yükseltti
- On binlerce dosya içeren projelerde bile 2 tuş vuruşundan sonra istenen dosyanın ilk 2 sonuç içinde olma olasılığı yaklaşık %95
Regex motoru
- Regex üç yerde kullanılıyor: proje genelinde arama, sözdizimi vurgulama, buffer içinde bulma
- Mevcut
regex-automata crate'i yerine kendisinin yazmasının nedenleri
- Rust'ın raw string sözdizimi gibi bağlama duyarlı edge case'leri ele alma ihtiyacı
- Projenin kendisinin de kendi yığınını kurma ve anlama alıştırması olması
- İlk uygulama, parse crate'i
chumsky ile regex sözdizimini parse edip AST'yi her karakterde dolaşan yavaş bir yaklaşımdı
- Sonrasında kademeli optimizasyonlar yaptı
- Tek geçişli optimizer: tekrar eden karakter eşleme gruplarını tek bir
String düğümüne dönüştürerek tam metin araması yaptı
- Ortak önek çıkarımı: örneğin
hel[(lo)p] ifadesinde ortak önek hel bulunup eşleme yalnızca o konumlarda denendi → proje genelinde aramada büyük performans artışı sağladı
- AST yürütücüsünü, Rust'ın dinamik çağrılarına dayalı bir threaded code VM olarak yeniden yazdı
- Threaded code VM'yi CPS (Continuation-Passing Style) biçimine dönüştürdü; böylece her VM komutu sonraki komutu tail-call ederek derleyici optimizasyonlarından yararlandı
- Rust'ın yavaş dinamik fonksiyon çağrılarını vtable lookup olmadan sarmaladı; birçok regex komutunun codegen'i birkaç makine komutuna kadar indi
- Mümkün olduğunca çok regex komutunu Unicode codepoint yerine byte düzeyinde uyguladı; UTF-8 tasarımı sayesinde ASCII optimizasyonları çok baytlı codepoint'lerde de geçerli kaldı
- Jump LUT zincirine derlemeyi de denedi, ancak benchmark sonuçlarında threaded code'a göre yalnızca %20-30 kadar daha hızlı olduğu ve esnekliği ciddi biçimde düşürdüğü için bunu benimsemedi
- Nihai sonuç: Rust için en karmaşık sözdizimi vurgulama örneklerinden birinde, 50.000 satırlık otomatik üretilmiş binding dosyasını temiz durumda 10 milisaniyenin altında tamamen vurgulayabildi
Sözdizimi vurgulama önbelleği
- Başlangıçta her değişiklikte tüm dosyayı yeniden vurguluyordu, ancak büyük dosyalarda performans sorunu ortaya çıktı
- İstek anında çalışan token vurgulama önbelleği uyguladı
- Token'ları yaklaşık benzer boyuttaki chunk'lar halinde vurguladı
- Buffer'da değişiklik (damage) olduğunda yalnızca o konumla çakışan veya sonrasındaki chunk'ları geçersiz kıldı
- En kötü durumda bile (büyük bir dosyanın ortasında düzenleme), damage öncesindeki vurgulama durumu korunuyor; ekranın alt tarafında kalan bölüm için ise vurgulama bilgisi talep edilmediğinden işlem gerekmiyor
- Bu talep güdümlü (demand-driven) yaklaşım sayesinde aynı buffer'ın farklı bölümlerine bakan birden fazla panelde de doğru çalışıyor
Proje genelinde arama
- Arama süreci 4 aşamadan oluşuyor
- Geçerli dizinden geriye doğru
.git/ dizinini arayarak proje kökünü belirleme
- Proje kökündeki tüm dizinleri özyinelemeli dolaşıp arama desenini dosya içerikleriyle eşleme
- Her pozitif eşleşmede dosya parçacığını çıkarıp sonuç önizlemesi için sözdizimi vurgulama uygulama
- Sonuçları, geçerli yoldan olan gezinme mesafesine göre sıralama (yakın dosyalar daha üstte)
- Build dizinleri gibi yerlerden kaçınmak için varsayılan filtreleme kuralları uyguluyor
- Çok iş parçacıklı çalışıyor; iş parçacıkları arasında temel bir work-stealing yaklaşımıyla iş dağıtıyor
- Tüm iş parçacıklarının hem üretici hem tüketici olduğu özel yapıda sonlanma tespiti sorununu çözdü
- Bekleyen iş parçacığı atomik sayacı artırıyor; sayaç worker sayısına ulaşıp iş kuyruğu boşsa tümü sonlanıyor
- Regex optimizasyonları ve modern SSD hızları sayesinde Veloren gibi büyük kod tabanlarında bile basit desen aramaları neredeyse anında tamamlanıyor
- Flamegraph üzerinde zamanın büyük kısmı IO-bound görünüyor
- Editör içinde büyük kod tabanlarında düşünce hızında arama yapabilmek üretkenliğe büyük katkı sağlıyor
Terminal emülatörü buffer'ı
- Panel tabanlı editörde bir paneli terminal penceresi olarak kullanabilmek çok kullanışlı
- ANSI parser'ını kendisi yazmak istemiş olsa da OSC52, Kitty keyboard extension gibi modern terminal render özelliklerinin desteği çok kapsamlıydı
alacritty_terminal crate'ini kullanarak Alacritty terminal emülatörünün escape sequence parser'ını ve terminal durum yönetimi mantığını yeniden kullandı
- Sonuç olarak
screen/tmux'un temel işlevlerini karşılayabiliyor ve daha zengin escape sequence desteği sunuyor
Render optimizasyonu
- TUI tabanlı olsa da uzaktan mobil bağlantılarda bant genişliği hâlâ önemli
- Double buffering: terminal ekranının iç kopyasını çift olarak tutuyor
- Yeniden çizimde önceki kareyle karşılaştırıp yalnızca değişen hücreler için ANSI escape sequence çıktı veriyor
- İmleç hareketi, stil modu değişimi gibi sequence'ları da yalnızca gerçekten gerektiğinde gönderiyor
- Çoğu terminal emülatöründe (Ghostty hariç), editörün terminal panelinde büyük bir dosyayı
cat edip sonra editörü kapatmak, host terminalde doğrudan cat çalıştırmaktan daha hızlı
- Çünkü
alacritty_terminal, host terminale stdout byte'larını işleme maliyetini engelliyor
Sonuç: kendi aracını yap
- Kendi yaptığı editör artık iş akışına kusursuz uyan bir araç haline geldi
- Kendi editörünü/aracını yapmanın anlamsız bir çile olduğu yönündeki yaygın kanıya karşı çıkıyor
- Dört avantaj sıralıyor
- Kusursuz uyum: yalnızca istenen davranışları yapıyor, ne fazlası ne eksiği
- Çeşitli teknolojileri öğrenme: regex, ANSI, pseudoterminal (pty), TUI tasarımı, UTF-8'in ayrıntıları gibi genel olarak faydalı teknolojiler hakkında derin anlayış kazanma
- Uzun vadeli üretkenlik artışı: kendi aracını tamamen anlayıp kişisel iş akışına uygun işlevleri içine gömerek araçla yaşanan sürtünmeyi azaltma
- Saf keyif: kendi içinde tamamlanan problemleri çözüp sonucunu parmaklarının ucunda hissetme deneyimi, programlama sevgisini yeniden canlandırdı; yıllar sonra kod yazarken geniş geniş gülümsemesine ve kendi kendine kahkaha atmasına yol açtı
- Metin editörü olmak zorunda da değil; kendi aracını yapmayı öneriyor ve zor kısımları istatistik kutularına (AI vb.) bırakmak yerine meydan okumanın kendisinden keyif alınmasını vurguluyor
5 yorum
Aslında bu yazıda en şaşırtıcı olan şey tek bir kelime.
Fingerspitzengefühl
Finger(parmak) + Spitzen(uçlar) + Gefühl(his)
Parmak uçlarındaki kullanım hissini ifade eden bir kelimenin olması Almancada gerçekten... ah...
Demek ki Finger da Almancaymış. İngilizce sanmıştım...
Aynı dil ailesine ait oldukları için temel kelime dağarcığının büyük bir kısmını paylaşıyorlar.
Almanca ya, kelime kombinasyonları sonsuz mümkün oluyor haha
Hacker News yorumları
Bunu okurken baştan sona çok keyif aldım. Arkadaşlarıma da kendi metin düzenleyicilerini yapmalarını tavsiye ediyorum
Ben yaklaşık 10 yıldır kendi editörüm olan
Left'i kullanıyorum. Başta kusursuz değildi amaLeftileLeft'i düzenleyerek geliştirdim. Her sabah kendi ellerimle yaptığım aracı açarken hissettiğim neşe, harcadığım zamanın 20 katı ödül gibi geliyoraoeui'yi kullanıyorum. Bu, üretkenliğimi artıran en büyük tercihlerden biriydi“İnsan hayatta bir kez ev yapmalı, ağaç dikmeli ve bir editör yazmalı” diye bir söz var. Ben sonuncusundan başladım
Bu, PicoLisp tabanlı Vi tarzı editör Vip içinde geçen bir ifade
Ben de sıfırdan kendi metin düzenleyicimi yaptım. Çok sayıda özellik gerektiği için LSP, tree-sitter ve fzf gibi harici araçlardan yoğun biçimde yararlandım.
suckless tarzında, yalnızca kodu değiştirerek özelleştirilebilecek kadar sade olacak şekilde tasarladım.
İlk birkaç hafta tam bir hata yuvasıydı ama düzelttikçe giderek daha kararlı hale geldi. İsteyenler projem hat'e bakabilir
Acaba önerebileceğiniz bir metin düzenleme kütüphanesi var mı?
GUI şart olduğu için yazı tipi oluşturucu ve grafik bağlamını da doğrudan ele almak gerekiyor.
Sadece basit bir konsol çözümü benim işime yaramaz, ama sadece GUI yaparsam da düzenleme işlevi olmaz; yani ikisine de ihtiyacım var.
Şaşırtıcı biçimde, bu gereksinimleri karşılayan saf API biçiminde bir kütüphane bulmak zor.
Çoğu ya tamamlanmış bir editör ya da devasa bir framework seviyesinde.
Aslında tek istediğim, büyük metin dosyalarını hızlı işleyebilen temel bir düzenleme motoru
trolley gibi araçlarla bunu ghostty tabanlı yerel bir UI gibi de sarabilirsiniz
Onun yerine SDL ile SDL_ttf birleşimi oldukça iyi bir seçenek. SDL3_ttf ile dize işleme de iyileşti
antirez'in
kiloeditörünü yeniden yazmayı denedim.Orijinal kod ve eğitim çok iyi hazırlanmış; terminal modunu ve C dilinin temellerini öğrenmek için harika bir projeydi
90'larda COBOL ve ASM dosyaları için kendi editörümü yapmıştım.
Sözdizimi vurgulama, hızlı tamponlama, hatta ekran koruyucu bile vardı.
Pentium 120'de çalışıyordu ve hatırladığım kadarıyla bugünün VSCode'undan bin kat daha hızlıydı
O zamanlar HTML etiketlerinin hepsini büyük harfle yazıyorduk
Yazıdaki kişinin yaptığı editör bu: zte
“Zor kısımları istatistik kutusunun içine itme ayartısına diren” cümlesi beni gerçekten etkiledi
Ben de kendi özel editörümü kullanıyorum. Başkaları pek ilgilenmiyor ama kendi yaptığın araçtan elde ettiğin değer büyük oluyor
F5 ile bağlantı açabilen basit bir “tarayıcı” işlevi de var
Josh Barretto, Super Mario 64 GBA portunu yapan dâhi. Onun editörünü seve seve denerim