Commit ffd7efde authored by Michael Aaron Murphy's avatar Michael Aaron Murphy
Browse files

Implement Ion Docs Launch Support

- We now have a setup.ion script for performing more advanced setup/installations.
- If the documentation is installed, it is accessible via the ion-docs builtin.
- This requires that the user specifies a BROWSER variable
- Fixed a bug with the quote terminator
parent 9ef49729
......@@ -95,9 +95,7 @@ there's an official git plugin that can be installed to experiment with the exis
To install the git plugin, first install ion, and then execute the following:
```ion
git clone https://github.com/mmstick/ion-plugins
cd ion-plugins
./install.ion
./setup.ion install plugins
```
It can be tested out by navigating to a directory within a git repository, and running the following:
......@@ -106,6 +104,11 @@ It can be tested out by navigating to a directory within a git repository, and r
echo Current Branch: ${git::branch}
```
# Install Documentation
The mdBook shipping with Ion can be installed into the system and accessed via the `ion-docs` builtin.
See the `setup.ion` script in this repository (execute it without arguments to get more info).
# Vim/NeoVim Syntax Highlighting Plugin
We do have an [officially-supported syntax highlighting plugin](https://github.com/vmchale/ion-vim) for all the
......
......@@ -11,3 +11,7 @@ three"
echo 'one two"
three'
echo "one two \
three four \
five six"
......@@ -6,3 +6,4 @@ one two'
three
one two"
three
one two three four five six
#!/usr/bin/env ion
# Get the root directory of the cargo project.
let PROJECT_DIR = $parent(@split($(cargo locate-project), '"')[3])
# If the destination for the binary was not give, set it.
if not exists ${env::DESTDIR}
let DESTDIR = "/usr/bin/"
end
# If the share directory was not given, set it.
if not exists ${env::SHAREDIR}
let SHAREDIR = "/usr/share/ion/";
end
# Ensure that we begin execution with this as the working directory.
cd $PROJECT_DIR
fn print_option definition description
echo " ${c::bold}- ${c::0x0CF}$definition: ${c::reset}$description"
end
# In case a bad argument was supplied, this will be used.
fn bad_arg argument
echo -e "${c::0xF60,bold}Error: ${c::0xF06}`$argument`${c::0xF60} is \
not a valid command.${c::reset}\n${c::0x0F6}Available options for \
this script are:${c::reset}"
print_option "build ion" " Build the Ion shell"
print_option "build docs" " Build the Ion mdBook"
print_option "install ion" " Install the Ion Shell"
print_option "install docs" " Install the Ion mdBook"
print_option "install plugins" "Install official Ion plugins"
print_option "uninstall ion" " Removes Ion from System"
exit
end
# Arguments are required!
if test 1 -eq $len(@args); bad_arg; end
# Rust/Cargo is required!
if not exists -b "cargo"
echo "${c::0xF60,bold}Error: Rust/Cargo is not installed."
exit
end
# The first and second argument will determine what the user wants.
match "@args[1..3]"
case "build ion"
cargo build --release
case "build docs"
if not exists -b "mdbook"
echo "${c::09F}Installing mdbook from Crates.io${c::reset}"
cargo install mdbook --force
end
cd manual && mdbook build
case "install ion"
sudo install target/release/ion ${DESTDIR}/ion
case "install docs"
echo "${c::0xF30,bold}Installing documentation with root${c::reset}"
sudo mkdir ${SHAREDIR}/docs/ -p
sudo cp manual/book/* ${SHAREDIR}/docs/ -R
case "install plugins"
git clone https://github.com/mmstick/ion-plugins
cd ion-plugins && ion install.ion
case "uninstall ion"
echo "${c::0xF30,bold}Removing ${c::0x09F}${DESTDIR}${c::0xF30}/ion \
and ${c::0xF30}${SHAREDIR}${c::reset}"
sudo rm ${DESTDIR}/ion
sudo rm ${SHAREDIR} -R
case _
bad_arg "@args[1..3]"
end
use std::error::Error;
use std::fs;
use std::io::{self, BufWriter};
use std::os::unix::fs::{PermissionsExt};
#[cfg(test)]
use smallstring::SmallString;
#[cfg(test)]
use smallvec::SmallVec;
use std::error::Error;
use std::fs;
use std::io::{self, BufWriter};
use std::os::unix::fs::PermissionsExt;
#[cfg(test)]
use builtins::Builtin;
use shell::Shell;
#[cfg(test)]
use shell::flow_control::{Function, FunctionArgument, Statement};
use shell::Shell;
const MAN_PAGE: &'static str = r#"NAME
exists - check whether items exist
......@@ -113,9 +112,7 @@ fn evaluate_arguments<W: io::Write>(arguments: &[&str], buffer: &mut W, shell: &
})
})
}
Some(string) => {
Ok(string_is_nonzero(string))
}
Some(string) => Ok(string_is_nonzero(string)),
None => Ok(false),
}
}
......@@ -198,7 +195,7 @@ fn string_is_nonzero(string: &str) -> bool { !string.is_empty() }
fn array_var_is_not_empty(arrayvar: &str, shell: &Shell) -> bool {
match shell.variables.get_array(arrayvar) {
Some(array) => !array.is_empty(),
None => false
None => false,
}
}
......@@ -206,7 +203,7 @@ fn array_var_is_not_empty(arrayvar: &str, shell: &Shell) -> bool {
fn string_var_is_not_empty(stringvar: &str, shell: &Shell) -> bool {
match shell.variables.get_var(stringvar) {
Some(string) => !string.is_empty(),
None => false
None => false,
}
}
......@@ -214,7 +211,7 @@ fn string_var_is_not_empty(stringvar: &str, shell: &Shell) -> bool {
fn function_is_defined(function: &str, shell: &Shell) -> bool {
match shell.functions.get(function) {
Some(_) => true,
None => false
None => false,
}
}
......@@ -244,7 +241,10 @@ fn test_evaluate_arguments() {
// check `exists -a`
// no argument means we treat it as a string
assert_eq!(evaluate_arguments(&["-a"], &mut sink, &shell), Ok(true));
shell.variables.set_array("emptyarray", SmallVec::from_vec(Vec::new()));
shell.variables.set_array(
"emptyarray",
SmallVec::from_vec(Vec::new()),
);
assert_eq!(evaluate_arguments(&["-a", "emptyarray"], &mut sink, &shell), Ok(false));
let mut vec = Vec::new();
vec.push("element".to_owned());
......@@ -257,7 +257,9 @@ fn test_evaluate_arguments() {
// TODO: see test_binary_is_in_path()
// no argument means we treat it as a string
assert_eq!(evaluate_arguments(&["-b"], &mut sink, &shell), Ok(true));
let oldpath = shell.variables.get_var("PATH").unwrap_or("/usr/bin".to_owned());
let oldpath = shell.variables.get_var("PATH").unwrap_or(
"/usr/bin".to_owned(),
);
shell.variables.set_var("PATH", "testing/");
assert_eq!(evaluate_arguments(&["-b", "executable_file"], &mut sink, &shell), Ok(true));
......@@ -332,7 +334,10 @@ fn test_match_flag_argument() {
let shell = Shell::new(&builtins);
// we don't really care about the passed values, as long as both sited return the same value
assert_eq!(match_flag_argument('a', "ARRAY", &shell), array_var_is_not_empty("ARRAY", &shell));
assert_eq!(
match_flag_argument('a', "ARRAY", &shell),
array_var_is_not_empty("ARRAY", &shell)
);
assert_eq!(match_flag_argument('b', "binary", &shell), binary_is_in_path("binary", &shell));
assert_eq!(match_flag_argument('d', "path", &shell), path_is_directory("path"));
assert_eq!(match_flag_argument('f', "file", &shell), path_is_file("file"));
......@@ -348,7 +353,10 @@ fn test_match_option_argument() {
let shell = Shell::new(&builtins);
// we don't really care about the passed values, as long as both sited return the same value
assert_eq!(match_option_argument("fn", "FUN", &shell), array_var_is_not_empty("FUN", &shell));
assert_eq!(
match_option_argument("fn", "FUN", &shell),
array_var_is_not_empty("FUN", &shell)
);
// Any option which is not implemented
assert_eq!(match_option_argument("foo", "ARG", &shell), false);
......@@ -403,12 +411,18 @@ fn test_array_var_is_not_empty() {
let builtins = Builtin::map();
let mut shell = Shell::new(&builtins);
shell.variables.set_array("EMPTY_ARRAY", SmallVec::from_vec(Vec::new()));
shell.variables.set_array(
"EMPTY_ARRAY",
SmallVec::from_vec(Vec::new()),
);
assert_eq!(array_var_is_not_empty("EMPTY_ARRAY", &shell), false);
let mut not_empty_vec = Vec::new();
not_empty_vec.push("array not empty".to_owned());
shell.variables.set_array("NOT_EMPTY_ARRAY", SmallVec::from_vec(not_empty_vec));
shell.variables.set_array(
"NOT_EMPTY_ARRAY",
SmallVec::from_vec(not_empty_vec),
);
assert_eq!(array_var_is_not_empty("NOT_EMPTY_ARRAY", &shell), true);
// test for array which does not even exist
......@@ -434,7 +448,10 @@ fn test_string_var_is_not_empty() {
// string_var_is_not_empty should NOT match for arrays with the same name
let mut vec = Vec::new();
vec.push("not-empty".to_owned());
shell.variables.set_array("ARRAY_NOT_EMPTY", SmallVec::from_vec(vec) );
shell.variables.set_array(
"ARRAY_NOT_EMPTY",
SmallVec::from_vec(vec),
);
assert_eq!(string_var_is_not_empty("ARRAY_NOT_EMPTY", &shell), false);
// test for a variable which does not even exist
......
use fnv::FnvHashMap;
use shell::flow_control::Function;
use shell::status::*;
......
use shell::Shell;
use shell::status::*;
use std::path::Path;
use std::process::Command;
const DOCPATH: &str = "/usr/share/ion/docs/index.html";
pub fn ion_docs(_: &[&str], shell: &mut Shell) -> i32 {
if !Path::new(DOCPATH).exists() {
eprintln!("ion: ion shell documentation is not installed");
return FAILURE;
}
if let Some(cmd) = shell.variables.get_var("BROWSER".into()) {
if let Ok(_) = Command::new(&cmd).arg(DOCPATH).spawn() {
return SUCCESS;
}
} else {
eprintln!("ion: BROWSER variable isn't defined");
}
FAILURE
}
......@@ -10,14 +10,16 @@ mod time;
mod echo;
mod set;
mod exists;
mod ion;
use self::conditionals::{contains, ends_with, starts_with};
use self::echo::echo;
use self::exists::exists;
use self::functions::fn_;
use self::ion::ion_docs;
use self::source::source;
use self::test::test;
use self::variables::{alias, drop_alias, drop_array, drop_variable};
use self::exists::exists;
use fnv::FnvHashMap;
use std::error::Error;
......@@ -155,6 +157,7 @@ impl Builtin {
"Evaluates if the supplied argument contains a given string"
);
insert_builtin!("exists", builtin_exists, "Performs tests on files and text");
insert_builtin!("ion-docs", ion_docs, "Opens the Ion manual");
commands
}
......
use liner::KeyBindings;
use shell::Shell;
use shell::flags::*;
......
use shell::{FlowLogic, Shell};
use std::fs::File;
use std::io::Read;
......
use smallstring::SmallString;
use std::error::Error;
use std::fs;
......
use std::error::Error;
use std::io::{Write, stdout};
use std::process::Command;
......
......@@ -81,8 +81,14 @@ impl QuoteTerminator {
}
if self.flags.intersects(SQUOTE | DQUOTE) {
self.read += 1;
self.buffer.push('\n');
if let Some(b'\\') = self.buffer.bytes().last() {
let _ = self.buffer.pop();
self.read -= 1;
self.flags |= TRIM;
} else {
self.read += 1;
self.buffer.push('\n');
}
false
} else {
if let Some(b'\\') = self.buffer.bytes().last() {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment