Skip to content

Commit

Permalink
support command output in prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
mitnk committed Nov 15, 2018
1 parent 8f0e1d9 commit 3ce108b
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 99 deletions.
50 changes: 42 additions & 8 deletions docs/prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,33 @@ username@hostname: current-dir$
## Available Prompt items

A prompt item is prompt value fields like `$USER`, `${COLOR_STATUS}` etc.
Note `$XYZ` is the same as `${XYZ}`, but sometime you need the `${XYZ}` form
to achieve prompt string like `FOO${XYZ}BAR`, where it would be treated as
`$XYZBAR` without the `{}` chars. Also, `$XYZ` is the same as `$xyz`.
Note `$XYZ` is the same as `${XYZ}`, and `$XYZ` is the same as `$xyz`.

| Prompt Item | Description |
| --- | --- |
| ${BLUE} | change terminal color to blue. |
| ${COLOR_STATUS} | change terminal color to green/red based on last exit status code. |
| ${CWD} | current work directory base name. e.g. `baz` for dir `/foo/bar/baz`. |
| ${GREEN} | change terminal color to green. |
| ${HOSTNAME} | system hostname. |
| ${NEWLINE} | the newline char: `\n`. |
| ${RED} | change terminal color to red. |
| ${RESET} | reset terminal color. |
| ${USER} | system user name. |
| ${BLACK} | change terminal color to black. |
| ${BLACK_B} | change terminal color to bold black. |
| ${BLACK_BG} | change terminal color to background black. |
| ${BLUE} | change terminal color to blue. |
| ${BLUE_B} | change terminal color to bold blue. |
| ${BLUE_BG} | change terminal color to background blue. |
| ${GREEN} | change terminal color to green. |
| ${GREEN_B} | change terminal color to bold green. |
| ${GREEN_BG} | change terminal color to background green. |
| ${RED} | change terminal color to red. |
| ${RED_B} | change terminal color to bold red. |
| ${RED_BG} | change terminal color to background red. |
| ${WHITE} | change terminal color to white. |
| ${WHITE_B} | change terminal color to bold white. |
| ${WHITE_BG} | change terminal color to background white. |
| ${COLOR_STATUS} | change terminal color to green/red based on last exit status code. |
| ${BOLD} | make text bold. |
| ${UNDERLINED} | Underlined text. |
| ${RESET} | reset terminal color & format. |

Note you can also use regular environment variables that not in the list, like `$HOME`, in the `$PROMPT` value.

