<commit_before>#![feature(convert, collections, unicode)]
#![allow(unused_variables)]

extern crate rustc_unicode;

use std::collections::{HashMap, VecDeque};
use std::hash::{Hash, Hasher};
use std::io;
use std::io::prelude::*;
use std::rc::Rc;
use std::fmt;
use std::str::FromStr;
use rustc_unicode::str::UnicodeStr;

type Int = i32;
type Double = f64;

type Dictionary = HashMap<String, Rc<Entry>>;
type Statement = VecDeque<Op>;
type Stack = Vec<Int>;
type NativeFn = Box<Fn(&mut Interpreter, &mut Stack)>;

#[derive(Clone, Debug)]
enum Op {
	Number(Int),
	Word(Rc<Entry>),
}

enum Code {
	Native(NativeFn),
	Forth(Statement),
}

#[derive(Clone)]
struct Entry {
	name: String,
	code: Rc<Code>,
}

impl PartialEq for Entry {
	fn eq(&self, other: &Self) -> bool { self.name == other.name }
}

impl Eq for Entry {}

impl Hash for Entry {
	fn hash<H>(&self, state: &mut H) where H: Hasher {
		self.name.hash(state)
	}
}

impl fmt::Debug for Entry {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		self.name.fmt(fmt)
	}
}

impl Entry {
	fn new(name: &str, code: Code) -> Entry {
		Entry {
			name: String::from_str(name),
			code: Rc::new(code),
		}
	}

	fn from_statement(name: &str, stmt: Statement) -> Entry {
		Entry {
			name: name.to_string(),
			code: Rc::new(Code::Forth(stmt)),
		}
	}
}

impl Code {
	fn run(&self, interp: &mut Interpreter, stack: &mut Stack) {
		match self {
			&Code::Native(ref f) => {
				f(interp, stack);
			},
			&Code::Forth(ref statement) => {
				for ref op in statement {
					match *op {
						&Op::Number(ref n) => { stack.push(*n) }
						&Op::Word(ref w) => {
							(*w).code.run(interp, stack);
						},
					}
				}
			},
		}
	}
}

trait StatementExt {
	fn run(&self, &mut Interpreter);
}

impl StatementExt for Statement {
	fn run(&self, interp: &mut Interpreter) {
		match interp.mode {
			InterpreterMode::Normal => {
				let mut stack = Stack::new();
				for word in self {
					match word {
						&Op::Number(n) => {
							stack.push(n);
						},
						&Op::Word(ref w) => {
							let code = interp.dictionary[w.name.as_str()].code.clone();
							code.run(interp, &mut stack);
						},
					};
				};
			},
			InterpreterMode::Compiler => {
				let mut word = Statement::new();

			},
		}
	}
}

trait DictionaryExt {
	fn insert_entry(&mut self, Entry);
}

impl DictionaryExt for Dictionary {
	fn insert_entry(&mut self, entry: Entry) {
		self.insert(entry.name.clone(), Rc::new(entry));
	}
}

#[derive(PartialEq, Eq)]
enum InterpreterMode {
	Normal,
	Compiler,
}

struct Interpreter {
    dictionary: Dictionary,
    mode: InterpreterMode,
}

macro_rules! binary_entry {
	($name:expr, $o:expr) => {
		Entry::new($name,
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let b = stack.pop().unwrap();
					let a = stack.pop().unwrap();
					stack.push($o(a, b));
				})),
			)
	}
}

macro_rules! unary_entry {
	($name:expr, $o:expr) => {
		Entry::new($name,
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let a = stack.pop().unwrap();
					stack.push($o(a));
				})),
			)
	}
}

macro_rules! nonary_entry {
	($name:expr, $o:expr) => {
		Entry::new($name,
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					Op::Number($o);
				})),
			)
	}
}

impl Interpreter {
	fn new() -> Interpreter {
		let mut dict = Dictionary::new();

		dict.insert_entry(binary_entry!("/", ::std::ops::Div::div));
		dict.insert_entry(binary_entry!("*", ::std::ops::Mul::mul));
		dict.insert_entry(binary_entry!("+", ::std::ops::Add::add));
		dict.insert_entry(binary_entry!("-", ::std::ops::Sub::sub));
		dict.insert_entry(binary_entry!("mod", ::std::ops::Rem::rem));
		dict.insert_entry(binary_entry!("and", ::std::ops::BitAnd::bitand));
		dict.insert_entry(binary_entry!("or", ::std::ops::BitOr::bitor));
		dict.insert_entry(binary_entry!("xor", ::std::ops::BitXor::bitxor));
		dict.insert_entry(binary_entry!("rshift", ::std::ops::Shr::shr));
		dict.insert_entry(binary_entry!("lshift", ::std::ops::Shl::shl));

		dict.insert_entry(unary_entry!("negate", ::std::ops::Neg::neg));
		dict.insert_entry(unary_entry!("not", ::std::ops::Not::not));

		dict.insert_entry(nonary_entry!("bye", ::std::process::exit(0)));

		dict.insert_entry(Entry::new("<",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let y = stack.pop().unwrap();
					let x = stack.pop().unwrap();
					stack.push(if x < y { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new(">",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let y = stack.pop().unwrap();
					let x = stack.pop().unwrap();
					stack.push(if x > y { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("=",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let y = stack.pop().unwrap();
					let x = stack.pop().unwrap();
					stack.push(if x == y { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("0<",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(if x < 0 { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("0=",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(if x == 0 { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("0>",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(if x > 0 { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("1+",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x + 1);
				})),
			));

		dict.insert_entry(Entry::new("1-",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x - 1);
				})),
			));

		dict.insert_entry(Entry::new("2+",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x + 2);
				})),
			));

		dict.insert_entry(Entry::new("2-",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x - 2);
				})),
			));

		dict.insert_entry(Entry::new("2/",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x >> 1); // Per fst83 standard
				})),
			));

		dict.insert_entry(Entry::new("dup",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x.clone());
					stack.push(x);
				})),
			));

		dict.insert_entry(Entry::new("?dup",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					if x != 0 {
						stack.push(x.clone());
						stack.push(x);
					} else {
						stack.push(x);
					}
				})),
			));

		dict.insert_entry(Entry::new("over",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					let y = stack.pop().unwrap();
					stack.push(x.clone());
					stack.push(y);
					stack.push(x);
				})),
			));

		dict.insert_entry(Entry::new("swap",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					let y = stack.pop().unwrap();
					stack.push(x);
					stack.push(y);
				})),
			));

		dict.insert_entry(Entry::new("rot",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					let y = stack.pop().unwrap();
					let z = stack.pop().unwrap();
					stack.push(y);
					stack.push(x);
					stack.push(z);
				})),
			));

		dict.insert_entry(Entry::new("dump",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					println!("ds =  {:?} ", stack);
				})),
			));

		dict.insert_entry(Entry::new("cr",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					println!("");
				})),
			));

		dict.insert_entry(Entry::new(".",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					println!("{}", stack.pop().unwrap());
				})),
			));

		dict.insert_entry(Entry::new(":",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					if interp.mode != InterpreterMode::Compiler {
						interp.mode = InterpreterMode::Compiler;
					} else {
						panic!("Compilerception!")
					}
				})),
			));

		dict.insert_entry(Entry::new(";",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					if interp.mode == InterpreterMode::Compiler {
						interp.mode = InterpreterMode::Normal;
					} else {
						panic!("Got ';' when not in Compile mode")
					}
				})),
			));

		let square = {
			let mut s = Statement::new();
			s.push_back(Op::Word(dict.get("dup").unwrap().clone()));
			s.push_back(Op::Word(dict.get("*").unwrap().clone()));
			Code::Forth(s)
		};
		dict.insert_entry(Entry::new("square", square));

		Interpreter {
			dictionary: dict,
			mode: InterpreterMode::Normal,
		}
	}

	fn exec(&mut self, statement: &str) {
		let mut words = statement.split(|c: char| c.is_whitespace());
		let mut stmt = Statement::new();
		while let Some(word) = words.next() { match word {
			"(" => while let Some(w) = words.next() { if w == ")" { break; } },
			"\\" => while let Some(w) = words.next() { if w == "\n" { break; } },
			":" => {
				let mut comp = Statement::new();
				let name = words.next().unwrap();
				while let Some(w) = words.next() {
					if w == ";" { break; }
					match w.parse::<i32>() {
						Ok(n) => comp.push_back(Op::Number(n)),
						Err(_) => comp.push_back(Op::Word(self.dictionary.get(w).unwrap().clone())),
					}
				}
				self.dictionary.insert_entry(Entry::new(name, Code::Forth(comp)));
			},
			_ => match word.parse::<i32>() {
				Ok(n) => {
					stmt.push_back(Op::Number(n));
				},
				Err(e) => {
					if let Some(elem) = self.dictionary.get(word) {
						stmt.push_back(Op::Word(elem.clone()));
					} else {
						println!("Invalid word: {}", word);
						return;
					}
				},
			},

		}}

		stmt.run(self);
	}
}

