<commit_before>extern crate hkg;
extern crate termion;
extern crate rustc_serialize;
extern crate kuchiki;
extern crate chrono;
extern crate hyper;
extern crate cancellation;
extern crate time;
extern crate url;

use std::io::{stdout, stdin, Write};
use std::thread;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use cancellation::{CancellationToken, CancellationTokenSource, OperationCanceled};
use kuchiki::traits::*;
use rustc_serialize::json;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use termion::event::Key;
use hkg::status::*;
use hkg::model::IconItem;
use hkg::model::ListTopicItem;
use hkg::state_manager::*;
use hkg::screen_manager::*;
use hkg::resources::common::*;
use hkg::caches::file_cache::*;
use hkg::net::*;
use hkg::net::web_resource::*;

fn main() {

    // Initialize
    let stdout = stdout();
    let mut stdout = stdout.lock().into_raw_mode().unwrap();

    // Clear the screen.
    hkg::screen::common::clear_screen();

    let mut builder = hkg::builder::Builder::new();

    let mut state_manager = StateManager::new();
    let mut screen_manager = ScreenManager::new();

    let icon_manifest_string = hkg::utility::readfile(String::from("data/icon.manifest.json"));
    let icon_collection: Box<Vec<IconItem>> = Box::new(json::decode(&icon_manifest_string).unwrap());

    // initialize empty page
    let mut list_topic_items: Vec<ListTopicItem> = vec![];
    let mut show_item = builder.default_show_item();

    let mut status_bar = hkg::screen::status_bar::StatusBar::new();
    let mut index = hkg::screen::index::Index::new();
    let mut show = hkg::screen::show::Show::new(icon_collection);

    let (tx_req, rx_req) = channel::<ChannelItem>();
    let (tx_res, rx_res) = channel::<ChannelItem>();

    // web client
    thread::spawn(move || {
        let mut wr = WebResource::new();
        let mut fc = Box::new(FileCache::new());
        let ct = CancellationTokenSource::new();
        ct.cancel_after(std::time::Duration::new(10, 0));
        loop {
            match rx_req.recv() {
                Ok(item) => {

                    let th = thread::current();
                    ct.run(|| {
                               th.unpark();
                           },
                           || {
                                match item.extra.clone() {
                                    ChannelItemType::Index(_) => {
                                        let mut index_resource = hkg::resources::index_resource::IndexResource::new(&mut wr, &ct, &mut fc);
                                        tx_res.send(index_resource.fetch(&item)).unwrap();
                                    },
                                    ChannelItemType::Show(_) => {
                                        let mut show_resource = hkg::resources::show_resource::ShowResource::new(&mut wr, &ct, &mut fc);
                                        tx_res.send(show_resource.fetch(&item)).unwrap();
                                    },
                                    ChannelItemType::Image(_) => {
                                    }
                                }
                           });

                    if ct.is_canceled() {
                        thread::park_timeout(std::time::Duration::new(0, 250));
                        // Err(OperationCanceled)
                    } else {
                        // Ok(())
                    }
                }
                Err(_) => {}
            }
        }
    });

    // topics request
    let status_message = list_page(&mut state_manager, &tx_req);
    status_bar.append(&screen_manager, &status_message);

    loop {

        match rx_res.try_recv() {
            Ok(item) => {
                match item.extra {
                    ChannelItemType::Show(extra) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        let posturl = get_posturl(&extra.postid, extra.page);
                        show_item = builder.show_item(&document, &posturl);

                        status_bar.append(&screen_manager, &format!("[{}-{}:ROK][{}]",
                                 show_item.url_query.message,
                                 show_item.page,
                                 state_manager.isWebRequest()));

                        show.resetY();
                        hkg::screen::common::clear_screen();
                        state_manager.updateState(Status::Show); //state = Status::Show;
                        state_manager.setWebRequest(false); // is_web_requesting = false;
                    },
                    ChannelItemType::Index(_) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        list_topic_items = builder.list_topic_items(&document);

                        status_bar.append(&screen_manager,
                                               &format!("[TOPICS:ROK]"));

                        hkg::screen::common::clear_screen();

                        state_manager.updateState(Status::List); // state = Status::List;
                        state_manager.setWebRequest(false); // is_web_requesting = false;

                    },
                    ChannelItemType::Image(extra) => {
                    }
                }
            }
            Err(_) => {}
        }

        match state_manager.getState() {
            Status::Startup => {

            },
            Status::List => {
                index.print(&mut stdout, &list_topic_items);
            }
            Status::Show => {
                show.print(&mut stdout, &show_item);
            }
        }

        status_bar.print(&screen_manager);

        stdout.flush().unwrap();

        if !state_manager.isWebRequest() {

            let stdin = stdin();

            for c in stdin.keys() {

                if screen_manager.isWidthChanged() {
                    hkg::screen::common::clear_screen();
                }

                match state_manager.getState() {
                    Status::Startup => {},
                    Status::List => {
                        match c.unwrap() {
                            Key::Char('q') => {
                                hkg::screen::common::reset_screen();
                                return
                            },
                            Key::Char('\n') => {
                                status_bar.append(&screen_manager, "ENTER");
                                let i = index.get_selected_topic();
                                if i > 0 {
                                    let topic_item = &list_topic_items[i - 1];
                                    let postid = &topic_item.title.url_query.message;
                                    let page = 1;
                                    let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                    status_bar.append(&screen_manager,
                                                           &get_show_page_status_message(postid, page, &status_message));
                                }
                                break
                            },
                            Key::PageUp => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Up => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Down => {
                                status_bar.append(&screen_manager, "↓");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp < index.body_height() {
                                    index.select_topic(tmp + 1);
                                }
                                break
                            },
                            _ => {},
                        }
                    },
                    Status::Show => {
                            match c.unwrap() {
                                Key::Char('q') => {
                                    hkg::screen::common::reset_screen(); // print!("{}{}{}", termion::clear::All, style::Reset, termion::cursor::Show);
                                    return
                                },
                                Key::Left => {
                                    status_bar.append(&screen_manager, &format!("←"));
                                    if show_item.page > 1 {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page - 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                }
                                Key::Right => {
                                    status_bar.append(&screen_manager, &format!("→"));
                                    if show_item.max_page > show_item.page {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page + 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                },
                                Key::PageUp => {
                                    status_bar.append(&screen_manager, "↑");
                                    let bh = show.body_height();
                                    if show.scrollUp(bh) {
                                    hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::PageDown => {
                                    status_bar.append(&screen_manager, "↓");
                                    let bh = show.body_height();
                                    if show.scrollDown(bh) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Up => {
                                    status_bar.append(&screen_manager, "↑");
                                    if show.scrollUp(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Down => {
                                    status_bar.append(&screen_manager, "↓");
                                    if show.scrollDown(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Backspace => {
                                    status_bar.append(&screen_manager, "B");
                                    state_manager.updateState(Status::List); // state = Status::List;
                                    hkg::screen::common::clear_screen();
                                    break
                                },
                                _ => {},
                            }
                        }
                }

            }
        }

    }
}
fn get_posturl(postid: &String, page: usize) -> String {
    let base_url = "http://forum1.hkgolden.com/view.aspx";
    let posturl = format!("{base_url}?type=BW&message={postid}&page={page}",
                          base_url = base_url,
                          postid = postid,
                          page = page);
    posturl
}

fn list_page(state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Index(ChannelIndexItem { }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true);    // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn show_page(postid: &String, page: usize, state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Show(ChannelShowItem { postid: postid.clone(), page: page }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true); // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn get_show_page_status_message(postid: &String, page: usize, status_message: &String) -> String {
    format!("[{}-{}:{}]", postid, page, status_message)
}
<commit_msg>main - image request send to background download<commit_after>extern crate hkg;
extern crate termion;
extern crate rustc_serialize;
extern crate kuchiki;
extern crate chrono;
extern crate hyper;
extern crate cancellation;
extern crate time;
extern crate url;

use std::io::{stdout, stdin, Write};
use std::thread;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use cancellation::{CancellationToken, CancellationTokenSource, OperationCanceled};
use kuchiki::traits::*;
use rustc_serialize::json;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use termion::event::Key;
use hkg::status::*;
use hkg::model::IconItem;
use hkg::model::ListTopicItem;
use hkg::state_manager::*;
use hkg::screen_manager::*;
use hkg::resources::common::*;
use hkg::caches::file_cache::*;
use hkg::net::*;
use hkg::net::web_resource::*;

fn main() {

    // Initialize
    let stdout = stdout();
    let mut stdout = stdout.lock().into_raw_mode().unwrap();

    // Clear the screen.
    hkg::screen::common::clear_screen();

    let mut builder = hkg::builder::Builder::new();

    let mut state_manager = StateManager::new();
    let mut screen_manager = ScreenManager::new();

    let icon_manifest_string = hkg::utility::readfile(String::from("data/icon.manifest.json"));
    let icon_collection: Box<Vec<IconItem>> = Box::new(json::decode(&icon_manifest_string).unwrap());

    // initialize empty page
    let mut list_topic_items: Vec<ListTopicItem> = vec![];
    let mut show_item = builder.default_show_item();

    let mut status_bar = hkg::screen::status_bar::StatusBar::new();
    let mut index = hkg::screen::index::Index::new();
    let mut show = hkg::screen::show::Show::new(icon_collection);

    let (tx_req, rx_req) = channel::<ChannelItem>();
    let (tx_res, rx_res) = channel::<ChannelItem>();

    // web client
    thread::spawn(move || {
        let mut wr = WebResource::new();
        let mut fc = Box::new(FileCache::new());
        let ct = CancellationTokenSource::new();
        ct.cancel_after(std::time::Duration::new(10, 0));
        loop {
            match rx_req.recv() {
                Ok(item) => {

                    let th = thread::current();
                    ct.run(|| {
                               th.unpark();
                           },
                           || {
                                match item.extra.clone() {
                                    ChannelItemType::Index(_) => {
                                        let mut index_resource = hkg::resources::index_resource::IndexResource::new(&mut wr, &ct, &mut fc);
                                        tx_res.send(index_resource.fetch(&item)).unwrap();
                                    },
                                    ChannelItemType::Show(_) => {
                                        let mut show_resource = hkg::resources::show_resource::ShowResource::new(&mut wr, &ct, &mut fc);
                                        tx_res.send(show_resource.fetch(&item)).unwrap();
                                    },
                                    ChannelItemType::Image(_) => {
                                    }
                                }
                           });

                    if ct.is_canceled() {
                        thread::park_timeout(std::time::Duration::new(0, 250));
                        // Err(OperationCanceled)
                    } else {
                        // Ok(())
                    }
                }
                Err(_) => {}
            }
        }
    });

    // topics request
    let status_message = list_page(&mut state_manager, &tx_req);
    status_bar.append(&screen_manager, &status_message);

    loop {

        match rx_res.try_recv() {
            Ok(item) => {
                match item.extra {
                    ChannelItemType::Show(extra) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        let posturl = get_posturl(&extra.postid, extra.page);
                        show_item = builder.show_item(&document, &posturl);

                        status_bar.append(&screen_manager, &format!("[{}-{}:ROK][{}]",
                                 show_item.url_query.message,
                                 show_item.page,
                                 state_manager.isWebRequest()));

                        show.resetY();
                        hkg::screen::common::clear_screen();
                        state_manager.updateState(Status::Show); //state = Status::Show;
                        state_manager.setWebRequest(false); // is_web_requesting = false;
                    },
                    ChannelItemType::Index(_) => {
                        let document = kuchiki::parse_html().from_utf8().one(item.result.as_bytes());

                        list_topic_items = builder.list_topic_items(&document);

                        status_bar.append(&screen_manager,
                                               &format!("[TOPICS:ROK]"));

                        hkg::screen::common::clear_screen();

                        state_manager.updateState(Status::List); // state = Status::List;
                        state_manager.setWebRequest(false); // is_web_requesting = false;

                    },
                    ChannelItemType::Image(extra) => {
                    }
                }
            }
            Err(_) => {}
        }

        match state_manager.getState() {
            Status::Startup => {

            },
            Status::List => {
                index.print(&mut stdout, &list_topic_items);
            }
            Status::Show => {
                show.print(&mut stdout, &show_item);
            }
        }

        status_bar.print(&screen_manager);

        stdout.flush().unwrap();

        if !state_manager.isWebRequest() {

            let stdin = stdin();

            for c in stdin.keys() {

                if screen_manager.isWidthChanged() {
                    hkg::screen::common::clear_screen();
                }

                match state_manager.getState() {
                    Status::Startup => {},
                    Status::List => {
                        match c.unwrap() {
                            Key::Char('q') => {
                                hkg::screen::common::reset_screen();
                                return
                            },
                            Key::Char('\n') => {
                                status_bar.append(&screen_manager, "ENTER");
                                let i = index.get_selected_topic();
                                if i > 0 {
                                    let topic_item = &list_topic_items[i - 1];
                                    let postid = &topic_item.title.url_query.message;
                                    let page = 1;
                                    let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                    status_bar.append(&screen_manager,
                                                           &get_show_page_status_message(postid, page, &status_message));
                                }
                                break
                            },
                            Key::PageUp => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Up => {
                                status_bar.append(&screen_manager, "↑");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp > 1 {
                                    index.select_topic(tmp - 1);
                                }
                                break
                            },
                            Key::Down => {
                                status_bar.append(&screen_manager, "↓");
                                let tmp = index.get_selected_topic();
                                status_bar.append(&screen_manager, &format!("{}", tmp));

                                if tmp < index.body_height() {
                                    index.select_topic(tmp + 1);
                                }
                                break
                            },
                            _ => {},
                        }
                    },
                    Status::Show => {
                            match c.unwrap() {
                                Key::Char('q') => {
                                    hkg::screen::common::reset_screen(); // print!("{}{}{}", termion::clear::All, style::Reset, termion::cursor::Show);
                                    return
                                },
                                Key::Left => {
                                    status_bar.append(&screen_manager, &format!("←"));
                                    if show_item.page > 1 {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page - 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                }
                                Key::Right => {
                                    status_bar.append(&screen_manager, &format!("→"));
                                    if show_item.max_page > show_item.page {
                                        let postid = &show_item.url_query.message;
                                        let page = &show_item.page + 1;
                                        let status_message = show_page(&postid, page, &mut state_manager, &tx_req);

                                        status_bar.append(&screen_manager,
                                                               &get_show_page_status_message(postid, page, &status_message));
                                    }
                                    break
                                },
                                Key::PageUp => {
                                    status_bar.append(&screen_manager, "↑");
                                    let bh = show.body_height();
                                    if show.scrollUp(bh) {
                                    hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::PageDown => {
                                    status_bar.append(&screen_manager, "↓");
                                    let bh = show.body_height();
                                    if show.scrollDown(bh) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Up => {
                                    status_bar.append(&screen_manager, "↑");
                                    if show.scrollUp(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Down => {
                                    status_bar.append(&screen_manager, "↓");
                                    if show.scrollDown(2) {
                                        hkg::screen::common::clear_screen();
                                    }
                                    break
                                },
                                Key::Backspace => {
                                    status_bar.append(&screen_manager, "B");
                                    state_manager.updateState(Status::List); // state = Status::List;
                                    hkg::screen::common::clear_screen();
                                    break
                                },
                                _ => {},
                            }
                        }
                }

            }
        }

    }
}
fn get_posturl(postid: &String, page: usize) -> String {
    let base_url = "http://forum1.hkgolden.com/view.aspx";
    let posturl = format!("{base_url}?type=BW&message={postid}&page={page}",
                          base_url = base_url,
                          postid = postid,
                          page = page);
    posturl
}

fn list_page(state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Index(ChannelIndexItem { }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true);    // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn show_page(postid: &String, page: usize, state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Show(ChannelShowItem { postid: postid.clone(), page: page }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true); // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn image_request(url: &String, state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Image(ChannelImageItem { url: url.to_string(), bytes: Vec::new() }),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.setWebRequest(true); // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn get_show_page_status_message(postid: &String, page: usize, status_message: &String) -> String {
    format!("[{}-{}:{}]", postid, page, status_message)
}
<|endoftext|>


<commit_before>#![deny(warnings)]

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

#[macro_use]
extern crate nickel;

#[macro_use]
extern crate log;

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

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

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

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

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

    let mut opts = Options::new();

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

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

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

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

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

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

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

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

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

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

    builder.init().unwrap();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    loop {
                        match rx.recv() {
                            Ok(val) => {
                                trace!("file changed {:?}", val);
                                if let Some(path) = val.path {
                                    if path.is_absolute() {
                                        // get where process was run from
                                        let cwd = std::env::current_dir().unwrap_or(PathBuf::new());
                                        // strip absolute path
                                        let rel_path = path.strip_prefix(&cwd).unwrap_or(&cwd);

                                        // check if path starts with the build folder.
                                        if !&config.ignore.iter().any(|pattern| Pattern::matches_path(
                                            pattern,
                                            rel_path)) {
                                            build(&config);
                                        }

                                    } else {
                                        // check if path starts with build folder.
                                        // TODO: may want to check if it starts `./`
                                        if !&config.ignore.iter().any(|pattern| Pattern::matches_path(pattern, &path)) {
                                            build(&config);
                                        }
                                    }
                                }
                            }

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

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

        "new" => {
            if matches.free.len() == 2 {
                let dest = matches.free[1].clone();

                match create_new_project(&dest) {
                    Ok(_) => info!("Created new project at {}", dest),
                    Err(e) => {
                        error!("{}", e);
                        error!("Could not create a new cobalt project");
                        std::process::exit(1);
                    }
                }
            } else {
                println!("cobalt new DIRECTORY");
                print_usage(opts);
                std::process::exit(1);
            }
        }

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

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

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

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

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

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

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

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

    if meta.is_dir() {
        match import_dir(&config.dest, branch, message) {
            Ok(_) => info!("Import successful"),
            Err(e) => {
                error!("{}", e);
                error!("Import not successful");
                std::process::exit(1);
            }
        }
    } else {
        error!("Build dir is not a directory: {}", config.dest);
        error!("Import not successful");
        std::process::exit(1);
    }
}
<commit_msg>cleaned up error message for new command<commit_after>#![deny(warnings)]

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

#[macro_use]
extern crate nickel;

#[macro_use]
extern crate log;

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

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

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

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

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

    let mut opts = Options::new();

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

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

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

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

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

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

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

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

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

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

    builder.init().unwrap();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    loop {
                        match rx.recv() {
                            Ok(val) => {
                                trace!("file changed {:?}", val);
                                if let Some(path) = val.path {
                                    if path.is_absolute() {
                                        // get where process was run from
                                        let cwd = std::env::current_dir().unwrap_or(PathBuf::new());
                                        // strip absolute path
                                        let rel_path = path.strip_prefix(&cwd).unwrap_or(&cwd);

                                        // check if path starts with the build folder.
                                        if !&config.ignore.iter().any(|pattern| Pattern::matches_path(
                                            pattern,
                                            rel_path)) {
                                            build(&config);
                                        }

                                    } else {
                                        // check if path starts with build folder.
                                        // TODO: may want to check if it starts `./`
                                        if !&config.ignore.iter().any(|pattern| Pattern::matches_path(pattern, &path)) {
                                            build(&config);
                                        }
                                    }
                                }
                            }

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

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

        "new" => {
            if matches.free.len() == 2 {
                let dest = matches.free[1].clone();

                match create_new_project(&dest) {
                    Ok(_) => info!("Created new project at {}", dest),
                    Err(e) => {
                        error!("{}", e);
                        error!("Could not create a new cobalt project");
                        std::process::exit(1);
                    }
                }
            } else {
                error!("No directory specified for new blog.");
                error!("USAGE: new DIRECTORY");
                std::process::exit(1);
            }
        }

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

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

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

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

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

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

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

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

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


<commit_before>extern crate sfml;
extern crate survive;

use sfml::graphics::*;
use sfml::window::*;
use sfml::system::{Clock, Vector2i};
use survive::*;

fn main() {
    let mut win = GameWindow::new();
    win.rwin.clear(&Color::white());
    win.rwin.display();

    let res = Resources::new();

    let wg = Worldgen::new();
    //let test = Sprite::with_texture(&wg.textures[9]);

    let tilemgr = TileManager::new(wg.textures());

    let mut entitymgr = EntityManager::new();
    //entitymgr.add(entities::deciduous_tree::DeciduousTree::new(&res));
    //entitymgr.add(Box::new(entities::deciduous_tree::DeciduousTree::new(&res)));
    plants::generate_plants(&res, wg.world(), &mut entitymgr);

    let mut player = Player::new(&res);

    let mut stat = stats::Stats::new();

    let mut ui = UiManager::new(&res);

    let mut clock = Clock::start();
    'mainl: loop {
        let delta = clock.restart().as_seconds();

        win.rwin.clear(&Color::rgb(180, 215, 255));
        for i in &tilemgr {
            win.rwin.draw(i);
        }
        //win.rwin.draw(&test);
        entitymgr.draw_all(&mut win.rwin);
        win.rwin.draw(&player);
        ui.draw_all(&mut win.rwin);
        win.rwin.display();

        let dead = stat.dead();

        while let Some(e) = win.rwin.poll_event() {
            match e {
                Event::KeyPressed { code: Key::Escape, .. }
                        => break 'mainl,
                Event::MouseButtonPressed { button, x, y }
                    if !dead && button == mouse::Button::Left =>
                        entitymgr.mouse_click(&win.rwin, x, y),
                Event::Closed => break 'mainl,
                Event::Resized { width, height } => {
                    win.on_resize(width, height);
                    ui.on_resize(width, height);
                },
                _ => {},
            }
        }

        if dead {
            ui.set_display_death(true);
        } else {
            match player.update(delta, &win) {
                Some(s) => win.scroll(&s),
                None => {},
            };

            let Vector2i { x: mx, y: my } = win.rwin.mouse_position();
            player.mouse_pos(&win.rwin, mx, my);

            if player.is_in_water(&wg.world()) {
                stat.event(delta, &stats::StatEvent::InWater);
            }
            stat.update(delta);
        }

        ui.update(delta, &stat);

        //println!("{:?}", stat);
        //println!("dead: {}", stat.dead());
    }
}
<commit_msg>Make game restart after death<commit_after>extern crate sfml;
extern crate survive;

use sfml::graphics::*;
use sfml::window::*;
use sfml::system::{Clock, Vector2i, Vector2u};
use survive::*;

fn main() {
    let mut win = GameWindow::new();
    win.rwin.clear(&Color::white());
    win.rwin.display();

    let res = Resources::new();

    'outer: loop {
        let wg = Worldgen::new();
        //let test = Sprite::with_texture(&wg.textures[9]);

        let tilemgr = TileManager::new(wg.textures());

        let mut entitymgr = EntityManager::new();
        //entitymgr.add(entities::deciduous_tree::DeciduousTree::new(&res));
        //entitymgr.add(Box::new(entities::deciduous_tree::DeciduousTree::new(&res)));
        plants::generate_plants(&res, wg.world(), &mut entitymgr);

        let mut player = Player::new(&res);

        let mut stat = stats::Stats::new();

        let mut ui = UiManager::new(&res);
        let Vector2u { x: width, y: height } = win.rwin.size();
        ui.on_resize(width, height);

        let mut dead = stat.dead();
        let mut restart_clock = Clock::start();

        let mut clock = Clock::start();
        'mainl: loop {
            let delta = clock.restart().as_seconds();

            win.rwin.clear(&Color::rgb(180, 215, 255));
            for i in &tilemgr {
                win.rwin.draw(i);
            }
            //win.rwin.draw(&test);
            entitymgr.draw_all(&mut win.rwin);
            win.rwin.draw(&player);
            ui.draw_all(&mut win.rwin);
            win.rwin.display();

            if !dead && stat.dead() {
                dead = true;
                restart_clock.restart();
            }

            while let Some(e) = win.rwin.poll_event() {
                match e {
                    Event::KeyPressed { code: Key::Escape, .. }
                            => break 'outer,
                    Event::MouseButtonPressed { button, x, y }
                        if !dead && button == mouse::Button::Left =>
                            entitymgr.mouse_click(&win.rwin, x, y),
                    Event::Closed => break 'outer,
                    Event::Resized { width, height } => {
                        win.on_resize(width, height);
                        ui.on_resize(width, height);
                    },
                    _ => {},
                }
            }

            if dead {
                ui.set_display_death(true);

                //println!("restart_clock: {}", restart_clock.elapsed_time().as_seconds());
                if restart_clock.elapsed_time().as_milliseconds() > 2000 {
                    continue 'outer;
                }
            } else {
                match player.update(delta, &win) {
                    Some(s) => win.scroll(&s),
                    None => {},
                };

                let Vector2i { x: mx, y: my } = win.rwin.mouse_position();
                player.mouse_pos(&win.rwin, mx, my);

                if player.is_in_water(&wg.world()) {
                    stat.event(delta, &stats::StatEvent::InWater);
                }
                stat.update(delta);
            }

            ui.update(delta, &stat);

            //println!("{:?}", stat);
            //println!("dead: {}", stat.dead());
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals, dead_code)]
#![feature(box_syntax)]
#![feature(slice_patterns)]

mod gamestate;
use gamestate::*;

extern crate rand;
//use rand::{Rng, SeedableRng, XorShiftRng};

extern crate piston;
extern crate image;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::rc::Rc;
use std::cell::RefCell;

use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window;
use image::GenericImage;
use piston::input::{ MouseButton };
use piston::window::{WindowSettings, AdvancedWindow};
use piston::event::*;

fn main() {
    let mut game = GameState::new();

    let mut paused = true;
    let mut raining = true;

    let mut mouse_buttons_pressed = (false, false); //left, right

    let opengl = OpenGL::_3_2;
    let (width, height) = (WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32);
    let window = Sdl2Window::new(
        opengl,
        WindowSettings::new("Falling Sand", (width, height))
        .exit_on_esc(true)
        //what those do?
        .vsync(true)
        .samples(4)
        .fullscreen(true)
    );
    let window = Rc::new(RefCell::new(window));
    let mut image = image::ImageBuffer::from_pixel(width, height, image::Rgba([0, 0, 0, 255]));
    let mut texture = Texture::from_image(&image);
    let ref mut gl = GlGraphics::new(opengl);
    for e in window.clone().events().max_fps(120).ups(60) {
        use piston::event::*;
        use piston::input::{Button, Key};

        if let Some(Button::Keyboard(key)) = e.press_args() {
            match key {
                Key::Space => {
                    paused = !paused;
                    window.borrow_mut().set_capture_cursor(!paused); //remove cursor when game is running
                },
                Key::R => {raining = !raining},
                _ => {}
            }
        }

        if let Some(_) = e.update_args() {
            //Update game and image on every loop
            if !paused {
                if raining {game.rain()}
                game.update();
            }//if !paused {
        }

        if paused {
            if let Some(button) = e.press_args() {
                match button {
                    Button::Mouse(MouseButton::Left) => {mouse_buttons_pressed.0 = true},
                    Button::Mouse(MouseButton::Right) => {mouse_buttons_pressed.1 = true},
                    _ => {}
                }
            }
            if let Some(button) = e.release_args() {
                match button {
                    Button::Mouse(MouseButton::Left) => {mouse_buttons_pressed.0 = false},
                    Button::Mouse(MouseButton::Right) => {mouse_buttons_pressed.1 = false},
                    _ => {}
                }
            }
            if let Some(pos) = e.mouse_cursor_args() {
                //get mouse coordinates and draw something if there is place
                let (mouse_x, mouse_y) = (pos[0] as i16, pos[1] as i16);

                match mouse_buttons_pressed {
                   (true, false) => {
                       game.paint_square_obstacles(mouse_x, mouse_y, 30, 30);
                   }
                   (false, true) => {
                       //remove everything from map and both lists
                       game.remove_square(mouse_x, mouse_y, 30, 30);
                   }
                   _ => {}
               }
            }
        } //if paused

        if let Some(args) = e.render_args() {

            image = image::ImageBuffer::from_pixel(width, height, image::Rgba([0, 0, 0, 255]));
            for particle in game.particles.iter() {
                image.put_pixel(particle.x as u32, particle.y as u32, image::Rgba([238,232,170,255]));
            }
            for obstacle in game.obstacles.iter() {
                image.put_pixel(obstacle.x as u32, obstacle.y as u32, image::Rgba([128,0,0,255]));
            }
            texture.update(&image);
            gl.draw(args.viewport(), |c, gl| {
                graphics::clear([1.0; 4], gl);
                graphics::image(&texture, c.transform, gl);
            });

        };
    }
}
<commit_msg>Improve drawing performance.<commit_after>#![allow(non_upper_case_globals, dead_code)]
#![feature(box_syntax)]
#![feature(slice_patterns)]

mod gamestate;
use gamestate::*;

extern crate rand;
//use rand::{Rng, SeedableRng, XorShiftRng};

extern crate piston;
extern crate image;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::rc::Rc;
use std::cell::RefCell;

use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window;
use image::GenericImage;
use piston::input::{ MouseButton };
use piston::window::{WindowSettings, AdvancedWindow};
use piston::event::*;

fn main() {
    let mut game = GameState::new();

    let mut paused = true;
    let mut raining = true;

    let mut mouse_buttons_pressed = (false, false); //left, right

    let opengl = OpenGL::_3_2;
    let (width, height) = (WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32);
    let window = Sdl2Window::new(
        opengl,
        WindowSettings::new("Falling Sand", (width, height))
        .exit_on_esc(true)
        //what those do?
        .vsync(true)
        .samples(4)
        .fullscreen(true)
    );
    let window = Rc::new(RefCell::new(window));
    let mut image = image::ImageBuffer::from_pixel(width, height, image::Rgba([0, 0, 0, 255]));
    let blank = image.clone().into_raw();
    let mut texture = Texture::from_image(&image);
    let ref mut gl = GlGraphics::new(opengl);
    for e in window.clone().events().max_fps(120).ups(60) {
        use piston::event::*;
        use piston::input::{Button, Key};

        if let Some(Button::Keyboard(key)) = e.press_args() {
            match key {
                Key::Space => {
                    paused = !paused;
                    window.borrow_mut().set_capture_cursor(!paused); //remove cursor when game is running
                },
                Key::R => {raining = !raining},
                _ => {}
            }
        }

        if let Some(_) = e.update_args() {
            //Update game and image on every loop
            if !paused {
                if raining {game.rain()}
                game.update();
            }//if !paused {
        }

        if paused {
            if let Some(button) = e.press_args() {
                match button {
                    Button::Mouse(MouseButton::Left) => {mouse_buttons_pressed.0 = true},
                    Button::Mouse(MouseButton::Right) => {mouse_buttons_pressed.1 = true},
                    _ => {}
                }
            }
            if let Some(button) = e.release_args() {
                match button {
                    Button::Mouse(MouseButton::Left) => {mouse_buttons_pressed.0 = false},
                    Button::Mouse(MouseButton::Right) => {mouse_buttons_pressed.1 = false},
                    _ => {}
                }
            }
            if let Some(pos) = e.mouse_cursor_args() {
                //get mouse coordinates and draw something if there is place
                let (mouse_x, mouse_y) = (pos[0] as i16, pos[1] as i16);

                match mouse_buttons_pressed {
                   (true, false) => {
                       game.paint_square_obstacles(mouse_x, mouse_y, 30, 30);
                   }
                   (false, true) => {
                       //remove everything from map and both lists
                       game.remove_square(mouse_x, mouse_y, 30, 30);
                   }
                   _ => {}
               }
            }
        } //if paused

        if let Some(args) = e.render_args() {

            image = image::ImageBuffer::from_vec(width, height, blank.clone()).unwrap();
            for particle in game.particles.iter() {
                image.put_pixel(particle.x as u32, particle.y as u32, image::Rgba([238,232,170,255]));
            }
            for obstacle in game.obstacles.iter() {
                image.put_pixel(obstacle.x as u32, obstacle.y as u32, image::Rgba([128,0,0,255]));
            }
            texture.update(&image);
            gl.draw(args.viewport(), |c, gl| {
                graphics::clear([1.0; 4], gl);
                graphics::image(&texture, c.transform, gl);
            });

        };
    }
}
<|endoftext|>


<commit_before>#![crate_name = "limonite"]
#![crate_type = "bin"]
#![allow(dead_code)]

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

use std::io::{BufReader, Read};
use std::fs::File;
use std::path::Path;
use docopt::Docopt;
use syntax::lexer::Lexer;
use syntax::parser::Parser;
use codegen::codegen::codegen;

pub mod syntax;
pub mod codegen;

static USAGE: &'static str = "\
Usage: limonite <file>
       limonite (-s | --stdin)
       limonite (-v | --version)

Options:
    -h, --help      Display this message
    -s, --stdin     Read input from stdin
    -v, --version   Displays current version
";

#[derive(RustcDecodable)]
struct Args {
    pub arg_file: String,
    pub flag_stdin: bool,
    pub flag_version: bool
}

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

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

    // TODO: Compile the version in from the .toml
    if args.flag_version {
        let version = env!("CARGO_PKG_VERSION");

        return println!("limonite {}", version);
    }

    let input_string = if !args.flag_stdin {
        // Read from file
        let ref file_name = &args.arg_file;
        let path = Path::new(file_name);
        let file = match File::open(&path) {
            Ok(f)  => f,
            Err(e) => panic!("Failed to open file. File error: {}", e)
        };

        let mut input_string = String::new();
        if let Err(e) = BufReader::new(file).read_to_string(&mut input_string) {
            panic!(e);
        }

        input_string
    } else {
        // Read from stdin
        let mut input_string = String::new();
        if let Err(e) = std::io::stdin().read_to_string(&mut input_string) {
            panic!(e);
        }

        input_string
    };

    // Tokanize the input
    let lexer = Lexer::new(&input_string);

    // Parse & Build an AST
    let mut parser = Parser::new(lexer);

    // Could just unwrap this?:
    let ast_root = match parser.parse() {
        Some(ast) => ast,
        None => return,
    };

    // TODO: Semantic Analysis

    // Run Code Gen
    unsafe {
        codegen("module1", ast_root, true);
    }
}
<commit_msg>Added detail to panics<commit_after>#![crate_name = "limonite"]
#![crate_type = "bin"]
#![allow(dead_code)]

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

use std::io::{BufReader, Read};
use std::fs::File;
use std::path::Path;
use docopt::Docopt;
use syntax::lexer::Lexer;
use syntax::parser::Parser;
use codegen::codegen::codegen; // REVIEW: better codegen name convention + class?

pub mod syntax;
pub mod codegen;

static USAGE: &'static str = "\
Usage: limonite <file>
       limonite (-s | --stdin)
       limonite (-v | --version)

Options:
    -h, --help      Display this message
    -s, --stdin     Read input from stdin
    -v, --version   Displays current version
";

#[derive(RustcDecodable)]
struct Args {
    pub arg_file: String,
    pub flag_stdin: bool,
    pub flag_version: bool
}

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

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

    // TODO: Compile the version in from the .toml
    if args.flag_version {
        let version = env!("CARGO_PKG_VERSION");

        return println!("limonite {}", version);
    }

    let input_string = if !args.flag_stdin {
        let ref file_name = &args.arg_file;
        let path = Path::new(file_name);
        let file = match File::open(&path) {
            Ok(f)  => f,
            Err(e) => panic!("Failed to open file: {}", e)
        };

        let mut input_string = String::new();
        if let Err(e) = BufReader::new(file).read_to_string(&mut input_string) {
            panic!("Failed to read file: {}", e);
        }

        input_string
    } else {
        let mut input_string = String::new();
        if let Err(e) = std::io::stdin().read_to_string(&mut input_string) {
            panic!("Failed to read file: {}", e);
        }

        input_string
    };

    // Tokanize the input
    let lexer = Lexer::new(&input_string);

    // Parse & Build an AST
    let mut parser = Parser::new(lexer);

    let ast_root = match parser.parse() {
        Some(ast) => ast,
        None => return,
    };

    // TODO: Semantic Analysis

    // Run Code Gen
    unsafe {
        codegen("module1", ast_root, true);
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;

use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };

mod block;
mod board;

use board::Board;

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    rotation: f64,   // Rotation for the square.

    board: board::Board // the game board
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
        const RED:   [f32; 4] = [1.0, 0.0, 0.0, 1.0];

        let square = rectangle::square(0.0, 0.0, 50.0);
        let rotation = self.rotation;
        let (x, y) = ((args.width / 2) as f64,
                      (args.height / 2) as f64);

        self.gl.draw(args.viewport(), |c, gl| {
            // Clear the screen.
            clear(GREEN, gl);

            let transform = c.transform.trans(x, y)
                                       .rot_rad(rotation)
                                       .trans(-25.0, -25.0);

            // Draw a box rotating around the middle of the screen.
            rectangle(RED, square, transform, gl);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        // Rotate 2 radians per second.
        self.rotation += 2.0 * args.dt;
    }

    fn handle_input(&mut self, inp: Input) {
        self.board.handle_key_press(inp);
    }
}

fn main() {
    // Change this to OpenGL::V2_1 if not working.
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window: Window = WindowSettings::new(
            "t e t r i s",
            [400, 700]
        )
        .opengl(opengl)
        .exit_on_esc(true)
        .build()
        .unwrap();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        rotation: 0.0,
        board: Board::init_board()
    };

    let mut events = window.events();
    while let Some(e) = events.next(&mut window) {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }

        if let Some(u) = e.update_args() {
            app.update(&u);
        }

        if let Event::Input(i) = e {
            app.handle_input(i);
        }
    }
}

<commit_msg>smol refactor<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;

use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{ GlGraphics, OpenGL };

mod block;
mod board;

use board::Board;

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    rotation: f64,   // Rotation for the square.

    board: board::Board // the game board
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
        const RED:   [f32; 4] = [1.0, 0.0, 0.0, 1.0];

        let square = rectangle::square(0.0, 0.0, 50.0);
        let rotation = self.rotation;
        let (x, y) = ((args.width / 2) as f64,
                      (args.height / 2) as f64);

        self.gl.draw(args.viewport(), |c, gl| {
            // Clear the screen.
            clear(GREEN, gl);

            let transform = c.transform.trans(x, y)
                                       .rot_rad(rotation)
                                       .trans(-25.0, -25.0);

            // Draw a box rotating around the middle of the screen.
            rectangle(RED, square, transform, gl);
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        // Rotate 2 radians per second.
        self.rotation += 2.0 * args.dt;
    }
}

fn main() {
    // Change this to OpenGL::V2_1 if not working.
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window: Window = WindowSettings::new(
            "t e t r i s",
            [400, 700]
        )
        .opengl(opengl)
        .exit_on_esc(true)
        .build()
        .unwrap();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        rotation: 0.0,
        board: Board::init_board()
    };

    let mut events = window.events();
    while let Some(e) = events.next(&mut window) {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }

        if let Some(u) = e.update_args() {
            app.update(&u);
        }

        if let Event::Input(i) = e {
            app.board.handle_key_press(i);
        }
    }
}

<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate toml;
extern crate rustc_serialize;

mod lockfile;

use std::fs::File;
use std::io::{self, Read, Write, ErrorKind};
use std::process::{self, Command, ExitStatus};
use std::fmt;
use std::env;

#[cfg(feature = "logging")]
fn init_logging() {
    extern crate env_logger;
    env_logger::init().unwrap();
    info!("logging enabled");
}
#[cfg(not(feature = "logging"))]
fn init_logging() {}

/// The kinds of errors that can occur in `run()`.
#[derive(Debug)]
enum RunError {
    /// The lock file didn't exist
    LockFileNotFound,
    /// Lock file exists, but is invalid
    LockFileError(lockfile::ReadError),
    /// I/O error when trying to open the given file
    ///
    /// (less specific than `LockFileNotFound`, but more specific then `IoError`)
    FileError(String, io::Error),
    /// Unknown I/O error
    IoError(io::Error),
    /// Invalid command line arguments (with description)
    InvalidArgument(String),
    /// Invoked subcommand returned an error
    ExecError(ExitStatus),
}

impl From<io::Error> for RunError {
    fn from(e: io::Error) -> Self {
        RunError::IoError(e)
    }
}

impl From<lockfile::ReadError> for RunError {
    fn from(e: lockfile::ReadError) -> Self {
        RunError::LockFileError(e)
    }
}

impl fmt::Display for RunError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RunError::LockFileNotFound => write!(f, "lock file 'Cargo.lock' not found (try running \
                                                     `cargo generate-lockfile` first)"),
            RunError::LockFileError(ref e) => write!(f, "error reading lockfile: {}", e),
            RunError::FileError(ref name, ref e) => write!(f, "error opening '{}': {}", name, e),
            RunError::IoError(ref e) => write!(f, "{}", e),
            RunError::InvalidArgument(ref e) => write!(f, "invalid arguments: {}", e),
            RunError::ExecError(status) => write!(f, "command exited with error: {}", status),
        }
    }
}

/// Main entry point.
fn run() -> Result<(), RunError> {
    // First, validate cmd line arguments
    let mut args = env::args();
    // We can dispose of the first 2 arguments (the executable, and the subcommand passed by cargo)
    args.next().expect("exec name not passed as argument");
    if args.next() == None {
        return Err(RunError::InvalidArgument("subcommand not passed as argument (not running with \
                                              cargo?)".into()));
    }
    // Then we expect at least one more argument to pass to cargo
    let cargo_cmd = match args.next() {
        Some(cmd) => cmd,
        None => return Err(RunError::InvalidArgument("no cargo command passed".into())),
    };
    // Any other arg is passed along to cargo
    let cargo_args: Vec<_> = args.collect();

    // Helper for running Cargo on a package
    let run_cargo = |pkg: &str| -> Result<(), RunError> {
        let mut cmd = Command::new("cargo");
        cmd.arg(&cargo_cmd).arg("-p").arg(pkg).args(&cargo_args);
        info!("running {:?}", cmd);
        let status = try!(cmd.status());

        if !status.success() {
            return Err(RunError::ExecError(status));
        }

        Ok(())
    };

    let mut file = try!(File::open("Cargo.lock").map_err(|e| match e.kind() {
        ErrorKind::NotFound => {
            RunError::LockFileNotFound
        }
        _ => {
            RunError::FileError(String::from("Cargo.lock"), e)
        }
    }));
    let mut string = String::new();
    try!(file.read_to_string(&mut string));
    let lockfile = try!(lockfile::parse(&string));
    debug!("parsed lockfile: {:#?}", lockfile);
    info!("root pkg: {}", &lockfile.root.name);

    // Run the subcommand on the main pkg. This isn't normally done via `-p`, but should work
    // regardless.
    info!("handling root pkg");
    try!(run_cargo(&lockfile.root.name));

    for dep in &lockfile.package {
        if dep.is_local() {
            info!("got local package '{}'", dep.name);
            try!(run_cargo(&dep.name));
        }
    }

    Ok(())
}

fn main() {
    init_logging();

    match run() {
        Ok(()) => {},
        Err(e) => {
            let mut stderr = io::stderr();
            writeln!(stderr, "an error occurred: {}", e).unwrap();
            process::exit(1);
        }
    }
}
<commit_msg>Collect local pkgs separately<commit_after>#[macro_use] extern crate log;
extern crate toml;
extern crate rustc_serialize;

mod lockfile;

use std::fs::File;
use std::io::{self, Read, Write, ErrorKind};
use std::process::{self, Command, ExitStatus};
use std::fmt;
use std::env;
use std::iter;

#[cfg(feature = "logging")]
fn init_logging() {
    extern crate env_logger;
    env_logger::init().unwrap();
    info!("logging enabled");
}
#[cfg(not(feature = "logging"))]
fn init_logging() {}

/// The kinds of errors that can occur in `run()`.
#[derive(Debug)]
enum RunError {
    /// The lock file didn't exist
    LockFileNotFound,
    /// Lock file exists, but is invalid
    LockFileError(lockfile::ReadError),
    /// I/O error when trying to open the given file
    ///
    /// (less specific than `LockFileNotFound`, but more specific then `IoError`)
    FileError(String, io::Error),
    /// Unknown I/O error
    IoError(io::Error),
    /// Invalid command line arguments (with description)
    InvalidArgument(String),
    /// Invoked subcommand returned an error
    ExecError(ExitStatus),
}

impl From<io::Error> for RunError {
    fn from(e: io::Error) -> Self {
        RunError::IoError(e)
    }
}

impl From<lockfile::ReadError> for RunError {
    fn from(e: lockfile::ReadError) -> Self {
        RunError::LockFileError(e)
    }
}

impl fmt::Display for RunError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RunError::LockFileNotFound => write!(f, "lock file 'Cargo.lock' not found (try running \
                                                     `cargo generate-lockfile` first)"),
            RunError::LockFileError(ref e) => write!(f, "error reading lockfile: {}", e),
            RunError::FileError(ref name, ref e) => write!(f, "error opening '{}': {}", name, e),
            RunError::IoError(ref e) => write!(f, "{}", e),
            RunError::InvalidArgument(ref e) => write!(f, "invalid arguments: {}", e),
            RunError::ExecError(status) => write!(f, "command exited with error: {}", status),
        }
    }
}

/// Main entry point.
fn run() -> Result<(), RunError> {
    // First, validate cmd line arguments
    let mut args = env::args();
    // We can dispose of the first 2 arguments (the executable, and the subcommand passed by cargo)
    args.next().expect("exec name not passed as argument");
    if args.next() == None {
        return Err(RunError::InvalidArgument("subcommand not passed as argument (not running with \
                                              cargo?)".into()));
    }
    // Then we expect at least one more argument to pass to cargo
    let cargo_cmd = match args.next() {
        Some(cmd) => cmd,
        None => return Err(RunError::InvalidArgument("no cargo command passed".into())),
    };
    // Any other arg is passed along to cargo
    let cargo_args: Vec<_> = args.collect();

    // Helper for running Cargo on a package
    let run_cargo = |pkg: &str| -> Result<(), RunError> {
        let mut cmd = Command::new("cargo");
        cmd.arg(&cargo_cmd).arg("-p").arg(pkg).args(&cargo_args);
        info!("running {:?}", cmd);
        let status = try!(cmd.status());

        if !status.success() {
            return Err(RunError::ExecError(status));
        }

        Ok(())
    };

    let mut file = try!(File::open("Cargo.lock").map_err(|e| match e.kind() {
        ErrorKind::NotFound => {
            RunError::LockFileNotFound
        }
        _ => {
            RunError::FileError(String::from("Cargo.lock"), e)
        }
    }));
    let mut string = String::new();
    try!(file.read_to_string(&mut string));
    let lockfile = try!(lockfile::parse(&string));
    debug!("parsed lockfile: {:#?}", lockfile);
    info!("root pkg: {}", &lockfile.root.name);

    // First, collect all local packages, including the main package
    let local_pkgs = iter::once(&lockfile.root.name)
                          .chain(lockfile.package
                                 .iter()
                                 .filter(|pkg| pkg.is_local())
                                 .map(|pkg| &pkg.name))
                          .collect::<Vec<_>>();
    debug!("local packages: {:?}", local_pkgs);

    // Now run the subcommand for all packages we collected
    for pkg in &local_pkgs {
        try!(run_cargo(pkg));
    }

    Ok(())
}

fn main() {
    init_logging();

    match run() {
        Ok(()) => {},
        Err(e) => {
            let mut stderr = io::stderr();
            writeln!(stderr, "an error occurred: {}", e).unwrap();
            process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>pub extern crate rusty_sword;
use rusty_sword::*;

fn main() {
    let mut rng = rand::thread_rng();

    // To avoid lock contention for this group of objects, we'll follow the rule:
    // - You must have a lock on floor before trying to lock anything else
    // - You must not keep any locks when floor gets unlocked
    let floor        = Arc::new(Mutex::new(Floor::new(60, 30)));
    let dirty_coords = Arc::new(Mutex::new(Vec::<Coord>::new()));
    let messages     = Arc::new(Mutex::new(Vec::<String>::new()));
    let player       = Arc::new(Mutex::new(Player::new(Coord::new(30, 15))));
    let monsters     = Arc::new(Mutex::new(Vec::<Monster>::new()));

    // `stop` is not related to the objects above. To avoid lock contention, we'll follow the rule:
    // - stop should be locked and released when no other objects are locked
    let stop = Arc::new(Mutex::new(false));

    // Render Thread
    let render_thread = {
        let floor = floor.clone();
        let dirty_coords = dirty_coords.clone();
        let messages = messages.clone();
        let player = player.clone();
        let monsters = monsters.clone();
        let stop = stop.clone();
        spawn(move || { render_loop(floor, dirty_coords, messages, player, monsters, stop) })
    };

    // Sound Thread
    let (sound_tx, sound_rx) = mpsc::channel::<&str>();
    let sound_thread = {
        let stop = stop.clone();
        spawn(move || { sound_loop(sound_rx, stop) } )
    };

    //-------------------------------------------------------------------------
    // Game Loop
    let mut player_moved = false;
    let mut quit = false;
    let mut astdin = async_stdin();
    let mut bytebuf : [u8; 1] = [0];
    let mut spawn_timer = Timer::from_millis(1000);
    let mut last_instant = Instant::now();
    loop {
        sleep(Duration::from_millis(10));
        if quit {
            { *stop.lock().unwrap() = true; }
        }
        // Time to stop?
        {
            if *stop.lock().unwrap() {
                break;
            }
        }
        // Once we can lock floor, we can lock anything else we want in this thread.
        let floor = floor.lock().unwrap();
        let mut dirty_coords = dirty_coords.lock().unwrap();
        let mut player = player.lock().unwrap();
        let mut monsters = monsters.lock().unwrap();
        let mut messages = messages.lock().unwrap();

        let current_instant = Instant::now();
        let delta = current_instant - last_instant;

        // Player moves?
        while let Ok(amount) = astdin.read(&mut bytebuf) {
            if amount == 1 { // input was available
                match bytebuf[0] {
                    27|b'q' => {
                        quit = true;
                    },
                    _ => {
                        if let Some(direction) = byte_to_direction(bytebuf[0]) {
                            player_moved = player.travel(direction, &floor, &mut dirty_coords);
                        }
                    },
                }
            } else { // no more input
                break;
            }
        }

        // Update monster timers
        for monster in monsters.iter_mut() {
            monster.update(delta);
        }

        // Monsters move?
        if !player_moved {
            for monster in monsters.iter_mut() {
                monster.try_travel(player.coord, &mut dirty_coords);
            }
        }

        // Did a monster die?
        let num_monsters = monsters.len();
        monsters.retain(|monster| monster.coord != player.sword_coord);
        let num_killed = num_monsters - monsters.len();
        if num_killed > 0 {
            for _ in 0..num_killed {
                sound_tx.send("monster_dies").unwrap();
                messages.push("You killed a monster!".to_string());
            }
            player.score += num_killed as u64;
        }

        // Spawn a new monster!
        spawn_timer.update(delta);
        if spawn_timer.ready {
            spawn_timer = Timer::from_millis(sample(&mut rng, 1000..5000, 1)[0]);
            let to_coord = Coord::new(
                sample(&mut rng, 1..59, 1)[0],
                sample(&mut rng, 1..29, 1)[0],
            );
            if to_coord != player.coord {
                let monster = Monster::new(to_coord, &mut rng);
                sound_tx.send("monster_spawns").unwrap();
                messages.push(format!("Monster {} spawned", monster.symbol));
                monsters.push(monster);
            }
        }

        // Did the player die?
        if monsters.iter().any(|monster| monster.coord == player.coord) {
            sound_tx.send("player_dies").unwrap();
            messages.push(format!("You were eaten by a monster."));
            quit = true;
        }

        // Take care of loop variables
        last_instant = current_instant;
        player_moved = false;
    }
    // End game loop

    // Wait for other threads to stop before exiting
    render_thread.join().unwrap();
    println!("Thanks for playing!");
    sound_thread.join().unwrap();
}
<commit_msg>wording<commit_after>pub extern crate rusty_sword;
use rusty_sword::*;

fn main() {
    let mut rng = rand::thread_rng();

    // To avoid lock contention for this group of objects, we'll follow the rule:
    // - You must have a lock on floor before trying to lock anything else
    // - You must unlock all other locks before (or when) floor gets unlocked
    let floor        = Arc::new(Mutex::new(Floor::new(60, 30)));
    let dirty_coords = Arc::new(Mutex::new(Vec::<Coord>::new()));
    let messages     = Arc::new(Mutex::new(Vec::<String>::new()));
    let player       = Arc::new(Mutex::new(Player::new(Coord::new(30, 15))));
    let monsters     = Arc::new(Mutex::new(Vec::<Monster>::new()));

    // `stop` is not related to the objects above. To avoid lock contention, we'll follow the rule:
    // - stop should be locked only when no other objects are locked
    let stop = Arc::new(Mutex::new(false));

    // Render Thread
    let render_thread = {
        let floor = floor.clone();
        let dirty_coords = dirty_coords.clone();
        let messages = messages.clone();
        let player = player.clone();
        let monsters = monsters.clone();
        let stop = stop.clone();
        spawn(move || { render_loop(floor, dirty_coords, messages, player, monsters, stop) })
    };

    // Sound Thread
    let (sound_tx, sound_rx) = mpsc::channel::<&str>();
    let sound_thread = {
        let stop = stop.clone();
        spawn(move || { sound_loop(sound_rx, stop) } )
    };

    //-------------------------------------------------------------------------
    // Game Loop
    let mut player_moved = false;
    let mut quit = false;
    let mut astdin = async_stdin();
    let mut bytebuf : [u8; 1] = [0];
    let mut spawn_timer = Timer::from_millis(1000);
    let mut last_instant = Instant::now();
    loop {
        sleep(Duration::from_millis(10));
        if quit {
            { *stop.lock().unwrap() = true; }
        }
        // Time to stop?
        {
            if *stop.lock().unwrap() {
                break;
            }
        }
        // Once we can lock floor, we can lock anything else we want in this thread.
        let floor = floor.lock().unwrap();
        let mut dirty_coords = dirty_coords.lock().unwrap();
        let mut player = player.lock().unwrap();
        let mut monsters = monsters.lock().unwrap();
        let mut messages = messages.lock().unwrap();

        let current_instant = Instant::now();
        let delta = current_instant - last_instant;

        // Player moves?
        while let Ok(amount) = astdin.read(&mut bytebuf) {
            if amount == 1 { // input was available
                match bytebuf[0] {
                    27|b'q' => {
                        quit = true;
                    },
                    _ => {
                        if let Some(direction) = byte_to_direction(bytebuf[0]) {
                            player_moved = player.travel(direction, &floor, &mut dirty_coords);
                        }
                    },
                }
            } else { // no more input
                break;
            }
        }

        // Update monster timers
        for monster in monsters.iter_mut() {
            monster.update(delta);
        }

        // Monsters move?
        if !player_moved {
            for monster in monsters.iter_mut() {
                monster.try_travel(player.coord, &mut dirty_coords);
            }
        }

        // Did a monster die?
        let num_monsters = monsters.len();
        monsters.retain(|monster| monster.coord != player.sword_coord);
        let num_killed = num_monsters - monsters.len();
        if num_killed > 0 {
            for _ in 0..num_killed {
                sound_tx.send("monster_dies").unwrap();
                messages.push("You killed a monster!".to_string());
            }
            player.score += num_killed as u64;
        }

        // Spawn a new monster!
        spawn_timer.update(delta);
        if spawn_timer.ready {
            spawn_timer = Timer::from_millis(sample(&mut rng, 1000..5000, 1)[0]);
            let to_coord = Coord::new(
                sample(&mut rng, 1..59, 1)[0],
                sample(&mut rng, 1..29, 1)[0],
            );
            if to_coord != player.coord {
                let monster = Monster::new(to_coord, &mut rng);
                sound_tx.send("monster_spawns").unwrap();
                messages.push(format!("Monster {} spawned", monster.symbol));
                monsters.push(monster);
            }
        }

        // Did the player die?
        if monsters.iter().any(|monster| monster.coord == player.coord) {
            sound_tx.send("player_dies").unwrap();
            messages.push(format!("You were eaten by a monster."));
            quit = true;
        }

        // Take care of loop variables
        last_instant = current_instant;
        player_moved = false;
    }
    // End game loop

    // Wait for other threads to stop before exiting
    render_thread.join().unwrap();
    println!("Thanks for playing!");
    sound_thread.join().unwrap();
}
<|endoftext|>