<commit_before>extern crate libc;
extern crate ncurses;

mod util;
mod item;

use std::io::{stdin, Read, BufRead, BufReader};
use std::error::Error;
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use std::process::{Command, Stdio, exit};
use std::char;
use std::mem;
use std::sync::mpsc::{Sender, Receiver, channel};
use util::eventbox::EventBox;

use ncurses::*;

use item::{Item, MatchedItem};

//==============================================================================

struct FZF {
    query: String,
}

//==============================================================================
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
enum Event{
    EvReaderNewItem,
    EvReaderFinished,
    EvMatcherNewItem,
    EvMatcherResetQuery,
    EvMatcherUpdateProcess,
    EvMatcherFinished,
    EvQueryChange,
    EvInputToggle,
    EvInputUp,
    EvInputDown,
    EvInputSelect,
}

// matcher will receive two events:
// 1. EvMatcherNewItem, to reset the input strings
// 2. EvMatcherResetQuery, to interrupt current processing.
//
// will send two events:
// 1. EvMatcherUpdateProcess, to notify the matched/total items
// 2. EvMatcherFinished.

struct Matcher {
    tx_output: Sender<MatchedItem>,   // channel to send output to
    eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Arc<RwLock<Vec<Item>>>,
    item_pos: usize,
    num_matched: u64,
    query: String,
}

impl Matcher {
    pub fn new(items: Arc<RwLock<Vec<Item>>>, tx_output: Sender<MatchedItem>,
               eb_req: Arc<EventBox<Event>>, eb_notify: Arc<EventBox<Event>>) -> Self {
        Matcher {
            tx_output: tx_output,
            eb_req: eb_req,
            eb_notify: eb_notify,
            items: items,
            item_pos: 0,
            num_matched: 0,
            query: String::new(),
        }
    }

    fn match_str(&self, item: &str) -> bool {
        if self.query == "" {
            return true;
        }

        item.starts_with(&self.query)
    }

    pub fn process(&mut self) {
        let items = self.items.read().unwrap();
        for item in items[self.item_pos..].into_iter() {
            // process the matcher
            //self.tx_output.send(string.clone());
            if self.match_str(&item.text) {
                self.num_matched += 1;
                self.tx_output.send(MatchedItem::new(self.item_pos));
            }

            (*self.eb_notify).set(Event::EvMatcherUpdateProcess, Box::new((self.num_matched, items.len() as u64)));

            self.item_pos += 1;
            if (self.item_pos % 100) == 99 && !self.eb_req.is_empty() {
                break;
            }
        }
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.num_matched = 0;
        self.item_pos = 0;
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in (*self.eb_req).wait() {
                match e {
                    Event::EvMatcherNewItem => {}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            self.process()
        }
    }
}

//==============================================================================
// Input: fetch the query string, handle key event

struct Input {
    query: Vec<char>,
    index: usize, // index in chars
    pos: usize, // position in bytes
    eb: Arc<EventBox<Event>>,
}

impl Input {
    pub fn new(eb: Arc<EventBox<Event>>) -> Self {
        Input {
            query: Vec::new(),
            index: 0,
            pos: 0,
            eb: eb,
        }
    }

    fn get_query(&self) -> String {
        self.query.iter().cloned().collect::<String>()
    }

    fn add_char (&mut self, ch: char) {
        self.query.insert(self.index, ch);
        self.index += 1;
        self.pos += if ch.len_utf8() > 1 {2} else {1};
    }

    fn delete_char(&mut self) {
        if self.index == 0 {
            return;
        }

        let ch = self.query.remove(self.index-1);
        self.index -= 1;
        self.pos -= if ch.len_utf8() > 1 {2} else {1};
    }

    pub fn run(&mut self) {
        loop {
            self.handle_char();
        }
    }

    // fetch input from curses and turn it into query.
    fn handle_char(&mut self) {
        let ch = wget_wch(stdscr);

        let orig_query = self.query.clone();

        match ch {
            Some(WchResult::KeyCode(_)) => {
                // will later handle readline-like shortcuts
            }

            Some(WchResult::Char(c)) => {
                /* Enable attributes and output message. */
                let ch = char::from_u32(c as u32).expect("Invalid char");
                match ch {
                    '\x7F' => { // backspace
                        self.delete_char();
                        self.eb.set(Event::EvQueryChange, Box::new((self.get_query(), self.pos)));
                    }

                    '\x0A' => { // enter
                        self.eb.set(Event::EvInputSelect, Box::new(true));
                    }

                    ch => { // other characters
                        self.add_char(ch);
                        self.eb.set(Event::EvQueryChange, Box::new((self.get_query(), self.pos)));
                    }
                }
            }

            None => { }
        }
    }
}

//==============================================================================
// Reader: fetch a list of lines from stdin or command output

const READER_LINES_CACHED: usize = 100;

struct Reader {
    cmd: Option<&'static str>, // command to invoke
    eb: Arc<EventBox<Event>>,         // eventbox
    tx: Sender<Item>,    // sender to send the string read from command output
}

impl Reader {

    pub fn new(cmd: Option<&'static str>, eb: Arc<EventBox<Event>>, tx: Sender<Item>) -> Self {
        Reader{cmd: cmd, eb: eb, tx: tx}
    }

    // invoke find comand.
    fn get_command_output(&self) -> Result<Box<BufRead>, Box<Error>> {
        let command = try!(Command::new("sh")
                           .arg("-c")
                           .arg(self.cmd.unwrap_or("find ."))
                           .stdout(Stdio::piped())
                           .stderr(Stdio::null())
                           .spawn());
        let stdout = try!(command.stdout.ok_or("command output: unwrap failed".to_owned()));
        Ok(Box::new(BufReader::new(stdout)))
    }

    fn run(&mut self) {
        // check if the input is TTY
        let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

        let mut read;
        if istty {
            read = self.get_command_output().expect("command not found");
        } else {
            read = Box::new(BufReader::new(stdin()))
        };

        loop {
            let mut input = String::new();
            match read.read_line(&mut input) {
                Ok(n) => {
                    if n <= 0 { break; }

                    if input.ends_with("\n") {
                        input.pop();
                        if input.ends_with("\r") {
                            input.pop();
                        }
                    }
                    self.tx.send(Item::new(input));
                }
                Err(_err) => { break; }
            }
            self.eb.set(Event::EvReaderNewItem, Box::new(0));
        }
        self.eb.set(Event::EvReaderFinished, Box::new(0));
    }
}

//==============================================================================
// Model: data structure for display the result
struct Model {
    query: String,
    query_cursor: i32,
    num_matched: u64,
    num_total: u64,
    items: Arc<RwLock<Vec<Item>>>,
    matched_items: Vec<MatchedItem>,
    item_start_pos: i64,
    line_cursor: i32,
    max_y: i32,
    max_x: i32,
}

impl Model {
    pub fn new() -> Self {
        let mut max_y = 0;
        let mut max_x = 0;
        getmaxyx(stdscr, &mut max_y, &mut max_x);

        Model {
            query: String::new(),
            query_cursor: 0,
            num_matched: 0,
            num_total: 0,
            items: Arc::new(RwLock::new(Vec::new())),
            matched_items: Vec::new(),
            item_start_pos: 0,
            line_cursor: 0,
            max_y: max_y,
            max_x: max_x,
        }
    }

    pub fn update_query(&mut self, query: String, cursor: i32) {
        self.query = query;
        self.query_cursor = cursor;
    }

    pub fn update_process_info(&mut self, matched: u64, total: u64) {
        self.num_matched = matched;
        self.num_total = total;
    }

    pub fn push_item(&mut self, item: MatchedItem) {
        self.matched_items.push(item);
    }

    pub fn clear_items(&mut self) {
        self.matched_items.clear();
    }

    pub fn move_line_cursor(&mut self, diff: i32) {
        self.line_cursor += diff;
    }

    pub fn print_query(&self) {
        // > query
        mv(self.max_y-1, 0);
        addstr("> ");
        addstr(&self.query);
        mv(self.max_y-1, self.query_cursor+2);
    }

    pub fn print_info(&self) {
        mv(self.max_y-2, 0);
        addstr(format!("  {}/{}", self.num_matched, self.num_total).as_str());
    }

    pub fn print_items(&self) {
        let items = self.items.read().unwrap();
        let mut y = self.max_y - 2;
        for item in self.matched_items.iter() {
            mv(y, 2);

            let shown_str: String = items[item.index].text.chars().take((self.max_x-1) as usize).collect();
            addstr(&shown_str);

            y -= 1;
            if y <= 0 {
                break;
            }
        }
    }

    pub fn refresh(&self) {
        refresh();
    }