fn main() {
	println!("forth-rs version 0.1.0");
	println!("Type 'bye' to exit");
    let mut interp = Interpreter::new();
    let mut stdin = io::stdin();
    loop {
    	print!("Forth> ");
    	io::stdout().flush().ok().expect("Could not flush stdout");
    	let mut line = String::new();
    	stdin.read_line(&mut line).ok().expect("Unable to read from stdin");
    	let result = interp.exec(line.trim());
    }
}
<commit_msg>Remove cruft.<commit_after>#![feature(convert, collections, unicode)]
#![allow(unused_variables)]

use std::collections::{HashMap, VecDeque};
use std::hash::{Hash, Hasher};
use std::io;
use std::io::prelude::*;
use std::rc::Rc;
use std::fmt;

extern crate rustc_unicode;
use rustc_unicode::str::UnicodeStr;

type Int = i32;
type Double = f64;

type Dictionary = HashMap<String, Rc<Entry>>;
type Statement = VecDeque<Op>;
type Stack = Vec<Int>;
type NativeFn = Box<Fn(&mut Interpreter, &mut Stack)>;

#[derive(Clone, Debug)]
enum Op {
	Number(Int),
	Word(Rc<Entry>),
}

enum Code {
	Native(NativeFn),
	Forth(Statement),
}

#[derive(Clone)]
struct Entry {
	name: String,
	code: Rc<Code>,
}

impl PartialEq for Entry {
	fn eq(&self, other: &Self) -> bool { self.name == other.name }
}

impl Eq for Entry {}

impl Hash for Entry {
	fn hash<H>(&self, state: &mut H) where H: Hasher {
		self.name.hash(state)
	}
}

impl fmt::Debug for Entry {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		self.name.fmt(fmt)
	}
}

impl Entry {
	fn new(name: &str, code: Code) -> Entry {
		Entry {
			name: String::from_str(name),
			code: Rc::new(code),
		}
	}

	fn from_statement(name: &str, stmt: Statement) -> Entry {
		Entry {
			name: name.to_string(),
			code: Rc::new(Code::Forth(stmt)),
		}
	}
}

impl Code {
	fn run(&self, interp: &mut Interpreter, stack: &mut Stack) {
		match self {
			&Code::Native(ref f) => {
				f(interp, stack);
			},
			&Code::Forth(ref statement) => {
				for ref op in statement {
					match *op {
						&Op::Number(ref n) => { stack.push(*n) }
						&Op::Word(ref w) => {
							(*w).code.run(interp, stack);
						},
					}
				}
			},
		}
	}
}

trait StatementExt {
	fn run(&self, &mut Interpreter);
}

impl StatementExt for Statement {
	fn run(&self, interp: &mut Interpreter) {
		let mut stack = Stack::new();
		for word in self {
			match word {
				&Op::Number(n) => {
					stack.push(n);
				},
				&Op::Word(ref w) => {
					let code = interp.dictionary[w.name.as_str()].code.clone();
					code.run(interp, &mut stack);
				},
			};
		};
	}
}

trait DictionaryExt {
	fn insert_entry(&mut self, Entry);
}

impl DictionaryExt for Dictionary {
	fn insert_entry(&mut self, entry: Entry) {
		self.insert(entry.name.clone(), Rc::new(entry));
	}
}

struct Interpreter {
    dictionary: Dictionary,
}

macro_rules! binary_entry {
	($name:expr, $o:expr) => {
		Entry::new($name,
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let b = stack.pop().unwrap();
					let a = stack.pop().unwrap();
					stack.push($o(a, b));
				})),
			)
	}
}

macro_rules! unary_entry {
	($name:expr, $o:expr) => {
		Entry::new($name,
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let a = stack.pop().unwrap();
					stack.push($o(a));
				})),
			)
	}
}

macro_rules! nonary_entry {
	($name:expr, $o:expr) => {
		Entry::new($name,
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					Op::Number($o);
				})),
			)
	}
}

impl Interpreter {
	fn new() -> Interpreter {
		let mut dict = Dictionary::new();

		dict.insert_entry(binary_entry!("/", ::std::ops::Div::div));
		dict.insert_entry(binary_entry!("*", ::std::ops::Mul::mul));
		dict.insert_entry(binary_entry!("+", ::std::ops::Add::add));
		dict.insert_entry(binary_entry!("-", ::std::ops::Sub::sub));
		dict.insert_entry(binary_entry!("mod", ::std::ops::Rem::rem));
		dict.insert_entry(binary_entry!("and", ::std::ops::BitAnd::bitand));
		dict.insert_entry(binary_entry!("or", ::std::ops::BitOr::bitor));
		dict.insert_entry(binary_entry!("xor", ::std::ops::BitXor::bitxor));
		dict.insert_entry(binary_entry!("rshift", ::std::ops::Shr::shr));
		dict.insert_entry(binary_entry!("lshift", ::std::ops::Shl::shl));

		dict.insert_entry(unary_entry!("negate", ::std::ops::Neg::neg));
		dict.insert_entry(unary_entry!("not", ::std::ops::Not::not));

		dict.insert_entry(nonary_entry!("bye", ::std::process::exit(0)));

		dict.insert_entry(Entry::new("<",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let y = stack.pop().unwrap();
					let x = stack.pop().unwrap();
					stack.push(if x < y { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new(">",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let y = stack.pop().unwrap();
					let x = stack.pop().unwrap();
					stack.push(if x > y { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("=",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let y = stack.pop().unwrap();
					let x = stack.pop().unwrap();
					stack.push(if x == y { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("0<",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(if x < 0 { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("0=",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(if x == 0 { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("0>",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(if x > 0 { 1 } else { 0 });
				})),
			));

		dict.insert_entry(Entry::new("1+",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x + 1);
				})),
			));

		dict.insert_entry(Entry::new("1-",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x - 1);
				})),
			));

		dict.insert_entry(Entry::new("2+",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x + 2);
				})),
			));

		dict.insert_entry(Entry::new("2-",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x - 2);
				})),
			));

		dict.insert_entry(Entry::new("2/",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x >> 1); // Per fst83 standard
				})),
			));

		dict.insert_entry(Entry::new("dup",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					stack.push(x.clone());
					stack.push(x);
				})),
			));

		dict.insert_entry(Entry::new("?dup",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					if x != 0 {
						stack.push(x.clone());
						stack.push(x);
					} else {
						stack.push(x);
					}
				})),
			));

		dict.insert_entry(Entry::new("over",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					let y = stack.pop().unwrap();
					stack.push(x.clone());
					stack.push(y);
					stack.push(x);
				})),
			));

		dict.insert_entry(Entry::new("swap",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					let y = stack.pop().unwrap();
					stack.push(x);
					stack.push(y);
				})),
			));

		dict.insert_entry(Entry::new("rot",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					let x = stack.pop().unwrap();
					let y = stack.pop().unwrap();
					let z = stack.pop().unwrap();
					stack.push(y);
					stack.push(x);
					stack.push(z);
				})),
			));

		dict.insert_entry(Entry::new("dump",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					println!("ds =  {:?} ", stack);
				})),
			));

		dict.insert_entry(Entry::new("cr",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					println!("");
				})),
			));

		dict.insert_entry(Entry::new(".",
				Code::Native(Box::new(|interp: &mut Interpreter, stack: &mut Stack| {
					println!("{}", stack.pop().unwrap());
				})),
			));

		let square = {
			let mut s = Statement::new();
			s.push_back(Op::Word(dict.get("dup").unwrap().clone()));
			s.push_back(Op::Word(dict.get("*").unwrap().clone()));
			Code::Forth(s)
		};
		dict.insert_entry(Entry::new("square", square));

		Interpreter {
			dictionary: dict,
		}
	}

	fn exec(&mut self, statement: &str) {
		let mut words = statement.split(|c: char| c.is_whitespace());
		let mut stmt = Statement::new();
		while let Some(word) = words.next() { match word {
			"(" => while let Some(w) = words.next() { if w == ")" { break; } },
			"\\" => while let Some(w) = words.next() { if w == "\n" { break; } },
			":" => {
				let mut comp = Statement::new();
				let name = words.next().unwrap();
				while let Some(w) = words.next() {
					if w == ";" { break; }
					match w.parse::<i32>() {
						Ok(n) => comp.push_back(Op::Number(n)),
						Err(_) => comp.push_back(Op::Word(self.dictionary.get(w).unwrap().clone())),
					}
				}
				self.dictionary.insert_entry(Entry::from_statement(name, comp));
			},
			_ => match word.parse::<i32>() {
				Ok(n) => {
					stmt.push_back(Op::Number(n));
				},
				Err(e) => {
					if let Some(elem) = self.dictionary.get(word) {
						stmt.push_back(Op::Word(elem.clone()));
					} else {
						println!("Invalid word: {}", word);
						return;
					}
				},
			},

		}}

		stmt.run(self);
	}
}

