<commit_before>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 0.99;
const WIDTH: u32 = 1024;
const HEIGHT: u32 = 800;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut goobs = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for goob in &goobs {
                    image(&sprite, c.transform.trans(goob.geometry()[0], goob.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 16).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(button),
                    Button::Keyboard(Key::Down)   => inputs.push(button),
                    Button::Keyboard(Key::Left)   => inputs.push(button),
                    Button::Keyboard(Key::Right)  => inputs.push(button),
                    Button::Keyboard(Key::Space)  => inputs.push(button),
                    Button::Keyboard(Key::A)      => {
                        goobs.push(
                            Entity::new(
                            Point(0.0, 0.0),
                            [0.3, 0.0, 0.7, 0.5],
                            25.0, 25.0
                            )
                        );
                        inputs.push(button);
                    },
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                match inputs.pop() {
                    Some(button) => handle_input(button, &mut goobs, &mut i),
                    None => ()
                }
            }
            for goob in goobs.iter_mut() {
                goob.nudge();
            }
        }
    }

    fn handle_input(button: Button, goobs: &mut [Entity], i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => goobs[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => goobs[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => goobs[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => goobs[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == goobs.len() - 1 { *i = 0 } else { *i += 1 },
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &Vec<Button>) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                Button::Keyboard(Key::A)     => "+",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<commit_msg>Switch back to accepting inputs once command queue empties<commit_after>extern crate piston_window;

mod entity;

use piston_window::*;
use entity::Entity;
use std::time::SystemTime;

#[derive(Debug, Clone)]
pub struct Point(f64, f64);

const MU: f64 = 0.99;
const WIDTH: u32 = 1024;
const HEIGHT: u32 = 800;
const WAIT_TIME: u32 = 300_000_000; //nanoseconds

fn main() {
    let title = "Goober";
    let mut inputs_submitted = false;
    let mut inputs = Vec::new();
    let mut timestamp = SystemTime::now();
    let mut i: usize = 0;
    let mut goobs = vec![
        Entity::new(Point(0.0, 0.0), [0.3, 0.0, 0.7, 0.5], 25.0, 25.0)
    ];

    let mut window: PistonWindow = WindowSettings::new(title, [WIDTH, HEIGHT])
        .exit_on_esc(true)
        .build()
        .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e));

    let sprite_path = "./assets/green-blob-hi.png";
    let sprite = Texture::from_path(
            &mut window.factory,
            &sprite_path,
            Flip::None,
            &TextureSettings::new())
            .unwrap();

    let font = "assets/FiraSans-Regular.ttf";
    let factory = window.factory.clone();
    let mut glyphs = Glyphs::new(font, factory).unwrap();

    while let Some(e) = window.next() {

        if let Some(_) = e.render_args() {
            window.draw_2d(&e, |c, g| {
                clear([0.8, 0.0, 0.8, 1.0], g);
                for goob in &goobs {
                    image(&sprite, c.transform.trans(goob.geometry()[0], goob.geometry()[1]), g);
                }

                text::Text::new_color([0.0, 1.0, 0.0, 1.0], 16).draw(
                    &format_inputs(&inputs),
                    &mut glyphs,
                    &c.draw_state,
                    c.transform.trans(40.0, 40.0), g
                );
            });
        }

        if let Some(button) = e.press_args() {
            if !inputs_submitted {
                match button {
                    Button::Keyboard(Key::Up)     => inputs.push(button),
                    Button::Keyboard(Key::Down)   => inputs.push(button),
                    Button::Keyboard(Key::Left)   => inputs.push(button),
                    Button::Keyboard(Key::Right)  => inputs.push(button),
                    Button::Keyboard(Key::Space)  => inputs.push(button),
                    Button::Keyboard(Key::A)      => {
                        goobs.push(
                            Entity::new(
                            Point(0.0, 0.0),
                            [0.3, 0.0, 0.7, 0.5],
                            25.0, 25.0
                            )
                        );
                        inputs.push(button);
                    },
                    Button::Keyboard(Key::Return) => {inputs_submitted = true; inputs.reverse()},
                    _ => ()
                }
            }
        }

        if let Some(_) = e.update_args() {
            if inputs_submitted && wait_time_elapsed(timestamp) {
                timestamp = SystemTime::now();
                match inputs.pop() {
                    Some(button) => handle_input(button, &mut goobs, &mut i),
                    None => ()
                }
            } else if inputs.len() == 0 {
                inputs_submitted = false;
            }
            for goob in goobs.iter_mut() {
                goob.nudge();
            }
        }
    }

    fn handle_input(button: Button, goobs: &mut [Entity], i: &mut usize) {
        match button {
            Button::Keyboard(Key::Up)     => goobs[*i].adjust_dy(-1.0),
            Button::Keyboard(Key::Down)   => goobs[*i].adjust_dy(1.0),
            Button::Keyboard(Key::Left)   => goobs[*i].adjust_dx(-1.0),
            Button::Keyboard(Key::Right)  => goobs[*i].adjust_dx(1.0),
            Button::Keyboard(Key::Space)  => if *i == goobs.len() - 1 { *i = 0 } else { *i += 1 },
            _ => ()
        }
    }

    fn wait_time_elapsed(timestamp: SystemTime) -> bool {
        match timestamp.elapsed() {
            Ok(elapsed) => elapsed.subsec_nanos() >= WAIT_TIME,
            Err(e) => {println!("{:?}", e); false}
        }
    }

    fn format_inputs(inputs: &Vec<Button>) -> String {
        inputs.iter().map(|button|
            match *button {
                Button::Keyboard(Key::Up)    => "↑",
                Button::Keyboard(Key::Down)  => "↓",
                Button::Keyboard(Key::Left)  => "←",
                Button::Keyboard(Key::Right) => "→",
                Button::Keyboard(Key::Space) => "↔",
                Button::Keyboard(Key::A)     => "+",
                _ => ""
            }
        ).collect::<Vec<_>>().concat()
    }
}
<|endoftext|>


<commit_before>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
extern crate lapp;
use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::PathBuf;

mod crate_utils;
mod platform;

use platform::{open,edit,EXE};

fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}

// this will be initially written to ~/.cargo/.runner/prelude and
// can then be edited.
const PRELUDE: &'static str = "
#![allow(unused_imports)]
#![allow(dead_code)]
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::env;
use std::path::{PathBuf,Path};
#[allow(unused_macros)]
macro_rules! debug {
    ($x:expr) => {
        println!(\"{} = {:?}\",stringify!($x),$x);
    }
}

";

fn runner_directory() -> PathBuf {
    let mut home = env::home_dir().or_die("no home!");
    home.push(".cargo");
    home.push(".runner");
    home
}

fn cargo(args: &[&str]) {
    let res = process::Command::new("cargo")
        .args(args)
        .status()
        .or_die("can't run cargo");
    if ! res.success() {
        es::quit("cargo failed");
    }
}

const STATIC_CACHE: &str = "static-cache";
const DYNAMIC_CACHE: &str = "dy-cache";

fn static_cache_dir() -> PathBuf {
    runner_directory().join(STATIC_CACHE)
}

fn static_cache_dir_check(args: &lapp::Args) -> PathBuf {
    let static_cache = static_cache_dir();
    if ! static_cache.exists() {
        args.quit("please build static cache with --create first");
    }
    static_cache
}

fn build_static_cache() {
    cargo(&["build"]);
    cargo(&["build","--release"]);
    cargo(&["doc"]);
}

fn create_static_cache(crates: &[String], create: bool) {
    use std::io::prelude::*;
    let mut home = runner_directory();
    env::set_current_dir(&home).or_die("cannot change to home directory");
    if create {
        cargo(&["new","--bin",STATIC_CACHE]);
    }
    home.push(STATIC_CACHE);
    env::set_current_dir(&home).or_die("could not create static cache");
    {
        let mut deps = fs::OpenOptions::new().append(true)
            .open("Cargo.toml").or_die("could not append to cargo.toml");
        for c in crates {
            write!(deps,"{}=\"*\"\n",c).or_die("could not modify cargo.toml");
        }
    }
    build_static_cache();
}

fn prelude_and_cache(build_static: bool, optimize: bool) -> (String,PathBuf) {
    let mut home = runner_directory();
    let pristine = ! home.is_dir();
    if pristine {
        fs::create_dir(&home).or_die("cannot create runner directory");
    }
    let mut prelude = home.clone();
    prelude.push("prelude");
    let scache;
    let cache = if build_static {
        let dir = if optimize {"release"} else {"debug"};
        scache = format!("{}/target/{}/deps",STATIC_CACHE,dir);
        &scache
    } else {DYNAMIC_CACHE};
    home.push(cache);
    if pristine {
        es::write_all(&prelude,PRELUDE);
        fs::create_dir(&home).or_die("cannot create dynamic cache");
    }
    (es::read_to_string(&prelude),home)
}

fn massage_snippet(code: String, prelude: String) -> String {
    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }
    let mut prefix = prelude;
    let mut body = String::new();
    {
        let mut lines = code.lines();
        for line in lines.by_ref() {
            let line = line.trim_left();
            if line.starts_with("//") || line.starts_with("#[") ||
                line.starts_with("extern ") || line.starts_with("use ") {
                prefix += line;
                prefix.push('\n');
            } else {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    format!("{}
use std::error::Error;
fn run() -> Result<(),Box<Error>> {{
{}    Ok(())
}}
fn main() {{
    run().unwrap();
}}
        ",prefix,body)

}

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -O, --optimize optimized static build
  -c, --create (string...) initialize the static cache with crates
  -a, --add  (string...) add new crates to the cache (after --create)
  -e, --edit  edit the static cache Cargo.toml
  -b, --build rebuild the static cache
  -d, --doc  display
  -P, --crate-path show path of crate source in Cargo cache
  -C, --compile  compile crate dynamically (limited)
  <program> (string) Rust program or snippet
  <args> (string...) arguments to pass to program
";

fn main() {
    let args = lapp::parse_args(USAGE);

    let crates = args.get_strings("create");
    if crates.len() > 0 {
        create_static_cache(&crates,true);
        return;
    }
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        static_cache_dir_check(&args);
        create_static_cache(&crates,false);
        return;
    }

    if args.get_bool("edit") || args.get_bool("build") || args.get_bool("doc") {
        let static_cache = static_cache_dir_check(&args);
        if args.get_bool("build") {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            build_static_cache();
        } else
        if args.get_bool("doc") {
            let docs = static_cache.join("target/doc/static_cache/index.html");
            open(&docs);
        } else {
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

    let file = PathBuf::from(args.get_string("program"));

    if args.get_bool("crate-path") || args.get_bool("compile") {
        let (crate_path,crate_name) = if file.exists() {
            let filename = crate_utils::path_file_name(&file);
            (file, filename)
        } else {
            let arg = args.get_string("program");
            (crate_utils::cache_path(&arg), arg)
        };
        if args.get_bool("crate-path") {
            println!("{}",crate_path.display());
        } else {
            let valid_crate_name = crate_name.replace('-',"_");
            let (_,cache) = prelude_and_cache(false, false);
            process::Command::new("rustc")
                .args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"])
                .arg("-L").arg(&cache)
                .args(&["--crate-type","dylib"])
                .arg("--out-dir").arg(&cache)
                .arg("--crate-name").arg(&valid_crate_name)
                .arg(crate_path.join("src/lib.rs"))
           .status().or_die("can't run rustc");
        }
        return;
    }
    let ext = file.extension().or_die("no file extension");
    if ext != "rs" {
        es::quit("file extension must be .rs");
    }

    let build_static = args.get_bool("static");
    let optimize = args.get_bool("optimize");

    // we'll pass rest of arguments to program
    let args = args.get_strings("args");

    // we are going to put the expanded source and resulting exe in temp
    let out_dir = "temp";
    if ! fs::metadata(out_dir).is_dir() {
        fs::create_dir(out_dir).or_die("cannot create temp directory here");
    }

    let mut code = es::read_to_string(&file);

    let (prelude,cache) = prelude_and_cache(build_static, optimize);

    if code.find("fn main").is_none() {
        code = massage_snippet(code,prelude);
    }

    let mut out_file = PathBuf::from(out_dir);
    out_file.push(&file);
    let mut program = out_file.clone();
    program.set_extension(EXE);

    es::write_all(&out_file,&code);

    let mut builder = process::Command::new("rustc");
    if ! build_static {
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
    } else {
        builder.arg(if optimize {"-O"} else {"-g"});
    }
    builder.arg("-L").arg(&cache);
    let status = builder.arg("-o").arg(&program)
        .arg(&out_file)
        .status().or_die("can't run rustc");
    if ! status.success() {
        return;
    }

    let mut builder = process::Command::new(&program);
    if ! build_static {
        builder.env("LD_LIBRARY_PATH",format!("{}:{}",rustup_lib(),cache.display()));
    }
    builder.args(&args)
        .status()
        .or_die(&format!("can't run program {:?}",program));

}

<commit_msg>New commands: --edit-prelude,--expression, --iterator, --lines<commit_after>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
extern crate lapp;
use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::PathBuf;

mod crate_utils;
mod platform;

use platform::{open,edit,EXE};

fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}

// this will be initially written to ~/.cargo/.runner/prelude and
// can then be edited.
const PRELUDE: &'static str = "
#![allow(unused_imports)]
#![allow(dead_code)]
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::env;
use std::path::{PathBuf,Path};
#[allow(unused_macros)]
macro_rules! debug {
    ($x:expr) => {
        println!(\"{} = {:?}\",stringify!($x),$x);
    }
}

";

fn runner_directory() -> PathBuf {
    let mut home = env::home_dir().or_die("no home!");
    home.push(".cargo");
    home.push(".runner");
    home
}

fn cargo(args: &[&str]) {
    let res = process::Command::new("cargo")
        .args(args)
        .status()
        .or_die("can't run cargo");
    if ! res.success() {
        es::quit("cargo failed");
    }
}

const STATIC_CACHE: &str = "static-cache";
const DYNAMIC_CACHE: &str = "dy-cache";

fn static_cache_dir() -> PathBuf {
    runner_directory().join(STATIC_CACHE)
}

fn static_cache_dir_check(args: &lapp::Args) -> PathBuf {
    let static_cache = static_cache_dir();
    if ! static_cache.exists() {
        args.quit("please build static cache with --create first");
    }
    static_cache
}

fn build_static_cache() {
    cargo(&["build"]);
    cargo(&["build","--release"]);
    cargo(&["doc"]);
}

fn create_static_cache(crates: &[String], create: bool) {
    use std::io::prelude::*;
    let mut home = runner_directory();
    env::set_current_dir(&home).or_die("cannot change to home directory");
    if create {
        cargo(&["new","--bin",STATIC_CACHE]);
    }
    home.push(STATIC_CACHE);
    env::set_current_dir(&home).or_die("could not create static cache");
    {
        let mut deps = fs::OpenOptions::new().append(true)
            .open("Cargo.toml").or_die("could not append to cargo.toml");
        for c in crates {
            write!(deps,"{}=\"*\"\n",c).or_die("could not modify cargo.toml");
        }
    }
    build_static_cache();
}

fn prelude_and_cache(build_static: bool, optimize: bool) -> (String,PathBuf) {
    let mut home = runner_directory();
    let pristine = ! home.is_dir();
    if pristine {
        fs::create_dir(&home).or_die("cannot create runner directory");
    }
    let mut prelude = home.clone();
    prelude.push("prelude");
    let scache;
    let cache = if build_static {
        let dir = if optimize {"release"} else {"debug"};
        scache = format!("{}/target/{}/deps",STATIC_CACHE,dir);
        &scache
    } else {DYNAMIC_CACHE};
    home.push(cache);
    if pristine {
        es::write_all(&prelude,PRELUDE);
        fs::create_dir(&home).or_die("cannot create dynamic cache");
    }
    (es::read_to_string(&prelude),home)
}

fn massage_snippet(code: String, prelude: String) -> String {
    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }
    let mut prefix = prelude;
    let mut body = String::new();
    {
        let mut lines = code.lines();
        for line in lines.by_ref() {
            let line = line.trim_left();
            if line.starts_with("//") || line.starts_with("#[") ||
                line.starts_with("extern ") || line.starts_with("use ") {
                prefix += line;
                prefix.push('\n');
            } else {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    format!("{}
use std::error::Error;
fn run() -> Result<(),Box<Error>> {{
{}    Ok(())
}}
fn main() {{
    run().unwrap();
}}
        ",prefix,body)

}

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator evaluate an iterator
  -n, --lines evaluate expression over stdin; 'line' is defined

  Cache Management:
  -c, --create (string...) initialize the static cache with crates
  -a, --add  (string...) add new crates to the cache (after --create)
  -e, --edit  edit the static cache Cargo.toml
  -b, --build rebuild the static cache
  -d, --doc  display
  -E, --edit-prelude edit the default prelude for snippets

  Dynamic compilation:
  -P, --crate-path show path of crate source in Cargo cache
  -C, --compile  compile crate dynamically (limited)

  <program> (string) Rust program, snippet or expression
  <args> (string...) arguments to pass to program
";

fn main() {
    let args = lapp::parse_args(USAGE);

    if args.get_bool("edit-prelude") {
        let mut rdir = runner_directory();
        if ! rdir.exists() {
            args.quit("Runner dir not created yet. Run any snippet first");
        }
        rdir.push("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("create");
    if crates.len() > 0 {
        create_static_cache(&crates,true);
        return;
    }
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        static_cache_dir_check(&args);
        create_static_cache(&crates,false);
        return;
    }

    if args.get_bool("edit") || args.get_bool("build") || args.get_bool("doc") {
        let static_cache = static_cache_dir_check(&args);
        if args.get_bool("build") {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            build_static_cache();
        } else
        if args.get_bool("doc") {
            let docs = static_cache.join("target/doc/static_cache/index.html");
            open(&docs);
        } else {
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

    let first_arg = args.get_string("program");
    let file = PathBuf::from(&first_arg);

    // Dynamically linking crates (experimental!)
    if args.get_bool("crate-path") || args.get_bool("compile") {
        let (crate_path,crate_name) = if file.exists() {
            let filename = crate_utils::path_file_name(&file);
            (file, filename)
        } else {
            (crate_utils::cache_path(&first_arg), first_arg)
        };
        if args.get_bool("crate-path") {
            println!("{}",crate_path.display());
        } else {
            let valid_crate_name = crate_name.replace('-',"_");
            let (_,cache) = prelude_and_cache(false, false);
            process::Command::new("rustc")
                .args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"])
                .arg("-L").arg(&cache)
                .args(&["--crate-type","dylib"])
                .arg("--out-dir").arg(&cache)
                .arg("--crate-name").arg(&valid_crate_name)
                .arg(crate_path.join("src/lib.rs"))
           .status().or_die("can't run rustc");
        }
        return;
    }

    let build_static = args.get_bool("static");
    let optimize = args.get_bool("optimize");

    // we'll pass rest of arguments to program
    let program_args = args.get_strings("args");

    // we are going to put the expanded source and resulting exe in temp
    let out_dir = "temp";
    if ! fs::metadata(out_dir).is_dir() {
        fs::create_dir(out_dir).or_die("cannot create temp directory here");
    }

    let (prelude,cache) = prelude_and_cache(build_static, optimize);

    let mut snippet = false;
    let mut code = if args.get_bool("expression") {
        // Evaluating an expression: just print it out.
        format!("let res = {};\nprintln!(\"{{:?}}\",res);", first_arg)
    } else
    if args.get_bool("iterator") {
        // The expression is anything that implements IntoIterator
        format!("let iter = {};\n for val in iter {{ println!(\"{{:?}}\",val);}}", first_arg)
    } else
    if args.get_bool("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        format!("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {{
                let val = {};
                println!(\"{{:?}}\",val?);
            }}
            ", first_arg)
    } else { // otherwise, just a file
        // for now, we insist it has the usual Rust extension...
        let ext = file.extension().or_die("no file extension");
        if ext != "rs" {
            es::quit("file extension must be .rs");
        }
        snippet = true;
        es::read_to_string(&file)
    };

    // proper Rust programs are accepted (this is a bit rough)
    if code.find("fn main").is_none() {
        code = massage_snippet(code,prelude);
    }

    let mut out_file = PathBuf::from(out_dir);
    if snippet {
        out_file.push(&file);
    } else {
        out_file.push("tmp.rs");
    }
    let mut program = out_file.clone();
    program.set_extension(EXE);

    es::write_all(&out_file,&code);

    let mut builder = process::Command::new("rustc");
    if ! build_static {
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
    } else {
        builder.arg(if optimize {"-O"} else {"-g"});
    }
    builder.arg("-L").arg(&cache);
    let status = builder.arg("-o").arg(&program)
        .arg(&out_file)
        .status().or_die("can't run rustc");
    if ! status.success() {
        return;
    }

    let mut builder = process::Command::new(&program);
    if ! build_static {
        builder.env("LD_LIBRARY_PATH",format!("{}:{}",rustup_lib(),cache.display()));
    }
    builder.args(&program_args)
        .status()
        .or_die(&format!("can't run program {:?}",program));

}

<|endoftext|>


<commit_before>// TODO:
//  * remove every panic!() -- this is meant for prompt
//  * add option to debug: print all errors
//  * create function to display everything
//  * colors

extern crate git2;

use git2::Error;
use git2::{Repository,Branch,BranchType,Oid,Reference,StatusShow};
use git2::{StatusOptions,Statuses,Status,RepositoryState};
use git2::{STATUS_WT_MODIFIED,STATUS_WT_DELETED,STATUS_WT_NEW,STATUS_WT_TYPECHANGE,STATUS_WT_RENAMED};
use git2::{STATUS_INDEX_MODIFIED,STATUS_INDEX_DELETED,STATUS_INDEX_NEW,STATUS_INDEX_TYPECHANGE,STATUS_INDEX_RENAMED};

struct Program {
    repo: Repository,
}

fn get_branch_remote(reference: Reference) -> Option<Oid> {
    let b = Branch::wrap(reference);
    let upstream = match b.upstream() {
        Ok(u) => u,
        Err(_) => return None,
    };
    upstream.get().target()
}

fn get_ref_to_oid(reference: Reference) -> Oid {
    match reference.target() {
        Some(v) => v,
        None => panic!("Failed to get oid for reference."),
    }
}

impl Program {
    fn get_head(&self) -> Reference {
        match self.repo.head() {
            Ok(head) => head,
            Err(e) => panic!("Failed to get head: {}.", e)
        }
    }

    fn get_current_branch_oid(&self) -> Oid {
        let head = self.get_head();
        match head.target() {
            Some(v) => v,
            None => panic!("Failed to get reference to head."),
        }
    }

    fn get_current_branch_name(&self) -> String {
        match self.get_head().shorthand() {
            Some(v) => v.to_string(),
            None => panic!("Failed to get name of head."),
        }
    }

    // fn get_current_branch_remote(&self) -> String {
    //     let oid = self.get_current_branch_oid();
    //     let b = Branch::wrap(oid);
    //     let upstream = b.upstream().ok().unwrap();
    //     String::from(upstream.name().ok().unwrap().unwrap())
    // }

    fn get_current_branch_remote_oid(&self) -> Option<Oid> {
        get_branch_remote(self.get_head())
    }

    fn get_current_branch_ahead_behind(&self) -> Option<(usize, usize)> {
        let oid = match self.get_current_branch_remote_oid() {
            Some(r) => r,
            None => return None
        };
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            oid
        );
        match res {
            Ok(r) => Some(r),
            Err(_) => None
        }
    }

    fn get_upstream_branch_ahead_behind(&self) -> Option<(usize, usize)>  {
        let upstream_reference = match self.find_upstream_repo_branch() {
            Ok(u) => u.into_reference(),
            Err(_) => return None,
        };
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            get_ref_to_oid(upstream_reference),
        );
        match res {
            Ok(r) => Some(r),
            Err(_) => None
        }
    }

    fn find_upstream_repo_branch(&self) -> Result<Branch, Error> {
        let us_branch_name = format!("{}{}", "upstream/", self.get_current_branch_name());
        self.repo.find_branch(&us_branch_name, BranchType::Remote)
    }

    fn get_status(&self) -> Statuses {
        let mut so = StatusOptions::new();
        let mut opts = so.show(StatusShow::IndexAndWorkdir);
        opts.include_untracked(true);
        let statuses = match self.repo.statuses(Some(&mut opts)) {
            Ok(s) => s,
            Err(e) => panic!("failed to get statuses: {}", e),
        };
        statuses
    }

    fn get_repository_state(&self) -> RepositoryState {
        self.repo.state()
    }
}

fn main() {
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => panic!("failed to open: {}", e),
    };
    let program = Program{ repo: repo };
    println!("{}", program.get_current_branch_name());

    match program.get_current_branch_ahead_behind() {
        Some((ahead, behind)) => println!("A: {}, B: {}", ahead, behind),
        None => {}
    }

    match program.get_upstream_branch_ahead_behind() {
        Some((ahead, behind)) => println!("U A: {}, B: {}", ahead, behind),
        None => {}
    }

    let statuses = program.get_status();
    for s in statuses.iter() {
        let file_status = s.status();
        println!("{}", s.path().unwrap());
        if file_status.intersects(
            STATUS_WT_MODIFIED | STATUS_WT_DELETED | STATUS_WT_TYPECHANGE | STATUS_WT_RENAMED
        ) {
            println!("changes");
        };
        if file_status.contains(STATUS_WT_NEW) {
            println!("new files");
        };
        if file_status.intersects(
            STATUS_INDEX_MODIFIED | STATUS_INDEX_DELETED | STATUS_INDEX_TYPECHANGE | STATUS_INDEX_RENAMED | STATUS_INDEX_NEW
        ) {
            println!("index update");
        };
    }
    println!("{:?}", program.get_repository_state());
}
<commit_msg>structure displaying<commit_after>// TODO:
//  * remove every panic!() -- this is meant for prompt
//  * add option to debug: print all errors
//  * create function to display everything
//  * colors

extern crate git2;

use std::io::{self, Write};

use git2::Error;
use git2::{Repository,Branch,BranchType,Oid,Reference,StatusShow};
use git2::{StatusOptions,Statuses,Status,RepositoryState};
use git2::{STATUS_WT_MODIFIED,STATUS_WT_DELETED,STATUS_WT_NEW,STATUS_WT_TYPECHANGE,STATUS_WT_RENAMED};
use git2::{STATUS_INDEX_MODIFIED,STATUS_INDEX_DELETED,STATUS_INDEX_NEW,STATUS_INDEX_TYPECHANGE,STATUS_INDEX_RENAMED};

struct Program {
    repo: Repository,
}

fn get_branch_remote(reference: Reference) -> Option<Oid> {
    let b = Branch::wrap(reference);
    let upstream = match b.upstream() {
        Ok(u) => u,
        Err(_) => return None,
    };
    upstream.get().target()
}

fn get_ref_to_oid(reference: Reference) -> Oid {
    match reference.target() {
        Some(v) => v,
        None => panic!("Failed to get oid for reference."),
    }
}

impl Program {
    fn get_head(&self) -> Reference {
        match self.repo.head() {
            Ok(head) => head,
            Err(e) => panic!("Failed to get head: {}.", e)
        }
    }

    fn get_current_branch_oid(&self) -> Oid {
        let head = self.get_head();
        match head.target() {
            Some(v) => v,
            None => panic!("Failed to get reference to head."),
        }
    }

    fn get_current_branch_name(&self) -> String {
        match self.get_head().shorthand() {
            Some(v) => v.to_string(),
            None => panic!("Failed to get name of head."),
        }
    }

    // fn get_current_branch_remote(&self) -> String {
    //     let oid = self.get_current_branch_oid();
    //     let b = Branch::wrap(oid);
    //     let upstream = b.upstream().ok().unwrap();
    //     String::from(upstream.name().ok().unwrap().unwrap())
    // }

    fn get_current_branch_remote_oid(&self) -> Option<Oid> {
        get_branch_remote(self.get_head())
    }

    fn get_current_branch_ahead_behind(&self) -> Option<(usize, usize)> {
        let oid = match self.get_current_branch_remote_oid() {
            Some(r) => r,
            None => return None
        };
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            oid
        );
        match res {
            Ok(r) => Some(r),
            Err(_) => None
        }
    }

    fn get_upstream_branch_ahead_behind(&self) -> Option<(usize, usize)>  {
        let upstream_reference = match self.find_upstream_repo_branch() {
            Ok(u) => u.into_reference(),
            Err(_) => return None,
        };
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            get_ref_to_oid(upstream_reference),
        );
        match res {
            Ok(r) => Some(r),
            Err(_) => None
        }
    }

    fn find_upstream_repo_branch(&self) -> Result<Branch, Error> {
        let us_branch_name = format!("{}{}", "upstream/", self.get_current_branch_name());
        self.repo.find_branch(&us_branch_name, BranchType::Remote)
    }

    fn get_status(&self) -> Statuses {
        let mut so = StatusOptions::new();
        let mut opts = so.show(StatusShow::IndexAndWorkdir);
        opts.include_untracked(true);
        let statuses = match self.repo.statuses(Some(&mut opts)) {
            Ok(s) => s,
            Err(e) => panic!("failed to get statuses: {}", e),
        };
        statuses
    }

    fn get_repository_state(&self) -> RepositoryState {
        self.repo.state()
    }

    fn run(&self) {
        // TODO: print short hash if not on branch
        print!("{}|", self.get_current_branch_name());

        match self.get_current_branch_ahead_behind() {
            // FIXME: cover case behind && ahead
            Some((_, behind)) if behind > 0 => print!("-{}", behind),
            Some((ahead, _)) if ahead > 0 => print!("+{}", ahead),
            Some(_) => {}
            None => {}
        }

        match self.get_upstream_branch_ahead_behind() {
            Some((ahead, behind)) => print!("U+{}-{}|", ahead, behind),
            None => {}
        }

        // let statuses = self.get_status();
        // for s in statuses.iter() {
        //     let file_status = s.status();
        //     println!("{}", s.path().unwrap());
        //     if file_status.intersects(
        //         STATUS_WT_MODIFIED | STATUS_WT_DELETED | STATUS_WT_TYPECHANGE | STATUS_WT_RENAMED
        //     ) {
        //         println!("changes");
        //     };
        //     if file_status.contains(STATUS_WT_NEW) {
        //         println!("new files");
        //     };
        //     if file_status.intersects(
        //         STATUS_INDEX_MODIFIED | STATUS_INDEX_DELETED | STATUS_INDEX_TYPECHANGE | STATUS_INDEX_RENAMED | STATUS_INDEX_NEW
        //     ) {
        //         println!("index update");
        //     };
        // }
        // println!("{:?}", program.get_repository_state());

        print!("\n");
    }
}

fn main() {
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(_) => return (),
    };
    let program = Program{ repo: repo };
    program.run();
}
<|endoftext|>


<commit_before>extern crate ppbert;

use std::io;
use std::io::Read;

use ppbert::parser;
use ppbert::pretty;

fn main() {
    let mut stdin = io::stdin();
    let mut buf: Vec<u8> = Vec::new();

    let _ = stdin.read_to_end(&mut buf);
    let mut parser = parser::Parser::new(buf);
    match parser.parse() {
        Ok(ref term) => { pretty::print(term, 0); }
        Err(error) => { println!("ppbert: {}", error); }
    }
}
<commit_msg>Add a newline after pretty printing<commit_after>extern crate ppbert;

use std::io;
use std::io::Read;

use ppbert::parser;
use ppbert::pretty;

fn main() {
    let mut stdin = io::stdin();
    let mut buf: Vec<u8> = Vec::new();

    let _ = stdin.read_to_end(&mut buf);
    let mut parser = parser::Parser::new(buf);
    match parser.parse() {
        Ok(ref term) => {
            pretty::print(term, 0);
            println!();
        }
        Err(error) => { println!("ppbert: {}", error); }
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(path)]

extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo>
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    let mut revwalk = repo.revwalk()
        .ok().expect("Unable to get revwalk.");
    // Setup some options.
    revwalk.simplify_first_parent(); // TODO: Maybe remove?
    let mut flags = git2::Sort::empty();
    flags.insert(git2::SORT_TIME);
    flags.insert(git2::SORT_TOPOLOGICAL);
    revwalk.set_sorting(flags);
    // Push HEAD to the revwalk.
    revwalk.push_head()
        .ok().expect("Unable to push HEAD.");
    // We sadly must collect here to use `.windows()`
    let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
        .collect::<Vec<Commit>>();
    // Walk through each pair of commits.
    for pair in history.windows(2) {
        let (old, new) = (&pair[1], &pair[0]);
        println!("\nOLD: {:?} - NEW: {:?}\n", old.id(), new.id());
        let old_tree = old.tree()
            .ok().expect("Could not get tree.");
        let new_tree = new.tree()
            .ok().expect("Could not get tree.");
        // Build up a diff of the two trees.
        let diff = Diff::tree_to_tree(&repo, Some(&old_tree), Some(&new_tree), None)
            .ok().expect("Couldn't diff trees.");
        diff.print(DiffFormat::Patch, handler);
    }
}

fn handler(delta: DiffDelta, hunk: Option<DiffHunk>, line: DiffLine) -> bool {
    println!("----\n{}----\n", str::from_utf8(line.content()).unwrap());
    true
}
<commit_msg>Bit of documentation<commit_after>#![feature(core)]
#![feature(path)]

extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo>
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    let mut revwalk = repo.revwalk()
        .ok().expect("Unable to get revwalk.");
    // Setup some options.
    revwalk.simplify_first_parent(); // TODO: Maybe remove?
    let mut flags = git2::Sort::empty();
    flags.insert(git2::SORT_TIME);
    flags.insert(git2::SORT_TOPOLOGICAL);
    revwalk.set_sorting(flags);
    // Push HEAD to the revwalk.
    revwalk.push_head()
        .ok().expect("Unable to push HEAD.");
    // We sadly must collect here to use `.windows()`
    let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
        .collect::<Vec<Commit>>();
    // Walk through each pair of commits.
    for pair in history.windows(2) {
        let (old, new) = (&pair[1], &pair[0]);
        println!("\nOLD: {:?} - NEW: {:?}\n", old.id(), new.id());
        let old_tree = old.tree()
            .ok().expect("Could not get tree.");
        let new_tree = new.tree()
            .ok().expect("Could not get tree.");
        // Build up a diff of the two trees.
        let diff = Diff::tree_to_tree(&repo, Some(&old_tree), Some(&new_tree), None)
            .ok().expect("Couldn't diff trees.");
        diff.print(DiffFormat::Patch, handler);
    }
}

// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
// It's a bit weird, but I think it will provide the necessary information.
fn handler(delta: DiffDelta, hunk: Option<DiffHunk>, line: DiffLine) -> bool {
    println!("----\n{}----\n", str::from_utf8(line.content()).unwrap());
    false
}
<|endoftext|>


<commit_before>mod diff;

use std::io;

enum Mode {
    Command,
    Input,
}

struct Range {
    start: i32,
    end: i32,
}

fn command_line(line: &String, mode: &mut Mode) {
    match line.trim() {
        "a" => *mode = Mode::Input,
        "q" => std::process::exit(0),
        _ => println!("Command: {}", line),
    }
}

fn input_line(line: &String, mode: &mut Mode) {
    match line.trim() {
        "." => *mode = Mode::Command,
        _ => println!("Input: {}", line),
    }
}

fn append_after(lines: Vec<String>, range: Range, diff: &mut diff::Diff) {
    diff.add_lines(range.start, lines);
}

fn main() {
    let mut mode = Mode::Command;
    loop {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => (),
            Err(_) => {
                println!("?");
                continue
            },
        }
        match mode {
            Mode::Command => command_line(&line, &mut mode),
            Mode::Input => input_line(&line, &mut mode),
        }
    }
}
<commit_msg>Simplify command parsing; Add input loop<commit_after>mod diff;

use std::io;

struct Range {
    start: i32,
    end: i32,
}

fn input() -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();
    loop {
        let mut line = String::new();
        io::stdin().read_line(&mut line)
            .ok()
            .expect("Error reading line");
        match line.trim() {
            "." => {
                break
            },
            _ => {
                lines.push(line)
            }
        }
    }
    return lines;
}

fn command(line: &String, line_num: &mut i32, diff: &mut diff::Diff) {
    // parse the command line to get
    // Line num or range
    // command
    match line.trim() {
        "a" => {
            append_after(Range{start: *line_num, end: *line_num}, diff);
        },
        "q" => std::process::exit(0),
        _ => println!("Command: {}", line),
    }
}

fn append_after(range: Range, diff: &mut diff::Diff) {
    diff.add_lines(range.end+1, input());
}

fn main() {
    let prompt = ":";
    let mut diff = diff::Diff::new();
    let mut line_num: i32 = 1;
    loop {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => (),
            Err(_) => {
                println!("?");
                continue
            },
        }
        command(&line, &mut line_num, &mut diff);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate rocket_contrib;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

extern crate file;
extern crate rand;

use rocket_contrib::JSON;
use rocket::response::content::Content;
use rocket::http::ContentType;

use std::collections::HashSet;
use std::str::FromStr;

use rand::Rng;

#[derive(Serialize, Debug, Clone, Copy)]
enum Sex {
    Male,
    Female
}

impl rand::Rand for Sex {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        let variants = [Sex::Male, Sex::Female];
        *rng.choose(&variants).unwrap()
    }
}

#[derive(Serialize, Debug)]
struct Person {
    sex: Sex,
    first_name: String,
    second_name: String,
    last_name: String
}

#[derive(Debug)]
struct NamePool {
    female: Vec<String>,
    male: Vec<String>,
    surname: Vec<String>,
}

impl NamePool {
    fn random_name(&self) -> Person {
        fn random_value(vec: &Vec<String>) -> &String {
            // todo unwrap_or
            rand::thread_rng().choose(vec).unwrap()
        }

        let sex: Sex = rand::random();
        let first_name = match sex {
            Sex::Male => random_value(&self.male),
            Sex::Female => random_value(&self.female)
        };

        let person = Person {
            sex: sex,
            first_name: first_name.to_string(),
            second_name: random_value(&self.male).to_string(),
            last_name: random_value(&self.surname).to_string()
        };

        println!("{:?}", person);
        person
    }
}

#[get("/")]
fn index(pool: rocket::State<NamePool>) -> JSON<Person> {
    let person = pool.random_name();
    JSON(person)
}

fn json_workaround() -> ContentType {
    ContentType::from_str("application/json; encoding=utf-8").unwrap()
}

#[get("/2")]
fn index2(pool: rocket::State<NamePool>) -> Content<String> {
    let person = pool.random_name();
    let json = serde_json::to_string(&person).unwrap();
    Content(json_workaround(), json)
}

fn load_name_pool() -> NamePool {
    let female_names = merge_names(&[
        "src/names/female-names-v1-14376.txt",
        "src/names/female-names-v2-16673.txt",
    ]);

    let male_names = merge_names(&[
        "src/names/male-names-v1-14999.txt",
        "src/names/male-names-v2-21904.txt",
    ]);

    let surnames = merge_names(&[
        "src/names/surnames-184624.txt",
    ]);

    NamePool { female: female_names, male: male_names, surname: surnames }
}

fn merge_names(filenames: &[&str]) -> Vec<String> {
    let mut distinct = HashSet::new();
    for filename in filenames {
        let names = load_from_file(filename);
        for item in names {
            distinct.insert(item);
        }
    }

    let mut result = vec![];
    for item in distinct {
        result.push(item);
    }

    result
}

fn load_from_file(filename: &str) -> HashSet<String> {
    let content = Box::new(file::get_text(filename).unwrap_or("".to_string()));
    let mut names = HashSet::new();
    for line in content.as_ref().split_whitespace() {
        names.insert(line.to_string());
    }
    names
}

fn main() {
    let pool = load_name_pool();
    rocket::ignite()
        .manage(pool)
        .mount("/", routes![index, index2]).launch();
}
<commit_msg>Добавлен примитивный генератор отчества.<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate rocket_contrib;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

extern crate file;
extern crate rand;

use rocket_contrib::JSON;
use rocket::response::content::Content;
use rocket::http::ContentType;

use std::collections::HashSet;
use std::str::FromStr;

use rand::Rng;

use patronymic::Sex;

impl rand::Rand for Sex {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        let variants = [Sex::Male, Sex::Female];
        *rng.choose(&variants).unwrap()
    }
}

#[derive(Serialize, Debug)]
struct Person {
    sex: Sex,
    first_name: String,
    patronymic: String,
    surname: String
}

#[derive(Debug)]
struct NamePool {
    female: Vec<String>,
    male: Vec<String>,
    surname: Vec<String>,
}

impl NamePool {
    fn random_name(&self) -> Person {
        fn random_value(vec: &Vec<String>) -> &String {
            // todo unwrap_or
            rand::thread_rng().choose(vec).unwrap()
        }

        let sex: Sex = rand::random();
        let first_name = match sex {
            Sex::Male => random_value(&self.male),
            Sex::Female => random_value(&self.female)
        };

        let person = Person {
            sex: sex,
            first_name: first_name.to_string(),
            patronymic: patronymic::from_name(random_value(&self.male), sex).to_string(),
            surname: random_value(&self.surname).to_string()
        };

        println!("{:?}", person);
        person
    }
}

#[get("/")]
fn index(pool: rocket::State<NamePool>) -> JSON<Person> {
    let person = pool.random_name();
    JSON(person)
}

fn json_workaround() -> ContentType {
    ContentType::from_str("application/json; encoding=utf-8").unwrap()
}

#[get("/2")]
fn index2(pool: rocket::State<NamePool>) -> Content<String> {
    let person = pool.random_name();
    let json = serde_json::to_string(&person).unwrap();
    Content(json_workaround(), json)
}

fn load_name_pool() -> NamePool {
    let female_names = merge_names(&[
        "src/names/female-names-v1-14376.txt",
        "src/names/female-names-v2-16673.txt",
    ]);

    let male_names = merge_names(&[
        "src/names/male-names-v1-14999.txt",
        "src/names/male-names-v2-21904.txt",
    ]);

    let surnames = merge_names(&[
        "src/names/surnames-184624.txt",
    ]);

    NamePool { female: female_names, male: male_names, surname: surnames }
}

fn merge_names(filenames: &[&str]) -> Vec<String> {
    let mut distinct = HashSet::new();
    for filename in filenames {
        let names = load_from_file(filename);
        for item in names {
            distinct.insert(item);
        }
    }

    let mut result = vec![];
    for item in distinct {
        result.push(item);
    }

    result
}

fn load_from_file(filename: &str) -> HashSet<String> {
    let content = Box::new(file::get_text(filename).unwrap_or("".to_string()));
    let mut names = HashSet::new();
    for line in content.as_ref().split_whitespace() {
        names.insert(line.to_string());
    }
    names
}

fn main() {
    let pool = load_name_pool();
    rocket::ignite()
        .manage(pool)
        .mount("/", routes![index, index2]).launch();
}

mod patronymic {
    #[derive(Serialize, Debug, Clone, Copy, PartialEq)]
    pub enum Sex {
        Male,
        Female
    }

    /// http://zags.kurganobl.ru/obrazovanie_i_napisanie_otchestv.html
    /// 	Отчества от мужских имен (русских и нерусских) в русском языке образуются по следующим правилам:
    /// 1. Если имя оканчивается на твёрдый согласный (кроме ж, ш, ч, щ, ц), добавляется -ович / овна:
    /// Александр + ович/овна, Иван + ович/овна, Гамзат + ович/овна.
    ///
    /// 2. К именам, оканчивающимся на ж, ш, ч, щ, ц, добавляется -евич / евна:
    /// Жорж + евич/евна, Януш + евич/евна, Милич + евич/евна, Франц + евич/евна.
    ///
    /// 3. Если имя оканчивается на неударный гласный а, у, ы, к нему добавляется -ович / овна, причём конечные гласные имени отбрасываются:
    /// Антипа - Антипович/Антиповна, Вавила - Вавилович/ Вавиловна.
    /// Исключение: от русских имён Аникита, Никита, Мина, Савва, Сила, Фока образуются традиционные формы отчеств на -ич / ична:
    /// Никита - Никитич/ Никитична, Мина - Минич/Минична, Савва — Саввич/Саввична.
    ///
    /// 4. Если имя оканчивается на неударный гласный о, к нему добавляется -ович / овна, причём конечный гласный имени и начальный суффикса сливаются в один звук "о":
    /// Василько + ович/овна, Михайло + ович/овна, Отто + ович/овна.
    ///
    /// 5. Если неударному конечному гласному предшествует ж или ш, ч, щ, ц, то добавляется -евич / евна, а гласный отбрасывается:
    /// Важа - Важевич/Важевна, Гоча - Гочевич/Гочевна.
    ///
    /// 6. Если имя оканчивается на мягкий согласный, т. е. на согласный + ь, к нему добавляется -евич / евна, а конечный ь отбрасывается:
    /// Игорь - Игоревич/Игоревна, Цезарь - Цезаревич/Цезаревна, Виль - Вилевич/Вилевна, Камиль — Камилевич/Камилевна.
    ///
    /// 7. Если имя оканчивается на неударный гласный е, к нему добавляется -евич / евна, причём конечный гласный имени и начальный суффикса сливаются:
    /// Аарне - Аарневич/Аарневна, Григоре - Григоревич/Григоревна, Вилье — Вильевич/Вильевна.
    ///
    /// 8. Если имя оканчивается на неударный гласный и, к нему добавляется -евич / евна, при этом конечный гласный сохраняется:
    /// Вилли - Виллиевич/Виллиевна, Илмари - Илмариевич/Илмариевна.
    ///
    /// 9. Если имя оканчивается на неударное сочетание ий, к нему добавляется -евич / евна, причём конечный й отбрасывается, а предпоследний и либо переходит в ь, либо остаётся:
    /// а) переходит в ь после одного согласного или группы нт:
    /// Василий - Васильевич/Васильевна, Марий - Марьевич/Марьевна, Юлий — Юльевич/Юльевна.
    /// б) остаётся после к, х, ц, а также после двух согласных (кроме группы нт ):
    /// Никий - Никиевич/Никиевна, Люций - Люциевич/ Люциевна, Стахий — Стахиевич/Стахиевна.
    ///
    /// 10. Старые русские имена, оканчивающиеся на сочетания ея и ия , образуют отчества прибавлением -евич / евна, при этом конечное я отбрасывается, а и или е сохраняется:
    /// Менея - Менеевич/ Менеевна, Захария — Захариевич/Захариевна.
    ///
    /// 11. К именам, оканчивающимся на ударные гласные а, я, е, э, и, ы, ё, о, у, ю, добавляется -евич / евна, при этом конечный гласный сохраняется:
    /// Айбу - Айбуевич/Айбуевна, Бадма - Бадмаевич/Бадмаевна, Бату - Бутуевич/Батуевна, Вали - Валиевич/Валиевна, Дакко - Даккоевич/Даккоевна, Исе — Исеевич/Исеевна.
    ///
    /// 12. Имена, оканчивающиеся на ударные сочетания ай, яй, ей, эй, ий, ый, ой, уй, юй, образуют отчества прибавлением -евич / евна, причём конечный й отбрасывается:
    /// Акбай - Акбаевич/Акбаевна, Кий - Киевич/Киевна, Матвей — Матвеевич/Матвеевна.
    ///
    /// 13. Имена, оканчивающиеся на два гласных аа, ау, еу, ээ, ии, уу сохраняют их, образуя отчества прибавлением -евич / евна:
    /// Бимбии - Бимбииевич/Бимбииевна, Бобоо-Бобооевич/Бобооевна,Бурбээ—Бурбээевич/Бурбээевна.
    ///
    /// По настоянию заявителей возможны образования отчеств, которые несколько не соотвествуют изложенным правилам, так как с течением времени правила образования отчеств изменяются.
    /// Например, отчества от татарских и некоторых других имён имеют тенденцию выравниваться по русским образцам и принимать формы Набиуллович (вместо Набиуллаевич),
    /// Хамзевич (вместо Хамзяевич), Янович (вместо Янисович), Мариевич (вместо Мариусович) и т. д.
    /// Если у отца именуемого двойное имя, отчество для него образуется от любого из двух имен по выбору заявителей.
    /// Например, если отец Игорь-Эдуард,а ребенка назвали Антон, в его документах пишется либо Антон Игоревич, либо Антон Эдуардович,
    /// либо Антон Игорь-Эдуардович, как родители сочтут более удобным.
    pub fn from_name(first_name: &str, sex: Sex) -> String {
        let mut name = first_name.to_owned();
        let last_letter = name.pop().unwrap();

        let result = match last_letter {
            'б' | 'в' | 'г' | 'д' | 'р' | 'н' | 'т' => {
                // todo что такое твёрдый согласный?
                let ending = if sex == Sex::Male { "ович" } else { "овна" };
                first_name.to_owned() + ending
            }
            'й' => {
                let ending = if sex == Sex::Male { "евич" } else { "евна" };
                name.to_owned() + ending
            }
            'ж' | 'ш' | 'ч' | 'щ' | 'ц' => {
                let ending = if sex == Sex::Male { "евич" } else { "евна" };
                first_name.to_owned() + ending
            }
            'а' | 'у' | 'ы' | 'о' => {
                match first_name {
                    "Аникита" | "Никита" | "Мина" | "Савва" | "Сила" | "Фока" => {
                        let ending = if sex == Sex::Male { "ич" } else { "ична" };
                        name.to_owned() + ending
                    }
                    _ => {
                        let ending = if sex == Sex::Male { "ович" } else { "овна" };
                        name.to_owned() + ending
                    }
                }
            }
            _ => name
        };

        result.to_owned()
    }

    #[test]
    fn test_from_name() {
        fn test_name(name: &str, male_name: &str, female_name: &str) {
            assert_eq!(male_name, from_name(name, Sex::Male));
            assert_eq!(female_name, from_name(name, Sex::Female));
        }

        // 1.
        test_name("Александр", "Александрович", "Александровна");
        test_name("Иван", "Иванович", "Ивановна");
        test_name("Гамзат", "Гамзатович", "Гамзатовна");
        // 2.
        test_name("Андрей", "Андреевич", "Андреевна");
        test_name("Жорж", "Жоржевич", "Жоржевна");
        test_name("Милич", "Миличевич", "Миличевна");
        test_name("Франц", "Францевич", "Францевна");
        test_name("Януш", "Янушевич", "Янушевна");
        // 3.
        test_name("Антипа", "Антипович", "Антиповна");
        test_name("Вавила", "Вавилович", "Вавиловна");
        test_name("Бату", "Батович", "Батовна");
        test_name("Метлы", "Метлович", "Метловна");
        test_name("Аникита", "Аникитич", "Аникитична");
        test_name("Никита", "Никитич", "Никитична");
        test_name("Мина", "Минич", "Минична");
        test_name("Савва", "Саввич", "Саввична");
        test_name("Сила", "Силич", "Силична");
        test_name("Фока", "Фокич", "Фокична");
        // 4.
        test_name("Василько", "Василькович", "Васильковна");
        test_name("Отто", "Оттович", "Оттовна");
    }
}<|endoftext|>


<commit_before>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

//extern crate getopts;
//use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos:usize = 0;
    //0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate:usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset:usize = 0;
    const SPALTEN:usize = 16;
    let mut command = String::new();

    //start ncursesw
    initscr();
    let screenheight : usize = getmaxy(stdscr) as usize;
    //ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    /*
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("f", "", "set file name", "NAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    }
    let path = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    };*/

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

//TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);

    let mut key;
//    key = getch() as u8;
//    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key{
                104 => { // Button "h"
                    if cursorstate == 2 { // ascii mode
                        if cursorpos > 0 { // not at start
                            cursorpos-=1; // go left
                        }
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        if cursorpos > 0 { // not at start
                            cursorstate = 1; // right nibble
                            cursorpos-=1; // go left
                        }
                    }
                },
                106 => { //Button "j"
                    if cursorpos+SPALTEN < buf.len() { // not at end
                        cursorpos+=SPALTEN; // go down
                    }
                    else { // when at end
                        if buf.len() != 0 { // Suppress underflow
                            cursorpos=buf.len()-1; // go to end
                        }
                    }
                },
                107 => { //Button "k"
                    if cursorpos >= SPALTEN {
                        cursorpos-=SPALTEN;
                    }
                },
                108 => { // Button "l"
                    if cursorstate == 2 { // ascii mode
                        if cursorpos < buf.len()-1 { // not at end
                            cursorpos+=1; // go right
                        }
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        if cursorpos < buf.len()-1 { // not at end
                            cursorstate = 0; // left nibble
                            cursorpos+=1; // go right
                        }
                    }
                },
                 48 => { // Button "0"
                    cursorpos -= cursorpos%SPALTEN; // jump to start of line
                    if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                },
                 36 => { // Button "$"
                    if cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1) < buf.len() { // check if no overflow
                        cursorpos = cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1); // jump to end of line
                    }
                    else {
                        cursorpos = buf.len()-1 // jump to end of line
                    }
                    if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                },
                114 => { // Button "r"
                    mode = Mode::Replace;
                },
                120 => { // Button "x"
                    if buf.len() > 0 { // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() {
                            cursorpos = buf.len()-1;
                        }
                    }
                },
                105 => { // Button "i"
                    mode = Mode::Insert;
                },
                 58 => { // Button ":"
                     command.clear(); // delete old command
                     mode = Mode::TypeCommand;
                 },
                 74 => { // Button "J"
                     if cursorstate == 2 { // ascii mode
                         cursorstate = 0; // hex mode, left nibble
                     }
                     else {
                         cursorstate = 2; // jump to ascii
                     }
                 },
                 63 => { //TODO
                     command.push_str("No helpfile yet");
                 },
                 47 => { //TODO
                     command.clear();
                     mode = Mode::TypeSearch;
                 },
                _ => (),
            }

            //Always move screen when cursor leaves screen
            if cursorpos > (screenheight+screenoffset-1)*SPALTEN -1 {
                screenoffset+=1; // move screen
            }
            if cursorpos < screenoffset*SPALTEN {
                screenoffset-=1; // move screen
            }

        } else
        if mode == Mode::Replace && cursorstate == 2 { // r was pressed so replace next char in ascii mode
            match key {
                c @ 32...126 => { buf[cursorpos] = c },
                _ => (),
            }
            mode = Mode::Command;
        } else
        if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            match key { // Change the selected nibble
                c @ 65... 70 => // A-F
                    { buf[cursorpos] = buf[cursorpos]&mask | (c-55)<<shift },
                c @ 97...102 => // a-f
                    { buf[cursorpos] = buf[cursorpos]&mask | (c-87)<<shift },
                c @ 48... 57 => // 0-9
                    { buf[cursorpos] = buf[cursorpos]&mask | (c-48)<<shift },
                _ => ()
            }
            mode = Mode::Command;
        } else
        if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => { command.push(c as char); },
                27 => {command.clear();mode = Mode::Command;},
                10 => { // Enter pressed, compute command!
                        if (command == "w".to_string()) || (command == "wq".to_string()) {
                            file.seek(SeekFrom::Start(0)).ok().expect("Filepointer could not be set to 0");
                            file.write_all(&mut buf).ok().expect("File could not be written.");
                            if command == "wq".to_string() {
                                quitnow = 1;
                            }
                            command.clear();mode = Mode::Command;
                        }
                        else if command == "q".to_string() {
                            quitnow = 1;
                        }
                        else {
                            command.clear();
                            command.push_str("Bad_command!");
                            mode = Mode::Command;
                        }
                    },
                _ => (),
            }
        } else
        if mode == Mode::Insert {
            if cursorstate == 0 { // Left nibble
                match key {
                    c @ 65... 70 => // A-F
                        {buf.insert(cursorpos, (c-55)<<4 ); cursorstate = 1;},
                    c @ 97...102 => // a-f
                        {buf.insert(cursorpos, (c-87)<<4 ); cursorstate = 1;},
                    c @ 48... 57 => // 0-9
                        {buf.insert(cursorpos, (c-48)<<4 ); cursorstate = 1;},
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else
            if cursorstate == 1 { // Right nibble
                match key {
                    c @ 65...70 => // A-F
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-55); cursorstate = 0; cursorpos+=1; },
                    c @ 97...102 => // a-f
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-87); cursorstate = 0; cursorpos+=1; },
                    c @ 48...57 => // 0-9
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-48); cursorstate = 0; cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else
            if cursorstate == 2 { // Ascii
                match key {
                    c @ 32...126 => { buf.insert(cursorpos, c); cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => (),
                }
            }
        } else
        if mode == Mode::TypeSearch {
//            if cursorstate == 2 { // Ascii search
                match key {
                    c @ 32...126 => { command.push(c as char); },
                    27 => {command.clear();mode = Mode::Command;},
                    10 => { // Enter pressed, compute command!
                        mode = Mode::SearchIt;
                    }
                    _ => (),
                }
//            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                    //command.push_str("Bad_command!");
            }
        }
        draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);
    }

    refresh();
    endwin();
}

