<commit_before>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::env;
use std::fs::File;
use std::io::{self, Stdin, Stdout, Read, BufRead, BufReader, Error, ErrorKind, Write};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

const TAB_STOP: usize = 8;

#[derive(PartialEq, Clone, Copy)]
enum Key {
    Character(u8),
    ArrowLeft,
    ArrowRight,
    ArrowUp,
    ArrowDown,
    Delete,
    Home,
    End,
    PageUp,
    PageDown,
}

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct RawMode {
    orig_term: Termios,
}

struct Row {
    chars: String,
    render: String,
}

struct Editor {
    _mode: RawMode,
    cx: usize,
    cy: usize,
    rowoff: usize,
    coloff: usize,
    screenrows: usize,
    screencols: usize,
    rows: Option<Vec<Row>>,
    stdin: Stdin,
    stdout: Stdout,
}

impl RawMode {
    fn enable_raw_mode() -> io::Result<RawMode> {
        let mut term = Termios::from_fd(STDIN_FILENO)?;
        let mode = RawMode { orig_term: term };

        term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        term.c_oflag &= !OPOST;
        term.c_cflag |= CS8;
        term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
        term.c_cc[VMIN] = 0;
        term.c_cc[VTIME] = 1;

        tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
        Ok(mode)
    }
}