fn main() {
	println!("forth-rs version 0.1.0");
	println!("Type 'bye' to exit");
    let mut interp = Interpreter::new();
    let mut stdin = io::stdin();
    loop {
    	print!("Forth> ");
    	io::stdout().flush().ok().expect("Could not flush stdout");
    	let mut line = String::new();
    	stdin.read_line(&mut line).ok().expect("Unable to read from stdin");
    	let result = interp.exec(line.trim());
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(unicode)]

//modules

mod config;
mod word;

//extern crates

extern crate rand;
extern crate rustc_serialize;
extern crate regex;

//use

use config::*;
use word::*;
use std::io::prelude::*;
//use rustc_serialize::*;    //commented out as it is only used to emit test configs
use std::fs::File;
use rand::distributions::Weighted;

//static variables

static CONFIG_FILE_NAME: &'static str = "main_config.json";

//functions

fn main() {
    let config: WordGeneratorConfig = load_config(&CONFIG_FILE_NAME);

    //comment other code and uncomment these to emit a new test config
    //let mut file = File::create(&CONFIG_FILE_NAME).unwrap();

    /*match file.write(json::encode(&config).unwrap().as_bytes()) {
        Ok(_) => (),
        Err(err) => panic!("Error writing test config: {}", err),
    }*/

    let mut first_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut last_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut normal_syllable_list : Vec<Weighted<String>> = Vec::new();

    //generate weighted lists of syllable configurations in each syllable position

    for syllable in &config.syllables {
        let syllable_weighted : Weighted<String> = Weighted{
            weight: syllable.weight as u32,
            item: syllable.string.clone()
        };
        //if the syllable is eligible for all positions
        if !(syllable.only_first_syllable || syllable.only_last_syllable) {
            normal_syllable_list.push(syllable_weighted.clone());
            first_syllable_list.push(syllable_weighted.clone());
            last_syllable_list.push(syllable_weighted.clone());
        }
        //these need to be separate ifs, as marking only first + only last syllable means it can be used for either
        if syllable.only_first_syllable {
            first_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_last_syllable {
            last_syllable_list.push(syllable_weighted.clone());
        }

    }

    let grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = transform_graphemes(&config.graphemes);

    let word_factory : WordFactory = WordFactory {
        first_syllable_list : first_syllable_list,
        normal_syllable_list : normal_syllable_list,
        last_syllable_list : last_syllable_list,
        graphemes : grapheme_groups,
        generate_settings : config.generate_settings.clone(),
        rewrites : config.rewrites.clone(),
        rejects : config.rejects.clone(),
    };

    let mut file = File::create(&config.output_settings.output_file).unwrap();

    for word in generate_word_list(&config, &word_factory) {
        match file.write(get_word_graphemes(&word).as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
        match file.write("\n".as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
    }
}

fn generate_word_list(config : &WordGeneratorConfig, word_factory : &WordFactory) -> Vec<Word> {
    let mut word_list : Vec<Word> = Vec::new();

    for _ in 0..config.output_settings.word_count {

        let mut word : Word = Word {
            syllables : String::new(),
            graphemes : String::new(),
            syllable_rewrite_history : Vec::new(),
            grapheme_rewrite_history : Vec::new(),
            syllable_rejects : Vec::new(),
            grapheme_rejects : Vec::new()
        };

        word_factory.generate_syllables(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_syllables(&mut word);
            word_factory.mark_syllable_rejects(&mut word);
        } else {
            word_factory.mark_syllable_rejects(&mut word);
            word_factory.rewrite_syllables(&mut word);
        };

        word_factory.generate_graphemes(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_graphemes(&mut word);
            word_factory.mark_grapheme_rejects(&mut word);
        } else {
            word_factory.mark_grapheme_rejects(&mut word);
            word_factory.rewrite_graphemes(&mut word);
        };
        word_list.push(word);
    }
    word_list
}

//unwraps a list of GraphemeGroups into a tuple list of String and Vec<Weighted<String>>, mostly due to requirement of Weighted for random weighted samples later
fn transform_graphemes(graphemes : &Vec<GraphemeGroup>) -> Vec<(String, Vec<Weighted<String>>)> {

    let mut grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = Vec::new();

    for group in graphemes {
        let mut graphemes_converted : Vec<Weighted<String>> = Vec::new();

        graphemes_converted.extend(
            group.graphemes.iter().map(
                |g: &Grapheme| Weighted{weight: g.weight as u32, item: g.string.clone() }
                )
            );
        grapheme_groups.push((group.name.clone(), graphemes_converted));
    }
    grapheme_groups
}
<commit_msg>words marked for rejection are now actually ommited from word file<commit_after>#![feature(collections)]
#![feature(unicode)]

//modules

mod config;
mod word;

//extern crates

extern crate rand;
extern crate rustc_serialize;
extern crate regex;

//use

use config::*;
use word::*;
use std::io::prelude::*;
//use rustc_serialize::*;    //commented out as it is only used to emit test configs
use std::fs::File;
use rand::distributions::Weighted;

//static variables

static CONFIG_FILE_NAME: &'static str = "main_config.json";

//functions

fn main() {
    let config: WordGeneratorConfig = load_config(&CONFIG_FILE_NAME);

    //comment other code and uncomment these to emit a new test config
    //let mut file = File::create(&CONFIG_FILE_NAME).unwrap();

    /*match file.write(json::encode(&config).unwrap().as_bytes()) {
        Ok(_) => (),
        Err(err) => panic!("Error writing test config: {}", err),
    }*/

    let mut first_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut last_syllable_list : Vec<Weighted<String>> = Vec::new();
    let mut normal_syllable_list : Vec<Weighted<String>> = Vec::new();

    //generate weighted lists of syllable configurations in each syllable position

    for syllable in &config.syllables {
        let syllable_weighted : Weighted<String> = Weighted{
            weight: syllable.weight as u32,
            item: syllable.string.clone()
        };
        //if the syllable is eligible for all positions
        if !(syllable.only_first_syllable || syllable.only_last_syllable) {
            normal_syllable_list.push(syllable_weighted.clone());
            first_syllable_list.push(syllable_weighted.clone());
            last_syllable_list.push(syllable_weighted.clone());
        }
        //these need to be separate ifs, as marking only first + only last syllable means it can be used for either
        if syllable.only_first_syllable {
            first_syllable_list.push(syllable_weighted.clone());
        }
        if syllable.only_last_syllable {
            last_syllable_list.push(syllable_weighted.clone());
        }

    }

    let grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = transform_graphemes(&config.graphemes);

    let word_factory : WordFactory = WordFactory {
        first_syllable_list : first_syllable_list,
        normal_syllable_list : normal_syllable_list,
        last_syllable_list : last_syllable_list,
        graphemes : grapheme_groups,
        generate_settings : config.generate_settings.clone(),
        rewrites : config.rewrites.clone(),
        rejects : config.rejects.clone(),
    };

    let mut file = File::create(&config.output_settings.output_file).unwrap();

    for word in generate_word_list(&config, &word_factory) {
        //if the word has been rejected then ignore it and don't print it
        if word.syllable_rejects.len() > 0 || word.grapheme_rejects.len() > 0 {
            continue;
        }
        match file.write(get_word_graphemes(&word).as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
        match file.write("\n".as_bytes()) {
                Err(error) => panic!("error {} writing to file", error),
                Ok(_) => (),
        };
    }
}

fn generate_word_list(config : &WordGeneratorConfig, word_factory : &WordFactory) -> Vec<Word> {
    let mut word_list : Vec<Word> = Vec::new();

    for _ in 0..config.output_settings.word_count {

        let mut word : Word = Word {
            syllables : String::new(),
            graphemes : String::new(),
            syllable_rewrite_history : Vec::new(),
            grapheme_rewrite_history : Vec::new(),
            syllable_rejects : Vec::new(),
            grapheme_rejects : Vec::new()
        };

        word_factory.generate_syllables(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_syllables(&mut word);
            word_factory.mark_syllable_rejects(&mut word);
        } else {
            word_factory.mark_syllable_rejects(&mut word);
            word_factory.rewrite_syllables(&mut word);
        };

        word_factory.generate_graphemes(&mut word);

        if config.generate_settings.rewrites_before_rejects {
            word_factory.rewrite_graphemes(&mut word);
            word_factory.mark_grapheme_rejects(&mut word);
        } else {
            word_factory.mark_grapheme_rejects(&mut word);
            word_factory.rewrite_graphemes(&mut word);
        };
        word_list.push(word);
    }
    word_list
}

//unwraps a list of GraphemeGroups into a tuple list of String and Vec<Weighted<String>>, mostly due to requirement of Weighted for random weighted samples later
fn transform_graphemes(graphemes : &Vec<GraphemeGroup>) -> Vec<(String, Vec<Weighted<String>>)> {

    let mut grapheme_groups : Vec<(String, Vec<Weighted<String>>)> = Vec::new();

    for group in graphemes {
        let mut graphemes_converted : Vec<Weighted<String>> = Vec::new();

        graphemes_converted.extend(
            group.graphemes.iter().map(
                |g: &Grapheme| Weighted{weight: g.weight as u32, item: g.string.clone() }
                )
            );
        grapheme_groups.push((group.name.clone(), graphemes_converted));
    }
    grapheme_groups
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate window;
extern crate opengl_graphics;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate chip8_vm;

use std::cell::RefCell;
use std::rc::Rc;
use sdl2_window::Sdl2Window;
use window::WindowSettings;
use opengl_graphics::{
    Gl,
};

use std::env;
use std::io::{Read, BufReader};
use std::fs::File;
use std::path::Path;
use input::Button;

use chip8_vm::vm::Vm;

const TITLE: &'static str = "Chip8";
const BEEP_TITLE: &'static str = "♬ Chip8 ♬";

const INTRO_ROM: &'static [u8] = include_bytes!("intro/intro.ch8");

fn main() {
    env_logger::init().unwrap();

    let mut vm = Vm::new();

    let mut rom: Option<File> = None;

    if let Some(rom_path) = env::args().skip(1).next() {
        if let Ok(f) = File::open(&Path::new(&rom_path)) {
            rom = Some(f);
        } else {
            error!("Could not open ROM {}", rom_path);
        }
    }

    // rustc warns about the "trivial casts" to Read,
    // but without those the match arms are incompatible.
    // This part of the code might be obsoleted by #26
    let intro_reader = &mut BufReader::new(INTRO_ROM) as &mut Read;
    let mut rom_reader = match &mut rom {
        &mut Some(ref mut r) => r as &mut Read,
        _ => {
            info!("You can provide a path to a CHIP-8 ROM to run it.");
            intro_reader
        }
    };

    match vm.load_rom(rom_reader) {
        Ok(size) => debug!("Loaded ROM of size: {}", size),
        Err(e) => {
            error!("Error loading ROM: {}", e);
            return;
        }
    }

    let (width, height) = (800, 400);
    let opengl = shader_version::OpenGL::_3_2;
    let settings = WindowSettings::new(
        TITLE.to_string(),
        window::Size {
            width: width,
            height: height
        }
    );
    let window = Sdl2Window::new(
        opengl,
        settings
    );

    let ref mut gl = Gl::new(opengl);
    let window = Rc::new(RefCell::new(window));

    fn keymap(k: Option<Button>) -> Option<u8> {
        use input::Key::*;
        if let Some(Button::Keyboard(k)) = k {
            return match k {
                D1 => Some(0x1),
                D2 => Some(0x2),
                D3 => Some(0x3),

                Q  => Some(0x4),
                W  => Some(0x5),
                E  => Some(0x6),

                A  => Some(0x7),
                S  => Some(0x8),
                D  => Some(0x9),

                Z  => Some(0xA),
                X  => Some(0x0),
                C  => Some(0xB),

                D4 => Some(0xC),
                R  => Some(0xD),
                F  => Some(0xE),
                V  => Some(0xF),

                _ => None
            }
        }
        return None
    }

    for e in event::events(window.clone()) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            vm.step(args.dt as f32);
            if vm.beeping() {
                (window.borrow_mut()).window.set_title(BEEP_TITLE).unwrap();
            } else {
                (window.borrow_mut()).window.set_title(TITLE).unwrap();
            }
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
                let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
                let off = [0.0, 0.0, 0.0, 1.0];
                let on = [1.0, 1.0, 1.0, 1.0];

                let w = args.width as f64 / 64.0;
                let h = args.height as f64 / 32.0;

                for (y,row) in vm.screen_rows().enumerate() {
                    for (x,byte) in row.iter().enumerate() {
                        let x = x as f64 * w;
                        let y = y as f64 * h;
                        let color = match *byte { 0 => off, _ => on };
                        r.color(color).draw([x, y, w, h], &c.draw_state, c.transform, gl);
                    }
                }
            });
        }
        if let Some(keynum) = keymap(e.press_args()) {
            vm.set_key(keynum);
        }
        if let Some(keynum) = keymap(e.release_args()) {
            vm.unset_key(keynum);
        }
    }
}
<commit_msg>Exit on Esc again<commit_after>#![cfg_attr(test, allow(dead_code))]

extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate window;
extern crate opengl_graphics;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate chip8_vm;

use std::cell::RefCell;
use std::rc::Rc;
use sdl2_window::Sdl2Window;
use window::WindowSettings;
use opengl_graphics::{
    Gl,
};

use std::env;
use std::io::{Read, BufReader};
use std::fs::File;
use std::path::Path;
use input::Button;

use chip8_vm::vm::Vm;

const TITLE: &'static str = "Chip8";
const BEEP_TITLE: &'static str = "♬ Chip8 ♬";

const INTRO_ROM: &'static [u8] = include_bytes!("intro/intro.ch8");

fn main() {
    env_logger::init().unwrap();

    let mut vm = Vm::new();

    let mut rom: Option<File> = None;

    if let Some(rom_path) = env::args().skip(1).next() {
        if let Ok(f) = File::open(&Path::new(&rom_path)) {
            rom = Some(f);
        } else {
            error!("Could not open ROM {}", rom_path);
        }
    }

    // rustc warns about the "trivial casts" to Read,
    // but without those the match arms are incompatible.
    // This part of the code might be obsoleted by #26
    let intro_reader = &mut BufReader::new(INTRO_ROM) as &mut Read;
    let mut rom_reader = match &mut rom {
        &mut Some(ref mut r) => r as &mut Read,
        _ => {
            info!("You can provide a path to a CHIP-8 ROM to run it.");
            intro_reader
        }
    };

    match vm.load_rom(rom_reader) {
        Ok(size) => debug!("Loaded ROM of size: {}", size),
        Err(e) => {
            error!("Error loading ROM: {}", e);
            return;
        }
    }

    let (width, height) = (800, 400);
    let opengl = shader_version::OpenGL::_3_2;
    let settings = WindowSettings::new(
        TITLE.to_string(),
        window::Size {
            width: width,
            height: height
        }
    ).exit_on_esc(true);
    let window = Sdl2Window::new(
        opengl,
        settings
    );

    let ref mut gl = Gl::new(opengl);
    let window = Rc::new(RefCell::new(window));

    fn keymap(k: Option<Button>) -> Option<u8> {
        use input::Key::*;
        if let Some(Button::Keyboard(k)) = k {
            return match k {
                D1 => Some(0x1),
                D2 => Some(0x2),
                D3 => Some(0x3),

                Q  => Some(0x4),
                W  => Some(0x5),
                E  => Some(0x6),

                A  => Some(0x7),
                S  => Some(0x8),
                D  => Some(0x9),

                Z  => Some(0xA),
                X  => Some(0x0),
                C  => Some(0xB),

                D4 => Some(0xC),
                R  => Some(0xD),
                F  => Some(0xE),
                V  => Some(0xF),

                _ => None
            }
        }
        return None
    }

    for e in event::events(window.clone()) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            vm.step(args.dt as f32);
            if vm.beeping() {
                (window.borrow_mut()).window.set_title(BEEP_TITLE).unwrap();
            } else {
                (window.borrow_mut()).window.set_title(TITLE).unwrap();
            }
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
                let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
                let off = [0.0, 0.0, 0.0, 1.0];
                let on = [1.0, 1.0, 1.0, 1.0];

                let w = args.width as f64 / 64.0;
                let h = args.height as f64 / 32.0;

                for (y,row) in vm.screen_rows().enumerate() {
                    for (x,byte) in row.iter().enumerate() {
                        let x = x as f64 * w;
                        let y = y as f64 * h;
                        let color = match *byte { 0 => off, _ => on };
                        r.color(color).draw([x, y, w, h], &c.draw_state, c.transform, gl);
                    }
                }
            });
        }
        if let Some(keynum) = keymap(e.press_args()) {
            vm.set_key(keynum);
        }
        if let Some(keynum) = keymap(e.release_args()) {
            vm.unset_key(keynum);
        }
    }
}
<|endoftext|>