    pub fn display(&self) {
        erase();
        self.print_items();
        self.print_info();
        self.print_query();
        self.refresh();
    }
}

//==============================================================================
// Display: for printing the result

//==============================================================================

fn main() {
    // initialize ncurses
    let local_conf = LcCategory::all;
    setlocale(local_conf, "en_US.UTF-8"); // for showing wide characters
    initscr();
    raw();
    keypad(stdscr, true);
    noecho();

    let mut model = Model::new();

    let eb = Arc::new(EventBox::new());
    let (tx_source, rx_source) = channel();
    let (tx_matched, rx_matched) = channel();

    let eb_clone_reader = eb.clone();
    let mut reader = Reader::new(Some(&"find ."), eb_clone_reader, tx_source);

    let eb_matcher = Arc::new(EventBox::new());
    let eb_matcher_clone = eb_matcher.clone();
    let eb_clone_matcher = eb.clone();
    let items = model.items.clone();
    let mut matcher = Matcher::new(items, tx_matched, eb_matcher_clone, eb_clone_matcher);

    let eb_clone_input = eb.clone();
    let mut input = Input::new(eb_clone_input);

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

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

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

    'outer: loop {
        for (e, val) in eb.wait() {
            match e {
                Event::EvReaderNewItem | Event::EvReaderFinished => {
                    let mut items = model.items.write().unwrap();
                    while let Ok(string) = rx_source.try_recv() {
                        items.push(string);
                    }
                    eb_matcher.set(Event::EvMatcherNewItem, Box::new(true));
                }

                Event::EvMatcherUpdateProcess => {
                    let (matched, total) : (u64, u64) = *val.downcast().unwrap();
                    model.update_process_info(matched, total);

                    while let Ok(matchedItem) = rx_matched.try_recv() {
                        model.push_item(matchedItem);
                    }
                }

                Event::EvQueryChange => {
                    let (query, pos) : (String, usize) = *val.downcast().unwrap();
                    let modified = query != model.query;
                    model.update_query(query.clone(), pos as i32);

                    if modified {
                        model.clear_items();
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(model.query.clone()));
                    }
                }

                Event::EvInputSelect => {
                    // break out of the loop and output the selected item.
                    break 'outer;
                }

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

    endwin();
}
<commit_msg>Finish the basic interaction<commit_after>extern crate libc;
extern crate ncurses;

mod util;
mod item;

use std::io::{stdin, Read, BufRead, BufReader};
use std::error::Error;
use std::sync::{Arc, RwLock};
use std::thread;
use std::process::{Command, Stdio};
use std::char;
use std::cmp;
use std::sync::mpsc::{Sender, channel};
use util::eventbox::EventBox;

use ncurses::*;

use item::{Item, MatchedItem};

//==============================================================================
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
enum Event{
    EvReaderNewItem,
    EvReaderFinished,
    EvMatcherNewItem,
    EvMatcherResetQuery,
    EvMatcherUpdateProcess,
    EvQueryChange,
    EvInputToggle,
    EvInputUp,
    EvInputDown,
    EvInputSelect,
}

// matcher will receive two events:
// 1. EvMatcherNewItem, to reset the input strings
// 2. EvMatcherResetQuery, to interrupt current processing.
//
// will send two events:
// 1. EvMatcherUpdateProcess, to notify the matched/total items
// 2. EvMatcherFinished.

struct Matcher {
    tx_output: Sender<MatchedItem>,   // channel to send output to
    eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Arc<RwLock<Vec<Item>>>,
    item_pos: usize,
    num_matched: u64,
    query: String,
}

impl Matcher {
    pub fn new(items: Arc<RwLock<Vec<Item>>>, tx_output: Sender<MatchedItem>,
               eb_req: Arc<EventBox<Event>>, eb_notify: Arc<EventBox<Event>>) -> Self {
        Matcher {
            tx_output: tx_output,
            eb_req: eb_req,
            eb_notify: eb_notify,
            items: items,
            item_pos: 0,
            num_matched: 0,
            query: String::new(),
        }
    }

    fn match_str(&self, item: &str) -> bool {
        if self.query == "" {
            return true;
        }

        item.starts_with(&self.query)
    }

    pub fn process(&mut self) {
        let items = self.items.read().unwrap();
        for item in items[self.item_pos..].into_iter() {
            // process the matcher
            //self.tx_output.send(string.clone());
            if self.match_str(&item.text) {
                self.num_matched += 1;
                let _ = self.tx_output.send(MatchedItem::new(self.item_pos));
            }

            (*self.eb_notify).set(Event::EvMatcherUpdateProcess, Box::new((self.num_matched, items.len() as u64)));

            self.item_pos += 1;
            if (self.item_pos % 100) == 99 && !self.eb_req.is_empty() {
                break;
            }
        }
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.num_matched = 0;
        self.item_pos = 0;
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in (*self.eb_req).wait() {
                match e {
                    Event::EvMatcherNewItem => {}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            self.process()
        }
    }
}

//==============================================================================
// Input: fetch the query string, handle key event

struct Input {
    query: Vec<char>,
    index: usize, // index in chars
    pos: usize, // position in bytes
    eb: Arc<EventBox<Event>>,
}

impl Input {
    pub fn new(eb: Arc<EventBox<Event>>) -> Self {
        Input {
            query: Vec::new(),
            index: 0,
            pos: 0,
            eb: eb,
        }
    }

    fn get_query(&self) -> String {
        self.query.iter().cloned().collect::<String>()
    }

    fn add_char (&mut self, ch: char) {
        self.query.insert(self.index, ch);
        self.index += 1;
        self.pos += if ch.len_utf8() > 1 {2} else {1};
    }

    fn delete_char(&mut self) {
        if self.index == 0 {
            return;
        }

        let ch = self.query.remove(self.index-1);
        self.index -= 1;
        self.pos -= if ch.len_utf8() > 1 {2} else {1};
    }

    pub fn run(&mut self) {
        loop {
            self.handle_char();
        }
    }

    // fetch input from curses and turn it into query.
    fn handle_char(&mut self) {
        let ch = wget_wch(stdscr);

        match ch {
            Some(WchResult::KeyCode(_)) => {
                // will later handle readline-like shortcuts
            }

            Some(WchResult::Char(c)) => {
                /* Enable attributes and output message. */
                let ch = char::from_u32(c as u32).expect("Invalid char");
                match ch {
                    '\x7F' => { // backspace
                        self.delete_char();
                        self.eb.set(Event::EvQueryChange, Box::new((self.get_query(), self.pos)));
                    }

                    '\x0A' => { // enter
                        self.eb.set(Event::EvInputSelect, Box::new(true));
                    }

                    '\x09' => { // tab
                        self.eb.set(Event::EvInputToggle, Box::new(true));
                    }

                    '\x10' => { // ctrl-p
                        self.eb.set(Event::EvInputUp, Box::new(true));
                    }

                    '\x0E' => { // ctrl-n
                        self.eb.set(Event::EvInputDown, Box::new(true));
                    }

                    ch => { // other characters
                        self.add_char(ch);
                        self.eb.set(Event::EvQueryChange, Box::new((self.get_query(), self.pos)));
                    }
                }
            }

            None => { }
        }
    }
}

//==============================================================================
// Reader: fetch a list of lines from stdin or command output

struct Reader {
    cmd: Option<&'static str>, // command to invoke
    eb: Arc<EventBox<Event>>,         // eventbox
    tx: Sender<Item>,    // sender to send the string read from command output
}

impl Reader {

    pub fn new(cmd: Option<&'static str>, eb: Arc<EventBox<Event>>, tx: Sender<Item>) -> Self {
        Reader{cmd: cmd, eb: eb, tx: tx}
    }

    // invoke find comand.
    fn get_command_output(&self) -> Result<Box<BufRead>, Box<Error>> {
        let command = try!(Command::new("sh")
                           .arg("-c")
                           .arg(self.cmd.unwrap_or("find ."))
                           .stdout(Stdio::piped())
                           .stderr(Stdio::null())
                           .spawn());
        let stdout = try!(command.stdout.ok_or("command output: unwrap failed".to_owned()));
        Ok(Box::new(BufReader::new(stdout)))
    }

    fn run(&mut self) {
        // check if the input is TTY
        let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

        let mut read;
        if istty {
            read = self.get_command_output().expect("command not found");
        } else {
            read = Box::new(BufReader::new(stdin()))
        };

        loop {
            let mut input = String::new();
            match read.read_line(&mut input) {
                Ok(n) => {
                    if n <= 0 { break; }

                    if input.ends_with("\n") {
                        input.pop();
                        if input.ends_with("\r") {
                            input.pop();
                        }
                    }
                    let _ = self.tx.send(Item::new(input));
                }
                Err(_err) => { break; }
            }
            self.eb.set(Event::EvReaderNewItem, Box::new(0));
        }
        self.eb.set(Event::EvReaderFinished, Box::new(0));
    }
}

//==============================================================================
// Model: data structure for display the result
struct Model {
    query: String,
    query_cursor: i32,  // > qu<query_cursor>ery
    num_matched: u64,
    num_total: u64,
    items: Arc<RwLock<Vec<Item>>>, // all items
    matched_items: Vec<MatchedItem>,
    item_cursor: usize, // the index of matched item currently highlighted.
    line_cursor: usize, // line No.
    item_start_pos: usize, // for screen scroll.
    max_y: i32,
    max_x: i32,
}

impl Model {
    pub fn new() -> Self {
        let mut max_y = 0;
        let mut max_x = 0;
        getmaxyx(stdscr, &mut max_y, &mut max_x);

        Model {
            query: String::new(),
            query_cursor: 0,
            num_matched: 0,
            num_total: 0,
            items: Arc::new(RwLock::new(Vec::new())),
            matched_items: Vec::new(),
            item_cursor: 0,
            line_cursor: (max_y - 3) as usize,
            item_start_pos: 0,
            max_y: max_y,
            max_x: max_x,
        }
    }

    pub fn output(&self) {
        let items = self.items.read().unwrap();
        for item in items.iter() {
            if item.selected {
                println!("{}", item.text);
            }
        }
        //println!("{:?}", items[self.matched_items[self.item_cursor].index].text);
        //items[self.matched_items[self.item_cursor].index].selected = s;
    }

    pub fn toggle_select(&self, selected: Option<bool>) {
        let mut items = self.items.write().unwrap();
        items[self.matched_items[self.item_cursor].index].toggle_select(selected);
    }

    pub fn update_query(&mut self, query: String, cursor: i32) {
        self.query = query;
        self.query_cursor = cursor;
    }

    pub fn update_process_info(&mut self, matched: u64, total: u64) {
        self.num_matched = matched;
        self.num_total = total;
    }

    pub fn push_item(&mut self, item: MatchedItem) {
        self.matched_items.push(item);
    }

    pub fn clear_items(&mut self) {
        self.matched_items.clear();
    }

    pub fn move_line_cursor(&mut self, diff: i32) {

        let y = self.line_cursor as i32 + diff;
        let item_y = cmp::max(0, self.item_cursor as i32 - diff);
        let screen_height = (self.max_y - 3) as usize;

        match y {
            y if y < 0 => {
                self.line_cursor = 0;
                self.item_cursor = cmp::min(item_y as usize, self.matched_items.len()-1);
                self.item_start_pos = self.item_cursor - screen_height;
            }

            y if y > screen_height as i32 => {
                self.line_cursor = screen_height;
                self.item_cursor = cmp::max(0, item_y as usize);
                self.item_start_pos = self.item_cursor;
            }

            y => {
                self.line_cursor = y as usize;
                self.item_cursor = item_y as usize;
            }
        }
    }

    pub fn print_query(&self) {
        // > query
        mv(self.max_y-1, 0);
        addstr("> ");
        addstr(&self.query);
        mv(self.max_y-1, self.query_cursor+2);
    }

    pub fn print_info(&self) {
        mv(self.max_y-2, 0);
        addstr(format!("  {}/{}", self.num_matched, self.num_total).as_str());
    }

    fn print_item(&self, item: &Item) {
        let shown_str: String = item.text.chars().take((self.max_x-1) as usize).collect();
        if item.selected {
            printw(">");
        } else {
            printw(" ");
        }

        addstr(&shown_str);
    }

    pub fn print_items(&self) {
        let items = self.items.read().unwrap();

        let mut y = self.max_y - 3;
        for matched in self.matched_items[self.item_start_pos..].into_iter() {
            mv(y, 0);
            let is_current_line = y == self.line_cursor as i32;

            if is_current_line {
                printw(">");
            } else {
                printw(" ");
            }

            self.print_item(&items[matched.index]);

            y -= 1;
            if y < 0 {
                break;
            }
        }
    }

    pub fn refresh(&self) {
        refresh();
    }

    pub fn display(&self) {
        erase();
        self.print_items();
        self.print_info();
        self.print_query();
        self.refresh();
    }
}

//==============================================================================
// Display: for printing the result

//==============================================================================

fn main() {
    // initialize ncurses
    let local_conf = LcCategory::all;
    setlocale(local_conf, "en_US.UTF-8"); // for showing wide characters
    initscr();
    raw();
    keypad(stdscr, true);
    noecho();

    let mut model = Model::new();

    let eb = Arc::new(EventBox::new());
    let (tx_source, rx_source) = channel();
    let (tx_matched, rx_matched) = channel();

    let eb_clone_reader = eb.clone();
    let mut reader = Reader::new(Some(&"find ."), eb_clone_reader, tx_source);

    let eb_matcher = Arc::new(EventBox::new());
    let eb_matcher_clone = eb_matcher.clone();
    let eb_clone_matcher = eb.clone();
    let items = model.items.clone();
    let mut matcher = Matcher::new(items, tx_matched, eb_matcher_clone, eb_clone_matcher);

    let eb_clone_input = eb.clone();
    let mut input = Input::new(eb_clone_input);

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

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

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

    'outer: loop {
        for (e, val) in eb.wait() {
            match e {
                Event::EvReaderNewItem | Event::EvReaderFinished => {
                    let mut items = model.items.write().unwrap();
                    while let Ok(string) = rx_source.try_recv() {
                        items.push(string);
                    }
                    eb_matcher.set(Event::EvMatcherNewItem, Box::new(true));
                }

                Event::EvMatcherUpdateProcess => {
                    let (matched, total) : (u64, u64) = *val.downcast().unwrap();
                    model.update_process_info(matched, total);

                    while let Ok(matched_item) = rx_matched.try_recv() {
                        model.push_item(matched_item);
                    }
                }

                Event::EvQueryChange => {
                    let (query, pos) : (String, usize) = *val.downcast().unwrap();
                    let modified = query != model.query;
                    model.update_query(query.clone(), pos as i32);

                    if modified {
                        model.clear_items();
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(model.query.clone()));
                    }
                }

                Event::EvInputSelect => {
                    // break out of the loop and output the selected item.
                    break 'outer;
                }

                Event::EvInputToggle => {
                    model.toggle_select(None);
                    model.move_line_cursor(1);
                }
                Event::EvInputUp=> {
                    model.move_line_cursor(-1);
                }
                Event::EvInputDown=> {
                    model.move_line_cursor(1);
                }

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

    endwin();
    model.output();
}
<|endoftext|>


<commit_before>extern crate orbclient;

use orbclient::window::EventIter;

use std::time::Instant;

struct Vertex {
    x: f32,
    y: f32
}

struct RenderContext {
    window: Box<orbclient::Window>,
    scan_buffer: Vec<u32> //TODO(dustin): do i need Vec<32> here? [i32]
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{scan_buffer: vec![0; (height * 2) as usize], window: orb_window}
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF000000 });
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn fill_convex_shape(&mut self, y_min: u32, y_max: u32) {

        for y_idx in y_min..y_max {
            let x_min = self.scan_buffer.get((y_idx * 2) as usize).unwrap().clone();
            let x_max = self.scan_buffer.get((y_idx * 2 + 1) as usize).unwrap().clone();

            for x_idx in x_min..x_max {
                self.window.pixel(x_idx as i32, y_idx as i32, orbclient::Color { data: 0xFFFFFFFF });
            }
        }
    }

    pub fn convert_triangle(&mut self, min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: i32) {
		self.convert_line(min_vert, max_vert, 0 + side);
		self.convert_line(min_vert, mid_vert, 1 - side);
		self.convert_line(mid_vert, max_vert, 1 - side);
	}

	fn convert_line(&mut self, min_vert: &Vertex, max_vert: &Vertex, side: i32) {
        let start_y = min_vert.y;
        let start_x = min_vert.x;
        let end_y = max_vert.y;
        let end_x = max_vert.x;

        let dist_y = end_y - start_y;
        let dist_x = end_x - start_x;

		if dist_y <= 0f32 {
			return;
		}

		let setp_x = dist_x as f32 / dist_y as f32;
		let mut current_x = start_x;

        for y_coord in start_y as i32..end_y as i32 {
            self.scan_buffer.insert((y_coord * 2 + side) as usize, current_x as u32);
            current_x += setp_x;
        }
	}

}

fn main() {

    let mut render_context = RenderContext::new(500, 400, "pixelcannon");
    let mut start = Instant::now();

    let min_vert = Vertex{x: 100f32, y: 50f32};
    let mid_vert = Vertex{x: 200f32, y: 200f32};
    let max_vert = Vertex{x: 70f32, y: 300f32};

    'event: loop {

        {
            let end = Instant::now();
            let delta = end.duration_since(start);
            let delta_ms = delta.as_secs() * 1000 + (delta.subsec_nanos() as u64)/1000000;
            start = Instant::now();
            // println!("{} ms", delta_ms);

            render_context.clear();
            render_context.convert_triangle(&min_vert, &mid_vert, &max_vert, 0);
            render_context.fill_convex_shape(50, 300);
            render_context.sync();
        }

        for orbital_event in render_context.events() {
            match orbital_event.to_option() {
                orbclient::EventOption::Quit(_quit_event) => break 'event,
                _ => (),
            };
        }

    }
}
<commit_msg>draw abitrary triangle<commit_after>extern crate orbclient;

use orbclient::window::EventIter;

use std::time::Instant;

struct Vertex {
    x: f32,
    y: f32
}

impl Vertex {
    pub fn calc_area(&self, v1: &Vertex, v2: &Vertex) -> f32 {

        let x1 = v1.x - self.x;
        let y1 = v1.y - self.y;
        let x2 = v2.x - self.x;
        let y2 = v2.y - self.y;

        (x1 * y2 - x2 * y1)
    }
}

struct RenderContext {
    window: Box<orbclient::Window>,
    scan_buffer: Vec<u32> //TODO(dustin): do i need Vec<32> here? [i32]
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{scan_buffer: vec![0; (height * 2) as usize], window: orb_window}
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF000000 });
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex) {

        let mut min_vert = &v1;
        let mut mid_vert = &v2;
        let mut max_vert = &v3;

        if max_vert.y < mid_vert.y {
            let tmp = max_vert;
            max_vert = mid_vert;
            mid_vert = tmp;
        }

        if mid_vert.y < min_vert.y {
            let tmp = mid_vert;
            mid_vert = min_vert;
            min_vert = tmp;
        }

        if max_vert.y < mid_vert.y {
            let tmp = max_vert;
            max_vert = mid_vert;
            mid_vert = tmp;
        }

        let area = min_vert.calc_area(&max_vert, &mid_vert);
        let side = if area >= 0f32 { 1 } else { 0 };
        self.convert_triangle(&min_vert, &mid_vert, &max_vert, side);
        self.fill_convex_shape(min_vert.y as u32, max_vert.y as u32);
    }

    fn fill_convex_shape(&mut self, y_min: u32, y_max: u32) {

        for y_idx in y_min..y_max {
            let x_min = self.scan_buffer.get((y_idx * 2) as usize).unwrap().clone();
            let x_max = self.scan_buffer.get((y_idx * 2 + 1) as usize).unwrap().clone();

            for x_idx in x_min..x_max {
                self.window.pixel(x_idx as i32, y_idx as i32, orbclient::Color { data: 0xFFFFFFFF });
            }
        }
    }

    fn convert_triangle(&mut self, min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: i32) {
		self.convert_line(min_vert, max_vert, 0 + side);
		self.convert_line(min_vert, mid_vert, 1 - side);
		self.convert_line(mid_vert, max_vert, 1 - side);
	}

	fn convert_line(&mut self, min_vert: &Vertex, max_vert: &Vertex, side: i32) {
        let start_y = min_vert.y;
        let start_x = min_vert.x;
        let end_y = max_vert.y;
        let end_x = max_vert.x;

        let dist_y = end_y - start_y;
        let dist_x = end_x - start_x;

		if dist_y <= 0f32 {
			return;
		}

		let setp_x = dist_x as f32 / dist_y as f32;
		let mut current_x = start_x;

        for y_coord in start_y as i32..end_y as i32 {
            self.scan_buffer.insert((y_coord * 2 + side) as usize, current_x as u32);
            current_x += setp_x;
        }
	}

}