impl Drop for RawMode {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

impl Row {
    fn new<T>(s: T) -> Row
        where T: Into<String>
    {
        let chars = s.into();
        let mut idx = 0;
        let mut render = String::new();
        for ch in chars.chars() {
            if ch == '\t' {
                render.push(' ');
                idx += 1;
                while idx % TAB_STOP != 0 {
                    render.push(' ');
                    idx += 1;
                }
            } else {
                render.push(ch);
                idx += 1;
            }
        }
        Row { chars, render }
    }
}

fn read_non_blocking<R: Read>(r: &mut R, buf: &mut [u8]) -> usize {
    r.read(buf)
        .or_else(|e| if e.kind() == ErrorKind::WouldBlock {
                     Ok(0)
                 } else {
                     Err(e)
                 })
        .expect("read_non_blocking")
}

fn byte_slice(s: &str, offset: usize, max_len: usize) -> &[u8] {
    if s.len() > max_len + offset {
        s[offset..(max_len + offset)].as_bytes()
    } else if s.len() > offset {
        s[offset..].as_bytes()
    } else {
        s[0..0].as_bytes()
    }
}

fn editor_read_key(stdin: &mut Stdin) -> Key {
    let mut buf = [0; 1];
    loop {
        let n = read_non_blocking(stdin, &mut buf);
        if n == 1 {
            if buf[0] == b'\x1b' {
                let mut seq = [0; 2];
                let n = read_non_blocking(stdin, &mut seq);
                if n == 2 && seq[0] == b'[' {
                    if seq[1] >= b'0' && seq[1] <= b'9' {
                        let mut last = [0; 1];
                        let n = read_non_blocking(stdin, &mut last);
                        if n == 1 && last[0] == b'~' {
                            return match seq[1] {
                                       b'1' | b'7' => Key::Home,
                                       b'3' => Key::Delete,
                                       b'4' | b'8' => Key::End,
                                       b'5' => Key::PageUp,
                                       b'6' => Key::PageDown,
                                       _ => Key::Character(b'\x1b'),
                                   };
                        }
                    } else {
                        return match seq[1] {
                                   b'A' => Key::ArrowUp,
                                   b'B' => Key::ArrowDown,
                                   b'C' => Key::ArrowRight,
                                   b'D' => Key::ArrowLeft,
                                   b'H' => Key::Home,
                                   b'F' => Key::End,
                                   _ => Key::Character(b'\x1b'),
                               };
                    }
                } else if n == 2 && seq[0] == b'O' {
                    return match seq[1] {
                               b'H' => Key::Home,
                               b'F' => Key::End,
                               _ => Key::Character(b'\x1b'),
                           };
                }
                return Key::Character(b'\x1b');
            } else {
                return Key::Character(buf[0]);
            }
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize {
        ws_col: 0,
        ws_row: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"));
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

impl Editor {
    fn new() -> io::Result<Editor> {
        let mode = RawMode::enable_raw_mode()?;
        let (rows, cols) = get_window_size()?;
        let stdin = io::stdin();
        let stdout = io::stdout();
        Ok(Editor {
               _mode: mode,
               cx: 0,
               cy: 0,
               rowoff: 0,
               coloff: 0,
               screenrows: rows as usize,
               screencols: cols as usize,
               rows: None,
               stdin: stdin,
               stdout: stdout,
           })
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<()> {
        self.stdout.write_all(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }

    fn scroll(&mut self) {
        if self.cy < self.rowoff {
            self.rowoff = self.cy;
        }
        if self.cy >= self.rowoff + self.screenrows {
            self.rowoff = self.cy - self.screenrows + 1;
        }
        if self.cx < self.coloff {
            self.coloff = self.cx;
        }
        if self.cx >= self.coloff + self.screencols {
            self.coloff = (1 + self.cx) - self.screencols;
        }
    }

    fn numrows(&self) -> usize {
        self.rows.as_ref().map_or(0, |v| v.len())
    }

    fn draw_rows(&mut self) -> io::Result<()> {
        let numrows = self.numrows();
        for y in 0..(self.screenrows) {
            let filerow = y + self.rowoff;
            if filerow >= numrows {
                if self.rows.is_none() && y == self.screenrows / 3 {
                    let mut msg = format!("Kilo-rs editor -- version {}", VERSION);
                    msg.truncate(self.screencols);
                    let padding = (self.screencols - msg.len()) / 2;
                    if padding > 0 {
                        self.write(b"~")?;
                        for _ in 1..padding {
                            self.write(b" ")?;
                        }
                    }
                    self.write(msg.as_bytes())?;
                } else {
                    self.write(b"~")?;
                }
            } else {
                let rows = self.rows.as_ref().unwrap();
                self.stdout
                    .write_all(byte_slice(&rows[filerow].render, self.coloff, self.screencols))?;
            }

            self.write(b"\x1b[K")?;
            if y < self.screenrows - 1 {
                self.write(b"\r\n")?;
            }
        }
        Ok(())
    }

    fn refresh_screen(&mut self) -> io::Result<()> {
        self.scroll();

        self.write(b"\x1b[?25l")?;
        self.write(b"\x1b[H")?;

        self.draw_rows()?;

        let move_cursor = format!("\x1b[{};{}H",
                                  (self.cy - self.rowoff) + 1,
                                  (self.cx - self.coloff) + 1)
                .into_bytes();
        self.write(&move_cursor)?;

        self.write(b"\x1b[?25h")?;
        self.flush()
    }

    fn rowlen(&self, index: usize) -> usize {
        let row = self.rows.as_ref().and_then(|r| r.get(index));
        row.map_or(0, |r| r.chars.len())
    }

    fn move_cursor(&mut self, k: Key) {
        match k {
            Key::ArrowUp => {
                if self.cy > 0 {
                    self.cy -= 1;
                }
            }
            Key::ArrowDown => {
                if self.cy < self.numrows() {
                    self.cy += 1;
                }
            }
            Key::ArrowLeft => {
                if self.cx > 0 {
                    self.cx -= 1;
                } else if self.cy > 0 {
                    self.cy -= 1;
                    self.cx = self.rowlen(self.cy);
                }
            }
            Key::ArrowRight => {
                let row = self.rows.as_ref().and_then(|r| r.get(self.cy));
                let rowlen = row.map_or(0, |r| r.chars.len());
                if self.cx < rowlen {
                    self.cx += 1;
                } else if row.is_some() && self.cx == rowlen {
                    self.cx = 0;
                    self.cy += 1;
                }
            }
            _ => (),
        }

        let rowlen = self.rowlen(self.cy);
        if self.cx > rowlen {
            self.cx = rowlen;
        }
    }

    fn process_keypress(&mut self) -> bool {
        let c = editor_read_key(&mut self.stdin);

        match c {
            Key::Character(k) if k == ctrl_key!(b'q') => return false,
            Key::Home => {
                self.cx = 0;
            }
            Key::End => {
                self.cx = self.screencols - 1;
            }
            Key::PageUp | Key::PageDown => {
                let key = if c == Key::PageUp {
                    Key::ArrowUp
                } else {
                    Key::ArrowDown
                };
                for _ in 0..(self.screenrows) {
                    self.move_cursor(key);
                }
            }
            Key::ArrowUp | Key::ArrowDown | Key::ArrowLeft | Key::ArrowRight => {
                self.move_cursor(c);
            }
            _ => (),
        };
        true
    }

    fn open(&mut self, filename: &str) -> io::Result<()> {
        let f = File::open(filename)?;
        let file = BufReader::new(&f);
        let results: io::Result<Vec<Row>> = file.lines().map(|r| r.map(Row::new)).collect();
        self.rows = Some(results?);
        Ok(())
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        // clear screen
        self.stdout.write_all(b"\x1b[2J").unwrap();
        self.stdout.write_all(b"\x1b[H").unwrap();
        self.stdout.flush().unwrap();
    }
}

fn main() {
    let mut editor = Editor::new().unwrap();
    if let Some(filename) = env::args().nth(1) {
        editor.open(&filename).unwrap();
    }

    editor.refresh_screen().unwrap();
    while editor.process_keypress() {
        editor.refresh_screen().unwrap();
    }
}
<commit_msg>Tabs and the cursor<commit_after>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::env;
use std::fs::File;
use std::io::{self, Stdin, Stdout, Read, BufRead, BufReader, Error, ErrorKind, Write};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

const TAB_STOP: usize = 8;

#[derive(PartialEq, Clone, Copy)]
enum Key {
    Character(u8),
    ArrowLeft,
    ArrowRight,
    ArrowUp,
    ArrowDown,
    Delete,
    Home,
    End,
    PageUp,
    PageDown,
}

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct RawMode {
    orig_term: Termios,
}

struct Row {
    chars: String,
    render: String,
}

struct Editor {
    _mode: RawMode,
    cx: usize,
    cy: usize,
    rx: usize,
    rowoff: usize,
    coloff: usize,
    screenrows: usize,
    screencols: usize,
    rows: Option<Vec<Row>>,
    stdin: Stdin,
    stdout: Stdout,
}

impl RawMode {
    fn enable_raw_mode() -> io::Result<RawMode> {
        let mut term = Termios::from_fd(STDIN_FILENO)?;
        let mode = RawMode { orig_term: term };

        term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        term.c_oflag &= !OPOST;
        term.c_cflag |= CS8;
        term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
        term.c_cc[VMIN] = 0;
        term.c_cc[VTIME] = 1;

        tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
        Ok(mode)
    }
}

impl Drop for RawMode {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

impl Row {
    fn new<T>(s: T) -> Row
        where T: Into<String>
    {
        let chars = s.into();
        let mut idx = 0;
        let mut render = String::new();
        for ch in chars.chars() {
            if ch == '\t' {
                render.push(' ');
                idx += 1;
                while idx % TAB_STOP != 0 {
                    render.push(' ');
                    idx += 1;
                }
            } else {
                render.push(ch);
                idx += 1;
            }
        }
        Row { chars, render }
    }

    fn cx_to_rx(&self, cx: usize) -> usize {
        let mut rx = 0;
        for ch in self.chars.chars().take(cx) {
            if ch == '\t' {
                rx += (TAB_STOP - 1) - (rx % TAB_STOP);
            }
            rx += 1;
        }
        rx
    }
}

fn read_non_blocking<R: Read>(r: &mut R, buf: &mut [u8]) -> usize {
    r.read(buf)
        .or_else(|e| if e.kind() == ErrorKind::WouldBlock {
                     Ok(0)
                 } else {
                     Err(e)
                 })
        .expect("read_non_blocking")
}

fn byte_slice(s: &str, offset: usize, max_len: usize) -> &[u8] {
    if s.len() > max_len + offset {
        s[offset..(max_len + offset)].as_bytes()
    } else if s.len() > offset {
        s[offset..].as_bytes()
    } else {
        s[0..0].as_bytes()
    }
}

fn editor_read_key(stdin: &mut Stdin) -> Key {
    let mut buf = [0; 1];
    loop {
        let n = read_non_blocking(stdin, &mut buf);
        if n == 1 {
            if buf[0] == b'\x1b' {
                let mut seq = [0; 2];
                let n = read_non_blocking(stdin, &mut seq);
                if n == 2 && seq[0] == b'[' {
                    if seq[1] >= b'0' && seq[1] <= b'9' {
                        let mut last = [0; 1];
                        let n = read_non_blocking(stdin, &mut last);
                        if n == 1 && last[0] == b'~' {
                            return match seq[1] {
                                       b'1' | b'7' => Key::Home,
                                       b'3' => Key::Delete,
                                       b'4' | b'8' => Key::End,
                                       b'5' => Key::PageUp,
                                       b'6' => Key::PageDown,
                                       _ => Key::Character(b'\x1b'),
                                   };
                        }
                    } else {
                        return match seq[1] {
                                   b'A' => Key::ArrowUp,
                                   b'B' => Key::ArrowDown,
                                   b'C' => Key::ArrowRight,
                                   b'D' => Key::ArrowLeft,
                                   b'H' => Key::Home,
                                   b'F' => Key::End,
                                   _ => Key::Character(b'\x1b'),
                               };
                    }
                } else if n == 2 && seq[0] == b'O' {
                    return match seq[1] {
                               b'H' => Key::Home,
                               b'F' => Key::End,
                               _ => Key::Character(b'\x1b'),
                           };
                }
                return Key::Character(b'\x1b');
            } else {
                return Key::Character(buf[0]);
            }
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize {
        ws_col: 0,
        ws_row: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"));
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

impl Editor {
    fn new() -> io::Result<Editor> {
        let mode = RawMode::enable_raw_mode()?;
        let (rows, cols) = get_window_size()?;
        let stdin = io::stdin();
        let stdout = io::stdout();
        Ok(Editor {
               _mode: mode,
               cx: 0,
               cy: 0,
               rx: 0,
               rowoff: 0,
               coloff: 0,
               screenrows: rows as usize,
               screencols: cols as usize,
               rows: None,
               stdin: stdin,
               stdout: stdout,
           })
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<()> {
        self.stdout.write_all(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }

    fn scroll(&mut self) {
        self.rx = self.cx;
        if self.cy < self.numrows() {
            self.rx = self.rows.as_ref().unwrap()[self.cy].cx_to_rx(self.cx);
        }

        if self.cy < self.rowoff {
            self.rowoff = self.cy;
        }
        if self.cy >= self.rowoff + self.screenrows {
            self.rowoff = self.cy - self.screenrows + 1;
        }
        if self.rx < self.coloff {
            self.coloff = self.rx;
        }
        if self.rx >= self.coloff + self.screencols {
            self.coloff = (1 + self.rx) - self.screencols;
        }
    }

    fn numrows(&self) -> usize {
        self.rows.as_ref().map_or(0, |v| v.len())
    }

    fn draw_rows(&mut self) -> io::Result<()> {
        let numrows = self.numrows();
        for y in 0..(self.screenrows) {
            let filerow = y + self.rowoff;
            if filerow >= numrows {
                if self.rows.is_none() && y == self.screenrows / 3 {
                    let mut msg = format!("Kilo-rs editor -- version {}", VERSION);
                    msg.truncate(self.screencols);
                    let padding = (self.screencols - msg.len()) / 2;
                    if padding > 0 {
                        self.write(b"~")?;
                        for _ in 1..padding {
                            self.write(b" ")?;
                        }
                    }
                    self.write(msg.as_bytes())?;
                } else {
                    self.write(b"~")?;
                }
            } else {
                let rows = self.rows.as_ref().unwrap();
                self.stdout
                    .write_all(byte_slice(&rows[filerow].render, self.coloff, self.screencols))?;
            }

            self.write(b"\x1b[K")?;
            if y < self.screenrows - 1 {
                self.write(b"\r\n")?;
            }
        }
        Ok(())
    }

    fn refresh_screen(&mut self) -> io::Result<()> {
        self.scroll();

        self.write(b"\x1b[?25l")?;
        self.write(b"\x1b[H")?;

        self.draw_rows()?;

        let move_cursor = format!("\x1b[{};{}H",
                                  (self.cy - self.rowoff) + 1,
                                  (self.rx - self.coloff) + 1)
                .into_bytes();
        self.write(&move_cursor)?;

        self.write(b"\x1b[?25h")?;
        self.flush()
    }

    fn rowlen(&self, index: usize) -> usize {
        let row = self.rows.as_ref().and_then(|r| r.get(index));
        row.map_or(0, |r| r.chars.len())
    }

    fn move_cursor(&mut self, k: Key) {
        match k {
            Key::ArrowUp => {
                if self.cy > 0 {
                    self.cy -= 1;
                }
            }
            Key::ArrowDown => {
                if self.cy < self.numrows() {
                    self.cy += 1;
                }
            }
            Key::ArrowLeft => {
                if self.cx > 0 {
                    self.cx -= 1;
                } else if self.cy > 0 {
                    self.cy -= 1;
                    self.cx = self.rowlen(self.cy);
                }
            }
            Key::ArrowRight => {
                let row = self.rows.as_ref().and_then(|r| r.get(self.cy));
                let rowlen = row.map_or(0, |r| r.chars.len());
                if self.cx < rowlen {
                    self.cx += 1;
                } else if row.is_some() && self.cx == rowlen {
                    self.cx = 0;
                    self.cy += 1;
                }
            }
            _ => (),
        }

        let rowlen = self.rowlen(self.cy);
        if self.cx > rowlen {
            self.cx = rowlen;
        }
    }

    fn process_keypress(&mut self) -> bool {
        let c = editor_read_key(&mut self.stdin);

        match c {
            Key::Character(k) if k == ctrl_key!(b'q') => return false,
            Key::Home => {
                self.cx = 0;
            }
            Key::End => {
                self.cx = self.screencols - 1;
            }
            Key::PageUp | Key::PageDown => {
                let key = if c == Key::PageUp {
                    Key::ArrowUp
                } else {
                    Key::ArrowDown
                };
                for _ in 0..(self.screenrows) {
                    self.move_cursor(key);
                }
            }
            Key::ArrowUp | Key::ArrowDown | Key::ArrowLeft | Key::ArrowRight => {
                self.move_cursor(c);
            }
            _ => (),
        };
        true
    }

    fn open(&mut self, filename: &str) -> io::Result<()> {
        let f = File::open(filename)?;
        let file = BufReader::new(&f);
        let results: io::Result<Vec<Row>> = file.lines().map(|r| r.map(Row::new)).collect();
        self.rows = Some(results?);
        Ok(())
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        // clear screen
        self.stdout.write_all(b"\x1b[2J").unwrap();
        self.stdout.write_all(b"\x1b[H").unwrap();
        self.stdout.flush().unwrap();
    }
}

fn main() {
    let mut editor = Editor::new().unwrap();
    if let Some(filename) = env::args().nth(1) {
        editor.open(&filename).unwrap();
    }

    editor.refresh_screen().unwrap();
    while editor.process_keypress() {
        editor.refresh_screen().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate rustbox;

use regex::Regex;
use rustbox::{Color, RustBox};
use rustbox::Key;
use std::io;
use std::io::BufRead;

fn main() {
    let stdin = io::stdin();
    let all_lines: Vec<String> = read_stdin(stdin);

    let mut matches: Vec<&String> = Vec::new();
    let mut input: String = String::new();

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

    loop {
        matches.clear();
        find_matches(input.clone(), &all_lines, &mut matches);
        render_lines(&rustbox, input.clone(), &matches);

        match rustbox.poll_event(false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Some(Key::Enter) => {
                        print!("{}", matches.first().unwrap());
                        break;
                    },
                    Some(Key::Esc) => { break; },
                    Some(Key::Backspace) => {
                        input.pop();
                    },
                    Some(Key::Char(character)) => {
                        input = format!("{}{}", input, character)
                    },
                    _ => { }
                }
            },

            Err(e) => panic!("{}", e),

            _ => { }
        }
    }
}

fn read_stdin(stdin: io::Stdin) -> Vec<String> {
    stdin.lock().lines().map(|line| {
        line.unwrap().trim().to_string()
    }).collect()
}

fn find_matches<'a>(search: String, base: &'a Vec<String>, matches: &mut Vec<&'a String>) {
    let regex_string: String = search.split("").fold(String::new(), |acc, input| {
        acc + ".*" + input
    });

    let re = Regex::new(&regex_string).unwrap();

    for line in base {
        if re.is_match(&line) {
            matches.push(&line)
        }
    }
}

fn render_lines(rustbox: &RustBox, search_string: String, matches: &Vec<&String>) {
    rustbox.clear();

    rustbox.print(1, 0, rustbox::RB_BOLD, Color::White, Color::Black, &search_string);

    let mut index = 1;
    for line in matches {
        rustbox.print(1, index, rustbox::RB_NORMAL, Color::White, Color::Black, &line);
        index += 1;
    }

    rustbox.present();
}
<commit_msg>Add ability to select match<commit_after>extern crate regex;
extern crate rustbox;

use regex::Regex;
use rustbox::{Color, RustBox};
use rustbox::Key;
use std::io;
use std::io::BufRead;

fn main() {
    let stdin = io::stdin();
    let all_lines: Vec<String> = read_stdin(stdin);

    let mut matches: Vec<&String> = Vec::new();
    let mut input: String = String::new();
    let mut selection: usize = 1;

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

    find_matches(input.clone(), &all_lines, &mut matches);
    render_lines(&rustbox, input.clone(), &matches, selection);

    loop {
        match rustbox.poll_event(false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Some(Key::Enter) => {
                        print!("{}", matches.get(selection - 1).unwrap());
                        break;
                    },
                    Some(Key::Esc) => { break; },
                    Some(Key::Backspace) => {
                        input.pop();
                    },
                    Some(Key::Down) => {
                        if selection != rustbox.height() && selection != matches.len() {
                            selection += 1
                        }
                    },
                    Some(Key::Up) => {
                        if selection != 1 {
                            selection -= 1
                        }
                    },
                    Some(Key::Char(character)) => {
                        input = format!("{}{}", input, character)
                    },
                    _ => { }
                }
            },

            Err(e) => panic!("{}", e),

            _ => { }
        }

        matches.clear();
        find_matches(input.clone(), &all_lines, &mut matches);

        let count = matches.len();
        if selection > count && count != 0 {
            selection = matches.len();
        }

        render_lines(&rustbox, input.clone(), &matches, selection);
    }
}

fn read_stdin(stdin: io::Stdin) -> Vec<String> {
    stdin.lock().lines().map(|line| {
        line.unwrap().trim().to_string()
    }).collect()
}

fn find_matches<'a>(search: String, base: &'a Vec<String>, matches: &mut Vec<&'a String>) {
    let regex_string: String = search.split("").fold(String::new(), |acc, input| {
        acc + ".*" + input
    });

    let re = Regex::new(&regex_string).unwrap();

    for line in base {
        if re.is_match(&line) {
            matches.push(&line)
        }
    }
}

fn render_lines(rustbox: &RustBox, search_string: String, matches: &Vec<&String>, selection: usize) {
    rustbox.clear();

    let search_box_text = format!("> {}", search_string);
    rustbox.print(1, 0, rustbox::RB_BOLD, Color::White, Color::Black, &search_box_text);

    let mut index = 1;
    for line in matches {
        if index == selection {
            rustbox.print(0, index, rustbox::RB_BOLD, Color::Red, Color::Black, ">");
            rustbox.print(2, index, rustbox::RB_BOLD, Color::Red, Color::Black, &line);
        } else {
            rustbox.print(2, index, rustbox::RB_NORMAL, Color::White, Color::Black, &line);
        }
        index += 1;
    }

    rustbox.present();
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{Arg, App, Error};

mod workfile;
mod srt;
mod txt_rep;
mod rules;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

///////////////////////////////////////////////////////////////////////////////
fn do_replacements(subtitles: &mut Vec<srt::Subtitle>, language: &str) {

	for subtitle in subtitles.iter_mut() {
		for text_index in 0..subtitle.text_count as usize {
			subtitle.texts[text_index] = txt_rep::replace_one(&subtitle.texts[text_index], &language);
		}
		//print!("{}", subtitle.to_string());
	}
}

fn do_time_changes(subtitles: &mut Vec<srt::Subtitle>,
                   time_shift_ms: i32, time_stretch_ms: i32) {

	if time_shift_ms == 0 && time_stretch_ms == 0 {
		return;
	}
	let sub_count = subtitles.len();
	if sub_count == 0 {
		return;
	}

	if sub_count > std::i32::MAX as usize {
		eprintln!("Too many subtitles");
		return;
	};

	// Compute the limit for stretching
	let sub_count_i32 = if srt::should_keep_last_sub(subtitles) {
		sub_count as i32
	}
	else {
		println!("last not kept");
		(sub_count - 1) as i32
	};

	let mut sub_index = 0;
	for subtitle in subtitles.iter_mut() {

		subtitle.time_from += time_shift_ms;
		subtitle.time_to += time_shift_ms;

		if time_stretch_ms > 0 && sub_count_i32 > 1 && sub_index < sub_count_i32 {
			let stretching = (sub_index * time_stretch_ms) / (sub_count_i32 - 1);
			subtitle.time_from += stretching;
			subtitle.time_to += stretching;
		}
		sub_index += 1;
	}
}

///////////////////////////////////////////////////////////////////////////////
fn main() {
	let matches = App::new("fixsrt")
		.version(VERSION)
		.author("Hadrien Nilsson")
		.about("Fix spelling and encoding mistakes in SRT subtitle files")
		.arg(Arg::with_name("nobak")
			.long("nobak")
			.help("Avoids creating a backup file"))
		.arg(Arg::with_name("SRTFILE")
			.required(true)
			.multiple(true)
			.help("SRT file to update"))
		.arg(Arg::with_name("out")
			.short("o")
			.long("out")
			.takes_value(true)
			.help("Outputs to another file (single input only)"))
		.arg(Arg::with_name("shift")
			.long("shift")
			.takes_value(true)
			.help("Shifts all subtitles of several seconds"))
		.arg(Arg::with_name("stretch")
			.long("stretch")
			.takes_value(true)
			.help("Stretches all subtitles after adding several seconds to the last one"))
		.arg(Arg::with_name("lang")
			.long("lang")
			.takes_value(true)
			.help("Selects the language of the SRT file(s) (fr/en)"))
		.get_matches();

	let no_backup = matches.is_present("nobak");
	let in_file_paths: Vec<_> = matches.values_of("SRTFILE").unwrap().collect();
	let out_file_path = matches.value_of("out");
	let time_shift_ms = match matches.value_of("shift") {
		Some(tos) => match srt::parse_srt_time(tos) {
			Some(tos_ms) => tos_ms,
			None => {
				let err = Error { message: "--shift invalid argument".into(),
					kind: clap::ErrorKind::TooManyValues,
					info: None };
				err.exit();
			}
		},
		None => 0
	};
	let time_stretch_ms = match matches.value_of("stretch") {
		Some(tos) => match srt::parse_srt_time(tos) {
			Some(tos_ms) => tos_ms,
			None => {
				let err = Error { message: "--stretch invalid argument".into(),
					kind: clap::ErrorKind::TooManyValues,
					info: None };
				err.exit();
			}
		},
		None => 0
	};
	let language = matches.value_of("lang").unwrap_or("fr");

	if language != "en" && language != "fr" {
		println!("Bad language");
		std::process::exit(1);
	}

	// Additional check. Is there a way to do it with clap?
	if out_file_path.is_some() && in_file_paths.len() > 1 {
		let err = Error { message: "--out works only with single input".into(),
			kind: clap::ErrorKind::TooManyValues,
			info: None};
		err.exit();
	}

	/////////////////////////////////////////////////////////////////
	for in_file_path in in_file_paths {
		print!("{} ... ", in_file_path);

		let subtitles_res = srt::load_subtitles(&in_file_path);
		match subtitles_res {
			Ok(_) => (),
			Err(ref err) => {
				println!("{}", err);
				std::process::exit(1);
			}
		}

		let mut subtitles = subtitles_res.unwrap();
		do_replacements(&mut subtitles, &language);
		do_time_changes(&mut subtitles, time_shift_ms, time_stretch_ms);

		// Do backup
		if !no_backup {
			let backup_file_path = format!("{}~", in_file_path);
			match std::fs::copy(&in_file_path, &backup_file_path) {
				Ok(_) => (),
				Err(err) => println!("Cannot create backup: {}", err)
			}
		}

		let final_out_file_path = if out_file_path.is_none() {
			in_file_path
		}
		else {
			out_file_path.unwrap()
		};

		match srt::save_subtitles(&subtitles, &final_out_file_path) {
			Ok(_) => (),
			Err(_) => {
				println!("Save failed");
				std::process::exit(1);
			}
		}
		println!("done: {} subtitles", subtitles.len());
	}
}
<commit_msg>Remove another debug line<commit_after>extern crate clap;

use clap::{Arg, App, Error};

mod workfile;
mod srt;
mod txt_rep;
mod rules;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

///////////////////////////////////////////////////////////////////////////////
fn do_replacements(subtitles: &mut Vec<srt::Subtitle>, language: &str) {

	for subtitle in subtitles.iter_mut() {
		for text_index in 0..subtitle.text_count as usize {
			subtitle.texts[text_index] = txt_rep::replace_one(&subtitle.texts[text_index], &language);
		}
		//print!("{}", subtitle.to_string());
	}
}

fn do_time_changes(subtitles: &mut Vec<srt::Subtitle>,
                   time_shift_ms: i32, time_stretch_ms: i32) {

	if time_shift_ms == 0 && time_stretch_ms == 0 {
		return;
	}
	let sub_count = subtitles.len();
	if sub_count == 0 {
		return;
	}

	if sub_count > std::i32::MAX as usize {
		eprintln!("Too many subtitles");
		return;
	};

	// Compute the limit for stretching
	let sub_count_i32 = if srt::should_keep_last_sub(subtitles) {
		sub_count as i32
	}
	else {
		(sub_count - 1) as i32
	};

	let mut sub_index = 0;
	for subtitle in subtitles.iter_mut() {

		subtitle.time_from += time_shift_ms;
		subtitle.time_to += time_shift_ms;

		if time_stretch_ms > 0 && sub_count_i32 > 1 && sub_index < sub_count_i32 {
			let stretching = (sub_index * time_stretch_ms) / (sub_count_i32 - 1);
			subtitle.time_from += stretching;
			subtitle.time_to += stretching;
		}
		sub_index += 1;
	}
}

///////////////////////////////////////////////////////////////////////////////
fn main() {
	let matches = App::new("fixsrt")
		.version(VERSION)
		.author("Hadrien Nilsson")
		.about("Fix spelling and encoding mistakes in SRT subtitle files")
		.arg(Arg::with_name("nobak")
			.long("nobak")
			.help("Avoids creating a backup file"))
		.arg(Arg::with_name("SRTFILE")
			.required(true)
			.multiple(true)
			.help("SRT file to update"))
		.arg(Arg::with_name("out")
			.short("o")
			.long("out")
			.takes_value(true)
			.help("Outputs to another file (single input only)"))
		.arg(Arg::with_name("shift")
			.long("shift")
			.takes_value(true)
			.help("Shifts all subtitles of several seconds"))
		.arg(Arg::with_name("stretch")
			.long("stretch")
			.takes_value(true)
			.help("Stretches all subtitles after adding several seconds to the last one"))
		.arg(Arg::with_name("lang")
			.long("lang")
			.takes_value(true)
			.help("Selects the language of the SRT file(s) (fr/en)"))
		.get_matches();

	let no_backup = matches.is_present("nobak");
	let in_file_paths: Vec<_> = matches.values_of("SRTFILE").unwrap().collect();
	let out_file_path = matches.value_of("out");
	let time_shift_ms = match matches.value_of("shift") {
		Some(tos) => match srt::parse_srt_time(tos) {
			Some(tos_ms) => tos_ms,
			None => {
				let err = Error { message: "--shift invalid argument".into(),
					kind: clap::ErrorKind::TooManyValues,
					info: None };
				err.exit();
			}
		},
		None => 0
	};
	let time_stretch_ms = match matches.value_of("stretch") {
		Some(tos) => match srt::parse_srt_time(tos) {
			Some(tos_ms) => tos_ms,
			None => {
				let err = Error { message: "--stretch invalid argument".into(),
					kind: clap::ErrorKind::TooManyValues,
					info: None };
				err.exit();
			}
		},
		None => 0
	};
	let language = matches.value_of("lang").unwrap_or("fr");

	if language != "en" && language != "fr" {
		println!("Bad language");
		std::process::exit(1);
	}

	// Additional check. Is there a way to do it with clap?
	if out_file_path.is_some() && in_file_paths.len() > 1 {
		let err = Error { message: "--out works only with single input".into(),
			kind: clap::ErrorKind::TooManyValues,
			info: None};
		err.exit();
	}

	/////////////////////////////////////////////////////////////////
	for in_file_path in in_file_paths {
		print!("{} ... ", in_file_path);

		let subtitles_res = srt::load_subtitles(&in_file_path);
		match subtitles_res {
			Ok(_) => (),
			Err(ref err) => {
				println!("{}", err);
				std::process::exit(1);
			}
		}

		let mut subtitles = subtitles_res.unwrap();
		do_replacements(&mut subtitles, &language);
		do_time_changes(&mut subtitles, time_shift_ms, time_stretch_ms);

		// Do backup
		if !no_backup {
			let backup_file_path = format!("{}~", in_file_path);
			match std::fs::copy(&in_file_path, &backup_file_path) {
				Ok(_) => (),
				Err(err) => println!("Cannot create backup: {}", err)
			}
		}

		let final_out_file_path = if out_file_path.is_none() {
			in_file_path
		}
		else {
			out_file_path.unwrap()
		};

		match srt::save_subtitles(&subtitles, &final_out_file_path) {
			Ok(_) => (),
			Err(_) => {
				println!("Save failed");
				std::process::exit(1);
			}
		}
		println!("done: {} subtitles", subtitles.len());
	}
}
<|endoftext|>


<commit_before>extern crate image;
extern crate image_base64;
extern crate cgi;

use std::fs::File;
use std::path::Path;
use std::env;
use std::io;//::{self, Write};
use image::GenericImage;

//should be a trait.  I am not sure how to impliment one for only Vec <Vec <bool>> and not Vec <T>
fn boundless_insert(y: i64, x: i64, value: bool, img: &mut Vec<Vec <bool>>) {
	let mut tx = x;
	let mut ty = y;
	for i in 0..img.len(){
		let mut ttx = x;
		while ttx < 0 {
			img[i].insert(0, false);
			ttx += 1;
		}
		assert!(((x < 0) && (ttx == 0)) || (x == ttx), "Expected ttx = zero or ttx = x.  Found {}", ttx);
		while img[i].len() <= ttx as usize {
			img[i].push(false);
		}
		tx = ttx
	}
	let mut row:Vec <bool> = Vec::new();
	for i in 0..img[0].len() {
		row.push(false);
	}
	while ty < 0 {
		img.insert(0, row.clone());
		ty += 1;
	}
	assert!(((y < 0) && (ty == 0)) || (y == ty), "Expected ty = zero or ty = y.  Found {}", ty);
	while img.len() <= ty as usize {
		img.push(row.clone())
	}
	img[ty as usize][tx as usize] = value;
}

struct ImgBlob {
	blob_type: u8, //0: object, 1: line
	top_right: [usize; 2],
	middle: [usize; 2],
	text: String,
	bitmap: Vec <Vec <bool>>
}

impl ImgBlob {
	fn from_top_right(x: usize, y: usize, claim: &mut Vec <Vec <bool>>, img: &Vec <Vec <bool>>) -> Option<ImgBlob>{
		//let mut imgbuf = image::ImageBuffer::new(2550u32, 3300u32);
		let mut right = x;
		let mut top = y; //pretty sure that this is not supposed to change and can be eliminated
		let mut bitmap: Vec <Vec <bool>> = Vec::new();
		let mut queue: Vec <[usize; 2]> = Vec::new();
		claim[y][x] = true;
		//imgbuf.put_pixel(x as u32, y as u32, image::Rgb([0, 255, 0]));
		queue.push([y+1, x]);
		queue.push([y, x+1]);
		bitmap.push(vec![true]);
		while queue.len() > 0 {
			let tempx = queue[0][1];
			let tempy = queue[0][0];
			if (tempy < img.len()) && (tempx  0) && (tempx > 0) {
				if img[tempy][tempx] && !(claim[tempy][tempx]){
					boundless_insert(((tempy as i64)-(top as i64)), ((tempx as i64)-(right as i64)), true, &mut bitmap);
					if tempx < right {
						right = tempx;
					}
					if tempy < top {
						top = tempy;
					}
					//imgbuf.put_pixel(tempx as u32, tempy as u32, image::Rgb([0, 255, 0]));
					claim[tempy][tempx] = true;
					if queue[0][1] > top {
						queue.push([tempy-1, tempx]);
					}
					queue.push([tempy, tempx-1]);
					queue.push([tempy+1, tempx]);
					queue.push([tempy, tempx+1]);
				}/* else if !(claim[tempy][tempx]) {
					imgbuf.put_pixel(tempx as u32, tempy as u32, image::Rgb([255, 0, 0]));
				}*/
			}/* else {
				imgbuf.put_pixel(tempx as u32, tempy as u32, image::Rgb([255, 0, 0]));
			}*/
			queue.remove(0);
		}
		if (bitmap[0].len() + bitmap.len() > 6) && (bitmap.len() > 3) && (bitmap[0].len() > 3) {
			/*let mut imgbuf = image::ImageBuffer::new((bitmap[0].len()) as u32, (bitmap.len()) as u32);
			for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
				*pixel = image::Luma([if bitmap[y as usize][x as usize] {255} else {0}]);
			}
			let xdim = &*bitmap[0].len().to_string();
			let ydim = &*bitmap.len().to_string();
			let ref mut fout = File::create(&Path::new(&(String::from("outg")+xdim+"x"+ydim+".png"))).unwrap();
			let _ = image::ImageRgb8(imgbuf).save(fout, image::PNG);*/
			println!("Found: {} x {}", bitmap[0].len(), bitmap.len());
			Some(ImgBlob {
				blob_type: if (bitmap[0].len() / bitmap.len()) > 10 {1} else {0},
				top_right: [right, top],
				middle: [right+(bitmap[0].len()/2), top+(bitmap.len()/2)],
				text: String::from(""),
				bitmap: bitmap
			})
		} else {
			None
		}
	}
}

struct Section {
	Heading: ImgBlob,
	blobs: Vec <ImgBlob>
}

struct Chapter {
	heading: ImgBlob,
	blobs: Vec <ImgBlob>,
	Sections: Vec

}

fn main() {
	let mut claimed: Vec <Vec <bool>> = Vec::new();
	let mut thresh: Vec <Vec <bool>> = Vec::new();
	//let mut rblobs: Vec <ImgBlob> = Vec::new();
	let mut gblobs: Vec <ImgBlob> = Vec::new();
	//let mut bblobs: Vec <ImgBlob> = Vec::new();
	let img = image::open(&Path::new("target.jpg")).unwrap();
	let mut row:Vec <bool> = Vec::new();
	for x in 0..img.width() {
		row.push(false);
	}
	for y in 0..img.height() {
		claimed.push(row.clone());
		thresh.push(row.clone());
	}
	let rgbimg = img.to_rgb();
	//let mut imgbuf = image::ImageBuffer::new(img.width(), img.height());
	/*for (x, y, pixel) in rgbimg.enumerate_pixels() {
		thresh[y as usize][x as usize] = if (pixel[0] > 140) && (pixel[1] <= 170) && (pixel[2] <= 170) {true} else {false};
		imgbuf.put_pixel(x, y, image::Luma([if (pixel[0] > 140) & (pixel[1] <= 170) & (pixel[2] <= 170) {255} else {0}]));
	}
	let ref mut fout = File::create(&Path::new("outr.png")).unwrap();
	let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
	for y in 0..thresh.len() {
		for x in 0..thresh[0].len() {
			if thresh[y][x] {
				match ImgBlob::from_top_right(x, y, &mut claimed, &thresh){
					Some(o) => rblobs.push(o),
					None => {},
				}
			}
		}
	}
	println!("Finished R");*/
	for (x, y, pixel) in rgbimg.enumerate_pixels() {
		thresh[y as usize][x as usize] = if (pixel[1] > 140) && (pixel[0] <= 170) && (pixel[2] <= 170) {true} else {false};
	}
	for y in 0..thresh.len() {
		for x in 0..thresh[0].len() {
			//imgbuf.put_pixel(x as u32, y as u32, image::Luma([if thresh[y][x] {255} else {0}]));
			if thresh[y][x] {
				match ImgBlob::from_top_right(x, y, &mut claimed, &thresh){
					Some(o) => gblobs.push(o),
					None => {},
				}
			}
		}
	}
	/*let ref mut fout = File::create(&Path::new("outg.png")).unwrap();
	let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);*/
	let mut imgbuf = image::ImageBuffer::new(img.width(), img.height());
	for i in 0..gblobs.len() {
		let xoff = gblobs[i].top_right[0];
		let yoff = gblobs[i].top_right[1];
		for y in 0..gblobs[i].bitmap.len() {
			for x in 0..gblobs[i].bitmap[y].len() {
				if gblobs[i].blob_type == 0 {
					imgbuf.put_pixel((x+xoff) as u32, (y+yoff) as u32, image::Rgb(if (gblobs[i].bitmap[y][x]) {[0, 255, 0]} else {[0, 0, 0]}));
				} else {
					imgbuf.put_pixel((x+xoff) as u32, (y+yoff) as u32, image::Rgb(if (gblobs[i].bitmap[y][x]) {[255, 0, 0]} else {[0, 0, 0]}));
				}
			}
		}
	}
	let ref mut fout = File::create(&Path::new("reconstructg.png")).unwrap();
	let _ = image::ImageRgb8(imgbuf).save(fout, image::PNG);
	println!("Finished G");
	/*for (x, y, pixel) in rgbimg.enumerate_pixels() {
		thresh[y as usize][x as usize] = if (pixel[2] > 140) && (pixel[1] <= 170) && (pixel[0] <= 170) {true} else {false};
	}
	for y in 0..thresh.len() {
		for x in 0..thresh[0].len() {
			imgbuf.put_pixel(x as u32, y as u32, image::Luma([if thresh[y][x] {255} else {0}]));
			if thresh[y][x] {
				match ImgBlob::from_top_right(x, y, &mut claimed, &thresh){
					Some(o) => bblobs.push(o),
					None => {},
				}
			}
		}
	}
	let ref mut fout = File::create(&Path::new("outb.png")).unwrap();
	let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
	println!("Finished B");*/

}
<commit_msg>Cleanup<commit_after>extern crate image;
extern crate image_base64;
extern crate cgi;

use std::fs::File;
use std::path::Path;
use std::env;
use std::io;//::{self, Write};
use image::GenericImage;

//should be a trait.  I am not sure how to impliment one for only Vec <Vec <bool>> and not Vec <T>
fn boundless_insert(y: i64, x: i64, value: bool, img: &mut Vec<Vec <bool>>) {
	let mut tx = x;
	let mut ty = y;
	for i in 0..img.len(){
		let mut ttx = x;
		while ttx < 0 {
			img[i].insert(0, false);
			ttx += 1;
		}
		assert!(((x < 0) && (ttx == 0)) || (x == ttx), "Expected ttx = zero or ttx = x.  Found {}", ttx);
		while img[i].len() <= ttx as usize {
			img[i].push(false);
		}
		tx = ttx
	}
	let mut row:Vec <bool> = Vec::new();
	for i in 0..img[0].len() {
		row.push(false);
	}
	while ty < 0 {
		img.insert(0, row.clone());
		ty += 1;
	}
	assert!(((y < 0) && (ty == 0)) || (y == ty), "Expected ty = zero or ty = y.  Found {}", ty);
	while img.len() <= ty as usize {
		img.push(row.clone())
	}
	img[ty as usize][tx as usize] = value;
}

struct ImgBlob {
	blob_type: u8, //0: object, 1: line
	top_right: [usize; 2],
	middle: [usize; 2],
	text: String,
	bitmap: Vec <Vec <bool>>
}

impl ImgBlob {
	fn from_top_right(x: usize, y: usize, claim: &mut Vec <Vec <bool>>, img: &Vec <Vec <bool>>) -> Option<ImgBlob>{
		let mut right = x;
		let mut top = y; //pretty sure that this is not supposed to change and can be eliminated
		let mut bitmap: Vec <Vec <bool>> = Vec::new();
		let mut queue: Vec <[usize; 2]> = Vec::new();
		claim[y][x] = true;
		queue.push([y+1, x]);
		queue.push([y, x+1]);
		bitmap.push(vec![true]);
		while queue.len() > 0 {
			let tempx = queue[0][1];
			let tempy = queue[0][0];
			if (tempy < img.len()) && (tempx  0) && (tempx > 0) {
				if img[tempy][tempx] && !(claim[tempy][tempx]){
					boundless_insert(((tempy as i64)-(top as i64)), ((tempx as i64)-(right as i64)), true, &mut bitmap);
					if tempx < right {
						right = tempx;
					}
					if tempy < top {
						top = tempy;
					}
					claim[tempy][tempx] = true;
					if queue[0][1] > top {
						queue.push([tempy-1, tempx]);
					}
					queue.push([tempy, tempx-1]);
					queue.push([tempy+1, tempx]);
					queue.push([tempy, tempx+1]);
				}
			}
			queue.remove(0);
		}
		if (bitmap[0].len() + bitmap.len() > 6) && (bitmap.len() > 3) && (bitmap[0].len() > 3) {
			println!("Found: {} x {}", bitmap[0].len(), bitmap.len());
			Some(ImgBlob {
				blob_type: if (bitmap[0].len() / bitmap.len()) > 10 {1} else {0},
				top_right: [right, top],
				middle: [right+(bitmap[0].len()/2), top+(bitmap.len()/2)],
				text: String::from(""),
				bitmap: bitmap
			})
		} else {
			None
		}
	}
}

struct Section {
	Heading: ImgBlob,
	blobs: Vec <ImgBlob>
}

struct Chapter {
	heading: ImgBlob,
	blobs: Vec <ImgBlob>,
	Sections: Vec

}

fn main() {
	let mut claimed: Vec <Vec <bool>> = Vec::new();
	let mut thresh: Vec <Vec <bool>> = Vec::new();
	let mut rblobs: Vec <ImgBlob> = Vec::new();
	let mut gblobs: Vec <ImgBlob> = Vec::new();
	let mut bblobs: Vec <ImgBlob> = Vec::new();
	let img = image::open(&Path::new("target.jpg")).unwrap();
	let mut row:Vec <bool> = Vec::new();
	for x in 0..img.width() {
		row.push(false);
	}
	for y in 0..img.height() {
		claimed.push(row.clone());
		thresh.push(row.clone());
	}
	let rgbimg = img.to_rgb();
	for (x, y, pixel) in rgbimg.enumerate_pixels() {
		thresh[y as usize][x as usize] = if (pixel[0] > 140) && (pixel[1] <= 170) && (pixel[2] <= 170) {true} else {false};
	}
	for y in 0..thresh.len() {
		for x in 0..thresh[0].len() {
			if thresh[y][x] {
				match ImgBlob::from_top_right(x, y, &mut claimed, &thresh){
					Some(o) => rblobs.push(o),
					None => {},
				}
			}
		}
	}
	println!("Finished R");
	for (x, y, pixel) in rgbimg.enumerate_pixels() {
		thresh[y as usize][x as usize] = if (pixel[1] > 140) && (pixel[0] <= 170) && (pixel[2] <= 170) {true} else {false};
	}
	for y in 0..thresh.len() {
		for x in 0..thresh[0].len() {
			if thresh[y][x] {
				match ImgBlob::from_top_right(x, y, &mut claimed, &thresh){
					Some(o) => gblobs.push(o),
					None => {},
				}
			}
		}
	}
	println!("Finished G");
	for (x, y, pixel) in rgbimg.enumerate_pixels() {
		thresh[y as usize][x as usize] = if (pixel[2] > 140) && (pixel[1] <= 170) && (pixel[0] <= 170) {true} else {false};
	}
	for y in 0..thresh.len() {
		for x in 0..thresh[0].len() {
			imgbuf.put_pixel(x as u32, y as u32, image::Luma([if thresh[y][x] {255} else {0}]));
			if thresh[y][x] {
				match ImgBlob::from_top_right(x, y, &mut claimed, &thresh){
					Some(o) => bblobs.push(o),
					None => {},
				}
			}
		}
	}
	println!("Finished B");
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate mnemesis_utils;

mod add;
mod get;

use clap::{App, Arg, SubCommand};

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .subcommand(SubCommand::with_name("add")
                    .about("Add new credentials to the registry")
                    .arg(Arg::with_name("PATH")
                         .required(true))
                    .arg(Arg::with_name("totp")
                         .short("t")
                         .long("totp")))
        .subcommand(SubCommand::with_name("get")
                    .about("Get some credentials from the registry")
                    .arg(Arg::with_name("PATH")
                         .required(true)))
        .get_matches();

    if let Some(sub) = matches.subcommand_matches("add") {
        add::_main(sub);
    } else if let Some(sub) = matches.subcommand_matches("get") {
        get::_main(sub);
    } else {
        println!("{}", matches.usage());
    }
}
<commit_msg>default to get subcommand<commit_after>extern crate clap;
extern crate mnemesis_utils;

mod add;
mod get;

use clap::{App, Arg, SubCommand};

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .subcommand(SubCommand::with_name("add")
                    .about("Add new credentials to the registry")
                    .arg(Arg::with_name("PATH")
                         .required(true))
                    .arg(Arg::with_name("totp")
                         .short("t")
                         .long("totp")))
        .subcommand(SubCommand::with_name("get")
                    .about("Get some credentials from the registry")
                    .arg(Arg::with_name("PATH")
                         .required(true)))
        .arg(Arg::with_name("PATH"))
        .get_matches();

    if let Some(sub) = matches.subcommand_matches("add") {
        add::_main(sub);
    } else if let Some(sub) = matches.subcommand_matches("get") {
        get::_main(sub);
    } else if matches.is_present("PATH") {
        get::_main(&matches);
    } else {
        println!("{}", matches.usage());
    }
}
<|endoftext|>


<commit_before>#![feature(fs_walk, custom_derive, plugin, iter_arith, result_expect)]
#![plugin(serde_macros)]
extern crate serde;
extern crate serde_json;
extern crate nalgebra;

use serde::Deserialize;
use serde_json::Value as JsonValue;
use serde_json::Deserializer;

use nalgebra::{DMat, DVec, Iterable};

use std::io::{BufReader, BufRead};
use std::fs::{File, WalkDir, read_dir, walk_dir};
use std::env::args;
use std::collections::{HashSet, HashMap};
use std::mem::swap;

#[derive(Debug, Serialize, Deserialize)]
struct Package {
    name: String,
    vers: String,
    deps: Vec<Dep>,
    cksum: String,
    features: JsonValue,
    yanked: bool,
}

#[derive(Debug, Serialize, Deserialize)]
struct Dep {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>,
}

fn get_packages(path: &str) -> Vec<Package> {
    read_dir(path)
        .unwrap()
        .map(Result::unwrap)
        .filter(|dir| {
            let path = dir.path();
            let file = path.file_name().unwrap().to_str().unwrap();
            file != ".git" && file != "config.json"
        })
        .flat_map::<WalkDir, _>(|dir| walk_dir(dir.path()).unwrap())
        .map(Result::unwrap)
        .filter(|file| file.file_type().unwrap().is_file())
        .map(|file| {
            let reader = BufReader::new(File::open(file.path()).unwrap());
            let latest_version = reader.lines().last().unwrap().unwrap();
            let mut deserializer = Deserializer::new(latest_version.as_bytes().iter().map(|b| Ok(*b)));
            let pkg = Package::deserialize(&mut deserializer).unwrap();
            pkg
        })
        .collect()
}

fn cargo_rank(packages: &[Package]) -> Vec<(&Package, f64)> {
    let damp = 0.85;
    let starting_rank = 1.0 / packages.len() as f64;
    let mut cargo_ranks: HashMap<_, _> = packages.iter().map(|pkg| (&*pkg.name, (pkg, starting_rank))).collect();
    let mut new_ranks: HashMap<_, _>;
    let mut delta = std::f64::MAX;
    let threshold = 0.000001;
    let iterative_starting_rank = (1.0 - damp) / packages.len() as f64;
    while delta > threshold {
        new_ranks = packages.iter().map(|pkg| (&*pkg.name, (pkg, iterative_starting_rank))).collect();
        for &(pkg, rank) in cargo_ranks.values() {
            let num_deps = pkg.deps.len();
            let boost;
            if num_deps == 0 { // distribute evenly when there are no deps
                boost = damp * rank / packages.len() as f64;
                for dep in packages.iter() {
                    new_ranks.get_mut(&*dep.name).unwrap().1 += boost;
                }
            } else {
                boost = damp * rank / num_deps as f64;
                for dep in &pkg.deps {
                    new_ranks.get_mut(&*dep.name).unwrap().1 += boost;
                }
            }
        }
        delta = cargo_ranks.values().map(|&(pkg, rank)| (new_ranks[&*pkg.name].1 - rank).abs()).sum();
        cargo_ranks.clear();
        let sum: f64 = new_ranks.values().map(|&(_, rank)| rank).sum();
        assert!((1.0 - sum).abs() < 0.0000000001f64);
        swap(&mut cargo_ranks, &mut new_ranks);
        println!("Delta: {}", delta);
    }
    let mut ranks: Vec<_> = cargo_ranks.into_iter().map(|(_, pkg_rank)| pkg_rank).collect();
    ranks.sort_by(|&(_, rank1), &(_, ref rank2)| rank1.partial_cmp(rank2).unwrap().reverse());
    ranks
}

fn mat_cargo_rank(packages: &[Package]) -> Vec<(&Package, f64)> {
    let damp = 0.85;
    let starting_rank = 1.0 / packages.len() as f64;
    let mut cargo_ranks = DVec::from_elem(packages.len(), starting_rank);
    let deps: Vec<f64> = packages.iter().flat_map(|pkg| {
        let deps: HashSet<_> = pkg.deps.iter().map(|dep| &*dep.name).collect();
        let num_deps = deps.len() as f64;
        packages.iter().map(move |dep| if deps.len() == 0 { 1.0 / packages.len() as f64 } else { if deps.contains(&*dep.name) { 1.0 / num_deps } else { 0.0 }})
    }).collect();
    let deps = DMat::from_col_vec(packages.len(), packages.len(), &deps);

    let mut delta = std::f64::MAX;
    let threshold = 0.000001;
    while delta > threshold {
        let starting_rank = (1.0 - damp) / packages.len() as f64;
        let starting_ranks = DVec::from_elem(packages.len(), starting_rank);
        let new_ranks = starting_ranks + (deps.clone() * cargo_ranks.clone()) * damp;
        delta = cargo_ranks.iter().zip(new_ranks.iter()).map(|(old, new)| (old - new).abs()).sum();
        let sum: f64 = new_ranks.iter().sum();
        assert!((1.0 - sum).abs() < 0.0000000001f64);
        cargo_ranks = new_ranks;
        println!("Delta: {}", delta);
    }
    let mut ranks: Vec<_> = packages.iter().zip(cargo_ranks.iter().cloned()).collect();
    ranks.sort_by(|&(_, rank1), &(_, ref rank2)| rank1.partial_cmp(rank2).unwrap().reverse());
    ranks
}

fn main() {
    let mut args = std::env::args().skip(1);
    let path = args.next().unwrap();
    let packages = get_packages(&path);
    let limit = args.next().unwrap().parse().expect("Not a number?");

    println!("loop ranks");
    let ranks = cargo_rank(&packages);
    for (i, (pkg, rank)) in ranks.into_iter().take(limit).enumerate() {
        println!("{}. {} ({})", i + 1, pkg.name, rank);
    }

    println!("mat ranks");
    let mat_ranks = mat_cargo_rank(&packages);
    for (i, (pkg, rank)) in mat_ranks.into_iter().take(limit).enumerate() {
        println!("{}. {} ({})", i + 1, pkg.name, rank);
    }
}
<commit_msg>Remove loop version<commit_after>#![feature(fs_walk, custom_derive, plugin, iter_arith, result_expect, test)]
#![plugin(serde_macros)]
extern crate serde;
extern crate serde_json;
extern crate nalgebra;
extern crate test;

use serde::Deserialize;
use serde_json::Value as JsonValue;
use serde_json::Deserializer;

use nalgebra::{DMat, DVec, Iterable};

use std::io::{BufReader, BufRead};
use std::fs::{File, WalkDir, read_dir, walk_dir};
use std::env::args;
use std::collections::HashSet;

#[derive(Debug, Serialize, Deserialize)]
struct Package {
    name: String,
    vers: String,
    deps: Vec<Dep>,
    cksum: String,
    features: JsonValue,
    yanked: bool,
}

#[derive(Debug, Serialize, Deserialize)]
struct Dep {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>,
}

fn get_packages(path: &str) -> Vec<Package> {
    read_dir(path)
        .unwrap()
        .map(Result::unwrap)
        .filter(|dir| {
            let path = dir.path();
            let file = path.file_name().unwrap().to_str().unwrap();
            file != ".git" && file != "config.json"
        })
        .flat_map::<WalkDir, _>(|dir| walk_dir(dir.path()).unwrap())
        .map(Result::unwrap)
        .filter(|file| file.file_type().unwrap().is_file())
        .map(|file| {
            let reader = BufReader::new(File::open(file.path()).unwrap());
            let latest_version = reader.lines().last().unwrap().unwrap();
            let mut deserializer = Deserializer::new(latest_version.as_bytes().iter().map(|b| Ok(*b)));
            let pkg = Package::deserialize(&mut deserializer).unwrap();
            pkg
        })
        .collect()
}

fn cargo_rank(packages: &[Package]) -> Vec<(&Package, f64)> {
    let damp = 0.85;
    let starting_rank = 1.0 / packages.len() as f64;
    let mut cargo_ranks = DVec::from_elem(packages.len(), starting_rank);
    let deps: Vec<f64> = packages.iter().flat_map(|pkg| {
        let deps: HashSet<_> = pkg.deps.iter().map(|dep| &*dep.name).collect();
        let num_deps = deps.len() as f64;
        packages.iter().map(move |dep| if deps.len() == 0 {
            1.0 / packages.len() as f64
        } else {
            if deps.contains(&*dep.name) { 1.0 / num_deps } else { 0.0 }
        })
    }).collect();
    let deps = DMat::from_col_vec(packages.len(), packages.len(), &deps);

    let mut delta = std::f64::MAX;
    let threshold = 0.000001;
    let starting_ranks = DVec::from_elem(packages.len(), (1.0 - damp) / packages.len() as f64);
    while delta > threshold {
        let new_ranks = starting_ranks.clone() + (deps.clone() * cargo_ranks.clone()) * damp;
        delta = cargo_ranks.iter().zip(new_ranks.iter()).map(|(old, new)| (old - new).abs()).sum();
        println!("Delta: {}", delta);
        cargo_ranks = new_ranks;
    }
    let mut ranks: Vec<_> = packages.iter().zip(cargo_ranks.iter().cloned()).collect();
    ranks.sort_by(|&(_, rank1), &(_, rank2)| rank1.partial_cmp(&rank2).unwrap().reverse());
    ranks
}

fn main() {
    let mut args = std::env::args().skip(1);
    let path = args.next().unwrap();
    let packages = get_packages(&path);
    let limit = args.next().unwrap().parse().expect("Not a number?");

    println!("ranks:");
    let ranks = cargo_rank(&packages);
    for (i, (pkg, rank)) in ranks.into_iter().take(limit).enumerate() {
        println!("{}. {} ({})", i + 1, pkg.name, rank);
    }
}

#[cfg(test)]
mod tests {
    use super::{get_packages, cargo_rank};
    use test::Bencher;

    #[bench]
    #[ignore]
    fn bench_cargo_rank(b: &mut Bencher) {
        let packages = get_packages("../crates.io-index/");
        b.iter(|| cargo_rank(&packages));
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate osmpbfreader;
extern crate postgis;
#[macro_use] extern crate postgres;
#[macro_use] extern crate postgres_derive;

use osmpbfreader::OsmPbfReader;
use osmpbfreader::objects::{OsmId, OsmObj};
use postgis::ewkb::AsEwkbPoint;
use postgis::twkb::Point;
use postgres::{Connection, TlsMode};
use std::fs::File;

#[derive(Debug, ToSql, FromSql)]
#[postgres(name = "point_type")]
enum Type {
    #[postgres(name = "amenity")]
    Amenity,
    #[postgres(name = "shop")]
    Shop,
}

fn main() {
    let matches = clap_app!(myapp =>
        (about: "Import points from OSM")
        (@arg db: -d --("database-url") +takes_value +required env("DATABASE_URL") "Sets a database URL")
        (@arg input: +required "Sets the input file to use")
    ).get_matches();

    let database_url = matches.value_of("db").unwrap();
    let conn = Connection::connect(database_url, TlsMode::None).unwrap();

    let add_point = conn.prepare(
        "INSERT INTO points (id, location, type, subtype, name, email, phone, website, opening_hours, operator) \
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"
    ).unwrap();

    let add_tag = conn.prepare(
        "INSERT INTO tags (point_id, key, value) VALUES ($1, $2, $3)"
    ).unwrap();

    let file_path = matches.value_of("input").unwrap();
    let file = File::open(file_path).unwrap();

    let mut pbf = OsmPbfReader::new(&file);

    for obj in pbf.iter().map(Result::unwrap) {
        if !obj.is_node() {
            continue;
        }

        if !obj.tags().contains_key("amenity") && !obj.tags().contains_key("shop") {
            continue;
        }

        let id = get_object_id(&obj);
        let tags = obj.tags();
        let location = Point {
            x: obj.node().unwrap().lat(),
            y: obj.node().unwrap().lon(),
        };

        add_point.execute(&[
            &id, &location.as_ewkb(), &Type::Amenity, &tags.get("amenity"), &tags.get("name"), &tags.get("email"),
            &tags.get("phone"), &tags.get("website"), &tags.get("opening_hours"), &tags.get("operator")
        ]).unwrap();

        for tag in obj.tags().iter() {
            match tag.0.as_ref() {
                "amenity" | "shop" => continue,
                "created_by" | "name" | "source" => continue,
                "email" | "phone" | "website" => continue,
                "opening_hours" | "operator" => continue,
                _ => ()
            }

            add_tag.execute(&[&id, &tag.0, &tag.1]).unwrap();
        }
    }
}

fn get_object_id(obj: &OsmObj) -> i64 {
    match obj.id() {
        OsmId::Node(id) => id.0,
        OsmId::Way(id) => id.0,
        OsmId::Relation(id) => id.0,
    }
}
<commit_msg>Add fix for shops<commit_after>#[macro_use] extern crate clap;
extern crate osmpbfreader;
extern crate postgis;
#[macro_use] extern crate postgres;
#[macro_use] extern crate postgres_derive;

use osmpbfreader::OsmPbfReader;
use osmpbfreader::objects::{OsmId, OsmObj};
use postgis::ewkb::AsEwkbPoint;
use postgis::twkb::Point;
use postgres::{Connection, TlsMode};
use std::fs::File;

#[derive(Debug, ToSql, FromSql)]
#[postgres(name = "point_type")]
enum Type {
    #[postgres(name = "amenity")]
    Amenity,
    #[postgres(name = "shop")]
    Shop,
}

struct Types(Type, String);

fn main() {
    let matches = clap_app!(myapp =>
        (about: "Import points from OSM")
        (@arg db: -d --("database-url") +takes_value +required env("DATABASE_URL") "Sets a database URL")
        (@arg input: +required "Sets the input file to use")
    ).get_matches();

    let database_url = matches.value_of("db").unwrap();
    let conn = Connection::connect(database_url, TlsMode::None).unwrap();

    let add_point = conn.prepare(
        "INSERT INTO points (id, location, type, subtype, name, email, phone, website, opening_hours, operator) \
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"
    ).unwrap();

    let add_tag = conn.prepare(
        "INSERT INTO tags (point_id, key, value) VALUES ($1, $2, $3)"
    ).unwrap();

    let file_path = matches.value_of("input").unwrap();
    let file = File::open(file_path).unwrap();

    let mut pbf = OsmPbfReader::new(&file);

    for obj in pbf.iter().map(Result::unwrap) {
        if !obj.is_node() {
            continue;
        }

        let types_option = get_types(&obj);

        if types_option.is_none() {
            continue;
        }

        let id = get_object_id(&obj);
        let tags = obj.tags();
        let types = types_option.unwrap();
        let location = Point {
            x: obj.node().unwrap().lat(),
            y: obj.node().unwrap().lon(),
        };

        add_point.execute(&[
            &id, &location.as_ewkb(), &types.0, &types.1, &tags.get("name"), &tags.get("email"),
            &tags.get("phone"), &tags.get("website"), &tags.get("opening_hours"), &tags.get("operator")
        ]).unwrap();

        for tag in obj.tags().iter() {
            match tag.0.as_ref() {
                "amenity" | "shop" => continue,
                "created_by" | "name" | "source" => continue,
                "email" | "phone" | "website" => continue,
                "opening_hours" | "operator" => continue,
                _ => ()
            }

            add_tag.execute(&[&id, &tag.0, &tag.1]).unwrap();
        }
    }
}

fn get_object_id(obj: &OsmObj) -> i64 {
    match obj.id() {
        OsmId::Node(id) => id.0,
        OsmId::Way(id) => id.0,
        OsmId::Relation(id) => id.0,
    }
}

fn get_types(obj: &OsmObj) -> Option<Types> {
    let tags = obj.tags();

    if tags.contains_key("amenity") {
        let types = Types(Type::Amenity, tags.get("amenity").unwrap().clone());
        return Some(types);
    }

    if tags.contains_key("shop") {
        let types = Types(Type::Shop, tags.get("shop").unwrap().clone());
        return Some(types);
    }

    None
}
<|endoftext|>


<commit_before>use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::io::BufRead;
use std::path::Path;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;

mod run;
mod util;
mod verify;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger, Carol Nichols")
        .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
        .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
        .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .about("Runs/Tests a single exercise")
                .arg(Arg::with_name("file").required(true).index(1))
                .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
        )
        .get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    if None == matches.subcommand_name() {
        println!();
        println!(r#"       welcome to...                      "#);
        println!(r#"                 _   _ _                  "#);
        println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
        println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
        println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
        println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
        println!(r#"                               |___/      "#);
        println!();
    }

    if !Path::new("info.toml").exists() {
        println!(
            "{} must be run from the rustlings directory",
            std::env::current_exe().unwrap().to_str().unwrap()
        );
        std::process::exit(1);
    }

    if let Some(matches) = matches.subcommand_matches("run") {
        run(matches.clone()).unwrap();
    }

    if matches.subcommand_matches("verify").is_some() {
        match verify(None) {
            Ok(_) => {}
            Err(_) => std::process::exit(1),
        }
    }

    if matches.subcommand_matches("watch").is_some() {
        watch().unwrap();
    }

    if matches.subcommand_name().is_none() {
        let mut highlighter =
            HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn watch() -> notify::Result<()> {
    let (tx, rx) = channel();

    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
    watcher.watch("./exercises", RecursiveMode::Recursive)?;

    let _ignored = verify(None);

    loop {
        match rx.recv() {
            Ok(event) => match event {
                DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
                    if b.extension() == Some(OsStr::new("rs")) {
                        println!("----------**********----------\n");
                        let _ignored = verify(Some(b.as_path().to_str().unwrap()));
                    }
                }
                _ => {}
            },
            Err(e) => println!("watch error: {:?}", e),
        }
    }
}
<commit_msg>fix watch command path execution<commit_after>use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::io::BufRead;
use std::path::Path;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;

mod run;
mod util;
mod verify;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger, Carol Nichols")
        .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
        .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
        .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .about("Runs/Tests a single exercise")
                .arg(Arg::with_name("file").required(true).index(1))
                .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
        )
        .get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    if None == matches.subcommand_name() {
        println!();
        println!(r#"       welcome to...                      "#);
        println!(r#"                 _   _ _                  "#);
        println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
        println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
        println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
        println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
        println!(r#"                               |___/      "#);
        println!();
    }

    if !Path::new("info.toml").exists() {
        println!(
            "{} must be run from the rustlings directory",
            std::env::current_exe().unwrap().to_str().unwrap()
        );
        std::process::exit(1);
    }

    if let Some(matches) = matches.subcommand_matches("run") {
        run(matches.clone()).unwrap();
    }

    if matches.subcommand_matches("verify").is_some() {
        match verify(None) {
            Ok(_) => {}
            Err(_) => std::process::exit(1),
        }
    }

    if matches.subcommand_matches("watch").is_some() {
        watch().unwrap();
    }

    if matches.subcommand_name().is_none() {
        let mut highlighter =
            HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn watch() -> notify::Result<()> {
    let (tx, rx) = channel();

    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
    watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;

    let _ignored = verify(None);

    loop {
        match rx.recv() {
            Ok(event) => match event {
                DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
                    if b.extension() == Some(OsStr::new("rs")) {
                        println!("----------**********----------\n");
                        let _ignored = verify(Some(b.as_path().to_str().unwrap()));
                    }
                }
                _ => {}
            },
            Err(e) => println!("watch error: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>//! Uniform point distribution in an annulus using Bridson’s algorithm for
//! Poisson-disc sampling
//! from [Visualizing Algorithms](http://bost.ocks.org/mike/algorithms/).
//!
//! Uses [qhull](http://qhull.org/) to generate a Delaunay triangulation.
extern crate docopt;
extern crate rand;
extern crate rustc_serialize;
extern crate gnuplot;
extern crate mersenne_twister;

mod annulus_distribution;

use std::f64::consts::PI;
#[allow(unused_imports)]
use gnuplot::{Figure, Caption, Color, Fix, AxesCommon, PlotOption, DashType, Coordinate, TextColor};
use rand::{Rng, SeedableRng};
use std::io::{Read, Write, Cursor, BufRead};
use std::process::{Command, Stdio};
use docopt::Docopt;
use mersenne_twister::MT19937_64;
use std::ops::Add;
use annulus_distribution::AnnulusDist;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = r"
Simple wave equation solver.
Usage: annulus_mesh [options]
       annulus_mesh (-h | --help | --version)

Options:
    -r INNER        Inner radius [default: 0.2]
    -d DIST         Point distance [default: 0.2]
    -h, --help      Print help
    --plot FILE     Output mesh plot
    --no-show       Do not plot anything
    --version       Print version
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_d: f64,
    flag_r: f64,
    flag_no_show: bool,
    flag_plot: Option<String>,
}

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

impl Add for Point {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Point(self.0 + rhs.0, self.1 + rhs.1)
    }
}

fn dist_sq(x: Point, y: Point) -> f64 {
    (x.0 - y.0).powi(2) + (x.1 - y.1).powi(2)
}

fn dist(x: Point, y: Point) -> f64 {
    ((x.0 - y.0).powi(2) + (x.1 - y.1).powi(2)).sqrt()
}

fn qhull_triangulation(ps: &[Point]) -> Vec<Vec<usize>> {
    let mut process = Command::new("qhull")
                          .stdin(Stdio::piped())
                          .stdout(Stdio::piped())
                          .arg("d")
                          .arg("i")
                          .spawn()
                          .unwrap_or_else(|e| panic!("couldn't spawn qhull: {:?}", e));

    if let Some(ref mut out) = process.stdin {
        writeln!(out, "2\n{}", ps.len()).unwrap();

        for &Point(x, y) in ps {
            writeln!(out, "{} {}", x, y).unwrap();
        }
    }

    // process.stdout.unwrap().read_to_string(&mut s);
    let output = process.wait_with_output().unwrap();

    let mut lines = Cursor::new(output.stdout).lines();

    let n = lines.next().unwrap().unwrap().parse::<usize>().unwrap();

    let mut res = vec![];

    for line in lines {
        let s = line.unwrap();
        let poly: Vec<usize> = s.split_whitespace().map(|e| e.parse::<usize>().unwrap()).collect();
        res.push(poly);
    }

    assert_eq!(res.len(), n);
    res
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| d.version(Some(VERSION.to_string())).decode())
                         .unwrap_or_else(|e| e.exit());

    let seed: u64 = 0;
    let mut rng: MT19937_64 = SeedableRng::from_seed(seed);

    let mut ps = vec![];
    let mut active: Vec<Point> = vec![];

    let r1 = args.flag_r;
    let r2 = 1.;
    let n_gen = 30;

    let h = args.flag_d;
    let mean_dist_ratio = 0.7;

    let k1 = (mean_dist_ratio * 2. * PI * r1 / h).round() as i32;
    let k2 = (mean_dist_ratio * 2. * PI * r2 / h).round() as i32;

    // generate boundary points
    for &(k, r) in &[(k1, r1), (k2, r2)] {
        for i in 0..k {
            let (y, x) = (2. * PI * i as f64 / k as f64).sin_cos();
            ps.push(Point(r * x, r * y));
        }
    }

    // make boundary points active
    active.extend(&ps);

    let n_fixed = ps.len();

    let annulus_dist = AnnulusDist::new(h, 2.0 * h);

    while !active.is_empty() {
        // select a random active point
        let i = rng.gen_range(0, active.len());

        let c = active[i];

        if let Some(p) = annulus_dist.ind_iter(&mut rng)
                                     .map(|p| p + c)
                                     .filter(|&p| {
                                         let d = dist(p, Point(0., 0.));
                                         r1 <= d && d <= r2
                                     })
                                     .take(n_gen)
                                     .filter(|&p| ps.iter().all(|&q| dist(p, q) >= h))
                                     .next() {
            ps.push(p);
            active.push(p);
        } else {
            active.remove(i);
        }

    }

    let indices = qhull_triangulation(&ps);

    let mut neighbors: Vec<Vec<usize>> = ps.iter().map(|_| vec![]).collect();
    for poly in &indices {
        for (&i, &j) in poly.iter().zip(poly.iter().cycle().skip(1)) {
            neighbors[i].push(j);
            neighbors[j].push(i);
        }
    }

    for list in &mut neighbors {
        list.sort();
        list.dedup();
    }

    // Laplace smoothing
    let n_laplace_step = 1;

    let laplace_eps = 1.0e-3;

    for _ in 0..n_laplace_step {
        let mut change = 0.;
        // Gauss-Seidel
        for i in n_fixed..ps.len() {
            let mut x = 0.;
            let mut y = 0.;
            for &j in &neighbors[i] {
                x += ps[j].0;
                y += ps[j].1;
            }
            let n = neighbors[i].len() as f64;
            let p = ps[i];
            let q = Point(x / n, y / n);
            ps[i] = q;
            change += dist_sq(p, q);
        }

        if change.sqrt() < laplace_eps {
            break;
        }
    }

    if !args.flag_no_show {
        let mut fg = Figure::new();
        if let Some(file) = args.flag_plot {
            fg.set_terminal("pngcairo size 720, 720", &file);
        }

        fg.clear_axes();
        {
            let axes = fg.axes2d();
            axes.set_aspect_ratio(Fix(1.));
            for poly in indices {
                axes.lines(poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].0),
                           poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].1),
                           &[]);
            }
        }

        fg.show();
    }

}
<commit_msg>Do not discard samples outside of the domain<commit_after>//! Uniform point distribution in an annulus using Bridson’s algorithm for
//! Poisson-disc sampling
//! from [Visualizing Algorithms](http://bost.ocks.org/mike/algorithms/).
//!
//! Uses [qhull](http://qhull.org/) to generate a Delaunay triangulation.
extern crate docopt;
extern crate rand;
extern crate rustc_serialize;
extern crate gnuplot;
extern crate mersenne_twister;

mod annulus_distribution;

use std::f64::consts::PI;
#[allow(unused_imports)]
use gnuplot::{Figure, Caption, Color, Fix, AxesCommon, PlotOption, DashType, Coordinate, TextColor};
use rand::{Rng, SeedableRng};
use std::io::{Read, Write, Cursor, BufRead};
use std::process::{Command, Stdio};
use docopt::Docopt;
use mersenne_twister::MT19937_64;
use std::ops::Add;
use annulus_distribution::AnnulusDist;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = r"
Simple wave equation solver.
Usage: annulus_mesh [options]
       annulus_mesh (-h | --help | --version)

Options:
    -r INNER        Inner radius [default: 0.2]
    -d DIST         Point distance [default: 0.2]
    -h, --help      Print help
    --plot FILE     Output mesh plot
    --no-show       Do not plot anything
    --version       Print version
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_d: f64,
    flag_r: f64,
    flag_no_show: bool,
    flag_plot: Option<String>,
}

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

impl Add for Point {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Point(self.0 + rhs.0, self.1 + rhs.1)
    }
}

fn dist_sq(x: Point, y: Point) -> f64 {
    (x.0 - y.0).powi(2) + (x.1 - y.1).powi(2)
}

fn dist(x: Point, y: Point) -> f64 {
    ((x.0 - y.0).powi(2) + (x.1 - y.1).powi(2)).sqrt()
}

fn qhull_triangulation(ps: &[Point]) -> Vec<Vec<usize>> {
    let mut process = Command::new("qhull")
                          .stdin(Stdio::piped())
                          .stdout(Stdio::piped())
                          .arg("d")
                          .arg("i")
                          .spawn()
                          .unwrap_or_else(|e| panic!("couldn't spawn qhull: {:?}", e));

    if let Some(ref mut out) = process.stdin {
        writeln!(out, "2\n{}", ps.len()).unwrap();

        for &Point(x, y) in ps {
            writeln!(out, "{} {}", x, y).unwrap();
        }
    }

    // process.stdout.unwrap().read_to_string(&mut s);
    let output = process.wait_with_output().unwrap();

    let mut lines = Cursor::new(output.stdout).lines();

    let n = lines.next().unwrap().unwrap().parse::<usize>().unwrap();

    let mut res = vec![];

    for line in lines {
        let s = line.unwrap();
        let poly: Vec<usize> = s.split_whitespace().map(|e| e.parse::<usize>().unwrap()).collect();
        res.push(poly);
    }

    assert_eq!(res.len(), n);
    res
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| d.version(Some(VERSION.to_string())).decode())
                         .unwrap_or_else(|e| e.exit());

    let seed: u64 = 0;
    let mut rng: MT19937_64 = SeedableRng::from_seed(seed);

    let mut ps = vec![];
    let mut active: Vec<Point> = vec![];

    let r1 = args.flag_r;
    let r2 = 1.;
    let n_gen = 30;

    let h = args.flag_d;
    let mean_dist_ratio = 0.7;

    let k1 = (mean_dist_ratio * 2. * PI * r1 / h).round() as i32;
    let k2 = (mean_dist_ratio * 2. * PI * r2 / h).round() as i32;

    // generate boundary points
    for &(k, r) in &[(k1, r1), (k2, r2)] {
        for i in 0..k {
            let (y, x) = (2. * PI * i as f64 / k as f64).sin_cos();
            ps.push(Point(r * x, r * y));
        }
    }

    // make boundary points active
    active.extend(&ps);

    let n_fixed = ps.len();

    let annulus_dist = AnnulusDist::new(h, 2.0 * h);

    while !active.is_empty() {
        // select a random active point
        let i = rng.gen_range(0, active.len());

        let c = active[i];

        if let Some(p) = annulus_dist.ind_iter(&mut rng)
                                     .map(|p| p + c)
                                     .take(n_gen)
                                     .filter(|&p| {
                                         let d = dist(p, Point(0., 0.));
                                         r1 <= d && d <= r2
                                     })
                                     .filter(|&p| ps.iter().all(|&q| dist(p, q) >= h))
                                     .next() {
            ps.push(p);
            active.push(p);
        } else {
            active.remove(i);
        }

    }

    let indices = qhull_triangulation(&ps);

    let mut neighbors: Vec<Vec<usize>> = ps.iter().map(|_| vec![]).collect();
    for poly in &indices {
        for (&i, &j) in poly.iter().zip(poly.iter().cycle().skip(1)) {
            neighbors[i].push(j);
            neighbors[j].push(i);
        }
    }

    for list in &mut neighbors {
        list.sort();
        list.dedup();
    }

    // Laplace smoothing
    let n_laplace_step = 1;

    let laplace_eps = 1.0e-3;

    for _ in 0..n_laplace_step {
        let mut change = 0.;
        // Gauss-Seidel
        for i in n_fixed..ps.len() {
            let mut x = 0.;
            let mut y = 0.;
            for &j in &neighbors[i] {
                x += ps[j].0;
                y += ps[j].1;
            }
            let n = neighbors[i].len() as f64;
            let p = ps[i];
            let q = Point(x / n, y / n);
            ps[i] = q;
            change += dist_sq(p, q);
        }

        if change.sqrt() < laplace_eps {
            break;
        }
    }

    if !args.flag_no_show {
        let mut fg = Figure::new();
        if let Some(file) = args.flag_plot {
            fg.set_terminal("pngcairo size 720, 720", &file);
        }

        fg.clear_axes();
        {
            let axes = fg.axes2d();
            axes.set_aspect_ratio(Fix(1.));
            for poly in indices {
                axes.lines(poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].0),
                           poly.iter().cycle().take(poly.len() + 1).map(|&i| ps[i as usize].1),
                           &[]);
            }
        }

        fg.show();
    }

}
<|endoftext|>