Add array support for local/export/readonly builtins
Add array length syntax ${arr[#]}
Map read path now expands variables before splitting on ., fixing map "$node" with dotted paths
Map assignment path uses quote-aware token splitting, enabling quoted keys like "--type="
Completion errors now display above prompt instead of being overwritten
Fix nested if/fi parser bug when closing keywords appear on separate lines
Add QuoteState enum, replacing ad-hoc quote tracking booleans across lexer, highlighter, and expansion
Add split_tk_at/split_tk for quote-aware token splitting with span preservation
Refactor setup_builtin to accept optional argv for deferred expansion
Add ariadne dependency (not yet wired up)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
jobs::JobBldr,
|
||||
libsh::error::{ShErr, ShErrKind, ShResult},
|
||||
parse::{NdRule, Node},
|
||||
parse::{NdRule, Node, lex::split_tk_at},
|
||||
prelude::*,
|
||||
procio::{IoStack, borrow_fd},
|
||||
state::{self, VarFlags, VarKind, read_vars, write_vars},
|
||||
@@ -18,7 +18,10 @@ pub fn readonly(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResu
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let (argv, _guard) = setup_builtin(argv, job, Some((io_stack, node.redirs)))?;
|
||||
let (_, _guard) = setup_builtin(None, job, Some((io_stack, node.redirs)))?;
|
||||
|
||||
// Remove "readonly" from argv
|
||||
let argv = if !argv.is_empty() { &argv[1..] } else { &argv[..] };
|
||||
|
||||
if argv.is_empty() {
|
||||
// Display the local variables
|
||||
@@ -38,10 +41,17 @@ pub fn readonly(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResu
|
||||
let stdout = borrow_fd(STDOUT_FILENO);
|
||||
write(stdout, vars_output.as_bytes())?; // Write it
|
||||
} else {
|
||||
for (arg, _) in argv {
|
||||
if let Some((var, val)) = arg.split_once('=') {
|
||||
write_vars(|v| v.set_var(var, VarKind::Str(val.to_string()), VarFlags::READONLY))?;
|
||||
for tk in argv {
|
||||
if let Some((var_tk, val_tk)) = split_tk_at(tk, "=") {
|
||||
let var = var_tk.expand()?.get_words().join(" ");
|
||||
let val = if val_tk.as_str().starts_with('(') && val_tk.as_str().ends_with(')') {
|
||||
VarKind::arr_from_tk(val_tk.clone())?
|
||||
} else {
|
||||
VarKind::Str(val_tk.expand()?.get_words().join(" "))
|
||||
};
|
||||
write_vars(|v| v.set_var(&var, val, VarFlags::READONLY))?;
|
||||
} else {
|
||||
let arg = tk.clone().expand()?.get_words().join(" ");
|
||||
write_vars(|v| v.set_var(&arg, VarKind::Str(String::new()), VarFlags::READONLY))?;
|
||||
}
|
||||
}
|
||||
@@ -61,7 +71,8 @@ pub fn unset(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let (argv, _guard) = setup_builtin(argv, job, Some((io_stack, node.redirs)))?;
|
||||
let (argv, _guard) = setup_builtin(Some(argv), job, Some((io_stack, node.redirs)))?;
|
||||
let argv = argv.unwrap();
|
||||
|
||||
if argv.is_empty() {
|
||||
return Err(ShErr::full(
|
||||
@@ -95,7 +106,10 @@ pub fn export(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let (argv, _guard) = setup_builtin(argv, job, Some((io_stack, node.redirs)))?;
|
||||
let (_, _guard) = setup_builtin(None, job, Some((io_stack, node.redirs)))?;
|
||||
|
||||
// Remove "export" from argv
|
||||
let argv = if !argv.is_empty() { &argv[1..] } else { &argv[..] };
|
||||
|
||||
if argv.is_empty() {
|
||||
// Display the environment variables
|
||||
@@ -109,12 +123,18 @@ pub fn export(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult
|
||||
let stdout = borrow_fd(STDOUT_FILENO);
|
||||
write(stdout, env_output.as_bytes())?; // Write it
|
||||
} else {
|
||||
for (arg, _) in argv {
|
||||
if let Some((var, val)) = arg.split_once('=') {
|
||||
write_vars(|v| v.set_var(var, VarKind::Str(val.to_string()), VarFlags::EXPORT))?;
|
||||
for tk in argv {
|
||||
if let Some((var_tk, val_tk)) = split_tk_at(tk, "=") {
|
||||
let var = var_tk.expand()?.get_words().join(" ");
|
||||
let val = if val_tk.as_str().starts_with('(') && val_tk.as_str().ends_with(')') {
|
||||
VarKind::arr_from_tk(val_tk.clone())?
|
||||
} else {
|
||||
VarKind::Str(val_tk.expand()?.get_words().join(" "))
|
||||
};
|
||||
write_vars(|v| v.set_var(&var, val, VarFlags::EXPORT))?;
|
||||
} else {
|
||||
write_vars(|v| v.export_var(&arg)); // Export an existing variable, if
|
||||
// any
|
||||
let arg = tk.clone().expand()?.get_words().join(" ");
|
||||
write_vars(|v| v.export_var(&arg)); // Export an existing variable, if any
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,7 +151,10 @@ pub fn local(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let (argv, _guard) = setup_builtin(argv, job, Some((io_stack, node.redirs)))?;
|
||||
let (_, _guard) = setup_builtin(None, job, Some((io_stack, node.redirs)))?;
|
||||
|
||||
// Remove "local" from argv
|
||||
let argv = if !argv.is_empty() { &argv[1..] } else { &argv[..] };
|
||||
|
||||
if argv.is_empty() {
|
||||
// Display the local variables
|
||||
@@ -150,10 +173,17 @@ pub fn local(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<
|
||||
let stdout = borrow_fd(STDOUT_FILENO);
|
||||
write(stdout, vars_output.as_bytes())?; // Write it
|
||||
} else {
|
||||
for (arg, _) in argv {
|
||||
if let Some((var, val)) = arg.split_once('=') {
|
||||
write_vars(|v| v.set_var(var, VarKind::Str(val.to_string()), VarFlags::LOCAL))?;
|
||||
for tk in argv {
|
||||
if let Some((var_tk, val_tk)) = split_tk_at(tk, "=") {
|
||||
let var = var_tk.expand()?.get_words().join(" ");
|
||||
let val = if val_tk.as_str().starts_with('(') && val_tk.as_str().ends_with(')') {
|
||||
VarKind::arr_from_tk(val_tk.clone())?
|
||||
} else {
|
||||
VarKind::Str(val_tk.expand()?.get_words().join(" "))
|
||||
};
|
||||
write_vars(|v| v.set_var(&var, val, VarFlags::LOCAL))?;
|
||||
} else {
|
||||
let arg = tk.clone().expand()?.get_words().join(" ");
|
||||
write_vars(|v| v.set_var(&arg, VarKind::Str(String::new()), VarFlags::LOCAL))?;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user