fn main() {

    let mut render_context = RenderContext::new(500, 400, "pixelcannon");
    let mut start = Instant::now();

    let min_vert = Vertex{x: 100f32, y: 50f32};
    let mid_vert = Vertex{x: 200f32, y: 200f32};
    let max_vert = Vertex{x: 70f32, y: 300f32};

    'event: loop {

        {
            let end = Instant::now();
            let delta = end.duration_since(start);
            let delta_ms = delta.as_secs() * 1000 + (delta.subsec_nanos() as u64)/1000000;
            start = Instant::now();
            // println!("{} ms", delta_ms);

            render_context.clear();
            render_context.draw_triangle(&max_vert, &mid_vert, &min_vert);
            render_context.sync();
        }

        for orbital_event in render_context.events() {
            match orbital_event.to_option() {
                orbclient::EventOption::Quit(_quit_event) => break 'event,
                _ => (),
            };
        }

    }
}
<|endoftext|>


<commit_before>#![crate_name="orbclient"]
#![crate_type="lib"]
#![feature(alloc)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(const_ptr_null_mut)]
#![cfg_attr(feature="no_std", no_std)]

#![deny(warnings)]

extern crate alloc;
#[cfg(not(feature="no_std"))]
extern crate core;

pub static FONT: &'static [u8] = include_bytes!("../res/unifont.font");

