brush_core/shell/
callstack.rs1use crate::{ExecutionParameters, callstack, env, error, functions, trace_categories};
4
5impl<SE: crate::extensions::ShellExtensions> crate::Shell<SE> {
6 pub fn in_sourced_script(&self) -> bool {
8 self.call_stack.in_sourced_script()
9 }
10
11 pub fn in_function(&self) -> bool {
13 self.call_stack.in_function()
14 }
15
16 pub fn start_interactive_session(&mut self) -> Result<(), error::Error> {
19 self.call_stack.push_interactive_session();
20 Ok(())
21 }
22
23 pub fn end_interactive_session(&mut self) -> Result<(), error::Error> {
26 if self
27 .call_stack
28 .current_frame()
29 .is_none_or(|frame| !frame.frame_type.is_interactive_session())
30 {
31 return Err(error::ErrorKind::NotInInteractiveSession.into());
32 }
33
34 self.call_stack.pop();
35
36 Ok(())
37 }
38
39 pub fn start_command_string_mode(&mut self) {
42 self.call_stack.push_command_string();
43 }
44
45 pub fn end_command_string_mode(&mut self) -> Result<(), error::Error> {
48 if self
49 .call_stack
50 .current_frame()
51 .is_none_or(|frame| !frame.frame_type.is_command_string())
52 {
53 return Err(error::ErrorKind::NotExecutingCommandString.into());
54 }
55
56 self.call_stack.pop();
57
58 Ok(())
59 }
60
61 pub(crate) fn enter_trap_handler(
62 &mut self,
63 signal: crate::traps::TrapSignal,
64 handler: Option<&crate::traps::TrapHandler>,
65 ) {
66 self.call_stack.push_trap_handler(signal, handler);
67 }
68
69 pub(crate) fn leave_trap_handler(&mut self) {
70 self.call_stack.pop();
71 }
72
73 pub(crate) const fn acquire_trap_delivery_block(&mut self) {
77 self.call_stack.acquire_trap_delivery_block();
78 }
79
80 pub(crate) const fn release_trap_delivery_block(&mut self) {
83 self.call_stack.release_trap_delivery_block();
84 }
85
86 pub(crate) fn enter_function(
96 &mut self,
97 name: &str,
98 function: &functions::Registration,
99 args: impl IntoIterator<Item = String>,
100 _params: &ExecutionParameters,
101 ) -> Result<(), error::Error> {
102 if let Some(max_call_depth) = self.options.max_function_call_depth
103 && self.call_stack.function_call_depth() >= max_call_depth
104 {
105 return Err(error::ErrorKind::MaxFunctionCallDepthExceeded.into());
106 }
107
108 if tracing::enabled!(target: trace_categories::FUNCTIONS, tracing::Level::DEBUG) {
109 let depth = self.call_stack.function_call_depth();
110 let prefix = repeated_char_str(' ', depth);
111 tracing::debug!(target: trace_categories::FUNCTIONS, "Entering func [depth={depth}]: {prefix}{name}");
112 }
113
114 self.call_stack.push_function(name, function, args);
115 self.env.push_scope(env::EnvironmentScope::Local);
116
117 Ok(())
118 }
119
120 pub(crate) fn leave_function(&mut self) -> Result<(), error::Error> {
123 self.env.pop_scope(env::EnvironmentScope::Local)?;
124
125 if let Some(exited_call) = self.call_stack.pop() {
126 if let callstack::FrameType::Function(func_call) = exited_call.frame_type {
127 if tracing::enabled!(target: trace_categories::FUNCTIONS, tracing::Level::DEBUG) {
128 let depth = self.call_stack.function_call_depth();
129 let prefix = repeated_char_str(' ', depth);
130 tracing::debug!(target: trace_categories::FUNCTIONS, "Exiting func [depth={depth}]: {prefix}{}", func_call.function_name);
131 }
132 } else {
133 let err: error::Error =
134 error::ErrorKind::InternalError("mismatched call stack state".to_owned())
135 .into();
136 return Err(err.into_fatal());
137 }
138 }
139
140 Ok(())
141 }
142
143 pub fn current_shell_args(&self) -> &[String] {
146 for frame in self.call_stack.iter() {
147 match frame.frame_type {
148 crate::callstack::FrameType::Function(..) => return &frame.args,
150 _ if frame.frame_type.is_run_script() => return &frame.args,
152 _ if frame.frame_type.is_sourced_script() && !frame.args.is_empty() => {
154 return &frame.args;
155 }
156 _ => (),
157 }
158 }
159
160 self.args.as_slice()
161 }
162
163 pub fn current_shell_args_mut(&mut self) -> &mut Vec<String> {
166 for frame in self.call_stack.iter_mut() {
167 match frame.frame_type {
168 crate::callstack::FrameType::Function(..) => return &mut frame.args,
170 _ if frame.frame_type.is_run_script() => return &mut frame.args,
172 _ if frame.frame_type.is_sourced_script() && !frame.args.is_empty() => {
174 return &mut frame.args;
175 }
176 _ => (),
177 }
178 }
179
180 &mut self.args
181 }
182}
183
184fn repeated_char_str(c: char, count: usize) -> String {
185 (0..count).map(|_| c).collect()
186}