summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarcnmx <arcnmx@users.noreply.github.com>2021-12-30 13:12:53 -0800
committerGitHub <noreply@github.com>2021-12-30 15:12:53 -0600
commita95332485b690c9147c3265f272898ce503ad643 (patch)
treee68a7535b1fa1d5db7c25c518ba10bd982fd116b
parent1c305c9de7c7e02e60496833107cbff3fbda98c3 (diff)
perf(git_status): tweak exec flags to omit unnecessary info (#3287)
* perf(git_status): tweak flags to omit extra info `git status` can be prohibitively slow on some repos, so allow the config to influence what flags are passed to git. For instance, if there is no configured symbol for untracked files, tell git to omit them from its output. This can easily result in a 2~10x speedup in many cases, but requires the user to opt-in to hiding information from the prompt. * docs(git_status): add ignore_submodules option
-rw-r--r--docs/config/README.md33
-rw-r--r--src/configs/git_status.rs2
-rw-r--r--src/modules/git_status.rs50
3 files changed, 53 insertions, 32 deletions
diff --git a/docs/config/README.md b/docs/config/README.md
index 1a08e8c78..6113747bf 100644
--- a/docs/config/README.md
+++ b/docs/config/README.md
@@ -1407,22 +1407,23 @@ current directory.
### 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` |
-| `style` | `"bold red"` | The style for the module. |
-| `disabled` | `false` | Disables the `git_status` module. |
+| 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` |
+| `style` | `"bold red"` | The style for the module. |
+| `ignore_submodules` | `false` | Ignore changes to submodules. |
+| `disabled` | `false` | Disables the `git_status` module. |
### Variables
diff --git a/src/configs/git_status.rs b/src/configs/git_status.rs
index 213ad2149..8a0140445 100644
--- a/src/configs/git_status.rs
+++ b/src/configs/git_status.rs
@@ -18,6 +18,7 @@ pub struct GitStatusConfig<'a> {
pub modified: &'a str,
pub staged: &'a str,
pub untracked: &'a str,
+ pub ignore_submodules: bool,
pub disabled: bool,
}
@@ -37,6 +38,7 @@ impl<'a> Default for GitStatusConfig<'a> {
modified: "!",
staged: "+",
untracked: "?",
+ ignore_submodules: false,
disabled: false,
}
}
diff --git a/src/modules/git_status.rs b/src/modules/git_status.rs
index 7a5f20abf..db02083f5 100644
--- a/src/modules/git_status.rs
+++ b/src/modules/git_status.rs
@@ -27,11 +27,11 @@ const ALL_STATUS_FORMAT: &str = "$conflicted$stashed$deleted$renamed$modified$st
/// - `»` — A renamed file has been added to the staging area
/// - `✘` — A file's deletion has been added to the staging area
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
- let info = Arc::new(GitStatusInfo::load(context));
-
let mut module = context.new_module("git_status");
let config: GitStatusConfig = GitStatusConfig::try_load(module.config);
+ let info = Arc::new(GitStatusInfo::load(context, config.clone()));
+
//Return None if not in git repository
context.get_repo().ok()?;
@@ -116,14 +116,16 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
struct GitStatusInfo<'a> {
context: &'a Context<'a>,
+ config: GitStatusConfig<'a>,
repo_status: OnceCell<Option<RepoStatus>>,
stashed_count: OnceCell<Option<usize>>,
}
impl<'a> GitStatusInfo<'a> {
- pub fn load(context: &'a Context) -> Self {
+ pub fn load(context: &'a Context, config: GitStatusConfig<'a>) -> Self {
Self {
context,
+ config,
repo_status: OnceCell::new(),
stashed_count: OnceCell::new(),
}
@@ -135,7 +137,7 @@ impl<'a> GitStatusInfo<'a> {
pub fn get_repo_status(&self) -> &Option<RepoStatus> {
self.repo_status
- .get_or_init(|| match get_repo_status(self.context) {
+ .get_or_init(|| match get_repo_status(self.context, &self.config) {
Some(repo_status) => Some(repo_status),
None => {
log::debug!("get_repo_status: git status execution failed");
@@ -181,21 +183,37 @@ impl<'a> GitStatusInfo<'a> {
}
/// Gets the number of files in various git states (staged, modified, deleted, etc...)
-fn get_repo_status(context: &Context) -> Option<RepoStatus> {
+fn get_repo_status(context: &Context, config: &GitStatusConfig) -> Option<RepoStatus> {
log::debug!("New repo status created");
let mut repo_status = RepoStatus::default();
- let status_output = context.exec_cmd(
- "git",
- &[
- OsStr::new("-C"),
- context.current_dir.as_os_str(),
- OsStr::new("--no-optional-locks"),
- OsStr::new("status"),
- OsStr::new("--porcelain=2"),
- OsStr::new("--branch"),
- ],
- )?;
+ let mut args = vec![
+ OsStr::new("-C"),
+ context.current_dir.as_os_str(),
+ OsStr::new("--no-optional-locks"),
+ OsStr::new("status"),
+ OsStr::new("--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(OsStr::new("--branch"));
+ }
+
+ // ... and add flags that omit information the user doesn't want
+ let has_untracked = !config.untracked.is_empty();
+ if !has_untracked {
+ args.push(OsStr::new("--untracked-files=no"));
+ }
+ if config.ignore_submodules {
+ args.push(OsStr::new("--ignore-submodules=dirty"));
+ } else if !has_untracked {
+ args.push(OsStr::new("--ignore-submodules=untracked"));
+ }
+
+ let status_output = context.exec_cmd("git", &args)?;
let statuses = status_output.stdout.lines();
statuses.for_each(|status| {