pub use color::Color;
pub use event::*;
#[cfg(not(feature="no_std"))]
pub use sys::{get_display_size, EventIter, Window};
pub use graphicspath::GraphicsPath;
pub use renderer::Renderer;

pub mod color;
pub mod event;
pub mod graphicspath;
pub mod renderer;

#[derive(Clone, Copy, Debug)]
pub enum WindowFlag {
    Async,
    Back,
    Front,
    Resizable,
    Unclosable
}

#[cfg(all(not(feature="no_std"), target_os = "redox"))]
#[path="sys/orbital.rs"]
mod sys;

#[cfg(all(not(feature="no_std"), not(target_os = "redox")))]
#[path="sys/sdl2.rs"]
mod sys;
<commit_msg>Only add feature on non-redox targets<commit_after>#![crate_name="orbclient"]
#![crate_type="lib"]
#![feature(alloc)]
#![feature(asm)]
#![feature(const_fn)]
#![cfg_attr(all(not(feature="no_std"), not(target_os = "redox")), feature(const_ptr_null_mut))]
#![cfg_attr(feature="no_std", no_std)]

#![deny(warnings)]

extern crate alloc;
#[cfg(not(feature="no_std"))]
extern crate core;

pub static FONT: &'static [u8] = include_bytes!("../res/unifont.font");

pub use color::Color;
pub use event::*;
#[cfg(not(feature="no_std"))]
pub use sys::{get_display_size, EventIter, Window};
pub use graphicspath::GraphicsPath;
pub use renderer::Renderer;

pub mod color;
pub mod event;
pub mod graphicspath;
pub mod renderer;

#[derive(Clone, Copy, Debug)]
pub enum WindowFlag {
    Async,
    Back,
    Front,
    Resizable,
    Unclosable
}

#[cfg(all(not(feature="no_std"), target_os = "redox"))]
#[path="sys/orbital.rs"]
mod sys;

#[cfg(all(not(feature="no_std"), not(target_os = "redox")))]
#[path="sys/sdl2.rs"]
mod sys;
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate getopts;
extern crate isatty;
extern crate regex;
extern crate walkdir;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::Write;
use std::path::Path;
use std::process;

use ansi_term::Colour;
use getopts::Options;
use isatty::stdout_isatty;
use regex::{Regex, RegexBuilder};
use walkdir::{WalkDir, DirEntry, WalkDirIterator};

/// Configuration options for *fd*.
struct FdOptions {
    case_sensitive: bool,
    search_full_path: bool,
    search_hidden: bool,
    follow_links: bool,
    colored: bool,
    max_depth: usize
}

/// The default maximum recursion depth.
const MAX_DEPTH_DEFAULT : usize = 25;

/// Print a search result to the console.
fn print_entry(entry: &DirEntry, path_rel: &Path, config: &FdOptions) {
    let path_str = match path_rel.to_str() {
        Some(p) => p,
        None    => return
    };

    if config.colored {
        let style = match entry {
            e if e.path_is_symbolic_link() => Colour::Purple,
            e if e.path().is_dir()         => Colour::Cyan,
            _                              => Colour::White
        };
        println!("{}", style.paint(path_str));
    } else {
        println!("{}", path_str);
    }
}

/// Check if filename of entry starts with a dot.
fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

/// Recursively scan the given root path and search for files / pathnames
/// matching the pattern.
fn scan(root: &Path, pattern: &Regex, config: &FdOptions) {
    let walker = WalkDir::new(root)
                     .follow_links(config.follow_links)
                     .max_depth(config.max_depth)
                     .into_iter()
                     .filter_entry(|e| config.search_hidden || !is_hidden(e))
                     .filter_map(|e| e.ok())
                     .filter(|e| e.path() != root);

    for entry in walker {
        let path_rel = match entry.path().strip_prefix(root) {
            Ok(p) => p,
            Err(_) => continue
        };

        let search_str =
            if config.search_full_path {
                path_rel.to_str()
            } else {
                if !path_rel.is_file() { continue }

                path_rel.file_name()
                        .and_then(OsStr::to_str)
            };

        search_str.and_then(|s| pattern.find(s))
                  .map(|_| print_entry(&entry, path_rel, &config));
    }
}

/// Print error message to stderr and exit with status `1`.
fn error(message: &str) -> ! {
    writeln!(&mut std::io::stderr(), "{}", message)
        .expect("Failed writing to stderr");
    process::exit(1);
}

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

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help message");
    opts.optflag("s", "sensitive",
                      "case-sensitive search (default: smart case)");
    opts.optflag("f", "filename",
                      "search filenames only (default: full path)");
    opts.optflag("H", "hidden",
                      "search hidden files/directories (default: off)");
    opts.optflag("F", "follow", "follow symlinks (default: off)");
    opts.optflag("n", "no-color", "do not colorize output (default: on)");
    opts.optopt("d", "max-depth",
                     format!("maximum search depth (default: {})",
                             MAX_DEPTH_DEFAULT).as_str(),
                     "D");

    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(e) => error(e.description())
    };

    if matches.opt_present("h") {
        let brief = "Usage: fd [options] [PATTERN]";
        print!("{}", opts.usage(&brief));
        process::exit(1);
    }

    let empty = String::new();
    let pattern = matches.free.get(0).unwrap_or(&empty);

    let current_dir_buf = match env::current_dir() {
        Ok(cd) => cd,
        Err(_) => error("Could not get current directory!")
    };
    let current_dir = current_dir_buf.as_path();

    let config = FdOptions {
        // The search will be case-sensitive if the command line flag is set or
        // if the pattern has an uppercase character (smart case).
        case_sensitive:    matches.opt_present("sensitive") ||
                           pattern.chars().any(char::is_uppercase),
        search_full_path: !matches.opt_present("filename"),
        search_hidden:     matches.opt_present("hidden"),
        colored:          !matches.opt_present("no-color") &&
                           stdout_isatty(),
        follow_links:      matches.opt_present("follow"),
        max_depth:
            matches.opt_str("max-depth")
                   .and_then(|ds| usize::from_str_radix(&ds, 10).ok())
                   .unwrap_or(MAX_DEPTH_DEFAULT)
    };

    match RegexBuilder::new(pattern)
              .case_insensitive(!config.case_sensitive)
              .build() {
        Ok(re)   => scan(&current_dir, &re, &config),
        Err(err) => error(err.description())
    }
}
<commit_msg>Colorize each path component, closes #19<commit_after>extern crate ansi_term;
extern crate getopts;
extern crate isatty;
extern crate regex;
extern crate walkdir;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::Write;
use std::path::{Path, Component};
use std::process;

use ansi_term::Colour;
use getopts::Options;
use isatty::stdout_isatty;
use regex::{Regex, RegexBuilder};
use walkdir::{WalkDir, DirEntry, WalkDirIterator};

/// Configuration options for *fd*.
struct FdOptions {
    case_sensitive: bool,
    search_full_path: bool,
    search_hidden: bool,
    follow_links: bool,
    colored: bool,
    max_depth: usize
}

/// The default maximum recursion depth.
const MAX_DEPTH_DEFAULT : usize = 25;

/// Print a search result to the console.
fn print_entry(path_root: &Path, path_entry: &Path, config: &FdOptions) {
    let path_full = path_root.join(path_entry);

    let path_str = match path_entry.to_str() {
        Some(p) => p,
        None    => return
    };

    if !config.colored {
        println!("{}", path_str);
    } else {
        let mut component_path = path_root.to_path_buf();

        // Traverse the path and colorize each component
        for component in path_entry.components() {
            let comp_str = match component {
                Component::Normal(p) => p,
                _                    => error("Unexpected path component")
            };

            component_path.push(Path::new(comp_str));

            let style =
                if component_path.symlink_metadata()
                                 .map(|md| md.file_type().is_symlink())
                                 .unwrap_or(false) {
                    Colour::Purple
                } else if component_path.is_dir() {
                    Colour::Cyan
                } else {
                    Colour::White
                };

            print!("{}", style.paint(comp_str.to_str().unwrap()));

            if component_path.is_dir() && component_path != path_full {
                let sep = std::path::MAIN_SEPARATOR.to_string();
                print!("{}", style.paint(sep));
            }
        }
        print!("\n");
    }
}

/// Check if filename of entry starts with a dot.
fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

/// Recursively scan the given root path and search for files / pathnames
/// matching the pattern.
fn scan(root: &Path, pattern: &Regex, config: &FdOptions) {
    let walker = WalkDir::new(root)
                     .follow_links(config.follow_links)
                     .max_depth(config.max_depth)
                     .into_iter()
                     .filter_entry(|e| config.search_hidden || !is_hidden(e))
                     .filter_map(|e| e.ok())
                     .filter(|e| e.path() != root);

    for entry in walker {
        let path_rel = match entry.path().strip_prefix(root) {
            Ok(p) => p,
            Err(_) => continue
        };

        let search_str =
            if config.search_full_path {
                path_rel.to_str()
            } else {
                if !path_rel.is_file() { continue }

                path_rel.file_name()
                        .and_then(OsStr::to_str)
            };

        search_str.and_then(|s| pattern.find(s))
                  .map(|_| print_entry(&root, path_rel, &config));
    }
}

