Fixed command substitutions not expanding when used as a command name
This commit is contained in:
13
src/main.rs
13
src/main.rs
@@ -23,7 +23,6 @@ use std::process::ExitCode;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::libc::STDIN_FILENO;
|
||||
use nix::poll::{PollFd, PollFlags, PollTimeout, poll};
|
||||
use nix::unistd::read;
|
||||
|
||||
@@ -33,7 +32,7 @@ use crate::libsh::sys::TTY_FILENO;
|
||||
use crate::parse::execute::exec_input;
|
||||
use crate::prelude::*;
|
||||
use crate::prompt::get_prompt;
|
||||
use crate::prompt::readline::term::raw_mode;
|
||||
use crate::prompt::readline::term::{RawModeGuard, raw_mode};
|
||||
use crate::prompt::readline::{FernVi, ReadlineEvent};
|
||||
use crate::signal::{QUIT_CODE, check_signals, sig_setup, signals_pending};
|
||||
use crate::state::{read_logic, source_rc, write_jobs, write_meta};
|
||||
@@ -115,8 +114,7 @@ fn main() -> ExitCode {
|
||||
};
|
||||
|
||||
if let Some(trap) = read_logic(|l| l.get_trap(TrapTarget::Exit))
|
||||
&& let Err(e) = exec_input(trap, None, false)
|
||||
{
|
||||
&& let Err(e) = exec_input(trap, None, false) {
|
||||
eprintln!("fern: error running EXIT trap: {e}");
|
||||
}
|
||||
|
||||
@@ -215,10 +213,7 @@ fn fern_interactive() -> ShResult<()> {
|
||||
}
|
||||
|
||||
// Check if stdin has data
|
||||
if fds[0]
|
||||
.revents()
|
||||
.is_some_and(|r| r.contains(PollFlags::POLLIN))
|
||||
{
|
||||
if fds[0].revents().is_some_and(|r| r.contains(PollFlags::POLLIN)) {
|
||||
let mut buffer = [0u8; 1024];
|
||||
match read(*TTY_FILENO, &mut buffer) {
|
||||
Ok(0) => {
|
||||
@@ -244,7 +239,7 @@ fn fern_interactive() -> ShResult<()> {
|
||||
Ok(ReadlineEvent::Line(input)) => {
|
||||
let start = Instant::now();
|
||||
write_meta(|m| m.start_timer());
|
||||
if let Err(e) = exec_input(input, None, true) {
|
||||
if let Err(e) = RawModeGuard::with_cooked_mode(|| exec_input(input, None, true)) {
|
||||
match e.kind() {
|
||||
ShErrKind::CleanExit(code) => {
|
||||
QUIT_CODE.store(*code, Ordering::SeqCst);
|
||||
|
||||
@@ -155,7 +155,9 @@ pub fn exec_input(input: String, io_stack: Option<IoStack>, interactive: bool) -
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut dispatcher = Dispatcher::new(parser.extract_nodes(), interactive);
|
||||
let nodes = parser.extract_nodes();
|
||||
|
||||
let mut dispatcher = Dispatcher::new(nodes, interactive);
|
||||
if let Some(mut stack) = io_stack {
|
||||
dispatcher.io_stack.extend(stack.drain(..));
|
||||
}
|
||||
|
||||
@@ -659,6 +659,9 @@ impl LexStream {
|
||||
}
|
||||
_ if is_cmd_sub(text) => {
|
||||
new_tk.mark(TkFlags::IS_CMDSUB);
|
||||
if self.next_is_cmd() {
|
||||
new_tk.mark(TkFlags::IS_CMD);
|
||||
}
|
||||
self.set_next_is_cmd(false);
|
||||
}
|
||||
_ => {
|
||||
@@ -846,11 +849,26 @@ pub fn is_field_sep(ch: char) -> bool {
|
||||
}
|
||||
|
||||
pub fn is_keyword(slice: &str) -> bool {
|
||||
KEYWORDS.contains(&slice) || (slice.ends_with("()") && !slice.ends_with("\\()"))
|
||||
KEYWORDS.contains(&slice) || ends_with_unescaped(slice, "()")
|
||||
}
|
||||
|
||||
pub fn is_cmd_sub(slice: &str) -> bool {
|
||||
(slice.starts_with("$(") && slice.ends_with(')')) && !slice.ends_with("\\)")
|
||||
slice.starts_with("$(") && ends_with_unescaped(slice,")")
|
||||
}
|
||||
|
||||
pub fn ends_with_unescaped(slice: &str, pat: &str) -> bool {
|
||||
slice.ends_with(pat) && !pos_is_escaped(slice, slice.len() - pat.len())
|
||||
}
|
||||
|
||||
pub fn pos_is_escaped(slice: &str, pos: usize) -> bool {
|
||||
let bytes = slice.as_bytes();
|
||||
let mut escaped = false;
|
||||
let mut i = pos;
|
||||
while i > 0 && bytes[i - 1] == b'\\' {
|
||||
escaped = !escaped;
|
||||
i -= 1;
|
||||
}
|
||||
escaped
|
||||
}
|
||||
|
||||
pub fn lookahead(pat: &str, mut chars: Chars) -> Option<usize> {
|
||||
|
||||
@@ -184,14 +184,16 @@ impl Highlighter {
|
||||
input_chars.next();
|
||||
}
|
||||
|
||||
let inner_clean = Self::strip_markers(&inner);
|
||||
|
||||
// Determine prefix from content (handles both <( and >( for proc subs)
|
||||
let prefix = match ch {
|
||||
markers::CMD_SUB => "$(",
|
||||
markers::SUBSH => "(",
|
||||
markers::PROC_SUB => {
|
||||
if inner.starts_with("<(") {
|
||||
if inner_clean.starts_with("<(") {
|
||||
"<("
|
||||
} else if inner.starts_with(">(") {
|
||||
} else if inner_clean.starts_with(">(") {
|
||||
">("
|
||||
} else {
|
||||
"<("
|
||||
@@ -199,14 +201,13 @@ impl Highlighter {
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let inner_content = if incomplete {
|
||||
inner.strip_prefix(prefix).unwrap_or(&inner)
|
||||
inner_clean.strip_prefix(prefix).unwrap_or(&inner_clean)
|
||||
} else {
|
||||
inner
|
||||
inner_clean
|
||||
.strip_prefix(prefix)
|
||||
.and_then(|s| s.strip_suffix(")"))
|
||||
.unwrap_or(&inner)
|
||||
.unwrap_or(&inner_clean)
|
||||
};
|
||||
|
||||
let mut recursive_highlighter = Self::new();
|
||||
|
||||
Reference in New Issue
Block a user