<commit_msg>Style: Match keys as chars<commit_after>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

//extern crate getopts;
//use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos:usize = 0;
    //0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate:usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset:usize = 0;
    const SPALTEN:usize = 16;
    let mut command = String::new();

    //start ncursesw
    initscr();
    let screenheight : usize = getmaxy(stdscr) as usize;
    //ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    /*
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("f", "", "set file name", "NAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    }
    let path = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    };*/

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

//TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);

    let mut key;
//    key = getch() as u8;
//    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos > 0 { // not at start
                            cursorpos-=1; // go left
                        }
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        if cursorpos > 0 { // not at start
                            cursorstate = 1; // right nibble
                            cursorpos-=1; // go left
                        }
                    }
                },
                'j' => {
                    if cursorpos+SPALTEN < buf.len() { // not at end
                        cursorpos+=SPALTEN; // go down
                    }
                    else { // when at end
                        if buf.len() != 0 { // Suppress underflow
                            cursorpos=buf.len()-1; // go to end
                        }
                    }
                },
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos-=SPALTEN;
                    }
                },
                'l' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos < buf.len()-1 { // not at end
                            cursorpos+=1; // go right
                        }
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        if cursorpos < buf.len()-1 { // not at end
                            cursorstate = 0; // left nibble
                            cursorpos+=1; // go right
                        }
                    }
                },
                 '0' => {
                    cursorpos -= cursorpos%SPALTEN; // jump to start of line
                    if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                },
                 '$' => {
                    if cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1) < buf.len() { // check if no overflow
                        cursorpos = cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1); // jump to end of line
                    }
                    else {
                        cursorpos = buf.len()-1 // jump to end of line
                    }
                    if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                },
                'r' => {
                    mode = Mode::Replace;
                },
                'x' => {
                    if buf.len() > 0 { // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() {
                            cursorpos = buf.len()-1;
                        }
                    }
                },
                'i' => {
                    mode = Mode::Insert;
                },
                 ':' => {
                     command.clear(); // delete old command
                     mode = Mode::TypeCommand;
                 },
                 'J' => {
                     if cursorstate == 2 { // ascii mode
                         cursorstate = 0; // hex mode, left nibble
                     }
                     else {
                         cursorstate = 2; // jump to ascii
                     }
                 },
                 '?' => { //TODO
                     command.push_str("No helpfile yet");
                 },
                 '/' => { //TODO
                     command.clear();
                     mode = Mode::TypeSearch;
                 },
                _ => (),
            }

            //Always move screen when cursor leaves screen
            if cursorpos > (screenheight+screenoffset-1)*SPALTEN -1 {
                screenoffset+=1; // move screen
            }
            if cursorpos < screenoffset*SPALTEN {
                screenoffset-=1; // move screen
            }

        } else
        if mode == Mode::Replace && cursorstate == 2 { // r was pressed so replace next char in ascii mode
            match key {
                c @ 32...126 => { buf[cursorpos] = c },
                _ => (),
            }
            mode = Mode::Command;
        } else
        if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            // Change the selected nibble
            match key as char {
                c @ 'A'...'F' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 55)<<shift },
                c @ 'a'...'f' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 87)<<shift },
                c @ '0'...'9' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 48)<<shift },
                _ => ()
            }
            mode = Mode::Command;
        } else
        if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => { command.push(c as char); },
                27 => {command.clear();mode = Mode::Command;},
                10 => { // Enter pressed, compute command!
                        if (command == "w".to_string()) || (command == "wq".to_string()) {
                            file.seek(SeekFrom::Start(0)).ok().expect("Filepointer could not be set to 0");
                            file.write_all(&mut buf).ok().expect("File could not be written.");
                            if command == "wq".to_string() {
                                quitnow = 1;
                            }
                            command.clear();mode = Mode::Command;
                        }
                        else if command == "q".to_string() {
                            quitnow = 1;
                        }
                        else {
                            command.clear();
                            command.push_str("Bad_command!");
                            mode = Mode::Command;
                        }
                    },
                _ => (),
            }
        } else
        if mode == Mode::Insert {
            if cursorstate == 0 { // Left nibble
                match key {
                    c @ 65... 70 => // A-F
                        {buf.insert(cursorpos, (c-55)<<4 ); cursorstate = 1;},
                    c @ 97...102 => // a-f
                        {buf.insert(cursorpos, (c-87)<<4 ); cursorstate = 1;},
                    c @ 48... 57 => // 0-9
                        {buf.insert(cursorpos, (c-48)<<4 ); cursorstate = 1;},
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else
            if cursorstate == 1 { // Right nibble
                match key {
                    c @ 65...70 => // A-F
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-55); cursorstate = 0; cursorpos+=1; },
                    c @ 97...102 => // a-f
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-87); cursorstate = 0; cursorpos+=1; },
                    c @ 48...57 => // 0-9
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-48); cursorstate = 0; cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else
            if cursorstate == 2 { // Ascii
                match key {
                    c @ 32...126 => { buf.insert(cursorpos, c); cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => (),
                }
            }
        } else
        if mode == Mode::TypeSearch {
//            if cursorstate == 2 { // Ascii search
                match key {
                    c @ 32...126 => { command.push(c as char); },
                    27 => {command.clear();mode = Mode::Command;},
                    10 => { // Enter pressed, compute command!
                        mode = Mode::SearchIt;
                    }
                    _ => (),
                }
//            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                    //command.push_str("Bad_command!");
            }
        }
        draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);
    }

    refresh();
    endwin();
}

<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate cobalt;
extern crate getopts;
extern crate env_logger;
extern crate notify;
extern crate ghp;

#[macro_use]
extern crate nickel;

#[macro_use]
extern crate log;

use getopts::Options;
use std::env;
use std::fs;
use cobalt::Config;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;
use nickel::{Nickel, Options as NickelOptions, StaticFilesHandler};
use ghp::import_dir;

use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;
use std::thread;

fn print_version() {
    println!("0.2.0");
}

fn print_usage(opts: Options) {
    let usage = concat!("\n\tbuild -- build the cobalt project at the source dir",
                        "\n\tserve -- build and serve the cobalt project at the source dir",
                        "\n\twatch -- build, serve, and watch the project at the source dir",
                        "\n\tupload -- moves the contents of the dest folder to the gh-pages branch");
    println!("{}", opts.usage(usage));
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();

    opts.optopt("s", "source", "Source folder, Default: ./", "");
    opts.optopt("d", "destination", "Destination folder, Default: ./", "");
    opts.optopt("c",
                "config",
                "Config file to use, Default: .cobalt.yml",
                "");
    opts.optopt("l",
                "layouts",
                "\tLayout templates folder, Default: _layouts/",
                "");
    opts.optopt("p", "posts", "Posts folder, Default: _posts/", "");
    opts.optopt("P", "port", "Port to serve from, Default: 3000", "");

    opts.optflag("", "debug", "Log verbose (debug level) information");
    opts.optflag("", "trace", "Log ultra-verbose (trace level) information");
    opts.optflag("", "silent", "Suppress all output");
    opts.optflag("h", "help", "Print this help menu");
    opts.optflag("v", "version", "Display version");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    if matches.opt_present("version") {
        print_version();
        return;
    }

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);
    builder.filter(None, LogLevelFilter::Info);

    if matches.opt_present("debug") {
        builder.filter(None, LogLevelFilter::Debug);
    }

    if matches.opt_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.opt_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = match matches.opt_str("config") {
        Some(config) => config,
        None => "./.cobalt.yml".to_owned(),
    };

    // Fetch config information if available
    let mut config: Config = if fs::metadata(&config_path).is_ok() {
        info!("Using config file {}", &config_path);

        match Config::from_file(&config_path) {
            Ok(config) => config,
            Err(e) => {
                error!("Error reading config file:");
                error!("{}", e);
                std::process::exit(1);
            }
        }
    } else {
        Default::default()
    };

    if let Some(source) = matches.opt_str("s") {
        config.source = source;
    };

    if let Some(dest) = matches.opt_str("d") {
        config.dest = dest;
    };

    if let Some(layouts) = matches.opt_str("layouts") {
        config.layouts = layouts;
    };

    if let Some(posts) = matches.opt_str("posts") {
        config.posts = posts;
    };

    let command = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(opts);
        return;
    };

    // Check for port and set port variable to it
    let port = matches.opt_str("port").unwrap_or("3000".to_owned());

    match command.as_ref() {
        "build" => {
            build(&config);
        }

        "serve" => {
            build(&config);
            serve(&config.dest, &port);
        }

        "watch" => {
            build(&config);

            let dest = config.dest.clone();
            thread::spawn(move || {
                serve(&dest, &port);
            });

            let (tx, rx) = channel();
            let w: Result<RecommendedWatcher, Error> = Watcher::new(tx);

            match w {
                Ok(mut watcher) => {
                    // TODO: clean up this unwrap
                    watcher.watch(&config.source).unwrap();
                    info!("Watching {:?} for changes", &config.source);

                    loop {
                        match rx.recv() {
                            Ok(val) => {
                                trace!("file changed {:?}", val);
                                info!("Rebuilding cobalt site...");
                                build(&config);
                            }

                            Err(e) => {
                                error!("[Notify Error]: {}", e);
                                std::process::exit(1);
                            }
                        }
                    }
                }
                Err(e) => {
                    error!("[Notify Error]: {}", e);
                    std::process::exit(1);
                }
            }
        }

        "upload" => {
            info!("Importing {} to gh-pages", &config.dest);

            let meta = match fs::metadata(&config.dest) {
                Ok(data) => data,

                Err(e) => {
                    error!("{}", e);
                    error!("Import not successful");
                    std::process::exit(1);
                }
            };

            if meta.is_dir() {
                match import_dir(&config.dest, "gh-pages", "cobalt site upload") {
                    Ok(_) => info!("Import successful"),
                    Err(e) => {
                        error!("{}", e);
                        error!("Import not successful");
                        std::process::exit(1);
                    }
                }
            } else {
                error!("Build dir is not a directory: {}", &config.dest);
                error!("Import not successful");
                std::process::exit(1);
            }
        }

        _ => {
            print_usage(opts);
            return;
        }
    }
}