/// Print error message to stderr and exit with status `1`.
fn error(message: &str) -> ! {
    writeln!(&mut std::io::stderr(), "{}", message)
        .expect("Failed writing to stderr");
    process::exit(1);
}

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

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help message");
    opts.optflag("s", "sensitive",
                      "case-sensitive search (default: smart case)");
    opts.optflag("f", "filename",
                      "search filenames only (default: full path)");
    opts.optflag("H", "hidden",
                      "search hidden files/directories (default: off)");
    opts.optflag("F", "follow", "follow symlinks (default: off)");
    opts.optflag("n", "no-color", "do not colorize output (default: on)");
    opts.optopt("d", "max-depth",
                     format!("maximum search depth (default: {})",
                             MAX_DEPTH_DEFAULT).as_str(),
                     "D");

    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(e) => error(e.description())
    };

    if matches.opt_present("h") {
        let brief = "Usage: fd [options] [PATTERN]";
        print!("{}", opts.usage(&brief));
        process::exit(1);
    }

    let empty = String::new();
    let pattern = matches.free.get(0).unwrap_or(&empty);

    let current_dir_buf = match env::current_dir() {
        Ok(cd) => cd,
        Err(_) => error("Could not get current directory!")
    };
    let current_dir = current_dir_buf.as_path();

    let config = FdOptions {
        // The search will be case-sensitive if the command line flag is set or
        // if the pattern has an uppercase character (smart case).
        case_sensitive:    matches.opt_present("sensitive") ||
                           pattern.chars().any(char::is_uppercase),
        search_full_path: !matches.opt_present("filename"),
        search_hidden:     matches.opt_present("hidden"),
        colored:          !matches.opt_present("no-color") &&
                           stdout_isatty(),
        follow_links:      matches.opt_present("follow"),
        max_depth:
            matches.opt_str("max-depth")
                   .and_then(|ds| usize::from_str_radix(&ds, 10).ok())
                   .unwrap_or(MAX_DEPTH_DEFAULT)
    };

    match RegexBuilder::new(pattern)
              .case_insensitive(!config.case_sensitive)
              .build() {
        Ok(re)   => scan(&current_dir, &re, &config),
        Err(err) => error(err.description())
    }
}
<|endoftext|>


<commit_before>extern crate "dbus-rs" as dbus;

use std::os::args;
use dbus::{Connection, BusType, Message, MessageItem};

static DEST: &'static str = "org.kde.kdeconnect";
static PATH: &'static str = "/modules/kdeconnect";

fn get_ids(c: &Connection) -> Result<Vec<String>, &'static str> {
    let mut m = Message::new_method_call(DEST
                                         , PATH
                                         , [DEST, "daemon"].connect(".").as_slice()
                                         , "devices").unwrap();
    m.append_items(&[MessageItem::Bool(true)]); // onlyReachable
    m = c.send_with_reply_and_block(m, 1000).unwrap();
    let items = m.get_items();
    match items[0] {
        MessageItem::Array(_, 0) => Err("No reachable devices"),
        MessageItem::Array(ref a, _) => Ok(a.clone().into_iter().map(|e| match e {
            MessageItem::Str(s) => s,
            _ => unreachable!(),
        }).collect()),
        _ => unreachable!(),
    }
}

fn share_url(c: &Connection, id: &String, url: &String) {
    let mut m = Message::new_method_call(DEST
                                         , [PATH, "devices", id.as_slice(), "share"].connect("/").as_slice()
                                         , [DEST, "device.share"].connect(".").as_slice()
                                         , "shareUrl").unwrap();
    m.append_items(&[MessageItem::Str(url.clone())]);
    c.send_with_reply_and_block(m, 1000).unwrap();
}

fn main() {
    let mut urls = args();
    urls.remove(0);

    let ref c = Connection::get_private(BusType::Session).unwrap();
    let ids = get_ids(c).unwrap();
    for url in urls.iter() {
        for id in ids.iter() {
            share_url(c, id, url);
        }
    }
}
<commit_msg>clone each id string instead of the whole array<commit_after>extern crate "dbus-rs" as dbus;

use std::os::args;
use dbus::{Connection, BusType, Message, MessageItem};

static DEST: &'static str = "org.kde.kdeconnect";
static PATH: &'static str = "/modules/kdeconnect";

fn get_ids(c: &Connection) -> Result<Vec<String>, &'static str> {
    let mut m = Message::new_method_call(DEST
                                         , PATH
                                         , [DEST, "daemon"].connect(".").as_slice()
                                         , "devices").unwrap();
    m.append_items(&[MessageItem::Bool(true)]); // onlyReachable
    m = c.send_with_reply_and_block(m, 1000).unwrap();
    let items = m.get_items();
    match items[0] {
        MessageItem::Array(_, 0) => Err("No reachable devices"),
        MessageItem::Array(ref a, _) => Ok(a.iter().map(|&ref e| match *e {
            MessageItem::Str(ref s) => s.clone(),
            _ => unreachable!(),
        }).collect()),
        _ => unreachable!(),
    }
}

fn share_url(c: &Connection, id: &String, url: &String) {
    let mut m = Message::new_method_call(DEST
                                         , [PATH, "devices", id.as_slice(), "share"].connect("/").as_slice()
                                         , [DEST, "device.share"].connect(".").as_slice()
                                         , "shareUrl").unwrap();
    m.append_items(&[MessageItem::Str(url.clone())]);
    c.send_with_reply_and_block(m, 1000).unwrap();
}

fn main() {
    let mut urls = args();
    urls.remove(0);

    let ref c = Connection::get_private(BusType::Session).unwrap();
    let ids = get_ids(c).unwrap();
    for url in urls.iter() {
        for id in ids.iter() {
            share_url(c, id, url);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(collections, core, custom_attribute, plugin)]
#![plugin(secs)]

extern crate graphics;
extern crate id;
extern crate input;
extern crate opengl_graphics;
extern crate piston;
extern crate sdl2_window;
extern crate sprite;
extern crate time;
extern crate uuid;
extern crate tiled;

use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc;
use std::path::Path;

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

use graphics::Context;

use time::*;

use input::Button::{Keyboard};
use input::keyboard::Key;

use std::fs::File;

use sprite::*;

use tiled::parse as tiled_parse;

mod world;
mod player;
mod sprites;

/// TODO - level tiles should be entities
fn init_level() -> Vec<Sprite<Texture>> {
    let tmx_file = File::open(&Path::new("./assets/level.tmx")).unwrap();
    let map = tiled_parse(tmx_file).unwrap();

    println!("Map Loaded! Width: {}, Height: {}", map.width, map.height);

    // TODO - tileset-specific - keep in tile representation
    let mut tile_width = 32;
    let mut tile_height = 32;

    // Load tileset textures
    // TODO modify to handle tilesheets - need some representation of a texture subregion
    let mut tile_textures = Vec::new();
    for tileset in map.tilesets.iter() {
        for tileset_image in tileset.images.iter() {
            let path_string = format!("./assets/{}", tileset_image.source);
            let path = Path::new(&path_string[..]);
            let texture = Rc::new(Texture::from_path(&path).unwrap());
            tile_textures.push(texture);
        }
    }

    let mut tile_sprites = Vec::new();

    for layer in map.layers.iter() {
        for (column, tile_column) in layer.tiles.iter().enumerate() {
            for (row, tile) in tile_column.iter().enumerate() {

                if *tile < 1u32 {
                    continue;
                }

                let texture = &tile_textures[(tile - 1) as usize];
                let mut sprite = Sprite::from_texture(texture.clone());
                sprite.set_position((row * tile_width) as f64, (column * tile_height) as f64);
                tile_sprites.push(sprite);

                // TODO add physics for each tile ...

            }
        }
    }

    tile_sprites
}

fn spawn_player(data: &mut world::Components) -> world::Entity {

    let player_sprite_sheet = Rc::new(Texture::from_path(&Path::new("./assets/player.png")).unwrap());

    let walk_anim = world::SpriteAnimation {
        frames: vec![(0,0), (1,0), (2,0), (3,0)],
        frame_size: [32, 32],
        frame_duration: 0.25,
    };

    let walk_anim_aim_up = world::SpriteAnimation {
        frames: vec![(0,1), (1,1), (2,1), (3,1)],
        frame_size: [32, 32],
        frame_duration: 0.25,
    };

    let sprite_renderer = world::SpriteRenderer::from_texture_region(
        player_sprite_sheet.clone(),
        [0, 0, 32, 32],
    );

    let sprite_animator = world::SpriteAnimator {
        animation: walk_anim.clone(),
        start_time: time::precise_time_s(),
    };

    let player_controller = world::PlayerController { move_speed: 1.0 };

    // TODO physics

    world::Entity {
        position: Some(data.position.add(world::Position { x: 0.0, y: 0.0 })),
        sprite_renderer: Some(data.sprite_renderer.add(sprite_renderer)),
        sprite_animator: Some(data.sprite_animator.add(sprite_animator)),
        player_controller: Some(data.player_controller.add(player_controller)),
    }
}

fn main() {

    let (width, height) = (640, 480);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Space Roach Exterminator III".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut world = world::World::new();

    let level_sprites = init_level();
    let player_entity = spawn_player(&mut world.data);
    world.entities.push(player_entity);

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

    let mut control_state = world::ControlState {
        left: false,
        right: false,
        up: false,
        down: false,
    };

    let mut systems = vec![
        Box::new(player::PlayerSystem) as Box<world::System>,
        Box::new(sprites::SpriteSystem) as Box<world::System>,
    ];

    for e in piston::events(&window) {
        use piston::event::{ RenderEvent, PressEvent, ReleaseEvent };
        use world::System;

        e.press(|button| {
            match button {
                Keyboard(Key::Left) => control_state.left = true,
                Keyboard(Key::Right) => control_state.right = true,
                Keyboard(Key::Up) => control_state.up = true,
                Keyboard(Key::Down) => control_state.down = true,
                _ => {}
            }
        });

        e.release(|button| {
            match button {
                Keyboard(Key::Left) => control_state.left = false,
                Keyboard(Key::Right) => control_state.right = false,
                Keyboard(Key::Up) => control_state.up = false,
                Keyboard(Key::Down) => control_state.down = false,
                _ => {}
            }
        });

        // TODO where should this go?
        for system in systems.iter_mut() {
            system.update(&control_state, &mut world.data, &mut world.entities);
        }

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

            use graphics::*;

            gl.draw([0, 0, args.width as i32, args.height as i32], |context, mut gl| {
                graphics::clear([0.3, 0.3, 0.3, 1.0], gl);

                // TODO - need sprite sorting orders ..

                // Draw level
                for level_sprite in level_sprites.iter() {
                    level_sprite.draw(context.view, gl);
                }

                for system in systems.iter_mut() {
                    system.render(&context, &mut gl, &mut world.data, &mut world.entities);
                }
            });
        }
    }
}
<commit_msg>Level initiliation creates entity for each level tile<commit_after>#![feature(collections, core, custom_attribute, plugin)]
#![plugin(secs)]

extern crate graphics;
extern crate id;
extern crate input;
extern crate opengl_graphics;
extern crate piston;
extern crate sdl2_window;
extern crate sprite;
extern crate time;
extern crate uuid;
extern crate tiled;

use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc;
use std::path::Path;

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

use graphics::Context;

use time::*;

use input::Button::{Keyboard};
use input::keyboard::Key;

use std::fs::File;

use sprite::*;

use tiled::parse as tiled_parse;

mod world;
mod player;
mod sprites;

///
/// Load Tiled level, creating entities for each tile instance
///
fn init_level(data: &mut world::Components, entities: &mut Vec<world::Entity>) {

    let tmx_file = File::open(&Path::new("./assets/level.tmx")).unwrap();
    let map = tiled_parse(tmx_file).unwrap();

    println!("Map Loaded! Width: {}, Height: {}", map.width, map.height);

    // TODO - tileset-specific - keep in tile representation
    let mut tile_width = 32;
    let mut tile_height = 32;

    // Load tileset textures and create shared SpriteRenderer components for each
    // TODO modify to handle tilesheets - need some representation of a texture subregion
    // TODO is it OK for entities to share components? What happens when we destroy an entity?
    // Maybe just have multiple sprite renderers that share the same Sprite instance

    let mut sprite_renderer_ids = Vec::new();

    for tileset in map.tilesets.iter() {
        for tileset_image in tileset.images.iter() {
            let path_string = format!("./assets/{}", tileset_image.source);
            let path = Path::new(&path_string[..]);
            let texture = Rc::new(Texture::from_path(&path).unwrap());
            let sprite_renderer = world::SpriteRenderer::from_texture_region(
                texture.clone(),
                [0, 0, 32, 32],
            );
            sprite_renderer_ids.push(data.sprite_renderer.add(sprite_renderer));
        }
    }

    for layer in map.layers.iter() {
        for (column, tile_column) in layer.tiles.iter().enumerate() {
            for (row, tile) in tile_column.iter().enumerate() {

                if *tile < 1u32 {
                    continue;
                }

                let tile_entity = world::Entity {
                    position: Some(data.position.add(world::Position {
                        x: (row * tile_width) as f32,
                        y: (column * tile_height) as f32,
                    })),
                    sprite_renderer: Some(sprite_renderer_ids[(tile - 1) as usize]),
                    sprite_animator: None,
                    player_controller: None,

                };

                // TODO add collision for each tile ...

                entities.push(tile_entity);

            }
        }
    }
}

fn spawn_player(data: &mut world::Components) -> world::Entity {

    let player_sprite_sheet = Rc::new(Texture::from_path(&Path::new("./assets/player.png")).unwrap());

    let walk_anim = world::SpriteAnimation {
        frames: vec![(0,0), (1,0), (2,0), (3,0)],
        frame_size: [32, 32],
        frame_duration: 0.25,
    };

    let walk_anim_aim_up = world::SpriteAnimation {
        frames: vec![(0,1), (1,1), (2,1), (3,1)],
        frame_size: [32, 32],
        frame_duration: 0.25,
    };

    let sprite_renderer = world::SpriteRenderer::from_texture_region(
        player_sprite_sheet.clone(),
        [0, 0, 32, 32],
    );

    let sprite_animator = world::SpriteAnimator {
        animation: walk_anim.clone(),
        start_time: time::precise_time_s(),
    };

    let player_controller = world::PlayerController { move_speed: 1.0 };

    // TODO physics

    world::Entity {
        position: Some(data.position.add(world::Position { x: 0.0, y: 0.0 })),
        sprite_renderer: Some(data.sprite_renderer.add(sprite_renderer)),
        sprite_animator: Some(data.sprite_animator.add(sprite_animator)),
        player_controller: Some(data.player_controller.add(player_controller)),
    }
}

fn main() {

    let (width, height) = (640, 480);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Space Roach Exterminator III".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut world = world::World::new();

    init_level(&mut world.data, &mut world.entities);
    let player_entity = spawn_player(&mut world.data);
    world.entities.push(player_entity);

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

    let mut control_state = world::ControlState {
        left: false,
        right: false,
        up: false,
        down: false,
    };

    let mut systems: Vec<Box<world::System>> = vec![
        Box::new(player::PlayerSystem),
        Box::new(sprites::SpriteSystem),
    ];

    for e in piston::events(&window) {
        use piston::event::{ RenderEvent, PressEvent, ReleaseEvent };
        use world::System;

        e.press(|button| {
            match button {
                Keyboard(Key::Left) => control_state.left = true,
                Keyboard(Key::Right) => control_state.right = true,
                Keyboard(Key::Up) => control_state.up = true,
                Keyboard(Key::Down) => control_state.down = true,
                _ => {}
            }
        });

        e.release(|button| {
            match button {
                Keyboard(Key::Left) => control_state.left = false,
                Keyboard(Key::Right) => control_state.right = false,
                Keyboard(Key::Up) => control_state.up = false,
                Keyboard(Key::Down) => control_state.down = false,
                _ => {}
            }
        });

        // TODO where should this go?
        for system in systems.iter_mut() {
            system.update(&control_state, &mut world.data, &mut world.entities);
        }

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

            use graphics::*;

            gl.draw([0, 0, args.width as i32, args.height as i32], |context, mut gl| {
                graphics::clear([0.3, 0.3, 0.3, 1.0], gl);

                // TODO - probably want sprite sorting orders ..
                // Currently just draw in order of creation ..

                for system in systems.iter_mut() {
                    system.render(&context, &mut gl, &mut world.data, &mut world.entities);
                }
            });
        }
    }
}
<|endoftext|>


