आधुनिक TUI framework बनाते समय सीखी गई 7 बातें
(textualize.io)- Textual के development process ने दिखाया कि पुराने terminal protocol के ऊपर भी smooth TUI animation बनाए जा सकते हैं, लेकिन screen refresh के तरीके और output synchronization को बहुत सावधानी से संभालना पड़ता है
- flicker कम करने के लिए screen को clear करने के बजाय overwrite करना, standard output पर एक ही बार में लिखना, और Synchronized Output protocol का उपयोग करना महत्वपूर्ण है
- Python के
dict.items()view और@lru_cacherender diff निकालने और छोटे लेकिन बहुत बार चलने वाले function optimize करने में उपयोगी हैं, और CPython की C implementation cache performance को मजबूत बनाती है - लगभग immutable object, Unicode box character diagram, और
fractions.Fractionक्रमशः reasoning·caching·testing, documentation की समझ, और layout calculation की accuracy बढ़ाते हैं - terminal Emoji को Unicode version, character width, और multi-codepoint rendering के अंतर की वजह से predict करना कठिन है, इसलिए व्यवहार में Unicode 9 स्तर के सरल Emoji अधिक स्थिर रहते हैं
टर्मिनल animation और flicker control
- आधुनिक terminal emulator पुराने protocol पर काम करते हैं, लेकिन कई implementation ऐसे graphics technique का उपयोग करते हैं जो video game में भी इस्तेमाल होती हैं
- terminal visual effect में flicker या tearing आना आसान है, लेकिन कुछ शर्तें मानकर smooth animation लागू किए जा सकते हैं
- flicker कम करने का पहला तरीका “clear के बाद draw” नहीं, बल्कि मौजूदा content को overwrite करना है
- screen को साफ करने के बाद नया content जोड़ने पर खाली frame या आंशिक रूप से draw हुआ frame थोड़ी देर के लिए दिख सकता है
- दूसरा तरीका है update content को standard output पर single write के रूप में लिखना
- कई बार
file.writecall करने पर partial update user को दिखाई दे सकता है
- कई बार
- तीसरा तरीका है Synchronized Output protocol का उपयोग करना
- अगर terminal को frame की शुरुआत और अंत बताया जाए, तो terminal उसे flicker-free update के लिए इस्तेमाल कर सकता है
- Textual 60fps को baseline मानता है, और उसके बाद अंतर हमेशा स्पष्ट रूप से दिखे ऐसा ज़रूरी नहीं
- हर animation का मूल्य समान नहीं होता
- बाईं ओर से slide होने वाले sidebar जैसे effect देखने में अच्छे लगते हैं, लेकिन user experience में ठोस लाभ न भी दें
- smooth scrolling लंबे text में current position बनाए रखने में मदद करती है
- इसी वजह से Textual कुछ animation बंद करने का mechanism जोड़ने वाला है
DictView से render diff ढूँढना
- Python
dictकेkeys()औरitems()क्रमशःKeysView,ItemsViewलौटाते हैं, और ये set जैसी interface देते हैं - Textual का layout process Widget और screen position की mapping के रूप में render map बनाता है
- पहले के तरीके में एक Widget की position बदलने पर भी पूरी screen बेवजह refresh हो जाती थी
- दो
ItemsViewके symmetric difference का उपयोग करके नए बने या बदले हुए item निकाले जा सकते हैं- यह operation C level पर process होता है
- Textual CSS property बदलने पर बदले हुए screen area ढूँढकर optimized update में इसका उपयोग करता है
lru_cache और छोटे function optimization
functoolsstandard library का@lru_cachefunction return value cache करने वाला decorator हैmaxsizeसेट करने से cache के अनंत बढ़ने की स्थिति सीमित की जा सकती है- CPython का
lru_cacheC implementation का उपयोग करता है, इसलिए cache hit और miss दोनों में तेज़ है - Textual में कुछ छोटे function ऐसे हैं जो धीमे नहीं हैं, लेकिन बहुत बार call होते हैं, और इनमें से कई caching के लिए उपयुक्त थे
- आम तौर पर
maxsizeको 1000~4000 रखने पर ज़्यादातर call cache hit में बदलने के लिए पर्याप्त था - cache का उपयोग करते समय
cache_info()देखना ज़रूरी है- अगर cache प्रभावी है, तो उम्मीद की जाती है कि
hits,missesकी तुलना में तेज़ी से बढ़ेंगे
- अगर cache प्रभावी है, तो उम्मीद की जाती है कि
- दो rectangular area के overlapping हिस्से की गणना करने वाला
intersectionmethod अपने आप में भारी काम नहीं करता, लेकिन हज़ारों बार call होने से caching का लाभ देता है
immutable object से मिलने वाली सादगी
- Python में सख्त अर्थों में true immutable object नहीं हैं, लेकिन tuple,
NamedTuple, और frozen dataclass से कई लाभ मिलते हैं - object को बदल न सकने की पाबंदी मनमानी सीमा जैसी लग सकती है, लेकिन असली code में यह अक्सर मददगार होती है
- Textual में immutable object का उपयोग करने वाला code समझना आसान होता है, और cache व testing के लिए भी बेहतर है
- मुख्य कारण यह है कि side effect रहित code लिखना आसान हो जाता है
- class instance को function में pass करने पर उसी तरह side effect से बचना कठिन होता है
Unicode art और documentation
- जब तकनीकी बातों को सिर्फ शब्दों में समझाना कठिन हो, तब Unicode box character से बने diagram documentation समझने में बहुत मदद करते हैं
- Textual के docstring में किसी area को चार sub-area में बाँटने वाले method को समझाने के लिए box character diagram का उपयोग किया जाता है
- ऐसे diagram अच्छी तरह लिखे गए docstring की जगह नहीं लेते, लेकिन साथ में उपयोग करने पर समझ बेहतर होती है
- diagram बनाने के लिए monodraw का उपयोग किया जाता है
- Monodraw केवल macOS के लिए है
- दूसरे platform पर भी इसके विकल्प हो सकते हैं
fractions.Fraction से layout error कम करना
- Python standard library का
fractionsmodule Python 2.6 से मौजूद है Fractionसंख्या को व्यक्त करने का एक अलग तरीका है, और बनाने के बाद कई जगह float की जगह इस्तेमाल किया जा सकता है- floating point की सीमाएँ अच्छी तरह जानी जाती हैं
- उदाहरण के लिए
0.1 + 0.1 + 0.1 == 0.3का परिणामFalseहोता है
- उदाहरण के लिए
- Textual में screen को कई अनुपातों में बाँटने वाले layout में floating-point rounding error समस्या बनती है
- screen width के 1/3 panel और बचे हुए 2/3 को फिर बाँटने की स्थिति में एक character जितना gap बन सकता था
- float को
Fractionसे बदलने पर इस तरह की rounding error से बचा जा सकता हैFraction(1, 10)के तीन योगFraction(3, 10)के बराबर होते हैं
- 24 character को 7 हिस्सों में बाँटने के उदाहरण में float version में एक character कम पड़ गया, लेकिन Fraction version ने पूरी लंबाई भर दी
terminal Emoji की मुश्किलें
- Emoji support Rich की शुरुआत से लगातार समस्या रही है, और Textual को भी वही समस्या मिली है
- terminal में character आम तौर पर एक cell या दो cell घेरता है, और कुछ character की width 0 होती है
- CJK character पश्चिमी alphabet की तुलना में दोगुनी जगह लेते हैं
- center alignment या box drawing जैसी basic formatting करने के लिए output text की terminal width जानना ज़रूरी है
- इसलिए सिर्फ
len(text)से terminal में घिरी हुई width नहीं जानी जा सकती
- Unicode database में single-width और double-width character की mapping होती है
- Rich और Textual output के हर character के लिए इस database को lookup करते हैं
- यह काम हल्का नहीं है, लेकिन engineering और caching से इसे पर्याप्त तेज़ बनाया जा सकता है
- Emoji Unicode database में शामिल होने पर भी, हर नए Unicode release के साथ नए Emoji जुड़ते हैं, इसलिए नतीजे का अनुमान लगाना कठिन हो जाता है
- नया Emoji terminal में एक cell या दो cell में दिख सकता है
- यह सही render भी न हो सकता है
- terminal emulator कौन-सा Unicode version उपयोग करता है, इसे स्थिर रूप से detect करने का कोई standard तरीका नहीं है
- कोई standard environment variable भी नहीं है
- कुछ heuristic ऐसे हैं जो विशेष sequence print करके cursor position पूछते हैं, लेकिन test में Unicode database जानने के बाद भी terminal ने Emoji को अप्रत्याशित तरीके से render किया
- multi-codepoint Emoji समस्या को और जटिल बना देते हैं
- उदाहरण के लिए 👨🏻🦰 4 codepoint से बना है
- कुछ terminal इसे 4 character, 2 character, 1 character, एक cell, दो cell, या 4
?के रूप में render कर सकते हैं
- व्यवहारिक रूप से Unicode 9 के Emoji कई platform पर अपेक्षाकृत स्थिर रहते हैं
- नए Emoji और multi-codepoint character, भले ही मौजूदा terminal पर ठीक दिखें, फिर भी उनसे बचना बेहतर है
Textualize भर्ती
- Textualize ऐसा TUI framework बनाने के लिए भर्ती कर रहा है जो browser की कुछ भूमिकाओं की जगह ले सके
- भर्ती की जानकारी Jobs पर देखी जा सकती है
1 टिप्पणियां
Hacker News की राय
मज़ेदार है कि हर TUI डेवलपर आखिरकार Unicode से टकराता है, और अंतरराष्ट्रीय अक्षरों व emoji को सही तरह संभालना मूल TUI प्रोजेक्ट जितना या उससे भी बड़ा अलग प्रोजेक्ट बन जाता है
rivo/tview में भी ऐसा ही हुआ था, और इसके परिणामस्वरूप बनाए गए rivo/uniseg पैकेज के ज़रिए पता चला कि दूसरे TUI library maintainers भी यही समस्या झेलते हैं
आखिरकार अक्षरों की चौड़ाई standardized नहीं है और terminal जटिल होते हैं, इसलिए हर कोई अपना-अपना समाधान ईजाद करता है। लेख के लेखक सिर्फ Unicode 9 सपोर्ट करते हैं, जबकि अभी Unicode 15.1 है, इसलिए कभी न कभी किसी खास emoji या अंतरराष्ट्रीय अक्षर के गलत render होने की शिकायत आएगी; इस वजह से यकीन करना मुश्किल है कि यह अच्छा समाधान है
मैं दो TUI libraries maintain कर रहा हूं जो यह तकनीक इस्तेमाल करती हैं, और emoji support लगभग शानदार रहा है। उनमें से एक uniseg library भी इस्तेमाल करती है
https://mitchellh.com/writing/grapheme-clusters-in-terminals
textual को लेकर सबसे बड़ी शिकायत यह है कि वह React जैसा बनने की कोशिश करता है। समझ आता है कि ऐसा क्यों है, क्योंकि यह लोकप्रिय framework है जिससे बहुत लोग परिचित हैं, लेकिन मैं इसे user interface बनाने का अच्छा तरीका नहीं मानता
reactive design अपने आप में एक आज़माया हुआ रास्ता है, और जिस तरीके के काम करने की जानकारी है उस पर system design आधारित करना project risk घटाने का अच्छा तरीका है
लेकिन उसमें CSS का एक variant भी इस्तेमाल करना कुछ ज़्यादा लगता है। React model standardized components को पसंद करते हुए CSS की अवधारणा को कई मायनों में पहले ही तोड़ चुका है, और developers द्वारा CSS से components customize करना किसी ठोस architecture से ज़्यादा React के evolution का side effect लगता है
पिछली बार जब मैंने इसे इस्तेमाल किया था, तो CSS का उपयोग करना पड़ा था, और अच्छे standard components नहीं थे इसलिए खुद बनाने पड़े। component के साफ-सुथरे तरीके से encapsulated एक Python class बनने के बजाय, official docs में list component बनाकर उसे external stylesheet से सजाने का तरीका था
Python में किसी काम को करने का एक obvious तरीका होना चाहिए, और बेहतर हो तो सिर्फ एक ही। React को बहुत करीब से follow करते हुए यह JavaScript community की सबसे बुरी आदतों तक को अपनाता दिखता है
अच्छे standard components नहीं हैं—लगता है यह जांचे हुए काफी समय हो गया है: https://textual.textualize.io/widget_gallery/
मुझे अपने components भी नहीं बनाने पड़े और CSS मुझे पहले से आता था। बल्कि थोड़े layout differences और CSS से हटकर कुछ हिस्से कभी-कभी confusing लगे
इसे ऐसे समझें कि सामान्य GUI window के अंदर एक component terminal window हो। जानना चाहता हूं कि ऐसा कुछ है या बस fixed-width font text view इस्तेमाल करना होगा
यह TUI सुंदर है, लेकिन असल में मैं इसे इस्तेमाल करूँ और इसके लिए पैसे भी दूँ—ऐसी स्थिति की कल्पना करना मुश्किल है। शायद मैं सही माहौल में नहीं हूँ, लेकिन मेरे अनुभव में लोग या तो सच में बहुत minimal टूल्स से संतुष्ट हो जाते हैं, या फिर सीधे GUI से users को संतुष्ट करने की कोशिश करते हैं
उदाहरण के लिए, लेख के YouTube लिंक में cells को highlight करने वाली एक table दिखाई गई थी, लेकिन समझ नहीं आता कि उसे TUI में ही क्यों करना चाहिए। अगर highlighted active cell को move करना है, तो आखिरकार कई और features भी चाहिए होंगे, और अंत में शायद एक proper GUI की जरूरत पड़ेगी
हालांकि “proper GUI” क्या है, यह मुझे ठीक से नहीं पता। terminal में widely used public standards हैं, और ये protocols किसी भी GUI framework से ज्यादा standard और interoperable हैं, और सभी systems पर supported हैं
इसमें video जैसे elements आ जाएँ और कुछ gaps भर दिए जाएँ, तो browser से compete करना या पूरा computing experience terminal में लाना भी reasonable लगता है
बेशक, अगर terminal video जोड़ता है तो वह “proper GUI” की rendering pipeline की नकल करने जैसा होगा, लेकिन यह terminal experience को improve करने का काम है; और अगर यह बहुत सफल हुआ, तो इसे GUI में UNIX-शैली की simplicity लाने के रूप में भी देखा जा सकता है
कर्मचारी keyboard shortcuts से काम करते हैं और बेहद efficient होते हैं, और जब भी कोई AS400 को modern web app से बदलने की कोशिश करता है, productivity 100 गुना गिर जाती है
यह Vim/Emacs power users और दिखने में sleek लेकिन keyboard shortcuts के बिना GUI के अंतर जैसी स्थिति है
users को server में SSH से connect कराकर TUI app को shell की तरह इस्तेमाल कराया जा सकता है, हालांकि मानता हूँ कि यह scenario कुछ forced-सा है
व्यक्तिगत रूप से Textual इस्तेमाल करने में थोड़ा अजीब लगा, लेकिन ncurses से बेहतर था। फिर भी इसने मुझे मनचाहा result नहीं दिया। पुराने mainframe-style TUI applications काफी efficient महसूस होते थे
कभी-कभी यह ठीक चलता है, लेकिन सीमित cases में—जैसे high-bandwidth connection पर X forwarding इस्तेमाल करना। बाकी मामलों में GUI पूरी तरह sluggish हो जाता है
text-based GUI दोनों तरफ के फायदे ले सकता है, ऐसा लगता है
“पहली तरकीब है मिटाएँ नहीं, ऊपर से लिखें” वाला तरीका वैसा ही है जैसे DirectX से पहले के games लिखे जाते थे
frame buffer में सीधे लिखना, और पूरा साफ करके फिर से draw करने के बजाय बदले हुए हिस्सों और उनके आसपास/नीचे के हिस्सों को फिर से draw करना। क्योंकि पूरी screen को समय पर update करने का समय नहीं होता था
पहली थी किसी दूसरे buffer में लिखना और frame खत्म होने पर पूरा buffer एक बार में copy करना, ताकि हर pixel सिर्फ एक बार बदले। यह buffer अक्सर video RAM के बजाय सामान्य RAM में भी हो सकता था
दूसरी थी video RAM के अंदर किसी दूसरे buffer में लिखना और graphics hardware registers बदलना, ताकि monitor पर दिखाए जाने वाले pixels उसी buffer से generate हों
trade-offs अलग थे। पूरा buffer copy करना महंगा था, और address register बदलना सस्ता। लेकिन register details hardware-dependent हो सकती थीं, और proper graphics driver framework भी नहीं था
सिर्फ “buffer flipping” करने के लिए, off-screen buffer में rendering करते समय भी pixels को video RAM में भेजना पड़ता था, और याद है कि video RAM access सामान्य RAM से धीमा था। असल में यह NUMA जैसी structure थी, इसलिए pixels कितनी बार overdraw होते हैं इस पर निर्भर करते हुए, final copy शामिल करने के बाद भी सामान्य RAM में rendering करना कुल मिलाकर तेज हो सकता था
हालांकि मेरा मानना है कि terminal को frame की शुरुआत और अंत बताने की क्षमता कहीं ज्यादा powerful है
मुझे सच में समझ नहीं आता कि software engineers TUI में इतना interest क्यों रखते हैं। अच्छे command-line programs मुझे पसंद हैं, लेकिन TUI आकर्षित नहीं करता
ऊपर से इसमें hacker vibe है। style, content से बहुत मजबूती से अलग नहीं होता, और configurable style options भी सीमित हैं, इसलिए TUI apps आम तौर पर एक ही style की तरफ converge करते हैं। वह style hacker movies और cool sci-fi की याद दिलाता है
यह corporate designers की पसंद का क्षेत्र भी नहीं है, और companies TUI के आधार पर enterprise या consumer sales close नहीं करतीं। ऐसे commercial pressure के अभाव में TUI को developers, developers के लिए design करते हैं
इसलिए TUI meme खुद को reinforce करता है। developers TUI को देखते और इस्तेमाल करते हुए महसूस करते हैं कि यह आम तौर पर developers को ध्यान में रखकर बनाया गया tool है, और फिर अपना TUI बनाना चाहते हैं
cross-platform support लगभग मुफ्त मिलता है, pixel-perfect GUI बनाने की जरूरत नहीं होती और वैसे भी यह संभव नहीं, icons या graphics भी नहीं चाहिए। क्योंकि graphics दिखाए ही नहीं जा सकते
अपने पसंदीदा font वाले terminal emulator का उपयोग जारी रखते हुए GUI जैसा interface मिल सकता है
अब तक जिन TUI apps को इस्तेमाल किया है, उन सबका response time कम था। GUI apps भी आम तौर पर तेज होते हैं, लेकिन जो apps परेशान कर देने जितने धीमे थे, वे सभी GUI apps ही थे
Monodraw के alternative के रूप में ascii-draw है
https://github.com/Nokse22/ascii-draw
TurboVision के बाद मैंने जो लगभग सब कुछ देखा, वह प्रेरित तो था, लेकिन असल में उसमें परिपक्वता की कमी थी। टूलकिट को ठीक से इस्तेमाल करके देखें तो वह प्यारा लगता है, पर अधूरा-सा महसूस होता है
दूसरे शब्दों में कहें तो मैंने देखे कई TUI framework “opinionated” framework थे
शायद मैं ही थोड़ा सुस्त और कम रचनात्मक हूं, लेकिन 90 के दशक में DOS से Linux पर जाने के बाद से मैं कभी भी B800 के साथ काम करते समय जितना उत्पादक था, उतना नहीं रहा
यह भी संभव है कि double buffering की जरूरत, local direct text mode और terminal के फर्क, और escape sequences तक समझने में मुझे काफी समय लगा हो। फिर भी ncurses से खुद कुछ बनाने की हर कोशिश में स्पष्ट असंतोष के कारण मैंने लगभग हार मान ली। यह B800 के सरल आदर्श से जो किया जा सकता था, उससे बिल्कुल अलग था
पता नहीं मेरी दृष्टि पूरे शहर जितनी ढकी हुई थी या नहीं, लेकिन message pump के बाद के GUI framework मुझे बिल्कुल समझ में नहीं आते थे
खासकर यह समझ नहीं आया कि object-oriented framework multi-threaded UI समस्याओं को वास्तव में कैसे हल करते हैं। Win32 में मुख्य renderer को thread में रखते थे, और सहायक renderer बगल में model बनाकर केवल अंतर update करते थे। code कोई इतना बड़ा नहीं हुआ कि संभल न सके
अगर kitty चलाने वाले हैं, तो उससे कहीं ज्यादा कर सकते हैं: https://m.youtube.com/watch?v=ft1Q-DwGWIs
https://notcurses.com/
दोनों graphics दिखाने के लिए एक ही protocol का उपयोग कर सकते हैं। अगर सचमुच graphics चाहिए, तो terminal लगभग कभी सही समाधान नहीं होता। हालांकि icons जैसी छोटी चीजों के लिए यह कभी-कभी उपयोगी है
यह दिलचस्प है कि वे hiring कर रहे हैं। जानना चाहूंगा कि TUI framework से पैसे कमाने की उनकी योजना क्या है
संदर्भ के लिए, मैंने लगभग 12 compilable TUI libraries का मूल्यांकन किया था, और FTXUI सबसे आसान और स्थिर लगी
https://github.com/ArthurSonzogni/FTXUI
यह keyboard और mouse दोनों को support करने वाला interactive dashboard बनाने के लिए अच्छा tool है