fn build(config: &Config) {
    info!("Building from {} into {}", config.source, config.dest);
    match cobalt::build(&config) {
        Ok(_) => info!("Build successful"),
        Err(e) => {
            error!("{}", e);
            error!("Build not successful");
            std::process::exit(1);
        }
    };
}

fn serve(dest: &str, port: &str) {
    info!("Serving {:?} through static file server", dest);
    let mut server = Nickel::new();
    server.options = NickelOptions::default().output_on_listen(false);

    server.utilize(StaticFilesHandler::new(dest));

    let ip = "127.0.0.1:".to_owned() + port;
    info!("Server Listening on {}", &ip);
    info!("Ctrl-c to stop the server");
    server.listen(&*ip);
}
<commit_msg>cleaned up import command<commit_after>#![deny(warnings)]

extern crate cobalt;
extern crate getopts;
extern crate env_logger;
extern crate notify;
extern crate ghp;

#[macro_use]
extern crate nickel;

#[macro_use]
extern crate log;

use getopts::Options;
use std::env;
use std::fs;
use cobalt::Config;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;
use nickel::{Nickel, Options as NickelOptions, StaticFilesHandler};
use ghp::import_dir;

use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;
use std::thread;

fn print_version() {
    println!("0.2.0");
}

fn print_usage(opts: Options) {
    let usage = concat!("\n\tbuild -- build the cobalt project at the source dir, -i --import will import the site to the gh-pages branch",
                        "\n\tserve -- build and serve the cobalt project at the source dir",
                        "\n\twatch -- build, serve, and watch the project at the source dir",
                        "\n\timport -- moves the contents of the dest folder to the gh-pages branch");
    println!("{}", opts.usage(usage));
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();

    opts.optopt("s", "source", "Source folder, Default: ./", "");
    opts.optopt("d", "destination", "Destination folder, Default: ./", "");
    opts.optopt("c",
                "config",
                "Config file to use, Default: .cobalt.yml",
                "");
    opts.optopt("l",
                "layouts",
                "\tLayout templates folder, Default: _layouts/",
                "");
    opts.optopt("p", "posts", "Posts folder, Default: _posts/", "");
    opts.optopt("P", "port", "Port to serve from, Default: 3000", "");
    opts.optopt("b", "branch", "Branch that will be used to import the site to, Default: gh-pages", "");
    opts.optopt("m", "message", "Commit message that will be used on import, Default: cobalt site import", "");

    opts.optflag("", "debug", "Log verbose (debug level) information");
    opts.optflag("", "trace", "Log ultra-verbose (trace level) information");
    opts.optflag("", "silent", "Suppress all output");
    opts.optflag("i", "import", "Import after build to gh-pages branch");
    opts.optflag("h", "help", "Print this help menu");
    opts.optflag("v", "version", "Display version");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    if matches.opt_present("version") {
        print_version();
        return;
    }

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);
    builder.filter(None, LogLevelFilter::Info);

    if matches.opt_present("debug") {
        builder.filter(None, LogLevelFilter::Debug);
    }

    if matches.opt_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.opt_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = match matches.opt_str("config") {
        Some(config) => config,
        None => "./.cobalt.yml".to_owned(),
    };

    // Fetch config information if available
    let mut config: Config = if fs::metadata(&config_path).is_ok() {
        info!("Using config file {}", &config_path);

        match Config::from_file(&config_path) {
            Ok(config) => config,
            Err(e) => {
                error!("Error reading config file:");
                error!("{}", e);
                std::process::exit(1);
            }
        }
    } else {
        Default::default()
    };

    if let Some(source) = matches.opt_str("s") {
        config.source = source;
    };

    if let Some(dest) = matches.opt_str("d") {
        config.dest = dest;
    };

    if let Some(layouts) = matches.opt_str("layouts") {
        config.layouts = layouts;
    };

    if let Some(posts) = matches.opt_str("posts") {
        config.posts = posts;
    };

    let command = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(opts);
        return;
    };

    // Check for port and set port variable to it
    let port = matches.opt_str("port").unwrap_or("3000".to_owned());
    let branch = matches.opt_str("branch").unwrap_or("gh-pages".to_owned());
    let message = matches.opt_str("message").unwrap_or("cobalt site import".to_owned());
    let should_import = matches.opt_present("import");

    match command.as_ref() {
        "build" => {
            build(&config);
            if should_import {
                import(&config, &branch, &message);
            }
        }

        "serve" => {
            build(&config);
            serve(&config.dest, &port);
        }

        "watch" => {
            build(&config);

            let dest = config.dest.clone();
            thread::spawn(move || {
                serve(&dest, &port);
            });

            let (tx, rx) = channel();
            let w: Result<RecommendedWatcher, Error> = Watcher::new(tx);

            match w {
                Ok(mut watcher) => {
                    // TODO: clean up this unwrap
                    watcher.watch(&config.source).unwrap();
                    info!("Watching {:?} for changes", &config.source);

                    loop {
                        match rx.recv() {
                            Ok(val) => {
                                trace!("file changed {:?}", val);
                                info!("Rebuilding cobalt site...");
                                build(&config);
                            }

                            Err(e) => {
                                error!("[Notify Error]: {}", e);
                                std::process::exit(1);
                            }
                        }
                    }
                }
                Err(e) => {
                    error!("[Notify Error]: {}", e);
                    std::process::exit(1);
                }
            }
        }

        "import" => {
            import(&config, &branch, &message);
        }

        _ => {
            print_usage(opts);
            return;
        }
    }
}

