dsh-ide-git 0.19.11 → 0.19.13
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 +210 -5
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.13",
|
|
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.13",
|
|
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
|
@@ -295,6 +295,8 @@ window.__ModuleLoader__.load({
|
|
|
295
295
|
'composer.branchHint': '切换分支',
|
|
296
296
|
'composer.detached': 'HEAD(游离)',
|
|
297
297
|
'composer.changesHint': '未提交变更数',
|
|
298
|
+
'composer.fileHint': '新增 {a} · 删除 {d} 个文件',
|
|
299
|
+
'composer.linesHint': '+{ins} −{del} 行',
|
|
298
300
|
'composer.behindHint': '远程新提交(可拉取)',
|
|
299
301
|
'composer.aheadHint': '本地待推送提交',
|
|
300
302
|
'composer.inWorktree': '已被其他工作树签出',
|
|
@@ -623,6 +625,8 @@ window.__ModuleLoader__.load({
|
|
|
623
625
|
'composer.branchHint': 'Switch branch',
|
|
624
626
|
'composer.detached': 'HEAD (detached)',
|
|
625
627
|
'composer.changesHint': 'Uncommitted changes',
|
|
628
|
+
'composer.fileHint': '{a} added · {d} deleted files',
|
|
629
|
+
'composer.linesHint': '+{ins} −{del} lines',
|
|
626
630
|
'composer.behindHint': 'New upstream commits (pullable)',
|
|
627
631
|
'composer.aheadHint': 'Local commits waiting to push',
|
|
628
632
|
'composer.inWorktree': 'Checked out in another worktree',
|
|
@@ -959,6 +963,8 @@ window.__ModuleLoader__.load({
|
|
|
959
963
|
'composer.branchHint': '切換分支',
|
|
960
964
|
'composer.detached': 'HEAD(游離)',
|
|
961
965
|
'composer.changesHint': '未提交變更數',
|
|
966
|
+
'composer.fileHint': '新增 {a} · 刪除 {d} 個檔案',
|
|
967
|
+
'composer.linesHint': '+{ins} −{del} 行',
|
|
962
968
|
'composer.behindHint': '遠端新提交(可以拉取)',
|
|
963
969
|
'composer.aheadHint': '本地等待推送提交',
|
|
964
970
|
'composer.inWorktree': '已經喺其他工作樹簽出',
|
|
@@ -1287,6 +1293,8 @@ window.__ModuleLoader__.load({
|
|
|
1287
1293
|
'composer.branchHint': '切換分支',
|
|
1288
1294
|
'composer.detached': 'HEAD(分離)',
|
|
1289
1295
|
'composer.changesHint': '未提交變更數',
|
|
1296
|
+
'composer.fileHint': '新增 {a} · 刪除 {d} 個檔案',
|
|
1297
|
+
'composer.linesHint': '+{ins} −{del} 行',
|
|
1290
1298
|
'composer.behindHint': '遠端新提交(可拉取)',
|
|
1291
1299
|
'composer.aheadHint': '本地待推送提交',
|
|
1292
1300
|
'composer.inWorktree': '已被其他工作樹簽出',
|
|
@@ -1615,6 +1623,8 @@ window.__ModuleLoader__.load({
|
|
|
1615
1623
|
'composer.branchHint': '切換分支',
|
|
1616
1624
|
'composer.detached': 'HEAD(游離)',
|
|
1617
1625
|
'composer.changesHint': '未提交變更數',
|
|
1626
|
+
'composer.fileHint': '新增 {a} · 刪除 {d} 個檔案',
|
|
1627
|
+
'composer.linesHint': '+{ins} −{del} 行',
|
|
1618
1628
|
'composer.behindHint': '遠端新提交(可以拉取)',
|
|
1619
1629
|
'composer.aheadHint': '本地等待推送提交',
|
|
1620
1630
|
'composer.inWorktree': '已經喺其他工作樹簽出',
|
|
@@ -1943,6 +1953,8 @@ window.__ModuleLoader__.load({
|
|
|
1943
1953
|
'composer.branchHint': 'ブランチを切り替え',
|
|
1944
1954
|
'composer.detached': 'HEAD(切断)',
|
|
1945
1955
|
'composer.changesHint': '未コミットの変更数',
|
|
1956
|
+
'composer.fileHint': '追加 {a} · 削除 {d} ファイル',
|
|
1957
|
+
'composer.linesHint': '+{ins} −{del} 行',
|
|
1946
1958
|
'composer.behindHint': 'リモートの新規コミット(取得可能)',
|
|
1947
1959
|
'composer.aheadHint': 'プッシュ待ちのローカルコミット',
|
|
1948
1960
|
'composer.inWorktree': '別のワークツリーでチェックアウト中',
|
|
@@ -2271,6 +2283,8 @@ window.__ModuleLoader__.load({
|
|
|
2271
2283
|
'composer.branchHint': '브랜치 전환',
|
|
2272
2284
|
'composer.detached': 'HEAD(분리됨)',
|
|
2273
2285
|
'composer.changesHint': '커밋되지 않은 변경 수',
|
|
2286
|
+
'composer.fileHint': '추가 {a} · 삭제 {d}개 파일',
|
|
2287
|
+
'composer.linesHint': '+{ins} −{del}줄',
|
|
2274
2288
|
'composer.behindHint': '원격 새 커밋(가져오기 가능)',
|
|
2275
2289
|
'composer.aheadHint': '푸시 대기 중인 로컬 커밋',
|
|
2276
2290
|
'composer.inWorktree': '다른 작업 트리에서 체크아웃됨',
|
|
@@ -2599,6 +2613,8 @@ window.__ModuleLoader__.load({
|
|
|
2599
2613
|
'composer.branchHint': 'Zweig wechseln',
|
|
2600
2614
|
'composer.detached': 'HEAD (detached)',
|
|
2601
2615
|
'composer.changesHint': 'Uncommittete Änderungen',
|
|
2616
|
+
'composer.fileHint': '{a} hinzugefügt · {d} gelöscht',
|
|
2617
|
+
'composer.linesHint': '+{ins} −{del} Zeilen',
|
|
2602
2618
|
'composer.behindHint': 'Neue Upstream-Commits (abrufbar)',
|
|
2603
2619
|
'composer.aheadHint': 'Lokale Commits zum Pushen',
|
|
2604
2620
|
'composer.inWorktree': 'In anderem Worktree ausgecheckt',
|
|
@@ -2927,6 +2943,8 @@ window.__ModuleLoader__.load({
|
|
|
2927
2943
|
'composer.branchHint': 'Changer de branche',
|
|
2928
2944
|
'composer.detached': 'HEAD (détaché)',
|
|
2929
2945
|
'composer.changesHint': 'Modifications non commitées',
|
|
2946
|
+
'composer.fileHint': '{a} ajoutés · {d} supprimés',
|
|
2947
|
+
'composer.linesHint': '+{ins} −{del} lignes',
|
|
2930
2948
|
'composer.behindHint': 'Nouveaux commits amont (récupérables)',
|
|
2931
2949
|
'composer.aheadHint': 'Commits locaux en attente d’envoi',
|
|
2932
2950
|
'composer.inWorktree': 'Extrait dans un autre arbre de travail',
|
|
@@ -3255,6 +3273,8 @@ window.__ModuleLoader__.load({
|
|
|
3255
3273
|
'composer.branchHint': 'Сменить ветку',
|
|
3256
3274
|
'composer.detached': 'HEAD (отделён)',
|
|
3257
3275
|
'composer.changesHint': 'Незакоммиченные изменения',
|
|
3276
|
+
'composer.fileHint': 'добавлено: {a} · удалено: {d}',
|
|
3277
|
+
'composer.linesHint': '+{ins} −{del} строк',
|
|
3258
3278
|
'composer.behindHint': 'Новые коммиты upstream (можно забрать)',
|
|
3259
3279
|
'composer.aheadHint': 'Локальные коммиты, ожидающие отправки',
|
|
3260
3280
|
'composer.inWorktree': 'Выверен в другом worktree',
|
|
@@ -3583,6 +3603,8 @@ window.__ModuleLoader__.load({
|
|
|
3583
3603
|
'composer.branchHint': 'Trocar branch',
|
|
3584
3604
|
'composer.detached': 'HEAD (destacado)',
|
|
3585
3605
|
'composer.changesHint': 'Alterações não commitadas',
|
|
3606
|
+
'composer.fileHint': '{a} adicionados · {d} removidos',
|
|
3607
|
+
'composer.linesHint': '+{ins} −{del} linhas',
|
|
3586
3608
|
'composer.behindHint': 'Novos commits remotos (para pull)',
|
|
3587
3609
|
'composer.aheadHint': 'Commits locais aguardando push',
|
|
3588
3610
|
'composer.inWorktree': 'Em checkout em outra worktree',
|
|
@@ -3911,6 +3933,8 @@ window.__ModuleLoader__.load({
|
|
|
3911
3933
|
'composer.branchHint': 'Cambia ramo',
|
|
3912
3934
|
'composer.detached': 'HEAD (staccato)',
|
|
3913
3935
|
'composer.changesHint': 'Modifiche non ancora committate',
|
|
3936
|
+
'composer.fileHint': '{a} aggiunti · {d} eliminati',
|
|
3937
|
+
'composer.linesHint': '+{ins} −{del} righe',
|
|
3914
3938
|
'composer.behindHint': 'Nuovi commit upstream (scaricabili)',
|
|
3915
3939
|
'composer.aheadHint': 'Commit locali in attesa di push',
|
|
3916
3940
|
'composer.inWorktree': 'Estratto in un altro worktree',
|
|
@@ -4239,6 +4263,8 @@ window.__ModuleLoader__.load({
|
|
|
4239
4263
|
'composer.branchHint': 'Branch wisselen',
|
|
4240
4264
|
'composer.detached': 'HEAD (los)',
|
|
4241
4265
|
'composer.changesHint': 'Ongecommitte wijzigingen',
|
|
4266
|
+
'composer.fileHint': '{a} toegevoegd · {d} verwijderd',
|
|
4267
|
+
'composer.linesHint': '+{ins} −{del} regels',
|
|
4242
4268
|
'composer.behindHint': 'Nieuwe upstream-commits (op te halen)',
|
|
4243
4269
|
'composer.aheadHint': 'Lokale commits die wachten op push',
|
|
4244
4270
|
'composer.inWorktree': 'Uitgecheckt in een andere worktree',
|
|
@@ -4567,6 +4593,8 @@ window.__ModuleLoader__.load({
|
|
|
4567
4593
|
'composer.branchHint': 'Przełącz gałąź',
|
|
4568
4594
|
'composer.detached': 'HEAD (odłączony)',
|
|
4569
4595
|
'composer.changesHint': 'Niezatwierdzone zmiany',
|
|
4596
|
+
'composer.fileHint': 'dodane: {a} · usunięte: {d}',
|
|
4597
|
+
'composer.linesHint': '+{ins} −{del} linii',
|
|
4570
4598
|
'composer.behindHint': 'Nowe commity upstream (do pobrania)',
|
|
4571
4599
|
'composer.aheadHint': 'Lokalne commity oczekujące na wysłanie',
|
|
4572
4600
|
'composer.inWorktree': 'Wybrane w innym drzewie roboczym',
|
|
@@ -4895,6 +4923,8 @@ window.__ModuleLoader__.load({
|
|
|
4895
4923
|
'composer.branchHint': 'Byt gren',
|
|
4896
4924
|
'composer.detached': 'HEAD (frånkopplad)',
|
|
4897
4925
|
'composer.changesHint': 'Ocommittade ändringar',
|
|
4926
|
+
'composer.fileHint': '{a} tillagda · {d} borttagna',
|
|
4927
|
+
'composer.linesHint': '+{ins} −{del} rader',
|
|
4898
4928
|
'composer.behindHint': 'Nya upstream-commits (hämtbara)',
|
|
4899
4929
|
'composer.aheadHint': 'Lokala commits som väntar på push',
|
|
4900
4930
|
'composer.inWorktree': 'Utcheckad i ett annat arbetsträd',
|
|
@@ -5223,6 +5253,8 @@ window.__ModuleLoader__.load({
|
|
|
5223
5253
|
'composer.branchHint': 'Dal değiştir',
|
|
5224
5254
|
'composer.detached': 'HEAD (ayrık)',
|
|
5225
5255
|
'composer.changesHint': 'Commitlenmemiş değişiklikler',
|
|
5256
|
+
'composer.fileHint': '{a} eklendi · {d} silindi',
|
|
5257
|
+
'composer.linesHint': '+{ins} −{del} satır',
|
|
5226
5258
|
'composer.behindHint': 'Yeni upstream commitleri (çekilebilir)',
|
|
5227
5259
|
'composer.aheadHint': 'Push bekleyen yerel commitler',
|
|
5228
5260
|
'composer.inWorktree': 'Başka bir worktree’da checkout yapılmış',
|
|
@@ -5551,6 +5583,8 @@ window.__ModuleLoader__.load({
|
|
|
5551
5583
|
'composer.branchHint': 'Ganti cabang',
|
|
5552
5584
|
'composer.detached': 'HEAD (lepas)',
|
|
5553
5585
|
'composer.changesHint': 'Perubahan yang belum di-commit',
|
|
5586
|
+
'composer.fileHint': '{a} ditambahkan · {d} dihapus',
|
|
5587
|
+
'composer.linesHint': '+{ins} −{del} baris',
|
|
5554
5588
|
'composer.behindHint': 'Commit upstream baru (bisa ditarik)',
|
|
5555
5589
|
'composer.aheadHint': 'Commit lokal menunggu push',
|
|
5556
5590
|
'composer.inWorktree': 'Sudah di-checkout di worktree lain',
|
|
@@ -5879,6 +5913,8 @@ window.__ModuleLoader__.load({
|
|
|
5879
5913
|
'composer.branchHint': 'Chuyển nhánh',
|
|
5880
5914
|
'composer.detached': 'HEAD (tách rời)',
|
|
5881
5915
|
'composer.changesHint': 'Thay đổi chưa commit',
|
|
5916
|
+
'composer.fileHint': 'thêm {a} · xóa {d} tệp',
|
|
5917
|
+
'composer.linesHint': '+{ins} −{del} dòng',
|
|
5882
5918
|
'composer.behindHint': 'Commit mới từ xa (có thể kéo về)',
|
|
5883
5919
|
'composer.aheadHint': 'Commit cục bộ chờ đẩy lên',
|
|
5884
5920
|
'composer.inWorktree': 'Đã được checkout ở worktree khác',
|
|
@@ -6207,6 +6243,8 @@ window.__ModuleLoader__.load({
|
|
|
6207
6243
|
'composer.branchHint': 'تبديل الفرع',
|
|
6208
6244
|
'composer.detached': 'HEAD (منفصل)',
|
|
6209
6245
|
'composer.changesHint': 'تغييرات غير ملتزَم بها',
|
|
6246
|
+
'composer.fileHint': 'مضاف {a} · محذوف {d}',
|
|
6247
|
+
'composer.linesHint': '+{ins} −{del} أسطر',
|
|
6210
6248
|
'composer.behindHint': 'التزامات جديدة في المستودع البعيد (قابلة للسحب)',
|
|
6211
6249
|
'composer.aheadHint': 'التزامات محلية بانتظار الدفع',
|
|
6212
6250
|
'composer.inWorktree': 'مسحوب في شجرة عمل أخرى',
|
|
@@ -6535,6 +6573,8 @@ window.__ModuleLoader__.load({
|
|
|
6535
6573
|
'composer.branchHint': 'शाखा बदलें',
|
|
6536
6574
|
'composer.detached': 'HEAD (पृथक)',
|
|
6537
6575
|
'composer.changesHint': 'बिना कमिट बदलाव',
|
|
6576
|
+
'composer.fileHint': '{a} जोड़ी गईं · {d} हटाई गईं',
|
|
6577
|
+
'composer.linesHint': '+{ins} −{del} पंक्तियाँ',
|
|
6538
6578
|
'composer.behindHint': 'अपस्ट्रीम के नए कमिट (खींचने योग्य)',
|
|
6539
6579
|
'composer.aheadHint': 'पुश के लिए प्रतीक्षारत स्थानीय कमिट',
|
|
6540
6580
|
'composer.inWorktree': 'दूसरे वर्कट्री में चेकआउट',
|
|
@@ -6863,6 +6903,8 @@ window.__ModuleLoader__.load({
|
|
|
6863
6903
|
'composer.branchHint': 'สลับแบรนช์',
|
|
6864
6904
|
'composer.detached': 'HEAD (แยกขาด)',
|
|
6865
6905
|
'composer.changesHint': 'การเปลี่ยนแปลงที่ยังไม่คอมมิต',
|
|
6906
|
+
'composer.fileHint': 'เพิ่ม {a} · ลบ {d} ไฟล์',
|
|
6907
|
+
'composer.linesHint': '+{ins} −{del} บรรทัด',
|
|
6866
6908
|
'composer.behindHint': 'คอมมิตใหม่จากรีโมต (ดึงได้)',
|
|
6867
6909
|
'composer.aheadHint': 'คอมมิตในเครื่องรอพุช',
|
|
6868
6910
|
'composer.inWorktree': 'ถูกเช็คเอาต์ในเวิร์กทรีอื่น',
|
|
@@ -7339,6 +7381,58 @@ window.__ModuleLoader__.load({
|
|
|
7339
7381
|
return null
|
|
7340
7382
|
}
|
|
7341
7383
|
|
|
7384
|
+
/* How many changed FILES are additions vs deletions, from the status
|
|
7385
|
+
letters the summary already carries (index/worktree per entry) — no
|
|
7386
|
+
extra git call. Untracked entries ARE additions in git's own model
|
|
7387
|
+
(?? = to-be-added); a rename (R/C) or a conflict counts as neither. */
|
|
7388
|
+
function composerFileSplitOf(summary) {
|
|
7389
|
+
const changes = summary !== null && summary !== undefined && summary.changes !== null && typeof summary.changes === 'object' ? summary.changes : null
|
|
7390
|
+
if (changes === null) return { added: 0, deleted: 0 }
|
|
7391
|
+
let added = 0
|
|
7392
|
+
let deleted = 0
|
|
7393
|
+
const count = (list) => {
|
|
7394
|
+
for (const entry of list === undefined || list === null ? [] : list) {
|
|
7395
|
+
if (entry.index === 'A' || entry.worktree === 'A') added += 1
|
|
7396
|
+
else if (entry.index === 'D' || entry.worktree === 'D') deleted += 1
|
|
7397
|
+
}
|
|
7398
|
+
}
|
|
7399
|
+
count(changes.staged)
|
|
7400
|
+
count(changes.unstaged)
|
|
7401
|
+
added += changes.untracked === undefined || changes.untracked === null ? 0 : changes.untracked.length
|
|
7402
|
+
return { added: added, deleted: deleted }
|
|
7403
|
+
}
|
|
7404
|
+
|
|
7405
|
+
/* Total uncommitted line churn: the packed [path, additions, deletions,
|
|
7406
|
+
binary] rows the host's stats method returns, summed over both the
|
|
7407
|
+
worktree and the index passes. Untracked files have no line counts
|
|
7408
|
+
(git cannot diff what it does not track) — they only ever move the
|
|
7409
|
+
file counters above. */
|
|
7410
|
+
function composerStatsLinesOf(pack) {
|
|
7411
|
+
let additions = 0
|
|
7412
|
+
let deletions = 0
|
|
7413
|
+
if (pack !== null && pack !== undefined && typeof pack === 'object') {
|
|
7414
|
+
for (const row of pack.unstaged === undefined || pack.unstaged === null ? [] : pack.unstaged) { additions += row[1]; deletions += row[2] }
|
|
7415
|
+
for (const row of pack.staged === undefined || pack.staged === null ? [] : pack.staged) { additions += row[1]; deletions += row[2] }
|
|
7416
|
+
}
|
|
7417
|
+
return { additions: additions, deletions: deletions }
|
|
7418
|
+
}
|
|
7419
|
+
|
|
7420
|
+
/* Whether the line counts need a refetch: any path/status move or a new
|
|
7421
|
+
HEAD commit/checkout invalidates them; lines rewritten inside
|
|
7422
|
+
already-dirty files do NOT move this — the slow COMPOSER_STATS_MS
|
|
7423
|
+
floor covers those. */
|
|
7424
|
+
function composerFingerprintOf(summary) {
|
|
7425
|
+
if (summary === null || summary === undefined || summary.changes === null || typeof summary.changes !== 'object') return ''
|
|
7426
|
+
const rows = []
|
|
7427
|
+
const collect = (list) => { for (const entry of list === undefined || list === null ? [] : list) rows.push(entry.path + ':' + entry.index + entry.worktree) }
|
|
7428
|
+
collect(summary.changes.staged)
|
|
7429
|
+
collect(summary.changes.unstaged)
|
|
7430
|
+
collect(summary.changes.untracked)
|
|
7431
|
+
collect(summary.changes.conflicted)
|
|
7432
|
+
rows.sort()
|
|
7433
|
+
return rows.join('|') + '#' + String(summary.head === undefined || summary.head === null ? '' : summary.head)
|
|
7434
|
+
}
|
|
7435
|
+
|
|
7342
7436
|
async function prewarmWorkspace(sessionId, cwd) {
|
|
7343
7437
|
const generation = ++prewarmGeneration
|
|
7344
7438
|
try {
|
|
@@ -14897,12 +14991,24 @@ window.__ModuleLoader__.load({
|
|
|
14897
14991
|
'.dig-cs-pill{display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 8px;border:none;border-radius:var(--dsw-radius-sm,8px);background:transparent;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:var(--dsh-content-font-size-secondary,13px);line-height:20px;white-space:nowrap;cursor:pointer}',
|
|
14898
14992
|
'.dig-cs-pill:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}',
|
|
14899
14993
|
'.dig-cs-pill:disabled{cursor:default}',
|
|
14900
|
-
'.dig-cs-name{overflow:hidden;text-overflow:ellipsis;max-width:
|
|
14994
|
+
'.dig-cs-name{overflow:hidden;text-overflow:ellipsis;max-width:260px;white-space:nowrap;display:inline-block;vertical-align:bottom}',
|
|
14995
|
+
'.dig-cs-mrun{display:inline-flex;text-overflow:clip;-webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 14px),transparent);mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 14px),transparent)}',
|
|
14996
|
+
'.dig-cs-mrun .dig-cs-run{display:inline-flex;flex:none;will-change:transform}',
|
|
14997
|
+
'.dig-cs-mrun .dig-cs-chunk{flex:none;white-space:nowrap;padding-right:28px}',
|
|
14998
|
+
'.dig-cs-mrun:hover .dig-cs-run{animation:dig-cs-marquee var(--dig-cs-marquee-dur,10s) linear infinite}',
|
|
14999
|
+
'@keyframes dig-cs-marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}',
|
|
14901
15000
|
'.dig-cs-pill svg{flex:none}',
|
|
14902
15001
|
'.dig-cs-badge{display:inline-flex;align-items:center;font-size:12px;line-height:20px;font-variant-numeric:tabular-nums;white-space:nowrap;padding:0 3px;font-weight:500}',
|
|
14903
15002
|
'.dig-cs-changes{color:var(--dsw-alias-state-warn-primary)}',
|
|
14904
15003
|
'.dig-cs-behind{color:var(--dsw-alias-state-business-primary)}',
|
|
14905
15004
|
'.dig-cs-ahead{color:var(--dsw-alias-state-success-primary)}',
|
|
15005
|
+
/* v0.19.12: file-level add/del split rides INSIDE the ± chip at one
|
|
15006
|
+
step down (11px) so the two +/− groups read as two levels — small
|
|
15007
|
+
green/red = FILES, full-size green/red = LINES. */
|
|
15008
|
+
'.dig-cs-split{font-size:11px;line-height:20px;font-variant-numeric:tabular-nums;margin-left:2px}',
|
|
15009
|
+
'.dig-cs-add{color:var(--dsw-alias-state-success-primary)}',
|
|
15010
|
+
'.dig-cs-del{color:var(--dsw-alias-state-error-primary)}',
|
|
15011
|
+
'.dig-cs-lines{display:inline-flex;align-items:center;gap:2px;margin-left:5px}',
|
|
14906
15012
|
'.dig-cs-error{display:inline-flex;align-items:center;color:var(--dsw-alias-state-error-primary);font-size:12px;padding:0 3px;cursor:help}',
|
|
14907
15013
|
// .dig-cs-menu opens upward (the composer sits at the bottom of the UI). The surface
|
|
14908
15014
|
// carries no backdrop-filter of its own: the data-cordis-panel attribute opts the popover
|
|
@@ -15064,6 +15170,13 @@ window.__ModuleLoader__.load({
|
|
|
15064
15170
|
|
|
15065
15171
|
const COMPOSER_POLL_MS = 30000
|
|
15066
15172
|
const COMPOSER_ERROR_TTL_MS = 6000
|
|
15173
|
+
/* Line counts re-run at most this often without a real change: the two
|
|
15174
|
+
numstat passes are the expensive step on a big dirty tree (issue #11),
|
|
15175
|
+
so the pill keeps its cheap stats:false poll and refreshes lines only
|
|
15176
|
+
when the change set or HEAD moves — plus this slow floor for edits
|
|
15177
|
+
that rewrite lines in already-dirty files (nothing else in the
|
|
15178
|
+
fingerprint moves then). */
|
|
15179
|
+
const COMPOSER_STATS_MS = 90000
|
|
15067
15180
|
|
|
15068
15181
|
/* Windows paths ride backslashes, so both pill labels cut the leaf with
|
|
15069
15182
|
this slash-aware split instead of a bare forward-slash split — a drive
|
|
@@ -15106,6 +15219,51 @@ window.__ModuleLoader__.load({
|
|
|
15106
15219
|
return null
|
|
15107
15220
|
}
|
|
15108
15221
|
|
|
15222
|
+
/* Long repository/branch names: widen the label cap and, past it, run a
|
|
15223
|
+
hover-only seamless marquee (the official sidebar rows scroll hovered
|
|
15224
|
+
titles via useTitleMarquee, which this surface cannot require — this is
|
|
15225
|
+
the CSS twin). The label is measured after paint; only overflowing text
|
|
15226
|
+
switches to the duplicated-chunk structure, so short names keep the
|
|
15227
|
+
plain ellipsis and never animate. Duration follows the text width so a
|
|
15228
|
+
slightly-long name does not crawl. */
|
|
15229
|
+
const COMPOSER_NAME_MAX_PX = 260
|
|
15230
|
+
const MARQUEE_PX_PER_S = 28
|
|
15231
|
+
|
|
15232
|
+
function ComposerMarqueeName(props) {
|
|
15233
|
+
const text = typeof props.text === 'string' ? props.text : ''
|
|
15234
|
+
const boxRef = useRef(null)
|
|
15235
|
+
const [run, setRun] = useState(false)
|
|
15236
|
+
const [dur, setDur] = useState('')
|
|
15237
|
+
useEffect(() => {
|
|
15238
|
+
const box = boxRef.current
|
|
15239
|
+
if (box === null) return undefined
|
|
15240
|
+
const measure = () => {
|
|
15241
|
+
if (boxRef.current !== box) return /* replaced or unmounted */
|
|
15242
|
+
const overflow = box.scrollWidth > box.clientWidth + 1
|
|
15243
|
+
setRun(overflow)
|
|
15244
|
+
/* In the running structure scrollWidth covers BOTH chunks, so one
|
|
15245
|
+
chunk is half of it; the plain structure measures the text alone. */
|
|
15246
|
+
const unit = overflow === true && run === true ? box.scrollWidth / 2 : box.scrollWidth
|
|
15247
|
+
setDur(overflow === true ? (unit / MARQUEE_PX_PER_S).toFixed(2) + 's' : '')
|
|
15248
|
+
}
|
|
15249
|
+
measure()
|
|
15250
|
+
/* Webfonts land after paint and change text metrics — re-measure once. */
|
|
15251
|
+
let frame = 0
|
|
15252
|
+
const fonts = document.fonts
|
|
15253
|
+
if (fonts !== undefined && fonts !== null && fonts.ready !== undefined && typeof fonts.ready.then === 'function') {
|
|
15254
|
+
fonts.ready.then(() => { frame = requestAnimationFrame(measure) }, () => {})
|
|
15255
|
+
}
|
|
15256
|
+
return () => { if (frame !== 0) cancelAnimationFrame(frame) }
|
|
15257
|
+
}, [text, run])
|
|
15258
|
+
if (run !== true) {
|
|
15259
|
+
return E('span', { ref: boxRef, className: 'dig-cs-name' }, text)
|
|
15260
|
+
}
|
|
15261
|
+
return E('span', { ref: boxRef, className: 'dig-cs-name dig-cs-mrun', style: dur !== '' ? { '--dig-cs-marquee-dur': dur } : undefined },
|
|
15262
|
+
E('span', { className: 'dig-cs-run' },
|
|
15263
|
+
E('span', { className: 'dig-cs-chunk' }, text),
|
|
15264
|
+
E('span', { className: 'dig-cs-chunk', 'aria-hidden': 'true' }, text)))
|
|
15265
|
+
}
|
|
15266
|
+
|
|
15109
15267
|
function ComposerGitStatus(props) {
|
|
15110
15268
|
const ctx = props.ctx
|
|
15111
15269
|
const t = props.t
|
|
@@ -15134,6 +15292,13 @@ window.__ModuleLoader__.load({
|
|
|
15134
15292
|
const [checkingOut, setCheckingOut] = useState('')
|
|
15135
15293
|
const [error, setError] = useState('')
|
|
15136
15294
|
const [tick, setTick] = useState(0)
|
|
15295
|
+
/* Uncommitted line churn (+n −m), fetched lazily: only when the change
|
|
15296
|
+
set or HEAD moves — never on the ambient 30s tick by itself (the
|
|
15297
|
+
root tag keeps a previous repository's numbers from leaking into
|
|
15298
|
+
this one's pill). */
|
|
15299
|
+
const [lineStats, setLineStats] = useState(null)
|
|
15300
|
+
const statsStampRef = useRef('')
|
|
15301
|
+
const statsAtRef = useRef(0)
|
|
15137
15302
|
const rootRef = useRef(null)
|
|
15138
15303
|
|
|
15139
15304
|
/* The switch flips live through the same rail-config notify walk the
|
|
@@ -15192,7 +15357,7 @@ window.__ModuleLoader__.load({
|
|
|
15192
15357
|
The panel keeps its own 12s poll for its bigger surface; 30s here is
|
|
15193
15358
|
only the ambient state, never a correctness dependency. */
|
|
15194
15359
|
useEffect(() => {
|
|
15195
|
-
if (repoRoot === null || enabled !== true) { setSummary(null); return undefined }
|
|
15360
|
+
if (repoRoot === null || enabled !== true) { setSummary(null); setLineStats(null); return undefined }
|
|
15196
15361
|
let cancelled = false
|
|
15197
15362
|
const load = async () => {
|
|
15198
15363
|
try {
|
|
@@ -15204,6 +15369,27 @@ window.__ModuleLoader__.load({
|
|
|
15204
15369
|
mount with zero round trips. Merge only our field — a panel
|
|
15205
15370
|
page keeps its commits. */
|
|
15206
15371
|
mergePaintPage(repoRoot, { summary: data })
|
|
15372
|
+
/* Line counts ride the same tick only when something actually
|
|
15373
|
+
moved (any status/path change or a new HEAD), or when the slow
|
|
15374
|
+
floor elapsed for in-place edits of dirty files. A clean tree
|
|
15375
|
+
skips the numstat passes entirely and just zeroes the badges. */
|
|
15376
|
+
const fingerprint = composerFingerprintOf(data)
|
|
15377
|
+
const stamp = repoRoot + '::' + fingerprint
|
|
15378
|
+
const now = Date.now()
|
|
15379
|
+
const count = data.changes === null || typeof data.changes !== 'object' ? 0 : data.changes.staged.length + data.changes.unstaged.length + data.changes.untracked.length
|
|
15380
|
+
if (count === 0) {
|
|
15381
|
+
statsStampRef.current = stamp
|
|
15382
|
+
statsAtRef.current = now
|
|
15383
|
+
setLineStats({ root: repoRoot, additions: 0, deletions: 0 })
|
|
15384
|
+
} else if (stamp !== statsStampRef.current || now - statsAtRef.current >= COMPOSER_STATS_MS) {
|
|
15385
|
+
try {
|
|
15386
|
+
const pack = await request('stats', { cwd: cwd, repoRoot: repoRoot })
|
|
15387
|
+
if (cancelled === true) return
|
|
15388
|
+
statsStampRef.current = stamp
|
|
15389
|
+
statsAtRef.current = now
|
|
15390
|
+
setLineStats(Object.assign({ root: repoRoot }, composerStatsLinesOf(pack)))
|
|
15391
|
+
} catch (statsError) { void statsError }
|
|
15392
|
+
}
|
|
15207
15393
|
} catch (error) { void error }
|
|
15208
15394
|
}
|
|
15209
15395
|
const seed = readPaintPage(repoRoot)
|
|
@@ -15274,6 +15460,18 @@ window.__ModuleLoader__.load({
|
|
|
15274
15460
|
const changesCount = summary !== null && summary.changes !== null && typeof summary.changes === 'object'
|
|
15275
15461
|
? summary.changes.staged.length + summary.changes.unstaged.length + summary.changes.untracked.length
|
|
15276
15462
|
: null
|
|
15463
|
+
/* File-level add/del split (status letters, free) + the lazily fetched
|
|
15464
|
+
line churn, assembled into one tooltip that reads as a sentence. */
|
|
15465
|
+
const fileSplit = composerFileSplitOf(summary)
|
|
15466
|
+
const linesLive = lineStats !== null && lineStats.root === repoRoot ? lineStats : null
|
|
15467
|
+
const changesTitle = (() => {
|
|
15468
|
+
let title = t('composer.changesHint')
|
|
15469
|
+
if (changesCount !== null && changesCount > 0) {
|
|
15470
|
+
title += ' · ' + fill(t('composer.fileHint'), { a: fileSplit.added, d: fileSplit.deleted })
|
|
15471
|
+
if (linesLive !== null) title += ' · ' + fill(t('composer.linesHint'), { ins: linesLive.additions, del: linesLive.deletions })
|
|
15472
|
+
}
|
|
15473
|
+
return title
|
|
15474
|
+
})()
|
|
15277
15475
|
|
|
15278
15476
|
const openBranchMenu = async () => {
|
|
15279
15477
|
setMenu('branch')
|
|
@@ -15328,7 +15526,7 @@ window.__ModuleLoader__.load({
|
|
|
15328
15526
|
onClick: singleRepo === true ? undefined : () => { setMenu(menu === 'repo' ? null : 'repo') },
|
|
15329
15527
|
},
|
|
15330
15528
|
E(Icon, { name: 'commit', size: 13 }),
|
|
15331
|
-
E(
|
|
15529
|
+
E(ComposerMarqueeName, { text: repoName }),
|
|
15332
15530
|
singleRepo === true ? null : E(Icon, { name: 'chevron', size: 10 })),
|
|
15333
15531
|
branchName !== null ? E('button', {
|
|
15334
15532
|
type: 'button',
|
|
@@ -15337,10 +15535,17 @@ window.__ModuleLoader__.load({
|
|
|
15337
15535
|
onClick: () => { if (menu !== 'branch') void openBranchMenu(); else setMenu(null) },
|
|
15338
15536
|
},
|
|
15339
15537
|
E(Icon, { name: 'branch', size: 13 }),
|
|
15340
|
-
E(
|
|
15538
|
+
E(ComposerMarqueeName, { text: detached === true ? t('composer.detached') : branchName }),
|
|
15341
15539
|
E(Icon, { name: 'chevron', size: 10 })) : null,
|
|
15342
15540
|
changesCount !== null && changesCount > 0
|
|
15343
|
-
? E('span', { className: 'dig-cs-badge dig-cs-changes', title:
|
|
15541
|
+
? E('span', { className: 'dig-cs-badge dig-cs-changes', title: changesTitle }, '±' + String(changesCount),
|
|
15542
|
+
fileSplit.added > 0 ? E('span', { className: 'dig-cs-split dig-cs-add' }, '+' + String(fileSplit.added)) : null,
|
|
15543
|
+
fileSplit.deleted > 0 ? E('span', { className: 'dig-cs-split dig-cs-del' }, '−' + String(fileSplit.deleted)) : null)
|
|
15544
|
+
: null,
|
|
15545
|
+
linesLive !== null && (linesLive.additions > 0 || linesLive.deletions > 0)
|
|
15546
|
+
? E('span', { className: 'dig-cs-lines' },
|
|
15547
|
+
linesLive.additions > 0 ? E('span', { className: 'dig-cs-badge dig-cs-add', title: changesTitle }, '+' + String(linesLive.additions)) : null,
|
|
15548
|
+
linesLive.deletions > 0 ? E('span', { className: 'dig-cs-badge dig-cs-del', title: changesTitle }, '−' + String(linesLive.deletions)) : null)
|
|
15344
15549
|
: null,
|
|
15345
15550
|
behind > 0 ? E('span', { className: 'dig-cs-badge dig-cs-behind', title: t('composer.behindHint') }, '↓' + String(behind)) : null,
|
|
15346
15551
|
ahead > 0 ? E('span', { className: 'dig-cs-badge dig-cs-ahead', title: t('composer.aheadHint') }, '↑' + String(ahead)) : null,
|