mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-12-04 19:03:38 +00:00
Merge commit from fork
addresses GHSA-vx24-x4mv-vwr5
This commit is contained in:
parent
4fa3914ba7
commit
cfc58161e0
4
.github/config-schema.json
vendored
4
.github/config-schema.json
vendored
@ -6444,6 +6444,10 @@
|
|||||||
"ignore_timeout": {
|
"ignore_timeout": {
|
||||||
"default": false,
|
"default": false,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"unsafe_no_escape": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -4756,11 +4756,12 @@ If you have an interesting example not covered there, feel free to share it ther
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: warning Command output is printed unescaped to the prompt
|
::: warning If `unsafe_no_escape` is enabled or prior to starship v1.20 command output is printed unescaped to the prompt.
|
||||||
|
|
||||||
Whatever output the command generates is printed unmodified in the prompt. This means if the output
|
Whatever output the command generates is printed unmodified in the prompt. This means if the output
|
||||||
contains special sequences that are interpreted by your shell they will be expanded when displayed.
|
contains shell-specific interpretable sequences, they could be interpreted on display.
|
||||||
These special sequences are shell specific, e.g. you can write a command module that writes bash sequences,
|
Depending on the shell, this can mean that e.g. strings enclosed by backticks are executed by the shell.
|
||||||
|
Such sequences are usually shell specific, e.g. you can write a command module that writes bash sequences,
|
||||||
e.g. `\h`, but this module will not work in a fish or zsh shell.
|
e.g. `\h`, but this module will not work in a fish or zsh shell.
|
||||||
|
|
||||||
Format strings can also contain shell specific prompt sequences, e.g.
|
Format strings can also contain shell specific prompt sequences, e.g.
|
||||||
@ -4778,6 +4779,7 @@ Format strings can also contain shell specific prompt sequences, e.g.
|
|||||||
| `require_repo` | `false` | If `true`, the module will only be shown in paths containing a (git) repository. This option alone is not sufficient display condition in absence of other options. |
|
| `require_repo` | `false` | If `true`, the module will only be shown in paths containing a (git) repository. This option alone is not sufficient display condition in absence of other options. |
|
||||||
| `shell` | | [See below](#custom-command-shell) |
|
| `shell` | | [See below](#custom-command-shell) |
|
||||||
| `description` | `'<custom module>'` | The description of the module that is shown when running `starship explain`. |
|
| `description` | `'<custom module>'` | The description of the module that is shown when running `starship explain`. |
|
||||||
|
| `unsafe_no_escape` | `false` | When set, command output is not escaped of characters that could be interpreted by the shell. |
|
||||||
| `detect_files` | `[]` | The files that will be searched in the working directory for a match. |
|
| `detect_files` | `[]` | The files that will be searched in the working directory for a match. |
|
||||||
| `detect_folders` | `[]` | The directories that will be searched in the working directory for a match. |
|
| `detect_folders` | `[]` | The directories that will be searched in the working directory for a match. |
|
||||||
| `detect_extensions` | `[]` | The extensions that will be searched in the working directory for a match. |
|
| `detect_extensions` | `[]` | The extensions that will be searched in the working directory for a match. |
|
||||||
|
@ -30,6 +30,7 @@ pub struct CustomConfig<'a> {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub use_stdin: Option<bool>,
|
pub use_stdin: Option<bool>,
|
||||||
pub ignore_timeout: bool,
|
pub ignore_timeout: bool,
|
||||||
|
pub unsafe_no_escape: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for CustomConfig<'a> {
|
impl<'a> Default for CustomConfig<'a> {
|
||||||
@ -50,6 +51,7 @@ impl<'a> Default for CustomConfig<'a> {
|
|||||||
os: None,
|
os: None,
|
||||||
use_stdin: None,
|
use_stdin: None,
|
||||||
ignore_timeout: false,
|
ignore_timeout: false,
|
||||||
|
unsafe_no_escape: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,22 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
let variables_closure = |variable: &str| match variable {
|
||||||
formatter
|
"output" => {
|
||||||
|
let output = exec_command(config.command, context, &config)?;
|
||||||
|
let trimmed = output.trim();
|
||||||
|
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Ok(trimmed.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|mut formatter| {
|
||||||
|
formatter = formatter
|
||||||
.map_meta(|var, _| match var {
|
.map_meta(|var, _| match var {
|
||||||
"symbol" => Some(config.symbol),
|
"symbol" => Some(config.symbol),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -68,21 +82,15 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map_style(|variable| match variable {
|
.map_style(|variable| match variable {
|
||||||
"style" => Some(Ok(config.style)),
|
"style" => Some(Ok(config.style)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
});
|
||||||
.map_no_escaping(|variable| match variable {
|
|
||||||
"output" => {
|
|
||||||
let output = exec_command(config.command, context, &config)?;
|
|
||||||
let trimmed = output.trim();
|
|
||||||
|
|
||||||
if trimmed.is_empty() {
|
if config.unsafe_no_escape {
|
||||||
None
|
formatter = formatter.map_no_escaping(variables_closure)
|
||||||
} else {
|
} else {
|
||||||
Some(Ok(trimmed.to_string()))
|
formatter = formatter.map(variables_closure)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => None,
|
formatter.parse(None, Some(context))
|
||||||
})
|
|
||||||
.parse(None, Some(context))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
@ -244,6 +252,11 @@ fn exec_when(cmd: &str, config: &CustomConfig, context: &Context) -> bool {
|
|||||||
fn exec_command(cmd: &str, context: &Context, config: &CustomConfig) -> Option<String> {
|
fn exec_command(cmd: &str, context: &Context, config: &CustomConfig) -> Option<String> {
|
||||||
log::trace!("Running '{cmd}'");
|
log::trace!("Running '{cmd}'");
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
if cmd == "__starship_to_be_escaped" {
|
||||||
|
return Some("`to_be_escaped`".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(output) = shell_command(cmd, config, context) {
|
if let Some(output) = shell_command(cmd, config, context) {
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
log::trace!("Non-zero exit code '{:?}'", output.status.code());
|
log::trace!("Non-zero exit code '{:?}'", output.status.code());
|
||||||
@ -298,6 +311,7 @@ fn handle_shell(command: &mut Command, shell: &str, shell_args: &[&str]) -> bool
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::context::Shell;
|
||||||
use crate::test::{fixture_repo, FixtureProvider, ModuleRenderer};
|
use crate::test::{fixture_repo, FixtureProvider, ModuleRenderer};
|
||||||
use nu_ansi_term::Color;
|
use nu_ansi_term::Color;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -761,4 +775,47 @@ mod tests {
|
|||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
repo_dir.close()
|
repo_dir.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn output_is_escaped() -> io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
|
||||||
|
let actual = ModuleRenderer::new("custom.test")
|
||||||
|
.path(dir.path())
|
||||||
|
.config(toml::toml! {
|
||||||
|
[custom.test]
|
||||||
|
format = "$output"
|
||||||
|
command = "__starship_to_be_escaped"
|
||||||
|
when = true
|
||||||
|
ignore_timeout = true
|
||||||
|
})
|
||||||
|
.shell(Shell::Bash)
|
||||||
|
.collect();
|
||||||
|
let expected = Some("\\`to_be_escaped\\`".to_string());
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unsafe_no_escape() -> io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
|
||||||
|
let actual = ModuleRenderer::new("custom.test")
|
||||||
|
.path(dir.path())
|
||||||
|
.config(toml::toml! {
|
||||||
|
[custom.test]
|
||||||
|
format = "$output"
|
||||||
|
command = "__starship_to_be_escaped"
|
||||||
|
when = true
|
||||||
|
ignore_timeout = true
|
||||||
|
unsafe_no_escape = true
|
||||||
|
})
|
||||||
|
.shell(Shell::Bash)
|
||||||
|
.collect();
|
||||||
|
let expected = Some("`to_be_escaped`".to_string());
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user