<commit_before>extern crate git2;

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

struct Program {
    repo: Repository,
}

fn get_branch_remote(reference: Reference) -> Oid {
    let b = Branch::wrap(reference);
    let upstream = match b.upstream() {
        Ok(u) => u,
        Err(e) => panic!("Failed to get upstream: {}.", e)
    };
    match upstream.get().target() {
        Some(o) => o,
        None => panic!("Failed to get oid of branch.")
    }
}

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

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

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

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

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

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

    fn get_current_branch_ahead_behind(&self) -> (usize, usize)  {
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            self.get_current_branch_remote_oid(),
        );
        match res {
            Ok(r) => r,
            Err(e) => panic!("failed to compute ahead/behind: {}", e)
        }
    }

    fn get_upstream_branch_ahead_behind(&self) -> (usize, usize)  {
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            get_ref_to_oid(self.find_upstream_repo_branch()),
        );
        match res {
            Ok(r) => r,
            // TODO: don't error, skip instead
            Err(e) => panic!("failed to compute ahead/behind: {}", e)
        }
    }

    fn find_upstream_repo_branch(&self) -> Reference {
        let us_branch_name = format!("{}{}", "upstream/", self.get_current_branch_name());
        match self.repo.find_branch(&us_branch_name, BranchType::Remote) {
            Ok(u) => u.into_reference(),
            // TODO: don't error, skip instead
            Err(e) => panic!("failed to find upstream repo: {}", e),
        }
    }

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

fn main() {
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => panic!("failed to open: {}", e),
    };
    let program = Program{ repo: repo };
    println!("{}", program.get_current_branch_name());
    let (ahead, behind) = program.get_current_branch_ahead_behind();
    println!("A: {}, B: {}", ahead, behind);
    // let (ahead, behind) = program.get_upstream_branch_ahead_behind();
    // TODO: skip if None
    // println!("U A: {}, B: {}", ahead, behind);
    let statuses = program.get_status();
    for s in statuses.iter() {
        let file_status = s.status();
        println!("{}", s.path().unwrap());
        if file_status.intersects(
            STATUS_WT_MODIFIED | STATUS_WT_DELETED | STATUS_WT_TYPECHANGE | STATUS_WT_RENAMED
        ) {
            println!("changes");
        };
        if file_status.contains(STATUS_WT_NEW) {
            println!("new files");
        };
        if file_status.intersects(
            STATUS_INDEX_MODIFIED | STATUS_INDEX_DELETED | STATUS_INDEX_TYPECHANGE | STATUS_INDEX_RENAMED | STATUS_INDEX_NEW
        ) {
            println!("index update");
        };
    }
}
<commit_msg>display repository state<commit_after>extern crate git2;

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

struct Program {
    repo: Repository,
}

fn get_branch_remote(reference: Reference) -> Oid {
    let b = Branch::wrap(reference);
    let upstream = match b.upstream() {
        Ok(u) => u,
        Err(e) => panic!("Failed to get upstream: {}.", e)
    };
    match upstream.get().target() {
        Some(o) => o,
        None => panic!("Failed to get oid of branch.")
    }
}

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

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

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

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

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

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

    fn get_current_branch_ahead_behind(&self) -> (usize, usize)  {
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            self.get_current_branch_remote_oid(),
        );
        match res {
            Ok(r) => r,
            Err(e) => panic!("failed to compute ahead/behind: {}", e)
        }
    }

    fn get_upstream_branch_ahead_behind(&self) -> (usize, usize)  {
        let res = self.repo.graph_ahead_behind(
            self.get_current_branch_oid(),
            get_ref_to_oid(self.find_upstream_repo_branch()),
        );
        match res {
            Ok(r) => r,
            // TODO: don't error, skip instead
            Err(e) => panic!("failed to compute ahead/behind: {}", e)
        }
    }

    fn find_upstream_repo_branch(&self) -> Reference {
        let us_branch_name = format!("{}{}", "upstream/", self.get_current_branch_name());
        match self.repo.find_branch(&us_branch_name, BranchType::Remote) {
            Ok(u) => u.into_reference(),
            // TODO: don't error, skip instead
            Err(e) => panic!("failed to find upstream repo: {}", e),
        }
    }

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

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

fn main() {
    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => panic!("failed to open: {}", e),
    };
    let program = Program{ repo: repo };
    println!("{}", program.get_current_branch_name());
    let (ahead, behind) = program.get_current_branch_ahead_behind();
    println!("A: {}, B: {}", ahead, behind);
    // let (ahead, behind) = program.get_upstream_branch_ahead_behind();
    // TODO: skip if None
    // println!("U A: {}, B: {}", ahead, behind);
    let statuses = program.get_status();
    for s in statuses.iter() {
        let file_status = s.status();
        println!("{}", s.path().unwrap());
        if file_status.intersects(
            STATUS_WT_MODIFIED | STATUS_WT_DELETED | STATUS_WT_TYPECHANGE | STATUS_WT_RENAMED
        ) {
            println!("changes");
        };
        if file_status.contains(STATUS_WT_NEW) {
            println!("new files");
        };
        if file_status.intersects(
            STATUS_INDEX_MODIFIED | STATUS_INDEX_DELETED | STATUS_INDEX_TYPECHANGE | STATUS_INDEX_RENAMED | STATUS_INDEX_NEW
        ) {
            println!("index update");
        };
    }
    println!("{:?}", program.get_repository_state());
}
<|endoftext|>


