الطريقة الممتعة والوظيفية والفعالة لبناء التطبيقات الطرفية. إطار عمل Go يعتمد على The Elm Architecture. يعد Bubble Tea مناسبًا تمامًا للتطبيقات الطرفية البسيطة والمعقدة، سواء كانت مضمّنة أو نافذة كاملة أو مزيجًا من الاثنين معًا.
يتم استخدام Bubble Tea في الإنتاج ويتضمن عددًا من الميزات وتحسينات الأداء التي أضفناها على طول الطريق. ومن بين هذه الميزات العارض القياسي المعتمد على معدل الإطارات، والعارض للمناطق عالية الأداء القابلة للتمرير والتي تعمل جنبًا إلى جنب مع العارض الرئيسي، ودعم الماوس.
للبدء، راجع البرنامج التعليمي أدناه والأمثلة والمستندات ودروس الفيديو وبعض الموارد المشتركة.
تأكد من إطلاعك على Bubbles، وهي مكتبة تحتوي على مكونات واجهة المستخدم الشائعة لـ Bubble Tea.
يعتمد Bubble Tea على نماذج التصميم الوظيفية لـ The Elm Architecture، والتي تعمل بشكل جيد مع Go. إنها طريقة مبهجة لبناء التطبيقات.
يفترض هذا البرنامج التعليمي أن لديك معرفة عملية بـ Go.
بالمناسبة، الكود المصدري غير المشروح لهذا البرنامج متاح على GitHub.
في هذا البرنامج التعليمي، نحن نقوم بإعداد قائمة التسوق.
للبدء، سنقوم بتحديد الحزمة الخاصة بنا واستيراد بعض المكتبات. استيرادنا الخارجي الوحيد سيكون مكتبة Bubble Tea، والتي سنسميها اختصارًا tea
.
package main
import (
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
)
تتكون برامج Bubble Tea من نموذج يصف حالة التطبيق وثلاث طرق بسيطة لهذا النموذج:
لذلك دعونا نبدأ بتحديد نموذجنا الذي سيخزن حالة تطبيقنا. يمكن أن يكون أي نوع، ولكن struct
عادة ما تكون أكثر منطقية.
type model struct {
choices [] string // items on the to-do list
cursor int // which to-do list item our cursor is pointing at
selected map [ int ] struct {} // which to-do items are selected
}
بعد ذلك، سوف نحدد الحالة الأولية لتطبيقنا. في هذه الحالة، نقوم بتعريف دالة لإرجاع نموذجنا الأولي، ومع ذلك، يمكننا بسهولة تعريف النموذج الأولي كمتغير في مكان آخر أيضًا.
func initialModel () model {
return model {
// Our to-do list is a grocery list
choices : [] string { "Buy carrots" , "Buy celery" , "Buy kohlrabi" },
// A map which indicates which choices are selected. We're using
// the map like a mathematical set. The keys refer to the indexes
// of the `choices` slice, above.
selected : make ( map [ int ] struct {}),
}
}
بعد ذلك، نحدد طريقة Init
. يمكن Init
إرجاع Cmd
الذي يمكنه إجراء بعض عمليات الإدخال/الإخراج الأولية. في الوقت الحالي، لا نحتاج إلى إجراء أي إدخال/إخراج، لذا بالنسبة للأمر، سنعيد nil
فقط، والذي يُترجم إلى "no command".
func ( m model ) Init () tea. Cmd {
// Just return `nil`, which means "no I/O right now, please."
return nil
}
التالي هو طريقة التحديث. يتم استدعاء وظيفة التحديث عندما "تحدث الأشياء". وتتمثل مهمتها في النظر إلى ما حدث وإرجاع نموذج محدث ردًا على ذلك. ويمكنه أيضًا إرجاع Cmd
لتحقيق المزيد من الأشياء، ولكن في الوقت الحالي لا تقلق بشأن هذا الجزء.
في حالتنا، عندما يضغط المستخدم على السهم لأسفل، فإن مهمة Update
هي ملاحظة أنه تم الضغط على السهم لأسفل وتحريك المؤشر وفقًا لذلك (أو لا).
تأتي عبارة "حدث شيء ما" على شكل Msg
، والتي يمكن أن تكون من أي نوع. الرسائل هي نتيجة لبعض عمليات الإدخال/الإخراج التي حدثت، مثل الضغط على مفتاح أو علامة مؤقت أو استجابة من الخادم.
عادةً ما نكتشف نوع Msg
التي نتلقاها باستخدام مفتاح النوع، ولكن يمكنك أيضًا استخدام تأكيد النوع.
في الوقت الحالي، سنتعامل فقط مع رسائل tea.KeyMsg
، والتي يتم إرسالها تلقائيًا إلى وظيفة التحديث عند الضغط على المفاتيح.
func ( m model ) Update ( msg tea. Msg ) (tea. Model , tea. Cmd ) {
switch msg := msg .( type ) {
// Is it a key press?
case tea. KeyMsg :
// Cool, what was the actual key pressed?
switch msg . String () {
// These keys should exit the program.
case "ctrl+c" , "q" :
return m , tea . Quit
// The "up" and "k" keys move the cursor up
case "up" , "k" :
if m . cursor > 0 {
m . cursor --
}
// The "down" and "j" keys move the cursor down
case "down" , "j" :
if m . cursor < len ( m . choices ) - 1 {
m . cursor ++
}
// The "enter" key and the spacebar (a literal space) toggle
// the selected state for the item that the cursor is pointing at.
case "enter" , " " :
_ , ok := m . selected [ m . cursor ]
if ok {
delete ( m . selected , m . cursor )
} else {
m . selected [ m . cursor ] = struct {}{}
}
}
}
// Return the updated model to the Bubble Tea runtime for processing.
// Note that we're not returning a command.
return m , nil
}
ربما لاحظت أن ctrl+c و q أعلاه يُرجعان أمر tea.Quit
مع النموذج. هذا أمر خاص يوجه وقت تشغيل Bubble Tea للإنهاء، والخروج من البرنامج.
أخيرًا، حان الوقت لعرض واجهة المستخدم الخاصة بنا. من بين جميع الطرق، يعتبر العرض هو الأبسط. نحن ننظر إلى النموذج في حالته الحالية ونستخدمه لإرجاع string
. هذه السلسلة هي واجهة المستخدم لدينا!
نظرًا لأن العرض يصف واجهة المستخدم الكاملة لتطبيقك، فلا داعي للقلق بشأن إعادة رسم المنطق وأشياء من هذا القبيل. يعتني Bubble Tea بالأمر نيابةً عنك.
func ( m model ) View () string {
// The header
s := "What should we buy at the market? n n "
// Iterate over our choices
for i , choice := range m . choices {
// Is the cursor pointing at this choice?
cursor := " " // no cursor
if m . cursor == i {
cursor = ">" // cursor!
}
// Is this choice selected?
checked := " " // not selected
if _ , ok := m . selected [ i ]; ok {
checked = "x" // selected!
}
// Render the row
s += fmt . Sprintf ( "%s [%s] %s n " , cursor , checked , choice )
}
// The footer
s += " n Press q to quit. n "
// Send the UI for rendering
return s
}
الخطوة الأخيرة هي ببساطة تشغيل برنامجنا. نمرر نموذجنا الأولي إلى tea.NewProgram
ونتركه ينسخ:
func main () {
p := tea . NewProgram ( initialModel ())
if _ , err := p . Run (); err != nil {
fmt . Printf ( "Alas, there's been an error: %v" , err )
os . Exit ( 1 )
}
}
يغطي هذا البرنامج التعليمي أساسيات إنشاء واجهة مستخدم طرفية تفاعلية، ولكن في العالم الحقيقي ستحتاج أيضًا إلى إجراء الإدخال/الإخراج. للتعرف على ذلك، قم بإلقاء نظرة على البرنامج التعليمي للأوامر. انها بسيطة جدا.
هناك أيضًا العديد من أمثلة Bubble Tea المتاحة، وبالطبع هناك Go Docs.
نظرًا لأن تطبيقات Bubble Tea تتولى التحكم في stdin وstdout، فستحتاج إلى تشغيل التعمق في وضع مقطوعة الرأس ثم الاتصال به:
# Start the debugger
$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
API server listening at: 127.0.0.1:43000
# Connect to it from another terminal
$ dlv connect 127.0.0.1:43000
إذا لم تقم بتوفير علامة --listen
بشكل صريح، فسيختلف المنفذ المستخدم لكل عملية تشغيل، لذا فإن تمرير هذا يجعل استخدام مصحح الأخطاء أسهل من برنامج نصي أو من بيئة التطوير المتكاملة (IDE) التي تختارها.
بالإضافة إلى ذلك، قمنا بتمرير --api-version=2
نظرًا لأن إعدادات الحذف الافتراضية هي الإصدار 1 لأسباب تتعلق بالتوافق مع الإصدارات السابقة. ومع ذلك، توصي شركة delve باستخدام الإصدار 2 لجميع عمليات التطوير الجديدة وقد لا يعمل بعض العملاء مع الإصدار 1 بعد الآن. لمزيد من المعلومات، راجع وثائق Delve.
لا يمكنك حقًا تسجيل الدخول إلى stdout باستخدام Bubble Tea لأن TUI الخاص بك مشغول باحتلال ذلك! ومع ذلك، يمكنك تسجيل الدخول إلى ملف عن طريق تضمين شيء مثل ما يلي قبل بدء تشغيل برنامج Bubble Tea:
if len ( os . Getenv ( "DEBUG" )) > 0 {
f , err := tea . LogToFile ( "debug.log" , "debug" )
if err != nil {
fmt . Println ( "fatal:" , err )
os . Exit ( 1 )
}
defer f . Close ()
}
لرؤية ما يتم تسجيله في الوقت الفعلي، قم بتشغيل tail -f debug.log
أثناء تشغيل البرنامج في نافذة أخرى.
يوجد أكثر من 8 آلاف تطبيق تم تصميمه باستخدام Bubble Tea! وهنا حفنة منهم.
لمزيد من التطبيقات المبنية باستخدام Bubble Tea، راجع Charm & Friends. هل هناك شيء رائع صنعته باستخدام Bubble Tea وتريد مشاركته؟ العلاقات العامة هي موضع ترحيب!
انظر المساهمة.
نحن نحب أن نسمع أفكارك حول هذا المشروع. لا تتردد في ترك لنا ملاحظة!
يعتمد Bubble Tea على نماذج The Elm Architecture من تأليف Evan Czaplicki وآخرين والشاي الممتاز من تصميم TJ Holowaychuk. إنها مستوحاة من العديد من Zeichenorientierte Benutzerschnittstellen الرائعة في الأيام الماضية.
معهد ماساتشوستس للتكنولوجيا
جزء من سحر.
Charm热爱开源 • السحر يحب المصادر المفتوحة • نحنُ نعلم المعنى المفتوح