Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for xonsh #2807

Merged
merged 10 commits into from
Jul 16, 2021
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ shown below. Can't see yours? Have a look at the [extra platform instructions](h
# ~/.tcshrc

eval `starship init tcsh`

#### Xonsh

Add the following to the end of `~/.xonshrc`:

```sh
# ~/.xonshrc

execx($(starship init xonsh))
```

#### Nushell
Expand Down
4 changes: 2 additions & 2 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ module.exports = {
head: [
["link", { rel: "icon", href: "/icon.png" }],
["meta", { property: "og:title", content: "Starship: Cross-Shell Prompt" }],
["meta", { property: "og:description", content: "Starship is the minimal, blazing fast, and extremely customizable prompt for any shell! Shows the information you need, while staying sleek and minimal. Quick installation available for Bash, Fish, ZSH, Ion, and Powershell."}],
["meta", { property: "og:description", content: "Starship is the minimal, blazing fast, and extremely customizable prompt for any shell! Shows the information you need, while staying sleek and minimal. Quick installation available for Bash, Fish, ZSH, Ion, Tcsh, Elvish, Nu, Xonsh, and Powershell."}],
["meta", { property: "og:type", content: "website" }],
["meta", { property: "og:url", content: "https://starship.rs/" }],
["meta", { property: "og:image", content: "https://starship.rs/icon.png" }],
["meta", { name: "twitter:card", content: "summary"}],
["meta", { name: "twitter:title", content: "Starship: Cross-Shell Prompt"}],
["meta", { name: "twitter:description", content: "Starship is the minimal, blazing fast, and extremely customizable prompt for any shell! Shows the information you need, while staying sleek and minimal. Quick installation available for Bash, Fish, ZSH, Ion, and Powershell."}],
["meta", { name: "twitter:description", content: "Starship is the minimal, blazing fast, and extremely customizable prompt for any shell! Shows the information you need, while staying sleek and minimal. Quick installation available for Bash, Fish, ZSH, Ion, Tcsh, Elvish, Nu, Xonsh, and Powershell."}],
["meta", { name: "twitter:image", content: "https://starship.rs/icon.png"}],
["meta", { name: "twitter:alt", content: "Starship: Cross-Shell Prompt"}],
],
Expand Down
15 changes: 13 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ footer: ISC Licensed | Copyright © 2019-present Starship Contributors

# Used for the description meta tag, for SEO
metaTitle: "Starship: Cross-Shell Prompt"
description: Starship is the minimal, blazing fast, and extremely customizable prompt for any shell! Shows the information you need, while staying sleek and minimal. Quick installation available for Bash, Fish, ZSH, Ion, and PowerShell.
description: Starship is the minimal, blazing fast, and extremely customizable prompt for any shell! Shows the information you need, while staying sleek and minimal. Quick installation available for Bash, Fish, ZSH, Ion, Tcsh, Elvish, Nu, Xonsh, and PowerShell.
---

<div class="center">
Expand Down Expand Up @@ -106,6 +106,7 @@ description: Starship is the minimal, blazing fast, and extremely customizable p

eval $(starship init ion)
```

#### Elvish

::: warning
Expand All @@ -130,7 +131,7 @@ description: Starship is the minimal, blazing fast, and extremely customizable p
eval `starship init tcsh`
```

#### Nushell
#### Nushell

::: warning
This will change in the future.
Expand All @@ -147,3 +148,13 @@ description: Starship is the minimal, blazing fast, and extremely customizable p
]
prompt = "starship_prompt"
```

#### Xonsh

Add the following to the end of `~/.xonshrc`:

```sh
# ~/.xonshrc