fn build(config: &Config) {
    info!("Building from {} into {}", config.source, config.dest);
    match cobalt::build(&config) {
        Ok(_) => info!("Build successful"),
        Err(e) => {
            error!("{}", e);
            error!("Build not successful");
            std::process::exit(1);
        }
    };
}

fn serve(dest: &str, port: &str) {
    info!("Serving {:?} through static file server", dest);
    let mut server = Nickel::new();
    server.options = NickelOptions::default().output_on_listen(false);

    server.utilize(StaticFilesHandler::new(dest));

    let ip = "127.0.0.1:".to_owned() + port;
    info!("Server Listening on {}", &ip);
    info!("Ctrl-c to stop the server");
    server.listen(&*ip);
}

fn import(config: &Config, branch: &str, message: &str) {
    info!("Importing {} to {}", config.dest, branch);

    let meta = match fs::metadata(&config.dest) {
        Ok(data) => data,

        Err(e) => {
            error!("{}", e);
            error!("Import not successful");
            std::process::exit(1);
        }
    };

    if meta.is_dir() {
        match import_dir(&config.dest, branch, message) {
            Ok(_) => info!("Import successful"),
            Err(e) => {
                error!("{}", e);
                error!("Import not successful");
                std::process::exit(1);
            }
        }
    } else {
        error!("Build dir is not a directory: {}", config.dest);
        error!("Import not successful");
        std::process::exit(1);
    }
}
<|endoftext|>