diff --git a/src/binary/prompt.rs b/src/binary/prompt.rs index ed51d259bd1eae8d9e3d76381c55cde0a6805145..0212a566653ae6898e665a0f0562d2f317d1c416 100644 --- a/src/binary/prompt.rs +++ b/src/binary/prompt.rs @@ -1,5 +1,5 @@ -use ion_shell::{parser::Expander, sys, Capture, Shell, Value}; -use std::{io::Read, process}; +use ion_shell::{parser::Expander, Capture, Shell}; +use std::io::Read; pub fn prompt(shell: &Shell) -> String { let blocks = shell.block_len() + if shell.unterminated { 1 } else { 0 }; @@ -14,30 +14,21 @@ pub fn prompt(shell: &Shell) -> String { } pub fn prompt_fn(shell: &Shell) -> Option<String> { - if let Some(Value::Function(function)) = shell.variables().get_ref("PROMPT") { - let output = match shell.fork(Capture::StdoutThenIgnoreStderr, move |child| { - let _ = function.execute(child, &["ion"]); - }) { - Ok(result) => { + shell + .fork_function( + Capture::StdoutThenIgnoreStderr, + |result| { let mut string = String::with_capacity(1024); - match result.stdout?.read_to_string(&mut string) { - Ok(_) => Some(string), + match result.stdout.ok_or(())?.read_to_string(&mut string) { + Ok(_) => Ok(string), Err(why) => { eprintln!("ion: error reading stdout of child: {}", why); - None + Err(()) } } - } - Err(why) => { - eprintln!("ion: fork error: {}", why); - None - } - }; - - // Ensure that the parent retains ownership of the terminal before exiting. - let _ = sys::tcsetpgrp(sys::STDIN_FILENO, process::id()); - output - } else { - None - } + }, + "PROMPT", + &["ion"], + ) + .ok() } diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs index 57c644debb2826c243cb3ae9c7862b0a7c789a37..e94042ea8948677b303530dbee9af223aa1ecf20 100644 --- a/src/lib/builtins/mod.rs +++ b/src/lib/builtins/mod.rs @@ -38,7 +38,7 @@ use hashbrown::HashMap; use liner::{Completer, Context}; use crate::{ - shell::{self, status::*, ProcessState, Shell}, + shell::{self, status::*, Capture, ProcessState, Shell}, sys, types, }; use itertools::Itertools; @@ -270,7 +270,7 @@ pub fn builtin_cd(args: &[small::String], shell: &mut Shell) -> i32 { match shell.cd(args.get(1)) { Ok(()) => { - let _ = shell.fork_function("CD_CHANGE", &["ion"]); + let _ = shell.fork_function(Capture::None, |_| Ok(()), "CD_CHANGE", &["ion"]); SUCCESS } Err(why) => { diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 5ff9351307e2db060740a28e13b98e88bfdcc599..3063d8491649a8089e3193175914be85a67d46df 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -5,7 +5,7 @@ extern crate err_derive; extern crate ion_braces as braces; extern crate ion_lexers as lexers; extern crate ion_ranges as ranges; -pub extern crate ion_sys as sys; +extern crate ion_sys as sys; #[macro_use] pub mod types; diff --git a/src/lib/shell/fork.rs b/src/lib/shell/fork.rs index d315ff642f16cbdf4c8f93850cd6f687282bf218..513edfcc7de6eacba93c385504ea795b6a450c2e 100644 --- a/src/lib/shell/fork.rs +++ b/src/lib/shell/fork.rs @@ -20,7 +20,7 @@ pub fn wait_for_child(pid: u32) -> io::Result<u8> { } #[repr(u8)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] /// Instructs whether or not to capture the standard output and error streams. /// /// A type that is utilized by the `Fork` structure. diff --git a/src/lib/shell/fork_function.rs b/src/lib/shell/fork_function.rs index d20bbdec9bd486f24f7e68fb3f33f5556319b217..8e872dde5db601b68e678668df19e38ea6c428fc 100644 --- a/src/lib/shell/fork_function.rs +++ b/src/lib/shell/fork_function.rs @@ -1,5 +1,5 @@ use crate::{ - shell::{variables::Value, Capture, Shell}, + shell::{fork::IonResult, variables::Value, Capture, Shell}, sys, }; use std::process; @@ -7,22 +7,40 @@ use std::process; impl<'a> Shell<'a> { /// High-level function for executing a function programmatically. /// NOTE: Always add "ion" as a first argument in `args`. - pub fn fork_function<S: AsRef<str>>(&mut self, fn_name: &str, args: &[S]) -> Result<(), ()> { + pub fn fork_function<S: AsRef<str>, T, F: FnOnce(IonResult) -> Result<T, ()>>( + &self, + capture: Capture, + result: F, + fn_name: &str, + args: &[S], + ) -> Result<T, ()> { if let Some(Value::Function(function)) = self.variables.get_ref(fn_name) { - if let Err(err) = self.fork(Capture::None, move |child| { - if let Err(err) = function.execute(child, args) { - eprintln!("ion: {} function call: {}", fn_name, err); - } - }) { - eprintln!("ion: fork error: {}", err); - Err(()) - } else { - // Ensure that the parent retains ownership of the terminal before exiting. - let _ = sys::tcsetpgrp(sys::STDIN_FILENO, process::id()); - Ok(()) - } + let output = self + .fork(capture, move |child| { + if let Err(err) = function.execute(child, args) { + if capture == Capture::None { + eprintln!("ion: {} function call: {}", fn_name, err); + } + } + }) + .map_err(|err| eprintln!("ion: fork error: {}", err)) + .and_then(result); + + // Ensure that the parent retains ownership of the terminal before exiting. + let _ = sys::tcsetpgrp(sys::STDIN_FILENO, process::id()); + output } else { Err(()) } } + + /// Execute the function on command not found + pub fn command_not_found<S: AsRef<str>>(&self, cmd: S) { + if self + .fork_function(Capture::None, |_| Ok(()), "COMMAND_NOT_FOUND", &["ion", cmd.as_ref()]) + .is_err() + { + eprintln!("ion: command not found: {}", cmd.as_ref()); + } + } } diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs index 373de69af8b212c4dcd949c22beb50e19a49e271..e97779c97a40c5a715be697b09f834b0a3cede95 100644 --- a/src/lib/shell/mod.rs +++ b/src/lib/shell/mod.rs @@ -12,8 +12,7 @@ pub(crate) mod signals; pub mod status; pub mod variables; -pub use self::{fork::Capture, job::Job, pipe_exec::job_control::ProcessState, variables::Value}; - +pub(crate) use self::job::Job; use self::{ directory_stack::DirectoryStack, flow_control::{Block, Function, FunctionError, Statement}, @@ -23,6 +22,7 @@ use self::{ status::*, variables::{GetVariable, Variables}, }; +pub use self::{fork::Capture, pipe_exec::job_control::ProcessState, variables::Value}; use crate::{ builtins::BuiltinMap, lexers::{Key, Primitive}, diff --git a/src/lib/shell/pipe_exec/mod.rs b/src/lib/shell/pipe_exec/mod.rs index a021d373af786a8cf81f296f9f05d596a1e11c0d..2de0033462c444d43690e4d89ab77db2d2f20840 100644 --- a/src/lib/shell/pipe_exec/mod.rs +++ b/src/lib/shell/pipe_exec/mod.rs @@ -223,9 +223,7 @@ impl<'b> Shell<'b> { self.watch_foreground(-(pid as i32), "") } Err(ref err) if err.kind() == io::ErrorKind::NotFound => { - if self.fork_function("COMMAND_NOT_FOUND", &["ion", &name]).is_err() { - eprintln!("ion: command not found: {}", name); - } + self.command_not_found(name); NO_SUCH_COMMAND } Err(ref err) => { @@ -537,9 +535,7 @@ fn spawn_proc( *current_pid = pid; } Err(ref mut err) if err.kind() == io::ErrorKind::NotFound => { - if shell.fork_function("COMMAND_NOT_FOUND", &["ion", &name]).is_err() { - eprintln!("ion: command not found: {}", name); - } + shell.command_not_found(name) } Err(ref mut err) => { eprintln!("ion: command exec error: {}", err);