<commit_before>//! An implementation of [tldr](https://github.com/tldr-pages/tldr) in Rust.

#[macro_use] extern crate log;
#[cfg(feature = "logging")]extern crate env_logger;
extern crate docopt;
extern crate ansi_term;
extern crate flate2;
extern crate tar;
extern crate curl;
extern crate rustc_serialize;
extern crate time;

use std::io::BufReader;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process;

use docopt::Docopt;

mod types;
mod tokenizer;
mod formatter;
mod cache;
mod error;

use tokenizer::Tokenizer;
use cache::Cache;
use error::TldrError::{UpdateError, CacheError};
use formatter::print_lines;
use types::OsType;

const NAME: &'static str = "tldr-rs";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
Usage:

    tldr <command>
    tldr [options]

Options:

    -h --help           Show this screen
    -v --version        Show version information
    -l --list           List all commands in the cache
    -f --render <file>  Render a specific markdown file
    -o --os <type>      Override the operating system [linux, osx, sunos]
    -u --update         Update the local cache
    -c --clear-cache    Clear the local cache

Examples:

    $ tldr tar
    $ tldr --list

To control the cache:

    $ tldr --update
    $ tldr --clear-cache

To render a local file (for testing):

    $ tldr --render /path/to/file.md
";
const ARCHIVE_URL: &'static str = "https://github.com/tldr-pages/tldr/archive/master.tar.gz";
const MAX_CACHE_AGE: i64 = 2592000; // 30 days

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_command: Option<String>,
    flag_help: bool,
    flag_version: bool,
    flag_list: bool,
    flag_render: Option<String>,
    flag_os: Option<OsType>,
    flag_update: bool,
    flag_clear_cache: bool,
}