execx($(starship init xonsh))
```
1 change: 1 addition & 0 deletions docs/config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,7 @@ To enable it, set `disabled` to `false` in your configuration file.
| `ion_indicator` | `ion` | A format string used to represent ion. |
| `elvish_indicator` | `esh` | A format string used to represent elvish. |
| `tcsh_indicator` | `tsh` | A format string used to represent tcsh. |
| `xonsh_indicator` | `xsh` | A format string used to represent xonsh. |
| `unknown_indicator` | | The default value to be displayed when the shell is unknown. |
| `format` | `$indicator ` | The format for the module. |
| `disabled` | `true` | Disables the `shell` module. |
Expand Down
6 changes: 6 additions & 0 deletions install/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,10 @@ info "Please follow the steps for your shell to complete the installation:
Add the following to the end of ${BOLD}~/.tcshrc${NO_COLOR}:

eval \`starship init tcsh\`

${BOLD}${UNDERLINE}Xonsh${NO_COLOR}
Add the following to the end of ${BOLD}~/.xonshrc${NO_COLOR}:

execx($(starship init xonsh))

"
6 changes: 6 additions & 0 deletions snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ description: |

`Invoke-Expression (&starship init powershell)`

### Xonsh

Add the following to the end of ~/.xonshrc:

execx($(starship init xonsh))

grade: stable
confinement: strict

Expand Down
1 change: 1 addition & 0 deletions src/bug_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ fn get_config_path(shell: &str) -> Option<PathBuf> {
"zsh" => Some(".zshrc"),
"elvish" => Some(".elvish/rc.elv"),
"tcsh" => Some(".tcshrc"),
"xonsh" => Some(".xonshrc"),
_ => None,
}
.map(|path| home_dir.join(path))
Expand Down
2 changes: 2 additions & 0 deletions src/configs/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct ShellConfig<'a> {
pub elvish_indicator: &'a str,
pub tcsh_indicator: &'a str,
pub nu_indicator: &'a str,
pub xonsh_indicator: &'a str,
pub unknown_indicator: &'a str,
pub disabled: bool,
}
Expand All @@ -30,6 +31,7 @@ impl<'a> Default for ShellConfig<'a> {
elvish_indicator: "esh",
tcsh_indicator: "tsh",
nu_indicator: "nu",
xonsh_indicator: "xsh",
unknown_indicator: "",
disabled: true,
}
Expand Down
2 changes: 2 additions & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ impl<'a> Context<'a> {
"elvish" => Shell::Elvish,
"tcsh" => Shell::Tcsh,
"nu" => Shell::Nu,
"xonsh" => Shell::Xonsh,
_ => Shell::Unknown,
}
}
Expand Down Expand Up @@ -494,6 +495,7 @@ pub enum Shell {
Elvish,
Tcsh,
Nu,
Xonsh,
Unknown,
}

Expand Down
8 changes: 8 additions & 0 deletions src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ pub fn init_stub(shell_name: &str) -> io::Result<()> {
starship.sprint_posix()?
),
"nu" => print_script(NU_INIT, &StarshipPath::init()?.sprint_posix()?),
"xonsh" => print!(
r#"execx($({} init xonsh --print-full-init))"#,
starship.sprint_posix()?
),
_ => {
let quoted_arg = shell_words::quote(shell_basename);
println!(
Expand All @@ -182,6 +186,7 @@ pub fn init_stub(shell_name: &str) -> io::Result<()> {
* tcsh\\n\
* zsh\\n\
* nu\\n\
* xonsh\\n\
\\n\
Please open an issue in the starship repo if you would like to \
see support for %s:\\nhttps://github.com/starship/starship/issues/new\\n\\n\" {0} {0}",
Expand All @@ -205,6 +210,7 @@ pub fn init_main(shell_name: &str) -> io::Result<()> {
"ion" => print_script(ION_INIT, &starship_path.sprint()?),
"elvish" => print_script(ELVISH_INIT, &starship_path.sprint_posix()?),
"tcsh" => print_script(TCSH_INIT, &starship_path.sprint_posix()?),
"xonsh" => print_script(XONSH_INIT, &starship_path.sprint_posix()?),
_ => {
println!(
"printf \"Shell name detection failed on phase two init.\\n\
Expand Down Expand Up @@ -252,6 +258,8 @@ const TCSH_INIT: &str = include_str!("starship.tcsh");

const NU_INIT: &str = include_str!("starship.nu");

const XONSH_INIT: &str = include_str!("starship.xsh");

#[cfg(test)]
mod tests {
use super::*;
Expand Down
15 changes: 15 additions & 0 deletions src/init/starship.xsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import random
import string


def starship_prompt():
last_cmd = __xonsh__.history[-1] if __xonsh__.history else None
status = last_cmd.rtn if last_cmd else 0
jobs = len(__xonsh__.all_jobs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After running any command the jobs will sometimes display for me, with only the starship init in my .xonshrc.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Getting job accounting right in xonsh apparently requires regularly calling _clear_dead_jobs.

We could accomplish that here by calling get_next_job_number. In fact, #1265 did exactly that.

Unfortunately, due to what I believe is the same issue as above, we're pretty limited here: we can't use any imported functions or even any names we define outside of this function. As a workaround, I've duplicated enough of the relevant logic in _clear_dead_jobs to ignore dead jobs in our count here.

After running any command the jobs will sometimes display for me, with only the starship init in my .xonshrc.

Incidentally, I reproduced this on xonsh 0.9.27 but not on xonsh's latest main branch. But I don't understand why they would be different. 🤷🏻‍♂️

duration = round((last_cmd.ts[1] - last_cmd.ts[0]) * 1000) if last_cmd else 0
return $(::STARSHIP:: prompt --status=@(status) --jobs=@(jobs) --cmd-duration=@(duration))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that $STARSHIP_SESSION_KEY works I've found another issue:
Log messages (stderr) from starship don't get displayed (invalid config file). Maybe it needs a workaround like this for PowerShell?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems to work for me when using https://github.com/anki-code/xontrib-prompt-starship latest and

@ xonsh --version
xonsh/0.9.27
@ python -V
Python 3.9.2
@ starship --version
starship 0.55.0
tag:v0.55.0
commit_hash:09b12a52
build_time:2021-06-20 18:31:06
build_env:rustc 1.53.0 (53cb7b09b 2021-06-17)

image
image

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, @davidkna.

This was fixed upstream in xonsh just three weeks ago: xonsh/xonsh#4336

But since no released versions of xonsh contain that fix, we should probably work around it here. I've added a workaround: 1e0bc8d



$PROMPT = starship_prompt
$STARSHIP_SHELL = "xonsh"
$STARSHIP_SESSION_KEY = "".join(random.choice(string.ascii_letters + string.digits) for _ in range(16))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting a NameError: name 'random' is not defined here.

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduced on my end.

I'm pretty confused by xonsh's behavior here. I've reduced some of the surprising behavior to a minimal example and asked about it on the xonsh gitter: https://gitter.im/xonsh/xonsh?at=60e7d763951c58084ecb7108

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a work around you could use the uuid module from the python std library. I think this would be enough we just need a unique id for each session

srt(uuid.uuid4())
# or
uuid.uuid4().hex

Copy link
Sponsor Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for that suggestion.

2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ fn main() {
let shell_arg = Arg::with_name("shell")
.value_name("SHELL")
.help(
"The name of the currently running shell\nCurrently supported options: bash, zsh, fish, powershell, ion, elvish, tcsh, nu",
"The name of the currently running shell\nCurrently supported options: bash, zsh, fish, powershell, ion, elvish, tcsh, nu, xonsh",
)
.required(true);

Expand Down
31 changes: 31 additions & 0 deletions src/modules/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Shell::Elvish => Some(config.elvish_indicator),
Shell::Tcsh => Some(config.tcsh_indicator),
Shell::Nu => Some(config.nu_indicator),
Shell::Xonsh => Some(config.xonsh_indicator),
Shell::Unknown => Some(config.unknown_indicator),
},
_ => None,
Expand All @@ -37,6 +38,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
"ion_indicator" => Some(Ok(config.ion_indicator)),
"elvish_indicator" => Some(Ok(config.elvish_indicator)),
"tcsh_indicator" => Some(Ok(config.tcsh_indicator)),
"xonsh_indicator" => Some(Ok(config.xonsh_indicator)),
"unknown_indicator" => Some(Ok(config.unknown_indicator)),
_ => None,
})
Expand Down Expand Up @@ -279,6 +281,35 @@ mod tests {
assert_eq!(expected, actual);
}

#[test]
fn test_xonsh_default_format() {
let expected = Some(format!("{} ", "xsh"));
let actual = ModuleRenderer::new("shell")
.shell(Shell::Xonsh)
.config(toml::toml! {
[shell]
disabled = false
})
.collect();

assert_eq!(expected, actual);
}

#[test]
fn test_xonsh_custom_format() {
let expected = Some(format!("{} ", Color::Cyan.bold().paint("xonsh")));
let actual = ModuleRenderer::new("shell")
.shell(Shell::Xonsh)
.config(toml::toml! {
[shell]
xonsh_indicator = "[xonsh](bold cyan)"
disabled = false
})
.collect();

assert_eq!(expected, actual);
}

#[test]
fn test_custom_format_conditional_indicator_match() {
let expected = Some(format!("{} ", "B"));
Expand Down