Changed '\!' prompt escape sequence to '\@' to avoid conflicting with escaping ! history expansion

This commit is contained in:
2026-03-05 00:28:26 -05:00
parent 0ec8c5cca1
commit 1b676db3a2
2 changed files with 12 additions and 8 deletions

View File

@@ -29,17 +29,21 @@ The prompt string supports escape sequences for dynamic content:
| `\t`, `\T` | Last command runtime (milliseconds / human-readable) | | `\t`, `\T` | Last command runtime (milliseconds / human-readable) |
| `\s` | Shell name | | `\s` | Shell name |
| `\e[...` | ANSI escape sequences for colors and styling | | `\e[...` | ANSI escape sequences for colors and styling |
| `\!name` | Execute a shell function and embed its output | | `\@name` | Execute a shell function and embed its output |
The `\!` escape is particularly useful. It lets you embed the output of any shell function directly in your prompt. Define a function that prints something, then reference it in your prompt string: The `\@` escape is particularly useful. It lets you embed the output of any shell function directly in your prompt. Define a function that prints something, then reference it in your prompt string:
```sh ```sh
gitbranch() { git branch --show-current 2>/dev/null; } gitbranch() { git branch --show-current 2>/dev/null; }
export PS1='\u@\h \W \!gitbranch \$ ' export PS1='\u@\h \W \@gitbranch \$ '
``` ```
Additionally, `echo` now has a `-p` flag that expands prompt escape sequences, similar to how the `-e` flag expands conventional escape sequences. Additionally, `echo` now has a `-p` flag that expands prompt escape sequences, similar to how the `-e` flag expands conventional escape sequences.
### I Can't Believe It's Not `fzf`!
`shed` comes with fuzzy completion and history searching out of the box. It has it's own internal fuzzyfinder implementation, so `fzf` is not a dependency.
### Shell Language ### Shell Language
shed's scripting language contains all of the essentials. shed's scripting language contains all of the essentials.

View File

@@ -1033,7 +1033,7 @@ pub fn unescape_str(raw: &str) -> String {
'\\' => { '\\' => {
if let Some(next_ch) = chars.next() { if let Some(next_ch) = chars.next() {
match next_ch { match next_ch {
'"' | '\\' | '`' | '$' => { '"' | '\\' | '`' | '$' | '!' => {
// discard the backslash // discard the backslash
} }
_ => { _ => {
@@ -2037,7 +2037,7 @@ fn tokenize_prompt(raw: &str) -> Vec<PromptTk> {
'\'' => tokens.push(PromptTk::Text("'".into())), '\'' => tokens.push(PromptTk::Text("'".into())),
'(' => tokens.push(PromptTk::VisGroupOpen), '(' => tokens.push(PromptTk::VisGroupOpen),
')' => tokens.push(PromptTk::VisGroupClose), ')' => tokens.push(PromptTk::VisGroupClose),
'!' => { '@' => {
let mut func_name = String::new(); let mut func_name = String::new();
let is_braced = chars.peek() == Some(&'{'); let is_braced = chars.peek() == Some(&'{');
let mut handled = false; let mut handled = false;
@@ -2056,14 +2056,14 @@ fn tokenize_prompt(raw: &str) -> Vec<PromptTk> {
handled = true; handled = true;
if is_braced { if is_braced {
// Invalid character in braced function name // Invalid character in braced function name
tokens.push(PromptTk::Text(format!("\\!{{{func_name}"))); tokens.push(PromptTk::Text(format!("\\@{{{func_name}")));
} else { } else {
// End of unbraced function name // End of unbraced function name
let func_exists = read_logic(|l| l.get_func(&func_name).is_some()); let func_exists = read_logic(|l| l.get_func(&func_name).is_some());
if func_exists { if func_exists {
tokens.push(PromptTk::Function(func_name.clone())); tokens.push(PromptTk::Function(func_name.clone()));
} else { } else {
tokens.push(PromptTk::Text(format!("\\!{func_name}"))); tokens.push(PromptTk::Text(format!("\\@{func_name}")));
} }
} }
break; break;
@@ -2076,7 +2076,7 @@ fn tokenize_prompt(raw: &str) -> Vec<PromptTk> {
if func_exists { if func_exists {
tokens.push(PromptTk::Function(func_name)); tokens.push(PromptTk::Function(func_name));
} else { } else {
tokens.push(PromptTk::Text(format!("\\!{func_name}"))); tokens.push(PromptTk::Text(format!("\\@{func_name}")));
} }
} }
} }