/// Print page by path
fn print_page(path: &Path) -> Result<(), String> {
    // Open file
    let file = try!(
        File::open(path).map_err(|msg| format!("Could not open file: {}", msg))
    );
    let reader = BufReader::new(file);

    // Create tokenizer and print output
    let mut tokenizer = Tokenizer::new(reader);
    print_lines(&mut tokenizer);

    Ok(())
}

#[cfg(feature = "logging")]
fn init_log() {
    env_logger::init().unwrap();
}

#[cfg(not(feature = "logging"))]
fn init_log() { }

#[cfg(target_os = "linux")]
fn get_os() -> OsType { OsType::Linux }

#[cfg(target_os = "macos")]
fn get_os() -> OsType { OsType::OsX }

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_os() -> OsType { OsType::Other }

fn main() {

    // Initialize logger
    init_log();

    // Parse arguments
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    // Show version and exit
    if args.flag_version {
        println!("{} v{}", NAME, VERSION);
        process::exit(0);
    }

    // Initialize cache
    let os: OsType = get_os();
    let cache = Cache::new(ARCHIVE_URL, os);

    // Clear cache, pass through
    if args.flag_clear_cache {
        cache.clear().unwrap_or_else(|e| {
            match e {
                UpdateError(msg) | CacheError(msg) => println!("Could not delete cache: {}", msg),
            };
            process::exit(1);
        });
        println!("Successfully deleted cache.");
    }

    // Update cache, pass through
    if args.flag_update {
        cache.update().unwrap_or_else(|e| {
            match e {
                UpdateError(msg) | CacheError(msg) => println!("Could not update cache: {}", msg),
            };
            process::exit(1);
        });
        println!("Successfully updated cache.");
    }

    // Render local file and exit
    if let Some(file) = args.flag_render {
        let path = PathBuf::from(file);
        if let Err(msg) = print_page(&path) {
            println!("{}", msg);
            process::exit(1);
        } else {
            process::exit(0);
        };
    }

    // List cached commands and exit
    if args.flag_list {
        println!("Flag --list not yet implemented.");
        process::exit(1);
    }

    // Show command from cache
    if let Some(command) = args.arg_command {

        // Check cache
        if !args.flag_update {
            match cache.last_update() {
                Some(ago) if ago > MAX_CACHE_AGE => {
                    println!("Cache wasn't updated in {} days.", MAX_CACHE_AGE / 24 / 3600);
                    println!("You should probably run `tldr --update` soon.");
                },
                None => {
                    println!("Cache not found. Please run `tldr --update`.");
                    process::exit(1);
                },
                _ => {},
            }
        }

        // Search for command in cache
        if let Some(path) = cache.find_page(&command) {
            if let Err(msg) = print_page(&path) {
                println!("{}", msg);
                process::exit(1);
            } else {
                process::exit(0);
            }
        } else {
            println!("Page {} not found in cache", &command);
            println!("Try updating with `tldr --update`, or submit a pull request to:");
            println!("https://github.com/tldr-pages/tldr");
            process::exit(1);
        }
    }

    // Some flags can be run without a command.
    if !(args.flag_update || args.flag_clear_cache) {
        println!("{}", USAGE);
        process::exit(1);
    }
}

#[cfg(test)]
mod test {
    use types::LineType;

    #[test]
    fn test_linetype_from_str() {
        assert_eq!(LineType::from(""), LineType::Empty);
        assert_eq!(LineType::from(" \n \r"), LineType::Empty);
        assert_eq!(LineType::from("# Hello there"), LineType::Title("Hello there".into()));
        assert_eq!(LineType::from("> tis a description \n"), LineType::Description("tis a description".into()));
        assert_eq!(LineType::from("- some command"), LineType::ExampleText("some command".into()));
        assert_eq!(LineType::from("`$ cargo run`"), LineType::ExampleCode("$ cargo run".into()));
        assert_eq!(LineType::from("`$ cargo run"), LineType::Other("`$ cargo run".into()));
        assert_eq!(LineType::from("jklö"), LineType::Other("jklö".into()));
    }
}
<commit_msg>Fix argument format<commit_after>//! An implementation of [tldr](https://github.com/tldr-pages/tldr) in Rust.

#[macro_use] extern crate log;
#[cfg(feature = "logging")]extern crate env_logger;
extern crate docopt;
extern crate ansi_term;
extern crate flate2;
extern crate tar;
extern crate curl;
extern crate rustc_serialize;
extern crate time;

use std::io::BufReader;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process;

use docopt::Docopt;

mod types;
mod tokenizer;
mod formatter;
mod cache;
mod error;

use tokenizer::Tokenizer;
use cache::Cache;
use error::TldrError::{UpdateError, CacheError};
use formatter::print_lines;
use types::OsType;

const NAME: &'static str = "tldr-rs";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
Usage:

    tldr [options] <command>
    tldr [options]

Options:

    -h --help           Show this screen
    -v --version        Show version information
    -l --list           List all commands in the cache
    -f --render <file>  Render a specific markdown file
    -o --os <type>      Override the operating system [linux, osx, sunos]
    -u --update         Update the local cache
    -c --clear-cache    Clear the local cache

Examples:

    $ tldr tar
    $ tldr --list

To control the cache:

    $ tldr --update
    $ tldr --clear-cache

To render a local file (for testing):

    $ tldr --render /path/to/file.md
";
const ARCHIVE_URL: &'static str = "https://github.com/tldr-pages/tldr/archive/master.tar.gz";
const MAX_CACHE_AGE: i64 = 2592000; // 30 days

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_command: Option<String>,
    flag_help: bool,
    flag_version: bool,
    flag_list: bool,
    flag_render: Option<String>,
    flag_os: Option<OsType>,
    flag_update: bool,
    flag_clear_cache: bool,
}

/// Print page by path
fn print_page(path: &Path) -> Result<(), String> {
    // Open file
    let file = try!(
        File::open(path).map_err(|msg| format!("Could not open file: {}", msg))
    );
    let reader = BufReader::new(file);

    // Create tokenizer and print output
    let mut tokenizer = Tokenizer::new(reader);
    print_lines(&mut tokenizer);

    Ok(())
}

#[cfg(feature = "logging")]
fn init_log() {
    env_logger::init().unwrap();
}

#[cfg(not(feature = "logging"))]
fn init_log() { }

#[cfg(target_os = "linux")]
fn get_os() -> OsType { OsType::Linux }

