<commit_before>#![feature(io)]
extern crate libc;
extern crate ncurses;
extern crate getopts;
extern crate regex;
#[macro_use] extern crate lazy_static;
mod util;
mod item;
mod reader;
mod input;
mod matcher;
mod event;
mod model;
mod score;
mod orderedvec;
mod curses;
mod query;
mod ansi;

use std::sync::{Arc, RwLock};
use std::thread;
use std::time::Duration;
use std::mem;
use std::ptr;
use util::eventbox::EventBox;

use ncurses::*;
use event::Event;
use input::Input;
use reader::Reader;
use matcher::Matcher;
use model::Model;
use libc::{sigemptyset, sigaddset, sigwait, pthread_sigmask};
use curses::{ColorTheme, Curses};
use getopts::Options;
use std::env;
use orderedvec::OrderedVec;
use item::MatchedItem;

fn main() {
    let exit_code = real_main();
    std::process::exit(exit_code);
}

fn real_main() -> i32 {

    // option parsing

    let mut opts = Options::new();
    opts.optopt("b", "bind", "comma seperated keybindings, such as 'ctrl-j:accept,ctrl-k:kill-line'", "KEY:ACTION");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("m", "multi", "Enable Multiple Selection");
    opts.optopt("p", "prompt", "prompt string", "'> '");
    opts.optopt("e", "expect", "comma seperated keys that can be used to complete fzf", "KEYS");
    opts.optopt("t", "tiebreak", "comma seperated criteria", "[score,index,begin,end,-score,...]");
    opts.optflag("", "ansi", "parse ANSI color codes for input strings");
    opts.optopt("c", "cmd", "command to invoke dynamically", "ag");
    opts.optflag("i", "interactive", "Use skim as an interactive interface");
    opts.optflag("", "regex", "use regex instead of fuzzy match");
    opts.optopt("q", "query", "specify the initial query", "\"\"");
    opts.optopt("d", "delimiter", "specify the delimiter(in REGEX) for fields", "\\t");
    opts.optopt("n", "nth", "specify the fields to be matched", "1,2..5");
    opts.optopt("", "with-nth", "specify the fields to be transformed", "1,2..5");
    opts.optopt("I", "", "replace `replstr` with the selected item", "replstr");

    let default_options = match env::var("SKIM_DEFAULT_OPTIONS") {
        Ok(val) => val,
        Err(_) => "".to_string(),
    };

    let mut args = Vec::new();
    for option in default_options.split(" ") {
        args.push(option.to_string());
    }

    let program = env::args().nth(0).unwrap_or("sk".to_string());
    for arg in env::args().skip(1) {
        args.push(arg);
    }

    let options = match opts.parse(args) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    // print help message
    if options.opt_present("h") {
        print_usage(&program, opts);
        return 0;
    }

    let theme = ColorTheme::new();
    let curses = Curses::new();
    curses::init(Some(&theme), false, false);

    // register terminal resize event, `pthread_sigmask` should be run before any thread.
    let mut sigset = unsafe {mem::uninitialized()};
    unsafe {
        sigemptyset(&mut sigset);
        sigaddset(&mut sigset, libc::SIGWINCH);
        pthread_sigmask(libc::SIG_SETMASK, &mut sigset, ptr::null_mut());
    }

    // controller variables
    let eb = Arc::new(EventBox::new());
    let item_buffer = Arc::new(RwLock::new(Vec::new()));

    let eb_clone = eb.clone();
    thread::spawn(move || {
        // listen to the resize event;
        loop {
            let mut sig = 0;
            let _errno = unsafe {sigwait(&mut sigset, &mut sig)};
            eb_clone.set(Event::EvResize, Box::new(true));
        }
    });

    // model
    let mut model = Model::new(eb.clone(), curses);
    model.parse_options(&options);

    // matcher
    let items = model.items.clone();
    let mut matcher = Matcher::new(items, item_buffer.clone(), eb.clone());
    let eb_matcher = matcher.eb_req.clone();
    matcher.parse_options(&options);

    // reader
    let default_command = match env::var("SKIM_DEFAULT_COMMAND") {
        Ok(val) => val,
        Err(_) => "find .".to_string(),
    };
    let mut reader = Reader::new(default_command, eb.clone(), item_buffer.clone());
    reader.parse_options(&options);
    let eb_reader = reader.eb_req.clone();

    // input
    let mut input = Input::new(eb.clone());
    input.parse_keymap(options.opt_str("b"));
    input.parse_expect_keys(options.opt_str("e"));

    // start running
    thread::spawn(move || {
        reader.run();
    });

    thread::spawn(move || {
        matcher.run();
    });

    thread::spawn(move || {
        input.run();
    });

    model.print_query(); // to place cursor
    model.refresh();

    let exit_code;

    'outer: loop {
        let mut immediate_refresh = false;
        for (e, val) in eb.wait() {
            match e {
                Event::EvReaderNewItem => {
                    eb_matcher.set(Event::EvMatcherNewItem, Box::new(true));
                    let reading: bool = *val.downcast().unwrap();
                    model.reading = reading;

                    let new_items = item_buffer.read().unwrap();
                    model.update_num_total(new_items.len());
                    model.print_info();
                }

                Event::EvMatcherUpdateProcess => {
                    let percentage: u64 = *val.downcast().unwrap();
                    model.update_percentage(percentage);
                    model.print_info();
                }

                Event::EvMatcherEnd => {
                    // do nothing
                    let result: Arc<RwLock<OrderedVec<MatchedItem>>> = *val.downcast().unwrap();
                    model.update_percentage(100);
                    model.update_matched_items(result);
                    model.display();
                }

                Event::EvQueryChange => {
                    let query: String = *val.downcast().unwrap();

                    if model.is_interactive {
                        model.clear_items();
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(query.clone()));
                        eb.wait_for(Event::EvMatcherSync);
                        eb_reader.set(Event::EvReaderResetQuery, Box::new(query.clone()));
                        eb.wait_for(Event::EvReaderSync);
                        eb_reader.set(Event::EvModelAck, Box::new(true));
                        eb_matcher.set(Event::EvModelAck, Box::new(true));
                        eb.clear();
                        break;
                    } else {
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(query));
                    }
                }

                Event::EvInputInvalid => {
                    // ignore
                }

                Event::EvInputKey => {
                    // ignore for now
                }

                Event::EvResize => {
                    model.resize();
                    model.display();
                    immediate_refresh = true;
                }

                Event::EvActAddChar => {
                    let ch: char = *val.downcast().unwrap();
                    model.act_add_char(ch);
                    model.print_query();
                }

                // Actions
                Event::EvActAbort => {
                    exit_code = 130;
                    break 'outer;
                }

                Event::EvActAccept => {
                    // break out of the loop and output the selected item.
                    //if model.get_num_selected() <= 0 { model.act_toggle(Some(true)); }
                    let args: Option<String> = *val.downcast().unwrap();
                    let num_selected = model.act_accept(args);
                    exit_code = if num_selected > 0 {0} else {1};
                    break 'outer;
                }

                Event::EvActBackwardChar => {
                    model.act_backward_char();
                    model.print_query();
                }

                Event::EvActBackwardDeleteChar => {
                    model.act_backward_delete_char();
                    model.print_query();
                }

                Event::EvActBackwardKillWord => {
                    model.act_backward_kill_word();
                    model.print_query();
                }

                Event::EvActBackwardWord => {
                    model.act_backward_word();
                    model.print_query();
                }

                Event::EvActBeginningOfLine => {
                    model.act_beginning_of_line();
                    model.print_query();
                }

                Event::EvActCancel => {}

                Event::EvActClearScreen => {
                    immediate_refresh = true;
                }

                Event::EvActDeleteChar => {
                    model.act_delete_char();
                    model.print_query();
                }

                Event::EvActDeleteCharEOF => {
                    model.act_delete_char();
                    model.print_query();
                }

                Event::EvActDeselectAll => {
                    model.act_deselect_all();
                    model.print_info();
                    model.print_items();
                }

                Event::EvActDown => {
                    model.act_move_line_cursor(-1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActEndOfLine => {
                    model.act_end_of_line();
                    model.print_query();
                }

                Event::EvActForwardChar => {
                    model.act_forward_char();
                    model.print_query();
                }

                Event::EvActForwardWord => {
                    model.act_forward_word();
                    model.print_query();
                }

                Event::EvActIgnore => {}

                Event::EvActKillLine => {
                    model.act_kill_line();
                    model.print_query();
                }

                Event::EvActKillWord => {
                    model.act_kill_word();
                    model.print_query();
                }

                Event::EvActNextHistory => {}

                Event::EvActPageDown => {
                    model.act_move_page(-1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActPageUp => {
                    model.act_move_page(1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActPreviousHistory => {}

                Event::EvActScrollLeft => {
                    model.act_vertical_scroll(-1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActScrollRight => {
                    model.act_vertical_scroll(1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActSelectAll => {
                    model.act_select_all();
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggle => {
                    model.act_toggle();
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggleAll => {
                    model.act_toggle_all();
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggleDown => {
                    model.act_toggle();
                    model.act_move_line_cursor(-1);
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggleIn => {}

                Event::EvActToggleOut => {}

                Event::EvActToggleSort => {}

                Event::EvActToggleUp => {
                    model.act_toggle();
                    model.act_move_line_cursor(1);
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActUnixLineDiscard => {
                    model.act_line_discard();
                    model.print_query();
                }

                Event::EvActUnixWordRubout => {
                    model.act_backward_kill_word();
                    model.print_query();
                }

                Event::EvActUp => {
                    model.act_move_line_cursor(1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActYank => {}

                _ => {
                    printw(format!("{}\n", e as i32).as_str());
                }
            }
        }

        if immediate_refresh {
            model.refresh();
        } else {
            model.refresh_throttle();
        }
        thread::sleep(Duration::from_millis(10));
    };

    model.close();
    model.output();
    exit_code
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}
<commit_msg>add option to print out the version number<commit_after>#![feature(io)]
extern crate libc;
extern crate ncurses;
extern crate getopts;
extern crate regex;
#[macro_use] extern crate lazy_static;
mod util;
mod item;
mod reader;
mod input;
mod matcher;
mod event;
mod model;
mod score;
mod orderedvec;
mod curses;
mod query;
mod ansi;

use std::sync::{Arc, RwLock};
use std::thread;
use std::time::Duration;
use std::mem;
use std::ptr;
use util::eventbox::EventBox;

use ncurses::*;
use event::Event;
use input::Input;
use reader::Reader;
use matcher::Matcher;
use model::Model;
use libc::{sigemptyset, sigaddset, sigwait, pthread_sigmask};
use curses::{ColorTheme, Curses};
use getopts::Options;
use std::env;
use orderedvec::OrderedVec;
use item::MatchedItem;

fn main() {
    let exit_code = real_main();
    std::process::exit(exit_code);
}

fn real_main() -> i32 {

    // option parsing

    let mut opts = Options::new();
    opts.optopt("b", "bind", "comma seperated keybindings, such as 'ctrl-j:accept,ctrl-k:kill-line'", "KEY:ACTION");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("m", "multi", "Enable Multiple Selection");
    opts.optopt("p", "prompt", "prompt string", "'> '");
    opts.optopt("e", "expect", "comma seperated keys that can be used to complete fzf", "KEYS");
    opts.optopt("t", "tiebreak", "comma seperated criteria", "[score,index,begin,end,-score,...]");
    opts.optflag("", "ansi", "parse ANSI color codes for input strings");
    opts.optopt("c", "cmd", "command to invoke dynamically", "ag");
    opts.optflag("i", "interactive", "Use skim as an interactive interface");
    opts.optflag("", "regex", "use regex instead of fuzzy match");
    opts.optopt("q", "query", "specify the initial query", "\"\"");
    opts.optopt("d", "delimiter", "specify the delimiter(in REGEX) for fields", "\\t");
    opts.optopt("n", "nth", "specify the fields to be matched", "1,2..5");
    opts.optopt("", "with-nth", "specify the fields to be transformed", "1,2..5");
    opts.optopt("I", "", "replace `replstr` with the selected item", "replstr");
    opts.optflag("", "version", "print out the current version of skim");

    let default_options = match env::var("SKIM_DEFAULT_OPTIONS") {
        Ok(val) => val,
        Err(_) => "".to_string(),
    };

    let mut args = Vec::new();
    for option in default_options.split(" ") {
        args.push(option.to_string());
    }

    let program = env::args().nth(0).unwrap_or("sk".to_string());
    for arg in env::args().skip(1) {
        args.push(arg);
    }

    let options = match opts.parse(args) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    // print help message
    if options.opt_present("h") {
        print_usage(&program, opts);
        return 0;
    }

    // print version
    if options.opt_present("version") {
        println!("0.1.2");
        return 0;
    }

    let theme = ColorTheme::new();
    let curses = Curses::new();
    curses::init(Some(&theme), false, false);

    // register terminal resize event, `pthread_sigmask` should be run before any thread.
    let mut sigset = unsafe {mem::uninitialized()};
    unsafe {
        sigemptyset(&mut sigset);
        sigaddset(&mut sigset, libc::SIGWINCH);
        pthread_sigmask(libc::SIG_SETMASK, &mut sigset, ptr::null_mut());
    }

    // controller variables
    let eb = Arc::new(EventBox::new());
    let item_buffer = Arc::new(RwLock::new(Vec::new()));

    let eb_clone = eb.clone();
    thread::spawn(move || {
        // listen to the resize event;
        loop {
            let mut sig = 0;
            let _errno = unsafe {sigwait(&mut sigset, &mut sig)};
            eb_clone.set(Event::EvResize, Box::new(true));
        }
    });

    // model
    let mut model = Model::new(eb.clone(), curses);
    model.parse_options(&options);

    // matcher
    let items = model.items.clone();
    let mut matcher = Matcher::new(items, item_buffer.clone(), eb.clone());
    let eb_matcher = matcher.eb_req.clone();
    matcher.parse_options(&options);

    // reader
    let default_command = match env::var("SKIM_DEFAULT_COMMAND") {
        Ok(val) => val,
        Err(_) => "find .".to_string(),
    };
    let mut reader = Reader::new(default_command, eb.clone(), item_buffer.clone());
    reader.parse_options(&options);
    let eb_reader = reader.eb_req.clone();

    // input
    let mut input = Input::new(eb.clone());
    input.parse_keymap(options.opt_str("b"));
    input.parse_expect_keys(options.opt_str("e"));

    // start running
    thread::spawn(move || {
        reader.run();
    });

    thread::spawn(move || {
        matcher.run();
    });

    thread::spawn(move || {
        input.run();
    });

    model.print_query(); // to place cursor
    model.refresh();

    let exit_code;

    'outer: loop {
        let mut immediate_refresh = false;
        for (e, val) in eb.wait() {
            match e {
                Event::EvReaderNewItem => {
                    eb_matcher.set(Event::EvMatcherNewItem, Box::new(true));
                    let reading: bool = *val.downcast().unwrap();
                    model.reading = reading;

                    let new_items = item_buffer.read().unwrap();
                    model.update_num_total(new_items.len());
                    model.print_info();
                }

                Event::EvMatcherUpdateProcess => {
                    let percentage: u64 = *val.downcast().unwrap();
                    model.update_percentage(percentage);
                    model.print_info();
                }

                Event::EvMatcherEnd => {
                    // do nothing
                    let result: Arc<RwLock<OrderedVec<MatchedItem>>> = *val.downcast().unwrap();
                    model.update_percentage(100);
                    model.update_matched_items(result);
                    model.display();
                }

                Event::EvQueryChange => {
                    let query: String = *val.downcast().unwrap();

                    if model.is_interactive {
                        model.clear_items();
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(query.clone()));
                        eb.wait_for(Event::EvMatcherSync);
                        eb_reader.set(Event::EvReaderResetQuery, Box::new(query.clone()));
                        eb.wait_for(Event::EvReaderSync);
                        eb_reader.set(Event::EvModelAck, Box::new(true));
                        eb_matcher.set(Event::EvModelAck, Box::new(true));
                        eb.clear();
                        break;
                    } else {
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(query));
                    }
                }

                Event::EvInputInvalid => {
                    // ignore
                }

                Event::EvInputKey => {
                    // ignore for now
                }

                Event::EvResize => {
                    model.resize();
                    model.display();
                    immediate_refresh = true;
                }

                Event::EvActAddChar => {
                    let ch: char = *val.downcast().unwrap();
                    model.act_add_char(ch);
                    model.print_query();
                }

                // Actions
                Event::EvActAbort => {
                    exit_code = 130;
                    break 'outer;
                }

                Event::EvActAccept => {
                    // break out of the loop and output the selected item.
                    //if model.get_num_selected() <= 0 { model.act_toggle(Some(true)); }
                    let args: Option<String> = *val.downcast().unwrap();
                    let num_selected = model.act_accept(args);
                    exit_code = if num_selected > 0 {0} else {1};
                    break 'outer;
                }

                Event::EvActBackwardChar => {
                    model.act_backward_char();
                    model.print_query();
                }

                Event::EvActBackwardDeleteChar => {
                    model.act_backward_delete_char();
                    model.print_query();
                }

                Event::EvActBackwardKillWord => {
                    model.act_backward_kill_word();
                    model.print_query();
                }

                Event::EvActBackwardWord => {
                    model.act_backward_word();
                    model.print_query();
                }

                Event::EvActBeginningOfLine => {
                    model.act_beginning_of_line();
                    model.print_query();
                }

                Event::EvActCancel => {}

                Event::EvActClearScreen => {
                    immediate_refresh = true;
                }

                Event::EvActDeleteChar => {
                    model.act_delete_char();
                    model.print_query();
                }

                Event::EvActDeleteCharEOF => {
                    model.act_delete_char();
                    model.print_query();
                }

                Event::EvActDeselectAll => {
                    model.act_deselect_all();
                    model.print_info();
                    model.print_items();
                }

                Event::EvActDown => {
                    model.act_move_line_cursor(-1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActEndOfLine => {
                    model.act_end_of_line();
                    model.print_query();
                }

                Event::EvActForwardChar => {
                    model.act_forward_char();
                    model.print_query();
                }

                Event::EvActForwardWord => {
                    model.act_forward_word();
                    model.print_query();
                }

                Event::EvActIgnore => {}

                Event::EvActKillLine => {
                    model.act_kill_line();
                    model.print_query();
                }

                Event::EvActKillWord => {
                    model.act_kill_word();
                    model.print_query();
                }

                Event::EvActNextHistory => {}

                Event::EvActPageDown => {
                    model.act_move_page(-1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActPageUp => {
                    model.act_move_page(1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActPreviousHistory => {}

                Event::EvActScrollLeft => {
                    model.act_vertical_scroll(-1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActScrollRight => {
                    model.act_vertical_scroll(1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActSelectAll => {
                    model.act_select_all();
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggle => {
                    model.act_toggle();
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggleAll => {
                    model.act_toggle_all();
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggleDown => {
                    model.act_toggle();
                    model.act_move_line_cursor(-1);
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActToggleIn => {}

                Event::EvActToggleOut => {}

                Event::EvActToggleSort => {}

                Event::EvActToggleUp => {
                    model.act_toggle();
                    model.act_move_line_cursor(1);
                    model.print_info();
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActUnixLineDiscard => {
                    model.act_line_discard();
                    model.print_query();
                }

                Event::EvActUnixWordRubout => {
                    model.act_backward_kill_word();
                    model.print_query();
                }

                Event::EvActUp => {
                    model.act_move_line_cursor(1);
                    model.print_items();
                    immediate_refresh = true;
                }

                Event::EvActYank => {}

                _ => {
                    printw(format!("{}\n", e as i32).as_str());
                }
            }
        }

        if immediate_refresh {
            model.refresh();
        } else {
            model.refresh_throttle();
        }
        thread::sleep(Duration::from_millis(10));
    };

    model.close();
    model.output();
    exit_code
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{self, Command};

#[cfg(unix)]
use std::process::{Child, Stdio};

extern crate isatty;
use isatty::{stderr_isatty, stdout_isatty};

#[cfg(unix)]
extern crate tempfile;

fn main() {
    let result = cargo_expand();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

#[cfg(windows)]
fn cargo_expand() -> io::Result<i32> {
    // Build cargo command
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&wrap_args(env::args_os(), None));
    run(cmd)
}

#[cfg(unix)]
fn cargo_expand() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();
    match args.last().unwrap().to_str().unwrap_or("") {
        "--filter-cargo" => filter_err(ignore_cargo_err),
        "--filter-rustfmt" => filter_err(ignore_rustfmt_err),
        _ => {}
    }

    macro_rules! shell {
        ($($arg:expr)*) => {
            &[$(OsStr::new(&$arg)),*]
        };
    }

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if !color_never(&args) && stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        let mut builder = tempfile::Builder::new();
        builder.prefix("cargo-expand");
        Some(builder.tempdir().expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Build cargo command
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));

    // Pipe to a tmp file to separate out any println output from build scripts
    if let Some(outfile) = outfile {
        let mut filter_cargo = Vec::new();
        filter_cargo.extend(args.iter().map(OsString::as_os_str));
        filter_cargo.push(OsStr::new("--filter-cargo"));

        let _wait = cmd.pipe_to(shell!("cat"), Some(&filter_cargo))?;
        run(cmd)?;
        drop(_wait);

        cmd = Command::new("cat");
        cmd.arg(outfile);
    }

    // Pipe to rustfmt
    let _wait = match which_rustfmt {
        Some(ref fmt) => {
            let args: Vec<_> = env::args_os().collect();
            let mut filter_rustfmt = Vec::new();
            filter_rustfmt.extend(args.iter().map(OsString::as_os_str));
            filter_rustfmt.push(OsStr::new("--filter-rustfmt"));

            Some((
                cmd.pipe_to(shell!(fmt), None)?,
                cmd.pipe_to(shell!("cat"), Some(&filter_rustfmt))?,
            ))
        }
        None => None,
    };

    // Pipe to pygmentize
    let _wait = match which_pygmentize {
        Some(pyg) => Some(cmd.pipe_to(shell!(pyg "-l" "rust" "-O" "encoding=utf8"), None)?),
        None => None,
    };

    run(cmd)
}

fn run(mut cmd: Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap_or(1))
}

#[cfg(unix)]
struct Wait(Vec<Child>);

#[cfg(unix)]
impl Drop for Wait {
    fn drop(&mut self) {
        for child in &mut self.0 {
            if let Err(err) = child.wait() {
                let _ = writeln!(&mut io::stderr(), "{}", err);
            }
        }
    }
}

#[cfg(unix)]
trait PipeTo {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait>;
}

#[cfg(unix)]
impl PipeTo for Command {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait> {
        use std::os::unix::io::{AsRawFd, FromRawFd};

        self.stdout(Stdio::piped());
        if err.is_some() {
            self.stderr(Stdio::piped());
        }

        let child = self.spawn()?;

        *self = Command::new(out[0]);
        self.args(&out[1..]);
        self.stdin(unsafe {
            Stdio::from_raw_fd(child.stdout.as_ref().map(AsRawFd::as_raw_fd).unwrap())
        });

        match err {
            None => Ok(Wait(vec![child])),
            Some(err) => {
                let mut errcmd = Command::new(err[0]);
                errcmd.args(&err[1..]);
                errcmd.stdin(unsafe {
                    Stdio::from_raw_fd(child.stderr.as_ref().map(AsRawFd::as_raw_fd).unwrap())
                });
                errcmd.stdout(Stdio::null());
                errcmd.stderr(Stdio::inherit());
                let spawn = errcmd.spawn()?;
                Ok(Wait(vec![spawn, child]))
            }
        }
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
where
    I: IntoIterator<Item = OsString>,
{
    let mut args = vec!["rustc".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

fn color_never(args: &Vec<OsString>) -> bool {
    args.windows(2).any(|pair| pair[0] == *"--color" && pair[1] == *"never")
        || args.iter().any(|arg| *arg == *"--color=never")
}

#[cfg(unix)]
fn which(cmd: &[&str]) -> Option<OsString> {
    if env::args_os().find(|arg| arg == "--help").is_some() {
        return None;
    }

    if let Some(which) = env::var_os(&cmd[0].to_uppercase()) {
        return if which.is_empty() { None } else { Some(which) };
    }

    let spawn = Command::new(cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn();
    let mut child = match spawn {
        Ok(child) => child,
        Err(_) => {
            return None;
        }
    };

    let exit = match child.wait() {
        Ok(exit) => exit,
        Err(_) => {
            return None;
        }
    };

    if exit.success() {
        Some(cmd[0].into())
    } else {
        None
    }
}

#[cfg(unix)]
fn filter_err(ignore: fn(&str) -> bool) -> ! {
    let mut line = String::new();
    while let Ok(n) = io::stdin().read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    process::exit(0);
}

#[cfg(unix)]
fn ignore_rustfmt_err(_line: &str) -> bool {
    true
}

#[cfg(unix)]
fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag.",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}
<commit_msg>Attempt to find a nightly toolchain<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{self, Command};

#[cfg(unix)]
use std::process::{Child, Stdio};

extern crate isatty;
use isatty::{stderr_isatty, stdout_isatty};

#[cfg(unix)]
extern crate tempfile;

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> io::Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");
    nightly.args(env::args_os().skip(1));

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => if status.success() { 0 } else { 1 },
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

#[cfg(windows)]
fn cargo_expand() -> io::Result<i32> {
    // Build cargo command
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&wrap_args(env::args_os(), None));
    run(cmd)
}

#[cfg(unix)]
fn cargo_expand() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();
    match args.last().unwrap().to_str().unwrap_or("") {
        "--filter-cargo" => filter_err(ignore_cargo_err),
        "--filter-rustfmt" => filter_err(ignore_rustfmt_err),
        _ => {}
    }

    macro_rules! shell {
        ($($arg:expr)*) => {
            &[$(OsStr::new(&$arg)),*]
        };
    }

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if !color_never(&args) && stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        let mut builder = tempfile::Builder::new();
        builder.prefix("cargo-expand");
        Some(builder.tempdir().expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Build cargo command
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));

    // Pipe to a tmp file to separate out any println output from build scripts
    if let Some(outfile) = outfile {
        let mut filter_cargo = Vec::new();
        filter_cargo.extend(args.iter().map(OsString::as_os_str));
        filter_cargo.push(OsStr::new("--filter-cargo"));

        let _wait = cmd.pipe_to(shell!("cat"), Some(&filter_cargo))?;
        run(cmd)?;
        drop(_wait);

        cmd = Command::new("cat");
        cmd.arg(outfile);
    }

    // Pipe to rustfmt
    let _wait = match which_rustfmt {
        Some(ref fmt) => {
            let args: Vec<_> = env::args_os().collect();
            let mut filter_rustfmt = Vec::new();
            filter_rustfmt.extend(args.iter().map(OsString::as_os_str));
            filter_rustfmt.push(OsStr::new("--filter-rustfmt"));

            Some((
                cmd.pipe_to(shell!(fmt), None)?,
                cmd.pipe_to(shell!("cat"), Some(&filter_rustfmt))?,
            ))
        }
        None => None,
    };

    // Pipe to pygmentize
    let _wait = match which_pygmentize {
        Some(pyg) => Some(cmd.pipe_to(shell!(pyg "-l" "rust" "-O" "encoding=utf8"), None)?),
        None => None,
    };

    run(cmd)
}

fn run(mut cmd: Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap_or(1))
}

#[cfg(unix)]
struct Wait(Vec<Child>);

#[cfg(unix)]
impl Drop for Wait {
    fn drop(&mut self) {
        for child in &mut self.0 {
            if let Err(err) = child.wait() {
                let _ = writeln!(&mut io::stderr(), "{}", err);
            }
        }
    }
}

#[cfg(unix)]
trait PipeTo {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait>;
}

#[cfg(unix)]
impl PipeTo for Command {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait> {
        use std::os::unix::io::{AsRawFd, FromRawFd};

        self.stdout(Stdio::piped());
        if err.is_some() {
            self.stderr(Stdio::piped());
        }

        let child = self.spawn()?;

        *self = Command::new(out[0]);
        self.args(&out[1..]);
        self.stdin(unsafe {
            Stdio::from_raw_fd(child.stdout.as_ref().map(AsRawFd::as_raw_fd).unwrap())
        });

        match err {
            None => Ok(Wait(vec![child])),
            Some(err) => {
                let mut errcmd = Command::new(err[0]);
                errcmd.args(&err[1..]);
                errcmd.stdin(unsafe {
                    Stdio::from_raw_fd(child.stderr.as_ref().map(AsRawFd::as_raw_fd).unwrap())
                });
                errcmd.stdout(Stdio::null());
                errcmd.stderr(Stdio::inherit());
                let spawn = errcmd.spawn()?;
                Ok(Wait(vec![spawn, child]))
            }
        }
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
where
    I: IntoIterator<Item = OsString>,
{
    let mut args = vec!["rustc".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

fn color_never(args: &Vec<OsString>) -> bool {
    args.windows(2).any(|pair| pair[0] == *"--color" && pair[1] == *"never")
        || args.iter().any(|arg| *arg == *"--color=never")
}

#[cfg(unix)]
fn which(cmd: &[&str]) -> Option<OsString> {
    if env::args_os().find(|arg| arg == "--help").is_some() {
        return None;
    }

    if let Some(which) = env::var_os(&cmd[0].to_uppercase()) {
        return if which.is_empty() { None } else { Some(which) };
    }

    let spawn = Command::new(cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn();
    let mut child = match spawn {
        Ok(child) => child,
        Err(_) => {
            return None;
        }
    };

    let exit = match child.wait() {
        Ok(exit) => exit,
        Err(_) => {
            return None;
        }
    };

    if exit.success() {
        Some(cmd[0].into())
    } else {
        None
    }
}

#[cfg(unix)]
fn filter_err(ignore: fn(&str) -> bool) -> ! {
    let mut line = String::new();
    while let Ok(n) = io::stdin().read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    process::exit(0);
}

#[cfg(unix)]
fn ignore_rustfmt_err(_line: &str) -> bool {
    true
}

#[cfg(unix)]
fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag.",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}
<|endoftext|>


<commit_before>use std::fs;
use std::io;
use std::path::Path;
use std::collections::BTreeMap;

use handlebars::{Handlebars, no_escape};

const SITE_TITLE: &str = "Grauwoelfchen's Workroom";
const DST_DIR: &str = "./dst";

const LINKS: [(&str, &str); 4] = [
    ("Home", "/"),
    ("About", "/about.html"),
    ("Software", "/software.html"),
    ("Link", "/link.html"),
];

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Parse(handlebars::TemplateError),
    Render(handlebars::RenderError),
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Self::Io(error)
    }
}

impl From<handlebars::TemplateError> for Error {
    fn from(error: handlebars::TemplateError) -> Self {
        Self::Parse(error)
    }
}

impl From<handlebars::RenderError> for Error {
    fn from(error: handlebars::RenderError) -> Self {
        Self::Render(error)
    }
}

fn main() -> Result<(), Error> {
    let mut reg = Handlebars::new();

    let layout = include_str!("./layout.hbs");
    reg.register_template_string("layout", layout)?;
    reg.register_escape_fn(no_escape);

    let dst = Path::new(&DST_DIR);

    // error
    let dat = include_str!("./error.hbs");
    fs::write(dst.join("error.html"), &dat.as_bytes())?;

    // index
    let data = load("Home", include_str!("./index.hbs"));
    let result = reg.render("layout", &data)?;
    fs::write(dst.join("index.html"), result)?;

    // about
    let data = load("About", include_str!("./about.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("about.html"), result)?;

    // software
    let data = load("Software", include_str!("./software.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("software.html"), result)?;

    // link
    let data = load("Link", include_str!("./link.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("link.html"), result)?;

    reg.unregister_escape_fn();

    Ok(())
}

/// Returns built an entry for navigations list.
fn build_nav(heading: &str, link: (&str, &str)) -> String {
    let title = link.0;
    let href = link.1;

    let class = if title == heading {
        " class=\"active\""
    } else {
        ""
    };
    format!(r#"

  {}

"#,
        class,
        href,
        title,
    )
}

fn load(heading: &str, content: &str) -> BTreeMap<String, String> {
    let mut data = BTreeMap::new();

    let mut nav = "".to_string();
    for link in LINKS {
        nav.push_str(&build_nav(heading, link));
    }
    data.insert("navi".to_string(), nav);
    data.insert("content".to_string(), content.to_string());

    // meta
    if heading != "Home" {
        data.insert("page_title".to_string(), heading.to_string());
    }
    data.insert("site_title".to_string(), SITE_TITLE.to_string());
    data
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_build_nav() {
        let active = build_nav("Foo", ("Foo", "/foo.html"));
        assert_eq!(active, r#"

  Foo

"#);

        let inactive = build_nav("Bar", ("Foo", "/foo.html"));
        assert_eq!(inactive, r#"

  Foo

"#);
    }
}
<commit_msg>Fix formats<commit_after>use std::collections::BTreeMap;
use std::fs;
use std::io;
use std::path::Path;

use handlebars::{no_escape, Handlebars};

const SITE_TITLE: &str = "Grauwoelfchen's Workroom";
const DST_DIR: &str = "./dst";

const LINKS: [(&str, &str); 4] = [
    ("Home", "/"),
    ("About", "/about.html"),
    ("Software", "/software.html"),
    ("Link", "/link.html"),
];

#[derive(Debug)]
enum Error {
    Io(io::Error),
    Parse(handlebars::TemplateError),
    Render(handlebars::RenderError),
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Self {
        Self::Io(error)
    }
}

impl From<handlebars::TemplateError> for Error {
    fn from(error: handlebars::TemplateError) -> Self {
        Self::Parse(error)
    }
}

impl From<handlebars::RenderError> for Error {
    fn from(error: handlebars::RenderError) -> Self {
        Self::Render(error)
    }
}

fn main() -> Result<(), Error> {
    let mut reg = Handlebars::new();

    let layout = include_str!("./layout.hbs");
    reg.register_template_string("layout", layout)?;
    reg.register_escape_fn(no_escape);

    let dst = Path::new(&DST_DIR);

    // error
    let dat = include_str!("./error.hbs");
    fs::write(dst.join("error.html"), &dat.as_bytes())?;

    // index
    let data = load("Home", include_str!("./index.hbs"));
    let result = reg.render("layout", &data)?;
    fs::write(dst.join("index.html"), result)?;

    // about
    let data = load("About", include_str!("./about.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("about.html"), result)?;

    // software
    let data = load("Software", include_str!("./software.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("software.html"), result)?;

    // link
    let data = load("Link", include_str!("./link.hbs"));
    let result = reg.render("layout", &data).unwrap();
    fs::write(dst.join("link.html"), result)?;

    reg.unregister_escape_fn();

    Ok(())
}

/// Returns built an entry for navigations list.
fn build_nav(heading: &str, link: (&str, &str)) -> String {
    let title = link.0;
    let href = link.1;

    let class = if title == heading {
        " class=\"active\""
    } else {
        ""
    };
    format!(
        r#"

  {}

"#,
        class, href, title,
    )
}

fn load(heading: &str, content: &str) -> BTreeMap<String, String> {
    let mut data = BTreeMap::new();

    let mut nav = "".to_string();
    for link in LINKS {
        nav.push_str(&build_nav(heading, link));
    }
    data.insert("navi".to_string(), nav);
    data.insert("content".to_string(), content.to_string());

    // meta
    if heading != "Home" {
        data.insert("page_title".to_string(), heading.to_string());
    }
    data.insert("site_title".to_string(), SITE_TITLE.to_string());
    data
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_build_nav() {
        let active = build_nav("Foo", ("Foo", "/foo.html"));
        assert_eq!(
            active,
            r#"

  Foo

"#
        );

        let inactive = build_nav("Bar", ("Foo", "/foo.html"));
        assert_eq!(
            inactive,
            r#"

  Foo

"#
        );
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate cairo;

use gtk::prelude::*;
use gtk::{Builder, ApplicationWindow, HeaderBar, DrawingArea, Statusbar};

use cairo::enums::{FontSlant, FontWeight};
use cairo::Context;

fn draw_something(da: &DrawingArea, cr: &cairo::Context) -> Inhibit {
    let allocation = da.get_allocation();
    cr.scale(allocation.width as f64, allocation.height as f64);

    cr.select_font_face("Sans", FontSlant::Normal, FontWeight::Normal);
    cr.set_font_size(0.07);

    cr.move_to(0.1, 0.53);
    cr.show_text(&format!("{} place holder", da.get_name().unwrap()));

    Inhibit(false)
}

fn display_something(builder: &Builder) {
    let video_area: DrawingArea = builder.get_object("video-drawingarea").unwrap();
    video_area.connect_draw(draw_something);

    let audio_area: DrawingArea = builder.get_object("audio-drawingarea").unwrap();
    audio_area.connect_draw(draw_something);

    let status_bar: Statusbar = builder.get_object("status-bar").unwrap();
    status_bar.push(status_bar.get_context_id("dummy msg"), "Media-TOC prototype");
}

fn main() {
    if gtk::init().is_err() {
        panic!("Failed to initialize GTK.");
    }

    let glade_src = include_str!("media-toc.glade");
    let builder = Builder::new_from_string(glade_src);

    let window: ApplicationWindow = builder.get_object("application-window").unwrap();
    let header_bar: HeaderBar = builder.get_object("header-bar").unwrap();
    window.set_titlebar(&header_bar);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    window.show_all();

    display_something(&builder);

    gtk::main();
}
<commit_msg>Limit glade file content's lifetime (#1)<commit_after>extern crate gtk;
extern crate cairo;

use gtk::prelude::*;
use gtk::{Builder, ApplicationWindow, HeaderBar, DrawingArea, Statusbar};

use cairo::enums::{FontSlant, FontWeight};
use cairo::Context;

fn draw_something(da: &DrawingArea, cr: &cairo::Context) -> Inhibit {
    let allocation = da.get_allocation();
    cr.scale(allocation.width as f64, allocation.height as f64);

    cr.select_font_face("Sans", FontSlant::Normal, FontWeight::Normal);
    cr.set_font_size(0.07);

    cr.move_to(0.1, 0.53);
    cr.show_text(&format!("{} place holder", da.get_name().unwrap()));

    Inhibit(false)
}

fn display_something(builder: &Builder) {
    let video_area: DrawingArea = builder.get_object("video-drawingarea").unwrap();
    video_area.connect_draw(draw_something);

    let audio_area: DrawingArea = builder.get_object("audio-drawingarea").unwrap();
    audio_area.connect_draw(draw_something);

    let status_bar: Statusbar = builder.get_object("status-bar").unwrap();
    status_bar.push(status_bar.get_context_id("dummy msg"), "Media-TOC prototype");
}

fn main() {
    if gtk::init().is_err() {
        panic!("Failed to initialize GTK.");
    }

    let builder = Builder::new_from_string(include_str!("media-toc.glade"));

    let window: ApplicationWindow = builder.get_object("application-window").unwrap();
    let header_bar: HeaderBar = builder.get_object("header-bar").unwrap();
    window.set_titlebar(&header_bar);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    window.show_all();

    display_something(&builder);

    gtk::main();
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate git2;
extern crate yaml_rust;

use backend::Backend;
use cli::cli;
use conf::{Conf,get_configuration,create_default_config,Value,MonitoredRemote};
use constants::*;

use std::collections::HashMap;

use git2::Repository;

// util mod def needs to be first b/c of macro definitions and usage in other modules
#[macro_use]
mod util;
mod backend;
mod cli;
mod conf;
mod constants;

fn format_value(value: Value, data: String) -> String {
    format!("{}{}{}{}", value.pre_format, value.label, data, value.post_format)
}

fn substiute_special_values(s: String, values: &HashMap<String, String>) -> String {
    let mut r:String = s.clone();
    for (k, v) in values {
        r = r.replace(k, &v);
    }
    r
}

// struct for displaying all the data -- the actual program
struct Program {
    out: Vec<String>,
    backend: Backend,
    conf: Conf,
    debug: bool
}

impl Program {
    pub fn new(backend: Backend, conf: Conf, debug: bool) -> Program {
        let out: Vec<String> = Vec::new();
        Program { out: out, backend: backend, conf: conf, debug: debug }
    }

    // add repository state to output buffer
    fn add_repository_state(&mut self) {
        let repo_state = self.backend.get_repository_state();
        if !repo_state.is_empty() {
            self.out.push(repo_state);
        }
    }

    fn add_monitored_branches_state(&mut self) {
        let mut local_branch: String = self.backend.get_current_branch_name();
        let mr = match self.conf.get_remotes_monitoring() {
            Some(x) => x,
            None => return (),
        };
        for monitored_remote in mr {
            let b = match monitored_remote.branch {
                Some(x) => x,
                None => local_branch.clone()
            };
            let (ahead, behind) = match self.backend.get_remote_branch_ahead_behind(&monitored_remote.remote_name, &b) {
                Some(x) => x,
                None => (0, 0),
            };
            if monitored_remote.display_if_uptodate || ahead > 0 || behind > 0 {
                if let (Some(a_v), Some(b_v)) = (
                    self.conf.get_difference_ahead_value(),
                    self.conf.get_difference_behind_value()
                ) {
                    let mut special_values: HashMap<String, String> = HashMap::new();
                    special_values.insert("<BRANCH>".to_string(), b);
                    special_values.insert("<REMOTE>".to_string(), monitored_remote.remote_name);
                    let mut local: String = format!(
                        "{}{}",
                        substiute_special_values(monitored_remote.pre_format, &special_values),
                        substiute_special_values(monitored_remote.post_format, &special_values),
                    );
                    if ahead > 0 {
                        local += &format_value(a_v, ahead.to_string());
                    }
                    if behind > 0 {
                        local += &format_value(b_v, behind.to_string());
                    }
                    self.out.push(local);
                }
            }
        }
    }

    fn add_file_status(&mut self) {
        if let Some(s) = self.backend.get_file_status() {
            if !s.is_empty() {
                let mut o = String::from("");

                if let Some(x) = s.get(NEW_KEY) {
                    match self.conf.get_new_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CHANGED_KEY) {
                    match self.conf.get_changed_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(STAGED_KEY) {
                    match self.conf.get_staged_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CONFLICTS_KEY) {
                    match self.conf.get_conflicts_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                self.out.push(o);
            }
        }
    }

    fn populate(&mut self) {
        self.add_repository_state();
        self.add_monitored_branches_state();
        self.add_file_status();
    }

    // print output buffer
    fn output(&self) {
        log!(self, "# of blocks = {}", self.out.len());
        println!("{}", self.out.join("|"));
    }
}

fn main() {
    let app = cli();
    let matches = app.get_matches();

    let debug_enabled = matches.is_present("debug");
    if debug_enabled { println!("Debug messages are enabled."); }

    // FIXME: doesn't work when there is no .git inside .
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        // not a git repository, ignore
        Err(e) => {
            if debug_enabled { println!("This is not a git repository: {:?}", e); }
            return ();
        }
    };

    let mut conf_path: Option<String> = None;
    if matches.is_present("config") {
        conf_path = Some(String::from(matches.value_of("config").unwrap()));
    }

    let conf = get_configuration(conf_path);

    if matches.is_present(CLI_DEFAULT_CONFIG_SUBC_NAME) {
        let p = get_default_config_path();
        match create_default_config(p.clone()) {
            Ok(path) => {
                println!("Configuration file created at \"{}\"", path);
                return ();
            }
            Err(e) => {
                println!("Failed to create configuration file \"{}\": {}", p.to_str().unwrap(), e);
                return ();
            }
        };
    }

    let backend = Backend{ repo: repo, debug: debug_enabled };
    let mut output = Program::new(backend, conf, debug_enabled);

    output.populate();
    output.output();
}
<commit_msg>search for .git in parent dirs<commit_after>extern crate clap;
extern crate git2;
extern crate yaml_rust;

use backend::Backend;
use cli::cli;
use conf::{Conf,get_configuration,create_default_config,Value,MonitoredRemote};
use constants::*;

use std::collections::HashMap;

use git2::Repository;

// util mod def needs to be first b/c of macro definitions and usage in other modules
#[macro_use]
mod util;
mod backend;
mod cli;
mod conf;
mod constants;

fn format_value(value: Value, data: String) -> String {
    format!("{}{}{}{}", value.pre_format, value.label, data, value.post_format)
}

fn substiute_special_values(s: String, values: &HashMap<String, String>) -> String {
    let mut r:String = s.clone();
    for (k, v) in values {
        r = r.replace(k, &v);
    }
    r
}

// struct for displaying all the data -- the actual program
struct Program {
    out: Vec<String>,
    backend: Backend,
    conf: Conf,
    debug: bool
}

impl Program {
    pub fn new(backend: Backend, conf: Conf, debug: bool) -> Program {
        let out: Vec<String> = Vec::new();
        Program { out: out, backend: backend, conf: conf, debug: debug }
    }

    // add repository state to output buffer
    fn add_repository_state(&mut self) {
        let repo_state = self.backend.get_repository_state();
        if !repo_state.is_empty() {
            self.out.push(repo_state);
        }
    }

    fn add_monitored_branches_state(&mut self) {
        let mut local_branch: String = self.backend.get_current_branch_name();
        let mr = match self.conf.get_remotes_monitoring() {
            Some(x) => x,
            None => return (),
        };
        for monitored_remote in mr {
            let b = match monitored_remote.branch {
                Some(x) => x,
                None => local_branch.clone()
            };
            let (ahead, behind) = match self.backend.get_remote_branch_ahead_behind(&monitored_remote.remote_name, &b) {
                Some(x) => x,
                None => (0, 0),
            };
            if monitored_remote.display_if_uptodate || ahead > 0 || behind > 0 {
                if let (Some(a_v), Some(b_v)) = (
                    self.conf.get_difference_ahead_value(),
                    self.conf.get_difference_behind_value()
                ) {
                    let mut special_values: HashMap<String, String> = HashMap::new();
                    special_values.insert("<BRANCH>".to_string(), b);
                    special_values.insert("<REMOTE>".to_string(), monitored_remote.remote_name);
                    let mut local: String = format!(
                        "{}{}",
                        substiute_special_values(monitored_remote.pre_format, &special_values),
                        substiute_special_values(monitored_remote.post_format, &special_values),
                    );
                    if ahead > 0 {
                        local += &format_value(a_v, ahead.to_string());
                    }
                    if behind > 0 {
                        local += &format_value(b_v, behind.to_string());
                    }
                    self.out.push(local);
                }
            }
        }
    }

    fn add_file_status(&mut self) {
        if let Some(s) = self.backend.get_file_status() {
            if !s.is_empty() {
                let mut o = String::from("");

                if let Some(x) = s.get(NEW_KEY) {
                    match self.conf.get_new_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CHANGED_KEY) {
                    match self.conf.get_changed_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(STAGED_KEY) {
                    match self.conf.get_staged_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CONFLICTS_KEY) {
                    match self.conf.get_conflicts_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                self.out.push(o);
            }
        }
    }

    fn populate(&mut self) {
        self.add_repository_state();
        self.add_monitored_branches_state();
        self.add_file_status();
    }

    // print output buffer
    fn output(&self) {
        log!(self, "# of blocks = {}", self.out.len());
        println!("{}", self.out.join("|"));
    }
}

fn main() {
    let app = cli();
    let matches = app.get_matches();

    let debug_enabled = matches.is_present("debug");
    if debug_enabled { println!("Debug messages are enabled."); }

    let repo = match Repository::discover(".") {
        Ok(repo) => repo,
        // not a git repository, ignore
        Err(e) => {
            if debug_enabled { println!("This is not a git repository: {:?}", e); }
            return ();
        }
    };

    let mut conf_path: Option<String> = None;
    if matches.is_present("config") {
        conf_path = Some(String::from(matches.value_of("config").unwrap()));
    }

    let conf = get_configuration(conf_path);

    if matches.is_present(CLI_DEFAULT_CONFIG_SUBC_NAME) {
        let p = get_default_config_path();
        match create_default_config(p.clone()) {
            Ok(path) => {
                println!("Configuration file created at \"{}\"", path);
                return ();
            }
            Err(e) => {
                println!("Failed to create configuration file \"{}\": {}", p.to_str().unwrap(), e);
                return ();
            }
        };
    }

    let backend = Backend{ repo: repo, debug: debug_enabled };
    let mut output = Program::new(backend, conf, debug_enabled);

    output.populate();
    output.output();
}
<|endoftext|>


<commit_before>#![feature(globs, macro_rules, phase)]

extern crate debug;
extern crate piston;
extern crate sdl2;
extern crate sdl2_game_window;
extern crate gfx;
extern crate device;
extern crate render;
#[phase(plugin)]
extern crate gfx_macros;
extern crate image;
extern crate libc;
extern crate cgmath;
extern crate time;

extern crate flate;
extern crate native;
extern crate rustrt;
extern crate serialize;

use sdl2_game_window::GameWindowSDL2 as Window;
use piston::input;
use piston::cam;
use piston::vecmath::{vec3_add, vec3_scale, vec3_normalized};
use piston::{
    AssetStore,
    GameIterator,
    GameIteratorSettings,
    GameWindow,
    GameWindowSettings,
    Input,
    Render,
    Update
};

use array::*;

use std::cmp::max;
use std::f32::INFINITY;
use std::f32::consts::PI;
use std::io::fs::File;

pub mod array;
pub mod chunk;
pub mod cube;
pub mod shader;
pub mod texture;

pub mod minecraft {
    pub use self::data_1_8_pre2 as data;

    mod data_1_8_pre2;
    pub mod biome;
    pub mod block_state;
    pub mod model;
    pub mod nbt;
    pub mod region;
}

fn main() {
    let world = Path::new(std::os::args().as_slice().get(1).expect("Usage: ./hematite <path/to/world>").as_slice());

    let level = minecraft::nbt::Nbt::from_gzip(File::open(&world.join("level.dat")).read_to_end().unwrap().as_slice()).unwrap();
    println!("{}", level);
    let player_pos: [f32, ..3] = Array::from_iter(level["Data"]["Player"]["Pos"].as_double_list().unwrap().iter().map(|&x| x as f32));
    let player_chunk = [player_pos.x(), player_pos.z()].map(|x| (x / 16.0).floor() as i32);
    let player_rot = level["Data"]["Player"]["Rotation"].as_float_list().unwrap();
    let player_yaw = player_rot[0];
    let player_pitch = player_rot[1];

    let [region_x, region_z] = player_chunk.map(|x| x >> 5);
    let region_file = world.join(format!("region/r.{}.{}.mca", region_x, region_z));
    let region = minecraft::region::Region::open(&region_file);

    let mut window = Window::new(
        piston::shader_version::opengl::OpenGL_3_3,
        GameWindowSettings {
            title: format!("Hematite - {}", world.display()),
            size: [854, 480],
            fullscreen: false,
            exit_on_esc: true,
        }
    );
    let (mut device, frame) = window.gfx();

    let assets = &AssetStore::from_folder("../assets");

    // Load biomes.
    let biomes = minecraft::biome::Biomes::load(assets);

    // Load block state definitions and models.
    let block_states = minecraft::block_state::BlockStates::load(assets, &mut device);

    let mut renderer = shader::Renderer::new(device, frame, block_states.texture().tex);

    let mut chunk_manager = chunk::ChunkManager::new();

    println!("Started loading chunks...");
    let [cx_base, cz_base] = player_chunk.map(|x| max(0, (x & 0x1f) - 8) as u8);
    for cz in range(cz_base, cz_base + 16) {
        for cx in range(cx_base, cx_base + 16) {
            match region.get_chunk_column(cx, cz) {
                Some(column) => {
                    let [cx, cz] = [cx as i32 + region_x * 32, cz as i32 + region_z * 32];
                    chunk_manager.add_chunk_column(cx, cz, column)
                }
                None => {}
            }
        }
    }
    println!("Finished loading chunks.");

    let projection_mat = cam::CameraPerspective {
        fov: 70.0,
        near_clip: 0.1,
        far_clip: 1000.0,
        aspect_ratio: {
            let (w, h) = window.get_size();
            (w as f32) / (h as f32)
        }
    }.projection();
    renderer.set_projection(projection_mat);

    let mut first_person_settings = cam::FirstPersonSettings::keyboard_wasd();
    first_person_settings.speed_horizontal = 8.0;
    first_person_settings.speed_vertical = 4.0;
    let mut first_person = cam::FirstPerson::new(
        player_pos,
        first_person_settings
    );
    first_person.yaw = PI - player_yaw / 180.0 * PI;
    first_person.pitch = player_pitch / 180.0 * PI;

    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 120,
        max_frames_per_second: 10000
    };

    // Disable V-Sync.
    sdl2::video::gl_set_swap_interval(0);

    let mut fps_counter = piston::FPSCounter::new();

    let mut pending_chunks = vec![];
    chunk_manager.each_chunk_and_neighbors(|coords, buffer, chunks, column_biomes| {
        pending_chunks.push((coords, buffer, chunks, column_biomes));
    });

    let mut capture_cursor = false;
    println!("Press C to capture mouse");

    let mut staging_buffer = vec![];
    let mut last_render = time::precise_time_ns();
    let mut events = GameIterator::new(&mut window, &game_iter_settings);
    for e in events {
        match e {
            Render(_) => {
                // Update camera.
                let now = time::precise_time_ns();
                let dt = (now - last_render) as f64 / 1_000_000_000.0f64;
                first_person.update(dt);
                last_render = now;

                // Apply the same y/z camera offset vanilla minecraft has.
                let mut camera = first_person.camera(0.0);
                camera.position[1] += 1.62;
                let mut xz_forward = camera.forward;
                xz_forward[1] = 0.0;
                xz_forward = vec3_normalized(xz_forward);
                camera.position = vec3_add(camera.position, vec3_scale(xz_forward, 0.1));

                let view_mat = camera.orthogonal();
                renderer.set_view(view_mat);
                renderer.clear();
                let mut num_chunks = 0u;
                let mut num_total_chunks = 0u;
                chunk_manager.each_chunk(|cx, cy, cz, _, buffer| {
                    match buffer {
                        Some(buffer) => {
                            num_total_chunks += 1;

                            let inf = INFINITY;
                            let mut bb_min = [inf, inf, inf];
                            let mut bb_max = [-inf, -inf, -inf];
                            let xyz = [cx, cy, cz].map(|x| x as f32 * 16.0);
                            for &dx in [0.0, 16.0].iter() {
                                for &dy in [0.0, 16.0].iter() {
                                    for &dz in [0.0, 16.0].iter() {
                                        use piston::vecmath::col_mat4_transform;
                                        let [x, y, z] = vec3_add(xyz, [dx, dy, dz]);
                                        let xyzw = col_mat4_transform(view_mat, [x, y, z, 1.0]);
                                        let [x, y, z, w] = col_mat4_transform(projection_mat, xyzw);
                                        let xyz = vec3_scale([x, y, z], 1.0 / w);
                                        bb_min = Array::from_fn(|i| bb_min[i].min(xyz[i]));
                                        bb_max = Array::from_fn(|i| bb_max[i].max(xyz[i]));
                                    }
                                }
                            }

                            let cull_bits: [bool, ..3] = Array::from_fn(|i| {
                                let (min, max) = (bb_min[i], bb_max[i]);
                                min.signum() == max.signum() && min.abs().min(max.abs()) >= 1.0
                            });

                            if !cull_bits.iter().any(|&cull| cull) {
                                renderer.render(buffer);
                                num_chunks += 1;
                            }
                        }
                        None => {}
                    }
                });
                renderer.end_frame();

                let fps = fps_counter.tick();
                let title = format!("Hematite w/ {}/{}C @ {}FPS - {}",
                                    num_chunks, num_total_chunks, fps, world.display());
                events.game_window.window.set_title(title.as_slice());
            }
            Update(_) => {
                // HACK(eddyb) find the closest chunk to the player.
                // The pending vector should be sorted instead.
                let closest = pending_chunks.iter().enumerate().min_by(|&(_, &([cx, cy, cz], _, _, _))| {
                    let [px, py, pz] = first_person.position.map(|x| (x / 16.0).floor() as i32);
                    let [x2, y2, z2] = [cx - px, cy - py, cz - pz].map(|x| x * x);
                    x2 + y2 + z2
                }).map(|(i, _)| i);

                let pending = closest.and_then(|i| pending_chunks.swap_remove(i));
                match pending {
                    Some((coords, buffer, chunks, column_biomes)) => {
                        match buffer.get() {
                            Some(buffer) => renderer.delete_buffer(buffer),
                            None => {}
                        }
                        minecraft::block_state::fill_buffer(&block_states, &biomes,
                                                            &mut staging_buffer,
                                                            coords, chunks,
                                                            column_biomes);
                        buffer.set(Some(renderer.create_buffer(staging_buffer.as_slice())));
                        staging_buffer.clear();

                        if pending_chunks.is_empty() {
                            println!("Finished filling chunk vertex buffers.");
                        }
                    }
                    None => {}
                }
            }
            Input(input::Press(input::Keyboard(input::keyboard::C))) => {
                println!("Turned cursor capture {}",
                    if capture_cursor { "off" } else { "on" });
                capture_cursor = !capture_cursor;

                events.game_window.capture_cursor(capture_cursor);
            }
            Input(input::Move(input::MouseRelative(_, _))) => {
                if !capture_cursor {
                    // Don't send the mouse event to the FPS controller.
                    continue;
                }
            }
            _ => {}
        }

        // Camera controller.
        match e {
            Input(ref args) => first_person.input(args),
            _ => {}
        }
    }
}
<commit_msg>Display more debug information in the title, including timings.<commit_after>#![feature(globs, macro_rules, phase)]

extern crate debug;
extern crate piston;
extern crate sdl2;
extern crate sdl2_game_window;
extern crate gfx;
extern crate device;
extern crate render;
#[phase(plugin)]
extern crate gfx_macros;
extern crate image;
extern crate libc;
extern crate cgmath;
extern crate time;

extern crate flate;
extern crate native;
extern crate rustrt;
extern crate serialize;

use sdl2_game_window::GameWindowSDL2 as Window;
use piston::input;
use piston::cam;
use piston::vecmath::{vec3_add, vec3_scale, vec3_normalized};
use piston::{
    AssetStore,
    GameIterator,
    GameIteratorSettings,
    GameWindow,
    GameWindowSettings,
    Input,
    Render,
    Update
};

use array::*;

use std::cmp::max;
use std::f32::INFINITY;
use std::f32::consts::PI;
use std::io::fs::File;

pub mod array;
pub mod chunk;
pub mod cube;
pub mod shader;
pub mod texture;

pub mod minecraft {
    pub use self::data_1_8_pre2 as data;

    mod data_1_8_pre2;
    pub mod biome;
    pub mod block_state;
    pub mod model;
    pub mod nbt;
    pub mod region;
}

fn main() {
    let world = Path::new(std::os::args().as_slice().get(1).expect("Usage: ./hematite <path/to/world>").as_slice());

    let level = minecraft::nbt::Nbt::from_gzip(File::open(&world.join("level.dat")).read_to_end().unwrap().as_slice()).unwrap();
    println!("{}", level);
    let player_pos: [f32, ..3] = Array::from_iter(level["Data"]["Player"]["Pos"].as_double_list().unwrap().iter().map(|&x| x as f32));
    let player_chunk = [player_pos.x(), player_pos.z()].map(|x| (x / 16.0).floor() as i32);
    let player_rot = level["Data"]["Player"]["Rotation"].as_float_list().unwrap();
    let player_yaw = player_rot[0];
    let player_pitch = player_rot[1];

    let [region_x, region_z] = player_chunk.map(|x| x >> 5);
    let region_file = world.join(format!("region/r.{}.{}.mca", region_x, region_z));
    let region = minecraft::region::Region::open(&region_file);

    let mut window = Window::new(
        piston::shader_version::opengl::OpenGL_3_3,
        GameWindowSettings {
            title: format!("Hematite loading... - {}", world.filename_display()),
            size: [854, 480],
            fullscreen: false,
            exit_on_esc: true,
        }
    );
    let (mut device, frame) = window.gfx();

    let assets = &AssetStore::from_folder("../assets");

    // Load biomes.
    let biomes = minecraft::biome::Biomes::load(assets);

    // Load block state definitions and models.
    let block_states = minecraft::block_state::BlockStates::load(assets, &mut device);

    let mut renderer = shader::Renderer::new(device, frame, block_states.texture().tex);

    let mut chunk_manager = chunk::ChunkManager::new();

    println!("Started loading chunks...");
    let [cx_base, cz_base] = player_chunk.map(|x| max(0, (x & 0x1f) - 8) as u8);
    for cz in range(cz_base, cz_base + 16) {
        for cx in range(cx_base, cx_base + 16) {
            match region.get_chunk_column(cx, cz) {
                Some(column) => {
                    let [cx, cz] = [cx as i32 + region_x * 32, cz as i32 + region_z * 32];
                    chunk_manager.add_chunk_column(cx, cz, column)
                }
                None => {}
            }
        }
    }
    println!("Finished loading chunks.");

    let projection_mat = cam::CameraPerspective {
        fov: 70.0,
        near_clip: 0.1,
        far_clip: 1000.0,
        aspect_ratio: {
            let (w, h) = window.get_size();
            (w as f32) / (h as f32)
        }
    }.projection();
    renderer.set_projection(projection_mat);

    let mut first_person_settings = cam::FirstPersonSettings::keyboard_wasd();
    first_person_settings.speed_horizontal = 8.0;
    first_person_settings.speed_vertical = 4.0;
    let mut first_person = cam::FirstPerson::new(
        player_pos,
        first_person_settings
    );
    first_person.yaw = PI - player_yaw / 180.0 * PI;
    first_person.pitch = player_pitch / 180.0 * PI;

    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 120,
        max_frames_per_second: 10000
    };

    // Disable V-Sync.
    sdl2::video::gl_set_swap_interval(0);

    let mut fps_counter = piston::FPSCounter::new();

    let mut pending_chunks = vec![];
    chunk_manager.each_chunk_and_neighbors(|coords, buffer, chunks, column_biomes| {
        pending_chunks.push((coords, buffer, chunks, column_biomes));
    });

    let mut capture_cursor = false;
    println!("Press C to capture mouse");

    let mut staging_buffer = vec![];
    let mut last_render = time::precise_time_ns();
    let mut events = GameIterator::new(&mut window, &game_iter_settings);
    for e in events {
        match e {
            Render(_) => {
                // Update camera.
                let now = time::precise_time_ns();
                let dt = (now - last_render) as f64 / 1_000_000_000.0f64;
                first_person.update(dt);
                last_render = now;

                // Apply the same y/z camera offset vanilla minecraft has.
                let mut camera = first_person.camera(0.0);
                camera.position[1] += 1.62;
                let mut xz_forward = camera.forward;
                xz_forward[1] = 0.0;
                xz_forward = vec3_normalized(xz_forward);
                camera.position = vec3_add(camera.position, vec3_scale(xz_forward, 0.1));

                let view_mat = camera.orthogonal();
                renderer.set_view(view_mat);
                renderer.clear();
                let mut num_chunks = 0u;
                let mut num_sorted_chunks = 0u;
                let mut num_total_chunks = 0u;
                let start_time = time::precise_time_ns();
                chunk_manager.each_chunk(|cx, cy, cz, _, buffer| {
                    match buffer {
                        Some(buffer) => {
                            num_total_chunks += 1;

                            let inf = INFINITY;
                            let mut bb_min = [inf, inf, inf];
                            let mut bb_max = [-inf, -inf, -inf];
                            let xyz = [cx, cy, cz].map(|x| x as f32 * 16.0);
                            for &dx in [0.0, 16.0].iter() {
                                for &dy in [0.0, 16.0].iter() {
                                    for &dz in [0.0, 16.0].iter() {
                                        use piston::vecmath::col_mat4_transform;
                                        let [x, y, z] = vec3_add(xyz, [dx, dy, dz]);
                                        let xyzw = col_mat4_transform(view_mat, [x, y, z, 1.0]);
                                        let [x, y, z, w] = col_mat4_transform(projection_mat, xyzw);
                                        let xyz = vec3_scale([x, y, z], 1.0 / w);
                                        bb_min = Array::from_fn(|i| bb_min[i].min(xyz[i]));
                                        bb_max = Array::from_fn(|i| bb_max[i].max(xyz[i]));
                                    }
                                }
                            }

                            let cull_bits: [bool, ..3] = Array::from_fn(|i| {
                                let (min, max) = (bb_min[i], bb_max[i]);
                                min.signum() == max.signum() && min.abs().min(max.abs()) >= 1.0
                            });

                            if !cull_bits.iter().any(|&cull| cull) {
                                renderer.render(buffer);
                                num_chunks += 1;

                                if bb_min[0] < 0.0 && bb_max[0] > 0.0 || bb_min[1] < 0.0 && bb_max[1] > 0.0 {
                                    num_sorted_chunks += 1;
                                }
                            }
                        }
                        None => {}
                    }
                });
                let end_time = time::precise_time_ns();
                renderer.end_frame();
                let frame_end_time = time::precise_time_ns();

                let fps = fps_counter.tick();
                let title = format!("Hematite sort={} render={} total={} in {:.2}ms+{:.2}ms @ {}FPS - {}",
                                    num_sorted_chunks, num_chunks, num_total_chunks,
                                    (end_time - start_time) as f64 / 1e6,
                                    (frame_end_time - end_time) as f64 / 1e6,
                                    fps, world.filename_display());
                events.game_window.window.set_title(title.as_slice());
            }
            Update(_) => {
                // HACK(eddyb) find the closest chunk to the player.
                // The pending vector should be sorted instead.
                let closest = pending_chunks.iter().enumerate().min_by(|&(_, &([cx, cy, cz], _, _, _))| {
                    let [px, py, pz] = first_person.position.map(|x| (x / 16.0).floor() as i32);
                    let [x2, y2, z2] = [cx - px, cy - py, cz - pz].map(|x| x * x);
                    x2 + y2 + z2
                }).map(|(i, _)| i);

                let pending = closest.and_then(|i| pending_chunks.swap_remove(i));
                match pending {
                    Some((coords, buffer, chunks, column_biomes)) => {
                        match buffer.get() {
                            Some(buffer) => renderer.delete_buffer(buffer),
                            None => {}
                        }
                        minecraft::block_state::fill_buffer(&block_states, &biomes,
                                                            &mut staging_buffer,
                                                            coords, chunks,
                                                            column_biomes);
                        buffer.set(Some(renderer.create_buffer(staging_buffer.as_slice())));
                        staging_buffer.clear();

                        if pending_chunks.is_empty() {
                            println!("Finished filling chunk vertex buffers.");
                        }
                    }
                    None => {}
                }
            }
            Input(input::Press(input::Keyboard(input::keyboard::C))) => {
                println!("Turned cursor capture {}",
                    if capture_cursor { "off" } else { "on" });
                capture_cursor = !capture_cursor;

                events.game_window.capture_cursor(capture_cursor);
            }
            Input(input::Move(input::MouseRelative(_, _))) => {
                if !capture_cursor {
                    // Don't send the mouse event to the FPS controller.
                    continue;
                }
            }
            _ => {}
        }

        // Camera controller.
        match e {
            Input(ref args) => first_person.input(args),
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate gsdmm;

use gsdmm::GSDMM;
use docopt::Docopt;
use std::io::{BufRead,BufReader};
use std::fs::File;
use std::collections::HashSet;
use std::io::Write;

const USAGE: &'static str ="
Gibbs sampling algorithm for a Dirichlet Mixture Model of Yin and Wang 2014.

Usage:
  gsdmm <datafile> <vocabfile> <outprefix> [-k <max_clusters>] [-a <alpha>] [-b <beta>] [-m <maxit>]
  gsdmm (-h | --help)
  gsdmm --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  -k=<K>                Upper bound on the number of possible clusters. [default: 8]
  -a --alpha=<alpha>    Alpha controls the probability that a student will join a table that is currently empty
                        When alpha is 0, no one will join an empty table. [default: 0.1]
  -b --beta=<beta>      Beta controls the student's affinity for other students with similar interests. A low beta means
                        that students desire to sit with students of similar interests. A high beta means they are less
                        concerned with affinity and are more influenced by the popularity of a table. [default: 0.1]
  -m --maxit=<m>        Maximum number of iterations. [default: 30]

";

#[derive(Debug, RustcDecodable)]
struct Args {
    //    flag_mode: isize,
    arg_datafile: String,
    arg_vocabfile: String,
    arg_outprefix: String,
    flag_k: usize,
    flag_alpha: f64,
    flag_beta: f64,
    flag_maxit: isize
}

fn main() {

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

    // get the data and vocabulary
    let vocab:HashSet<String> = lines_from_file(&args.arg_vocabfile).into_iter().collect();
    let docs:Vec<Vec<String>> = lines_from_file(&args.arg_datafile).into_iter().map(|line| {
        let mut term_vector = line.to_owned()
            .split_whitespace()
            .map(|s| s.to_owned())
            .filter(|s| (&vocab).contains(s))
            .collect::<Vec<String>>();

        // sort and dedupe: this implementation requires binary term counts
        term_vector.sort();
        term_vector.dedup();
        term_vector
    }).collect::<Vec<Vec<String>>>();

    let mut model = GSDMM::new(args.flag_alpha, args.flag_beta, args.flag_k, args.flag_maxit, vocab, docs);
    model.fit();

    // write the labels
    {
        let fname = (&args.arg_outprefix).clone() + "labels.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        let mut scored = Vec::<(String,String)>::new();

        // zip with the input data so we get clustered, raw input documents in the output set
        for (doc,txt) in (&model.doc_vectors).iter().zip(lines_from_file(&args.arg_datafile).iter()) {
            let p = model.score( & doc);
            let mut row = p.iter().enumerate().collect::<Vec<_>>();
            if row_has_nan(&row, txt) {
                scored.push(("-1".to_string(), "0".to_string()));
            } else {
                row.sort_by(|a, b| (a.1.partial_cmp(b.1)).unwrap());
                let line = row.pop().unwrap();
                scored.push((line.0.to_string(), line.1.to_string()));
            }
        }
        scored.sort();
        for (label, score) in scored {
            let _ = f.write((label + "," + &score + "\n").as_bytes());
        }
    }

    // write the cluster descriptions
    {
        let fname = (&args.arg_outprefix).clone() + "cluster_descriptions.txt";
        let error_msg = format!("Could not write file {}!", fname);
        let mut f = File::create(fname).expect(&error_msg);
        for k in 0..args.flag_k {
            let ref word_dist = model.cluster_word_distributions[k];
            let mut line = k.to_string() + " ";
            let mut dist_counts:Vec<String> = word_dist.iter().map(|(a,b)| model.index_word_map.get(a).unwrap().to_string() + ":" + &b.clone().to_string() ).collect();
            dist_counts.sort();
            line += &dist_counts.join(" ");
            let _ = f.write((line+"\n").as_bytes());
        }
    }

    fn lines_from_file(filename: &str) -> Vec<String>
    {
        let error_msg = format!("Could not read file {}!", filename);
        let file = File::open(filename).expect(&error_msg);
        let buf = BufReader::new(file);
        buf.lines().map(|l| l.expect("Could not parse line!")).collect()
    }

    fn row_has_nan(row:&Vec<(usize, &f64)>, doc:&String) -> bool {
        for entry in row {
            if entry.1.is_nan() {
                println!("Cluster: {:?} has NaN score for document {:?}", entry, doc);
                return true
            }
        }
        return false;
    }
}
<commit_msg>Removed sort call in main -- no idea why it was there<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate gsdmm;

use gsdmm::GSDMM;
use docopt::Docopt;
use std::io::{BufRead,BufReader};
use std::fs::File;
use std::collections::HashSet;
use std::io::Write;

const USAGE: &'static str ="
Gibbs sampling algorithm for a Dirichlet Mixture Model of Yin and Wang 2014.

Usage:
  gsdmm <datafile> <vocabfile> <outprefix> [-k <max_clusters>] [-a <alpha>] [-b <beta>] [-m <maxit>]
  gsdmm (-h | --help)
  gsdmm --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  -k=<K>                Upper bound on the number of possible clusters. [default: 8]
  -a --alpha=<alpha>    Alpha controls the probability that a student will join a table that is currently empty
                        When alpha is 0, no one will join an empty table. [default: 0.1]
  -b --beta=<beta>      Beta controls the student's affinity for other students with similar interests. A low beta means
                        that students desire to sit with students of similar interests. A high beta means they are less
                        concerned with affinity and are more influenced by the popularity of a table. [default: 0.1]
  -m --maxit=<m>        Maximum number of iterations. [default: 30]

";

#[derive(Debug, RustcDecodable)]
struct Args {
    //    flag_mode: isize,
    arg_datafile: String,
    arg_vocabfile: String,
    arg_outprefix: String,
    flag_k: usize,
    flag_alpha: f64,
    flag_beta: f64,
    flag_maxit: isize
}

fn main() {

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

    // get the data and vocabulary
    let vocab:HashSet<String> = lines_from_file(&args.arg_vocabfile).into_iter().collect();
    let docs:Vec<Vec<String>> = lines_from_file(&args.arg_datafile).into_iter().map(|line| {
        let mut term_vector = line.to_owned()
            .split_whitespace()
            .map(|s| s.to_owned())
            .filter(|s| (&vocab).contains(s))
            .collect::<Vec<String>>();

        // sort and dedupe: this implementation requires binary term counts
        term_vector.sort();
        term_vector.dedup();
        term_vector
    }).collect::<Vec<Vec<String>>>();

    let mut model = GSDMM::new(args.flag_alpha, args.flag_beta, args.flag_k, args.flag_maxit, vocab, docs);
    model.fit();

    // write the labels
    {
        let fname = (&args.arg_outprefix).clone() + "labels.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        let mut scored = Vec::<(String,String)>::new();

        // zip with the input data so we get clustered, raw input documents in the output set
        for (doc,txt) in (&model.doc_vectors).iter().zip(lines_from_file(&args.arg_datafile).iter()) {
            let p = model.score( & doc);
            let mut row = p.iter().enumerate().collect::<Vec<_>>();
            if row_has_nan(&row, txt) {
                scored.push(("-1".to_string(), "0".to_string()));
            } else {
                row.sort_by(|a, b| (a.1.partial_cmp(b.1)).unwrap());
                let line = row.pop().unwrap();
                scored.push((line.0.to_string(), line.1.to_string()));
            }
        }

        for (label, score) in scored {
            let _ = f.write((label + "," + &score + "\n").as_bytes());
        }
    }

    // write the cluster descriptions
    {
        let fname = (&args.arg_outprefix).clone() + "cluster_descriptions.txt";
        let error_msg = format!("Could not write file {}!", fname);
        let mut f = File::create(fname).expect(&error_msg);
        for k in 0..args.flag_k {
            let ref word_dist = model.cluster_word_distributions[k];
            let mut line = k.to_string() + " ";
            let mut dist_counts:Vec<String> = word_dist.iter().map(|(a,b)| model.index_word_map.get(a).unwrap().to_string() + ":" + &b.clone().to_string() ).collect();
            dist_counts.sort();
            line += &dist_counts.join(" ");
            let _ = f.write((line+"\n").as_bytes());
        }
    }

    fn lines_from_file(filename: &str) -> Vec<String>
    {
        let error_msg = format!("Could not read file {}!", filename);
        let file = File::open(filename).expect(&error_msg);
        let buf = BufReader::new(file);
        buf.lines().map(|l| l.expect("Could not parse line!")).collect()
    }

    fn row_has_nan(row:&Vec<(usize, &f64)>, doc:&String) -> bool {
        for entry in row {
            if entry.1.is_nan() {
                println!("Cluster: {:?} has NaN score for document {:?}", entry, doc);
                return true
            }
        }
        return false;
    }
}
<|endoftext|>