Skip to content

Commit 3cd218d

Browse files
author
Stephan Dilly
authored
honor showUntrackedFiles config (#753)
1 parent eb28ba1 commit 3cd218d

File tree

12 files changed

+214
-100
lines changed

12 files changed

+214
-100
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
## Added
11+
- honor `config.showUntrackedFiles` improving speed with a lot of untracked items ([#752](https://github.com/extrawurst/gitui/issues/752))
12+
1013
## Fixed
1114
- wrong file with same name shown in file tree ([#748](https://github.com/extrawurst/gitui/issues/748))
1215

asyncgit/src/status.rs

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,14 @@ pub struct Status {
3131
pub struct StatusParams {
3232
tick: u128,
3333
status_type: StatusType,
34-
include_untracked: bool,
3534
}
3635

3736
impl StatusParams {
3837
///
39-
pub fn new(
40-
status_type: StatusType,
41-
include_untracked: bool,
42-
) -> Self {
38+
pub fn new(status_type: StatusType) -> Self {
4339
Self {
4440
tick: current_tick(),
4541
status_type,
46-
include_untracked,
4742
}
4843
}
4944
}
@@ -93,10 +88,9 @@ impl AsyncStatus {
9388
let hash_request = hash(&params);
9489

9590
log::trace!(
96-
"request: [hash: {}] (type: {:?}, untracked: {})",
91+
"request: [hash: {}] (type: {:?})",
9792
hash_request,
9893
params.status_type,
99-
params.include_untracked,
10094
);
10195

10296
{
@@ -115,14 +109,12 @@ impl AsyncStatus {
115109
let sender = self.sender.clone();
116110
let arc_pending = Arc::clone(&self.pending);
117111
let status_type = params.status_type;
118-
let include_untracked = params.include_untracked;
119112

120113
self.pending.fetch_add(1, Ordering::Relaxed);
121114

122115
rayon_core::spawn(move || {
123116
let ok = Self::fetch_helper(
124117
status_type,
125-
include_untracked,
126118
hash_request,
127119
&arc_current,
128120
&arc_last,
@@ -143,17 +135,15 @@ impl AsyncStatus {
143135

144136
fn fetch_helper(
145137
status_type: StatusType,
146-
include_untracked: bool,
147138
hash_request: u64,
148139
arc_current: &Arc<Mutex<Request<u64, Status>>>,
149140
arc_last: &Arc<Mutex<Status>>,
150141
) -> Result<()> {
151-
let res = Self::get_status(status_type, include_untracked)?;
142+
let res = Self::get_status(status_type)?;
152143
log::trace!(
153-
"status fetched: {} (type: {:?}, untracked: {})",
144+
"status fetched: {} (type: {:?})",
154145
hash_request,
155146
status_type,
156-
include_untracked
157147
);
158148

159149
{
@@ -171,16 +161,9 @@ impl AsyncStatus {
171161
Ok(())
172162
}
173163

174-
fn get_status(
175-
status_type: StatusType,
176-
include_untracked: bool,
177-
) -> Result<Status> {
164+
fn get_status(status_type: StatusType) -> Result<Status> {
178165
Ok(Status {
179-
items: sync::status::get_status(
180-
CWD,
181-
status_type,
182-
include_untracked,
183-
)?,
166+
items: sync::status::get_status(CWD, status_type)?,
184167
})
185168
}
186169
}

asyncgit/src/sync/config.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use super::utils::repo;
2+
use crate::error::Result;
3+
use git2::Repository;
4+
use scopetime::scope_time;
5+
6+
// see https://git-scm.com/docs/git-config#Documentation/git-config.txt-statusshowUntrackedFiles
7+
/// represents the `status.showUntrackedFiles` git config state
8+
pub enum ShowUntrackedFilesConfig {
9+
///
10+
No,
11+
///
12+
Normal,
13+
///
14+
All,
15+
}
16+
17+
impl ShowUntrackedFilesConfig {
18+
///
19+
pub const fn include_none(&self) -> bool {
20+
matches!(self, Self::No)
21+
}
22+
23+
///
24+
pub const fn include_untracked(&self) -> bool {
25+
matches!(self, Self::Normal | Self::All)
26+
}
27+
28+
///
29+
pub const fn recurse_untracked_dirs(&self) -> bool {
30+
matches!(self, Self::All)
31+
}
32+
}
33+
34+
pub fn untracked_files_config_repo(
35+
repo: &Repository,
36+
) -> Result<ShowUntrackedFilesConfig> {
37+
let show_untracked_files =
38+
get_config_string_repo(repo, "status.showUntrackedFiles")?;
39+
40+
if let Some(show_untracked_files) = show_untracked_files {
41+
if &show_untracked_files == "no" {
42+
return Ok(ShowUntrackedFilesConfig::No);
43+
} else if &show_untracked_files == "normal" {
44+
return Ok(ShowUntrackedFilesConfig::Normal);
45+
}
46+
}
47+
48+
Ok(ShowUntrackedFilesConfig::All)
49+
}
50+
51+
///
52+
pub fn untracked_files_config(
53+
repo_path: &str,
54+
) -> Result<ShowUntrackedFilesConfig> {
55+
let repo = repo(repo_path)?;
56+
untracked_files_config_repo(&repo)
57+
}
58+
59+
/// get string from config
60+
pub fn get_config_string(
61+
repo_path: &str,
62+
key: &str,
63+
) -> Result<Option<String>> {
64+
let repo = repo(repo_path)?;
65+
get_config_string_repo(&repo, key)
66+
}
67+
68+
pub fn get_config_string_repo(
69+
repo: &Repository,
70+
key: &str,
71+
) -> Result<Option<String>> {
72+
scope_time!("get_config_string_repo");
73+
74+
let cfg = repo.config()?;
75+
76+
// this code doesnt match what the doc says regarding what
77+
// gets returned when but it actually works
78+
let entry_res = cfg.get_entry(key);
79+
80+
let entry = match entry_res {
81+
Ok(ent) => ent,
82+
Err(_) => return Ok(None),
83+
};
84+
85+
if entry.has_value() {
86+
Ok(entry.value().map(std::string::ToString::to_string))
87+
} else {
88+
Ok(None)
89+
}
90+
}
91+
92+
#[cfg(test)]
93+
mod tests {
94+
use super::*;
95+
use crate::sync::tests::repo_init;
96+
97+
#[test]
98+
fn test_get_config() {
99+
let bad_dir_cfg =
100+
get_config_string("oodly_noodly", "this.doesnt.exist");
101+
assert!(bad_dir_cfg.is_err());
102+
103+
let (_td, repo) = repo_init().unwrap();
104+
let path = repo.path();
105+
let rpath = path.as_os_str().to_str().unwrap();
106+
let bad_cfg = get_config_string(rpath, "this.doesnt.exist");
107+
assert!(bad_cfg.is_ok());
108+
assert!(bad_cfg.unwrap().is_none());
109+
// repo init sets user.name
110+
let good_cfg = get_config_string(rpath, "user.name");
111+
assert!(good_cfg.is_ok());
112+
assert!(good_cfg.unwrap().is_some());
113+
}
114+
}

asyncgit/src/sync/diff.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,8 @@ mod tests {
459459
.unwrap();
460460
}
461461

462-
let res = get_status(repo_path, StatusType::WorkingDir, true)
463-
.unwrap();
462+
let res =
463+
get_status(repo_path, StatusType::WorkingDir).unwrap();
464464
assert_eq!(res.len(), 1);
465465
assert_eq!(res[0].path, "bar.txt");
466466

asyncgit/src/sync/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod commit;
99
mod commit_details;
1010
mod commit_files;
1111
mod commits_info;
12+
mod config;
1213
pub mod cred;
1314
pub mod diff;
1415
mod hooks;
@@ -44,6 +45,10 @@ pub use commit_files::get_commit_files;
4445
pub use commits_info::{
4546
get_commit_info, get_commits_info, CommitId, CommitInfo,
4647
};
48+
pub use config::{
49+
get_config_string, untracked_files_config,
50+
ShowUntrackedFilesConfig,
51+
};
4752
pub use diff::get_diff_commit;
4853
pub use hooks::{
4954
hooks_commit_msg, hooks_post_commit, hooks_pre_commit, HookResult,
@@ -250,12 +255,10 @@ mod tests {
250255
/// helper returning amount of files with changes in the (wd,stage)
251256
pub fn get_statuses(repo_path: &str) -> (usize, usize) {
252257
(
253-
get_status(repo_path, StatusType::WorkingDir, true)
254-
.unwrap()
255-
.len(),
256-
get_status(repo_path, StatusType::Stage, true)
258+
get_status(repo_path, StatusType::WorkingDir)
257259
.unwrap()
258260
.len(),
261+
get_status(repo_path, StatusType::Stage).unwrap().len(),
259262
)
260263
}
261264

asyncgit/src/sync/reset.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ mod tests {
8888
let root = repo.path().parent().unwrap();
8989
let repo_path = root.as_os_str().to_str().unwrap();
9090

91-
let res = get_status(repo_path, StatusType::WorkingDir, true)
92-
.unwrap();
91+
let res =
92+
get_status(repo_path, StatusType::WorkingDir).unwrap();
9393
assert_eq!(res.len(), 0);
9494

9595
let file_path = root.join("bar.txt");

asyncgit/src/sync/status.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
//! sync git api for fetching a status
22
3-
use crate::{error::Error, error::Result, sync::utils};
3+
use crate::{
4+
error::Error,
5+
error::Result,
6+
sync::{config::untracked_files_config_repo, utils},
7+
};
48
use git2::{Delta, Status, StatusOptions, StatusShow};
59
use scopetime::scope_time;
610
use std::path::Path;
@@ -92,20 +96,24 @@ impl From<StatusType> for StatusShow {
9296
pub fn get_status(
9397
repo_path: &str,
9498
status_type: StatusType,
95-
include_untracked: bool,
9699
) -> Result<Vec<StatusItem>> {
97100
scope_time!("get_status");
98101

99102
let repo = utils::repo(repo_path)?;
100103

101-
let statuses = repo.statuses(Some(
102-
StatusOptions::default()
103-
.show(status_type.into())
104-
.update_index(true)
105-
.include_untracked(include_untracked)
106-
.renames_head_to_index(true)
107-
.recurse_untracked_dirs(true),
108-
))?;
104+
let show_untracked = untracked_files_config_repo(&repo)?;
105+
106+
let mut options = StatusOptions::default();
107+
options
108+
.show(status_type.into())
109+
.update_index(true)
110+
.include_untracked(show_untracked.include_untracked())
111+
.renames_head_to_index(true)
112+
.recurse_untracked_dirs(
113+
show_untracked.recurse_untracked_dirs(),
114+
);
115+
116+
let statuses = repo.statuses(Some(&mut options))?;
109117

110118
let mut res = Vec::with_capacity(statuses.len());
111119

0 commit comments

Comments
 (0)