#[cfg(target_os = "macos")]
fn get_os() -> OsType { OsType::OsX }

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_os() -> OsType { OsType::Other }

fn main() {

    // Initialize logger
    init_log();

    // Parse arguments
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    // Show version and exit
    if args.flag_version {
        println!("{} v{}", NAME, VERSION);
        process::exit(0);
    }

    // Initialize cache
    let os: OsType = get_os();
    let cache = Cache::new(ARCHIVE_URL, os);

    // Clear cache, pass through
    if args.flag_clear_cache {
        cache.clear().unwrap_or_else(|e| {
            match e {
                UpdateError(msg) | CacheError(msg) => println!("Could not delete cache: {}", msg),
            };
            process::exit(1);
        });
        println!("Successfully deleted cache.");
    }

    // Update cache, pass through
    if args.flag_update {
        cache.update().unwrap_or_else(|e| {
            match e {
                UpdateError(msg) | CacheError(msg) => println!("Could not update cache: {}", msg),
            };
            process::exit(1);
        });
        println!("Successfully updated cache.");
    }

    // Render local file and exit
    if let Some(file) = args.flag_render {
        let path = PathBuf::from(file);
        if let Err(msg) = print_page(&path) {
            println!("{}", msg);
            process::exit(1);
        } else {
            process::exit(0);
        };
    }

    // List cached commands and exit
    if args.flag_list {
        println!("Flag --list not yet implemented.");
        process::exit(1);
    }

    // Show command from cache
    if let Some(command) = args.arg_command {

        // Check cache
        if !args.flag_update {
            match cache.last_update() {
                Some(ago) if ago > MAX_CACHE_AGE => {
                    println!("Cache wasn't updated in {} days.", MAX_CACHE_AGE / 24 / 3600);
                    println!("You should probably run `tldr --update` soon.");
                },
                None => {
                    println!("Cache not found. Please run `tldr --update`.");
                    process::exit(1);
                },
                _ => {},
            }
        }

        // Search for command in cache
        if let Some(path) = cache.find_page(&command) {
            if let Err(msg) = print_page(&path) {
                println!("{}", msg);
                process::exit(1);
            } else {
                process::exit(0);
            }
        } else {
            println!("Page {} not found in cache", &command);
            println!("Try updating with `tldr --update`, or submit a pull request to:");
            println!("https://github.com/tldr-pages/tldr");
            process::exit(1);
        }
    }

    // Some flags can be run without a command.
    if !(args.flag_update || args.flag_clear_cache) {
        println!("{}", USAGE);
        process::exit(1);
    }
}

#[cfg(test)]
mod test {
    use types::LineType;

    #[test]
    fn test_linetype_from_str() {
        assert_eq!(LineType::from(""), LineType::Empty);
        assert_eq!(LineType::from(" \n \r"), LineType::Empty);
        assert_eq!(LineType::from("# Hello there"), LineType::Title("Hello there".into()));
        assert_eq!(LineType::from("> tis a description \n"), LineType::Description("tis a description".into()));
        assert_eq!(LineType::from("- some command"), LineType::ExampleText("some command".into()));
        assert_eq!(LineType::from("`$ cargo run`"), LineType::ExampleCode("$ cargo run".into()));
        assert_eq!(LineType::from("`$ cargo run"), LineType::Other("`$ cargo run".into()));
        assert_eq!(LineType::from("jklö"), LineType::Other("jklö".into()));
    }
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#![feature(negate_unsigned)]
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate num;
extern crate rand;

mod ops;
mod extensions;
mod memory;
mod cpu;

use memory::GameboyMemory;
use cpu::Cpu;

fn main() {
    let mut memory = Box::new(GameboyMemory::new(0x10000));
    let mut cpu = Cpu::new(memory);

    let mut count: u64 = 0;
//    let mut handle = stdin();
    loop {
        debug!("cycle: {}", count);
        /*
        if count % 10 == 0 {
//            let val = handle.read_char();
        }
       */
        let clock_cycle = cpu.tick();
        count += 1;
    }

}
<commit_msg>Enable logging<commit_after>#![feature(box_syntax)]
#![feature(negate_unsigned)]
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate num;
extern crate rand;

mod ops;
mod extensions;
mod memory;
mod cpu;

use memory::GameboyMemory;
use cpu::Cpu;

fn main() {
    env_logger::init().unwrap();
    let mut memory = Box::new(GameboyMemory::new(0x10000));
    let mut cpu = Cpu::new(memory);

    let mut count: u64 = 0;
//    let mut handle = stdin();
    loop {
        debug!("cycle: {}", count);
        /*
        if count % 10 == 0 {
//            let val = handle.read_char();
        }
       */
        let clock_cycle = cpu.tick();
        count += 1;
    }

}
<|endoftext|>


<commit_before>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate serde_derive;
extern crate spaceapi_server;

use docopt::Docopt;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{PeopleNowPresentSensorTemplate, TemperatureSensorTemplate};
use spaceapi_server::modifiers::StateFromPeopleNowPresent;
use spaceapi_server::SpaceapiServerBuilder;
use std::env;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The IP address to listen on [default: 127.0.0.1].
";

#[derive(Deserialize, Debug)]
struct Args {
    flag_p: u16,
    flag_i: std::net::IpAddr,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init();

    // Parse arguments
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::StatusBuilder::new("coredump")
        .logo("https://www.coredump.ch/wp-content/uploads/2016/11/logo.png")
        .url("https://www.coredump.ch/")
        .location(api::Location {
            address: Some("Holzwiesstrasse 50, 8645 Jona, Switzerland".into()),
            lat: 47.2359607,
            lon: 8.8410057,
        })
        .contact(api::Contact {
            irc: Some("irc://freenode.net/#coredump".into()),
            twitter: Some("@coredump_ch".into()),
            email: Some("vorstand@lists.coredump.ch".into()),
            ..Default::default()
        })
        .add_issue_report_channel("email")
        .add_issue_report_channel("twitter")
        .spacefed(api::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        })
        .feeds(api::Feeds {
            blog: Some(api::Feed {
                type_: Some("rss".into()),
                url: "https://www.coredump.ch/feed/".into(),
            }),
            wiki: None,
            calendar: None,
            flickr: None,
        })
        .add_project("https://www.coredump.ch/projekte/")
        .add_project("https://forum.coredump.ch/c/projects")
        .add_project("https://github.com/coredump-ch/")
        .add_cam("https://webcam.coredump.ch/cams/ultimaker_0.jpg")
        .add_extension("ccc", "chaostreff")
        .build()
        .expect("Couldn't create status object");

    // Set state message
    status.state.message = Some("Open Mondays from 20:00".into());

    // Redis connection info
    let redis_host: String = env::var("REDIS_HOST").unwrap_or("127.0.0.1".to_string());
    let redis_port: u16 = env::var("REDIS_PORT")
        .unwrap_or("6379".to_string())
        .parse()
        .unwrap_or(6379);
    let redis_db: i64 = env::var("REDIS_DB")
        .unwrap_or("0".to_string())
        .parse()
        .unwrap_or(0);
    let redis_url = format!("redis://{}:{}/{}", redis_host, redis_port, redis_db);

    // Create server
    let server = SpaceapiServerBuilder::new(status)
        .redis_connection_info(&*redis_url)
        .add_status_modifier(StateFromPeopleNowPresent)
        .add_sensor(
            TemperatureSensorTemplate {
                unit: "°C".into(),
                location: "Hackerspace".into(),
                name: Some("Raspberry CPU".into()),
                description: None,
            },
            "temperature_raspi".into(),
        )
        .add_sensor(
            TemperatureSensorTemplate {
                unit: "°C".into(),
                location: "Hackerspace".into(),
                name: Some("Room Temperature (Entrance)".into()),
                description: None,
            },
            "temperature_entrance".into(),
        )
        .add_sensor(
            TemperatureSensorTemplate {
                unit: "°C".into(),
                location: "Hackerspace".into(),
                name: Some("Room Temperature (Tables)".into()),
                description: None,
            },
            "temperature_tables".into(),
        )
        .add_sensor(
            PeopleNowPresentSensorTemplate {
                location: Some("Hackerspace".into()),
                name: None,
                description: None,
                names: None,
            },
            "people_now_present".into(),
        )
        .build()
        .expect("Could not build server");

    server.serve((host, port)).expect("Could not start the server");
}
<commit_msg>Add calendar feed<commit_after>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate docopt;
extern crate env_logger;
#[macro_use]
extern crate serde_derive;
extern crate spaceapi_server;