Expand All @@ -39,3 +51,25 @@ See also [builtin vox](https://github.com/mitnk/cicada/blob/master/docs/built-in

When you enter a virtual env, the prompt will prefix by `(pyenv-name)`. e.g.
`(evn-test)mitnk:mbp: pip$ `.

## Use Command Output in Prompt

You can use `$(the cmd line)` in prompt, and the output of command
`the cmd line` will be rendered in prompt. e.g.
```
export PROMPT="[$(git rev-parse --abbrev-ref HEAD)] $USER@HOSTNAME$ "
```
would render prompt with:
```
$ [master] mitnk@mpb$
```

### Use prefix & suffix in it (BETA)
You can use `[` or `{` as prefix, and `]`, `}` as suffix when using command
output int prompt. e.g.
```
export PROMPT="$({git rev-parse --abbrev-ref HEAD}) $USER@HOSTNAME$ "
```
So that when the output of the command is empty, the prefix/suffix wouldn't
be rendered either.

20 changes: 19 additions & 1 deletion src/libs/colored.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
// setting prompt in crate linefeed needs wrap every SEQ chars
// with prefixing with '\x01' and suffix with '\x02'.
// todo full list - https://misc.flogisoft.com/bash/tip_colors_and_formatting
pub const RESET: &str = "\x01\x1B[0m\x02";
pub const BOLD: &str = "\x01\x1B[1m\x02";
pub const UNDERLINED: &str = "\x01\x1B[4m\x02";

pub const BLUE: &str = "\x01\x1B[34m\x02";
pub const BLACK: &str = "\x01\x1B[30m\x02";
pub const WHITE: &str = "\x01\x1B[97m\x02";
pub const RED: &str = "\x01\x1B[31m\x02";
pub const GREEN: &str = "\x01\x1B[32m\x02";
pub const RESET: &str = "\x01\x1B[0m\x02";

pub const BLUE_B: &str = "\x01\x1B[34m\x1B[1m\x02";
pub const BLACK_B: &str = "\x01\x1B[30m\x1B[1m\x02";
pub const WHITE_B: &str = "\x01\x1B[97m\x1B[1m\x02";
pub const RED_B: &str = "\x01\x1B[31m\x1B[1m\x02";
pub const GREEN_B: &str = "\x01\x1B[32m\x1B[1m\x02";

pub const BLUE_BG: &str = "\x01\x1B[44m\x02";
pub const BLACK_BG: &str = "\x01\x1B[40m\x02";
pub const WHITE_BG: &str = "\x01\x1B[107m\x02";
pub const RED_BG: &str = "\x01\x1B[41m\x02";
pub const GREEN_BG: &str = "\x01\x1B[42m\x02";
76 changes: 0 additions & 76 deletions src/libs/prompt.rs

This file was deleted.

63 changes: 55 additions & 8 deletions src/prompt/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
use std::env;

use execute;
use shell;
use tools;

const DEFAULT_PROMPT: &str = "${COLOR_STATUS}$USER${RESET}@${COLOR_STATUS}$HOSTNAME${RESET}: ${COLOR_STATUS}$CWD${RESET}$ ";
use super::preset::apply_preset_token;
use super::preset::apply_preset_item;
use super::preset::apply_pyenv;

fn is_prefix_char(c: char) -> bool {
c == '[' || c == '{'
}

fn is_suffix_char(c: char) -> bool {
c == ']' || c == '}'
}

fn is_prompt_item_char(c: char) -> bool {
let s = c.to_string();
tools::re_contains(&s, r#"^[a-zA-Z_]$"#)
Expand All @@ -19,28 +28,57 @@ pub fn get_prompt_string() -> String {
DEFAULT_PROMPT.to_string()
}

fn apply_token(sh: &shell::Shell, result: &mut String, token: &str) {
fn apply_prompt_item(sh: &shell::Shell, result: &mut String, token: &str) {
if let Ok(x) = env::var(token) {
result.push_str(&x);
return;
}
apply_preset_token(sh, result, token);
apply_preset_item(sh, result, token);
}

fn apply_command(result: &mut String, token: &str, prefix: &str, suffix: &str) {
let cr = execute::run(&token);
let output = cr.stdout.trim();
if !output.is_empty() {
result.push_str(&prefix);
result.push_str(&output);
result.push_str(&suffix);
}
}

pub fn render_prompt(sh: &shell::Shell, ps: &str) -> String {
let mut prompt = String::new();
apply_pyenv(&mut prompt);

let mut met_dollar = false;
let mut met_brace = false;
let mut met_paren = false;
let mut token = String::new();
let mut prefix = String::new();
let mut suffix = String::new();
for c in ps.chars() {
if met_dollar {
if c == '{' {
if c == '(' && !met_brace && !met_paren {
met_paren = true;
continue;
}
if c == ')' && met_paren {
apply_command(&mut prompt, &token, &prefix, &suffix);
token.clear();
prefix.clear();
suffix.clear();
met_dollar = false;
met_paren = false;
continue;
}
if c == '{' && !met_brace && !met_paren {
met_brace = true;
continue;
} else if c == '}' {
apply_token(sh, &mut prompt, &token);
} else if c == '}' && met_brace {
apply_prompt_item(sh, &mut prompt, &token);
token.clear();
met_dollar = false;
met_brace = false;
continue;
} else if c == '$' {
if token.is_empty() {
Expand All @@ -49,11 +87,20 @@ pub fn render_prompt(sh: &shell::Shell, ps: &str) -> String {
met_dollar = true;
continue;
} else {
apply_token(sh, &mut prompt, &token);
apply_prompt_item(sh, &mut prompt, &token);
token.clear();
// met_dollar is still true
continue;
}
} else if met_paren {
if is_prefix_char(c) {
prefix.push(c);
} else if is_suffix_char(c) {
suffix.push(c);
} else {
token.push(c);
}
continue;
} else if is_prompt_item_char(c) {
token.push(c);
continue;
Expand All @@ -71,7 +118,7 @@ pub fn render_prompt(sh: &shell::Shell, ps: &str) -> String {
}

if !token.is_empty() {
apply_token(sh, &mut prompt, &token);
apply_prompt_item(sh, &mut prompt, &token);
token.clear();
}
prompt.push(c);
Expand Down
Loading

0 comments on commit 3ce108b

Please sign in to comment.