Tab completion has been implemented

more small highlighter tune ups

2>&1 style redirections now work properly
This commit is contained in:
2026-02-18 21:53:36 -05:00
parent 01684cf8e5
commit 3b698628c6
22 changed files with 511 additions and 188 deletions

View File

@@ -138,7 +138,6 @@ impl Dispatcher {
}
}
pub fn begin_dispatch(&mut self) -> ShResult<()> {
log::trace!("beginning dispatch");
while let Some(node) = self.nodes.pop_front() {
let blame = node.get_span();
self.dispatch_node(node).try_blame(blame)?;
@@ -401,10 +400,23 @@ impl Dispatcher {
Ok(())
}
fn exec_for(&mut self, for_stmt: Node) -> ShResult<()> {
let NdRule::ForNode { vars, arr, body } = for_stmt.class else {
unreachable!();
};
let to_expanded_strings = |tks: Vec<Tk>| -> ShResult<Vec<String>> {
Ok(tks.into_iter()
.map(|tk| tk.expand().map(|tk| tk.get_words()))
.collect::<ShResult<Vec<Vec<String>>>>()?
.into_iter()
.flatten()
.collect::<Vec<_>>())
};
// Expand all array variables
let arr: Vec<String> = to_expanded_strings(arr)?;
let vars: Vec<String> = to_expanded_strings(vars)?;
let mut for_guard = VarCtxGuard::new(
vars.iter().map(|v| v.to_string()).collect()
);
@@ -415,7 +427,7 @@ impl Dispatcher {
.redirect()?;
'outer: for chunk in arr.chunks(vars.len()) {
let empty = Tk::default();
let empty = String::new();
let chunk_iter = vars.iter().zip(
chunk.iter().chain(std::iter::repeat(&empty)),
);
@@ -540,7 +552,6 @@ impl Dispatcher {
return self.dispatch_cmd(cmd);
}
log::trace!("doing builtin");
let result = match cmd_raw.span.as_str() {
"echo" => echo(cmd, io_stack_mut, curr_job_mut),
"cd" => cd(cmd, curr_job_mut),

View File

@@ -47,6 +47,11 @@ impl Span {
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
/// With great power comes great responsibility
/// Only use this in the most dire of circumstances
pub fn set_range(&mut self, range: Range<usize>) {
self.range = range;
}
}
/// Allows simple access to the underlying range wrapped by the span
@@ -176,7 +181,6 @@ bitflags! {
impl LexStream {
pub fn new(source: Arc<String>, flags: LexFlags) -> Self {
log::trace!("new lex stream");
let flags = flags | LexFlags::FRESH | LexFlags::NEXT_IS_CMD;
Self {
source,
@@ -260,7 +264,7 @@ impl LexStream {
pos += 1;
}
if !found_fd {
if !found_fd && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
return Some(Err(ShErr::full(
ShErrKind::ParseErr,
"Invalid redirection",
@@ -790,7 +794,6 @@ impl Iterator for LexStream {
match self.read_string() {
Ok(tk) => tk,
Err(e) => {
log::error!("{e:?}");
return Some(Err(e));
}
}

View File

@@ -860,6 +860,10 @@ impl ParseStream {
let redir_bldr = redir_bldr.with_io_mode(io_mode);
let redir = redir_bldr.build();
redirs.push(redir);
} else {
// io_mode is already set (e.g., for fd redirections like 2>&1)
let redir = redir_bldr.build();
redirs.push(redir);
}
}
Ok(())
@@ -1346,6 +1350,10 @@ impl ParseStream {
let redir_bldr = redir_bldr.with_io_mode(io_mode);
let redir = redir_bldr.build();
redirs.push(redir);
} else {
// io_mode is already set (e.g., for fd redirections like 2>&1)
let redir = redir_bldr.build();
redirs.push(redir);
}
}
_ => unimplemented!("Unexpected token rule `{:?}` in parse_cmd()", tk.class),