use docopt::Docopt;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{PeopleNowPresentSensorTemplate, TemperatureSensorTemplate};
use spaceapi_server::modifiers::StateFromPeopleNowPresent;
use spaceapi_server::SpaceapiServerBuilder;
use std::env;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The IP address to listen on [default: 127.0.0.1].
";

#[derive(Deserialize, Debug)]
struct Args {
    flag_p: u16,
    flag_i: std::net::IpAddr,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init();

    // Parse arguments
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::StatusBuilder::new("coredump")
        .logo("https://www.coredump.ch/wp-content/uploads/2016/11/logo.png")
        .url("https://www.coredump.ch/")
        .location(api::Location {
            address: Some("Holzwiesstrasse 50, 8645 Jona, Switzerland".into()),
            lat: 47.2359607,
            lon: 8.8410057,
        })
        .contact(api::Contact {
            irc: Some("irc://freenode.net/#coredump".into()),
            twitter: Some("@coredump_ch".into()),
            email: Some("vorstand@lists.coredump.ch".into()),
            ..Default::default()
        })
        .add_issue_report_channel("email")
        .add_issue_report_channel("twitter")
        .spacefed(api::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        })
        .feeds(api::Feeds {
            blog: Some(api::Feed {
                type_: Some("rss".into()),
                url: "https://www.coredump.ch/feed/".into(),
            }),
            wiki: None,
            calendar: Some(api::Feed {
                type_: Some("ical".into()),
                url: "https://www.coredump.ch/events/?ical=1".into(),
            }),
            flickr: None,
        })
        .add_project("https://www.coredump.ch/projekte/")
        .add_project("https://forum.coredump.ch/c/projects")
        .add_project("https://github.com/coredump-ch/")
        .add_cam("https://webcam.coredump.ch/cams/ultimaker_0.jpg")
        .add_extension("ccc", "chaostreff")
        .build()
        .expect("Couldn't create status object");

    // Set state message
    status.state.message = Some("Open Mondays from 20:00".into());

    // Redis connection info
    let redis_host: String = env::var("REDIS_HOST").unwrap_or("127.0.0.1".to_string());
    let redis_port: u16 = env::var("REDIS_PORT")
        .unwrap_or("6379".to_string())
        .parse()
        .unwrap_or(6379);
    let redis_db: i64 = env::var("REDIS_DB")
        .unwrap_or("0".to_string())
        .parse()
        .unwrap_or(0);
    let redis_url = format!("redis://{}:{}/{}", redis_host, redis_port, redis_db);

    // Create server
    let server = SpaceapiServerBuilder::new(status)
        .redis_connection_info(&*redis_url)
        .add_status_modifier(StateFromPeopleNowPresent)
        .add_sensor(
            TemperatureSensorTemplate {
                unit: "°C".into(),
                location: "Hackerspace".into(),
                name: Some("Raspberry CPU".into()),
                description: None,
            },
            "temperature_raspi".into(),
        )
        .add_sensor(
            TemperatureSensorTemplate {
                unit: "°C".into(),
                location: "Hackerspace".into(),
                name: Some("Room Temperature (Entrance)".into()),
                description: None,
            },
            "temperature_entrance".into(),
        )
        .add_sensor(
            TemperatureSensorTemplate {
                unit: "°C".into(),
                location: "Hackerspace".into(),
                name: Some("Room Temperature (Tables)".into()),
                description: None,
            },
            "temperature_tables".into(),
        )
        .add_sensor(
            PeopleNowPresentSensorTemplate {
                location: Some("Hackerspace".into()),
                name: None,
                description: None,
                names: None,
            },
            "people_now_present".into(),
        )
        .build()
        .expect("Could not build server");

    server.serve((host, port)).expect("Could not start the server");
}
<|endoftext|>


<commit_before>extern crate hkg;
extern crate rustbox;
extern crate rustc_serialize;

use std::default::Default;

use rustbox::{Color, RustBox};
use rustbox::Key;

use rustc_serialize::json;

use hkg::utility::cache;
use hkg::model::TopicItem;

