git-clone-resume 0.1.2 → 0.1.4

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.
@@ -539,6 +539,42 @@ function Get-GcrHistoryPath {
539
539
  return (Join-Path (Join-Path $root "git-clone-resume") "history.json")
540
540
  }
541
541
 
542
+ function Get-GcrSettingsPath {
543
+ $historyPath = Get-GcrHistoryPath
544
+ return (Join-Path (Split-Path -Parent $historyPath) "settings.json")
545
+ }
546
+
547
+ function Get-GcrLanguagePreference {
548
+ try {
549
+ $path = Get-GcrSettingsPath
550
+ if (-not (Test-Path -LiteralPath $path)) { return $null }
551
+ $settings = Get-Content -Raw -LiteralPath $path | ConvertFrom-Json
552
+ if ($settings.language -eq "en-US" -or $settings.language -eq "zh-CN") {
553
+ return [string]$settings.language
554
+ }
555
+ } catch { }
556
+ return $null
557
+ }
558
+
559
+ function Save-GcrLanguagePreference {
560
+ param([ValidateSet("zh-CN", "en-US")][string]$Language)
561
+ try {
562
+ $path = Get-GcrSettingsPath
563
+ $dir = Split-Path -Parent $path
564
+ if (-not (Test-Path -LiteralPath $dir)) {
565
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null
566
+ }
567
+ $settings = @{ language = $Language; updated = (Get-Date).ToString("o") }
568
+ [System.IO.File]::WriteAllText($path, (ConvertTo-Json $settings), (New-Object System.Text.UTF8Encoding $false))
569
+ } catch { }
570
+ }
571
+
572
+ function Set-GcrLanguage {
573
+ param([ValidateSet("zh-CN", "en-US")][string]$Language)
574
+ $script:GcrLanguage = $Language
575
+ Save-GcrLanguagePreference -Language $Language
576
+ }
577
+
542
578
  function Get-GcrHistory {
543
579
  $path = Get-GcrHistoryPath
544
580
  if (-not (Test-Path -LiteralPath $path)) { return @() }
@@ -609,6 +645,12 @@ function Format-GcrAgo {
609
645
  $dt = [datetime]$When
610
646
  } catch { return "" }
611
647
  $d = (Get-Date) - $dt
648
+ if ($script:GcrLanguage -eq "en-US") {
649
+ if ($d.TotalSeconds -lt 60) { return "just now" }
650
+ if ($d.TotalMinutes -lt 60) { return ("{0} minutes ago" -f [int]$d.TotalMinutes) }
651
+ if ($d.TotalHours -lt 24) { return ("{0} hours ago" -f [int]$d.TotalHours) }
652
+ return ("{0} days ago" -f [int]$d.TotalDays)
653
+ }
612
654
  if ($d.TotalSeconds -lt 60) { return "刚刚" }
613
655
  if ($d.TotalMinutes -lt 60) { return ("{0} 分钟前" -f [int]$d.TotalMinutes) }
614
656
  if ($d.TotalHours -lt 24) { return ("{0} 小时前" -f [int]$d.TotalHours) }
@@ -752,6 +794,10 @@ function Invoke-GcrTuiKey {
752
794
  $script:GcrTui.Dirty = $true
753
795
  }
754
796
  "H" { $script:GcrTui.Help = $true; $script:GcrTui.Dirty = $true }
797
+ "L" {
798
+ Set-GcrLanguage -Language $(if ($script:GcrLanguage -eq "en-US") { "zh-CN" } else { "en-US" })
799
+ $script:GcrTui.Dirty = $true
800
+ }
755
801
  "F" { $script:GcrTui.FailView = -not $script:GcrTui.FailView; $script:GcrTui.Dirty = $true }
756
802
  "UpArrow" {
757
803
  $script:GcrTui.LogOffset = [Math]::Min($script:GcrTui.Logs.Count, $script:GcrTui.LogOffset + 1)
@@ -902,6 +948,8 @@ function Render-GcrTui {
902
948
  function Push-GcrRow {
903
949
  param([string]$Left, [string]$Right = "", [string]$Color = "")
904
950
  if (-not $Color) { $Color = $c.W }
951
+ $Left = Convert-GcrText $Left
952
+ $Right = Convert-GcrText $Right
905
953
  $leftW = Get-GcrDisplayWidth $Left
906
954
  $rightW = Get-GcrDisplayWidth $Right
907
955
  $gap = $inner - $leftW - $rightW
@@ -1210,6 +1258,7 @@ function Convert-GcrWizardResult {
1210
1258
  Add-Member -InputObject $obj -NotePropertyName Verify -NotePropertyValue ([bool]$St.Verify)
1211
1259
  Add-Member -InputObject $obj -NotePropertyName ForceRefetch -NotePropertyValue ([bool]$St.ForceRefetch)
1212
1260
  Add-Member -InputObject $obj -NotePropertyName DryRun -NotePropertyValue ([bool]$St.DryRun)
1261
+ Add-Member -InputObject $obj -NotePropertyName Language -NotePropertyValue ([string]$St.Language)
1213
1262
  return ,$obj
1214
1263
  }
1215
1264
 
@@ -1256,6 +1305,7 @@ function Render-GcrTuiWizard {
1256
1305
  }
1257
1306
  function WRow([string]$Text, [string]$Color, [switch]$Sel) {
1258
1307
  if (-not $Color) { $Color = $c.W }
1308
+ $Text = Convert-GcrText $Text
1259
1309
  $body = Format-GcrCell -Text $Text -Width $inner
1260
1310
  if ($Sel) { $Color = (Get-GcrColor "rev") + $Color }
1261
1311
  $row = $c.D + $box.V + $c.R + $Color + $body + $c.R + $c.D + $box.V + $c.R
@@ -1268,7 +1318,7 @@ function Render-GcrTuiWizard {
1268
1318
  WRow " 断点续传克隆 · partial clone + 按批 checkout" $c.D
1269
1319
  WBorder "mid"
1270
1320
 
1271
- $formEnd = 11
1321
+ $formEnd = 12
1272
1322
  $recent = @($St.Recent)
1273
1323
  $maxFormVisible = [Math]::Max(6, $h - 10)
1274
1324
  if ($maxFormVisible -gt ($formEnd + 1)) { $maxFormVisible = $formEnd + 1 }
@@ -1286,7 +1336,10 @@ function Render-GcrTuiWizard {
1286
1336
  $mark = " "
1287
1337
  if ($sel -eq $i) { $mark = " " + $script:GcrTui.Box.Pointer }
1288
1338
  $val = [string]$it.Value
1289
- if ($it.Kind -eq "bool") { $val = $(if ($it.Flag) { "开" } else { "关" }) }
1339
+ if ($it.Kind -eq "bool") {
1340
+ if ($script:GcrLanguage -eq "en-US") { $val = $(if ($it.Flag) { "On" } else { "Off" }) }
1341
+ else { $val = $(if ($it.Flag) { "开" } else { "关" }) }
1342
+ }
1290
1343
  if ($St.Edit -and $sel -eq $i) {
1291
1344
  $buf = [string]$St.EditBuf
1292
1345
  $cur = [int]$St.EditCur
@@ -1294,7 +1347,8 @@ function Render-GcrTuiWizard {
1294
1347
  if ($cur -gt $buf.Length) { $cur = $buf.Length }
1295
1348
  $val = $buf.Insert($cur, "|")
1296
1349
  }
1297
- $label = Format-GcrCell $it.Label 14
1350
+ $labelText = Convert-GcrText ([string]$it.Label)
1351
+ $label = Format-GcrCell $labelText 20
1298
1352
  $text = $mark + " " + $label + " " + $val
1299
1353
  $col = $c.W
1300
1354
  if ($it.Kind -eq "start") { $col = $c.G + $c.B }
@@ -1302,15 +1356,31 @@ function Render-GcrTuiWizard {
1302
1356
  }
1303
1357
 
1304
1358
  WBorder "mid"
1305
- WRow " 最近任务 (Tab 切换 · Enter 填入)" $c.D
1306
- $recentSlots = $h - $lines.Count - 4
1359
+ $recentSlots = $h - $lines.Count - 5
1307
1360
  if ($recentSlots -lt 1) { $recentSlots = 1 }
1361
+ $recentTop = [int]$St.RecentTop
1362
+ $maxRecentTop = [Math]::Max(0, $recent.Count - $recentSlots)
1363
+ if ($recentTop -gt $maxRecentTop) { $recentTop = $maxRecentTop; $St.RecentTop = $recentTop }
1364
+ if ($St.Focus -eq "recent") {
1365
+ if ($St.RecentSel -lt $recentTop) { $recentTop = [int]$St.RecentSel; $St.RecentTop = $recentTop }
1366
+ if ($St.RecentSel -ge $recentTop + $recentSlots) {
1367
+ $recentTop = [int]$St.RecentSel - $recentSlots + 1
1368
+ $St.RecentTop = $recentTop
1369
+ }
1370
+ }
1371
+ $recentTitle = " 最近任务 (Tab 切换 · Enter 填入)"
1372
+ if ($recent.Count -gt $recentSlots) {
1373
+ $visibleEnd = [Math]::Min($recent.Count, $recentTop + $recentSlots)
1374
+ $recentTitle = $recentTitle + (" [{0}-{1}/{2}]" -f ($recentTop + 1), $visibleEnd, $recent.Count)
1375
+ }
1376
+ WRow $recentTitle $c.D
1308
1377
  if ($recent.Count -eq 0) {
1309
1378
  WRow " (无。完成一次克隆后会出现在这里)" $c.D
1310
1379
  $recentSlots--
1311
1380
  } else {
1312
- $show = [Math]::Min($recent.Count, [Math]::Max(1, $recentSlots))
1313
- for ($r = 0; $r -lt $show; $r++) {
1381
+ $show = [Math]::Min($recent.Count - $recentTop, [Math]::Max(1, $recentSlots))
1382
+ for ($slot = 0; $slot -lt $show; $slot++) {
1383
+ $r = $recentTop + $slot
1314
1384
  $it = $recent[$r]
1315
1385
  $name = [string]$it.outDir
1316
1386
  if ($name) { $name = Split-Path -Leaf $name }
@@ -1363,6 +1433,7 @@ function Get-GcrWizardItems {
1363
1433
  @{ Id = "verify"; Kind = "bool"; Label = "哈希校验"; Value = ""; Flag = [bool]$St.Verify; Guide = "续传时对已有文件做 hash-object 校验,哈希不一致则重新下载。Space 开关。" }
1364
1434
  @{ Id = "force"; Kind = "bool"; Label = "强制 refetch"; Value = ""; Flag = [bool]$St.ForceRefetch; Guide = "强制重新 fetch 目标 ref。换分支或更新到最新 commit 时打开。Space 开关。" }
1365
1435
  @{ Id = "dry"; Kind = "bool"; Label = "DryRun"; Value = ""; Flag = [bool]$St.DryRun; Guide = "只列出将要处理的文件,不下载 blob。适合先看清单。Space 开关。" }
1436
+ @{ Id = "language"; Kind = "enum"; Label = "语言"; Value = $(if ($St.Language -eq "en-US") { "英文" } else { "中文" }); Flag = $false; Guide = "选择界面语言。可随时按 L 在中文和英文之间切换。" }
1366
1437
  @{ Id = "start"; Kind = "start"; Label = "开始克隆"; Value = ""; Flag = $false; Guide = "按上面的设置开始或继续克隆。Enter 启动。中断后重跑即可续传。" }
1367
1438
  )
1368
1439
  }
@@ -1374,7 +1445,7 @@ function Apply-GcrRecentToWizard {
1374
1445
  if ($Item.outDir) { $St.OutDir = [string]$Item.outDir; $St.OutDirAuto = $false }
1375
1446
  if ($Item.ref) { $St.Ref = [string]$Item.ref }
1376
1447
  $St.Focus = "form"
1377
- $St.Sel = 11
1448
+ $St.Sel = 12
1378
1449
  }
1379
1450
 
1380
1451
  function Show-GcrTuiWizard {
@@ -1407,6 +1478,7 @@ function Show-GcrTuiWizard {
1407
1478
  OutDir = $dir
1408
1479
  OutDirAuto = $dirAuto
1409
1480
  Ref = $ref
1481
+ Language = $(if ($script:GcrLanguage) { $script:GcrLanguage } else { "zh-CN" })
1410
1482
  BatchSize = $batch
1411
1483
  MaxRetries = $retries
1412
1484
  Include = ""
@@ -1417,6 +1489,7 @@ function Show-GcrTuiWizard {
1417
1489
  DryRun = $false
1418
1490
  Sel = 0
1419
1491
  RecentSel = 0
1492
+ RecentTop = 0
1420
1493
  Focus = "form"
1421
1494
  Edit = $false
1422
1495
  EditBuf = ""
@@ -1536,18 +1609,32 @@ function Show-GcrTuiWizard {
1536
1609
  }
1537
1610
  "UpArrow" {
1538
1611
  if ($st.Focus -eq "recent") {
1539
- if ($st.RecentSel -gt 0) { $st.RecentSel-- }
1540
- else { $st.Focus = "form"; $st.Sel = 11 }
1612
+ if ($st.RecentSel -gt 0) {
1613
+ $st.RecentSel--
1614
+ if ($st.RecentSel -lt $st.RecentTop) { $st.RecentTop = $st.RecentSel }
1615
+ }
1616
+ else { $st.Focus = "form"; $st.Sel = 12 }
1541
1617
  } else {
1542
1618
  if ($st.Sel -gt 0) { $st.Sel-- }
1543
1619
  }
1544
1620
  }
1545
1621
  "DownArrow" {
1546
1622
  if ($st.Focus -eq "recent") {
1547
- if ($st.RecentSel -lt ($st.Recent.Count - 1)) { $st.RecentSel++ }
1623
+ if ($st.RecentSel -lt ($st.Recent.Count - 1)) {
1624
+ $st.RecentSel++
1625
+ $recentVisible = [Math]::Max(1, [int](Get-GcrTuiSize).H - 10)
1626
+ if ($st.RecentSel -ge $st.RecentTop + $recentVisible) {
1627
+ $st.RecentTop = $st.RecentSel - $recentVisible + 1
1628
+ }
1629
+ }
1548
1630
  } else {
1549
- if ($st.Sel -lt 11) { $st.Sel++ }
1550
- elseif ($st.Recent.Count -gt 0) { $st.Focus = "recent"; $st.RecentSel = 0 }
1631
+ if ($st.Sel -lt 12) { $st.Sel++ }
1632
+ elseif ($st.Recent.Count -gt 0) {
1633
+ $st.Focus = "recent"
1634
+ $st.RecentSel = [Math]::Min($st.RecentSel, $st.Recent.Count - 1)
1635
+ $recentVisible = [Math]::Max(1, [int](Get-GcrTuiSize).H - 10)
1636
+ $st.RecentTop = [Math]::Max(0, $st.RecentSel - $recentVisible + 1)
1637
+ }
1551
1638
  }
1552
1639
  }
1553
1640
  "K" {
@@ -1557,10 +1644,13 @@ function Show-GcrTuiWizard {
1557
1644
  }
1558
1645
  "J" {
1559
1646
  if ($k.KeyChar -eq "j") {
1560
- if ($st.Focus -eq "form" -and $st.Sel -lt 11) { $st.Sel++ }
1647
+ if ($st.Focus -eq "form" -and $st.Sel -lt 12) { $st.Sel++ }
1561
1648
  }
1562
1649
  }
1563
1650
  "LeftArrow" {
1651
+ if ($st.Focus -eq "form" -and $st.Sel -eq 11) {
1652
+ $st.Language = "zh-CN"
1653
+ }
1564
1654
  if ($st.Focus -eq "form" -and $st.Sel -eq 3) {
1565
1655
  $idx = [array]::IndexOf($batches, [int]$st.BatchSize)
1566
1656
  if ($idx -lt 0) { $idx = 2 }
@@ -1573,6 +1663,9 @@ function Show-GcrTuiWizard {
1573
1663
  }
1574
1664
  }
1575
1665
  "RightArrow" {
1666
+ if ($st.Focus -eq "form" -and $st.Sel -eq 11) {
1667
+ $st.Language = "en-US"
1668
+ }
1576
1669
  if ($st.Focus -eq "form" -and $st.Sel -eq 3) {
1577
1670
  $idx = [array]::IndexOf($batches, [int]$st.BatchSize)
1578
1671
  if ($idx -lt 0) { $idx = 2 }
@@ -1589,6 +1682,7 @@ function Show-GcrTuiWizard {
1589
1682
  if ($st.Sel -eq 8) { $st.Verify = -not $st.Verify }
1590
1683
  elseif ($st.Sel -eq 9) { $st.ForceRefetch = -not $st.ForceRefetch }
1591
1684
  elseif ($st.Sel -eq 10) { $st.DryRun = -not $st.DryRun }
1685
+ elseif ($st.Sel -eq 11) { $st.Language = $(if ($st.Language -eq "en-US") { "zh-CN" } else { "en-US" }); Set-GcrLanguage -Language $st.Language }
1592
1686
  }
1593
1687
  }
1594
1688
  "Enter" {
@@ -1617,6 +1711,7 @@ function Show-GcrTuiWizard {
1617
1711
  } elseif ($id -eq "verify") { $st.Verify = -not $st.Verify }
1618
1712
  elseif ($id -eq "force") { $st.ForceRefetch = -not $st.ForceRefetch }
1619
1713
  elseif ($id -eq "dry") { $st.DryRun = -not $st.DryRun }
1714
+ elseif ($id -eq "language") { $st.Language = $(if ($st.Language -eq "en-US") { "zh-CN" } else { "en-US" }); Set-GcrLanguage -Language $st.Language }
1620
1715
  elseif ($id -eq "batch" -or $id -eq "retry") { }
1621
1716
  else {
1622
1717
  $st.Edit = $true
@@ -1647,6 +1742,10 @@ function Show-GcrTuiWizard {
1647
1742
  }
1648
1743
  }
1649
1744
  default {
1745
+ if ($k.KeyChar -eq "l" -or $k.KeyChar -eq "L") {
1746
+ $st.Language = $(if ($st.Language -eq "en-US") { "zh-CN" } else { "en-US" })
1747
+ Set-GcrLanguage -Language $st.Language
1748
+ }
1650
1749
  if ($k.KeyChar -eq "?") { $st.Error = "Enter 编辑 · Space 开关 · Tab 最近任务 · S 开始 · Q 退出" }
1651
1750
  }
1652
1751
  }
@@ -1669,20 +1768,20 @@ function Show-GcrCliWizard {
1669
1768
  }
1670
1769
  $prompt = "仓库 URL"
1671
1770
  if ($pre) { $prompt = "仓库 URL [$pre]" }
1672
- $url = Read-Host $prompt
1771
+ $url = Read-Host (Convert-GcrText $prompt)
1673
1772
  if ([string]::IsNullOrWhiteSpace($url)) { $url = $pre }
1674
1773
  if ([string]::IsNullOrWhiteSpace($url)) { return $null }
1675
1774
  $defDir = Get-GcrFolderNameSafe -Url $url
1676
1775
  if ($Defaults -and $Defaults.ContainsKey("OutDir") -and $Defaults.OutDir) { $defDir = [string]$Defaults.OutDir }
1677
- $dir = Read-Host "本地目录 [$defDir]"
1776
+ $dir = Read-Host (Convert-GcrText "本地目录 [$defDir]")
1678
1777
  if ([string]::IsNullOrWhiteSpace($dir)) { $dir = $defDir }
1679
1778
  $defRef = "HEAD"
1680
1779
  if ($Defaults -and $Defaults.ContainsKey("Ref") -and $Defaults.Ref) { $defRef = [string]$Defaults.Ref }
1681
- $ref = Read-Host "分支/标签/commit [$defRef]"
1780
+ $ref = Read-Host (Convert-GcrText "分支/标签/commit [$defRef]")
1682
1781
  if ([string]::IsNullOrWhiteSpace($ref)) { $ref = $defRef }
1683
1782
  $batch = 32
1684
1783
  if ($Defaults -and $Defaults.ContainsKey("BatchSize") -and $Defaults.BatchSize) { $batch = [int]$Defaults.BatchSize }
1685
- $batchText = Read-Host "每批文件数 [$batch]"
1784
+ $batchText = Read-Host (Convert-GcrText "每批文件数 [$batch]")
1686
1785
  if ($batchText -match "^\d+$") { $batch = [int]$batchText }
1687
1786
  return @{
1688
1787
  RepoUrl = $url.Trim()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-clone-resume",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Resume-friendly partial clone tool for Windows",
5
5
  "bin": {
6
6
  "gcr": "gcr.cmd",
@@ -11,7 +11,8 @@
11
11
  "git-clone-resume.cmd",
12
12
  "git-clone-resume.ps1",
13
13
  "git-clone-resume.tui.ps1",
14
- "README.md"
14
+ "README.md",
15
+ "README.en.md"
15
16
  ],
16
17
  "engines": {
17
18
  "node": ">=16"