עריכת קוד ב־Go מחוץ לסביבות פיתוח כבדות דרשה עד היום סבלנות יוצאת דופן לפעולות בסיסיות. בזמן שמשתמשי GoLand נהנו מקיצורי מקלדת שמייצרים קוד לפי דרישה, מפתחים שבחרו בעורכים קלים נאלצו לתקתק struct tags ידנית או להסתמך על תוספים צד שלישי שנוטים להישבר בכל עדכון. עכשיו, צוות הפיתוח של השפה מביא את הדיאלוגים האינטראקטיביים ישירות לתוך gopls.
השבוע פורסם בבלוג הרשמי של Go כי שרת השפה מתחדש ביכולת לנהל שיחה אמיתית עם המפתח. העדכון נשען על v0.24.0 של שרת השפה ועל הרחבת VS Code בגרסה v0.56.0. מי שמנהל שירותי ענן בישראל ב־Go מקבל סוף סוף סביבת עבודה קלה שלא מתפשרת על פעולות תחזוקה שוטפות.
סוף לעיוורון של פקודות הקוד
הבעיה שעיכבה את הפיתוח הזה במשך שנים אינה קשורה למנוע הפנימי של Go, אלא למבנה של Language Server Protocol (LSP). הפרוטוקול תוכנן כך שפעולות קוד רגילות התנהגו כמו פונקציות ללא פרמטרים: המשתמש מפעיל פקודה, והשרת מחזיר מיד את עריכות הטקסט. החריג היחיד עד כה היה שינוי שם של סמל, שדרש קריאה ייעודית נפרדת בפרוטוקול כדי לקלוט שם חדש מהמשתמש.
המגבלה אינה ביכולת של gopls לחשב את העריכות הנדרשות, אלא בהיעדרו של מנגנון בתוך LSP המאפשר לשרתי שפה לבקש קלט מהמשתמש.הונגשיאנג ג׳יאנג, מהנדס בצוות Go, בבלוג הרשמי
במקום להטמיע טפסים ייעודיים שנעולים לעורך בודד, צוות Go חבר לצוות Dart. השניים גיבשו את LSP interactive refactoring proposal, שנמצאת בדיון בקהילת התקינה תחת microsoft/language-server-protocol#1164. ההרחבה מאפשרת לשרת השפה להציג תיבות קלט ורשימות בחירה מרובות שלבים בעורך, בלי שהעורך יצטרך להכיר את החוקים הפנימיים של שפת התכנות.
שלושה חידושים שעובדים כבר היום
החידוש הראשון מורגש בהוספת תגיות למבנים. במקום להזריק אוטומטית שדות JSON בתבנית camelCase ללא שאלות, הפקודה מציגה שדה קלט שבו אפשר לציין שילוב של תגיות כמו json, yaml ו־db. שלב נוסף מאפשר לבחור את סגנון השמות הרצוי, למשל snake_case או PascalCase, והשרת מעדכן את כל השדות בהתאם.
היכולת השנייה היא הסרה בררנית של תגיות. בעבר, מחיקת תגיות מחקה את כל המאפיינים של המבנה ללא הבחנה. עכשיו המערכת שואלת אילו מפתחות תרצו להסיר, ומאפשרת למחוק תגיות db בלבד תוך שמירה על הגדרות הסריאליזציה של הרשת.
היכולת השלישית פותרת את מימוש הממשקים. כשמפעילים את הפעולה על טיפוס בטקסט, העורך פותח שדה חיפוש דינמי המשלים שמות מתוך חבילות הפרויקט והספרייה הסטנדרטית. אם בממשק יש טיפוסים כלליים (generics), השרת מבקש מהמפתח להזין את הטיפוס הקונקרטי ומייצר שלד מתודות שלם עם שמות ה־receiver המתאימים. לא צריך יותר לזכור חתימות בעל פה.
לצד פעולות הייצור, המפתחים כללו פקודת הדגמה בשם Slay the dragon שמופעלת על משתנה בשם dragonSlayer, כדי לבדוק שהדיאלוגים הרב שלביים פועלים כסדרם בעורך.
פתוח בתקן, מוגבל בינתיים בעורך
למרות שהתקן תוכנן כסטנדרט פתוח לכלל השפות והעורכים, התמיכה המלאה והעובדת זמינה כרגע רק ב־VS Code.
למרות שהפרוטוקול תוכנן לשרת כל לקוח, התמיכה המלאה והיציבה מוטמעת נכון לעכשיו רק בהרחבה הרשמית של VS Code. מי שעובד בעורכים פופולריים אחרים יגלה שהדרך ארוכה יותר: עבור Neovim קיים כרגע רק מימוש ניסיוני לבדיקת היתכנות, ומצב דומה קיים בתוספים עבור Emacs. משתמשי עורכים קלים אחרים כמו Helix יצטרכו להמתין עד שצוותי הפיתוח של אותם כלים יטמיעו את מפרט הטפסים.
גם עורכי קוד מבוססי בינה מלאכותית כמו Cursor נשענים על תשתית LSP, אך אימוץ רשמי תלוי בקצב שבו מיקרוסופט תמזג את ההצעה לתקן הכללי. בנוסף, לא פורסם מידע על התנהגות החיפוש הדינמי במאגרי ענק (monorepos) עתירי קוד.
הזזת קוד ועדכון חתימות בקנה
מעבר למה שכבר שוחרר, צוות השפה מציג גרסת תצוגה מקדימה ליכולת העברת הצהרות (Move Declaration), שנמצאת במעקב תחת golang/go#70583. הפעולה מאפשרת לבחור טיפוס ולהעביר אותו לקובץ אחר או לחבילה חדשה דרך בורר קבצים. השרת מעביר איתו מתודות וקבועים פרטיים שקשורים אליו, משאיר קוד בלתי תלוי במקומו ומעדכן אוטומטית את הייבוא בכל הפרויקט.
על פי מפת הדרכים, השלב הבא הוא שינוי חתימות פונקציה (Change Signature) תחת golang/go#38028. שינוי של סדר פרמטרים או הוספת ארגומנטים דורשים הגדרת ערכי ברירת מחדל בכל נקודות הקריאה בקוד, משימה שאי אפשר לבצע בלי שאלון מקדים למפתח. בעתיד המנגנון ישמש גם לפעולות שאינן עריכת טקסט, כמו הגדרת פרופילים של מעבד וזיכרון בריצות מבחנים דרך שכבת ה־command.
| יכולת ריפקטורינג | סטטוס זמינות | גרסת מינימום נדרשת | דרישות קלט מהמשתמש |
|---|---|---|---|
| הוספת תגיות מבנה (Struct Tags) | זמין | gopls v0.23.0 / vscode-go v0.56.0 | הזנת שמות תגיות ובחירת סגנון אותיות |
| הסרת תגיות מבנה | זמין | gopls v0.23.0 / vscode-go v0.56.0 | בחירת מפתחות ספציפיים למחיקה |
| מימוש ממשקים (Implement Interface) | זמין | gopls v0.23.0 / vscode-go v0.56.0 | חיפוש שם ממשק והזנת ארגומנטי טיפוס |
| העברת הצהרות בין קבצים וחבילות | תצוגה מקדימה | גרסאות gopls הבאות | בחירת נתיב לקובץ יעד קיים או חדש |
| שינוי חתימת פונקציה (Change Signature) | בתכנון | לא פורסם | הגדרת סדר פרמטרים וערכי ברירת מחדל |
כדי להתחיל לעבוד עם הכלים החדשים אין צורך בהגדרות מיוחדות. שדרגו את שרת השפה gopls לגרסה v0.24.0, ודאו שתוסף Go ב־VS Code מעודכן לגרסה v0.56.0, ותיבות הקלט יופיעו אוטומטית ברגע שתפעילו את פעולות הקוד מהתפריט הרגיל. מה שבאמת מעניין כאן הוא שמי שמשלם על רישיונות GoLand רק בשביל יצירת תגיות ומימוש ממשקים יכול לשקול מחדש את ההוצאה. המרחק בין השניים הצטמצם בעוד צעד.
מקורות
- Interactive refactoring in goplshttps://go.dev/blog/interactive-refactoring
- goplshttps://go.dev/gopls
- Language Server Protocol (LSP)https://microsoft.github.io/language-server-protocol/
- v0.24.0https://go.dev/gopls/release/v0.24.0
- LSP interactive refactoring proposalhttps://go.googlesource.com/proposal/+/refs/heads/master/design/76331-lsp-interactive-refactoring.md
- microsoft/language-server-protocol#1164https://github.com/microsoft/language-server-protocol/issues/1164
- golang/go#70583https://go.dev/issue/70583
- golang/go#38028https://go.dev/issue/38028
- commandhttps://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#command
- v0.56.0https://github.com/golang/vscode-go/releases/tag/v0.56.0
- Neovimhttps://github.com/h9jiang/neovim/tree/interactive-refactoring
- Emacshttps://go-review.googlesource.com/c/tools/+/800220
- Cursorhttps://weba.co.il/tools/cursor/
- JSONhttps://weba.co.il/glossary/json/
הידיעה נכתבה מהמקורות שלמעלה בתאריך הפרסום, וכל טענה בה נבדקה מולם. מצאתם טעות? כתבו.