diff --git a/src/ascii_helpers.rs b/src/ascii_helpers.rs
index 9eea0e62aaaff1edddc467b6bdf005dbf05b28d5..6bc3f90b7a25a9e55b61c5e65cf6130f96abbb11 100644
--- a/src/ascii_helpers.rs
+++ b/src/ascii_helpers.rs
@@ -5,11 +5,11 @@ use std::ops::DerefMut;
 // TODO: These could be generalised to work on non-ASCII characters (and even
 //       strings!) as long as the byte size of the needle and haystack match.
 
-pub trait AsciiReplaceInPlace {
+pub(crate) trait AsciiReplaceInPlace {
     fn ascii_replace_in_place(&mut self, needle: char, haystack: char);
 }
 
-pub trait AsciiReplace: Sized {
+pub(crate) trait AsciiReplace: Sized {
     fn ascii_replace(self, needle: char, haystack: char) -> Self;
 }
 
diff --git a/src/builtins/calc.rs b/src/builtins/calc.rs
index 6dd7329c90b782a2e328d9dd26e2337e008323de..59ec8f056e2e8a6b91751cd0bfd93c23febc4849 100644
--- a/src/builtins/calc.rs
+++ b/src/builtins/calc.rs
@@ -8,7 +8,7 @@ fn calc_or_polish_calc(args: String) -> Result<Value, CalcError> {
     }
 }
 
-pub fn calc(args: &[&str]) -> Result<(), String> {
+pub(crate) fn calc(args: &[&str]) -> Result<(), String> {
     let stdout = io::stdout();
     let mut stdout = stdout.lock();
     if !args.is_empty() {
diff --git a/src/builtins/conditionals.rs b/src/builtins/conditionals.rs
index e45d9ec2e1c98a27138d9cb9cd7bb93eee69785c..bb723670685cdbca0a40d98187c345faaf61acbb 100644
--- a/src/builtins/conditionals.rs
+++ b/src/builtins/conditionals.rs
@@ -3,7 +3,7 @@ use shell::status::*;
 
 macro_rules! string_function {
     ($method:tt) => (
-        pub fn $method(args: &[&str], _: &mut Shell) -> i32 {
+        pub(crate) fn $method(args: &[&str], _: &mut Shell) -> i32 {
             match args.len() {
                 0...2 => {
                     eprintln!("ion: {}: two arguments must be supplied", args[0]);
diff --git a/src/builtins/echo.rs b/src/builtins/echo.rs
index af6ac439123e11c2ac25a8863c081463864099c5..297d6ec8b1e618ae51fc27edfeacd166e49cbad0 100644
--- a/src/builtins/echo.rs
+++ b/src/builtins/echo.rs
@@ -41,7 +41,7 @@ OPTIONS
         \v  vertical tab (VT)
 "#; // @MANEND
 
-pub fn echo(args: &[&str]) -> Result<(), io::Error> {
+pub(crate) fn echo(args: &[&str]) -> Result<(), io::Error> {
     let mut flags = Flags::empty();
     let mut data: Vec<&str> = vec![];
 
diff --git a/src/builtins/exists.rs b/src/builtins/exists.rs
index 1789555754ad6046ba6178cb56325d694559eb15..f1aa54cee47fc74c318e5905d6f64729c3411bdc 100644
--- a/src/builtins/exists.rs
+++ b/src/builtins/exists.rs
@@ -70,7 +70,7 @@ AUTHOR
     Heavily based on implementation of the test builtin, which was written by Michael Murph.
 "#; // @MANEND
 
-pub fn exists(args: &[&str], shell: &Shell) -> Result<bool, String> {
+pub(crate) fn exists(args: &[&str], shell: &Shell) -> Result<bool, String> {
     let stdout = io::stdout();
     let mut buffer = BufWriter::new(stdout.lock());
 
diff --git a/src/builtins/functions.rs b/src/builtins/functions.rs
index d91f667555bedd62c0da8c32cbacf5bb40fcb6c7..37400a5832c9fde13335b316e9f11fe4f7f404ba 100644
--- a/src/builtins/functions.rs
+++ b/src/builtins/functions.rs
@@ -18,7 +18,7 @@ fn print_functions(functions: &FnvHashMap<Identifier, Function>) {
     }
 }
 
-pub fn fn_(functions: &mut FnvHashMap<Identifier, Function>) -> i32 {
+pub(crate) fn fn_(functions: &mut FnvHashMap<Identifier, Function>) -> i32 {
     print_functions(functions);
     SUCCESS
 }
diff --git a/src/builtins/ion.rs b/src/builtins/ion.rs
index f00a3ac4e1455cd8d5f96f5c40559a4970c1f4da..da61866af6e9c3901bd8ab20cccf0d8addd5eea5 100644
--- a/src/builtins/ion.rs
+++ b/src/builtins/ion.rs
@@ -6,7 +6,7 @@ use std::process::Command;
 
 const DOCPATH: &str = "/usr/share/ion/docs/index.html";
 
-pub fn ion_docs(_: &[&str], shell: &mut Shell) -> i32 {
+pub(crate) fn ion_docs(_: &[&str], shell: &mut Shell) -> i32 {
     if !Path::new(DOCPATH).exists() {
         eprintln!("ion: ion shell documentation is not installed");
         return FAILURE;
diff --git a/src/builtins/job_control.rs b/src/builtins/job_control.rs
index 6e22ea2f0dbed4dc2072e380de3118e3b466233f..d81c7980714011b9cd9d41361cdcfb128112c7b7 100644
--- a/src/builtins/job_control.rs
+++ b/src/builtins/job_control.rs
@@ -9,7 +9,7 @@ use std::io::{stderr, Write};
 /// Disowns given process job IDs, and optionally marks jobs to not receive SIGHUP signals.
 /// The `-a` flag selects all jobs, `-r` selects all running jobs, and `-h` specifies to mark
 /// SIGHUP ignoral.
-pub fn disown(shell: &mut Shell, args: &[&str]) -> i32 {
+pub(crate) fn disown(shell: &mut Shell, args: &[&str]) -> i32 {
     let stderr = stderr();
     let mut stderr = stderr.lock();
     const NO_SIGHUP: u8 = 1;
@@ -75,7 +75,7 @@ pub fn disown(shell: &mut Shell, args: &[&str]) -> i32 {
 }
 
 /// Display a list of all jobs running in the background.
-pub fn jobs(shell: &mut Shell) {
+pub(crate) fn jobs(shell: &mut Shell) {
     let stderr = stderr();
     let mut stderr = stderr.lock();
     for (id, process) in shell.background.lock().unwrap().iter().enumerate() {
@@ -89,7 +89,7 @@ pub fn jobs(shell: &mut Shell) {
 /// Hands control of the foreground process to the specified jobs, recording their exit status.
 /// If the job is stopped, the job will be resumed.
 /// If multiple jobs are given, then only the last job's exit status will be returned.
-pub fn fg(shell: &mut Shell, args: &[&str]) -> i32 {
+pub(crate) fn fg(shell: &mut Shell, args: &[&str]) -> i32 {
     fn fg_job(shell: &mut Shell, njob: u32) -> i32 {
         let job;
         if let Some(borrowed_job) = shell.background.lock().unwrap().iter().nth(njob as usize) {
@@ -140,7 +140,7 @@ pub fn fg(shell: &mut Shell, args: &[&str]) -> i32 {
 }
 
 /// Resumes a stopped background process, if it was stopped.
-pub fn bg(shell: &mut Shell, args: &[&str]) -> i32 {
+pub(crate) fn bg(shell: &mut Shell, args: &[&str]) -> i32 {
     fn bg_job(shell: &mut Shell, njob: u32) -> bool {
         if let Some(job) = shell.background.lock().unwrap().iter_mut().nth(njob as usize) {
             match job.state {
diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs
index b03f72ca33feb3a617935ecceb33f2c2b21d44bf..c69f4f11ca4e268b930c5c5c2679984c66ecac12 100644
--- a/src/builtins/mod.rs
+++ b/src/builtins/mod.rs
@@ -33,7 +33,7 @@ use sys;
 /// Structure which represents a Terminal's command.
 /// This command structure contains a name, and the code which run the
 /// functionnality associated to this one, with zero, one or several argument(s).
-pub struct Builtin {
+pub(crate) struct Builtin {
     pub name: &'static str,
     pub help: &'static str,
     pub main: fn(&[&str], &mut Shell) -> i32,
@@ -41,7 +41,7 @@ pub struct Builtin {
 
 impl Builtin {
     /// Return the map from command names to commands
-    pub fn map() -> FnvHashMap<&'static str, Self> {
+    pub(crate) fn map() -> FnvHashMap<&'static str, Self> {
         let mut commands: FnvHashMap<&str, Self> =
             FnvHashMap::with_capacity_and_hasher(32, Default::default());
 
diff --git a/src/builtins/set.rs b/src/builtins/set.rs
index 6f04735b2437c2fe22cbd2e54735d058b782cad9..607b72f2dddcc635f402b4488077223e81684f7d 100644
--- a/src/builtins/set.rs
+++ b/src/builtins/set.rs
@@ -35,7 +35,7 @@ enum PositionalArgs {
 
 use self::PositionalArgs::*;
 
-pub fn set(args: &[&str], shell: &mut Shell) -> i32 {
+pub(crate) fn set(args: &[&str], shell: &mut Shell) -> i32 {
     let stdout = io::stdout();
     let stderr = io::stderr();
     let mut args_iter = args.iter();
diff --git a/src/builtins/source.rs b/src/builtins/source.rs
index 4ae4517490e542d0d6c8e47ed5e28aa4b2dc56ea..8bf58147a7c64616d11800b5253a583ae28501c7 100644
--- a/src/builtins/source.rs
+++ b/src/builtins/source.rs
@@ -3,7 +3,7 @@ use std::fs::File;
 use std::io::Read;
 
 /// Evaluates the given file and returns 'SUCCESS' if it succeeds.
-pub fn source(shell: &mut Shell, arguments: &[&str]) -> Result<(), String> {
+pub(crate) fn source(shell: &mut Shell, arguments: &[&str]) -> Result<(), String> {
     match arguments.get(1) {
         Some(argument) => if let Ok(mut file) = File::open(&argument) {
             let capacity = file.metadata().map(|x| x.len()).unwrap_or(0) as usize;
diff --git a/src/builtins/test.rs b/src/builtins/test.rs
index db5c761e58ec5a7cdb29da8efb5fc9ce5fa213d9..e8d4b63b9d49e26b8dcef1101f6c98e770f453e7 100644
--- a/src/builtins/test.rs
+++ b/src/builtins/test.rs
@@ -111,7 +111,7 @@ AUTHOR
     Written by Michael Murphy.
 "#; // @MANEND
 
-pub fn test(args: &[&str]) -> Result<bool, String> {
+pub(crate) fn test(args: &[&str]) -> Result<bool, String> {
     let stdout = io::stdout();
     let mut buffer = BufWriter::new(stdout.lock());
 
diff --git a/src/builtins/time.rs b/src/builtins/time.rs
index 9a6455037e2557c529584f98492486bee637ee58..5b73b28ae147d1fc8d6e4e1364b84f94d199dca5 100644
--- a/src/builtins/time.rs
+++ b/src/builtins/time.rs
@@ -18,7 +18,7 @@ OPTIONS
         display this help and exit
 "#;
 
-pub fn time(args: &[&str]) -> Result<(), String> {
+pub(crate) fn time(args: &[&str]) -> Result<(), String> {
     let stdout = stdout();
     let mut stdout = stdout.lock();
 
diff --git a/src/builtins/variables.rs b/src/builtins/variables.rs
index f1f8237f8f2ed736d8256dfe2a9baea8ad696d5a..c18753fde4038be7f131ecb6fa67ad2b280cb2e6 100644
--- a/src/builtins/variables.rs
+++ b/src/builtins/variables.rs
@@ -112,7 +112,7 @@ fn parse_alias(args: &str) -> Binding {
 
 /// The `alias` command will define an alias for another command, and thus may be used as a
 /// command itself.
-pub fn alias(vars: &mut Variables, args: &str) -> i32 {
+pub(crate) fn alias(vars: &mut Variables, args: &str) -> i32 {
     match parse_alias(args) {
         Binding::InvalidKey(key) => {
             let stderr = io::stderr();
@@ -139,7 +139,7 @@ pub fn alias(vars: &mut Variables, args: &str) -> i32 {
 
 
 /// Dropping an alias will erase it from the shell.
-pub fn drop_alias<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
+pub(crate) fn drop_alias<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
     where I::Item: AsRef<str>
 {
     let args = args.into_iter().collect::<Vec<I::Item>>();
@@ -159,7 +159,7 @@ pub fn drop_alias<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
 }
 
 /// Dropping an array will erase it from the shell.
-pub fn drop_array<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
+pub(crate) fn drop_array<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
     where I::Item: AsRef<str>
 {
     let args = args.into_iter().collect::<Vec<I::Item>>();
@@ -186,7 +186,7 @@ pub fn drop_array<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
 }
 
 /// Dropping a variable will erase it from the shell.
-pub fn drop_variable<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
+pub(crate) fn drop_variable<I: IntoIterator>(vars: &mut Variables, args: I) -> i32
     where I::Item: AsRef<str>
 {
     let args = args.into_iter().collect::<Vec<I::Item>>();
diff --git a/src/parser/arguments.rs b/src/parser/arguments.rs
index 1a1a5800f777f5d765779556941abd2d4e61425e..32c4886cb2a1bad8489a088237a5cd4cc811fe75 100644
--- a/src/parser/arguments.rs
+++ b/src/parser/arguments.rs
@@ -8,14 +8,14 @@ const ARRAY: u8 = 64;
 const METHOD: u8 = 128;
 
 /// An efficient `Iterator` structure for splitting arguments
-pub struct ArgumentSplitter<'a> {
+pub(crate) struct ArgumentSplitter<'a> {
     data:  &'a str,
     read:  usize,
     flags: u8,
 }
 
 impl<'a> ArgumentSplitter<'a> {
-    pub fn new(data: &'a str) -> ArgumentSplitter<'a> {
+    pub(crate) fn new(data: &'a str) -> ArgumentSplitter<'a> {
         ArgumentSplitter {
             data:  data,
             read:  0,
diff --git a/src/parser/assignments/actions.rs b/src/parser/assignments/actions.rs
index 418921aa7325234820e8b9d4d7dc8828645dcc6f..73766f47c042d4a405b55c2ecda69e1e1ab990c3 100644
--- a/src/parser/assignments/actions.rs
+++ b/src/parser/assignments/actions.rs
@@ -4,7 +4,7 @@ use super::super::ArgumentSplitter;
 use std::fmt::{self, Display, Formatter};
 
 #[derive(Debug, PartialEq)]
-pub enum AssignmentError<'a> {
+pub(crate) enum AssignmentError<'a> {
     NoKeys,
     NoOperator,
     NoValues,
@@ -33,7 +33,7 @@ impl<'a> Display for AssignmentError<'a> {
 ///
 /// Each request will tell the shell whether the assignment is asking to update an array or a
 /// string, and will contain the key/value pair to assign.
-pub struct AssignmentActions<'a> {
+pub(crate) struct AssignmentActions<'a> {
     keys:     KeyIterator<'a>,
     operator: Operator,
     values:   ArgumentSplitter<'a>,
@@ -42,7 +42,7 @@ pub struct AssignmentActions<'a> {
 }
 
 impl<'a> AssignmentActions<'a> {
-    pub fn new(data: &'a str) -> Result<AssignmentActions<'a>, AssignmentError<'a>> {
+    pub(crate) fn new(data: &'a str) -> Result<AssignmentActions<'a>, AssignmentError<'a>> {
         let (keys, op, vals) = split_assignment(data);
         Ok(AssignmentActions {
             keys:     keys.map(KeyIterator::new).ok_or(AssignmentError::NoKeys)?,
@@ -88,7 +88,7 @@ impl<'a> Iterator for AssignmentActions<'a> {
 /// Providing the key/value pair and operator to use during assignment, this variant defines
 /// whether the assignment should set a string or array.
 #[derive(Debug, PartialEq)]
-pub enum Action<'a> {
+pub(crate) enum Action<'a> {
     UpdateString(Key<'a>, Operator, &'a str),
     UpdateArray(Key<'a>, Operator, &'a str),
 }
diff --git a/src/parser/assignments/checker.rs b/src/parser/assignments/checker.rs
index 2d0fc19a8f1351193a2c513de00b6b30cc4284a5..ad919bc7630cd1d2d8be0d1ec5e635eb7ce01285 100644
--- a/src/parser/assignments/checker.rs
+++ b/src/parser/assignments/checker.rs
@@ -7,9 +7,9 @@ use super::super::expand_string;
 /// - `[ 1 2 3 ]` = Array
 /// - `[ 1 2 3 ][1]` = String
 /// - `string` = String
-pub fn is_array(value: &str) -> bool { value.starts_with('[') && value.ends_with(']') }
+pub(crate) fn is_array(value: &str) -> bool { value.starts_with('[') && value.ends_with(']') }
 
-pub fn is_boolean(value: &str) -> Result<&str, ()> {
+pub(crate) fn is_boolean(value: &str) -> Result<&str, ()> {
     if ["true", "1", "y"].contains(&value) {
         Ok("true")
     } else if ["false", "0", "n"].contains(&value) {
@@ -108,7 +108,7 @@ fn get_array<E: Expander>(shell: &E, value: &str) -> ReturnValue {
     ReturnValue::Vector(expand_string(value, shell, false))
 }
 
-pub fn value_check<'a, E: Expander>(
+pub(crate) fn value_check<'a, E: Expander>(
     shell: &E,
     value: &'a str,
     expected: Primitive,
diff --git a/src/parser/assignments/keys.rs b/src/parser/assignments/keys.rs
index 9919b124447adac2098148a31a3142f69b03dd9f..d227b96e423b16a3afcff9e39e630db2f15d1b4a 100644
--- a/src/parser/assignments/keys.rs
+++ b/src/parser/assignments/keys.rs
@@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
 /// Keys are used in assignments to define which variable will be set, and whether the correct
 /// types are being assigned.
 #[derive(Debug, PartialEq, Clone)]
-pub struct Key<'a> {
+pub(crate) struct Key<'a> {
     pub kind: Primitive,
     pub name: &'a str,
 }
@@ -11,14 +11,14 @@ pub struct Key<'a> {
 /// Functions require that their keys to have a longer lifetime, and that is made possible
 /// by eliminating the lifetime requirements via allocating a `String`.
 #[derive(Debug, PartialEq, Clone)]
-pub struct KeyBuf {
+pub(crate) struct KeyBuf {
     pub kind: Primitive,
     pub name: String,
 }
 
 
 #[derive(Debug, PartialEq)]
-pub enum TypeError<'a> {
+pub(crate) enum TypeError<'a> {
     Invalid(&'a str),
     BadValue(Primitive),
 }
@@ -52,7 +52,7 @@ impl<'a> From<Key<'a>> for KeyBuf {
 
 /// A primitive defines the type that a requested value should satisfy.
 #[derive(Debug, PartialEq, Copy, Clone)]
-pub enum Primitive {
+pub(crate) enum Primitive {
     Any,
     AnyArray,
     Str,
@@ -101,13 +101,13 @@ impl Display for Primitive {
 
 /// Quite simply, an iterator that returns keys.
 #[derive(Debug, PartialEq)]
-pub struct KeyIterator<'a> {
+pub(crate) struct KeyIterator<'a> {
     data: &'a str,
     read: usize,
 }
 
 impl<'a> KeyIterator<'a> {
-    pub fn new(data: &'a str) -> KeyIterator<'a> { KeyIterator { data, read: 0 } }
+    pub(crate) fn new(data: &'a str) -> KeyIterator<'a> { KeyIterator { data, read: 0 } }
 
     // Parameters are values that follow the semicolon (':').
     fn parse_parameter(&mut self, name: &'a str) -> Result<Key<'a>, TypeError<'a>> {
diff --git a/src/parser/assignments/mod.rs b/src/parser/assignments/mod.rs
index 9ccbbbbca9c3795256f07e8e651703c186b66886..fc2e24c014d08e9bc1304bc229ca7eeab6c60a11 100644
--- a/src/parser/assignments/mod.rs
+++ b/src/parser/assignments/mod.rs
@@ -4,16 +4,16 @@ mod splitter;
 mod keys;
 mod operator;
 
-pub use self::actions::{Action, AssignmentActions, AssignmentError};
-pub use self::checker::{is_array, is_boolean, value_check};
-pub use self::keys::{Key, KeyBuf, KeyIterator, Primitive, TypeError};
-pub use self::operator::Operator;
-pub use self::splitter::split_assignment;
+pub(crate) use self::actions::{Action, AssignmentActions, AssignmentError};
+pub(crate) use self::checker::{is_array, value_check};
+pub(crate) use self::keys::{Key, KeyBuf, KeyIterator, Primitive, TypeError};
+pub(crate) use self::operator::Operator;
+pub(crate) use self::splitter::split_assignment;
 
 use types::{Array, Value};
 
 #[derive(Debug, PartialEq)]
-pub enum ReturnValue {
+pub(crate) enum ReturnValue {
     Str(Value),
     Vector(Array),
 }
diff --git a/src/parser/assignments/operator.rs b/src/parser/assignments/operator.rs
index ca35ef2938add56e52680c61a5469bb00daf7bf6..230ff77545037f832bc8adf533123b4fa87e7b84 100644
--- a/src/parser/assignments/operator.rs
+++ b/src/parser/assignments/operator.rs
@@ -2,7 +2,7 @@ use super::AssignmentError;
 use std::fmt::{self, Display, Formatter};
 
 #[derive(Debug, PartialEq, Clone, Copy)]
-pub enum Operator {
+pub(crate) enum Operator {
     Add,
     Subtract,
     Divide,
@@ -13,7 +13,7 @@ pub enum Operator {
 }
 
 impl Operator {
-    pub fn parse<'a>(data: &'a str) -> Result<Operator, AssignmentError<'a>> {
+    pub(crate) fn parse<'a>(data: &'a str) -> Result<Operator, AssignmentError<'a>> {
         match data {
             "=" => Ok(Operator::Equal),
             "+=" => Ok(Operator::Add),
diff --git a/src/parser/assignments/splitter.rs b/src/parser/assignments/splitter.rs
index ba46769088f1bc8f42e8574258dc5c782503d243..f68a1c0823ec123f253d1e62c465493f4c6c81e6 100644
--- a/src/parser/assignments/splitter.rs
+++ b/src/parser/assignments/splitter.rs
@@ -1,5 +1,5 @@
 /// Given an valid assignment expression, this will split it into `keys`, `operator`, `values`.
-pub fn split_assignment<'a>(
+pub(crate) fn split_assignment<'a>(
     statement: &'a str,
 ) -> (Option<&'a str>, Option<&'a str>, Option<&'a str>) {
     let statement = statement.trim();
diff --git a/src/parser/loops/for_grammar.rs b/src/parser/loops/for_grammar.rs
index 35bb2c50a36f278451345532405a72296652ea9b..58a3c8bfcdcd40392029e3d2d182e5e21feabf38 100644
--- a/src/parser/loops/for_grammar.rs
+++ b/src/parser/loops/for_grammar.rs
@@ -2,14 +2,14 @@ use parser::{expand_string, Expander};
 use types::Value;
 
 #[derive(Debug, PartialEq)]
-pub enum ForExpression {
+pub(crate) enum ForExpression {
     Multiple(Vec<Value>),
     Normal(Value),
     Range(usize, usize),
 }
 
 impl ForExpression {
-    pub fn new<E: Expander>(expression: &[String], expanders: &E) -> ForExpression {
+    pub(crate) fn new<E: Expander>(expression: &[String], expanders: &E) -> ForExpression {
         let output: Vec<_> = expression
             .iter()
             .flat_map(|expression| expand_string(expression, expanders, true))
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 7e4bcf20a2c8b91d1e335bf8771f5448091e1fa0..acc4c66fdc681cea154a09d3bf4b97301b2dc3c4 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -6,8 +6,8 @@ pub mod shell_expand;
 mod statement;
 mod quotes;
 
-pub use self::arguments::ArgumentSplitter;
-pub use self::loops::for_grammar::ForExpression;
-pub use self::quotes::QuoteTerminator;
-pub use self::shell_expand::{expand_string, expand_tokens, Expander, Index, Range, Select, WordIterator, WordToken};
-pub use self::statement::{parse_and_validate, StatementError, StatementSplitter};
+pub(crate) use self::arguments::ArgumentSplitter;
+pub(crate) use self::loops::for_grammar::ForExpression;
+pub(crate) use self::quotes::QuoteTerminator;
+pub(crate) use self::shell_expand::{expand_string, Expander, Select};
+pub(crate) use self::statement::{parse_and_validate, StatementSplitter};
diff --git a/src/parser/pipelines/collector.rs b/src/parser/pipelines/collector.rs
index 23680684f05989dfafd3f1ad15999d32bd3c1692..89af7acc8228c4741535f65e1c2058f2128af11c 100644
--- a/src/parser/pipelines/collector.rs
+++ b/src/parser/pipelines/collector.rs
@@ -7,7 +7,7 @@ use super::{Input, Pipeline, RedirectFrom, Redirection};
 use shell::{Job, JobKind};
 use types::*;
 
-pub struct Collector<'a> {
+pub(crate) struct Collector<'a> {
     data: &'a str,
 }
 
@@ -17,9 +17,9 @@ lazy_static! {
 }
 
 impl<'a> Collector<'a> {
-    pub fn new(data: &'a str) -> Self { Collector { data } }
+    pub(crate) fn new(data: &'a str) -> Self { Collector { data } }
 
-    pub fn run(data: &'a str) -> Result<Pipeline, &'static str> { Collector::new(data).parse() }
+    pub(crate) fn run(data: &'a str) -> Result<Pipeline, &'static str> { Collector::new(data).parse() }
 
     fn peek(&self, index: usize) -> Option<u8> {
         if index < self.data.len() {
@@ -195,7 +195,7 @@ impl<'a> Collector<'a> {
         }
     }
 
-    pub fn parse(&self) -> Result<Pipeline, &'static str> {
+    pub(crate) fn parse(&self) -> Result<Pipeline, &'static str> {
         let mut bytes = self.data.bytes().enumerate().peekable();
         let mut args = Array::new();
         let mut jobs: Vec<Job> = Vec::new();
diff --git a/src/parser/pipelines/mod.rs b/src/parser/pipelines/mod.rs
index bf69db40f1a20ce98c3f6734581a77d3e1505948..09941aef6b6585b88674918e74447796cfec74df 100644
--- a/src/parser/pipelines/mod.rs
+++ b/src/parser/pipelines/mod.rs
@@ -1,20 +1,20 @@
 mod collector;
 
-pub use self::collector::*;
+pub(crate) use self::collector::*;
 
 use super::{expand_string, Expander};
 use shell::{Job, JobKind};
 use std::fmt;
 
 #[derive(Debug, PartialEq, Clone, Copy)]
-pub enum RedirectFrom {
+pub(crate) enum RedirectFrom {
     Stdout,
     Stderr,
     Both,
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct Redirection {
+pub(crate) struct Redirection {
     pub from:   RedirectFrom,
     pub file:   String,
     pub append: bool,
@@ -22,7 +22,7 @@ pub struct Redirection {
 
 /// Represents input that a process could initially receive from `stdin`
 #[derive(Debug, PartialEq, Clone)]
-pub enum Input {
+pub(crate) enum Input {
     /// A file; the contents of said file will be written to the `stdin` of a process
     File(String),
     /// A string literal that is written to the `stdin` of a process.
@@ -31,14 +31,14 @@ pub enum Input {
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct Pipeline {
+pub(crate) struct Pipeline {
     pub jobs:   Vec<Job>,
     pub stdout: Option<Redirection>,
     pub stdin:  Option<Input>,
 }
 
 impl Pipeline {
-    pub fn new(jobs: Vec<Job>, stdin: Option<Input>, stdout: Option<Redirection>) -> Self {
+    pub(crate) fn new(jobs: Vec<Job>, stdin: Option<Input>, stdout: Option<Redirection>) -> Self {
         Pipeline {
             jobs,
             stdin,
@@ -46,7 +46,7 @@ impl Pipeline {
         }
     }
 
-    pub fn expand<E: Expander>(&mut self, expanders: &E) {
+    pub(crate) fn expand<E: Expander>(&mut self, expanders: &E) {
         for job in &mut self.jobs {
             job.expand(expanders);
         }
@@ -68,7 +68,7 @@ impl Pipeline {
         }
     }
 
-    pub fn requires_piping(&self) -> bool {
+    pub(crate) fn requires_piping(&self) -> bool {
         self.jobs.len() > 1 || self.stdin != None || self.stdout != None ||
             self.jobs.last().unwrap().kind == JobKind::Background
     }
diff --git a/src/parser/quotes.rs b/src/parser/quotes.rs
index 5a13bd45c84a62b85a1c2c861eb6bad58f73cc93..27e541abcc49584c4d3149f2b4e99375eb8b6cbf 100644
--- a/src/parser/quotes.rs
+++ b/src/parser/quotes.rs
@@ -7,7 +7,7 @@ bitflags! {
     }
 }
 
-pub struct QuoteTerminator {
+pub(crate) struct QuoteTerminator {
     buffer:     String,
     eof:        Option<String>,
     eof_buffer: String,
@@ -16,7 +16,7 @@ pub struct QuoteTerminator {
 }
 
 impl QuoteTerminator {
-    pub fn new(input: String) -> QuoteTerminator {
+    pub(crate) fn new(input: String) -> QuoteTerminator {
         QuoteTerminator {
             buffer:     input,
             eof:        None,
@@ -26,7 +26,7 @@ impl QuoteTerminator {
         }
     }
 
-    pub fn append(&mut self, input: String) {
+    pub(crate) fn append(&mut self, input: String) {
         if self.eof.is_none() {
             self.buffer.push_str(if self.flags.contains(TRIM) { input.trim() } else { &input });
         } else {
@@ -34,7 +34,7 @@ impl QuoteTerminator {
         }
     }
 
-    pub fn check_termination(&mut self) -> bool {
+    pub(crate) fn check_termination(&mut self) -> bool {
         let mut eof_line = None;
         let eof = self.eof.clone();
         let status = if let Some(ref eof) = eof {
@@ -119,5 +119,5 @@ impl QuoteTerminator {
         status
     }
 
-    pub fn consume(self) -> String { self.buffer }
+    pub(crate) fn consume(self) -> String { self.buffer }
 }
diff --git a/src/parser/shell_expand/braces.rs b/src/parser/shell_expand/braces.rs
index 942066075546ec44698cfbf02db1f1e522616766..35dd1d9d1d7c0df52839d7aeae45e9de0680dc3e 100644
--- a/src/parser/shell_expand/braces.rs
+++ b/src/parser/shell_expand/braces.rs
@@ -2,12 +2,12 @@ use super::permutate::Permutator;
 
 #[derive(Debug)]
 /// A token primitive for the `expand_braces` function.
-pub enum BraceToken {
+pub(crate) enum BraceToken {
     Normal(String),
     Expander,
 }
 
-pub fn expand_braces(tokens: &[BraceToken], mut expanders: Vec<Vec<String>>) -> Vec<String> {
+pub(crate) fn expand_braces(tokens: &[BraceToken], mut expanders: Vec<Vec<String>>) -> Vec<String> {
     if expanders.len() > 1 {
         let tmp: Vec<Vec<&str>> = expanders
             .iter()
diff --git a/src/parser/shell_expand/mod.rs b/src/parser/shell_expand/mod.rs
index ce576f2076a1d2736203d5e1000876a8a9702330..d804687dd61bec42371463993b8822c892b01062 100644
--- a/src/parser/shell_expand/mod.rs
+++ b/src/parser/shell_expand/mod.rs
@@ -10,20 +10,20 @@ mod ranges;
 mod words;
 use self::braces::BraceToken;
 use self::ranges::parse_range;
-pub use self::words::{Index, Range, Select, WordIterator, WordToken};
+pub(crate) use self::words::{Index, Range, Select, WordIterator, WordToken};
 use glob::glob;
 use types::*;
 
 /// Determines whether an input string is expression-like as compared to a
 /// bare word. For example, strings starting with '"', '\'', '@', or '$' are
 /// all expressions
-pub fn is_expression(s: &str) -> bool {
+pub(crate) fn is_expression(s: &str) -> bool {
     s.starts_with('@') || s.starts_with('[') || s.starts_with('$') || s.starts_with('"') ||
         s.starts_with('\'')
 }
 
 /// Trait representing different elements of string expansion
-pub trait Expander {
+pub(crate) trait Expander {
     /// Expand a tilde form to the correct directory
     fn tilde(&self, &str) -> Option<String> { None }
     /// Expand an array variable with some selection
@@ -145,7 +145,7 @@ fn slice<S: AsRef<str>>(output: &mut String, expanded: S, selection: Select) {
 /// Performs shell expansions to an input string, efficiently returning the final
 /// expanded form. Shells must provide their own batteries for expanding tilde
 /// and variable words.
-pub fn expand_string<E: Expander>(original: &str, expand_func: &E, reverse_quoting: bool) -> Array {
+pub(crate) fn expand_string<E: Expander>(original: &str, expand_func: &E, reverse_quoting: bool) -> Array {
     let mut token_buffer = Vec::new();
     let mut contains_brace = false;
 
@@ -160,7 +160,7 @@ pub fn expand_string<E: Expander>(original: &str, expand_func: &E, reverse_quoti
 }
 
 #[allow(cyclomatic_complexity)]
-pub fn expand_tokens<E: Expander>(
+pub(crate) fn expand_tokens<E: Expander>(
     token_buffer: &[WordToken],
     expand_func: &E,
     reverse_quoting: bool,
diff --git a/src/parser/shell_expand/ranges.rs b/src/parser/shell_expand/ranges.rs
index 92fcb5f55fac6ce62a4c9e2af76c972c0ed41619..b755f5c2a7f95259afa5452bb5c957a746d1e624 100644
--- a/src/parser/shell_expand/ranges.rs
+++ b/src/parser/shell_expand/ranges.rs
@@ -117,7 +117,7 @@ fn strings_to_isizes(a: &str, b: &str) -> Option<(isize, isize)> {
 //      Inclusive nonstepped: {start...end}
 //      Exclusive stepped: {start..step..end}
 //      Inclusive stepped: {start..step...end}
-pub fn parse_range(input: &str) -> Option<Vec<String>> {
+pub(crate) fn parse_range(input: &str) -> Option<Vec<String>> {
     let mut read = 0;
     let mut bytes_iterator = input.bytes();
     while let Some(byte) = bytes_iterator.next() {
@@ -223,7 +223,7 @@ pub fn parse_range(input: &str) -> Option<Vec<String>> {
     None
 }
 
-pub fn parse_index_range(input: &str) -> Option<Range> {
+pub(crate) fn parse_index_range(input: &str) -> Option<Range> {
     let mut bytes_iterator = input.bytes().enumerate();
     while let Some((id, byte)) = bytes_iterator.next() {
         match byte {
diff --git a/src/parser/shell_expand/words.rs b/src/parser/shell_expand/words.rs
index 336981dab72c9f10f6a6fa2e9ca98c49c6927040..fb80d3b0071a734dae395612f669a91e3bc14c32 100644
--- a/src/parser/shell_expand/words.rs
+++ b/src/parser/shell_expand/words.rs
@@ -36,7 +36,7 @@ bitflags! {
 
 /// Index into a vector-like object
 #[derive(Debug, PartialEq, Copy, Clone)]
-pub enum Index {
+pub(crate) enum Index {
     /// Index starting from the beginning of the vector, where `Forward(0)`
     /// is the first element
     Forward(usize),
@@ -52,7 +52,7 @@ impl Index {
     /// ```
     /// assert_eq!(Index::new(-1), Index::Backward(0))
     /// ```
-    pub fn new(input: isize) -> Index {
+    pub(crate) fn new(input: isize) -> Index {
         if input < 0 {
             Index::Backward((input.abs() as usize) - 1)
         } else {
@@ -60,7 +60,7 @@ impl Index {
         }
     }
 
-    pub fn resolve(&self, vector_length: usize) -> Option<usize> {
+    pub(crate) fn resolve(&self, vector_length: usize) -> Option<usize> {
         match *self {
             Index::Forward(n) => Some(n),
             Index::Backward(n) => if n >= vector_length {
@@ -74,7 +74,7 @@ impl Index {
 
 /// A range of values in a vector-like object
 #[derive(Debug, PartialEq, Copy, Clone)]
-pub struct Range {
+pub(crate) struct Range {
     /// Starting index
     start: Index,
     /// Ending index
@@ -85,7 +85,7 @@ pub struct Range {
 }
 
 impl Range {
-    pub fn to(end: Index) -> Range {
+    pub(crate) fn to(end: Index) -> Range {
         Range {
             start: Index::new(0),
             end,
@@ -93,7 +93,7 @@ impl Range {
         }
     }
 
-    pub fn from(start: Index) -> Range {
+    pub(crate) fn from(start: Index) -> Range {
         Range {
             start,
             end: Index::new(-1),
@@ -101,7 +101,7 @@ impl Range {
         }
     }
 
-    pub fn inclusive(start: Index, end: Index) -> Range {
+    pub(crate) fn inclusive(start: Index, end: Index) -> Range {
         Range {
             start,
             end,
@@ -109,7 +109,7 @@ impl Range {
         }
     }
 
-    pub fn exclusive(start: Index, end: Index) -> Range {
+    pub(crate) fn exclusive(start: Index, end: Index) -> Range {
         Range {
             start,
             end,
@@ -128,7 +128,7 @@ impl Range {
     /// let selection = vec.iter().skip(start).take(size).collect::<Vec<_>>();
     /// assert_eq!(expected, selection);
     /// ```
-    pub fn bounds(&self, vector_length: usize) -> Option<(usize, usize)> {
+    pub(crate) fn bounds(&self, vector_length: usize) -> Option<(usize, usize)> {
         if let Some(start) = self.start.resolve(vector_length) {
             if let Some(end) = self.end.resolve(vector_length) {
                 if end < start {
@@ -148,17 +148,17 @@ impl Range {
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct Key {
+pub(crate) struct Key {
     key: ::types::Key,
 }
 
 impl Key {
-    pub fn get(&self) -> &::types::Key { return &self.key; }
+    pub(crate) fn get(&self) -> &::types::Key { return &self.key; }
 }
 
 /// Represents a filter on a vector-like object
 #[derive(Debug, PartialEq, Clone)]
-pub enum Select {
+pub(crate) enum Select {
     /// Select no elements
     None,
     /// Select all elements
@@ -171,7 +171,7 @@ pub enum Select {
     Key(Key),
 }
 
-pub trait SelectWithSize {
+pub(crate) trait SelectWithSize {
     type Item;
     fn select<O>(&mut self, Select, usize) -> O
         where O: FromIterator<Self::Item>;
@@ -227,7 +227,7 @@ enum Pattern<'a> {
 
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct ArrayMethod<'a> {
+pub(crate) struct ArrayMethod<'a> {
     method:    &'a str,
     variable:  &'a str,
     pattern:   Pattern<'a>,
@@ -235,14 +235,14 @@ pub struct ArrayMethod<'a> {
 }
 
 impl<'a> ArrayMethod<'a> {
-    pub fn returns_array(&self) -> bool {
+    pub(crate) fn returns_array(&self) -> bool {
         match self.method {
             "split" | "chars" | "bytes" | "graphemes" => true,
             _ => false,
         }
     }
 
-    pub fn handle<E: Expander>(&self, current: &mut String, expand_func: &E) {
+    pub(crate) fn handle<E: Expander>(&self, current: &mut String, expand_func: &E) {
         match self.method {
             "split" => {
                 let variable = if let Some(variable) = expand_func.variable(self.variable, false) {
@@ -327,7 +327,7 @@ impl<'a> ArrayMethod<'a> {
         }
     }
 
-    pub fn handle_as_array<E: Expander>(&self, expand_func: &E) -> Array {
+    pub(crate) fn handle_as_array<E: Expander>(&self, expand_func: &E) -> Array {
         macro_rules! resolve_var {
             () => {
                 if let Some(variable) = expand_func.variable(self.variable, false) {
@@ -440,7 +440,7 @@ impl<'a> ArrayMethod<'a> {
 
 /// Represents a method that operates on and returns a string
 #[derive(Debug, PartialEq, Clone)]
-pub struct StringMethod<'a> {
+pub(crate) struct StringMethod<'a> {
     /// Name of this method: currently `join`, `len`, and `len_bytes` are the
     /// supported methods
     method: &'a str,
@@ -455,7 +455,7 @@ pub struct StringMethod<'a> {
 }
 
 impl<'a> StringMethod<'a> {
-    pub fn handle<E: Expander>(&self, output: &mut String, expand: &E) {
+    pub(crate) fn handle<E: Expander>(&self, output: &mut String, expand: &E) {
         let (variable, pattern) = (self.variable, self.pattern);
 
         macro_rules! string_eval {
@@ -634,7 +634,7 @@ impl<'a> StringMethod<'a> {
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub enum WordToken<'a> {
+pub(crate) enum WordToken<'a> {
     /// Represents a normal string who may contain a globbing character
     /// (the second element) or a tilde expression (the third element)
     Normal(&'a str, bool, bool),
@@ -651,7 +651,7 @@ pub enum WordToken<'a> {
     Arithmetic(&'a str), // Glob(&'a str)
 }
 
-pub struct WordIterator<'a, E: Expander + 'a> {
+pub(crate) struct WordIterator<'a, E: Expander + 'a> {
     data:      &'a str,
     read:      usize,
     flags:     Flags,
@@ -659,7 +659,7 @@ pub struct WordIterator<'a, E: Expander + 'a> {
 }
 
 impl<'a, E: Expander + 'a> WordIterator<'a, E> {
-    pub fn new(data: &'a str, expand_processes: bool, expanders: &'a E) -> WordIterator<'a, E> {
+    pub(crate) fn new(data: &'a str, expand_processes: bool, expanders: &'a E) -> WordIterator<'a, E> {
         let flags = if expand_processes { EXPAND_PROCESSES } else { Flags::empty() };
         WordIterator {
             data,
diff --git a/src/parser/statement/case.rs b/src/parser/statement/case.rs
index cd98f8d9b21602781735ee350ff9c794db5d8a96..d5193636f336947c4cd47cea6eb53ac77c2a8f6f 100644
--- a/src/parser/statement/case.rs
+++ b/src/parser/statement/case.rs
@@ -2,7 +2,7 @@ use super::super::ArgumentSplitter;
 use std::fmt::{self, Display, Formatter};
 
 #[derive(Debug, PartialEq)]
-pub enum CaseError<'a> {
+pub(crate) enum CaseError<'a> {
     NoBindVariable,
     NoConditional,
     ExtraBind(&'a str),
@@ -22,7 +22,7 @@ impl<'a> Display for CaseError<'a> {
     }
 }
 
-pub fn parse_case<'a>(
+pub(crate) fn parse_case<'a>(
     data: &'a str,
 ) -> Result<(Option<&'a str>, Option<&'a str>, Option<String>), CaseError<'a>> {
     let mut splitter = ArgumentSplitter::new(data);
diff --git a/src/parser/statement/functions.rs b/src/parser/statement/functions.rs
index bd6c6d7dd470e084a1c8e327cd06382c711d58e5..5a51c94ee797355965842bfaf78826314e58bf75 100644
--- a/src/parser/statement/functions.rs
+++ b/src/parser/statement/functions.rs
@@ -4,7 +4,7 @@ use super::super::assignments::{KeyBuf, KeyIterator, TypeError};
 /// The arguments expression given to a function declaration goes into here, which will be
 /// converted into a tuple consisting of a `KeyIterator` iterator, which will collect type
 /// information, and an optional description of the function.
-pub fn parse_function<'a>(arg: &'a str) -> (KeyIterator<'a>, Option<&'a str>) {
+pub(crate) fn parse_function<'a>(arg: &'a str) -> (KeyIterator<'a>, Option<&'a str>) {
     let (args, description) = split_pattern(arg, "--");
     (KeyIterator::new(args), description)
 }
@@ -13,7 +13,7 @@ pub fn parse_function<'a>(arg: &'a str) -> (KeyIterator<'a>, Option<&'a str>) {
 /// type error is detected, then that error will be returned instead. This is required because
 /// of lifetime restrictions on `KeyIterator`, which will not live for the remainder of the
 /// declared function's lifetime.
-pub fn collect_arguments<'a>(args: KeyIterator<'a>) -> Result<Vec<KeyBuf>, TypeError<'a>> {
+pub(crate) fn collect_arguments<'a>(args: KeyIterator<'a>) -> Result<Vec<KeyBuf>, TypeError<'a>> {
     // NOTE: Seems to be some kind of issue with Rust's compiler accepting this:
     //     Ok(args.map(|a| a.map(Into::into)?).collect::<Vec<_>>())
     // Seems to think that `a` is a `KeyBuf` when it's actually a `Result<Key, _>`.
diff --git a/src/parser/statement/mod.rs b/src/parser/statement/mod.rs
index e8065c231dabff499605dc31e9a80bfbe0eefe7c..5a464e46745f2969656414ea17d7fe32efa22e67 100644
--- a/src/parser/statement/mod.rs
+++ b/src/parser/statement/mod.rs
@@ -3,12 +3,12 @@ mod functions;
 mod parse;
 mod splitter;
 
-pub use self::parse::parse;
-pub use self::splitter::{StatementError, StatementSplitter};
+pub(crate) use self::parse::parse;
+pub(crate) use self::splitter::{StatementError, StatementSplitter};
 use shell::flow_control::Statement;
 
 /// Parses a given statement string and return's the corresponding mapped `Statement`
-pub fn parse_and_validate<'a>(statement: Result<&str, StatementError<'a>>) -> Statement {
+pub(crate) fn parse_and_validate<'a>(statement: Result<&str, StatementError<'a>>) -> Statement {
     match statement {
         Ok(statement) => parse(statement),
         Err(err) => {
@@ -21,7 +21,7 @@ pub fn parse_and_validate<'a>(statement: Result<&str, StatementError<'a>>) -> St
 /// Splits a string into two, based on a given pattern. We know that the first string will always
 /// exist, but if the pattern is not found, or no string follows the pattern, then the second
 /// string will not exist. Useful for splitting the function expression by the "--" pattern.
-pub fn split_pattern<'a>(arg: &'a str, pattern: &str) -> (&'a str, Option<&'a str>) {
+pub(crate) fn split_pattern<'a>(arg: &'a str, pattern: &str) -> (&'a str, Option<&'a str>) {
     match arg.find(pattern) {
         Some(pos) => {
             let args = &arg[..pos].trim();
diff --git a/src/parser/statement/parse.rs b/src/parser/statement/parse.rs
index b5be5e7298644241201c3e692a5c6ed5fb94362d..eff034cc9ba6366d7aac2a48c047b766a817213a 100644
--- a/src/parser/statement/parse.rs
+++ b/src/parser/statement/parse.rs
@@ -19,7 +19,7 @@ fn collect<F>(arguments: &str, statement: F) -> Statement
 
 fn is_valid_name(name: &str) -> bool { !name.chars().any(|c| !(c.is_alphanumeric() || c == '_')) }
 
-pub fn parse(code: &str) -> Statement {
+pub(crate) fn parse(code: &str) -> Statement {
     let cmd = code.trim();
     match cmd {
         "end" => return Statement::End,
diff --git a/src/parser/statement/splitter.rs b/src/parser/statement/splitter.rs
index 5c78c4aa664cd483a36bdb5e3597a73ef4c20d0e..724c8e174a14e7b3317f2453ffcd1be0d420edc9 100644
--- a/src/parser/statement/splitter.rs
+++ b/src/parser/statement/splitter.rs
@@ -24,7 +24,7 @@ bitflags! {
 
 
 #[derive(Debug, PartialEq)]
-pub enum StatementError<'a> {
+pub(crate) enum StatementError<'a> {
     IllegalCommandName(&'a str),
     InvalidCharacter(char, usize),
     UnterminatedSubshell,
@@ -65,7 +65,7 @@ impl<'a> Display for StatementError<'a> {
     }
 }
 
-pub struct StatementSplitter<'a> {
+pub(crate) struct StatementSplitter<'a> {
     data:                &'a str,
     read:                usize,
     flags:               Flags,
@@ -77,7 +77,7 @@ pub struct StatementSplitter<'a> {
 }
 
 impl<'a> StatementSplitter<'a> {
-    pub fn new(data: &'a str) -> StatementSplitter<'a> {
+    pub(crate) fn new(data: &'a str) -> StatementSplitter<'a> {
         StatementSplitter {
             data:                data,
             read:                0,
diff --git a/src/shell/assignments.rs b/src/shell/assignments.rs
index 3fd866274a7603fda692e1f6fd0152a870a227f9..06468bba37fdb62772ec25a468c79da0cf549cb1 100644
--- a/src/shell/assignments.rs
+++ b/src/shell/assignments.rs
@@ -45,7 +45,7 @@ fn print_arrays(list: &ArrayVariableContext) {
 
 /// Represents: A variable store capable of setting local variables or
 /// exporting variables to some global environment
-pub trait VariableStore {
+pub(crate) trait VariableStore {
     /// Set a local variable given a binding
     fn local(&mut self, &str) -> i32;
     /// Export a variable to the process environment given a binding
diff --git a/src/shell/binary.rs b/src/shell/binary.rs
index 3375c408df09bdbf50a8437e9e11c72fec85bc98..addcc4d8295758ab4dc64d0841256fe11fb23e3b 100644
--- a/src/shell/binary.rs
+++ b/src/shell/binary.rs
@@ -19,7 +19,7 @@ use std::process;
 use sys;
 use types::*;
 
-pub trait Binary {
+pub(crate) trait Binary {
     /// Launches the shell, parses arguments, and then diverges into one of the `execution`
     /// paths.
     fn main(self);
diff --git a/src/shell/colors.rs b/src/shell/colors.rs
index d768fc4a6b50e71bcbbb5d77557278ac180a3a54..d54857024583469f5334debf76cd309887b5984f 100644
--- a/src/shell/colors.rs
+++ b/src/shell/colors.rs
@@ -70,7 +70,7 @@ enum Mode {
 
 #[derive(Debug, PartialEq)]
 /// Stores a reprensetation of text formatting data which can be used to get an ANSI color code.
-pub struct Colors {
+pub(crate) struct Colors {
     foreground: Option<Mode>,
     background: Option<Mode>,
     attributes: Option<Vec<&'static str>>,
@@ -80,7 +80,7 @@ impl Colors {
     /// Parses the given input and returns a structure obtaining the text data needed for proper
     /// transformation into ANSI code parameters, which may be obtained by calling the
     /// `into_string()` method on the newly-created `Colors` structure.
-    pub fn collect(input: &str) -> Colors {
+    pub(crate) fn collect(input: &str) -> Colors {
         let mut colors = Colors {
             foreground: None,
             background: None,
@@ -179,7 +179,7 @@ impl Colors {
     /// Attempts to transform the data in the structure into the corresponding ANSI code
     /// representation. It would very ugly to require shell scripters to have to interface
     /// with these codes directly.
-    pub fn into_string(self) -> Option<String> {
+    pub(crate) fn into_string(self) -> Option<String> {
         let mut output = String::from("\x1b[");
 
         let foreground = match self.foreground {
diff --git a/src/shell/completer.rs b/src/shell/completer.rs
index ca05fbe1e3955326ffb2c9e21f201d1a77071625..1f8f37c717fd3c08fef998023590bc14060b5ccb 100644
--- a/src/shell/completer.rs
+++ b/src/shell/completer.rs
@@ -5,7 +5,7 @@ use liner::{Completer, FilenameCompleter};
 /// Performs escaping to an inner `FilenameCompleter` to enable a handful of special cases
 /// needed by the shell, such as expanding '~' to a home directory, or adding a backslash
 /// when a special character is contained within an expanded filename.
-pub struct IonFileCompleter {
+pub(crate) struct IonFileCompleter {
     /// The completer that this completer is  handling.
     inner: FilenameCompleter,
     /// A pointer to the directory stack in the shell.
@@ -15,7 +15,7 @@ pub struct IonFileCompleter {
 }
 
 impl IonFileCompleter {
-    pub fn new(
+    pub(crate) fn new(
         path: Option<&str>,
         dir_stack: *const DirectoryStack,
         vars: *const Variables,
@@ -142,7 +142,7 @@ fn unescape(input: &str) -> String {
 
 /// A completer that combines suggestions from multiple completers.
 #[derive(Clone, Eq, PartialEq)]
-pub struct MultiCompleter<A, B>
+pub(crate) struct MultiCompleter<A, B>
     where A: Completer,
           B: Completer
 {
@@ -154,7 +154,7 @@ impl<A, B> MultiCompleter<A, B>
     where A: Completer,
           B: Completer
 {
-    pub fn new(a: Vec<A>, b: B) -> MultiCompleter<A, B> { MultiCompleter { a: a, b: b } }
+    pub(crate) fn new(a: Vec<A>, b: B) -> MultiCompleter<A, B> { MultiCompleter { a: a, b: b } }
 }
 
 impl<A, B> Completer for MultiCompleter<A, B>
diff --git a/src/shell/directory_stack.rs b/src/shell/directory_stack.rs
index 0b712cf9f1018697fba98e196840cb8b699f282b..fa1cf29ac352a6dabb4fb08cf0468a8881efc643 100644
--- a/src/shell/directory_stack.rs
+++ b/src/shell/directory_stack.rs
@@ -5,13 +5,13 @@ use std::collections::VecDeque;
 use std::env::{current_dir, home_dir, set_current_dir};
 use std::path::PathBuf;
 
-pub struct DirectoryStack {
+pub(crate) struct DirectoryStack {
     dirs: VecDeque<PathBuf>, // The top is always the current directory
 }
 
 impl DirectoryStack {
     /// Create a new `DirectoryStack` containing the current working directory, if available.
-    pub fn new() -> DirectoryStack {
+    pub(crate) fn new() -> DirectoryStack {
         let mut dirs: VecDeque<PathBuf> = VecDeque::new();
         match current_dir() {
             Ok(curr_dir) => {
@@ -36,7 +36,7 @@ impl DirectoryStack {
 
     /// Attempts to set the current directory to the directory stack's previous directory,
     /// and then removes the front directory from the stack.
-    pub fn popd<I: IntoIterator>(&mut self, args: I) -> Result<(), Cow<'static, str>>
+    pub(crate) fn popd<I: IntoIterator>(&mut self, args: I) -> Result<(), Cow<'static, str>>
         where I::Item: AsRef<str>
     {
         let mut keep_front = false; // whether the -n option is present
@@ -94,7 +94,7 @@ impl DirectoryStack {
         Ok(())
     }
 
-    pub fn pushd<I: IntoIterator>(
+    pub(crate) fn pushd<I: IntoIterator>(
         &mut self,
         args: I,
         variables: &Variables,
@@ -157,7 +157,7 @@ impl DirectoryStack {
         Ok(())
     }
 
-    pub fn cd<I: IntoIterator>(
+    pub(crate) fn cd<I: IntoIterator>(
         &mut self,
         args: I,
         variables: &Variables,
@@ -209,7 +209,7 @@ impl DirectoryStack {
         }
     }
 
-    pub fn change_and_push_dir(
+    pub(crate) fn change_and_push_dir(
         &mut self,
         dir: &str,
         variables: &Variables,
@@ -239,7 +239,7 @@ impl DirectoryStack {
         self.dirs.truncate(DirectoryStack::get_size(variables));
     }
 
-    pub fn dirs<I: IntoIterator>(&mut self, args: I) -> i32
+    pub(crate) fn dirs<I: IntoIterator>(&mut self, args: I) -> i32
         where I::Item: AsRef<str>
     {
         const CLEAR: u8 = 1; // -c
@@ -308,9 +308,9 @@ impl DirectoryStack {
         SUCCESS
     }
 
-    pub fn dir_from_top(&self, num: usize) -> Option<&PathBuf> { self.dirs.get(num) }
+    pub(crate) fn dir_from_top(&self, num: usize) -> Option<&PathBuf> { self.dirs.get(num) }
 
-    pub fn dir_from_bottom(&self, num: usize) -> Option<&PathBuf> {
+    pub(crate) fn dir_from_bottom(&self, num: usize) -> Option<&PathBuf> {
         self.dirs.iter().rev().nth(num)
     }
 
diff --git a/src/shell/flags.rs b/src/shell/flags.rs
index e2a72ceddd7467196e31585f7ce78a6c31e93d34..7322416ec2bdec8974b879e29da48f7378c68efd 100644
--- a/src/shell/flags.rs
+++ b/src/shell/flags.rs
@@ -1,2 +1,2 @@
-pub const ERR_EXIT: u8 = 1;
-pub const PRINT_COMMS: u8 = 2;
+pub(crate) const ERR_EXIT: u8 = 1;
+pub(crate) const PRINT_COMMS: u8 = 2;
diff --git a/src/shell/flow.rs b/src/shell/flow.rs
index 254d476351e2eaebe2a82eec1788eee7f0411395..0c825b4049eeb7387c512ad172d8c127683180b9 100644
--- a/src/shell/flow.rs
+++ b/src/shell/flow.rs
@@ -11,14 +11,14 @@ use std::io::{self, stdout, Write};
 use std::mem;
 use types::Array;
 
-pub enum Condition {
+pub(crate) enum Condition {
     Continue,
     Break,
     NoOp,
     SigInt,
 }
 
-pub trait FlowLogic {
+pub(crate) trait FlowLogic {
     /// Receives a command and attempts to execute the contents.
     fn on_command(&mut self, command_string: &str);
 
diff --git a/src/shell/flow_control.rs b/src/shell/flow_control.rs
index 039b1b8a2066de6074a1e8ec2765fe4238e0c952..8144064b988682a65ad06fefa13a6db13a6a522e 100644
--- a/src/shell/flow_control.rs
+++ b/src/shell/flow_control.rs
@@ -7,7 +7,7 @@ use types::*;
 use types::Identifier;
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct ElseIf {
+pub(crate) struct ElseIf {
     pub expression: Pipeline,
     pub success:    Vec<Statement>,
 }
@@ -33,7 +33,7 @@ pub struct ElseIf {
 /// Case { value: None, ... }
 /// ```
 #[derive(Debug, PartialEq, Clone)]
-pub struct Case {
+pub(crate) struct Case {
     pub value:       Option<String>,
     pub binding:     Option<String>,
     pub conditional: Option<String>,
@@ -42,7 +42,7 @@ pub struct Case {
 
 // TODO: Enable statements and expressions to contain &str values.
 #[derive(Debug, PartialEq, Clone)]
-pub enum Statement {
+pub(crate) enum Statement {
     Let { expression: String },
     Case(Case),
     Export(String),
@@ -83,7 +83,7 @@ pub enum Statement {
 }
 
 impl Statement {
-    pub fn short(&self) -> &'static str {
+    pub(crate) fn short(&self) -> &'static str {
         match *self {
             Statement::Let { .. } => "Let { .. }",
             Statement::Case(_) => "Case { .. }",
@@ -106,7 +106,7 @@ impl Statement {
     }
 }
 
-pub struct FlowControl {
+pub(crate) struct FlowControl {
     pub level:             usize,
     pub current_statement: Statement,
     pub current_if_mode:   u8, // { 0 = SUCCESS; 1 = FAILURE }
@@ -123,20 +123,20 @@ impl Default for FlowControl {
 }
 
 #[derive(Clone)]
-pub struct Function {
+pub(crate) struct Function {
     pub description: Option<String>,
     pub name:        Identifier,
     pub args:        Vec<KeyBuf>,
     pub statements:  Vec<Statement>,
 }
 
-pub enum FunctionError {
+pub(crate) enum FunctionError {
     InvalidArgumentCount,
     InvalidArgumentType(Primitive, String),
 }
 
 impl Function {
-    pub fn execute(self, shell: &mut Shell, args: &[&str]) -> Result<(), FunctionError> {
+    pub(crate) fn execute(self, shell: &mut Shell, args: &[&str]) -> Result<(), FunctionError> {
         if args.len() - 1 != self.args.len() {
             return Err(FunctionError::InvalidArgumentCount);
         }
@@ -192,7 +192,7 @@ impl Function {
     }
 }
 
-pub fn collect_cases<I>(
+pub(crate) fn collect_cases<I>(
     iterator: &mut I,
     cases: &mut Vec<Case>,
     level: &mut usize,
@@ -255,7 +255,7 @@ pub fn collect_cases<I>(
     return Ok(());
 }
 
-pub fn collect_loops<I: Iterator<Item = Statement>>(
+pub(crate) fn collect_loops<I: Iterator<Item = Statement>>(
     iterator: &mut I,
     statements: &mut Vec<Statement>,
     level: &mut usize,
@@ -292,7 +292,7 @@ pub fn collect_loops<I: Iterator<Item = Statement>>(
     }
 }
 
-pub fn collect_if<I>(
+pub(crate) fn collect_if<I>(
     iterator: &mut I,
     success: &mut Vec<Statement>,
     else_if: &mut Vec<ElseIf>,
diff --git a/src/shell/history.rs b/src/shell/history.rs
index e3235ff33c59bbc1ad879380053203a4ba58e942..a3fb72fcfcf8cab85ebeda4e99eb492d9353b096 100644
--- a/src/shell/history.rs
+++ b/src/shell/history.rs
@@ -19,14 +19,14 @@ bitflags! {
     }
 }
 
-pub struct IgnoreSetting {
+pub(crate) struct IgnoreSetting {
     flags: IgnoreFlags,
     // Yes, a bad heap-based Vec, however unfortunately its not possible to store Regex'es in Array
     regexes: Option<Vec<Regex>>,
 }
 
 impl IgnoreSetting {
-    pub fn default() -> IgnoreSetting {
+    pub(crate) fn default() -> IgnoreSetting {
         IgnoreSetting {
             flags:   IgnoreFlags::empty(),
             regexes: None,
@@ -35,7 +35,7 @@ impl IgnoreSetting {
 }
 
 /// Contains all history-related functionality for the `Shell`.
-pub trait ShellHistory {
+pub(crate) trait ShellHistory {
     /// Prints the commands contained within the history buffers to standard output.
     fn print_history(&self, _arguments: &[&str]) -> i32;
 
diff --git a/src/shell/job.rs b/src/shell/job.rs
index fc493780a6c6f50fcf7a6ca7ea0992d2a8e75cfc..46c6c82c7ae0f24eba98cd50aa9806f9e8c3f039 100644
--- a/src/shell/job.rs
+++ b/src/shell/job.rs
@@ -10,7 +10,7 @@ use smallstring::SmallString;
 use types::*;
 
 #[derive(Debug, PartialEq, Clone, Copy)]
-pub enum JobKind {
+pub(crate) enum JobKind {
     And,
     Background,
     Last,
@@ -19,14 +19,14 @@ pub enum JobKind {
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct Job {
+pub(crate) struct Job {
     pub command: Identifier,
     pub args:    Array,
     pub kind:    JobKind,
 }
 
 impl Job {
-    pub fn new(args: Array, kind: JobKind) -> Self {
+    pub(crate) fn new(args: Array, kind: JobKind) -> Self {
         let command = SmallString::from_str(&args[0]);
         Job {
             command,
@@ -37,7 +37,7 @@ impl Job {
 
     /// Takes the current job's arguments and expands them, one argument at a
     /// time, returning a new `Job` with the expanded arguments.
-    pub fn expand<E: Expander>(&mut self, expanders: &E) {
+    pub(crate) fn expand<E: Expander>(&mut self, expanders: &E) {
         let mut expanded = Array::new();
         expanded.grow(self.args.len());
         expanded.extend(self.args.drain().flat_map(|arg| {
@@ -54,7 +54,7 @@ impl Job {
 
 /// This represents a job that has been processed and expanded to be run
 /// as part of some pipeline
-pub enum RefinedJob {
+pub(crate) enum RefinedJob {
     /// An external program that is executed by this shell
     External(Command),
     /// A procedure embedded into Ion
@@ -101,7 +101,7 @@ macro_rules! set_field {
 }
 
 impl RefinedJob {
-    pub fn builtin(name: Identifier, args: Array) -> Self {
+    pub(crate) fn builtin(name: Identifier, args: Array) -> Self {
         RefinedJob::Builtin {
             name,
             args,
@@ -111,7 +111,7 @@ impl RefinedJob {
         }
     }
 
-    pub fn function(name: Identifier, args: Array) -> Self {
+    pub(crate) fn function(name: Identifier, args: Array) -> Self {
         RefinedJob::Function {
             name,
             args,
@@ -121,21 +121,21 @@ impl RefinedJob {
         }
     }
 
-    pub fn stdin(&mut self, file: File) {
+    pub(crate) fn stdin(&mut self, file: File) {
         set_field!(self, stdin, file);
     }
 
-    pub fn stdout(&mut self, file: File) {
+    pub(crate) fn stdout(&mut self, file: File) {
         set_field!(self, stdout, file);
     }
 
-    pub fn stderr(&mut self, file: File) {
+    pub(crate) fn stderr(&mut self, file: File) {
         set_field!(self, stderr, file);
     }
 
     /// Returns a short description of this job: often just the command
     /// or builtin name
-    pub fn short(&self) -> String {
+    pub(crate) fn short(&self) -> String {
         match *self {
             RefinedJob::External(ref cmd) => {
                 format!("{:?}", cmd).split('"').nth(1).unwrap_or("").to_string()
@@ -147,7 +147,7 @@ impl RefinedJob {
     }
 
     /// Returns a long description of this job: the commands and arguments
-    pub fn long(&self) -> String {
+    pub(crate) fn long(&self) -> String {
         match *self {
             RefinedJob::External(ref cmd) => {
                 let command = format!("{:?}", cmd);
diff --git a/src/shell/mod.rs b/src/shell/mod.rs
index 3513b20c3231df6a1f48405f0d6ab1e733170ada..ab97e46ed99efe56072a170f2efab9a2eeb8095e 100644
--- a/src/shell/mod.rs
+++ b/src/shell/mod.rs
@@ -14,11 +14,11 @@ pub mod signals;
 pub mod status;
 pub mod variables;
 
-pub use self::binary::Binary;
-pub use self::flow::FlowLogic;
-pub use self::history::{IgnoreSetting, ShellHistory};
-pub use self::job::{Job, JobKind};
-pub use self::pipe_exec::{foreground, job_control};
+pub(crate) use self::binary::Binary;
+pub(crate) use self::flow::FlowLogic;
+pub(crate) use self::history::{IgnoreSetting, ShellHistory};
+pub(crate) use self::job::{Job, JobKind};
+pub(crate) use self::pipe_exec::{foreground, job_control};
 
 use self::directory_stack::DirectoryStack;
 use self::flags::*;
@@ -49,7 +49,7 @@ use types::*;
 /// the entirety of the
 /// program. It is initialized at the beginning of the program, and lives until the end of the
 /// program.
-pub struct Shell<'a> {
+pub(crate) struct Shell<'a> {
     /// Contains a list of built-in commands that were created when the program started.
     pub builtins: &'a FnvHashMap<&'static str, Builtin>,
     /// Contains the history, completions, and manages writes to the history file.
@@ -88,7 +88,7 @@ pub struct Shell<'a> {
 
 impl<'a> Shell<'a> {
     /// Panics if DirectoryStack construction fails
-    pub fn new(builtins: &'a FnvHashMap<&'static str, Builtin>) -> Shell<'a> {
+    pub(crate) fn new(builtins: &'a FnvHashMap<&'static str, Builtin>) -> Shell<'a> {
         Shell {
             builtins:            builtins,
             context:             None,
@@ -108,7 +108,7 @@ impl<'a> Shell<'a> {
         }
     }
 
-    pub fn next_signal(&self) -> Option<i32> {
+    pub(crate) fn next_signal(&self) -> Option<i32> {
         for sig in 0..32 {
             if signals::PENDING.fetch_and(!(1 << sig), Ordering::SeqCst) & (1 << sig) == 1 << sig {
                 return Some(sig);
@@ -118,7 +118,7 @@ impl<'a> Shell<'a> {
         None
     }
 
-    pub fn exit(&mut self, status: i32) -> ! {
+    pub(crate) fn exit(&mut self, status: i32) -> ! {
         if let Some(context) = self.context.as_mut() {
             context.history.commit_history();
         }
@@ -147,7 +147,7 @@ impl<'a> Shell<'a> {
     }
 
     /// Evaluates the source init file in the user's home directory.
-    pub fn evaluate_init_file(&mut self) {
+    pub(crate) fn evaluate_init_file(&mut self) {
         match app_root(
             AppDataType::UserConfig,
             &AppInfo {
diff --git a/src/shell/pipe_exec/foreground.rs b/src/shell/pipe_exec/foreground.rs
index 5738016f5597b0b2b83121d0d3eea549ad530fac..9a30b1b6b65616e41b801683d4501b84109e954a 100644
--- a/src/shell/pipe_exec/foreground.rs
+++ b/src/shell/pipe_exec/foreground.rs
@@ -2,7 +2,7 @@
 
 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
 
-pub enum BackgroundResult {
+pub(crate) enum BackgroundResult {
     Errored,
     Status(u8),
 }
@@ -11,7 +11,7 @@ pub enum BackgroundResult {
 /// communication between the shell and background threads. The `fg` command uses this
 /// structure to notify a background thread that it needs to wait for and return
 /// the exit status back to the `fg` function.
-pub struct ForegroundSignals {
+pub(crate) struct ForegroundSignals {
     grab:    AtomicUsize, // TODO: Use AtomicU32 when stable
     status:  AtomicUsize, // TODO: Use AtomicU8 when stable
     reply:   AtomicBool,
@@ -19,7 +19,7 @@ pub struct ForegroundSignals {
 }
 
 impl ForegroundSignals {
-    pub fn new() -> ForegroundSignals {
+    pub(crate) fn new() -> ForegroundSignals {
         ForegroundSignals {
             grab:    AtomicUsize::new(0),
             status:  AtomicUsize::new(0),
@@ -28,21 +28,21 @@ impl ForegroundSignals {
         }
     }
 
-    pub fn signal_to_grab(&self, pid: u32) { self.grab.store(pid as usize, Ordering::Relaxed); }
+    pub(crate) fn signal_to_grab(&self, pid: u32) { self.grab.store(pid as usize, Ordering::Relaxed); }
 
-    pub fn reply_with(&self, status: i8) {
+    pub(crate) fn reply_with(&self, status: i8) {
         self.grab.store(0, Ordering::Relaxed);
         self.status.store(status as usize, Ordering::Relaxed);
         self.reply.store(true, Ordering::Relaxed);
     }
 
-    pub fn errored(&self) {
+    pub(crate) fn errored(&self) {
         self.grab.store(0, Ordering::Relaxed);
         self.errored.store(true, Ordering::Relaxed);
         self.reply.store(true, Ordering::Relaxed);
     }
 
-    pub fn was_processed(&self) -> Option<BackgroundResult> {
+    pub(crate) fn was_processed(&self) -> Option<BackgroundResult> {
         if self.reply.load(Ordering::Relaxed) {
             self.reply.store(false, Ordering::Relaxed);
             if self.errored.load(Ordering::Relaxed) {
@@ -56,7 +56,7 @@ impl ForegroundSignals {
         }
     }
 
-    pub fn was_grabbed(&self, pid: u32) -> bool {
+    pub(crate) fn was_grabbed(&self, pid: u32) -> bool {
         self.grab.load(Ordering::Relaxed) == pid as usize
     }
 }
diff --git a/src/shell/pipe_exec/fork.rs b/src/shell/pipe_exec/fork.rs
index 2d56243db252746459d39dbe02b4c47076d65818..476b0d232536284d17f9094384c941782e811624 100644
--- a/src/shell/pipe_exec/fork.rs
+++ b/src/shell/pipe_exec/fork.rs
@@ -1,7 +1,7 @@
 use sys;
 
 /// Ensures that the forked child is given a unique process ID.
-pub fn create_process_group(pgid: u32) { let _ = sys::setpgid(0, pgid); }
+pub(crate) fn create_process_group(pgid: u32) { let _ = sys::setpgid(0, pgid); }
 
 use super::job_control::{JobControl, ProcessState};
 use super::pipe;
@@ -12,7 +12,7 @@ use std::process::exit;
 
 /// Forks the shell, adding the child to the parent's background list, and executing
 /// the given commands in the child fork.
-pub fn fork_pipe(
+pub(crate) fn fork_pipe(
     shell: &mut Shell,
     commands: Vec<(RefinedJob, JobKind)>,
     command_name: String,
diff --git a/src/shell/pipe_exec/job_control.rs b/src/shell/pipe_exec/job_control.rs
index b10b9d5a4dd43c500c23d17960dc1e4c1583acd0..b0679124b265df32d8073a2c677c5e9b91f62efc 100644
--- a/src/shell/pipe_exec/job_control.rs
+++ b/src/shell/pipe_exec/job_control.rs
@@ -9,16 +9,16 @@ use std::time::Duration;
 use sys;
 
 use sys::job_control as self_sys;
-pub use sys::job_control::watch_background;
+pub(crate) use sys::job_control::watch_background;
 
 /// When given a process ID, that process's group will be assigned as the foreground process group.
-pub fn set_foreground_as(pid: u32) {
+pub(crate) fn set_foreground_as(pid: u32) {
     signals::block();
     let _ = sys::tcsetpgrp(0, pid);
     signals::unblock();
 }
 
-pub trait JobControl {
+pub(crate) trait JobControl {
     /// Waits for background jobs to finish before returning.
     fn wait_for_background(&mut self);
     /// Takes a background tasks's PID and whether or not it needs to be continued; resumes the
@@ -44,7 +44,7 @@ pub trait JobControl {
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 /// Defines whether the background process is running or stopped.
-pub enum ProcessState {
+pub(crate) enum ProcessState {
     Running,
     Stopped,
     Empty,
@@ -60,7 +60,7 @@ impl fmt::Display for ProcessState {
     }
 }
 
-pub fn add_to_background(
+pub(crate) fn add_to_background(
     processes: Arc<Mutex<Vec<BackgroundProcess>>>,
     pid: u32,
     state: ProcessState,
@@ -95,7 +95,7 @@ pub fn add_to_background(
 /// by the shell. The shell will only retain information about the process, such
 /// as the process ID, state that the process is in, and the command that the
 /// process is executing.
-pub struct BackgroundProcess {
+pub(crate) struct BackgroundProcess {
     pub pid:           u32,
     pub ignore_sighup: bool,
     pub state:         ProcessState,
diff --git a/src/shell/pipe_exec/mod.rs b/src/shell/pipe_exec/mod.rs
index 8f20a5ba94244f3ceb0a00fc40b37a5d1ea5e522..5e50b7827a2e26f7da9de4ada9300cedae5e67b3 100644
--- a/src/shell/pipe_exec/mod.rs
+++ b/src/shell/pipe_exec/mod.rs
@@ -158,7 +158,7 @@ fn redirect_output(stdout: Redirection, piped_commands: &mut Vec<(RefinedJob, Jo
     false
 }
 
-pub trait PipelineExecution {
+pub(crate) trait PipelineExecution {
     /// Given a pipeline, generates commands and executes them.
     ///
     /// The `Pipeline` structure contains a vector of `Job`s, and redirections to perform on the
@@ -449,7 +449,7 @@ impl<'a> PipelineExecution for Shell<'a> {
 }
 
 /// This function will panic if called with an empty slice
-pub fn pipe(shell: &mut Shell, commands: Vec<(RefinedJob, JobKind)>, foreground: bool) -> i32 {
+pub(crate) fn pipe(shell: &mut Shell, commands: Vec<(RefinedJob, JobKind)>, foreground: bool) -> i32 {
     fn close(file: &Option<File>) {
         if let &Some(ref file) = file {
             if let Err(e) = sys::close(file.as_raw_fd()) {
diff --git a/src/shell/plugins/library_iter/mod.rs b/src/shell/plugins/library_iter/mod.rs
index a5d9420ea86b441d23d3a66f3855a3c5b5e8e41c..286d5815aedba6635c57f138c25635754fa83cdc 100644
--- a/src/shell/plugins/library_iter/mod.rs
+++ b/src/shell/plugins/library_iter/mod.rs
@@ -1,9 +1,9 @@
 #[cfg(target_os = "redox")]
 mod redox;
 #[cfg(target_os = "redox")]
-pub use self::redox::*;
+pub(crate) use self::redox::*;
 
 #[cfg(all(unix, not(target_os = "redox")))]
 mod unix;
 #[cfg(all(unix, not(target_os = "redox")))]
-pub use self::unix::*;
+pub(crate) use self::unix::*;
diff --git a/src/shell/plugins/library_iter/redox.rs b/src/shell/plugins/library_iter/redox.rs
index 7ef4558d39acc5d247653db74c1f9bf9155a73a3..61fed872efafc8999de48645b17372e2241b6945 100644
--- a/src/shell/plugins/library_iter/redox.rs
+++ b/src/shell/plugins/library_iter/redox.rs
@@ -1,15 +1,15 @@
 use std::fs::ReadDir;
 use types::Identifier;
 
-pub struct Library;
+pub(crate) struct Library;
 
 /// Grabs all `Library` entries found within a given directory
-pub struct LibraryIterator {
+pub(crate) struct LibraryIterator {
     directory: ReadDir,
 }
 
 impl LibraryIterator {
-    pub fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } }
+    pub(crate) fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } }
 }
 
 impl Iterator for LibraryIterator {
diff --git a/src/shell/plugins/library_iter/unix.rs b/src/shell/plugins/library_iter/unix.rs
index f09ab7d394d5c9cab5d0e3b199870bd87fc2d1a6..4b1ba399f6ded2ba35fdd96e073e8bd370b4ca10 100644
--- a/src/shell/plugins/library_iter/unix.rs
+++ b/src/shell/plugins/library_iter/unix.rs
@@ -3,12 +3,12 @@ use std::fs::ReadDir;
 use types::Identifier;
 
 /// Grabs all `Library` entries found within a given directory
-pub struct LibraryIterator {
+pub(crate) struct LibraryIterator {
     directory: ReadDir,
 }
 
 impl LibraryIterator {
-    pub fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } }
+    pub(crate) fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } }
 }
 
 impl Iterator for LibraryIterator {
diff --git a/src/shell/plugins/methods/mod.rs b/src/shell/plugins/methods/mod.rs
index a5d9420ea86b441d23d3a66f3855a3c5b5e8e41c..286d5815aedba6635c57f138c25635754fa83cdc 100644
--- a/src/shell/plugins/methods/mod.rs
+++ b/src/shell/plugins/methods/mod.rs
@@ -1,9 +1,9 @@
 #[cfg(target_os = "redox")]
 mod redox;
 #[cfg(target_os = "redox")]
-pub use self::redox::*;
+pub(crate) use self::redox::*;
 
 #[cfg(all(unix, not(target_os = "redox")))]
 mod unix;
 #[cfg(all(unix, not(target_os = "redox")))]
-pub use self::unix::*;
+pub(crate) use self::unix::*;
diff --git a/src/shell/plugins/methods/redox.rs b/src/shell/plugins/methods/redox.rs
index 5c79869688e947ac3c86c711fa124f1c26c8f841..0f77cb0eddbd32c34f7d7bcb69a9e82afaf82a68 100644
--- a/src/shell/plugins/methods/redox.rs
+++ b/src/shell/plugins/methods/redox.rs
@@ -1,17 +1,17 @@
 use super::super::StringError;
 
-pub enum MethodArguments {
+pub(crate) enum MethodArguments {
     StringArg(String, Vec<String>),
     Array(Vec<String>, Vec<String>),
     NoArgs,
 }
 
-pub struct StringMethodPlugins;
+pub(crate) struct StringMethodPlugins;
 
 impl StringMethodPlugins {
-    pub fn new() -> StringMethodPlugins { StringMethodPlugins }
+    pub(crate) fn new() -> StringMethodPlugins { StringMethodPlugins }
 
-    pub fn execute(
+    pub(crate) fn execute(
         &self,
         _function: &str,
         _arguments: MethodArguments,
@@ -24,4 +24,4 @@ impl StringMethodPlugins {
 ///
 /// This function is meant to be called with `lazy_static` to ensure that there isn't a
 /// cost to collecting all this information when the shell never uses it in the first place!
-pub fn collect() -> StringMethodPlugins { StringMethodPlugins::new() }
+pub(crate) fn collect() -> StringMethodPlugins { StringMethodPlugins::new() }
diff --git a/src/shell/plugins/methods/unix.rs b/src/shell/plugins/methods/unix.rs
index a0aecfd3e87747cd172ff06f9ef0c5d209df8369..76390e1d75584f3aa3ec0e072ad392d24481b8ee 100644
--- a/src/shell/plugins/methods/unix.rs
+++ b/src/shell/plugins/methods/unix.rs
@@ -13,7 +13,7 @@ use types::Identifier;
 /// Either one or the other will be set. Optional status can be conveyed by setting the
 /// corresponding field to `NULL`. Libraries importing this structure should check for nullness.
 #[repr(C)]
-pub struct RawMethodArguments {
+pub(crate) struct RawMethodArguments {
     key_ptr:       *mut i8,
     key_array_ptr: *mut *mut i8,
     args_ptr:      *mut *mut i8,
@@ -21,7 +21,7 @@ pub struct RawMethodArguments {
     args_len:      usize,
 }
 
-pub enum MethodArguments {
+pub(crate) enum MethodArguments {
     StringArg(String, Vec<String>),
     Array(Vec<String>, Vec<String>),
     NoArgs,
@@ -97,7 +97,7 @@ impl From<MethodArguments> for RawMethodArguments {
 /// plugin to ensure that the plugin remains loaded in memory, and it's contained symbols
 /// remain validly-executable; and B) holds a map of functions that may be executed within
 /// the namespace.
-pub struct StringMethodPlugins {
+pub(crate) struct StringMethodPlugins {
     #[allow(dead_code)]
     /// Contains all of the loaded libraries from whence the symbols were obtained.
     libraries: Vec<Library>,
@@ -107,14 +107,14 @@ pub struct StringMethodPlugins {
 }
 
 impl StringMethodPlugins {
-    pub fn new() -> StringMethodPlugins {
+    pub(crate) fn new() -> StringMethodPlugins {
         StringMethodPlugins {
             libraries: Vec::new(),
             symbols:   FnvHashMap::default(),
         }
     }
 
-    pub fn load(&mut self, library: Library) -> Result<(), StringError> {
+    pub(crate) fn load(&mut self, library: Library) -> Result<(), StringError> {
         unsafe {
             {
                 // The `index` function contains a list of functions provided by the library.
@@ -197,7 +197,7 @@ impl StringMethodPlugins {
     ///
     /// If the function exists, it is executed, and it's return value is then converted into a
     /// proper Rusty type.
-    pub fn execute(
+    pub(crate) fn execute(
         &self,
         function: &str,
         arguments: MethodArguments,
@@ -222,7 +222,7 @@ impl StringMethodPlugins {
 ///
 /// This function is meant to be called with `lazy_static` to ensure that there isn't a
 /// cost to collecting all this information when the shell never uses it in the first place!
-pub fn collect() -> StringMethodPlugins {
+pub(crate) fn collect() -> StringMethodPlugins {
     let mut methods = StringMethodPlugins::new();
     if let Some(mut path) = config_dir() {
         path.push("methods");
diff --git a/src/shell/plugins/mod.rs b/src/shell/plugins/mod.rs
index e2c45f02677f93ea3bec507205ba8ab69a0005c9..f24320e6d284bc03a44d746370c1b0b015449971 100644
--- a/src/shell/plugins/mod.rs
+++ b/src/shell/plugins/mod.rs
@@ -3,13 +3,13 @@ pub mod namespaces;
 mod library_iter;
 mod string;
 
-pub use self::library_iter::*;
-pub use self::string::StringError;
+pub(crate) use self::library_iter::*;
+pub(crate) use self::string::StringError;
 
 use app_dirs::{app_root, AppDataType, AppInfo};
 use std::path::PathBuf;
 
-pub fn config_dir() -> Option<PathBuf> {
+pub(crate) fn config_dir() -> Option<PathBuf> {
     match app_root(
         AppDataType::UserConfig,
         &AppInfo {
diff --git a/src/shell/plugins/namespaces/mod.rs b/src/shell/plugins/namespaces/mod.rs
index a5d9420ea86b441d23d3a66f3855a3c5b5e8e41c..286d5815aedba6635c57f138c25635754fa83cdc 100644
--- a/src/shell/plugins/namespaces/mod.rs
+++ b/src/shell/plugins/namespaces/mod.rs
@@ -1,9 +1,9 @@
 #[cfg(target_os = "redox")]
 mod redox;
 #[cfg(target_os = "redox")]
-pub use self::redox::*;
+pub(crate) use self::redox::*;
 
 #[cfg(all(unix, not(target_os = "redox")))]
 mod unix;
 #[cfg(all(unix, not(target_os = "redox")))]
-pub use self::unix::*;
+pub(crate) use self::unix::*;
diff --git a/src/shell/plugins/namespaces/redox.rs b/src/shell/plugins/namespaces/redox.rs
index a828cce16dc1674c0b326d6a2fb537eb283ac11d..7c898a08d78454741132b0d52aa92bb7e0a6b51c 100644
--- a/src/shell/plugins/namespaces/redox.rs
+++ b/src/shell/plugins/namespaces/redox.rs
@@ -3,15 +3,15 @@ use fnv::FnvHashMap;
 use super::super::StringError;
 use types::Identifier;
 
-pub struct StringNamespace;
+pub(crate) struct StringNamespace;
 
 impl StringNamespace {
-    pub fn new() -> Result<StringNamespace, StringError> { Ok(StringNamespace) }
+    pub(crate) fn new() -> Result<StringNamespace, StringError> { Ok(StringNamespace) }
 
-    pub fn execute(&self, _function: Identifier) -> Result<Option<String>, StringError> { Ok(None) }
+    pub(crate) fn execute(&self, _function: Identifier) -> Result<Option<String>, StringError> { Ok(None) }
 }
 
-pub fn collect() -> FnvHashMap<Identifier, StringNamespace> {
+pub(crate) fn collect() -> FnvHashMap<Identifier, StringNamespace> {
     eprintln!("ion: Redox doesn't support plugins yet");
     FnvHashMap::default()
 }
diff --git a/src/shell/plugins/namespaces/unix.rs b/src/shell/plugins/namespaces/unix.rs
index 3c4423be412e8a89879e894cc9238d774556f975..d0585acf69a0a0e31c3ea10a6e434821ab4034c5 100644
--- a/src/shell/plugins/namespaces/unix.rs
+++ b/src/shell/plugins/namespaces/unix.rs
@@ -14,7 +14,7 @@ use types::Identifier;
 /// plugin to ensure that the plugin remains loaded in memory, and it's contained symbols
 /// remain validly-executable; and B) holds a map of functions that may be executed within
 /// the namespace.
-pub struct StringNamespace {
+pub(crate) struct StringNamespace {
     /// This field, although never used directly, is required to exist in order to ensure
     /// that each element in the `symbols` field remains relevant. When Rust can support
     /// self-referencing lifetimes, we won't need to hold raw symbols anymore.
@@ -26,7 +26,7 @@ pub struct StringNamespace {
 }
 
 impl StringNamespace {
-    pub fn new(library: Library) -> Result<StringNamespace, StringError> {
+    pub(crate) fn new(library: Library) -> Result<StringNamespace, StringError> {
         unsafe {
             let mut symbols = FnvHashMap::default();
             {
@@ -108,7 +108,7 @@ impl StringNamespace {
     ///
     /// If the function exists, it is executed, and it's return value is then converted into a
     /// proper Rusty type.
-    pub fn execute(&self, function: Identifier) -> Result<Option<String>, StringError> {
+    pub(crate) fn execute(&self, function: Identifier) -> Result<Option<String>, StringError> {
         let func =
             self.symbols.get(&function).ok_or(StringError::FunctionMissing(function.clone()))?;
         unsafe {
@@ -129,7 +129,7 @@ impl StringNamespace {
 ///
 /// This function is meant to be called with `lazy_static` to ensure that there isn't a
 /// cost to collecting all this information when the shell never uses it in the first place!
-pub fn collect() -> FnvHashMap<Identifier, StringNamespace> {
+pub(crate) fn collect() -> FnvHashMap<Identifier, StringNamespace> {
     let mut hashmap = FnvHashMap::default();
     if let Some(mut path) = config_dir() {
         path.push("namespaces");
diff --git a/src/shell/plugins/string.rs b/src/shell/plugins/string.rs
index f71cfd3cb994e05ad3bd6af968e43fd5372c3c50..fef188f0a9037f56b8b543b05885712e109fa768 100644
--- a/src/shell/plugins/string.rs
+++ b/src/shell/plugins/string.rs
@@ -5,7 +5,7 @@ use types::Identifier;
 #[derive(Debug)]
 /// A possible error that can be caused when attempting to obtain or execute a
 /// function that is supposed to return a string from across the FFI boundaries.
-pub enum StringError {
+pub(crate) enum StringError {
     /// This occurs when a symbol could not be loaded from the library in question. It is an
     /// error that infers that the problem is with the plugin, not Ion itself.
     SymbolErr(io::Error),
diff --git a/src/shell/signals.rs b/src/shell/signals.rs
index e3f55e5669d64bcc12c1356289e58273cba91901..1933ac5d5ecbeac488de5353af8311d24c4c44a4 100644
--- a/src/shell/signals.rs
+++ b/src/shell/signals.rs
@@ -7,22 +7,22 @@ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
 
 use sys;
 
-pub use sys::signals::{block, unblock};
+pub(crate) use sys::signals::{block, unblock};
 
 pub static PENDING: AtomicUsize = ATOMIC_USIZE_INIT;
 
 /// Suspends a given process by it's process ID.
-pub fn suspend(pid: u32) { let _ = sys::killpg(pid, sys::SIGSTOP); }
+pub(crate) fn suspend(pid: u32) { let _ = sys::killpg(pid, sys::SIGSTOP); }
 
 /// Resumes a given process by it's process ID.
-pub fn resume(pid: u32) { let _ = sys::killpg(pid, sys::SIGCONT); }
+pub(crate) fn resume(pid: u32) { let _ = sys::killpg(pid, sys::SIGCONT); }
 
 /// The purpose of the signal handler is to ignore signals when it is active, and then continue
 /// listening to signals once the handler is dropped.
-pub struct SignalHandler;
+pub(crate) struct SignalHandler;
 
 impl SignalHandler {
-    pub fn new() -> SignalHandler {
+    pub(crate) fn new() -> SignalHandler {
         block();
         SignalHandler
     }
diff --git a/src/shell/status.rs b/src/shell/status.rs
index 65d0b1ef980c9dc25fbbd08d9fb91aa77e1b6c90..64715262732b7e73c1cf556e0b1c0169d51e3f2e 100644
--- a/src/shell/status.rs
+++ b/src/shell/status.rs
@@ -1,8 +1,8 @@
-pub const SUCCESS: i32 = 0;
-pub const FAILURE: i32 = 1;
-pub const BAD_ARG: i32 = 2;
-pub const COULD_NOT_EXEC: i32 = 126;
-pub const NO_SUCH_COMMAND: i32 = 127;
-pub const TERMINATED: i32 = 143;
+pub(crate) const SUCCESS: i32 = 0;
+pub(crate) const FAILURE: i32 = 1;
+pub(crate) const BAD_ARG: i32 = 2;
+pub(crate) const COULD_NOT_EXEC: i32 = 126;
+pub(crate) const NO_SUCH_COMMAND: i32 = 127;
+pub(crate) const TERMINATED: i32 = 143;
 
-pub fn get_signal_code(signal: i32) -> i32 { 128 + signal }
+pub(crate) fn get_signal_code(signal: i32) -> i32 { 128 + signal }
diff --git a/src/shell/variables/mod.rs b/src/shell/variables/mod.rs
index 0cce1d8e573acbe607e3b5c664cf8cb29d81f958..e641c2e31865b1623a058c305b28d613a720f847 100644
--- a/src/shell/variables/mod.rs
+++ b/src/shell/variables/mod.rs
@@ -22,7 +22,7 @@ lazy_static! {
 }
 
 #[derive(Debug)]
-pub struct Variables {
+pub(crate) struct Variables {
     pub hashmaps:  HashMapVariableContext,
     pub arrays:    ArrayVariableContext,
     pub variables: VariableContext,
@@ -81,13 +81,13 @@ impl Default for Variables {
 const PLUGIN: u8 = 1;
 
 impl Variables {
-    pub fn has_plugin_support(&self) -> bool { self.flags & PLUGIN != 0 }
+    pub(crate) fn has_plugin_support(&self) -> bool { self.flags & PLUGIN != 0 }
 
-    pub fn enable_plugins(&mut self) { self.flags |= PLUGIN; }
+    pub(crate) fn enable_plugins(&mut self) { self.flags |= PLUGIN; }
 
-    pub fn disable_plugins(&mut self) { self.flags &= 255 ^ PLUGIN; }
+    pub(crate) fn disable_plugins(&mut self) { self.flags &= 255 ^ PLUGIN; }
 
-    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
+    pub(crate) fn read<I: IntoIterator>(&mut self, args: I) -> i32
         where I::Item: AsRef<str>
     {
         if sys::isatty(sys::STDIN_FILENO) {
@@ -111,7 +111,7 @@ impl Variables {
         SUCCESS
     }
 
-    pub fn set_var(&mut self, name: &str, value: &str) {
+    pub(crate) fn set_var(&mut self, name: &str, value: &str) {
         if name == "NS_PLUGINS" {
             match value {
                 "0" => self.disable_plugins(),
@@ -132,7 +132,7 @@ impl Variables {
         }
     }
 
-    pub fn set_array(&mut self, name: &str, value: Array) {
+    pub(crate) fn set_array(&mut self, name: &str, value: Array) {
         if !name.is_empty() {
             if value.is_empty() {
                 self.arrays.remove(name);
@@ -143,7 +143,7 @@ impl Variables {
     }
 
     #[allow(dead_code)]
-    pub fn set_hashmap_value(&mut self, name: &str, key: &str, value: &str) {
+    pub(crate) fn set_hashmap_value(&mut self, name: &str, key: &str, value: &str) {
         if !name.is_empty() {
             if let Some(map) = self.hashmaps.get_mut(name) {
                 map.insert(key.into(), value.into());
@@ -156,11 +156,11 @@ impl Variables {
         }
     }
 
-    pub fn get_map(&self, name: &str) -> Option<&HashMap> { self.hashmaps.get(name) }
+    pub(crate) fn get_map(&self, name: &str) -> Option<&HashMap> { self.hashmaps.get(name) }
 
-    pub fn get_array(&self, name: &str) -> Option<&Array> { self.arrays.get(name) }
+    pub(crate) fn get_array(&self, name: &str) -> Option<&Array> { self.arrays.get(name) }
 
-    pub fn unset_array(&mut self, name: &str) -> Option<Array> { self.arrays.remove(name) }
+    pub(crate) fn unset_array(&mut self, name: &str) -> Option<Array> { self.arrays.remove(name) }
 
     /// Obtains the value for the **SWD** variable.
     ///
@@ -202,7 +202,7 @@ impl Variables {
         swd
     }
 
-    pub fn get_var(&self, name: &str) -> Option<Value> {
+    pub(crate) fn get_var(&self, name: &str) -> Option<Value> {
         match name {
             "SWD" => return Some(self.get_simplified_directory()),
             "MWD" => return Some(self.get_minimal_directory()),
@@ -253,23 +253,23 @@ impl Variables {
         }
     }
 
-    pub fn get_var_or_empty(&self, name: &str) -> Value { self.get_var(name).unwrap_or_default() }
+    pub(crate) fn get_var_or_empty(&self, name: &str) -> Value { self.get_var(name).unwrap_or_default() }
 
-    pub fn unset_var(&mut self, name: &str) -> Option<Value> { self.variables.remove(name) }
+    pub(crate) fn unset_var(&mut self, name: &str) -> Option<Value> { self.variables.remove(name) }
 
-    pub fn get_vars(&self) -> Vec<Identifier> {
+    pub(crate) fn get_vars(&self) -> Vec<Identifier> {
         self.variables.keys().cloned().chain(env::vars().map(|(k, _)| k.into())).collect()
     }
 
-    pub fn is_valid_variable_character(c: char) -> bool {
+    pub(crate) fn is_valid_variable_character(c: char) -> bool {
         c.is_alphanumeric() || c == '_' || c == '?'
     }
 
-    pub fn is_valid_variable_name(name: &str) -> bool {
+    pub(crate) fn is_valid_variable_name(name: &str) -> bool {
         name.chars().all(Variables::is_valid_variable_character)
     }
 
-    pub fn tilde_expansion(&self, word: &str, dir_stack: &DirectoryStack) -> Option<String> {
+    pub(crate) fn tilde_expansion(&self, word: &str, dir_stack: &DirectoryStack) -> Option<String> {
         let mut chars = word.char_indices();
 
         let tilde_prefix;
@@ -338,7 +338,7 @@ impl Variables {
     }
 
     #[allow(dead_code)]
-    pub fn command_expansion(&self, command: &str) -> Option<Value> {
+    pub(crate) fn command_expansion(&self, command: &str) -> Option<Value> {
         if let Ok(exe) = env::current_exe() {
             if let Ok(output) = process::Command::new(exe).arg("-c").arg(command).output() {
                 if let Ok(mut stdout) = String::from_utf8(output.stdout) {
@@ -355,7 +355,7 @@ impl Variables {
     }
 
     #[allow(dead_code)]
-    pub fn is_hashmap_reference(key: &str) -> Option<(Identifier, Key)> {
+    pub(crate) fn is_hashmap_reference(key: &str) -> Option<(Identifier, Key)> {
         let mut key_iter = key.split('[');
 
         if let Some(map_name) = key_iter.next() {
diff --git a/src/sys/redox.rs b/src/sys/redox.rs
index 19111a5d20b6d31037d77d37d386ea1db62001c7..f536891597c9088fb25be87cf0f37e26b7e34fdc 100644
--- a/src/sys/redox.rs
+++ b/src/sys/redox.rs
@@ -5,45 +5,45 @@ use std::os::unix::io::RawFd;
 
 use syscall::SigAction;
 
-pub const PATH_SEPARATOR: &str = ";";
+pub(crate) const PATH_SEPARATOR: &str = ";";
 
-pub const O_CLOEXEC: usize = syscall::O_CLOEXEC;
-pub const SIGHUP: i32 = syscall::SIGHUP as i32;
-pub const SIGINT: i32 = syscall::SIGINT as i32;
-pub const SIGTERM: i32 = syscall::SIGTERM as i32;
-pub const SIGCONT: i32 = syscall::SIGCONT as i32;
-pub const SIGSTOP: i32 = syscall::SIGSTOP as i32;
-pub const SIGTSTP: i32 = syscall::SIGTSTP as i32;
+pub(crate) const O_CLOEXEC: usize = syscall::O_CLOEXEC;
+pub(crate) const SIGHUP: i32 = syscall::SIGHUP as i32;
+pub(crate) const SIGINT: i32 = syscall::SIGINT as i32;
+pub(crate) const SIGTERM: i32 = syscall::SIGTERM as i32;
+pub(crate) const SIGCONT: i32 = syscall::SIGCONT as i32;
+pub(crate) const SIGSTOP: i32 = syscall::SIGSTOP as i32;
+pub(crate) const SIGTSTP: i32 = syscall::SIGTSTP as i32;
 
-pub const STDIN_FILENO: RawFd = 0;
-pub const STDOUT_FILENO: RawFd = 1;
-pub const STDERR_FILENO: RawFd = 2;
+pub(crate) const STDIN_FILENO: RawFd = 0;
+pub(crate) const STDOUT_FILENO: RawFd = 1;
+pub(crate) const STDERR_FILENO: RawFd = 2;
 
-pub fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }
+pub(crate) fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }
 
 pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) }
 
-pub fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }
+pub(crate) fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }
 
-pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
+pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> {
     cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
 }
 
-pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
+pub(crate) fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
     cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
 }
 
-pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
+pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
     let mut fds = [0; 2];
     cvt(syscall::pipe2(&mut fds, flags))?;
     Ok((fds[0], fds[1]))
 }
 
-pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
+pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
     cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
 }
 
-pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
+pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
     let new = SigAction {
         sa_handler: unsafe { mem::transmute(handler) },
         sa_mask:    [0; 2],
@@ -52,7 +52,7 @@ pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
     cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
 }
 
-pub fn reset_signal(signal: i32) -> io::Result<()> {
+pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
     let new = SigAction {
         sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) },
         sa_mask:    [0; 2],
@@ -61,7 +61,7 @@ pub fn reset_signal(signal: i32) -> io::Result<()> {
     cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
 }
 
-pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
+pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
     let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;
 
     let pgid_usize = pgid as usize;
@@ -74,13 +74,13 @@ pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
     cvt(res).and(Ok(()))
 }
 
-pub fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }
+pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }
 
-pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(syscall::dup2(old, new, &[])) }
+pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(syscall::dup2(old, new, &[])) }
 
-pub fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }
+pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }
 
-pub fn isatty(fd: RawFd) -> bool {
+pub(crate) fn isatty(fd: RawFd) -> bool {
     if let Ok(tfd) = syscall::dup(fd, b"termios") {
         let _ = syscall::close(tfd);
         true
@@ -96,12 +96,12 @@ fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
 
 // TODO
 pub mod signals {
-    pub fn block() {}
+    pub(crate) fn block() {}
 
     /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
     /// controlled
     /// by the shell.
-    pub fn unblock() {}
+    pub(crate) fn unblock() {}
 }
 
 pub mod job_control {
@@ -115,7 +115,7 @@ pub mod job_control {
     use std::sync::{Arc, Mutex};
     use syscall;
 
-    pub fn watch_background(
+    pub(crate) fn watch_background(
         _fg: Arc<ForegroundSignals>,
         _processes: Arc<Mutex<Vec<BackgroundProcess>>>,
         _pid: u32,
@@ -125,7 +125,7 @@ pub mod job_control {
     }
 
 
-    pub fn watch_foreground<'a, F, D>(
+    pub(crate) fn watch_foreground<'a, F, D>(
         shell: &mut Shell<'a>,
         _pid: u32,
         last_pid: u32,
@@ -178,7 +178,7 @@ pub mod job_control {
 }
 
 pub mod variables {
-    pub fn get_user_home(_username: &str) -> Option<String> {
+    pub(crate) fn get_user_home(_username: &str) -> Option<String> {
         // TODO
         None
     }
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index 7197cb234f13804dd78502abc5ee8f3bd953739d..128504b8ed1c289c0aed4c6346bd3acb781d48bd 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -4,35 +4,35 @@ use libc::{c_int, pid_t, sighandler_t};
 use std::io;
 use std::os::unix::io::RawFd;
 
-pub const PATH_SEPARATOR: &str = ":";
+pub(crate) const PATH_SEPARATOR: &str = ":";
 
-pub const O_CLOEXEC: usize = libc::O_CLOEXEC as usize;
-pub const SIGHUP: i32 = libc::SIGHUP;
-pub const SIGINT: i32 = libc::SIGINT;
-pub const SIGTERM: i32 = libc::SIGTERM;
-pub const SIGCONT: i32 = libc::SIGCONT;
-pub const SIGSTOP: i32 = libc::SIGSTOP;
-pub const SIGTSTP: i32 = libc::SIGTSTP;
+pub(crate) const O_CLOEXEC: usize = libc::O_CLOEXEC as usize;
+pub(crate) const SIGHUP: i32 = libc::SIGHUP;
+pub(crate) const SIGINT: i32 = libc::SIGINT;
+pub(crate) const SIGTERM: i32 = libc::SIGTERM;
+pub(crate) const SIGCONT: i32 = libc::SIGCONT;
+pub(crate) const SIGSTOP: i32 = libc::SIGSTOP;
+pub(crate) const SIGTSTP: i32 = libc::SIGTSTP;
 
-pub const STDOUT_FILENO: i32 = libc::STDOUT_FILENO;
-pub const STDERR_FILENO: i32 = libc::STDERR_FILENO;
-pub const STDIN_FILENO: i32 = libc::STDIN_FILENO;
+pub(crate) const STDOUT_FILENO: i32 = libc::STDOUT_FILENO;
+pub(crate) const STDERR_FILENO: i32 = libc::STDERR_FILENO;
+pub(crate) const STDIN_FILENO: i32 = libc::STDIN_FILENO;
 
-pub fn is_root() -> bool { unsafe { libc::geteuid() == 0 } }
+pub(crate) fn is_root() -> bool { unsafe { libc::geteuid() == 0 } }
 
 pub unsafe fn fork() -> io::Result<u32> { cvt(libc::fork()).map(|pid| pid as u32) }
 
-pub fn getpid() -> io::Result<u32> { cvt(unsafe { libc::getpid() }).map(|pid| pid as u32) }
+pub(crate) fn getpid() -> io::Result<u32> { cvt(unsafe { libc::getpid() }).map(|pid| pid as u32) }
 
-pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
+pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> {
     cvt(unsafe { libc::kill(pid as pid_t, signal as c_int) }).and(Ok(()))
 }
 
-pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
+pub(crate) fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
     cvt(unsafe { libc::kill(-(pgid as pid_t), signal as c_int) }).and(Ok(()))
 }
 
-pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
+pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
     let mut fds = [0; 2];
 
     #[cfg(not(target_os = "macos"))]
@@ -44,11 +44,11 @@ pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
     Ok((fds[0], fds[1]))
 }
 
-pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
+pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
     cvt(unsafe { libc::setpgid(pid as pid_t, pgid as pid_t) }).and(Ok(()))
 }
 
-pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
+pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
     if unsafe { libc::signal(signal as c_int, handler as sighandler_t) } == libc::SIG_ERR {
         Err(io::Error::last_os_error())
     } else {
@@ -56,7 +56,7 @@ pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
     }
 }
 
-pub fn reset_signal(signal: i32) -> io::Result<()> {
+pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
     if unsafe { libc::signal(signal as c_int, libc::SIG_DFL) } == libc::SIG_ERR {
         Err(io::Error::last_os_error())
     } else {
@@ -64,17 +64,17 @@ pub fn reset_signal(signal: i32) -> io::Result<()> {
     }
 }
 
-pub fn tcsetpgrp(fd: RawFd, pgrp: u32) -> io::Result<()> {
+pub(crate) fn tcsetpgrp(fd: RawFd, pgrp: u32) -> io::Result<()> {
     cvt(unsafe { libc::tcsetpgrp(fd as c_int, pgrp as pid_t) }).and(Ok(()))
 }
 
-pub fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup(fd) }) }
+pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup(fd) }) }
 
-pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup2(old, new) }) }
+pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup2(old, new) }) }
 
-pub fn close(fd: RawFd) -> io::Result<()> { cvt(unsafe { libc::close(fd) }).and(Ok(())) }
+pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(unsafe { libc::close(fd) }).and(Ok(())) }
 
-pub fn isatty(fd: RawFd) -> bool { unsafe { libc::isatty(fd) == 1 } }
+pub(crate) fn isatty(fd: RawFd) -> bool { unsafe { libc::isatty(fd) == 1 } }
 
 // Support functions for converting libc return values to io errors {
 trait IsMinusOne {
@@ -103,7 +103,7 @@ fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
 pub mod signals {
     /// Blocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so that the shell never receives
     /// them.
-    pub fn block() {
+    pub(crate) fn block() {
         unsafe {
             use libc::*;
             use std::mem;
@@ -121,7 +121,7 @@ pub mod signals {
     /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
     /// controlled
     /// by the shell.
-    pub fn unblock() {
+    pub(crate) fn unblock() {
         unsafe {
             use libc::*;
             use std::mem;
@@ -155,7 +155,7 @@ pub mod job_control {
     use nix::{Errno, Error};
     use nix::sys::signal::Signal;
 
-    pub fn watch_background(
+    pub(crate) fn watch_background(
         fg: Arc<ForegroundSignals>,
         processes: Arc<Mutex<Vec<BackgroundProcess>>>,
         pid: u32,
@@ -223,7 +223,7 @@ pub mod job_control {
         }
     }
 
-    pub fn watch_foreground<'a, F, D>(
+    pub(crate) fn watch_foreground<'a, F, D>(
         shell: &mut Shell<'a>,
         _pid: u32,
         last_pid: u32,
@@ -277,7 +277,7 @@ pub mod variables {
     use users_unix::get_user_by_name;
     use users_unix::os::unix::UserExt;
 
-    pub fn get_user_home(username: &str) -> Option<String> {
+    pub(crate) fn get_user_home(username: &str) -> Option<String> {
         match get_user_by_name(username) {
             Some(user) => Some(user.home_dir().to_string_lossy().into_owned()),
             None => None,