perf(git_status): add option to use windows starship to render in wsl (#2146)
This commit is contained in:
parent
6f1d19470e
commit
d2366ddb9c
|
@ -1480,10 +1480,17 @@ format = '[+$added]($added_style)/[-$deleted]($deleted_style) '
|
|||
The `git_status` module shows symbols representing the state of the repo in your
|
||||
current directory.
|
||||
|
||||
::: tip
|
||||
|
||||
The Git Status module is very slow in Windows directories (for example under `/mnt/c/`) when in a WSL environment.
|
||||
You can disable the module or use the `windows_starship` option to use a Windows-native Starship executable to compute `git_status` for those paths.
|
||||
|
||||
:::
|
||||
|
||||
### 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` |
|
||||
|
@ -1499,6 +1506,7 @@ current directory.
|
|||
| `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. |
|
||||
|
||||
### Variables
|
||||
|
||||
|
@ -1562,6 +1570,15 @@ diverged = "⇕⇡${ahead_count}⇣${behind_count}"
|
|||
behind = "⇣${count}"
|
||||
```
|
||||
|
||||
Use Windows Starship executable on Windows paths in WSL
|
||||
|
||||
```toml
|
||||
# ~/.config/starship.toml
|
||||
|
||||
[git_status]
|
||||
windows_starship = '/mnt/c/Users/username/scoop/apps/starship/current/starship.exe'
|
||||
```
|
||||
|
||||
## Go
|
||||
|
||||
The `golang` module shows the currently installed version of [Go](https://golang.org/).
|
||||
|
|
|
@ -225,6 +225,21 @@ pub struct StarshipConfig {
|
|||
pub config: Option<Value>,
|
||||
}
|
||||
|
||||
pub fn get_config_path() -> Option<String> {
|
||||
if let Ok(path) = env::var("STARSHIP_CONFIG") {
|
||||
// Use $STARSHIP_CONFIG as the config path if available
|
||||
log::debug!("STARSHIP_CONFIG is set: {}", &path);
|
||||
Some(path)
|
||||
} else {
|
||||
// Default to using ~/.config/starship.toml
|
||||
log::debug!("STARSHIP_CONFIG is not set");
|
||||
let config_path = utils::home_dir()?.join(".config/starship.toml");
|
||||
let config_path_str = config_path.to_str()?.to_owned();
|
||||
log::debug!("Using default config path: {}", config_path_str);
|
||||
Some(config_path_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl StarshipConfig {
|
||||
/// Initialize the Config struct
|
||||
pub fn initialize() -> Self {
|
||||
|
@ -241,18 +256,7 @@ impl StarshipConfig {
|
|||
|
||||
/// Create a config from a starship configuration file
|
||||
fn config_from_file() -> Option<Value> {
|
||||
let file_path = if let Ok(path) = env::var("STARSHIP_CONFIG") {
|
||||
// Use $STARSHIP_CONFIG as the config path if available
|
||||
log::debug!("STARSHIP_CONFIG is set: {}", &path);
|
||||
path
|
||||
} else {
|
||||
// Default to using ~/.config/starship.toml
|
||||
log::debug!("STARSHIP_CONFIG is not set");
|
||||
let config_path = utils::home_dir()?.join(".config/starship.toml");
|
||||
let config_path_str = config_path.to_str()?.to_owned();
|
||||
log::debug!("Using default config path: {}", config_path_str);
|
||||
config_path_str
|
||||
};
|
||||
let file_path = get_config_path()?;
|
||||
|
||||
let toml_content = match utils::read_file(&file_path) {
|
||||
Ok(content) => {
|
||||
|
|
|
@ -20,6 +20,8 @@ pub struct GitStatusConfig<'a> {
|
|||
pub untracked: &'a str,
|
||||
pub ignore_submodules: bool,
|
||||
pub disabled: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub windows_starship: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> Default for GitStatusConfig<'a> {
|
||||
|
@ -40,6 +42,7 @@ impl<'a> Default for GitStatusConfig<'a> {
|
|||
untracked: "?",
|
||||
ignore_submodules: false,
|
||||
disabled: false,
|
||||
windows_starship: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,13 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||
|
||||
//Return None if not in git repository
|
||||
context.get_repo().ok()?;
|
||||
if let Some(git_status) = git_status_wsl(context, &config) {
|
||||
if git_status.is_empty() {
|
||||
return None;
|
||||
}
|
||||
module.set_segments(Segment::from_text(None, git_status));
|
||||
return Some(module);
|
||||
}
|
||||
|
||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||
formatter
|
||||
|
@ -354,6 +361,107 @@ fn format_symbol(format_str: &str, config_path: &str, context: &Context) -> Opti
|
|||
format_text(format_str, config_path, context, |_variable| None)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn git_status_wsl(context: &Context, conf: &GitStatusConfig) -> Option<String> {
|
||||
use crate::utils::create_command;
|
||||
use nix::sys::utsname::uname;
|
||||
use std::env;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
let starship_exe = conf.windows_starship?;
|
||||
|
||||
// Ensure this is WSL
|
||||
// This is lowercase in WSL1 and uppercase in WSL2, just skip the first letter
|
||||
if !uname().release().contains("icrosoft") {
|
||||
return None;
|
||||
}
|
||||
|
||||
log::trace!("Using WSL mode");
|
||||
|
||||
// Get Windows path
|
||||
let winpath = match create_command("wslpath")
|
||||
.map(|mut c| {
|
||||
c.arg("-w").arg(&context.current_dir);
|
||||
c
|
||||
})
|
||||
.and_then(|mut c| c.output())
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
// Not found might means this might not be WSL after all
|
||||
let level = if e.kind() == ErrorKind::NotFound {
|
||||
log::Level::Debug
|
||||
} else {
|
||||
log::Level::Error
|
||||
};
|
||||
|
||||
log::log!(level, "Failed to get Windows path:\n{:?}", e);
|
||||
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let winpath = match std::str::from_utf8(&winpath.stdout) {
|
||||
Ok(r) => r.trim_end(),
|
||||
Err(e) => {
|
||||
log::error!("Failed to parse Windows path:\n{:?}", e);
|
||||
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
log::trace!("Windows path: {}", winpath);
|
||||
|
||||
// In Windows or Linux dir?
|
||||
if winpath.starts_with(r"\\wsl") {
|
||||
log::trace!("Not a Windows path");
|
||||
return None;
|
||||
}
|
||||
|
||||
// Get foreign starship to use WSL config
|
||||
// https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
|
||||
let wslenv = env::var("WSLENV")
|
||||
.map(|e| e + ":STARSHIP_CONFIG/wp")
|
||||
.unwrap_or_else(|_| "STARSHIP_CONFIG/wp".to_string());
|
||||
|
||||
let out = match create_command(starship_exe)
|
||||
.map(|mut c| {
|
||||
c.env(
|
||||
"STARSHIP_CONFIG",
|
||||
crate::config::get_config_path().unwrap_or_else(|| "/dev/null".to_string()),
|
||||
)
|
||||
.env("WSLENV", wslenv)
|
||||
.args(&["module", "git_status", "--path", winpath]);
|
||||
c
|
||||
})
|
||||
.and_then(|mut c| c.output())
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
log::error!("Failed to run Git Status module on Windows:\n{}", e);
|
||||
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
match String::from_utf8(out.stdout) {
|
||||
Ok(r) => Some(r),
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Failed to parse Windows Git Status module status output:\n{}",
|
||||
e
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn git_status_wsl(_context: &Context, _conf: &GitStatusConfig) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ansi_term::{ANSIStrings, Color};
|
||||
|
|
Loading…
Reference in New Issue