dsh-ide-git 0.19.7 → 0.19.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +121 -12
- package/src/index.js +8 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-ide-git",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.9",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ide-git",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.9",
|
|
4
4
|
"description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -315,6 +315,7 @@ window.__ModuleLoader__.load({
|
|
|
315
315
|
'lf.truncated': '只显示前 {count} 行',
|
|
316
316
|
'preview.title': 'Git 预览',
|
|
317
317
|
'preview.hint': '点击文件或提交的「显示差异」,差异会在侧边栏这里打开。',
|
|
318
|
+
'preview.boundary': '预览渲染出错——请重载页面,或反馈这个问题。',
|
|
318
319
|
'settings.rail.title': '动作条',
|
|
319
320
|
'settings.rail.hint': '勾选要显示在动作条上的动作;顺序固定为默认顺序,取消勾选即隐藏。',
|
|
320
321
|
'settings.rail.unavailable': '当前宿主没有设置服务,请用面板内的「动作条设置」。',
|
|
@@ -642,6 +643,7 @@ window.__ModuleLoader__.load({
|
|
|
642
643
|
'lf.truncated': 'Showing the first {count} lines',
|
|
643
644
|
'preview.title': 'Git Preview',
|
|
644
645
|
'preview.hint': 'Click “Show diff” on a file or commit — the diff opens here in the sidebar.',
|
|
646
|
+
'preview.boundary': 'The preview failed to render — reload the page, or report an issue.',
|
|
645
647
|
'settings.rail.title': 'Action rail',
|
|
646
648
|
'settings.rail.hint': 'Tick the actions shown on the rail. The order is fixed; unticking one hides it.',
|
|
647
649
|
'settings.rail.unavailable': 'This host has no settings service; use the in-panel “Action rail settings”.',
|
|
@@ -977,6 +979,7 @@ window.__ModuleLoader__.load({
|
|
|
977
979
|
'lf.truncated': '只顯示前 {count} 行',
|
|
978
980
|
'preview.title': 'Git 預覽',
|
|
979
981
|
'preview.hint': '喺檔案或提交撳「顯示差異」,差異就會喺側邊欄度開啟。',
|
|
982
|
+
'preview.boundary': '預覽渲染出錯——請重新載入頁面,或者回報呢個問題。',
|
|
980
983
|
'settings.rail.title': '動作列',
|
|
981
984
|
'settings.rail.hint': '勾選要顯示在動作列上的動作;順序固定,取消勾選即隱藏。',
|
|
982
985
|
'settings.rail.unavailable': '目前宿主沒有設定服務,請用面板內的「動作條設定」。',
|
|
@@ -1304,6 +1307,7 @@ window.__ModuleLoader__.load({
|
|
|
1304
1307
|
'lf.truncated': '只顯示前 {count} 行',
|
|
1305
1308
|
'preview.title': 'Git 預覽',
|
|
1306
1309
|
'preview.hint': '點選檔案或提交的「顯示差異」,差異就會在側邊欄開啟。',
|
|
1310
|
+
'preview.boundary': '預覽算繪出錯——請重新載入頁面,或回報這個問題。',
|
|
1307
1311
|
'settings.rail.title': '動作列',
|
|
1308
1312
|
'settings.rail.hint': '勾選要顯示在動作列上的動作;順序固定,取消勾選即隱藏。',
|
|
1309
1313
|
'settings.rail.unavailable': '目前宿主沒有設定服務,請用面板內的「動作條設定」。',
|
|
@@ -1631,6 +1635,7 @@ window.__ModuleLoader__.load({
|
|
|
1631
1635
|
'lf.truncated': '只顯示前 {count} 行',
|
|
1632
1636
|
'preview.title': 'Git 預覽',
|
|
1633
1637
|
'preview.hint': '喺檔案或提交撳「顯示差異」,差異就會喺側邊欄度開啟。',
|
|
1638
|
+
'preview.boundary': '預覽渲染出錯——請重新載入頁面,或者回報呢個問題。',
|
|
1634
1639
|
'settings.rail.title': '動作列',
|
|
1635
1640
|
'settings.rail.hint': '勾選要顯示在動作列上的動作;順序固定,取消勾選即隱藏。',
|
|
1636
1641
|
'settings.rail.unavailable': '目前宿主沒有設定服務,請用面板內的「動作條設定」。',
|
|
@@ -1958,6 +1963,7 @@ window.__ModuleLoader__.load({
|
|
|
1958
1963
|
'lf.truncated': '先頭 {count} 行のみ表示',
|
|
1959
1964
|
'preview.title': 'Git プレビュー',
|
|
1960
1965
|
'preview.hint': 'ファイルやコミットの「差分を表示」をクリックすると、差分がここに開きます。',
|
|
1966
|
+
'preview.boundary': 'プレビューの描画に失敗しました——ページを再読み込みするか、問題を報告してください。',
|
|
1961
1967
|
'settings.rail.title': 'レール',
|
|
1962
1968
|
'settings.rail.hint': 'レールに表示する操作にチェックを入れてください。順序は固定で、チェックを外すと非表示になります。',
|
|
1963
1969
|
'settings.rail.unavailable': 'このホストには設定サービスがないため、パネル内の「アクションレール設定」を使ってください。',
|
|
@@ -2285,6 +2291,7 @@ window.__ModuleLoader__.load({
|
|
|
2285
2291
|
'lf.truncated': '처음 {count}줄만 표시',
|
|
2286
2292
|
'preview.title': 'Git 미리보기',
|
|
2287
2293
|
'preview.hint': '파일이나 커밋의 「차이 보기」를 클릭하면 차이가 사이드바 여기에 열립니다.',
|
|
2294
|
+
'preview.boundary': '미리보기 렌더링에 실패했습니다 — 페이지를 새로고침하거나 문제를 보고해 주세요.',
|
|
2288
2295
|
'settings.rail.title': '레일',
|
|
2289
2296
|
'settings.rail.hint': '레일에 표시할 동작을 선택하세요. 순서는 고정이며 선택을 해제하면 숨겨집니다.',
|
|
2290
2297
|
'settings.rail.unavailable': '이 호스트에는 설정 서비스가 없으므로 패널의 "액션 레일 설정"을 사용하세요.',
|
|
@@ -2612,6 +2619,7 @@ window.__ModuleLoader__.load({
|
|
|
2612
2619
|
'lf.truncated': 'Nur die ersten {count} Zeilen',
|
|
2613
2620
|
'preview.title': 'Git-Vorschau',
|
|
2614
2621
|
'preview.hint': '„Diff anzeigen“ an einer Datei oder einem Commit öffnet den Diff hier in der Seitenleiste.',
|
|
2622
|
+
'preview.boundary': 'Die Vorschau konnte nicht gerendert werden – Seite neu laden oder das Problem melden.',
|
|
2615
2623
|
'settings.rail.title': 'Aktionsleiste',
|
|
2616
2624
|
'settings.rail.hint': 'Die auf der Leiste sichtbaren Aktionen ankreuzen. Die Reihenfolge ist fest; abwählen blendet eine aus.',
|
|
2617
2625
|
'settings.rail.unavailable': 'Dieser Host hat keinen Einstellungsdienst; nutze die „Aktionsleisten-Einstellungen“ im Panel.',
|
|
@@ -2939,6 +2947,7 @@ window.__ModuleLoader__.load({
|
|
|
2939
2947
|
'lf.truncated': 'Affichage des {count} premières lignes',
|
|
2940
2948
|
'preview.title': 'Aperçu Git',
|
|
2941
2949
|
'preview.hint': 'Cliquez sur « Afficher le diff » sur un fichier ou un commit : le diff s’ouvre ici, dans la barre latérale.',
|
|
2950
|
+
'preview.boundary': 'L\'aperçu n\'a pas pu être affiché — rechargez la page ou signalez le problème.',
|
|
2942
2951
|
'settings.rail.title': 'Barre d’actions',
|
|
2943
2952
|
'settings.rail.hint': 'Cochez les actions affichées sur la barre. L’ordre est fixe ; décocher masque une action.',
|
|
2944
2953
|
'settings.rail.unavailable': 'Cet hôte n’a pas de service de réglages ; utilisez « Réglages de la barre d’actions » dans le panneau.',
|
|
@@ -3266,6 +3275,7 @@ window.__ModuleLoader__.load({
|
|
|
3266
3275
|
'lf.truncated': 'Показаны первые {count} строк',
|
|
3267
3276
|
'preview.title': 'Git-предпросмотр',
|
|
3268
3277
|
'preview.hint': 'Нажмите «Показать различия» у файла или коммита — различия откроются здесь, в боковой панели.',
|
|
3278
|
+
'preview.boundary': 'Не удалось отобразить предпросмотр — перезагрузите страницу или сообщите о проблеме.',
|
|
3269
3279
|
'settings.rail.title': 'Панель действий',
|
|
3270
3280
|
'settings.rail.hint': 'Отметьте действия, показываемые на панели. Порядок фиксирован; снятие флажка скрывает действие.',
|
|
3271
3281
|
'settings.rail.unavailable': 'На этом хосте нет службы настроек; используйте «Настройки панели действий» в панели.',
|
|
@@ -3593,6 +3603,7 @@ window.__ModuleLoader__.load({
|
|
|
3593
3603
|
'lf.truncated': 'Mostrando as primeiras {count} linhas',
|
|
3594
3604
|
'preview.title': 'Pré-visualização do Git',
|
|
3595
3605
|
'preview.hint': 'Clique em “Mostrar diff” num arquivo ou commit — o diff abre aqui, na barra lateral.',
|
|
3606
|
+
'preview.boundary': 'Falha ao renderizar a pré-visualização — recarregue a página ou relate o problema.',
|
|
3596
3607
|
'settings.rail.title': 'Barra de ações',
|
|
3597
3608
|
'settings.rail.hint': 'Marque as ações exibidas na barra. A ordem é fixa; desmarcar oculta uma ação.',
|
|
3598
3609
|
'settings.rail.unavailable': 'Este host não tem serviço de configurações; use «Configurações da barra de ações» no painel.',
|
|
@@ -3920,6 +3931,7 @@ window.__ModuleLoader__.load({
|
|
|
3920
3931
|
'lf.truncated': 'Mostrate le prime {count} righe',
|
|
3921
3932
|
'preview.title': 'Anteprima Git',
|
|
3922
3933
|
'preview.hint': 'Fai clic su «Mostra diff» su un file o un commit: il diff si apre qui, nella barra laterale.',
|
|
3934
|
+
'preview.boundary': 'Impossibile visualizzare l\'anteprima — ricarica la pagina o segnala il problema.',
|
|
3923
3935
|
'settings.rail.title': 'Barra delle azioni',
|
|
3924
3936
|
'settings.rail.hint': 'Seleziona le azioni mostrate sulla barra. L’ordine è fisso; deselezionando se ne nasconde una.',
|
|
3925
3937
|
'settings.rail.unavailable': 'Questo host non ha un servizio di impostazioni; usa «Impostazioni barra azioni» nel pannello.',
|
|
@@ -4247,6 +4259,7 @@ window.__ModuleLoader__.load({
|
|
|
4247
4259
|
'lf.truncated': 'Eerste {count} regels worden weergegeven',
|
|
4248
4260
|
'preview.title': 'Git-voorbeeld',
|
|
4249
4261
|
'preview.hint': 'Klik op „Diff tonen“ bij een bestand of commit — de diff opent hier in de zijbalk.',
|
|
4262
|
+
'preview.boundary': 'De voorvertoning kon niet worden weergegeven — herlaad de pagina of meld het probleem.',
|
|
4250
4263
|
'settings.rail.title': 'Actiebalk',
|
|
4251
4264
|
'settings.rail.hint': 'Vink de acties aan die op de balk verschijnen. De volgorde ligt vast; uitvinken verbergt er een.',
|
|
4252
4265
|
'settings.rail.unavailable': 'Deze host heeft geen instellingenservice; gebruik "Actiebalk-instellingen" in het paneel.',
|
|
@@ -4574,6 +4587,7 @@ window.__ModuleLoader__.load({
|
|
|
4574
4587
|
'lf.truncated': 'Pokazano pierwsze {count} wierszy',
|
|
4575
4588
|
'preview.title': 'Podgląd Git',
|
|
4576
4589
|
'preview.hint': 'Kliknij „Pokaż różnice” przy pliku lub commicie — różnice otworzą się tutaj, na pasku bocznym.',
|
|
4590
|
+
'preview.boundary': 'Nie udało się wyświetlić podglądu — odśwież stronę lub zgłoś problem.',
|
|
4577
4591
|
'settings.rail.title': 'Pasek akcji',
|
|
4578
4592
|
'settings.rail.hint': 'Zaznacz akcje widoczne na pasku. Kolejność jest stała; odznaczenie ukrywa akcję.',
|
|
4579
4593
|
'settings.rail.unavailable': 'Ten host nie ma usługi ustawień; użyj „Ustawienia paska akcji” w panelu.',
|
|
@@ -4901,6 +4915,7 @@ window.__ModuleLoader__.load({
|
|
|
4901
4915
|
'lf.truncated': 'Visar de första {count} raderna',
|
|
4902
4916
|
'preview.title': 'Git-förhandsvisning',
|
|
4903
4917
|
'preview.hint': 'Klicka på ”Visa diff” på en fil eller en commit — diffen öppnas här i sidopanelen.',
|
|
4918
|
+
'preview.boundary': 'Förhandsvisningen kunde inte visas — ladda om sidan eller rapportera problemet.',
|
|
4904
4919
|
'settings.rail.title': 'Åtgärdsfältet',
|
|
4905
4920
|
'settings.rail.hint': 'Markera de åtgärder som visas i fältet. Ordningen är fast; avmarkering döljer en.',
|
|
4906
4921
|
'settings.rail.unavailable': 'Denna värd saknar inställningstjänst; använd ”Åtgärdsfältets inställningar” i panelen.',
|
|
@@ -5228,6 +5243,7 @@ window.__ModuleLoader__.load({
|
|
|
5228
5243
|
'lf.truncated': 'Yalnızca ilk {count} satır gösteriliyor',
|
|
5229
5244
|
'preview.title': 'Git Önizlemesi',
|
|
5230
5245
|
'preview.hint': 'Bir dosya veya commit üzerinde „Farkı göster”e tıklayın — fark burada, kenar çubuğunda açılır.',
|
|
5246
|
+
'preview.boundary': 'Önizleme işlenemedi — sayfayı yeniden yükleyin veya sorunu bildirin.',
|
|
5231
5247
|
'settings.rail.title': 'Eylem çubuğu',
|
|
5232
5248
|
'settings.rail.hint': 'Çubukta gösterilecek eylemleri işaretleyin. Sıra sabittir; işareti kaldırmak eylemi gizler.',
|
|
5233
5249
|
'settings.rail.unavailable': 'Bu ana bilgisayarda ayar hizmeti yok; paneldeki "Eylem çubuğu ayarları"nı kullanın.',
|
|
@@ -5555,6 +5571,7 @@ window.__ModuleLoader__.load({
|
|
|
5555
5571
|
'lf.truncated': 'Menampilkan {count} baris pertama',
|
|
5556
5572
|
'preview.title': 'Pratinjau Git',
|
|
5557
5573
|
'preview.hint': 'Klik “Tampilkan diff” pada file atau commit — diff terbuka di sini, di bilah sisi.',
|
|
5574
|
+
'preview.boundary': 'Pratinjau gagal dirender — muat ulang halaman atau laporkan masalahnya.',
|
|
5558
5575
|
'settings.rail.title': 'Bilah aksi',
|
|
5559
5576
|
'settings.rail.hint': 'Centang aksi yang ditampilkan di bilah. Urutannya tetap; menghapus centang menyembunyikannya.',
|
|
5560
5577
|
'settings.rail.unavailable': 'Host ini tidak punya layanan pengaturan; gunakan "Pengaturan bilah aksi" di panel.',
|
|
@@ -5882,6 +5899,7 @@ window.__ModuleLoader__.load({
|
|
|
5882
5899
|
'lf.truncated': 'Chỉ hiện {count} dòng đầu',
|
|
5883
5900
|
'preview.title': 'Xem trước Git',
|
|
5884
5901
|
'preview.hint': 'Bấm “Xem diff” trên tệp hoặc commit — diff sẽ mở ở đây, trên thanh bên.',
|
|
5902
|
+
'preview.boundary': 'Không thể hiển thị bản xem trước — hãy tải lại trang hoặc báo cáo sự cố.',
|
|
5885
5903
|
'settings.rail.title': 'Thanh tác vụ',
|
|
5886
5904
|
'settings.rail.hint': 'Chọn các tác vụ hiển thị trên thanh. Thứ tự cố định; bỏ chọn sẽ ẩn tác vụ đó.',
|
|
5887
5905
|
'settings.rail.unavailable': 'Máy chủ này không có dịch vụ cài đặt; hãy dùng “Cài đặt thanh tác vụ” trong bảng điều khiển.',
|
|
@@ -6209,6 +6227,7 @@ window.__ModuleLoader__.load({
|
|
|
6209
6227
|
'lf.truncated': 'عرض أول {count} سطرًا فقط',
|
|
6210
6228
|
'preview.title': 'معاينة Git',
|
|
6211
6229
|
'preview.hint': 'انقر «عرض الفروق» على ملف أو commit — تُفتح الفروق هنا في الشريط الجانبي.',
|
|
6230
|
+
'preview.boundary': 'تعذّر عرض المعاينة — أعد تحميل الصفحة أو أبلغ عن المشكلة.',
|
|
6212
6231
|
'settings.rail.title': 'شريط الإجراءات',
|
|
6213
6232
|
'settings.rail.hint': 'حدّد الإجراءات المعروضة على الشريط. الترتيب ثابت، وإلغاء التحديد يخفي الإجراء.',
|
|
6214
6233
|
'settings.rail.unavailable': 'لا تتوفر خدمة إعدادات على هذا المضيف؛ استخدم «إعدادات شريط الإجراءات» في اللوحة.',
|
|
@@ -6536,6 +6555,7 @@ window.__ModuleLoader__.load({
|
|
|
6536
6555
|
'lf.truncated': 'केवल पहली {count} पंक्तियाँ दिखाई जा रही हैं',
|
|
6537
6556
|
'preview.title': 'Git पूर्वावलोकन',
|
|
6538
6557
|
'preview.hint': 'फ़ाइल या कमिट पर “अंतर दिखाएँ” पर क्लिक करें — अंतर यहीं साइडबार में खुलेगा।',
|
|
6558
|
+
'preview.boundary': 'पूर्वावलोकन रेंडर नहीं हो सका — पृष्ठ पुनः लोड करें या समस्या की रिपोर्ट करें।',
|
|
6539
6559
|
'settings.rail.title': 'क्रिया रेल',
|
|
6540
6560
|
'settings.rail.hint': 'रेल पर दिखने वाली क्रियाएँ चुनें। क्रम निश्चित है; चुनाव हटाने पर वह छिप जाती है।',
|
|
6541
6561
|
'settings.rail.unavailable': 'इस होस्ट में सेटिंग सेवा नहीं है; पैनल में «एक्शन रेल सेटिंग» का उपयोग करें।',
|
|
@@ -6863,6 +6883,7 @@ window.__ModuleLoader__.load({
|
|
|
6863
6883
|
'lf.truncated': 'แสดงเฉพาะ {count} บรรทัดแรก',
|
|
6864
6884
|
'preview.title': 'ดูตัวอย่าง Git',
|
|
6865
6885
|
'preview.hint': 'คลิก “แสดงความต่าง” ที่ไฟล์หรือคอมมิต — ความต่างจะเปิดที่นี่ในแถบข้าง',
|
|
6886
|
+
'preview.boundary': 'แสดงผลตัวอย่างไม่สำเร็จ — โหลดหน้าซ้ำหรือรายงานปัญหา',
|
|
6866
6887
|
'settings.rail.title': 'แถบการทำงาน',
|
|
6867
6888
|
'settings.rail.hint': 'ทำเครื่องหมายการทำงานที่จะแสดงบนแถบ ลำดับคงที่; ยกเลิกเครื่องหมายเพื่อซ่อน',
|
|
6868
6889
|
'settings.rail.unavailable': 'โฮสต์นี้ไม่มีบริการตั้งค่า ให้ใช้ «ตั้งค่าแถบการทำงาน» ในแผง',
|
|
@@ -7047,6 +7068,20 @@ window.__ModuleLoader__.load({
|
|
|
7047
7068
|
return kind + ':' + entry.name
|
|
7048
7069
|
}
|
|
7049
7070
|
|
|
7071
|
+
/* v0.19.9: the REMOTE section folds by path exactly like the local one. In
|
|
7072
|
+
the common single-remote repo every row starts with the same "<remote>/"
|
|
7073
|
+
prefix, which would nest every tree under one folder named after the
|
|
7074
|
+
remote — noise, not grouping — so the strip applies only when EVERY name
|
|
7075
|
+
shares that first segment AND carries it (a bare "main" beside
|
|
7076
|
+
"origin/main" means mixed shapes and keeps full names). */
|
|
7077
|
+
function remoteTreeStripOf(names) {
|
|
7078
|
+
if (names.length === 0) return ''
|
|
7079
|
+
const first = names.map((name) => String(name).split('/')[0])
|
|
7080
|
+
if (new Set(first).size !== 1) return ''
|
|
7081
|
+
const prefix = first[0] + '/'
|
|
7082
|
+
return names.every((name) => String(name).startsWith(prefix) === true) ? prefix : ''
|
|
7083
|
+
}
|
|
7084
|
+
|
|
7050
7085
|
/* Join selected values for the clipboard — one per line, the shape a
|
|
7051
7086
|
terminal or an editor expects when pasting a list. */
|
|
7052
7087
|
function clipboardLines(values) {
|
|
@@ -9095,6 +9130,30 @@ window.__ModuleLoader__.load({
|
|
|
9095
9130
|
return E(SeedTooltip, { label: props.label, side: 'bottom', delayMs: 500 }, inner)
|
|
9096
9131
|
}
|
|
9097
9132
|
|
|
9133
|
+
/* Render boundary around the preview body (issue #16): a throw inside the
|
|
9134
|
+
diff rows used to bubble past every plugin component into the host's
|
|
9135
|
+
slot boundary, which unmounts the whole tab — the user sees a silently
|
|
9136
|
+
blank "Git 预览" pane. With the boundary the panel keeps its chrome and
|
|
9137
|
+
shows one line of explanation instead. React only supports error
|
|
9138
|
+
boundaries as classes; this stays a module-level pure class (no hooks,
|
|
9139
|
+
no context) so the no-build client rules are untouched. */
|
|
9140
|
+
class RenderBoundary extends React.Component {
|
|
9141
|
+
constructor(props) {
|
|
9142
|
+
super(props)
|
|
9143
|
+
this.state = { failed: false }
|
|
9144
|
+
}
|
|
9145
|
+
static getDerivedStateFromError() {
|
|
9146
|
+
return { failed: true }
|
|
9147
|
+
}
|
|
9148
|
+
componentDidCatch(error) {
|
|
9149
|
+
try { console.error('[dsh-ide-git] preview render failed:', error) } catch (_) { /* diagnostics must never rethrow */ }
|
|
9150
|
+
}
|
|
9151
|
+
render() {
|
|
9152
|
+
if (this.state.failed === true) return E('div', { className: 'dig-preview-boundary' }, this.props.message)
|
|
9153
|
+
return this.props.children
|
|
9154
|
+
}
|
|
9155
|
+
}
|
|
9156
|
+
|
|
9098
9157
|
/* The external preview's diff view: the official review's header (file
|
|
9099
9158
|
selector + counts + split/wrap/open tools) over the official row
|
|
9100
9159
|
anatomy, fed by the plugin's own patch text instead of the host's
|
|
@@ -9200,10 +9259,18 @@ window.__ModuleLoader__.load({
|
|
|
9200
9259
|
? E(SplitColumns, { hunks: cut.hunks, highlights: cut.maps })
|
|
9201
9260
|
: cut.hunks.map((hunk, position) => {
|
|
9202
9261
|
const paired = split === true ? splitRows(hunk) : null
|
|
9262
|
+
// The wrapped branch must iterate the SAME row list it indexes
|
|
9263
|
+
// (issue #16): splitRows pairs del/add runs, so its length is
|
|
9264
|
+
// max(dels, adds) per run — strictly less than hunkRows'
|
|
9265
|
+
// per-line count whenever anything pairs. Indexing paired with
|
|
9266
|
+
// hunkRows' indices handed SplitLine an undefined row and took
|
|
9267
|
+
// the whole panel down (no boundary above it). Each paired
|
|
9268
|
+
// entry is already { left, right } — exactly SplitLine's shape.
|
|
9269
|
+
const rows = split === true ? paired : hunkRows(hunk)
|
|
9203
9270
|
return E('section', { key: position, className: 'dig-lf-hunk' },
|
|
9204
9271
|
E('div', { className: 'dig-lf-hunkHeader', 'data-diff-hunk-header': '' }, hunkHeader(hunk)),
|
|
9205
|
-
|
|
9206
|
-
? E(SplitLine, { key: at, row:
|
|
9272
|
+
rows.map((row, at) => split === true
|
|
9273
|
+
? E(SplitLine, { key: at, row: row, spans: cut.maps[position] })
|
|
9207
9274
|
: E(UnifiedLine, { key: at, row: row, spans: cut.maps[position] })))
|
|
9208
9275
|
})))
|
|
9209
9276
|
}
|
|
@@ -10196,6 +10263,22 @@ window.__ModuleLoader__.load({
|
|
|
10196
10263
|
return props.vertical === true ? rect.width : rect.height
|
|
10197
10264
|
}
|
|
10198
10265
|
const sign = props.side === 'next' ? -1 : 1
|
|
10266
|
+
/* Pointermove arrives faster than frames can paint, and every dragPane
|
|
10267
|
+
* does a forced reflow (measurePanes) plus two setStates — handling each
|
|
10268
|
+
* event is layout thrashing, and the report (#16 follow-up) is exactly
|
|
10269
|
+
* that: a drag starts smooth, then feels glued to the cursor. The latest
|
|
10270
|
+
* px parks in a ref and ONE rAF per frame hands it to the clamp; pointerup
|
|
10271
|
+
* flushes the parked value first so a gesture never ends on a stale size. */
|
|
10272
|
+
const frameRef = useRef(0)
|
|
10273
|
+
const pendingRef = useRef(null)
|
|
10274
|
+
const flushRef = useRef(null)
|
|
10275
|
+
useEffect(() => () => { if (frameRef.current !== 0) cancelAnimationFrame(frameRef.current) }, [])
|
|
10276
|
+
flushRef.current = () => {
|
|
10277
|
+
if (frameRef.current !== 0) { cancelAnimationFrame(frameRef.current); frameRef.current = 0 }
|
|
10278
|
+
const value = pendingRef.current
|
|
10279
|
+
pendingRef.current = null
|
|
10280
|
+
if (value !== null) props.onDrag(value)
|
|
10281
|
+
}
|
|
10199
10282
|
const onPointerDown = (event) => {
|
|
10200
10283
|
if (event.button !== undefined && event.button !== 0) return
|
|
10201
10284
|
dragRef.current = {
|
|
@@ -10211,11 +10294,13 @@ window.__ModuleLoader__.load({
|
|
|
10211
10294
|
const drag = dragRef.current
|
|
10212
10295
|
if (drag === null || drag.id !== event.pointerId) return
|
|
10213
10296
|
const at = props.vertical === true ? event.clientX : event.clientY
|
|
10214
|
-
|
|
10297
|
+
pendingRef.current = drag.size + sign * (at - drag.at)
|
|
10298
|
+
if (frameRef.current === 0) frameRef.current = requestAnimationFrame(() => flushRef.current())
|
|
10215
10299
|
}
|
|
10216
10300
|
const onPointerUp = () => {
|
|
10217
10301
|
if (dragRef.current === null) return
|
|
10218
10302
|
dragRef.current = null
|
|
10303
|
+
if (frameRef.current !== 0) flushRef.current()
|
|
10219
10304
|
props.onEnd()
|
|
10220
10305
|
}
|
|
10221
10306
|
const onKeyDown = (event) => {
|
|
@@ -10425,6 +10510,13 @@ window.__ModuleLoader__.load({
|
|
|
10425
10510
|
double-click browses the current branch's history, right-click opens
|
|
10426
10511
|
the same row menu (quick jump back to HEAD lives there). */
|
|
10427
10512
|
const headEntry = locals.find((entry) => entry.head === true) || null
|
|
10513
|
+
/* v0.19.9: remote rows group by their path BELOW the "<remote>/" prefix;
|
|
10514
|
+
the full name still drives every selKey/menu/checkout path. */
|
|
10515
|
+
const remoteStrip = remoteTreeStripOf(remotes.map((entry) => entry.name))
|
|
10516
|
+
const remoteNameOf = (entry) => {
|
|
10517
|
+
const name = String(entry.name)
|
|
10518
|
+
return remoteStrip !== '' && name.startsWith(remoteStrip) === true ? name.slice(remoteStrip.length) : name
|
|
10519
|
+
}
|
|
10428
10520
|
/* A refresh that makes a picked ref disappear must not keep it selected. */
|
|
10429
10521
|
useEffect(() => {
|
|
10430
10522
|
reportGestureRef.current = false
|
|
@@ -10454,10 +10546,14 @@ window.__ModuleLoader__.load({
|
|
|
10454
10546
|
* row only SELECTS it (checking out rewrites the working tree), so the row
|
|
10455
10547
|
* carries the selection and a double-click does the checkout.
|
|
10456
10548
|
*/
|
|
10457
|
-
|
|
10549
|
+
/* nameOf (v0.19.9) lets the remote section group by its name WITHOUT the
|
|
10550
|
+
"<remote>/" prefix (see remoteTreeStripOf) while every row keeps its
|
|
10551
|
+
full entry.name for selection, menus and checkout. */
|
|
10552
|
+
const forestOf = (entries, nameOf) => {
|
|
10553
|
+
const labelOf = nameOf === undefined ? (entry) => entry.name : nameOf
|
|
10458
10554
|
const root = { folders: new Map(), leaves: [] }
|
|
10459
10555
|
for (const entry of entries) {
|
|
10460
|
-
const parts = String(entry
|
|
10556
|
+
const parts = String(labelOf(entry)).split('/')
|
|
10461
10557
|
let node = root
|
|
10462
10558
|
for (let index = 0; index < parts.length - 1; index += 1) {
|
|
10463
10559
|
const key = parts[index]
|
|
@@ -10538,7 +10634,9 @@ window.__ModuleLoader__.load({
|
|
|
10538
10634
|
for (const leaf of node.leaves) out.push(branchRow(leaf.entry, leaf.label, depth))
|
|
10539
10635
|
return out
|
|
10540
10636
|
}
|
|
10541
|
-
|
|
10637
|
+
/* ns (v0.19.9) namespaces the fold ids of a grouped section ("remote/…")
|
|
10638
|
+
so its folders remember their state independently of the local ones. */
|
|
10639
|
+
const section = (key, title, entries, decorate, grouped, ns, nameOf) => E('div', { className: 'dig-section', key: key },
|
|
10542
10640
|
E('button', {
|
|
10543
10641
|
type: 'button', className: 'dig-section-head',
|
|
10544
10642
|
onClick: () => setCollapsed((previous) => Object.assign({}, previous, { [key]: !previous[key] })),
|
|
@@ -10549,14 +10647,16 @@ window.__ModuleLoader__.load({
|
|
|
10549
10647
|
E('span', null, title)),
|
|
10550
10648
|
collapsed[key] === true ? null : E('div', { className: 'dig-section-body' },
|
|
10551
10649
|
grouped === true
|
|
10552
|
-
? rowsOf(forestOf(entries.map((entry) => decorate(entry))), '', 0)
|
|
10650
|
+
? rowsOf(forestOf(entries.map((entry) => decorate(entry)), nameOf), ns || '', 0)
|
|
10553
10651
|
: entries.map((entry) => branchRow(decorate(entry), undefined, 0))))
|
|
10554
10652
|
/* Render-order mirror for Shift-ranges and Ctrl+A, plus the selKey→entry
|
|
10555
10653
|
lookup the right-click menu and the Delete key resolve through. */
|
|
10556
10654
|
const visibleLeaves = []
|
|
10557
10655
|
if (favorites.length > 0) flatLeaves(forestOf(locals.filter((entry) => favorites.indexOf(entry.name) >= 0)), '', 0, visibleLeaves)
|
|
10558
10656
|
flatLeaves(forestOf(locals), '', 0, visibleLeaves)
|
|
10559
|
-
|
|
10657
|
+
/* Same tree, same prefix namespace the section renders with — Shift-ranges
|
|
10658
|
+
and Ctrl+A must walk the EXACT order rows are shown in. */
|
|
10659
|
+
flatLeaves(forestOf(remotes.map((entry) => Object.assign({}, entry, { remote: true })), remoteNameOf), 'remote', 0, visibleLeaves)
|
|
10560
10660
|
for (const entry of tags) visibleLeaves.push({ entry: entry, label: undefined, depth: 0 })
|
|
10561
10661
|
visibleRef.current = visibleLeaves
|
|
10562
10662
|
const entryBySelKey = new Map()
|
|
@@ -10673,7 +10773,7 @@ window.__ModuleLoader__.load({
|
|
|
10673
10773
|
}, t('branches.head')),
|
|
10674
10774
|
favorites.length === 0 ? null : section('favorites', t('branches.favorites'), locals.filter((entry) => favorites.indexOf(entry.name) >= 0), (entry) => entry),
|
|
10675
10775
|
section('local', t('branches.local'), locals, (entry) => entry, true),
|
|
10676
|
-
section('remote', t('branches.remote'), remotes, (entry) => Object.assign({}, entry, { remote: true })),
|
|
10776
|
+
section('remote', t('branches.remote'), remotes, (entry) => Object.assign({}, entry, { remote: true }), true, 'remote', remoteNameOf),
|
|
10677
10777
|
section('tags', t('branches.tags'), tags, (entry) => Object.assign({}, entry, { tag: true }))),
|
|
10678
10778
|
E(MarqueeBox, { box: treeMarquee.box }))
|
|
10679
10779
|
}
|
|
@@ -12036,7 +12136,15 @@ window.__ModuleLoader__.load({
|
|
|
12036
12136
|
re-clamps a stored size has to see the same numbers the drag did — a drag
|
|
12037
12137
|
allowed further than the render allows snaps back under the cursor. The
|
|
12038
12138
|
bail-out comparison is what keeps this from looping. */
|
|
12039
|
-
|
|
12139
|
+
/* A LAYOUT effect: on mount this runs before the first paint, so the
|
|
12140
|
+
fallback layout (paneGeometry's stylesheet/literal defaults) is
|
|
12141
|
+
replaced by the live one inside the same frame instead of being
|
|
12142
|
+
painted and then jumped a frame later. Painting both is the "height
|
|
12143
|
+
animation" on tab switches from issue #16 — two visible layouts ~80px
|
|
12144
|
+
apart read as a smooth resize in a low-fps screen recording. Later
|
|
12145
|
+
runs still track content arrival; the layout-phase cost is one
|
|
12146
|
+
querySelectorAll over the 3-4 panes the post-paint run already paid. */
|
|
12147
|
+
useMeasureLayoutEffect(() => {
|
|
12040
12148
|
const found = measurePanes()
|
|
12041
12149
|
setPaneSizes((current) => (samePaneSizes(current, found) ? current : found))
|
|
12042
12150
|
})
|
|
@@ -14699,6 +14807,7 @@ window.__ModuleLoader__.load({
|
|
|
14699
14807
|
'.dig-lf-root{--diff-empty-fill:color-mix(in srgb,var(--dsw-alias-interactive-bg-hover) 50%,transparent);display:flex;flex-direction:column;box-sizing:border-box;width:100%;min-height:0;color:var(--dsw-alias-label-primary)}',
|
|
14700
14808
|
'.dig-lf-header{display:flex;flex:0 0 auto;gap:6px;align-items:center;box-sizing:border-box;min-height:38px;padding:0 6px 0 8px;border-bottom:0.5px solid var(--dsw-alias-border-l3)}',
|
|
14701
14809
|
'.dig-lf-status{display:flex;gap:12px;align-items:center;margin:0;padding:16px;font-size:13px;color:var(--dsw-alias-label-secondary)}',
|
|
14810
|
+
'.dig-preview-boundary{display:flex;align-items:center;justify-content:center;margin:0;padding:24px 16px;font-size:13px;color:var(--dsw-alias-label-secondary);text-align:center}',
|
|
14702
14811
|
'.dig-lf-body{display:flex;flex:1 1 auto;flex-direction:column;min-height:0;overflow:auto;padding:8px 0 16px;font:var(--dsw-font-markdown-code-block)}',
|
|
14703
14812
|
'.dig-lf-columns{display:grid;flex:1 1 auto;grid-template-columns:minmax(0,1fr) minmax(0,1fr);min-height:0}',
|
|
14704
14813
|
'.dig-lf-column,.dig-lf-body[data-review-view=unified]:not([data-review-wrap]){display:grid;grid-template-columns:minmax(max-content,100%);align-content:start}',
|
|
@@ -15539,14 +15648,14 @@ window.__ModuleLoader__.load({
|
|
|
15539
15648
|
? E('div', { className: 'dig-preview-body' }, E('div', { className: 'dig-empty' }, t('preview.hint')))
|
|
15540
15649
|
: state.error !== null
|
|
15541
15650
|
? E('div', { className: 'dig-preview-body' }, E('div', { className: 'dig-empty' }, state.error))
|
|
15542
|
-
: E('div', { className: 'dig-preview-body' }, E(LineDiff, {
|
|
15651
|
+
: E('div', { className: 'dig-preview-body' }, E(RenderBoundary, { message: t('preview.boundary') }, E(LineDiff, {
|
|
15543
15652
|
patch: state.patch,
|
|
15544
15653
|
loading: state.loading,
|
|
15545
15654
|
t: t,
|
|
15546
15655
|
/* worktree seeds carry the file path: the review's open-file
|
|
15547
15656
|
tool jumps to the host's whole-file preview. */
|
|
15548
15657
|
onOpenFile: seed.path !== undefined && seed.path !== null && seed.path !== '' ? openInFilePreview : undefined,
|
|
15549
|
-
})))
|
|
15658
|
+
}))))
|
|
15550
15659
|
}
|
|
15551
15660
|
|
|
15552
15661
|
function apply(ctx) {
|
package/src/index.js
CHANGED
|
@@ -755,7 +755,14 @@ async function branches(payload) {
|
|
|
755
755
|
behind: 0,
|
|
756
756
|
}
|
|
757
757
|
if (parts[0].startsWith('refs/heads/')) local.push(entry)
|
|
758
|
-
else if (parts[0].startsWith('refs/remotes/'))
|
|
758
|
+
else if (parts[0].startsWith('refs/remotes/')) {
|
|
759
|
+
/* "<remote>/HEAD" is the symbolic pointer at a remote's default branch —
|
|
760
|
+
its %(refname:short) collapses to the BARE remote name, so it is not a
|
|
761
|
+
branch anyone can check out. It never becomes a row (the stray
|
|
762
|
+
"<remote>" entry used to pollute the remote tree and, grouped, it also
|
|
763
|
+
defeated the tree's single-remote prefix strip). */
|
|
764
|
+
if (/^refs\/remotes\/[^/]+\/HEAD$/.test(parts[0]) === false) remote.push(entry)
|
|
765
|
+
}
|
|
759
766
|
else if (parts[0].startsWith('refs/tags/')) tags.push({ name: entry.name, hash: entry.hash, shortHash: entry.shortHash, date: entry.date, subject: entry.subject })
|
|
760
767
|
}
|
|
761
768
|
for (const entry of local) {
|