<commit_before>#![feature(old_io)]
#![feature(old_path)]

extern crate time;

use std::old_io::IoError;
use std::old_io::net::udp::UdpSocket;
use std::old_io::net::ip::{ Ipv4Addr, SocketAddr };
use std::result;
use time::Tm;
use std::old_io::net::pipe::UnixStream;

/// A type alias for `Result<(), IoError>`, the result of writing a log message
pub type Result = result::Result<(), IoError>;

/// Syslog Facilites as defined by [rfc5424](https://tools.ietf.org/html/rfc5424#page-10)
#[derive(Copy,Clone)]
pub enum Facility {
  KERN     = 0,
  USER     = 1 << 3,
  MAIL     = 2 << 3,
  DAEMON   = 3 << 3,
  AUTH     = 4 << 3,
  SYSLOG   = 5 << 3,
  LINEPTR  = 6 << 3,
  NEWS     = 7 << 3,
  UUCP     = 8 << 3,
  CLOCK    = 9 << 3,
  AUTHPRIV = 10 << 3,
  FTP      = 11 << 3,
  LOCAL0   = 16 << 3,
  LOCAL1   = 17 << 3,
  LOCAL2   = 18 << 3,
  LOCAL3   = 19 << 3,
  LOCAL4   = 20 << 3,
  LOCAL5   = 21 << 3,
  LOCAL6   = 22 << 3,
  LOCAL7   = 23 << 3
}

/// Syslog Severity as defined by [rfc5424](https://tools.ietf.org/html/rfc5424#page-11)
pub enum Severity {
  EMERGENCY,
  ALERT,
  CRITICAL,
  ERROR,
  WARNING,
  NOTICE,
  INFO,
  DEBUG
}

trait Transport {
  fn send(&mut self, line: &str) -> Result;
}

impl Transport for (UdpSocket, SocketAddr) {
  fn send(&mut self, line: &str) -> Result {
    self.0.send_to(line.as_bytes(), self.1)
  }
}

impl Transport for UnixStream {
  fn send(&mut self, line: &str) -> Result {
    self.write_line(line)
  }
}

/// A rust interface for Syslog, a standard unix system logging service
pub struct Syslog {
  /// A Syslog facility to target when logging
  facility: Facility,
  /// An optional tag append to Syslog messages
  tag: Option<String>,
  transport: Box<Transport>
}

impl Syslog {
   /// Factory for a Syslog appender that writes to
   /// remote Syslog daemon listening a SocketAddr
   pub fn udp(host: SocketAddr) -> Syslog {
     let socket =
       match UdpSocket::bind(SocketAddr { ip: Ipv4Addr(0,0,0,0), port: 0 }) {
         Err(e) => panic!("error binding to local addr {}", e),
         Ok(s) => s
       };
      let tup = (socket, host);
      Syslog {
        facility: Facility::USER,
        tag: None,
        transport: Box::new(tup)
      }
  }

  /// Factory for a Syslog appender that writes
  /// to a host-local Syslog daemon listening on a unix socket domain
  /// hosted at the given Path
  pub fn unix(path: Path) -> Syslog {
    let stream =
      match UnixStream::connect(&path) {
        Err(_) => panic!("failed to connect to socket"),
        Ok(s)  => s
      };
    Syslog {
      facility: Facility::USER,
      tag: None,
      transport: Box::new(stream)
    }
  }

  /// Returns a new Syslog appender, configured to append with
  /// the provided tag
  pub fn tag(self, tag: &str) -> Syslog {
    Syslog {
      facility: self.facility,
      tag: Some(tag.to_string()),
      transport: self.transport
    }
  }

  /// Returns a new Syslog appender configured to append with
  /// the provided Facility
  pub fn facility(self, facility: Facility) -> Syslog {
    Syslog {
      facility: facility,
      tag: self.tag,
      transport: self.transport
    }
  }

  pub fn debug(&mut self, msg: &str) -> Result {
    self.log(Severity::DEBUG, msg)
  }

  pub fn info(&mut self, msg: &str) -> Result {
    self.log(Severity::INFO, msg)
  }

  pub fn notice(&mut self, msg: &str) -> Result {
    self.log(Severity::NOTICE, msg)
  }

  pub fn warn(&mut self, msg: &str) -> Result {
    self.log(Severity::WARNING, msg)
  }

  pub fn err(&mut self, msg: &str) -> Result {
    self.log(Severity::ERROR, msg)
  }

  pub fn critical(&mut self, msg: &str) -> Result {
    self.log(Severity::CRITICAL, msg)
  }

  pub fn alert(&mut self, msg: &str) -> Result {
    self.log(Severity::ALERT, msg)
  }

  pub fn emergency(&mut self, msg: &str) -> Result {
    self.log(Severity::EMERGENCY, msg)
  }

  fn log(&mut self, severity: Severity,  msg: &str) -> Result {
    let formatted = Syslog::line(self.facility.clone(), severity, time::now(), msg);
    self.transport.send(&formatted)
  }

  fn line(facility: Facility, severity: Severity, timestamp: Tm, msg: &str) -> String {
    format!("<{:?}> {} {}", Syslog::priority(facility, severity), timestamp.rfc3339(), msg)
  }

  // computes the priority of a message based on a facility and severity
  fn priority(facility: Facility, severity: Severity) -> u8 {
    facility as u8 | severity as u8
  }
}

#[cfg(test)]
mod tests {
  use super::{Syslog, Facility, Severity};
  use time;
  #[test]
  fn test_syslog_line() {
    let ts = time::now();
    assert_eq!(Syslog::line(Facility::LOCAL0, Severity::INFO, ts, "yo"),
               format!("<134> {} yo", ts.rfc3339()));
  }
}
<commit_msg>local udp convenience<commit_after>#![feature(old_io)]
#![feature(old_path)]

extern crate time;

use std::old_io::IoError;
use std::old_io::net::udp::UdpSocket;
use std::old_io::net::ip::{ Ipv4Addr, SocketAddr };
use std::result;
use time::Tm;
use std::old_io::net::pipe::UnixStream;

/// A type alias for `Result<(), IoError>`, the result of writing a log message
pub type Result = result::Result<(), IoError>;

/// Syslog Facilites as defined by [rfc5424](https://tools.ietf.org/html/rfc5424#page-10)
#[derive(Copy,Clone)]
pub enum Facility {
  KERN     = 0,
  USER     = 1 << 3,
  MAIL     = 2 << 3,
  DAEMON   = 3 << 3,
  AUTH     = 4 << 3,
  SYSLOG   = 5 << 3,
  LINEPTR  = 6 << 3,
  NEWS     = 7 << 3,
  UUCP     = 8 << 3,
  CLOCK    = 9 << 3,
  AUTHPRIV = 10 << 3,
  FTP      = 11 << 3,
  LOCAL0   = 16 << 3,
  LOCAL1   = 17 << 3,
  LOCAL2   = 18 << 3,
  LOCAL3   = 19 << 3,
  LOCAL4   = 20 << 3,
  LOCAL5   = 21 << 3,
  LOCAL6   = 22 << 3,
  LOCAL7   = 23 << 3
}

/// Syslog Severity as defined by [rfc5424](https://tools.ietf.org/html/rfc5424#page-11)
pub enum Severity {
  EMERGENCY,
  ALERT,
  CRITICAL,
  ERROR,
  WARNING,
  NOTICE,
  INFO,
  DEBUG
}

trait Transport {
  fn send(&mut self, line: &str) -> Result;
}

impl Transport for (UdpSocket, SocketAddr) {
  fn send(&mut self, line: &str) -> Result {
    self.0.send_to(line.as_bytes(), self.1)
  }
}

impl Transport for UnixStream {
  fn send(&mut self, line: &str) -> Result {
    self.write_line(line)
  }
}

/// A rust interface for Syslog, a standard unix system logging service
pub struct Syslog {
  /// A Syslog facility to target when logging
  facility: Facility,
  /// An optional tag append to Syslog messages
  tag: Option<String>,
  transport: Box<Transport>
}

impl Syslog {
   /// Factory for a Syslog appender that writes to
   /// remote Syslog daemon listening a SocketAddr
   pub fn udp(host: SocketAddr) -> Syslog {
     let socket =
       match UdpSocket::bind(SocketAddr { ip: Ipv4Addr(0,0,0,0), port: 0 }) {
         Err(e) => panic!("error binding to local addr {}", e),
         Ok(s) => s
       };
      let tup = (socket, host);
      Syslog {
        facility: Facility::USER,
        tag: None,
        transport: Box::new(tup)
      }
  }