fn main() {

    // GUI init
    let rustbox = match RustBox::init(Default::default()) {
        Result::Ok(v) => v,
        Result::Err(e) => panic!("{}", e),
    };

    loop {

        let w = rustbox.width();
        let h = rustbox.height();
        let title = String::from("高登");
        print_header(&rustbox, w, title);

        let s = cache::readfile(String::from("topics.json"));
        let collection: Vec<TopicItem> = json::decode(&s).unwrap();

        print_body(&rustbox, w, 2, h - 3, collection);

        rustbox.print(1,
                      h - 1,
                      rustbox::RB_BOLD,
                      Color::White,
                      Color::Black,
                      "Press 'q' to quit.");

        rustbox.present();
        match rustbox.poll_event(false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Key::Char('q') => {
                        break;
                    }
                    _ => {}
                }
            }
            Err(e) => panic!("{}", e),
            _ => {}
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: String) {
    let padding = (width - text.len()) / 2;
    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  &text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              collection: Vec<TopicItem>) {

    let right_offset = 3;
    let author_max_width = 12;
    let no_max_width = 5;
    let title_max_width = width - no_max_width - author_max_width - right_offset;
    let author_position = width - author_max_width - right_offset;

    for (i, item) in collection.iter().take(rows).enumerate() {

        let title: String = item.titles[0].text.chars().take(title_max_width/2).collect();
        let title_len = string_jks_len(&title);
        let title_spacin_minus = no_max_width + title_len + author_max_width + right_offset;
        let title_spacing_width = if width > title_spacin_minus {
            width - title_spacin_minus
        } else {
            0
        };
        let title_spacing = (0..title_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        let author = item.author.name.clone();
        let author_spacing_width = author_max_width - string_jks_len(&author) + right_offset;
        let author_spacing = (0..author_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        rustbox.print(0,
                      i + offset_y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
                               no = i + 1,
                               title = title,
                               title_spacing = title_spacing,
                               author = &author,
                               author_spacing = author_spacing
                           ));
    }

    rustbox.print(0,
                  rows + 2,
                  rustbox::RB_NORMAL,
                  Color::White,
                  Color::Black,
                  &format!("{} {}", title_max_width, author_position));

}

fn clearline(rustbox: &rustbox::RustBox, width: usize, x: usize, y: usize) {
    let s = (0..width).map(|_| "  ").collect::<Vec<_>>().join("");

    rustbox.print(x, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn contains(c: char) -> bool {
    let cjks = vec![(0x4E00..0xA000),
                    (0x3400..0x4DC0),
                    (0x20000..0x2A6E0),
                    (0x2A700..0x2B740),
                    (0x2B740..0x2B820),
                    (0xF900..0xFB00),
                    (0x2F800..0x2FA20),
                    (0x9FA6..0x9FCC),

                    (0x3000..0x303F), // CJK Symbols and Punctuation
                    (0xff00..0xffef) /* Halfwidth and Fullwidth Forms */];

    for cjk in cjks {
        let h = c as u32;
        if cjk.start <= h && h < cjk.end {
            return true;
        }
    }
    return false;
}

fn string_jks_len(s: &str) -> usize {
    return s.chars()
            .map(|x| if contains(x) {
                2
            } else {
                1
            })
            .collect::<Vec<usize>>()
            .iter()
            .fold(0, |acc, &x| acc + x);
}

// fn debug_load_and_print_topics() {
//     let s = cache::readfile(String::from("topics.json"));
//     let collection: Vec<TopicItem> = json::decode(&s).unwrap();
//
//     println!("topics {:?}", collection.len());
//     debug_print_topics(collection);
// }
//
// fn debug_print_topics(collection: Vec<TopicItem>) {
//     for (i, item) in collection.iter().enumerate() {
//
//         println!("item[{}]= {title} {author_name} {last_replied_date} {last_replied_time} \
//                   {reply_count} {rating}",
//                  i,
//                  title = item.titles[0].text,
//                  author_name = item.author.name,
//                  last_replied_date = item.last_replied_date,
//                  last_replied_time = item.last_replied_time,
//                  reply_count = item.reply_count,
//                  rating = item.rating);
//     }
// }
<commit_msg>clean up<commit_after>extern crate hkg;
extern crate rustbox;
extern crate rustc_serialize;

use std::default::Default;

use rustbox::{Color, RustBox};
use rustbox::Key;

use rustc_serialize::json;

use hkg::utility::cache;
use hkg::model::TopicItem;

fn main() {

    // GUI init
    let rustbox = match RustBox::init(Default::default()) {
        Result::Ok(v) => v,
        Result::Err(e) => panic!("{}", e),
    };

    loop {

        let w = rustbox.width();
        let h = rustbox.height();
        let title = String::from("高登");
        print_header(&rustbox, w, title);

        let s = cache::readfile(String::from("topics.json"));
        let collection: Vec<TopicItem> = json::decode(&s).unwrap();

        print_body(&rustbox, w, 2, h - 3, collection);

        rustbox.print(1,
                      h - 1,
                      rustbox::RB_BOLD,
                      Color::White,
                      Color::Black,
                      "Press 'q' to quit.");

        rustbox.present();
        match rustbox.poll_event(false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Key::Char('q') => {
                        break;
                    }
                    _ => {}
                }
            }
            Err(e) => panic!("{}", e),
            _ => {}
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: String) {
    let padding = (width - text.len()) / 2;
    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  &text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              collection: Vec<TopicItem>) {

    let right_offset = 3;
    let author_max_width = 12;
    let no_max_width = 5;
    let title_max_width = width - no_max_width - author_max_width - right_offset;

    for (i, item) in collection.iter().take(rows).enumerate() {

        let title: String = item.titles[0].text.chars().take(title_max_width/2).collect();
        let title_len = string_jks_len(&title);
        let title_spacin_minus = no_max_width + title_len + author_max_width + right_offset;
        let title_spacing_width = if width > title_spacin_minus {
            width - title_spacin_minus
        } else {
            0
        };
        let title_spacing = (0..title_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        let author = item.author.name.clone();
        let author_spacing_width = author_max_width - string_jks_len(&author) + right_offset;
        let author_spacing = (0..author_spacing_width).map(|_| " ").collect::<Vec<_>>().join("");

        rustbox.print(0,
                      i + offset_y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &format!("[{no:0>2}] {title}{title_spacing}| {author}{author_spacing}",
                               no = i + 1,
                               title = title,
                               title_spacing = title_spacing,
                               author = &author,
                               author_spacing = author_spacing
                           ));
    }

}

fn clearline(rustbox: &rustbox::RustBox, width: usize, x: usize, y: usize) {
    let s = (0..width).map(|_| "  ").collect::<Vec<_>>().join("");

    rustbox.print(x, y, rustbox::RB_NORMAL, Color::White, Color::Black, &s);
}

fn contains(c: char) -> bool {
    let cjks = vec![(0x4E00..0xA000),
                    (0x3400..0x4DC0),
                    (0x20000..0x2A6E0),
                    (0x2A700..0x2B740),
                    (0x2B740..0x2B820),
                    (0xF900..0xFB00),
                    (0x2F800..0x2FA20),
                    (0x9FA6..0x9FCC),

                    (0x3000..0x303F), // CJK Symbols and Punctuation
                    (0xff00..0xffef) /* Halfwidth and Fullwidth Forms */];

    for cjk in cjks {
        let h = c as u32;
        if cjk.start <= h && h < cjk.end {
            return true;
        }
    }
    return false;
}

fn string_jks_len(s: &str) -> usize {
    return s.chars()
            .map(|x| if contains(x) {
                2
            } else {
                1
            })
            .collect::<Vec<usize>>()
            .iter()
            .fold(0, |acc, &x| acc + x);
}

// fn debug_load_and_print_topics() {
//     let s = cache::readfile(String::from("topics.json"));
//     let collection: Vec<TopicItem> = json::decode(&s).unwrap();
//
//     println!("topics {:?}", collection.len());
//     debug_print_topics(collection);
// }
//
// fn debug_print_topics(collection: Vec<TopicItem>) {
//     for (i, item) in collection.iter().enumerate() {
//
//         println!("item[{}]= {title} {author_name} {last_replied_date} {last_replied_time} \
//                   {reply_count} {rating}",
//                  i,
//                  title = item.titles[0].text,
//                  author_name = item.author.name,
//                  last_replied_date = item.last_replied_date,
//                  last_replied_time = item.last_replied_time,
//                  reply_count = item.reply_count,
//                  rating = item.rating);
//     }
// }
<|endoftext|>


<commit_before>extern crate cline;
extern crate termios;

use std::io;
use std::io::prelude::*;
use std::os::unix::io::RawFd;
use termios::*;

fn main() {
    let mut cli = cline::Cli::new();
    let mut termios = Termios::from_fd(0).unwrap();
    let mut buf:Vec<u8> = Vec::new();
    let term_orig = termios;

    cli.register(vec!["show", "stuff"], | _ | { println!("wooo haaa") });
    cli.register(vec!["show", "other"], | _ | { println!("wooo haaa") });
    cli.register(vec!["foo", "bar"], | _ | { println!("wooo haaa") });
    cli.register(vec!["exit"], | _ | { std::process::exit(0); });

    //termios.c_lflag = ECHONL;
    termios.c_lflag &= !(ICANON | IEXTEN | ISIG);
    tcsetattr(0, TCSANOW, &termios);
    tcflush(0, TCIOFLUSH);

    println!("-----> {:?}", term_orig);
    print!(">> ");
    io::stdout().flush();
    for byte in io::stdin().bytes() {
        let b = byte.unwrap();
        let mut command:String = String::new();
        if let Ok(string) = String::from_utf8(buf.clone()) {
            command = string;
        }

        match b {
            3 => break,
            9 => {
                let mut outbuf:String = String::new();
                let res = cli.complete(&command);

                for suggestion in res.iter() {
                    outbuf.push_str(suggestion);
                    outbuf.push_str("  ");
                }

                //TODO: meh...
                match command.chars().last() {
                    Some(' ') => {
                        //if res.len() > 0 {
                            //buf.extend(res[0].bytes());
                            //command.push_str(res[0]);
                        //}
                    }
                    _ => {
                        if res.len() > 1 {
                        } else if res.len() == 1 {
                        } else {
                            //nothing found
                        }
                    }
                }

                println!("\n{}", outbuf);
                print!(">> {}", command);
                io::stdout().flush();
            }
            10 => {
                println!("execute for: '{}'", command);
                cli.exec(&command);
                command.clear();
                buf.clear();
                print!(">> ");
                io::stdout().flush();
            }
            _ => {
                buf.push(b);
            }
        }

    }

    tcsetattr(0, termios::TCSANOW, &term_orig);
}
<commit_msg>update example to support backspace - still hacky<commit_after>extern crate cline;
extern crate termios;

use std::io;
use std::io::prelude::*;
use std::os::unix::io::RawFd;
use termios::*;

fn main() {
    let mut termios = Termios::from_fd(0).unwrap();
    let term_orig = termios;
    let mut cli = cline::Cli::new();
    let mut buf:Vec<u8> = Vec::new();

    cli.register(vec!["show", "stuff"], | _ | { println!("wooo haaa") });
    cli.register(vec!["show", "other"], | _ | { println!("wooo haaa") });
    cli.register(vec!["foo", "bar"], | _ | { println!("wooo haaa") });
    cli.register(vec!["exit"], | _ | {
        tcsetattr(0, termios::TCSANOW, &term_orig);
        std::process::exit(0);
    });

    //termios.c_lflag = ECHONL;
    termios.c_lflag &= !(ICANON | IEXTEN | ISIG | ECHO);
    tcsetattr(0, TCSANOW, &termios);
    tcflush(0, TCIOFLUSH);

    println!("-----> {:?}", term_orig);
    print!(">> ");
    io::stdout().flush();
    for byte in io::stdin().bytes() {
        let b = byte.unwrap();
        let mut command:String = String::new();
        if let Ok(string) = String::from_utf8(buf.clone()) {
            command = string;
        }

        match b {
            3 => break,
            9 => {
                //Tab
                let mut outbuf:String = String::new();
                let res = cli.complete(&command);

                for suggestion in res.iter() {
                    outbuf.push_str(suggestion);
                    outbuf.push_str("  ");
                }

                //TODO: meh...
                match command.chars().last() {
                    Some(' ') => {
                        if res.len() == 1 {
                            buf.extend(res[0].bytes());
                            command.push_str(res[0]);
                        }
                    }
                    _ => {
                        if res.len() > 1 {
                        } else if res.len() == 1 {
                        } else {
                            //nothing found
                        }
                    }
                }

                println!("\n{}", outbuf);
                print!(">> {}", command);
                io::stdout().flush();
            }
            10 => {
                //CRLF
                println!("\nexecute for: '{}'", command);
                cli.exec(&command);
                command.clear();
                buf.clear();
                print!(">> ");
                io::stdout().flush();
            }
            0x7f => {
                //backspace
                print!("{} {}", 0x08 as char, 0x08 as char);
                io::stdout().flush();
                buf.pop();
            }
            _ => {
                buf.push(b);
                print!("{}", b as char);
                io::stdout().flush();
            }
        }
    }

    tcsetattr(0, termios::TCSANOW, &term_orig);
}
<|endoftext|>