mirror of
https://github.com/starship/starship.git
synced 2026-06-21 02:02:14 +07:00
perf: use gitoxide for git_status and git_metrics modules (#6476)
This commit is contained in:
@@ -664,7 +664,8 @@
|
||||
"style": "red bold",
|
||||
"typechanged": "",
|
||||
"untracked": "?",
|
||||
"up_to_date": ""
|
||||
"up_to_date": "",
|
||||
"use_git_executable": false
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
@@ -3649,6 +3650,10 @@
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"use_git_executable": {
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"windows_starship": {
|
||||
"type": [
|
||||
"string",
|
||||
|
||||
Generated
+317
-78
@@ -360,6 +360,12 @@ version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytesize"
|
||||
version = "1.3.3"
|
||||
@@ -607,6 +613,20 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deelevate"
|
||||
version = "0.2.0"
|
||||
@@ -846,10 +866,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "faster-hex"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
|
||||
checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -980,27 +1001,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix"
|
||||
version = "0.71.0"
|
||||
version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a61e71ec6817fc3c9f12f812682cfe51ee6ea0d2e27e02fc3849c35524617435"
|
||||
checksum = "01237e8d3d78581f71642be8b0c2ae8c0b2b5c251c9c5d9ebbea3c1ea280dce8"
|
||||
dependencies = [
|
||||
"gix-actor",
|
||||
"gix-attributes",
|
||||
"gix-command",
|
||||
"gix-commitgraph",
|
||||
"gix-config",
|
||||
"gix-date",
|
||||
"gix-diff",
|
||||
"gix-dir",
|
||||
"gix-discover",
|
||||
"gix-features",
|
||||
"gix-filter",
|
||||
"gix-fs",
|
||||
"gix-glob",
|
||||
"gix-hash",
|
||||
"gix-hashtable",
|
||||
"gix-ignore",
|
||||
"gix-index",
|
||||
"gix-lock",
|
||||
"gix-object",
|
||||
"gix-odb",
|
||||
"gix-pack",
|
||||
"gix-path",
|
||||
"gix-pathspec",
|
||||
"gix-protocol",
|
||||
"gix-ref",
|
||||
"gix-refspec",
|
||||
@@ -1008,12 +1035,15 @@ dependencies = [
|
||||
"gix-revwalk",
|
||||
"gix-sec",
|
||||
"gix-shallow",
|
||||
"gix-status",
|
||||
"gix-submodule",
|
||||
"gix-tempfile",
|
||||
"gix-trace",
|
||||
"gix-traverse",
|
||||
"gix-url",
|
||||
"gix-utils",
|
||||
"gix-validate",
|
||||
"gix-worktree",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"thiserror 2.0.12",
|
||||
@@ -1021,9 +1051,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-actor"
|
||||
version = "0.34.0"
|
||||
version = "0.35.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f438c87d4028aca4b82f82ba8d8ab1569823cfb3e5bc5fa8456a71678b2a20e7"
|
||||
checksum = "6b300e6e4f31f3f6bd2de5e2b0caab192ced00dc0fcd0f7cc56e28c575c8e1ff"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-date",
|
||||
@@ -1033,6 +1063,23 @@ dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-attributes"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e26b3ac280ddb25bb6980d34f4a82ee326f78bf2c6d4ea45eef2d940048b8e"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-glob",
|
||||
"gix-path",
|
||||
"gix-quote",
|
||||
"gix-trace",
|
||||
"kstring",
|
||||
"smallvec",
|
||||
"thiserror 2.0.12",
|
||||
"unicode-bom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-bitmap"
|
||||
version = "0.2.14"
|
||||
@@ -1053,9 +1100,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-command"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0378995847773a697f8e157fe2963ecf3462fe64be05b7b3da000b3b472def8"
|
||||
checksum = "d2f47f3fb4ba33644061e8e0e1030ef2a937d42dc969553118c320a205a9fb28"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-path",
|
||||
@@ -1066,9 +1113,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-commitgraph"
|
||||
version = "0.27.0"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "043cbe49b7a7505150db975f3cb7c15833335ac1e26781f615454d9d640a28fe"
|
||||
checksum = "e05050fd6caa6c731fe3bd7f9485b3b520be062d3d139cb2626e052d6c127951"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-chunk",
|
||||
@@ -1079,9 +1126,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-config"
|
||||
version = "0.44.0"
|
||||
version = "0.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c6f830bf746604940261b49abf7f655d2c19cadc9f4142ae9379e3a316e8cfa"
|
||||
checksum = "48f3c8f357ae049bfb77493c2ec9010f58cfc924ae485e1116c3718fc0f0d881"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-config-value",
|
||||
@@ -1100,9 +1147,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-config-value"
|
||||
version = "0.14.12"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dc2c844c4cf141884678cabef736fd91dd73068b9146e6f004ba1a0457944b6"
|
||||
checksum = "439d62e241dae2dffd55bfeeabe551275cf9d9f084c5ebc6b48bad49d03285b7"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bstr",
|
||||
@@ -1113,33 +1160,66 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-date"
|
||||
version = "0.9.4"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daa30058ec7d3511fbc229e4f9e696a35abd07ec5b82e635eff864a2726217e4"
|
||||
checksum = "3a98593f1f1e14b9fa15c5b921b2c465e904d698b9463e21bb377be8376c3c1a"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"itoa",
|
||||
"jiff",
|
||||
"smallvec",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-diff"
|
||||
version = "0.51.0"
|
||||
version = "0.52.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2c975dad2afc85e4e233f444d1efbe436c3cdcf3a07173984509c436d00a3f8"
|
||||
checksum = "5e9b43e95fe352da82a969f0c84ff860c2de3e724d93f6681fedbcd6c917f252"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-attributes",
|
||||
"gix-command",
|
||||
"gix-filter",
|
||||
"gix-fs",
|
||||
"gix-hash",
|
||||
"gix-index",
|
||||
"gix-object",
|
||||
"gix-path",
|
||||
"gix-pathspec",
|
||||
"gix-tempfile",
|
||||
"gix-trace",
|
||||
"gix-traverse",
|
||||
"gix-worktree",
|
||||
"imara-diff",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-dir"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01e6e2dc5b8917142d0ffe272209d1671e45b771e433f90186bc71c016792e87"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-discover",
|
||||
"gix-fs",
|
||||
"gix-ignore",
|
||||
"gix-index",
|
||||
"gix-object",
|
||||
"gix-path",
|
||||
"gix-pathspec",
|
||||
"gix-trace",
|
||||
"gix-utils",
|
||||
"gix-worktree",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-discover"
|
||||
version = "0.39.0"
|
||||
version = "0.40.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fb8a4349b854506a3915de18d3341e5f1daa6b489c8affc9ca0d69efe86781"
|
||||
checksum = "dccfe3e25b4ea46083916c56db3ba9d1e6ef6dce54da485f0463f9fc0fe1837c"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"dunce",
|
||||
@@ -1153,9 +1233,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-features"
|
||||
version = "0.41.1"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "016d6050219458d14520fe22bdfdeb9cb71631dec9bc2724767c983f60109634"
|
||||
checksum = "56f4399af6ec4fd9db84dd4cf9656c5c785ab492ab40a7c27ea92b4241923fed"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"crossbeam-channel",
|
||||
@@ -1172,10 +1252,31 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-fs"
|
||||
version = "0.14.0"
|
||||
name = "gix-filter"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "951e886120dc5fa8cac053e5e5c89443f12368ca36811b2e43d1539081f9c111"
|
||||
checksum = "f90c21f0d61778f518bbb7c431b00247bf4534b2153c3e85bcf383876c55ca6c"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"encoding_rs",
|
||||
"gix-attributes",
|
||||
"gix-command",
|
||||
"gix-hash",
|
||||
"gix-object",
|
||||
"gix-packetline-blocking",
|
||||
"gix-path",
|
||||
"gix-quote",
|
||||
"gix-trace",
|
||||
"gix-utils",
|
||||
"smallvec",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-fs"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a0637149b4ef24d3ea55f81f77231401c8463fae6da27331c987957eb597c7"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"fastrand",
|
||||
@@ -1187,9 +1288,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-glob"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20972499c03473e773a2099e5fd0c695b9b72465837797a51a43391a1635a030"
|
||||
checksum = "2926b03666e83b8d01c10cf06e5733521aacbd2d97179a4c9b1fdddabb9e937d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bstr",
|
||||
@@ -1199,9 +1300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-hash"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "834e79722063958b03342edaa1e17595cd2939bb2b3306b3225d0815566dcb49"
|
||||
checksum = "8d4900562c662852a6b42e2ef03442eccebf24f047d8eab4f23bc12ef0d785d8"
|
||||
dependencies = [
|
||||
"faster-hex",
|
||||
"gix-features",
|
||||
@@ -1211,9 +1312,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-hashtable"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f06066d8702a9186dc1fdc1ed751ff2d7e924ceca21cb5d51b8f990c9c2e014a"
|
||||
checksum = "b5b5cb3c308b4144f2612ff64e32130e641279fcf1a84d8d40dad843b4f64904"
|
||||
dependencies = [
|
||||
"gix-hash",
|
||||
"hashbrown 0.14.5",
|
||||
@@ -1221,10 +1322,23 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-index"
|
||||
version = "0.39.0"
|
||||
name = "gix-ignore"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "855bece2d4153453aa5d0a80d51deea1ce8cd6a3b4cf213da85ac344ccb908a7"
|
||||
checksum = "ae358c3c96660b10abc7da63c06788dfded603e717edbd19e38c6477911b71c8"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-glob",
|
||||
"gix-path",
|
||||
"gix-trace",
|
||||
"unicode-bom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-index"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d505aea7d7c4267a3153cb90c712a89970b4dd02a2cb3205be322891f530b5"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bstr",
|
||||
@@ -1243,16 +1357,16 @@ dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
"memmap2",
|
||||
"rustix 0.38.44",
|
||||
"rustix 1.0.5",
|
||||
"smallvec",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-lock"
|
||||
version = "17.0.0"
|
||||
version = "17.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df47b8f11c34520db5541bc5fc9fbc8e4b0bdfcec3736af89ccb1a5728a0126f"
|
||||
checksum = "570f8b034659f256366dc90f1a24924902f20acccd6a15be96d44d1269e7a796"
|
||||
dependencies = [
|
||||
"gix-tempfile",
|
||||
"gix-utils",
|
||||
@@ -1261,9 +1375,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-object"
|
||||
version = "0.48.0"
|
||||
version = "0.49.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4943fcdae6ffc135920c9ea71e0362ed539182924ab7a85dd9dac8d89b0dd69a"
|
||||
checksum = "d957ca3640c555d48bb27f8278c67169fa1380ed94f6452c5590742524c40fbb"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-actor",
|
||||
@@ -1282,9 +1396,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-odb"
|
||||
version = "0.68.0"
|
||||
version = "0.69.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50306d40dcc982eb6b7593103f066ea6289c7b094cb9db14f3cd2be0b9f5e610"
|
||||
checksum = "868f703905fdbcfc1bd750942f82419903ecb7039f5288adb5206d6de405e0c9"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"gix-date",
|
||||
@@ -1303,9 +1417,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-pack"
|
||||
version = "0.58.0"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b65fffb09393c26624ca408d32cfe8776fb94cd0a5cdf984905e1d2f39779cb"
|
||||
checksum = "9d49c55d69c8449f2a0a5a77eb9cbacfebb6b0e2f1215f0fc23a4cb60528a450"
|
||||
dependencies = [
|
||||
"clru",
|
||||
"gix-chunk",
|
||||
@@ -1322,9 +1436,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-packetline"
|
||||
version = "0.18.4"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "123844a70cf4d5352441dc06bab0da8aef61be94ec239cb631e0ba01dc6d3a04"
|
||||
checksum = "8ddc034bc67c848e4ef7596ab5528cd8fd439d310858dbe1ce8b324f25deb91c"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"faster-hex",
|
||||
"gix-trace",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-packetline-blocking"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c44880f028ba46d6cf37a66d27a300310c6b51b8ed0e44918f93df061168e2f3"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"faster-hex",
|
||||
@@ -1334,22 +1460,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-path"
|
||||
version = "0.10.15"
|
||||
version = "0.10.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f910668e2f6b2a55ff35a1f04df88a1a049f7b868507f4cbeeaa220eaba7be87"
|
||||
checksum = "c091d2e887e02c3462f52252c5ea61150270c0f2657b642e8d0d6df56c16e642"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-trace",
|
||||
"gix-validate",
|
||||
"home",
|
||||
"once_cell",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-protocol"
|
||||
version = "0.49.0"
|
||||
name = "gix-pathspec"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5678ddae1d62880bc30e2200be1b9387af3372e0e88e21f81b4e7f8367355b5a"
|
||||
checksum = "ce061c50e5f8f7c830cacb3da3e999ae935e283ce8522249f0ce2256d110979d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bstr",
|
||||
"gix-attributes",
|
||||
"gix-config-value",
|
||||
"gix-glob",
|
||||
"gix-path",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-protocol"
|
||||
version = "0.50.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5c17d78bb0414f8d60b5f952196dc2e47ec320dca885de9128ecdb4a0e38401"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-date",
|
||||
@@ -1366,9 +1508,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-quote"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b005c550bf84de3b24aa5e540a23e6146a1c01c7d30470e35d75a12f827f969"
|
||||
checksum = "4a375a75b4d663e8bafe3bf4940a18a23755644c13582fa326e99f8f987d83fd"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-utils",
|
||||
@@ -1377,9 +1519,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-ref"
|
||||
version = "0.51.0"
|
||||
version = "0.52.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2e1f7eb6b7ce82d2d19961f74bd637bab3ea79b1bc7bfb23dbefc67b0415d8b"
|
||||
checksum = "d1b7985657029684d759f656b09abc3e2c73085596d5cdb494428823970a7762"
|
||||
dependencies = [
|
||||
"gix-actor",
|
||||
"gix-features",
|
||||
@@ -1398,9 +1540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-refspec"
|
||||
version = "0.29.0"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d8587b21e2264a6e8938d940c5c99662779c13a10741a5737b15fc85c252ffc"
|
||||
checksum = "445ed14e3db78e8e79980085e3723df94e1c8163b3ae5bc8ed6a8fe6cf983b42"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-hash",
|
||||
@@ -1412,9 +1554,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-revision"
|
||||
version = "0.33.0"
|
||||
version = "0.34.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "342caa4e158df3020cadf62f656307c3948fe4eacfdf67171d7212811860c3e9"
|
||||
checksum = "78d0b8e5cbd1c329e25383e088cb8f17439414021a643b30afa5146b71e3c65d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"bstr",
|
||||
@@ -1430,9 +1572,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-revwalk"
|
||||
version = "0.19.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc7c3d7e5cdc1ab8d35130106e4af0a4f9f9eca0c81f4312b690780e92bde0d"
|
||||
checksum = "1bc756b73225bf005ddeb871d1ca7b3c33e2417d0d53e56effa5a36765b52b28"
|
||||
dependencies = [
|
||||
"gix-commitgraph",
|
||||
"gix-date",
|
||||
@@ -1445,21 +1587,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-sec"
|
||||
version = "0.10.12"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47aeb0f13de9ef2f3033f5ff218de30f44db827ac9f1286f9ef050aacddd5888"
|
||||
checksum = "d0dabbc78c759ecc006b970339394951b2c8e1e38a37b072c105b80b84c308fd"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"gix-path",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-shallow"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc0598aacfe1d52575a21c9492fee086edbb21e228ec36c819c42ab923f434c3"
|
||||
checksum = "6b9a6f6e34d6ede08f522d89e5c7990b4f60524b8ae6ebf8e850963828119ad4"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-hash",
|
||||
@@ -1468,11 +1610,50 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-tempfile"
|
||||
version = "17.0.0"
|
||||
name = "gix-status"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6de439bbb9a5d3550c9c7fab0e16d2d637d120fcbe0dfbc538772a187f099b"
|
||||
checksum = "072099c2415cfa5397df7d47eacbcb6016d2cd17e0d674c74965e6ad1b17289f"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"filetime",
|
||||
"gix-diff",
|
||||
"gix-dir",
|
||||
"gix-features",
|
||||
"gix-filter",
|
||||
"gix-fs",
|
||||
"gix-hash",
|
||||
"gix-index",
|
||||
"gix-object",
|
||||
"gix-path",
|
||||
"gix-pathspec",
|
||||
"gix-worktree",
|
||||
"portable-atomic",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-submodule"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f51472f05a450cc61bc91ed2f62fb06e31e2bbb31c420bc4be8793f26c8b0c1"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-config",
|
||||
"gix-path",
|
||||
"gix-pathspec",
|
||||
"gix-refspec",
|
||||
"gix-url",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-tempfile"
|
||||
version = "17.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c750e8c008453a2dba67a2b0d928b7716e05da31173a3f5e351d5457ad4470aa"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"gix-fs",
|
||||
"libc",
|
||||
"once_cell",
|
||||
@@ -1488,9 +1669,9 @@ checksum = "7c396a2036920c69695f760a65e7f2677267ccf483f25046977d87e4cb2665f7"
|
||||
|
||||
[[package]]
|
||||
name = "gix-transport"
|
||||
version = "0.46.0"
|
||||
version = "0.47.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3f68c2870bfca8278389d2484a7f2215b67d0b0cc5277d3c72ad72acf41787e"
|
||||
checksum = "edfe22ba26d4b65c17879f12b9882eafe65d3c8611c933b272fce2c10f546f59"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-command",
|
||||
@@ -1504,9 +1685,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-traverse"
|
||||
version = "0.45.0"
|
||||
version = "0.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36c0b049f8bdb61b20016694102f7b507f2e1727e83e9c5e6dad4f7d84ff7384"
|
||||
checksum = "39094185f6d9a4d81101130fbbf7f598a06441d774ae3b3ae7930a613bbe1157"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"gix-commitgraph",
|
||||
@@ -1521,9 +1702,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-url"
|
||||
version = "0.30.0"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48dfe23f93f1ddb84977d80bb0dd7aa09d1bf5d5afc0c9b6820cccacc25ae860"
|
||||
checksum = "42a1ad0b04a5718b5cb233e6888e52a9b627846296161d81dcc5eb9203ec84b8"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-features",
|
||||
@@ -1535,24 +1716,44 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gix-utils"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "189f8724cf903e7fd57cfe0b7bc209db255cacdcb22c781a022f52c3a774f8d0"
|
||||
checksum = "5351af2b172caf41a3728eb4455326d84e0d70fe26fc4de74ab0bd37df4191c5"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"fastrand",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-validate"
|
||||
version = "0.9.4"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34b5f1253109da6c79ed7cf6e1e38437080bb6d704c76af14c93e2f255234084"
|
||||
checksum = "77b9e00cacde5b51388d28ed746c493b18a6add1f19b5e01d686b3b9ece66d4d"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gix-worktree"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54f1916f8d928268300c977d773dd70a8746b646873b77add0a34876a8c847e9"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-attributes",
|
||||
"gix-features",
|
||||
"gix-fs",
|
||||
"gix-glob",
|
||||
"gix-hash",
|
||||
"gix-ignore",
|
||||
"gix-index",
|
||||
"gix-object",
|
||||
"gix-path",
|
||||
"gix-validate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "guess_host_triple"
|
||||
version = "0.1.4"
|
||||
@@ -1565,6 +1766,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@@ -1599,6 +1809,16 @@ dependencies = [
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -1789,6 +2009,15 @@ dependencies = [
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imara-diff"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
@@ -1917,6 +2146,15 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kstring"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1"
|
||||
dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -3087,6 +3325,7 @@ dependencies = [
|
||||
"nu-ansi-term",
|
||||
"open",
|
||||
"os_info",
|
||||
"parking_lot",
|
||||
"path-slash",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
|
||||
+8
-1
@@ -42,7 +42,7 @@ clap_complete_nushell = "4.5.5"
|
||||
dirs = "6.0.0"
|
||||
dunce = "1.0.5"
|
||||
# default feature restriction addresses https://github.com/starship/starship/issues/4251
|
||||
gix = { version = "0.71.0", default-features = false, features = ["max-performance-safe", "revision", "zlib-rs"] }
|
||||
gix = { version = "0.72.1", default-features = false, features = ["max-performance-safe", "revision", "zlib-rs", "status"] }
|
||||
indexmap = { version = "2.9.0", features = ["serde"] }
|
||||
jsonc-parser = { version = "0.26.2", features = ["serde"] }
|
||||
log = { version = "0.4.27", features = ["std"] }
|
||||
@@ -53,6 +53,8 @@ nu-ansi-term = "0.50.1"
|
||||
open = "5.3.2"
|
||||
# update os module config and tests when upgrading os_info
|
||||
os_info = "3.10.0"
|
||||
# for efficient shared state between `git_status` and `git_metrics`, allowing parallel printing. This is for poison-free locks.
|
||||
parking_lot = "0.12.3"
|
||||
path-slash = "0.2.1"
|
||||
pest = "2.8.0"
|
||||
pest_derive = "2.8.0"
|
||||
@@ -124,6 +126,11 @@ codegen-units = 1
|
||||
lto = true
|
||||
strip = true
|
||||
|
||||
[profile.bench]
|
||||
codegen-units = 16
|
||||
lto = "thin"
|
||||
strip = false
|
||||
|
||||
[[bin]]
|
||||
name = "starship"
|
||||
path = "src/main.rs"
|
||||
|
||||
+20
-19
@@ -1960,25 +1960,26 @@ You can disable the module or use the `windows_starship` option to use a Windows
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| ------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| `format` | `'([\[$all_status$ahead_behind\]]($style) )'` | The default format for `git_status` |
|
||||
| `conflicted` | `'='` | This branch has merge conflicts. |
|
||||
| `ahead` | `'⇡'` | The format of `ahead` |
|
||||
| `behind` | `'⇣'` | The format of `behind` |
|
||||
| `diverged` | `'⇕'` | The format of `diverged` |
|
||||
| `up_to_date` | `''` | The format of `up_to_date` |
|
||||
| `untracked` | `'?'` | The format of `untracked` |
|
||||
| `stashed` | `'$'` | The format of `stashed` |
|
||||
| `modified` | `'!'` | The format of `modified` |
|
||||
| `staged` | `'+'` | The format of `staged` |
|
||||
| `renamed` | `'»'` | The format of `renamed` |
|
||||
| `deleted` | `'✘'` | The format of `deleted` |
|
||||
| `typechanged` | `""` | The format of `typechanged` |
|
||||
| `style` | `'bold red'` | The style for the module. |
|
||||
| `ignore_submodules` | `false` | Ignore changes to submodules. |
|
||||
| `disabled` | `false` | Disables the `git_status` module. |
|
||||
| `windows_starship` | | Use this (Linux) path to a Windows Starship executable to render `git_status` when on Windows paths in WSL. |
|
||||
| Option | Default | Description |
|
||||
| -------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| `format` | `'([\[$all_status$ahead_behind\]]($style) )'` | The default format for `git_status` |
|
||||
| `conflicted` | `'='` | This branch has merge conflicts. |
|
||||
| `ahead` | `'⇡'` | The format of `ahead` |
|
||||
| `behind` | `'⇣'` | The format of `behind` |
|
||||
| `diverged` | `'⇕'` | The format of `diverged` |
|
||||
| `up_to_date` | `''` | The format of `up_to_date` |
|
||||
| `untracked` | `'?'` | The format of `untracked` |
|
||||
| `stashed` | `'$'` | The format of `stashed` |
|
||||
| `modified` | `'!'` | The format of `modified` |
|
||||
| `staged` | `'+'` | The format of `staged` |
|
||||
| `renamed` | `'»'` | The format of `renamed` |
|
||||
| `deleted` | `'✘'` | The format of `deleted` |
|
||||
| `typechanged` | `""` | The format of `typechanged` |
|
||||
| `style` | `'bold red'` | The style for the module. |
|
||||
| `ignore_submodules` | `false` | Ignore changes to submodules. |
|
||||
| `disabled` | `false` | Disables the `git_status` module. |
|
||||
| `windows_starship` | | Use this (Linux) path to a Windows Starship executable to render `git_status` when on Windows paths in WSL. |
|
||||
| `use_git_executable` | `false` | Do not use `gitoxide` for computing the status, but use the `git` executable instead. |
|
||||
|
||||
### Variables
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ pub struct GitStatusConfig<'a> {
|
||||
pub typechanged: &'a str,
|
||||
pub ignore_submodules: bool,
|
||||
pub disabled: bool,
|
||||
pub use_git_executable: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub windows_starship: Option<&'a str>,
|
||||
}
|
||||
@@ -47,6 +48,7 @@ impl Default for GitStatusConfig<'_> {
|
||||
typechanged: "",
|
||||
ignore_submodules: false,
|
||||
disabled: false,
|
||||
use_git_executable: false,
|
||||
windows_starship: None,
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -294,12 +294,13 @@ impl<'a> Context<'a> {
|
||||
let mut git_open_opts_map =
|
||||
git_sec::trust::Mapping::<gix::open::Options>::default();
|
||||
|
||||
// don't use the global git configs
|
||||
// Load all the configuration as it affects aspects of the
|
||||
// `git_status` and `git_metrics` modules.
|
||||
let config = gix::open::permissions::Config {
|
||||
git_binary: false,
|
||||
system: false,
|
||||
git: false,
|
||||
user: false,
|
||||
git_binary: true,
|
||||
system: true,
|
||||
git: true,
|
||||
user: true,
|
||||
env: true,
|
||||
includes: true,
|
||||
};
|
||||
@@ -652,7 +653,7 @@ pub struct Repo {
|
||||
|
||||
/// Contains `true` if the value of `core.fsmonitor` is set to `true`.
|
||||
/// If not `true`, `fsmonitor` is explicitly disabled in git commands.
|
||||
fs_monitor_value_is_true: bool,
|
||||
pub(crate) fs_monitor_value_is_true: bool,
|
||||
|
||||
// Kind of repository, work tree or bare
|
||||
pub kind: Kind,
|
||||
@@ -671,7 +672,7 @@ impl Repo {
|
||||
pub fn exec_git<T: AsRef<OsStr> + Debug>(
|
||||
&self,
|
||||
context: &Context,
|
||||
git_args: &[T],
|
||||
git_args: impl IntoIterator<Item = T>,
|
||||
) -> Option<CommandOutput> {
|
||||
let mut command = create_command("git").ok()?;
|
||||
|
||||
|
||||
+17
@@ -3,6 +3,8 @@
|
||||
#[macro_use]
|
||||
extern crate shadow_rs;
|
||||
|
||||
use std::thread::available_parallelism;
|
||||
|
||||
shadow!(shadow);
|
||||
|
||||
// Lib is present to allow for benchmarking
|
||||
@@ -24,3 +26,18 @@ mod utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
/// Return the number of threads starship should use, if configured.
|
||||
pub fn num_configured_starship_threads() -> Option<usize> {
|
||||
std::env::var("STARSHIP_NUM_THREADS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
}
|
||||
|
||||
/// Return the maximum number of threads for the global thread-pool.
|
||||
pub fn num_rayon_threads() -> usize {
|
||||
num_configured_starship_threads()
|
||||
// Default to the number of logical cores,
|
||||
// but restrict the number of threads to 8
|
||||
.unwrap_or_else(|| available_parallelism().map(usize::from).unwrap_or(1).min(8))
|
||||
}
|
||||
|
||||
+1
-10
@@ -3,7 +3,6 @@
|
||||
use clap::crate_authors;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::thread::available_parallelism;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
|
||||
@@ -281,16 +280,8 @@ fn main() {
|
||||
|
||||
/// Initialize global `rayon` thread pool
|
||||
fn init_global_threadpool() {
|
||||
// Allow overriding the number of threads
|
||||
let num_threads = std::env::var("STARSHIP_NUM_THREADS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
// Default to the number of logical cores,
|
||||
// but restrict the number of threads to 8
|
||||
.unwrap_or_else(|| available_parallelism().map(usize::from).unwrap_or(1).min(8));
|
||||
|
||||
rayon::ThreadPoolBuilder::new()
|
||||
.num_threads(num_threads)
|
||||
.num_threads(num_rayon_threads())
|
||||
.build_global()
|
||||
.expect("Failed to initialize worker thread pool");
|
||||
}
|
||||
|
||||
+456
-26
@@ -1,12 +1,16 @@
|
||||
use gix::bstr::{BStr, ByteSlice};
|
||||
use gix::diff::blob::ResourceKind;
|
||||
use gix::diff::blob::pipeline::WorktreeRoots;
|
||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||
use regex::Regex;
|
||||
|
||||
use super::Context;
|
||||
use crate::configs::git_status::GitStatusConfig;
|
||||
use crate::{
|
||||
config::ModuleConfig, configs::git_metrics::GitMetricsConfig, formatter::StringFormatter,
|
||||
formatter::string_formatter::StringFormatterError, module::Module,
|
||||
};
|
||||
|
||||
use super::Context;
|
||||
|
||||
/// Creates a module with the current added/deleted lines in the git repository at the
|
||||
/// current directory
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
@@ -20,14 +24,227 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
};
|
||||
|
||||
let repo = context.get_repo().ok()?;
|
||||
let mut git_args = vec!["diff", "--shortstat"];
|
||||
if config.ignore_submodules {
|
||||
git_args.push("--ignore-submodules");
|
||||
let gix_repo = repo.open();
|
||||
if gix_repo.is_bare() {
|
||||
return None;
|
||||
}
|
||||
// TODO: remove this special case once `gitoxide` can handle sparse indices for tree-index comparisons.
|
||||
let stats = if gix_repo.index_or_empty().ok()?.is_sparse() || repo.fs_monitor_value_is_true {
|
||||
let mut git_args = vec!["diff", "--shortstat"];
|
||||
if config.ignore_submodules {
|
||||
git_args.push("--ignore-submodules");
|
||||
}
|
||||
|
||||
let diff = repo.exec_git(context, &git_args)?.stdout;
|
||||
let diff = repo.exec_git(context, &git_args)?.stdout;
|
||||
|
||||
let stats = GitDiff::parse(&diff);
|
||||
GitDiff::parse(&diff)
|
||||
} else {
|
||||
#[derive(Default)]
|
||||
struct Diff {
|
||||
added: usize,
|
||||
deleted: usize,
|
||||
}
|
||||
impl Diff {
|
||||
fn add(&mut self, c: Option<gix::diff::blob::sink::Counter<()>>) {
|
||||
let Some(c) = c else { return };
|
||||
self.added += c.insertions as usize;
|
||||
self.deleted += c.removals as usize;
|
||||
}
|
||||
}
|
||||
let status_module = context.new_module("git_status");
|
||||
let status_config = GitStatusConfig::try_load(status_module.config);
|
||||
let status = super::git_status::get_static_repo_status(context, repo, &status_config)?;
|
||||
let gix_repo = gix_repo.with_object_memory();
|
||||
gix_repo.write_blob([]).ok()?; /* create empty blob */
|
||||
let tree_index_cache = prevent_external_diff(
|
||||
gix_repo
|
||||
.diff_resource_cache(gix::diff::blob::pipeline::Mode::ToGit, Default::default())
|
||||
.ok()?,
|
||||
);
|
||||
let index_worktree_cache = prevent_external_diff(
|
||||
gix_repo
|
||||
.diff_resource_cache(
|
||||
gix::diff::blob::pipeline::Mode::ToGit,
|
||||
WorktreeRoots {
|
||||
old_root: None,
|
||||
new_root: gix_repo.workdir().map(ToOwned::to_owned),
|
||||
},
|
||||
)
|
||||
.ok()?,
|
||||
);
|
||||
let diff = status
|
||||
.changes
|
||||
.par_iter()
|
||||
.map_init(
|
||||
{
|
||||
let repo = gix_repo.into_sync();
|
||||
move || {
|
||||
let repo = repo.to_thread_local();
|
||||
(repo, tree_index_cache.clone(), index_worktree_cache.clone())
|
||||
}
|
||||
},
|
||||
|(repo, tree_index_cache, index_worktree_cache), change| {
|
||||
use gix::status;
|
||||
let mut diff = Diff::default();
|
||||
match change {
|
||||
status::Item::TreeIndex(change) => {
|
||||
use gix::diff::index::Change;
|
||||
match change {
|
||||
Change::Addition {
|
||||
entry_mode,
|
||||
location,
|
||||
id,
|
||||
..
|
||||
} => {
|
||||
diff.added += count_lines(
|
||||
location,
|
||||
id.as_ref().into(),
|
||||
*entry_mode,
|
||||
tree_index_cache,
|
||||
repo,
|
||||
);
|
||||
}
|
||||
Change::Deletion {
|
||||
entry_mode,
|
||||
location,
|
||||
id,
|
||||
..
|
||||
} => {
|
||||
diff.deleted += count_lines(
|
||||
location,
|
||||
id.as_ref().into(),
|
||||
*entry_mode,
|
||||
tree_index_cache,
|
||||
repo,
|
||||
);
|
||||
}
|
||||
Change::Modification {
|
||||
location,
|
||||
previous_entry_mode,
|
||||
previous_id,
|
||||
entry_mode,
|
||||
id,
|
||||
..
|
||||
} => {
|
||||
let location = location.as_ref();
|
||||
diff.add(diff_two_opt(
|
||||
location,
|
||||
previous_id.as_ref().to_owned(),
|
||||
*previous_entry_mode,
|
||||
location,
|
||||
id.as_ref().to_owned(),
|
||||
*entry_mode,
|
||||
tree_index_cache,
|
||||
repo,
|
||||
));
|
||||
}
|
||||
Change::Rewrite {
|
||||
source_location,
|
||||
source_entry_mode,
|
||||
source_id,
|
||||
location,
|
||||
entry_mode,
|
||||
id,
|
||||
copy,
|
||||
..
|
||||
} => {
|
||||
if *copy {
|
||||
diff.added += count_lines(
|
||||
location,
|
||||
id.as_ref().into(),
|
||||
*entry_mode,
|
||||
tree_index_cache,
|
||||
repo,
|
||||
);
|
||||
} else {
|
||||
diff.add(diff_two_opt(
|
||||
source_location.as_ref(),
|
||||
source_id.as_ref().to_owned(),
|
||||
*source_entry_mode,
|
||||
location,
|
||||
id.as_ref().to_owned(),
|
||||
*entry_mode,
|
||||
tree_index_cache,
|
||||
repo,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
status::Item::IndexWorktree(change) => {
|
||||
use gix::status::index_worktree::Item;
|
||||
use gix::status::plumbing::index_as_worktree::{Change, EntryStatus};
|
||||
match change {
|
||||
Item::Modification {
|
||||
rela_path,
|
||||
entry,
|
||||
status: EntryStatus::Change(Change::Removed),
|
||||
..
|
||||
} => {
|
||||
diff.deleted += count_lines(
|
||||
rela_path.as_bstr(),
|
||||
entry.id,
|
||||
entry.mode,
|
||||
tree_index_cache,
|
||||
repo,
|
||||
);
|
||||
}
|
||||
Item::Modification {
|
||||
rela_path,
|
||||
entry,
|
||||
status:
|
||||
EntryStatus::Change(Change::Modification {
|
||||
content_change: Some(_),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} => {
|
||||
let location = rela_path.as_bstr();
|
||||
diff.add(diff_two_opt(
|
||||
location,
|
||||
entry.id,
|
||||
entry.mode,
|
||||
location,
|
||||
repo.object_hash().null(),
|
||||
entry.mode,
|
||||
index_worktree_cache,
|
||||
repo,
|
||||
));
|
||||
}
|
||||
Item::Modification {
|
||||
rela_path,
|
||||
entry,
|
||||
status: EntryStatus::IntentToAdd,
|
||||
..
|
||||
} => {
|
||||
diff.added += count_lines(
|
||||
rela_path.as_bstr(),
|
||||
repo.object_hash().null(),
|
||||
entry.mode,
|
||||
index_worktree_cache,
|
||||
repo,
|
||||
);
|
||||
}
|
||||
Item::Rewrite { .. } => {
|
||||
unreachable!("not activated")
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
};
|
||||
diff
|
||||
},
|
||||
)
|
||||
.reduce(Diff::default, |a, b| Diff {
|
||||
added: a.added + b.added,
|
||||
deleted: a.deleted + b.deleted,
|
||||
});
|
||||
|
||||
GitDiff {
|
||||
added: diff.added.to_string(),
|
||||
deleted: diff.deleted.to_string(),
|
||||
}
|
||||
};
|
||||
|
||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||
formatter
|
||||
@@ -37,8 +254,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
_ => None,
|
||||
})
|
||||
.map(|variable| match variable {
|
||||
"added" => GitDiff::get_variable(config.only_nonzero_diffs, stats.added),
|
||||
"deleted" => GitDiff::get_variable(config.only_nonzero_diffs, stats.deleted),
|
||||
"added" => GitDiff::get_variable(config.only_nonzero_diffs, &stats.added),
|
||||
"deleted" => GitDiff::get_variable(config.only_nonzero_diffs, &stats.deleted),
|
||||
_ => None,
|
||||
})
|
||||
.parse(None, Some(context))
|
||||
@@ -55,16 +272,95 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
Some(module)
|
||||
}
|
||||
|
||||
/// Represents the parsed output from a git diff.
|
||||
struct GitDiff<'a> {
|
||||
added: &'a str,
|
||||
deleted: &'a str,
|
||||
fn prevent_external_diff(mut cache: gix::diff::blob::Platform) -> gix::diff::blob::Platform {
|
||||
cache.options.skip_internal_diff_if_external_is_configured = false;
|
||||
cache
|
||||
}
|
||||
|
||||
impl<'a> GitDiff<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn diff_two_opt(
|
||||
lhs_location: &BStr,
|
||||
lhs_id: gix::ObjectId,
|
||||
lhs_kind: gix::index::entry::Mode,
|
||||
rhs_location: &BStr,
|
||||
rhs_id: gix::ObjectId,
|
||||
rhs_kind: gix::index::entry::Mode,
|
||||
cache: &mut gix::diff::blob::Platform,
|
||||
find: &impl gix::objs::FindObjectOrHeader,
|
||||
) -> Option<gix::diff::blob::sink::Counter<()>> {
|
||||
cache
|
||||
.set_resource(
|
||||
lhs_id,
|
||||
lhs_kind.to_tree_entry_mode()?.kind(),
|
||||
lhs_location,
|
||||
ResourceKind::OldOrSource,
|
||||
find,
|
||||
)
|
||||
.ok()?;
|
||||
cache
|
||||
.set_resource(
|
||||
rhs_id,
|
||||
rhs_kind.to_tree_entry_mode()?.kind(),
|
||||
rhs_location,
|
||||
ResourceKind::NewOrDestination,
|
||||
find,
|
||||
)
|
||||
.ok()?;
|
||||
count_diff_lines(cache.prepare_diff().ok()?)
|
||||
}
|
||||
|
||||
fn count_lines(
|
||||
location: &BStr,
|
||||
id: gix::ObjectId,
|
||||
kind: gix::index::entry::Mode,
|
||||
cache: &mut gix::diff::blob::Platform,
|
||||
find: &impl gix::objs::FindObjectOrHeader,
|
||||
) -> usize {
|
||||
diff_two_opt(
|
||||
location,
|
||||
id.kind().null(),
|
||||
kind,
|
||||
location,
|
||||
id,
|
||||
kind,
|
||||
cache,
|
||||
find,
|
||||
)
|
||||
.map_or(0, |diff| diff.insertions as usize)
|
||||
}
|
||||
|
||||
fn count_diff_lines(
|
||||
prep: gix::diff::blob::platform::prepare_diff::Outcome<'_>,
|
||||
) -> Option<gix::diff::blob::sink::Counter<()>> {
|
||||
use gix::diff::blob::platform::prepare_diff::Operation;
|
||||
match prep.operation {
|
||||
Operation::InternalDiff { algorithm } => {
|
||||
let tokens = prep.interned_input();
|
||||
let counter = gix::diff::blob::diff(
|
||||
algorithm,
|
||||
&tokens,
|
||||
gix::diff::blob::sink::Counter::default(),
|
||||
);
|
||||
Some(counter)
|
||||
}
|
||||
Operation::ExternalCommand { .. } => {
|
||||
unreachable!("we disabled that")
|
||||
}
|
||||
Operation::SourceOrDestinationIsBinary => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the parsed output from a git diff.
|
||||
#[derive(Default)]
|
||||
struct GitDiff {
|
||||
added: String,
|
||||
deleted: String,
|
||||
}
|
||||
|
||||
impl GitDiff {
|
||||
/// Returns the first capture group given a regular expression and a string.
|
||||
/// If it fails to get the capture group it will return "0".
|
||||
fn get_matched_str(diff: &'a str, re: &Regex) -> &'a str {
|
||||
fn get_matched_str<'a>(diff: &'a str, re: &Regex) -> &'a str {
|
||||
match re.captures(diff) {
|
||||
Some(caps) => caps.get(1).unwrap().as_str(),
|
||||
_ => "0",
|
||||
@@ -72,13 +368,13 @@ impl<'a> GitDiff<'a> {
|
||||
}
|
||||
|
||||
/// Parses the result of 'git diff --shortstat' as a `GitDiff` struct.
|
||||
pub fn parse(diff: &'a str) -> Self {
|
||||
pub fn parse(diff: &str) -> Self {
|
||||
let added_re = Regex::new(r"(\d+) \w+\(\+\)").unwrap();
|
||||
let deleted_re = Regex::new(r"(\d+) \w+\(\-\)").unwrap();
|
||||
|
||||
Self {
|
||||
added: GitDiff::get_matched_str(diff, &added_re),
|
||||
deleted: GitDiff::get_matched_str(diff, &deleted_re),
|
||||
added: GitDiff::get_matched_str(diff, &added_re).to_owned(),
|
||||
deleted: GitDiff::get_matched_str(diff, &deleted_re).to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,10 +401,10 @@ mod tests {
|
||||
use std::path::Path;
|
||||
use std::process::Stdio;
|
||||
|
||||
use crate::modules::git_status::tests::make_sparse;
|
||||
use crate::test::{FixtureProvider, ModuleRenderer, fixture_repo};
|
||||
use nu_ansi_term::Color;
|
||||
|
||||
use crate::test::ModuleRenderer;
|
||||
|
||||
#[test]
|
||||
fn shows_nothing_on_empty_dir() -> io::Result<()> {
|
||||
let repo_dir = tempfile::tempdir()?;
|
||||
@@ -140,6 +436,78 @@ mod tests {
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_staged_addition() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
std::fs::write(path.join("new-file"), "new line")?;
|
||||
run_git_cmd(["add", "new-file"], Some(path), true)?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = Some(format!("{} ", Color::Green.bold().paint("+1"),));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_staged_rename_modification() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
let the_file = path.join("the_file");
|
||||
let mut the_file = OpenOptions::new().append(true).open(the_file)?;
|
||||
writeln!(the_file, "Added line")?;
|
||||
the_file.sync_all()?;
|
||||
run_git_cmd(["add", "the_file"], Some(path), true)?;
|
||||
run_git_cmd(["mv", "the_file", "that_file"], Some(path), true)?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = Some(format!("{} ", Color::Green.bold().paint("+1"),));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_staged_addition_intended() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
std::fs::write(path.join("new-file"), "new line")?;
|
||||
run_git_cmd(["add", "-N", "new-file"], Some(path), true)?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = Some(format!("{} ", Color::Green.bold().paint("+1"),));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_staged_modification() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
std::fs::write(path.join("the_file"), "modify all")?;
|
||||
run_git_cmd(["add", "the_file"], Some(path), true)?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = Some(format!(
|
||||
"{} {} ",
|
||||
Color::Green.bold().paint("+1"),
|
||||
Color::Red.bold().paint("-3")
|
||||
));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_deleted_lines() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
@@ -156,6 +524,36 @@ mod tests {
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_deleted_lines_of_entire_file() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
std::fs::remove_file(path.join("the_file"))?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = Some(format!("{} ", Color::Red.bold().paint("-3")));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_staged_deletion() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
run_git_cmd(["rm", "the_file"], Some(path), true)?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = Some(format!("{} ", Color::Red.bold().paint("-3")));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_all_changes() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
@@ -188,6 +586,32 @@ mod tests {
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_nothing_on_untracked() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
std::fs::write(path.join("untracked"), "a line")?;
|
||||
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = None;
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_nothing_if_no_changes_sparse() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
let path = repo_dir.path();
|
||||
|
||||
make_sparse(path)?;
|
||||
let actual = render_metrics(path);
|
||||
|
||||
let expected = None;
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_all_if_only_nonzero_diffs_is_false() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
@@ -202,21 +626,27 @@ mod tests {
|
||||
.config(toml::toml! {
|
||||
[git_metrics]
|
||||
disabled = false
|
||||
only_nonzero_diffs = false
|
||||
only_nonzero_diffs = true
|
||||
})
|
||||
.path(path)
|
||||
.collect();
|
||||
|
||||
let expected = Some(format!(
|
||||
"{} {} ",
|
||||
Color::Green.bold().paint("+1"),
|
||||
Color::Red.bold().paint("-0")
|
||||
));
|
||||
let expected = Some(format!("{} ", Color::Green.bold().paint("+1"),));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doesnt_generate_git_metrics_for_bare_repo() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::GitBare)?;
|
||||
|
||||
let actual = render_metrics(repo_dir.path());
|
||||
assert_eq!(None, actual);
|
||||
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_all_changes_with_ignored_submodules() -> io::Result<()> {
|
||||
let repo_dir = create_repo_with_commit()?;
|
||||
|
||||
+382
-53
@@ -1,13 +1,14 @@
|
||||
use regex::Regex;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use super::{Context, Module, ModuleConfig};
|
||||
|
||||
use crate::configs::git_status::GitStatusConfig;
|
||||
use crate::context;
|
||||
use crate::formatter::StringFormatter;
|
||||
use crate::segment::Segment;
|
||||
use std::sync::Arc;
|
||||
use crate::{context, num_configured_starship_threads, num_rayon_threads};
|
||||
use gix::bstr::ByteVec;
|
||||
use gix::status::Submodule;
|
||||
use regex::Regex;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
const ALL_STATUS_FORMAT: &str =
|
||||
"$conflicted$stashed$deleted$renamed$modified$typechanged$staged$untracked";
|
||||
@@ -47,7 +48,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
return Some(module);
|
||||
}
|
||||
|
||||
let info = Arc::new(GitStatusInfo::load(context, repo, config.clone()));
|
||||
let info = GitStatusInfo::load(context, repo, config.clone());
|
||||
|
||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||
formatter
|
||||
@@ -60,7 +61,6 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
_ => None,
|
||||
})
|
||||
.map_variables_to_segments(|variable: &str| {
|
||||
let info = Arc::clone(&info);
|
||||
let segments = match variable {
|
||||
"stashed" => info.get_stashed().and_then(|count| {
|
||||
format_count(config.stashed, "git_status.stashed", context, count)
|
||||
@@ -135,7 +135,7 @@ struct GitStatusInfo<'a> {
|
||||
context: &'a Context<'a>,
|
||||
repo: &'a context::Repo,
|
||||
config: GitStatusConfig<'a>,
|
||||
repo_status: OnceLock<Option<RepoStatus>>,
|
||||
repo_status: OnceLock<Option<Arc<RepoStatus>>>,
|
||||
stashed_count: OnceLock<Option<usize>>,
|
||||
}
|
||||
|
||||
@@ -158,16 +158,19 @@ impl<'a> GitStatusInfo<'a> {
|
||||
self.get_repo_status().map(|data| (data.ahead, data.behind))
|
||||
}
|
||||
|
||||
pub fn get_repo_status(&self) -> &Option<RepoStatus> {
|
||||
self.repo_status.get_or_init(|| {
|
||||
match get_repo_status(self.context, self.repo, &self.config) {
|
||||
Some(repo_status) => Some(repo_status),
|
||||
None => {
|
||||
log::debug!("get_repo_status: git status execution failed");
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
pub fn get_repo_status(&self) -> Option<&RepoStatus> {
|
||||
self.repo_status
|
||||
.get_or_init(
|
||||
|| match get_static_repo_status(self.context, self.repo, &self.config) {
|
||||
Some(repo_status) => Some(repo_status),
|
||||
None => {
|
||||
log::debug!("get_repo_status: git status execution failed");
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.as_ref()
|
||||
.map(|repo_status| repo_status.as_ref())
|
||||
}
|
||||
|
||||
pub fn get_stashed(&self) -> &Option<usize> {
|
||||
@@ -210,6 +213,29 @@ impl<'a> GitStatusInfo<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a globally shared version the repository status so it can be reused.
|
||||
/// It's shared so those who received a copy can keep it, even if the next call uses a different
|
||||
/// path so the cache is trashed.
|
||||
///
|
||||
/// The trashing is only expected when tests run though, as otherwise one path is used with a variety of modules.
|
||||
pub(crate) fn get_static_repo_status(
|
||||
context: &Context,
|
||||
repo: &context::Repo,
|
||||
config: &GitStatusConfig,
|
||||
) -> Option<Arc<RepoStatus>> {
|
||||
static REPO_STATUS: parking_lot::Mutex<Option<(Arc<RepoStatus>, PathBuf)>> =
|
||||
parking_lot::Mutex::new(None);
|
||||
let mut status = REPO_STATUS.lock();
|
||||
let needs_update = status
|
||||
.as_ref()
|
||||
.is_none_or(|(_status, status_path)| status_path != &context.current_dir);
|
||||
if needs_update {
|
||||
*status = get_repo_status(context, repo, config)
|
||||
.map(|status| (Arc::new(status), context.current_dir.clone()));
|
||||
}
|
||||
status.as_ref().map(|(status, _)| Arc::clone(status))
|
||||
}
|
||||
|
||||
/// Gets the number of files in various git states (staged, modified, deleted, etc...)
|
||||
fn get_repo_status(
|
||||
context: &Context,
|
||||
@@ -219,40 +245,226 @@ fn get_repo_status(
|
||||
log::debug!("New repo status created");
|
||||
|
||||
let mut repo_status = RepoStatus::default();
|
||||
let mut args = vec!["status", "--porcelain=2"];
|
||||
|
||||
// for performance reasons, only pass flags if necessary...
|
||||
let has_ahead_behind = !config.ahead.is_empty() || !config.behind.is_empty();
|
||||
let has_up_to_date_diverged = !config.up_to_date.is_empty() || !config.diverged.is_empty();
|
||||
if has_ahead_behind || has_up_to_date_diverged {
|
||||
args.push("--branch");
|
||||
}
|
||||
|
||||
// ... and add flags that omit information the user doesn't want
|
||||
let gix_repo = repo.open();
|
||||
// TODO: remove this special case once `gitoxide` can handle sparse indices for tree-index comparisons.
|
||||
let has_untracked = !config.untracked.is_empty();
|
||||
if !has_untracked {
|
||||
args.push("--untracked-files=no");
|
||||
}
|
||||
if config.ignore_submodules {
|
||||
args.push("--ignore-submodules=dirty");
|
||||
} else if !has_untracked {
|
||||
args.push("--ignore-submodules=untracked");
|
||||
}
|
||||
let git_config = gix_repo.config_snapshot();
|
||||
if config.use_git_executable
|
||||
|| gix_repo.index_or_empty().ok()?.is_sparse()
|
||||
|| repo.fs_monitor_value_is_true
|
||||
{
|
||||
let mut args = vec!["status", "--porcelain=2"];
|
||||
|
||||
let status_output = repo.exec_git(context, &args)?;
|
||||
let statuses = status_output.stdout.lines();
|
||||
|
||||
statuses.for_each(|status| {
|
||||
if status.starts_with("# branch.ab ") {
|
||||
repo_status.set_ahead_behind(status);
|
||||
} else if !status.starts_with('#') {
|
||||
repo_status.add(status);
|
||||
// for performance reasons, only pass flags if necessary...
|
||||
let has_ahead_behind = !config.ahead.is_empty() || !config.behind.is_empty();
|
||||
let has_up_to_date_diverged = !config.up_to_date.is_empty() || !config.diverged.is_empty();
|
||||
if has_ahead_behind || has_up_to_date_diverged {
|
||||
args.push("--branch");
|
||||
}
|
||||
});
|
||||
|
||||
// ... and add flags that omit information the user doesn't want
|
||||
if !has_untracked {
|
||||
args.push("--untracked-files=no");
|
||||
}
|
||||
if config.ignore_submodules {
|
||||
args.push("--ignore-submodules=dirty");
|
||||
} else if !has_untracked {
|
||||
args.push("--ignore-submodules=untracked");
|
||||
}
|
||||
|
||||
let status_output = repo.exec_git(context, &args)?;
|
||||
let statuses = status_output.stdout.lines();
|
||||
|
||||
statuses.for_each(|status| {
|
||||
if status.starts_with("# branch.ab ") {
|
||||
repo_status.set_ahead_behind(status);
|
||||
} else if !status.starts_with('#') {
|
||||
repo_status.add(status);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let is_interrupted = Arc::new(AtomicBool::new(false));
|
||||
std::thread::Builder::new()
|
||||
.name("starship timer".into())
|
||||
.stack_size(256 * 1024)
|
||||
.spawn({
|
||||
let is_interrupted = is_interrupted.clone();
|
||||
let abort_after =
|
||||
std::time::Duration::from_millis(context.root_config.command_timeout);
|
||||
move || {
|
||||
std::thread::sleep(abort_after);
|
||||
is_interrupted.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
})
|
||||
.expect("should be able to spawn timer thread");
|
||||
// We don't show details in submodules.
|
||||
let check_dirty = true;
|
||||
let status = gix_repo
|
||||
.status(gix::features::progress::Discard)
|
||||
.ok()?
|
||||
.index_worktree_submodules(if config.ignore_submodules {
|
||||
Submodule::Given {
|
||||
ignore: gix::submodule::config::Ignore::Dirty,
|
||||
check_dirty,
|
||||
}
|
||||
} else if !has_untracked {
|
||||
Submodule::Given {
|
||||
ignore: gix::submodule::config::Ignore::Untracked,
|
||||
check_dirty,
|
||||
}
|
||||
} else {
|
||||
Submodule::AsConfigured { check_dirty }
|
||||
})
|
||||
.index_worktree_options_mut(|opts| {
|
||||
opts.thread_limit = if cfg!(target_os = "macos") {
|
||||
Some(num_configured_starship_threads().unwrap_or(
|
||||
// TODO: figure out good defaults for other platforms, maybe make it configurable.
|
||||
// Git uses everything (if repo-size permits), but that's not the best choice for MacOS.
|
||||
3,
|
||||
))
|
||||
} else {
|
||||
Some(num_rayon_threads())
|
||||
};
|
||||
if config.untracked.is_empty() {
|
||||
opts.dirwalk_options.take();
|
||||
} else if let Some(opts) = opts.dirwalk_options.as_mut() {
|
||||
opts.set_emit_untracked(gix::dir::walk::EmissionMode::Matching)
|
||||
.set_emit_ignored(None)
|
||||
.set_emit_pruned(false)
|
||||
.set_emit_empty_directories(false);
|
||||
}
|
||||
})
|
||||
.tree_index_track_renames(if config.renamed.is_empty() {
|
||||
gix::status::tree_index::TrackRenames::Disabled
|
||||
} else {
|
||||
gix::status::tree_index::TrackRenames::Given(sanitize_rename_tracking(
|
||||
// Get configured diff-rename configuration, or use default settings.
|
||||
gix::diff::new_rewrites(&git_config, true)
|
||||
.unwrap_or_default()
|
||||
.0
|
||||
.unwrap_or_default(),
|
||||
))
|
||||
})
|
||||
.should_interrupt_owned(is_interrupted.clone());
|
||||
|
||||
// This will start the status machinery, collecting status items in the background.
|
||||
// Thus, we can do some work in this thread without blocking, before starting to count status items.
|
||||
let status = status.into_iter(None).ok()?;
|
||||
|
||||
// for performance reasons, only pass flags if necessary...
|
||||
let has_ahead_behind = !config.ahead.is_empty() || !config.behind.is_empty();
|
||||
let has_up_to_date_or_diverged =
|
||||
!config.up_to_date.is_empty() || !config.diverged.is_empty();
|
||||
if has_ahead_behind || has_up_to_date_or_diverged {
|
||||
if let Some(branch_name) = gix_repo.head_name().ok().flatten().and_then(|ref_name| {
|
||||
Vec::from(gix::bstr::BString::from(ref_name))
|
||||
.into_string()
|
||||
.ok()
|
||||
}) {
|
||||
let output = repo.exec_git(
|
||||
context,
|
||||
["for-each-ref", "--format", "%(upstream:track)"]
|
||||
.into_iter()
|
||||
.map(ToOwned::to_owned)
|
||||
.chain(Some(branch_name)),
|
||||
)?;
|
||||
if let Some(line) = output.stdout.lines().next() {
|
||||
repo_status.set_ahead_behind_for_each_ref(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for change in status.filter_map(Result::ok) {
|
||||
use gix::status;
|
||||
match &change {
|
||||
status::Item::TreeIndex(change) => {
|
||||
use gix::diff::index::Change;
|
||||
match change {
|
||||
Change::Addition { .. } => {
|
||||
repo_status.staged += 1;
|
||||
}
|
||||
Change::Deletion { .. } => {
|
||||
repo_status.deleted += 1;
|
||||
}
|
||||
Change::Modification { .. } => {
|
||||
repo_status.staged += 1;
|
||||
}
|
||||
Change::Rewrite { .. } => {
|
||||
repo_status.renamed += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
status::Item::IndexWorktree(change) => {
|
||||
use gix::status::index_worktree::Item;
|
||||
use gix::status::plumbing::index_as_worktree::{Change, EntryStatus};
|
||||
match change {
|
||||
Item::Modification {
|
||||
status: EntryStatus::Conflict(_),
|
||||
..
|
||||
} => {
|
||||
repo_status.conflicted += 1;
|
||||
}
|
||||
Item::Modification {
|
||||
status: EntryStatus::Change(Change::Removed),
|
||||
..
|
||||
} => {
|
||||
repo_status.deleted += 1;
|
||||
}
|
||||
Item::Modification {
|
||||
status:
|
||||
EntryStatus::IntentToAdd
|
||||
| EntryStatus::Change(
|
||||
Change::Modification { .. } | Change::SubmoduleModification(_),
|
||||
),
|
||||
..
|
||||
} => {
|
||||
repo_status.modified += 1;
|
||||
}
|
||||
Item::Modification {
|
||||
status: EntryStatus::Change(Change::Type { .. }),
|
||||
..
|
||||
} => {
|
||||
repo_status.typechanged += 1;
|
||||
}
|
||||
Item::DirectoryContents {
|
||||
entry:
|
||||
gix::dir::Entry {
|
||||
status: gix::dir::entry::Status::Untracked,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
repo_status.untracked += 1;
|
||||
}
|
||||
Item::Rewrite { .. } => {
|
||||
unreachable!(
|
||||
"this kind of rename tracking isn't enabled by default and specific to gitoxide"
|
||||
)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Keep it for potential reuse by `git_metrics`
|
||||
repo_status.changes.push(change);
|
||||
}
|
||||
if is_interrupted.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
repo_status = RepoStatus {
|
||||
ahead: repo_status.ahead,
|
||||
behind: repo_status.behind,
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Some(repo_status)
|
||||
}
|
||||
|
||||
fn sanitize_rename_tracking(mut config: gix::diff::Rewrites) -> gix::diff::Rewrites {
|
||||
config.limit = 100;
|
||||
config
|
||||
}
|
||||
|
||||
fn get_stashed_count(repo: &context::Repo) -> Option<usize> {
|
||||
let repo = repo.open();
|
||||
let reference = match repo.try_find_reference("refs/stash") {
|
||||
@@ -279,10 +491,11 @@ fn get_stashed_count(repo: &context::Repo) -> Option<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
struct RepoStatus {
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub(crate) struct RepoStatus {
|
||||
ahead: Option<usize>,
|
||||
behind: Option<usize>,
|
||||
pub(crate) changes: Vec<gix::status::Item>,
|
||||
conflicted: usize,
|
||||
deleted: usize,
|
||||
renamed: usize,
|
||||
@@ -355,6 +568,27 @@ impl RepoStatus {
|
||||
self.behind = caps.get(2).unwrap().as_str().parse::<usize>().ok();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ahead_behind_for_each_ref(&mut self, mut s: &str) {
|
||||
s = s.trim_matches(|c| c == '[' || c == ']');
|
||||
|
||||
for pair in s.split(',') {
|
||||
let mut tokens = pair.trim().splitn(2, ' ');
|
||||
if let (Some(name), Some(number)) = (tokens.next(), tokens.next()) {
|
||||
let storage = match name {
|
||||
"ahead" => &mut self.ahead,
|
||||
"behind" => &mut self.behind,
|
||||
_ => return,
|
||||
};
|
||||
*storage = number.parse().ok();
|
||||
}
|
||||
}
|
||||
for field in [&mut self.ahead, &mut self.behind] {
|
||||
if field.is_none() {
|
||||
*field = Some(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_text<F>(
|
||||
@@ -514,16 +748,15 @@ fn git_status_wsl(_context: &Context, _conf: &GitStatusConfig) -> Option<String>
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
pub(crate) mod tests {
|
||||
use crate::test::{FixtureProvider, ModuleRenderer, fixture_repo};
|
||||
use crate::utils::create_command;
|
||||
use nu_ansi_term::{AnsiStrings, Color};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, prelude::*};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::test::{FixtureProvider, ModuleRenderer, fixture_repo};
|
||||
use crate::utils::create_command;
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn format_output(symbols: &str) -> Option<String> {
|
||||
Some(format!(
|
||||
@@ -880,6 +1113,21 @@ mod tests {
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_typechanged_in_index() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
|
||||
create_typechanged_in_index(repo_dir.path())?;
|
||||
|
||||
let actual = ModuleRenderer::new("git_status")
|
||||
.path(repo_dir.path())
|
||||
.collect();
|
||||
let expected = format_output("+");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_modified() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
@@ -914,6 +1162,27 @@ mod tests {
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_modified_with_count_sparse() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
|
||||
make_sparse(repo_dir.path())?;
|
||||
create_modified(repo_dir.path())?;
|
||||
|
||||
let actual = ModuleRenderer::new("git_status")
|
||||
.config(toml::toml! {
|
||||
[git_status]
|
||||
modified = "!$count"
|
||||
ahead = ""
|
||||
})
|
||||
.path(repo_dir.path())
|
||||
.collect();
|
||||
let expected = format_output("!1");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_added() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
@@ -1075,6 +1344,21 @@ mod tests {
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_deleted_file_in_index() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
|
||||
create_deleted_in_index(repo_dir.path())?;
|
||||
|
||||
let actual = ModuleRenderer::new("git_status")
|
||||
.path(repo_dir.path())
|
||||
.collect();
|
||||
let expected = format_output("✘");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
repo_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shows_deleted_file_with_count() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
@@ -1139,7 +1423,6 @@ mod tests {
|
||||
// but as untracked instead. The following test checks if manually deleted and manually renamed
|
||||
// files are tracked by git_status module in the same way 'git status' does.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn ignore_manually_renamed() -> io::Result<()> {
|
||||
let repo_dir = fixture_repo(FixtureProvider::Git)?;
|
||||
File::create(repo_dir.path().join("a"))?.sync_all()?;
|
||||
@@ -1239,6 +1522,16 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_typechanged_in_index(repo_dir: &Path) -> io::Result<()> {
|
||||
create_typechanged(repo_dir)?;
|
||||
|
||||
create_command("git")?
|
||||
.args(["add", "readme.md"])
|
||||
.current_dir(repo_dir)
|
||||
.output()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_staged_typechange(repo_dir: &Path) -> io::Result<()> {
|
||||
create_typechanged(repo_dir)?;
|
||||
|
||||
@@ -1320,6 +1613,33 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn make_sparse(repo_dir: &Path) -> io::Result<()> {
|
||||
let sparse_dirname = "sparse-dir";
|
||||
let dir = repo_dir.join(sparse_dirname);
|
||||
std::fs::create_dir(&dir)?;
|
||||
File::create(dir.join("still-visible"))?.sync_all()?;
|
||||
let subdir = dir.join("not-checked-out");
|
||||
std::fs::create_dir(&subdir)?;
|
||||
File::create(subdir.join("invisible"))?.sync_all()?;
|
||||
|
||||
create_command("git")?
|
||||
.args(["add", "sparse-dir"])
|
||||
.current_dir(repo_dir)
|
||||
.output()?;
|
||||
|
||||
create_command("git")?
|
||||
.args(["commit", "-m", "add new directory", "--no-gpg-sign"])
|
||||
.current_dir(repo_dir)
|
||||
.output()?;
|
||||
|
||||
create_command("git")?
|
||||
.args(["sparse-checkout", "set", sparse_dirname, "--sparse-index"])
|
||||
.current_dir(repo_dir)
|
||||
.output()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_staged(repo_dir: &Path) -> io::Result<()> {
|
||||
File::create(repo_dir.join("license"))?.sync_all()?;
|
||||
|
||||
@@ -1384,6 +1704,15 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_deleted_in_index(repo_dir: &Path) -> io::Result<()> {
|
||||
create_command("git")?
|
||||
.args(["rm", "readme.md"])
|
||||
.current_dir(repo_dir)
|
||||
.output()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_staged_and_ignored(repo_dir: &Path) -> io::Result<()> {
|
||||
let mut file = File::create(repo_dir.join(".gitignore"))?;
|
||||
writeln!(&mut file, "ignored.txt")?;
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ mod git_branch;
|
||||
mod git_commit;
|
||||
mod git_metrics;
|
||||
mod git_state;
|
||||
mod git_status;
|
||||
pub(crate) mod git_status;
|
||||
mod gleam;
|
||||
mod golang;
|
||||
mod gradle;
|
||||
|
||||
+7
-6
@@ -246,12 +246,13 @@ pub fn fixture_repo(provider: FixtureProvider) -> io::Result<TempDir> {
|
||||
}
|
||||
FixtureProvider::GitBare => {
|
||||
let path = tempfile::tempdir()?;
|
||||
gix::ThreadSafeRepository::init(
|
||||
&path,
|
||||
gix::create::Kind::Bare,
|
||||
gix::create::Options::default(),
|
||||
)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
|
||||
|
||||
create_command("git")?
|
||||
.current_dir(path.path())
|
||||
.args(["clone", "-b", "master", "--bare"])
|
||||
.arg(GIT_FIXTURE.as_os_str())
|
||||
.arg(path.path())
|
||||
.output()?;
|
||||
Ok(path)
|
||||
}
|
||||
FixtureProvider::Hg => {
|
||||
|
||||
@@ -9,5 +9,6 @@ afe = "afe"
|
||||
typ = "typ"
|
||||
extentions = "extentions" # TODO: should be extensions
|
||||
worl = "worl" # typo on purpose
|
||||
rela = "rela"
|
||||
[files]
|
||||
extend-exclude = ["CHANGELOG.md", "docs/*"]
|
||||
|
||||
Reference in New Issue
Block a user