  /// Same as udp with providing local loopback address with the standard syslog port
  pub fn localudp() -> Syslog {
    Syslog::udp(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 514 })
  }

  /// Factory for a Syslog appender that writes
  /// to a host-local Syslog daemon listening on a unix socket domain
  /// hosted at the given Path
  pub fn unix(path: Path) -> Syslog {
    let stream =
      match UnixStream::connect(&path) {
        Err(_) => panic!("failed to connect to socket"),
        Ok(s)  => s
      };
    Syslog {
      facility: Facility::USER,
      tag: None,
      transport: Box::new(stream)
    }
  }

  /// Returns a new Syslog appender, configured to append with
  /// the provided tag
  pub fn tag(self, tag: &str) -> Syslog {
    Syslog {
      facility: self.facility,
      tag: Some(tag.to_string()),
      transport: self.transport
    }
  }

  /// Returns a new Syslog appender configured to append with
  /// the provided Facility
  pub fn facility(self, facility: Facility) -> Syslog {
    Syslog {
      facility: facility,
      tag: self.tag,
      transport: self.transport
    }
  }

  pub fn debug(&mut self, msg: &str) -> Result {
    self.log(Severity::DEBUG, msg)
  }

  pub fn info(&mut self, msg: &str) -> Result {
    self.log(Severity::INFO, msg)
  }

  pub fn notice(&mut self, msg: &str) -> Result {
    self.log(Severity::NOTICE, msg)
  }

  pub fn warn(&mut self, msg: &str) -> Result {
    self.log(Severity::WARNING, msg)
  }

  pub fn err(&mut self, msg: &str) -> Result {
    self.log(Severity::ERROR, msg)
  }

  pub fn critical(&mut self, msg: &str) -> Result {
    self.log(Severity::CRITICAL, msg)
  }

  pub fn alert(&mut self, msg: &str) -> Result {
    self.log(Severity::ALERT, msg)
  }

  pub fn emergency(&mut self, msg: &str) -> Result {
    self.log(Severity::EMERGENCY, msg)
  }

  fn log(&mut self, severity: Severity,  msg: &str) -> Result {
    let formatted = Syslog::line(self.facility.clone(), severity, time::now(), msg);
    self.transport.send(&formatted)
  }

  fn line(facility: Facility, severity: Severity, timestamp: Tm, msg: &str) -> String {
    format!("<{:?}> {} {}", Syslog::priority(facility, severity), timestamp.rfc3339(), msg)
  }

  // computes the priority of a message based on a facility and severity
  fn priority(facility: Facility, severity: Severity) -> u8 {
    facility as u8 | severity as u8
  }
}

#[cfg(test)]
mod tests {
  use super::{Syslog, Facility, Severity};
  use time;
  #[test]
  fn test_syslog_line() {
    let ts = time::now();
    assert_eq!(Syslog::line(Facility::LOCAL0, Severity::INFO, ts, "yo"),
               format!("<134> {} yo", ts.rfc3339()));
  }
}
<|endoftext|>


<commit_before>extern crate reqwest;
extern crate json;

mod bot;
mod message;
pub mod updater;

/// Construct an API URL with the base bot URL and an
/// array of strings which will construct the path.
fn construct_api_url(bot_url: &str, path: &[&str]) -> String {
    format!("{}/{}", bot_url, path.join("/"))
}
<commit_msg>Adding sub-struct modules.<commit_after>extern crate reqwest;
extern crate json;

mod bot;
mod message;
mod update;
pub mod updater;

/// Construct an API URL with the base bot URL and an
/// array of strings which will construct the path.
fn construct_api_url(bot_url: &str, path: &[&str]) -> String {
    format!("{}/{}", bot_url, path.join("/"))
}
<|endoftext|>


<commit_before>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate iron;
extern crate http;
#[phase(plugin, link)]
extern crate log;

use std::path::BytesContainer;
use std::str::from_utf8;

use iron::{Request, Response, ServeFile, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use http::server::request::AbsolutePath;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

impl Static {
    /// Create a new instance of `Static`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Middleware for Static {
    /// Serve static files.
    ///
    /// If a static file exists and can be read from, `enter` will serve it
    /// to the `Response` and `Unwind` the middleware stack.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.request_uri {
            AbsolutePath(ref path) => {
                debug!("Serving static file at {}{}.", from_utf8(self.root_path.container_as_bytes()).unwrap(), path);
                let mut relative_path = path.clone();
                let _ = relative_path.as_slice().slice_from(1u);
                match res.serve_file(&self.root_path.join(Path::new(relative_path.to_string()))) {
                    Ok(()) => { Unwind },
                    Err(_) => { Continue }
                }
            },
            _ => {
                Continue
            }
        }
    }
}
<commit_msg>(feat) Serve index.html.<commit_after>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate iron;
extern crate http;
#[phase(plugin, link)]
extern crate log;

use std::path::BytesContainer;
use std::str::from_utf8;

use iron::{Request, Response, ServeFile, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use http::server::request::AbsolutePath;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

impl Static {
    /// Create a new instance of `Static`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Middleware for Static {
    /// Serve static files.
    ///
    /// If a static file exists and can be read from, `enter` will serve it
    /// to the `Response` and `Unwind` the middleware stack.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.request_uri {
            AbsolutePath(ref path) => {
                debug!("Serving static file at {}{}.", from_utf8(self.root_path.container_as_bytes()).unwrap(), path);
                let mut relative_path = path.clone();
                if relative_path.eq(&"/".to_string()) {
                    relative_path = "index.html".to_string();
                } else {
                    let _ = relative_path.as_slice().slice_from(1u);
                }
                match res.serve_file(&self.root_path.join(Path::new(relative_path.to_string()))) {
                    Ok(()) => { Unwind },
                    Err(_) => { Continue }
                }
            },
            _ => {
                Continue
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use std::fs::File;
use std::process::{Command, Stdio};
use std::collections::BinaryHeap;
use std::fs;
use regex::Regex;
use std::io::{self, Read, Write};

#[derive(Debug)]
struct Testcase {
    input: String,
    output: String,
}

fn get_testcases() -> Result<Vec<Testcase>, io::Error> {
    let input_re = Regex::new(r"input.*").unwrap();
    let output_re = Regex::new(r"output.*").unwrap();

    let mut testcases = vec![];
    let mut inputs = BinaryHeap::new();
    let mut outputs = BinaryHeap::new();

    for entry in try!(fs::read_dir(".")) {
        let path = try!(entry);
        let path = path.path().into_os_string();
        if let Some(input) = input_re.captures(path.to_str().unwrap()) {
            inputs.push(input[0].to_string());
        }
        if let Some(output) = output_re.captures(path.to_str().unwrap()) {
            outputs.push(output[0].to_string());
        }
    }
    if inputs.len() != outputs.len() {
        return Err(io::Error::new(io::ErrorKind::Other, "mismatched input/output"));
    }
    while !inputs.is_empty() {
        testcases.push(Testcase {
            input: inputs.pop().unwrap(),
            output: outputs.pop().unwrap(),
        });
    }
    Ok(testcases)
}

fn run_testcase(binary: &str, testcase: &Testcase) -> Result<(), io::Error> {
    let process = Command::new(binary).stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    let mut f = File::open(&testcase.input)?;
    let mut inp = String::new();
    f.read_to_string(&mut inp)?;
    process.stdin.unwrap().write_all(inp.as_bytes())?;

    let mut outf = File::open(&testcase.output)?;
    let mut out_expected = String::new();
    outf.read_to_string(&mut out_expected)?;

    let mut out = String::new();
    process.stdout.unwrap().read_to_string(&mut out)?;
    if out == out_expected {
        Ok(())
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           format!("  Expected: '{}'
  Actual:   '{}'",
                                   out_expected,
                                   out)))
    }
}

fn main() {
    let binary = "./a.out";

    let mut failed_testcases = vec![];
    match get_testcases() {
        Ok(testcases) => {
            for testcase in testcases {
                match run_testcase(binary, &testcase) {
                    Ok(_) => print!("."),
                    Err(e) => {
                        failed_testcases.push((testcase, e));
                        print!("E");
                    }
                }
            }
            println!();
        }
        Err(e) => println!("{}", e),
    }
    if !failed_testcases.is_empty() {
        println!("Failed testcases:");
        for (testcase, e) in failed_testcases {
            println!("{:?}:\n{}\n", testcase, e);
        }
    } else {
        println!("OK");
    }
}
<commit_msg>Slightly cleaner error handling<commit_after>extern crate regex;

use std::fs::File;
use std::process::{Command, Stdio};
use std::collections::BinaryHeap;
use std::fs;
use regex::Regex;
use std::io::{self, Read, Write};

#[derive(Debug)]
struct Testcase {
    input: String,
    output: String,
}

enum Error {
    Io(io::Error),
    TooManyInputs,
    TooManyOutputs,
}

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

fn get_testcases() -> Result<Vec<Testcase>, Error> {
    let input_re = Regex::new(r"input.*").unwrap();
    let output_re = Regex::new(r"output.*").unwrap();

    let mut testcases = vec![];
    let mut inputs = BinaryHeap::new();
    let mut outputs = BinaryHeap::new();

    for entry in try!(fs::read_dir(".")) {
        let path = try!(entry);
        let path = path.path().into_os_string();
        if let Some(input) = input_re.captures(path.to_str().unwrap()) {
            inputs.push(input[0].to_string());
        }
        if let Some(output) = output_re.captures(path.to_str().unwrap()) {
            outputs.push(output[0].to_string());
        }
    }
    if inputs.len() < outputs.len() {
        return Err(Error::TooManyOutputs)
    } else if inputs.len() > outputs.len() {
        return Err(Error::TooManyInputs)
    }
    while !inputs.is_empty() {
        testcases.push(Testcase {
            input: inputs.pop().unwrap(),
            output: outputs.pop().unwrap(),
        });
    }
    Ok(testcases)
}

fn run_testcase(binary: &str, testcase: &Testcase) -> Result<(), io::Error> {
    let process = Command::new(binary).stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    let mut f = File::open(&testcase.input)?;
    let mut inp = String::new();
    f.read_to_string(&mut inp)?;
    process.stdin.unwrap().write_all(inp.as_bytes())?;

    let mut outf = File::open(&testcase.output)?;
    let mut out_expected = String::new();
    outf.read_to_string(&mut out_expected)?;

    let mut out = String::new();
    process.stdout.unwrap().read_to_string(&mut out)?;
    if out == out_expected {
        Ok(())
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           format!("  Expected: '{}'
  Actual:   '{}'",
                                   out_expected,
                                   out)))
    }
}

fn main() {
    let binary = "./a.out";

    let mut failed_testcases = vec![];
    match get_testcases() {
        Ok(testcases) => {
            for testcase in testcases {
                match run_testcase(binary, &testcase) {
                    Ok(_) => print!("."),
                    Err(e) => {
                        failed_testcases.push((testcase, e));
                        print!("E");
                    }
                }
            }
            println!();
        }
        Err(Error::Io(e)) => println!("I/O error: {}", e),
        Err(Error::TooManyInputs) => println!("There are more inputs than outputs"),
        Err(Error::TooManyOutputs) => println!("There are more outputs than inputs"),
    }
    if !failed_testcases.is_empty() {
        println!("Failed testcases:");
        for (testcase, e) in failed_testcases {
            println!("{:?}:\n{}\n", testcase, e);
        }
    } else {
        println!("OK");
    }
}
<|endoftext|>