<commit_before>#![feature(io, os, core, collections, rustc_private)]

extern crate getopts;
extern crate selecta;

use getopts::{optopt,getopts};
use selecta::configuration::Configuration;
use selecta::search::Search;
use selecta::tty::TTY;
use selecta::tty::IO;
use selecta::screen::Screen;

#[allow(dead_code)]
fn main() {
    let initial_query = extract_initial_query();
    let lines = read_lines();

    let config = Configuration::from_inputs(lines, initial_query, Some(20));
    let mut search = Search::blank(config);

    let mut tty = TTY::new();
    let mut screen = Screen::new();

    screen.print(&search);

    while !search.is_done() {
        let input = tty.read();
        match input {
            Some(n) => {
                search = screen.handle_keystroke(search, n.as_slice());
            },
            None => break,
        };
        screen.print(&search);
    }
    tty.reset();
    println!("{}\n", search.selection.unwrap_or("None".to_string()));
    screen.ansi.show_cursor();
}

fn extract_initial_query() -> Option<String> {
    let args = std::os::args();
    let opts = &[
        optopt("s", "search", "initial search query", ""),
    ];
    let matches = getopts(args.tail(), opts).unwrap();

    matches.opt_str("s")
}

fn read_lines() -> Vec<String> {
    std::old_io::stdio::stdin().lock().lines().map( |line| {
        line.unwrap()
    }).collect()
}
<commit_msg>Print newlines to avoid clobbering existing screen output<commit_after>#![feature(io, os, core, collections, rustc_private)]

extern crate getopts;
extern crate selecta;

use getopts::{optopt,getopts};
use selecta::configuration::Configuration;
use selecta::search::Search;
use selecta::tty::TTY;
use selecta::tty::IO;
use selecta::screen::Screen;

#[allow(dead_code)]
fn main() {
    let initial_query = extract_initial_query();
    let lines = read_lines();

    let config = Configuration::from_inputs(lines, initial_query, Some(20));
    let mut search = Search::blank(config);

    let mut tty = TTY::new();
    let mut screen = Screen::new();

    for _ in 0..search.config.visible_limit {
        tty.write("");
    }

    screen.print(&search);

    while !search.is_done() {
        let input = tty.read();
        match input {
            Some(n) => {
                search = screen.handle_keystroke(search, n.as_slice());
            },
            None => break,
        };
        screen.print(&search);
    }
    tty.reset();
    println!("{}\n", search.selection.unwrap_or("None".to_string()));
    screen.ansi.show_cursor();
}

fn extract_initial_query() -> Option<String> {
    let args = std::os::args();
    let opts = &[
        optopt("s", "search", "initial search query", ""),
    ];
    let matches = getopts(args.tail(), opts).unwrap();

    matches.opt_str("s")
}

fn read_lines() -> Vec<String> {
    std::old_io::stdio::stdin().lock().lines().map( |line| {
        line.unwrap()
    }).collect()
}
<|endoftext|>


<commit_before>#![allow(unused_parens)]
#![feature(custom_derive, plugin)] // necessary for serde
#![plugin(serde_macros)]
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

extern crate iron ;
extern crate staticfile;
extern crate mount;
extern crate router;

extern crate mpv ;
extern crate sdl2;
extern crate sdl2_ttf;
extern crate sdl2_image;
extern crate sdl2_sys;
#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate clap;
use clap::{Arg, App};

mod utils;
mod display;
mod init;
mod subtitles;
mod toyunda_player;

use toyunda_player::ToyundaPlayer;
use std::os::raw::c_void;

fn main() {
    // init the logger
    env_logger::init().unwrap();

    let matches = App::new("Toyunda Player")
                          .version(crate_version!())
                          .after_help("PLAYER SHORTCUTS :\n    \
                            * V : Hides / Shows subtitles\n    \
                            * F : Toggles fullscreen\n    \
                            * + / - : Raises / Lowers the volume\n    \
                            * Left / Right arrow : Seek backwards / frontwards\n    \
                            ")
                          .author("Cobrand")
                          .about("A flexible karaoke player for the epitanime association")
                          .arg(Arg::with_name("karaoke_mode")
                            .short("k")
                            .long("karaoke")
                            .help("Sets mode to karaoke mode"))
                          .arg(Arg::with_name("edit_mode")
                            .short("e")
                            .long("edit")
                            .help("Sets mode to edit mode")
                            .conflicts_with("karaoke_mode"))
                          .arg(Arg::with_name("fullscreen")
                            .short("f")
                            .long("fullscreen")
                            .help("Enables fullscreen"))
                          .arg(Arg::with_name("volume")
                            .short("v")
                            .long("volume")
                            .takes_value(true)
                            .help("Initial volume of the player; Default is 100"))
                          .arg(Arg::with_name("quit")
                            .short("q")
                            .long("quit")
                            .help("Forces quiting the player once the waiting queue is finished"))
                          .arg(Arg::with_name("no-quit")
                            .long("no-quit")
                            .conflicts_with("quit")
                            .help("Forces keeping alive the player once the waiting queue is finished"))
                          .arg(Arg::with_name("VIDEO_FILE")
                            .help("Sets the video file(s) to play")
                            .multiple(true)
                            .required(true))
                          .get_matches();

    // INIT SDL
    let sdl_context = sdl2::init().unwrap();
    let mut video_subsystem = sdl_context.video().unwrap();
    let renderer = init::init_sdl(&mut video_subsystem,&matches);
    let video_subsystem_ptr = &mut video_subsystem as *mut _ as *mut c_void;
    // INIT MPV
    let mut mpv_builder = mpv::MpvHandlerBuilder::new().expect("Error while creating MPV builder");
    mpv_builder.set_option("sid", "no").unwrap(); // disables subtitles if any
    mpv_builder.set_option("softvol", "yes").unwrap(); // enables softvol so it can go higher than 100%
    mpv_builder.set_option("softvol-max", 250.0).unwrap(); // makes the max volume at 250%
    mpv_builder.try_hardware_decoding().unwrap(); // try hardware decoding instead of software decoding
    let mpv = mpv_builder.build_with_gl(Some(init::get_proc_address), video_subsystem_ptr)
       .expect("Error while initializing MPV");
    // BIND MPV WITH SDL

    let displayer = display::Displayer::new(renderer)
                        .expect("Failed to init displayer");

    if matches.is_present("karaoke_mode") {
        let mouse_utils = sdl_context.mouse();
        mouse_utils.show_cursor(false);
        // dont show cursor on top of player in karaoke mode
    }
    // Create a new displayer for the toyunda_player

    let mut toyunda_player = ToyundaPlayer::new(mpv, displayer);
    match toyunda_player.start(matches) {
        Err(e) => {
            error!("Failed to start player with given arguments, expect default parameters !\n\
                    '{}' ({:?})",e,e);
        }
        Ok(_) => {
            info!("Parsed arguments successfully");
        }
    };
    let res = toyunda_player.main_loop(&sdl_context);
    match res {
        Ok(_) => {
            info!("Toyunda Player finished gracefully");
        },
        Err(e) => {
            error!("An uncoverable error occured : {}",e);
        }
    };
}
<commit_msg>[Video File] in CL is not required anymore<commit_after>#![allow(unused_parens)]
#![feature(custom_derive, plugin)] // necessary for serde
#![plugin(serde_macros)]
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

extern crate iron ;
extern crate staticfile;
extern crate mount;
extern crate router;

extern crate mpv ;
extern crate sdl2;
extern crate sdl2_ttf;
extern crate sdl2_image;
extern crate sdl2_sys;
#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate clap;
use clap::{Arg, App};

mod utils;
mod display;
mod init;
mod subtitles;
mod toyunda_player;

use toyunda_player::ToyundaPlayer;
use std::os::raw::c_void;

fn main() {
    // init the logger
    env_logger::init().unwrap();

    let matches = App::new("Toyunda Player")
                          .version(crate_version!())
                          .after_help("PLAYER SHORTCUTS :\n    \
                            * V : Hides / Shows subtitles\n    \
                            * F : Toggles fullscreen\n    \
                            * + / - : Raises / Lowers the volume\n    \
                            * Left / Right arrow : Seek backwards / frontwards\n    \
                            ")
                          .author("Cobrand")
                          .about("A flexible karaoke player for the epitanime association")
                          .arg(Arg::with_name("karaoke_mode")
                            .short("k")
                            .long("karaoke")
                            .help("Sets mode to karaoke mode"))
                          .arg(Arg::with_name("edit_mode")
                            .short("e")
                            .long("edit")
                            .help("Sets mode to edit mode")
                            .conflicts_with("karaoke_mode"))
                          .arg(Arg::with_name("fullscreen")
                            .short("f")
                            .long("fullscreen")
                            .help("Enables fullscreen"))
                          .arg(Arg::with_name("volume")
                            .short("v")
                            .long("volume")
                            .takes_value(true)
                            .help("Initial volume of the player; Default is 100"))
                          .arg(Arg::with_name("quit")
                            .short("q")
                            .long("quit")
                            .help("Forces quiting the player once the waiting queue is finished"))
                          .arg(Arg::with_name("no-quit")
                            .long("no-quit")
                            .conflicts_with("quit")
                            .help("Forces keeping alive the player once the waiting queue is finished"))
                          .arg(Arg::with_name("VIDEO_FILE")
                            .help("Sets the video file(s) to play")
                            .multiple(true))
                          .get_matches();

    // INIT SDL
    let sdl_context = sdl2::init().unwrap();
    let mut video_subsystem = sdl_context.video().unwrap();
    let renderer = init::init_sdl(&mut video_subsystem,&matches);
    let video_subsystem_ptr = &mut video_subsystem as *mut _ as *mut c_void;
    // INIT MPV
    let mut mpv_builder = mpv::MpvHandlerBuilder::new().expect("Error while creating MPV builder");
    mpv_builder.set_option("sid", "no").unwrap(); // disables subtitles if any
    mpv_builder.set_option("softvol", "yes").unwrap(); // enables softvol so it can go higher than 100%
    mpv_builder.set_option("softvol-max", 250.0).unwrap(); // makes the max volume at 250%
    mpv_builder.try_hardware_decoding().unwrap(); // try hardware decoding instead of software decoding
    let mpv = mpv_builder.build_with_gl(Some(init::get_proc_address), video_subsystem_ptr)
       .expect("Error while initializing MPV");
    // BIND MPV WITH SDL

    let displayer = display::Displayer::new(renderer)
                        .expect("Failed to init displayer");

    if matches.is_present("karaoke_mode") {
        let mouse_utils = sdl_context.mouse();
        mouse_utils.show_cursor(false);
        // dont show cursor on top of player in karaoke mode
    }
    // Create a new displayer for the toyunda_player

    let mut toyunda_player = ToyundaPlayer::new(mpv, displayer);
    match toyunda_player.start(matches) {
        Err(e) => {
            error!("Failed to start player with given arguments, expect default parameters !\n\
                    '{}' ({:?})",e,e);
        }
        Ok(_) => {
            info!("Parsed arguments successfully");
        }
    };
    let res = toyunda_player.main_loop(&sdl_context);
    match res {
        Ok(_) => {
            info!("Toyunda Player finished gracefully");
        },
        Err(e) => {
            error!("An uncoverable error occured : {}",e);
        }
    };
}
<|endoftext|>


<commit_before>extern crate sdl2;
mod cpu;
mod registers;
use cpu::CPU;

fn main() {
    let mut cpu = CPU::new();
    let r1 = cpu.alu_add(128, 127);
    let r2 = cpu.alu_adc(128,128);
    let r3 = cpu.alu_adc(128,0);
    println!("{}", r1);
    println!("{}", r2);
    println!("{}", r3);
}<commit_msg>Removed testing code from main kek<commit_after>extern crate sdl2;
mod cpu;
mod registers;
use cpu::CPU;

fn main() {

}<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate getopts;

use std::{env, io};
use std::io::{Read, Write};
use std::error::Error;

use getopts::Options;

mod error;

mod options;
use options::{DeleteOption, GitOptions};

mod branches;
use branches::Branches;

mod commands;
use commands::*;

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

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

    let mut opts = Options::new();
    opts.optflag("l", "locals", "only delete local branches");
    opts.optflag("r", "remotes", "only delete remote branches");
    opts.optflag("y", "yes", "skip the check for deleting branches");
    opts.optopt("R", "remote", "changes the git remote used (default is origin)", "REMOTE");
    opts.optopt("b", "branch", "changes the base for merged branches (default is master)", "BRANCH");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("v", "version", "print the version");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            println!("{}", e);
            print_help(opts);
            return;
        }
    };

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

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

    validate_git_installation().unwrap_or_else(print_and_exit);

    let git_options = GitOptions::new(&matches);
    git_options.validate().unwrap_or_else(print_and_exit);

    let branches = merged_branches(&git_options);

    if branches.string.len() == 0 {
        println!("No branches to delete, you're clean!");
        return;
    }

    let del_opt = DeleteOption::new(&matches);

    if !matches.opt_present("y") {
        print_warning(&branches, &del_opt);

        // Read the user's response on continuing
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        match input.to_lowercase().as_ref() {
            "y\n" => (),
            "yes\n" => (),
            "\n" => (),
            _ => return,
        }
    }

    let msg = delete_branches(&branches, &del_opt, &git_options);
    println!("\n{}", msg);
}

fn print_version() {
    println!("git-clean version {}", VERSION);
}

fn print_help(opts: Options) {
    print!("{}", opts.usage("Usage: git-clean [options]"));
}

fn print_warning(branches: &Branches, del_opt: &DeleteOption) {
    println!("{}", del_opt.warning_message());
    println!("{}", branches.format_columns());
    print!("Continue? (Y/n) ");
    io::stdout().flush().unwrap();
}

fn merged_branches(git_options: &GitOptions) -> Branches {
    let mut branches: Vec<String> = vec![];
    println!("Updating remote {}", git_options.remote);
    run_command_with_no_output(&["git", "remote", "update", &git_options.remote, "--prune"]);

    let merged_branches_regex = format!("\\*{branch}|\\s{branch}", branch = &git_options.base_branch);
    let merged_branches_filter = spawn_piped(&["grep", "-vE", &merged_branches_regex]);
    let merged_branches_cmd = run_command(&["git", "branch", "--merged"]);

    {
        merged_branches_filter.stdin.unwrap().write_all(&merged_branches_cmd.stdout).unwrap();
    }

    let mut merged_branches_output = String::new();
    merged_branches_filter.stdout.unwrap().read_to_string(&mut merged_branches_output).unwrap();
    let merged_branches = merged_branches_output.split("\n").map(|b| b.trim().into()).collect::<Vec<String>>();

    let local_branches_regex = format!("\\*{branch}|\\s{branch}", branch = &git_options.base_branch);
    let local_branches_filter = spawn_piped(&["grep", "-vE", &local_branches_regex]);
    let local_branches_cmd = run_command(&["git", "branch"]);

    {
        local_branches_filter.stdin.unwrap().write_all(&local_branches_cmd.stdout).unwrap();
    }

    let mut local_branches_output = String::new();
    local_branches_filter.stdout.unwrap().read_to_string(&mut local_branches_output).unwrap();
    let local_branches = local_branches_output.split("\n").map(|b| b.trim().into()).collect::<Vec<String>>();

    let remote_branches_regex = format!("(HEAD|{})", &git_options.base_branch);
    let remote_branches_filter = spawn_piped(&["grep", "-vE", &remote_branches_regex]);
    let remote_branches_cmd = run_command(&["git", "branch", "-r"]);

    {
        remote_branches_filter.stdin.unwrap().write_all(&remote_branches_cmd.stdout).unwrap();
    }

    let mut remote_branches_output = String::new();
    remote_branches_filter.stdout.unwrap().read_to_string(&mut remote_branches_output).unwrap();
    let remote_branches = remote_branches_output.split("\n").map(|b| b.trim().into()).collect::<Vec<String>>();

    for branch in local_branches {
        // First check if the local branch doesn't exist in the remote, it's the cheapest and easiest
        // way to determine if we want to suggest to delete it.
        if !remote_branches.contains(&format!("{}/{}", &git_options.remote, branch)) {
            branches.push(branch.to_owned());
            continue;
        }

        // If it does exist in the remote, check to see if it's listed in git branches --merged. If
        // it is, that means it wasn't merged using Github squashes, and we can suggest it.
        if merged_branches.contains(&branch) {
            branches.push(branch.to_owned());
            continue;
        }

        // If neither of the above matched, merge master into the branch and see if there's any
        // diff. If there's no diff, then it has likely been merged with Github squashes, and we
        // can suggest it.
        run_command(&["git", "checkout", &branch]);
        match run_command_with_status(&["git", "pull", "--ff-only", &git_options.remote, &git_options.base_branch]) {
            Ok(status) => {
                if !status.success() {
                    println!("Encountered error trying to update branch {}, skipping", branch);
                    run_command(&["git", "reset", "--hard"]);
                    continue;
                }
            }
            Err(err) => {
                println!("Encountered error trying to update branch {} with branch {}: {}", branch, git_options.base_branch, err);
                run_command(&["git", "reset", "--hard"]);
                continue;
            }
        }
        let git_diff_cmd = run_command(&["git", "diff", &git_options.base_branch]);
        let git_diff = String::from_utf8(git_diff_cmd.stdout).unwrap();

        // If there's no diff with the base branch, suggest it.
        if git_diff.trim().len() == 0 {
            branches.push(branch.to_owned());
        }

        run_command(&["git", "checkout", &git_options.base_branch]);
    }

    // if deleted in remote, list
    //
    // g branch -d -r <remote>/<branch>
    // g branch -d <branch>

    Branches::new(branches)
}

fn delete_branches(branches: &Branches, options: &DeleteOption, git_options: &GitOptions) -> String {
    match *options {
        DeleteOption::Local => delete_local_branches(branches),
        DeleteOption::Remote => delete_remote_branches(branches, git_options),
        DeleteOption::Both => {
            let local_output = delete_local_branches(branches);
            let remote_output = delete_remote_branches(branches, git_options);
            ["Remote:".to_owned(), remote_output, "\nLocal:".to_owned(), local_output].join("\n")
        },
    }
}

fn print_and_exit<E: Error>(e: E) {
    println!("{}", e);
    std::process::exit(1);
}

#[cfg(test)]
mod test {
    use options::{DeleteOption};
    use branches::Branches;

    use super::print_warning;

    #[test]
    fn test_print_warning() {
        print_warning(&Branches::new(vec!["branch".to_owned()]), &DeleteOption::Both);
    }
}
<commit_msg>Checkout the base branch after encountering a pull error<commit_after>#![deny(warnings)]

extern crate getopts;

use std::{env, io};
use std::io::{Read, Write};
use std::error::Error;

use getopts::Options;

mod error;

mod options;
use options::{DeleteOption, GitOptions};

mod branches;
use branches::Branches;

mod commands;
use commands::*;

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

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

    let mut opts = Options::new();
    opts.optflag("l", "locals", "only delete local branches");
    opts.optflag("r", "remotes", "only delete remote branches");
    opts.optflag("y", "yes", "skip the check for deleting branches");
    opts.optopt("R", "remote", "changes the git remote used (default is origin)", "REMOTE");
    opts.optopt("b", "branch", "changes the base for merged branches (default is master)", "BRANCH");
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("v", "version", "print the version");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            println!("{}", e);
            print_help(opts);
            return;
        }
    };

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

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

    validate_git_installation().unwrap_or_else(print_and_exit);

    let git_options = GitOptions::new(&matches);
    git_options.validate().unwrap_or_else(print_and_exit);

    let branches = merged_branches(&git_options);

    if branches.string.len() == 0 {
        println!("No branches to delete, you're clean!");
        return;
    }

    let del_opt = DeleteOption::new(&matches);

    if !matches.opt_present("y") {
        print_warning(&branches, &del_opt);

        // Read the user's response on continuing
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        match input.to_lowercase().as_ref() {
            "y\n" => (),
            "yes\n" => (),
            "\n" => (),
            _ => return,
        }
    }

    let msg = delete_branches(&branches, &del_opt, &git_options);
    println!("\n{}", msg);
}

fn print_version() {
    println!("git-clean version {}", VERSION);
}

fn print_help(opts: Options) {
    print!("{}", opts.usage("Usage: git-clean [options]"));
}

fn print_warning(branches: &Branches, del_opt: &DeleteOption) {
    println!("{}", del_opt.warning_message());
    println!("{}", branches.format_columns());
    print!("Continue? (Y/n) ");
    io::stdout().flush().unwrap();
}

fn merged_branches(git_options: &GitOptions) -> Branches {
    let mut branches: Vec<String> = vec![];
    println!("Updating remote {}", git_options.remote);
    run_command_with_no_output(&["git", "remote", "update", &git_options.remote, "--prune"]);

    let merged_branches_regex = format!("\\*{branch}|\\s{branch}", branch = &git_options.base_branch);
    let merged_branches_filter = spawn_piped(&["grep", "-vE", &merged_branches_regex]);
    let merged_branches_cmd = run_command(&["git", "branch", "--merged"]);

    {
        merged_branches_filter.stdin.unwrap().write_all(&merged_branches_cmd.stdout).unwrap();
    }

    let mut merged_branches_output = String::new();
    merged_branches_filter.stdout.unwrap().read_to_string(&mut merged_branches_output).unwrap();
    let merged_branches = merged_branches_output.split("\n").map(|b| b.trim().into()).collect::<Vec<String>>();

    let local_branches_regex = format!("\\*{branch}|\\s{branch}", branch = &git_options.base_branch);
    let local_branches_filter = spawn_piped(&["grep", "-vE", &local_branches_regex]);
    let local_branches_cmd = run_command(&["git", "branch"]);

    {
        local_branches_filter.stdin.unwrap().write_all(&local_branches_cmd.stdout).unwrap();
    }

    let mut local_branches_output = String::new();
    local_branches_filter.stdout.unwrap().read_to_string(&mut local_branches_output).unwrap();
    let local_branches = local_branches_output.split("\n").map(|b| b.trim().into()).collect::<Vec<String>>();

    let remote_branches_regex = format!("(HEAD|{})", &git_options.base_branch);
    let remote_branches_filter = spawn_piped(&["grep", "-vE", &remote_branches_regex]);
    let remote_branches_cmd = run_command(&["git", "branch", "-r"]);

    {
        remote_branches_filter.stdin.unwrap().write_all(&remote_branches_cmd.stdout).unwrap();
    }

    let mut remote_branches_output = String::new();
    remote_branches_filter.stdout.unwrap().read_to_string(&mut remote_branches_output).unwrap();
    let remote_branches = remote_branches_output.split("\n").map(|b| b.trim().into()).collect::<Vec<String>>();

    for branch in local_branches {
        // First check if the local branch doesn't exist in the remote, it's the cheapest and easiest
        // way to determine if we want to suggest to delete it.
        if !remote_branches.contains(&format!("{}/{}", &git_options.remote, branch)) {
            branches.push(branch.to_owned());
            continue;
        }

        // If it does exist in the remote, check to see if it's listed in git branches --merged. If
        // it is, that means it wasn't merged using Github squashes, and we can suggest it.
        if merged_branches.contains(&branch) {
            branches.push(branch.to_owned());
            continue;
        }

        // If neither of the above matched, merge master into the branch and see if there's any
        // diff. If there's no diff, then it has likely been merged with Github squashes, and we
        // can suggest it.
        run_command(&["git", "checkout", &branch]);
        match run_command_with_status(&["git", "pull", "--ff-only", &git_options.remote, &git_options.base_branch]) {
            Ok(status) => {
                if !status.success() {
                    println!("Encountered error trying to update branch {}, skipping", branch);
                    run_command(&["git", "reset", "--hard"]);
                    run_command(&["git", "checkout", &git_options.base_branch]);
                    continue;
                }
            }
            Err(err) => {
                println!("Encountered error trying to update branch {} with branch {}: {}", branch, git_options.base_branch, err);
                run_command(&["git", "reset", "--hard"]);
                run_command(&["git", "checkout", &git_options.base_branch]);
                continue;
            }
        }
        let git_diff_cmd = run_command(&["git", "diff", &git_options.base_branch]);
        let git_diff = String::from_utf8(git_diff_cmd.stdout).unwrap();

        // If there's no diff with the base branch, suggest it.
        if git_diff.trim().len() == 0 {
            branches.push(branch.to_owned());
        }

        run_command(&["git", "checkout", &git_options.base_branch]);
    }

    // if deleted in remote, list
    //
    // g branch -d -r <remote>/<branch>
    // g branch -d <branch>

    Branches::new(branches)
}

fn delete_branches(branches: &Branches, options: &DeleteOption, git_options: &GitOptions) -> String {
    match *options {
        DeleteOption::Local => delete_local_branches(branches),
        DeleteOption::Remote => delete_remote_branches(branches, git_options),
        DeleteOption::Both => {
            let local_output = delete_local_branches(branches);
            let remote_output = delete_remote_branches(branches, git_options);
            ["Remote:".to_owned(), remote_output, "\nLocal:".to_owned(), local_output].join("\n")
        },
    }
}

fn print_and_exit<E: Error>(e: E) {
    println!("{}", e);
    std::process::exit(1);
}

#[cfg(test)]
mod test {
    use options::{DeleteOption};
    use branches::Branches;

    use super::print_warning;

    #[test]
    fn test_print_warning() {
        print_warning(&Branches::new(vec!["branch".to_owned()]), &DeleteOption::Both);
    }
}
<|endoftext|>


<commit_before>use luminance::{Dim2, Flat, RGBA32F, Texture};

/// Time.
pub type Time = f32;

/// A clip is an object that implements a visual sequence.
pub struct Clip<'a> {
  act: Box<Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> + 'a>
}

impl<'a> Clip<'a> {
  pub fn new<F>(act: F) -> Self where F: 'a + Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> {
    Clip {
      act: Box::new(act)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a> {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'a Clip<'a>
}

impl<'a> Cut<'a> {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'a Clip<'a>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a> {
  cuts: Vec<Cut<'a>>
}

impl<'a> Track<'a> {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b> From<&'b [Cut<'a>]> for Track<'a> {
  fn from(cuts: &'b [Cut<'a>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a> {
  tracks: Vec<Track<'a>>,
}

impl<'a> Timeline<'a> {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  pub fn add_track(&mut self, track: Track<'a>) {
    self.tracks.push(track);
  }
}

impl<'a, 'b> From<&'b [Track<'a>]> for Timeline<'a> {
  fn from(tracks: &'b [Track<'a>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}
<commit_msg>Timeline::play.<commit_after>use luminance::{Dim2, Flat, RGBA32F, Texture};

/// Time.
pub type Time = f32;

/// A clip is an object that implements a visual sequence.
pub struct Clip<'a> {
  act: Box<Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> + 'a>
}

impl<'a> Clip<'a> {
  pub fn new<F>(act: F) -> Self where F: 'a + Fn(Time) -> &'a Texture<Flat, Dim2, RGBA32F> {
    Clip {
      act: Box::new(act)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a> {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'a Clip<'a>
}

impl<'a> Cut<'a> {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'a Clip<'a>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a> {
  cuts: Vec<Cut<'a>>
}

impl<'a> Track<'a> {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b> From<&'b [Cut<'a>]> for Track<'a> {
  fn from(cuts: &'b [Cut<'a>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a> {
  tracks: Vec<Track<'a>>,
}

impl<'a> Timeline<'a> {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  pub fn add_track(&mut self, track: Track<'a>) {
    self.tracks.push(track);
  }

  // TODO: currently, we play the first track we find; add transition support
  pub fn play(&self, t: Time) -> Option<&'a Texture<Flat, Dim2, RGBA32F>> {
    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          return Some((cut.clip.act)(t));
        }
      }
    }

    None
  }
}

impl<'a, 'b> From<&'b [Track<'a>]> for Timeline<'a> {
  fn from(tracks: &'b [Track<'a>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate clap;
extern crate clipboard;
extern crate ncurses;
extern crate mmo_parser_backend;
#[macro_use]
extern crate json;

use std::sync::mpsc::{self, RecvTimeoutError};

use libc::system;
use std::ffi::{CString, CStr};
use std::os::raw::c_char;

use clap::{Arg, App};

use clipboard::ClipboardContext;

use ncurses::*;

use std::fmt;

use std::{thread, time};

mod structs;

use mmo_parser_backend::eventloop::EventLoop;

fn speak(data: &CStr) {
    extern { fn system(data: *const c_char); }

    unsafe { system(data.as_ptr()) }
}

fn main()
{
    let matches = App::new("mmo_parser_cli")
        .version("0.1.0")
        .author("Bergman. <Morindhal@gmail.com>")
        .about("Parses MMO logs")
            .arg(Arg::with_name("GAME"))
                .help("Sets the game to parse, EQ2 is default")
            .arg(Arg::with_name("FILE")
                .help("Sets the log-file to use")
                .required(true)
                .index(1))
            .arg(Arg::with_name("player")
                .required(true)
                .help("Sets the character name to parse, this only catches the YOU and YOUR lines"))
        .get_matches();
    /*Set log-file and player whos view the combat is parsed from based on CL input, player should be replaced with a name collected from the file-string*/
    let from_file = matches.value_of("FILE").unwrap();
    let player = matches.value_of("player").unwrap();
    let player_display = String::from(player);

    let (send_data_request, recieve_answer) = EventLoop::new(String::from(from_file), String::from(player));

    /*start the n-curses UI*/
    initscr();
    keypad(stdscr(), true);
    noecho();
    start_color();
    init_pair(1, COLOR_RED, COLOR_BLACK);

    let (input_send, input_recieve) = mpsc::channel();
    //let (timer_tx, timer_rx) = mpsc::channel();

    let buttonlistener = thread::spawn(move ||
    {
        'input: loop/*Listen to input, send input to main*/
        {
            input_send.send(getch()).unwrap();
        }
    });

/*    let timer_counter = thread::spawn(move ||
    {
        let timeout = time::Duration::from_millis(500);
        let mut time = time::Instant::now();
        let mut timers: HashMap<&str, i32> = HashMap::new();
        'timer: loop//Listen to timers, give tts warning when time is up
        {
            match timer_rx.recv_timeout()
            {
                Ok(val) =>
                {
                    //add countdown timer
                    timers.insert(val);
                },
                Err(e) => {}
            }
            for (text, time) in timers
            {
                if time <= 0
                {
                    time -= time.elapsed().as_secs();
                    speak(&CString::new(format!("espeak \"{}\"", text)).unwrap());
                    timers.remove(&text);
                }
            }
        }
    });*/

    /*
    * Send request for data
    * recieve data, wait for data until data is sent.
    */
    let mut jsonobject:json::JsonValue = object!{"initial" => true};
    send_data_request.send(Box::new(object!{"initial" => true}));
    jsonobject = *(recieve_answer.recv().unwrap());

    let ui = thread::spawn(move ||
    {
        let mut ctx = ClipboardContext::new().unwrap();
        let timeout = time::Duration::from_millis(1);
        let mut ui_data = structs::ui_data{nav_xy: vec![(0,0)], nav_lock_encounter: false, nav_lock_combatant: false, nav_lock_filter: false, nav_lock_refresh: true, nav_main_win_scroll: (0, 0), nav_encounter_win_scroll: (5, 0), filters: String::from(""), debug: false};
        let mut update_ui = true;

        'ui: loop
        {
            send_data_request.send(Box::new(ui_data.jsonify()));
            match recieve_answer.recv_timeout(timeout)
            {
                Ok(val) =>
                {
                    jsonobject = *val;
                },
                Err(e) => {}
            }
            if !ui_data.nav_lock_encounter && ui_data.nav_lock_refresh
            {
                if jsonobject["attacks"].len() != 0 && !ui_data.is_locked()
                {
                    ui_data.nav_xy[0].0 = jsonobject["encounters"].len() as i32 - 1;
                    ui_data.nav_encounter_win_scroll.1 = 0;
                }
            }
            match input_recieve.recv_timeout(timeout)
            {
                Ok(val) => match val
                    {
                        27 => // escape
                        {
                            endwin();
                            std::process::exit(1);
                        },
                        99 | 67 =>  // C | c
                        {
                            if !ui_data.is_locked()
                            {
                                match ctx.set_contents(format!("{}", jsonobject["encounters"][ui_data.nav_xy[0].0 as usize - ui_data.nav_encounter_win_scroll.1 as usize]))//if ui_data.nav_xy[0].0 >= encounters.len() as i32 {&encounters[encounters.len()-1 as usize]} else {&encounters[ui_data.nav_xy[0].0 as usize]}))
                                {
                                    Ok(_)=>
                                    {
                                        /*This is currently linux dependant, probably not the best idea for future alerts but for now it "works" assuming one has the correct file on the system*/
                                        speak(&CString::new(format!("paplay /usr/share/sounds/freedesktop/stereo/message.oga")).unwrap());
                                    },
                                    Err(e)=>{println!("Clipboard error: {}", e);}
                                };
                            }
                            else
                            {
                                ui_data.filters.push( val as u8 as char );
                                update_ui = true;
                            }
                        },
                        KEY_UP =>
                        {
                            if ui_data.nav_xy.last().unwrap().0 > 0
                            {
                                if !ui_data.is_locked()
                                {
                                    if  ui_data.nav_encounter_win_scroll.0 - 2 < jsonobject["encounters"].len() as i32
                                    {
                                        if ui_data.nav_encounter_win_scroll.1 < jsonobject["encounters"].len() as i32 - ui_data.nav_encounter_win_scroll.0 - 2
                                        {
                                            ui_data.nav_encounter_win_scroll.1 += 1;
                                        }
                                        else
                                        {
                                            ui_data.nav_xy.last_mut().unwrap().0 -= 1;
                                        }
                                    }
                                    else
                                    {
                                        ui_data.nav_xy.last_mut().unwrap().0 -= 1;
                                    }
                                }
                                else if ui_data.nav_lock_encounter && jsonobject["combatants"].len() as i32 - ui_data.nav_main_win_scroll.0 - ui_data.nav_main_win_scroll.1 < 0 ||
                                        ui_data.nav_lock_encounter && jsonobject["combatants"].len() as i32 - ui_data.nav_main_win_scroll.0 - ui_data.nav_main_win_scroll.1 < 0
                                {
                                    ui_data.nav_main_win_scroll.1 += 1;speak(&CString::new(format!("paplay /usr/share/sounds/freedesktop/stereo/message.oga")).unwrap());
                                }
                                else
                                {
                                    ui_data.nav_xy.last_mut().unwrap().0 -= 1;
                                }
                            }
                            update_ui = true;
                        },
                        KEY_DOWN =>
                        {
                            if ui_data.nav_lock_encounter && ui_data.nav_xy[1].0 < jsonobject["combatants"].len() as i32 - 1
                            {
                                ui_data.nav_xy.last_mut().unwrap().0 += 1;
                            }
                            else if ui_data.nav_lock_combatant
                            {
                                ui_data.nav_xy.last_mut().unwrap().0 += 1;
                            }
                            else if !ui_data.is_locked() && ui_data.nav_xy.last().unwrap().0 < jsonobject["encounters"].len() as i32 - 1
                            {
                                if ui_data.nav_encounter_win_scroll.1 > 0
                                {
                                    ui_data.nav_encounter_win_scroll.1 -= 1;
                                }
                                else
                                {
                                    ui_data.nav_xy.last_mut().unwrap().0 += 1;
                                }
                            }
                            update_ui = true;
                        },/*
                        KEY_LEFT =>
                        {
                            if !ui_data.nav_lock_filter
                            {
                                if ui_data.nav_xy.last().unwrap().1 == 1 && ui_data.nav_lock_encounter && !ui_data.nav_lock_combatant
                                {
                                    ui_data.nav_xy.last().unwrap().1 = 0;
                                    update_ui = true;
                                }
                            }
                        },
                        KEY_RIGHT =>
                        {
                            if !ui_data.nav_lock_filter
                            {
                                if ui_data.nav_lock_encounter && ui_data.nav_xy.last().unwrap().0 < encounters.len() as i32
                                {
                                    ui_data.deeper();
                                    ui_data.unlock();
                                    ui_data.nav_lock_combatant = true;
                                     update_ui = true;
                                }
                            }
                        },*/
                        10 => // enter
                        {
                            if ui_data.nav_lock_filter
                            {
                                ui_data.surface();
                                ui_data.nav_lock_filter = false;
                            }
                            else if ui_data.nav_lock_encounter
                            {
                                ui_data.deeper();
                                ui_data.nav_lock_encounter = false;
                                ui_data.nav_lock_combatant = true;
                            }
                            else if !ui_data.is_locked()
                            {
                                if ui_data.nav_xy.last().unwrap().0 == jsonobject["encounters"].len() as i32
                                {
                                    ui_data.nav_xy.last_mut().unwrap().0 -= 1; // ugly code, will bug around --- needs fix
                                }
                                ui_data.deeper();
                                ui_data.nav_lock_encounter = true;
                            }
                            update_ui = true;
                        },
                        KEY_BACKSPACE =>
                        {
                            if !ui_data.nav_lock_filter
                            {
                                if ui_data.nav_lock_encounter
                                {
                                    ui_data.surface();
                                    ui_data.nav_lock_encounter = false;
                                }
                                else if ui_data.nav_lock_combatant
                                {
                                    ui_data.surface();
                                    ui_data.nav_lock_encounter = true;
                                    ui_data.nav_lock_combatant = false;
                                }
                                else  //backspace with ui_data.nav_xy having a len() of 1
                                {
                                }
                            }
                            else
                            {
                                ui_data.filters.pop();
                            }
                            update_ui = true;
                        },
                        43 => // + key
                        {
                            if !ui_data.nav_lock_filter
                            {
                                ui_data.deeper();
                                ui_data.nav_lock_filter = true;
                                update_ui = true;
                            }
                            else
                            {
                                ui_data.filters.push( val as u8 as char );
                                update_ui = true;
                            }
                        },
                        9 => // TAB key
                        {
                            if ui_data.nav_lock_refresh
                            {
                                ui_data.nav_lock_refresh = false;
                            }
                            else
                            {
                                ui_data.nav_lock_refresh = true;
                            }
                            update_ui = true;
                        },
                        _ =>
                        {
                            //ui_update(&format!("{}", val), &player_display, &mut ui_data, &encounters);
                            if ui_data.nav_lock_filter
                            {
                                ui_data.filters.push( val as u8 as char );
                                update_ui = true;
                            }
                        }
                        //ui_update(&format!("{}", val), &player_display, &mut ui_data, &encounters);}//ui_update(&format!("{}", encounters[0].attackers.len()), &player_display, &pointer, &encounters, &current_encounter);}//}
                    },
                Err(e) => {}
            }
            /*
            * parse what data the program is currently interested in and send that in a request to the Sender recieved from mmo_parser_backend
            * parse the response and update the display.
            *
            * do this procedure ONLY if a request for new data has been sent.
            *
            * poll for update every X secs.
            * OR
            * listen to updates from the parser.
            */
            if update_ui && !jsonobject["encounters"].is_empty()
            {
                structs::ui_draw(&format!(""), &player_display, &jsonobject, &mut ui_data);
                update_ui = false;
            }
        }
    });

}

/*
(1477272172)[Mon Oct 24 03:22:52 2016] YOUR Raging Whirlwind multi attacks Bonesnapper for a critical of 38996 cold damage.\r\n
(1477272172)[Mon Oct 24 03:22:52 2016] Kabernet\'s Asylum multi attacks Bonesnapper for a critical of 36622 mental damage.\r\n
(1478123041)[Wed Nov  2 22:44:01 2016] YOU hit training dummy for a critical of 377262 heat damage.
(1478123041)[Wed Nov  2 22:44:01 2016] YOU multi attack training dummy for a critical of 148320 heat damage.
(1478706458)[Wed Nov  9 16:47:38 2016] YOUR Noxious Rending IV hits training dummy for 875382 disease damage.
(1478132824)[Thu Nov  3 01:27:04 2016] Devorstator's Impatience heals Devorstator for 43947 hit points.
YOU aoe attack training dummy for a critical of 204585 heat damage.

println!("{}",buffer) <-- add this to the match X.captures() statement in the None body. Also needs to disable the code in the ui_update function.

send a request-JSON-object to the parser, this contains a wish-list of what I want.
    The response is then forwarded to the update_ui function and drawn.
        This has the benefit of being doable even if the response doesn't exactly match expectations.
    This request changes depending on user input.
        Limit how many resonses that are wanted by low+count.

*/
<commit_msg>Fixed all compile errors, nothing is tested yet though.<commit_after>extern crate libc;
extern crate clap;
extern crate clipboard;
extern crate ncurses;
extern crate mmo_parser_backend;
#[macro_use]
extern crate json;

use std::sync::mpsc::{self, RecvTimeoutError};

use libc::system;
use std::ffi::{CString, CStr};
use std::os::raw::c_char;

use clap::{Arg, App};

use clipboard::ClipboardContext;

use ncurses::*;

use std::fmt;

use std::{thread, time};

mod ui;

use mmo_parser_backend::eventloop::EventLoop;

fn speak(data: &CStr) {
    extern { fn system(data: *const c_char); }

    unsafe { system(data.as_ptr()) }
}

fn main()
{
    let matches = App::new("mmo_parser_cli")
        .version("0.1.0")
        .author("Bergman. <Morindhal@gmail.com>")
        .about("Parses MMO logs")
            .arg(Arg::with_name("GAME"))
                .help("Sets the game to parse, EQ2 is default")
            .arg(Arg::with_name("FILE")
                .help("Sets the log-file to use")
                .required(true)
                .index(1))
            .arg(Arg::with_name("player")
                .required(true)
                .help("Sets the character name to parse, this only catches the YOU and YOUR lines"))
        .get_matches();
    /*Set log-file and player whos view the combat is parsed from based on CL input, player should be replaced with a name collected from the file-string*/
    let from_file = matches.value_of("FILE").unwrap();
    let player = matches.value_of("player").unwrap();
    let player_display = String::from(player);

    let (send_data_request, recieve_answer) = EventLoop::new(String::from(from_file), String::from(player));

    /*start the n-curses UI*/
    initscr();
    keypad(stdscr(), true);
    noecho();
    start_color();
    init_pair(1, COLOR_RED, COLOR_BLACK);

    let (input_send, input_recieve) = mpsc::channel();
    //let (timer_tx, timer_rx) = mpsc::channel();

    let buttonlistener = thread::spawn(move ||
    {
        'input: loop/*Listen to input, send input to main*/
        {
            input_send.send(getch()).unwrap();
        }
    });

/*    let timer_counter = thread::spawn(move ||
    {
        let timeout = time::Duration::from_millis(500);
        let mut time = time::Instant::now();
        let mut timers: HashMap<&str, i32> = HashMap::new();
        'timer: loop//Listen to timers, give tts warning when time is up
        {
            match timer_rx.recv_timeout()
            {
                Ok(val) =>
                {
                    //add countdown timer
                    timers.insert(val);
                },
                Err(e) => {}
            }
            for (text, time) in timers
            {
                if time <= 0
                {
                    time -= time.elapsed().as_secs();
                    speak(&CString::new(format!("espeak \"{}\"", text)).unwrap());
                    timers.remove(&text);
                }
            }
        }
    });*/

    /*
    * Send request for data
    * recieve data, wait for data until data is sent.
    */
    let mut jsonobject:json::JsonValue = object!{"initial" => true};
    send_data_request.send(Box::new(object!{"initial" => true}));
    jsonobject = *(recieve_answer.recv().unwrap());

    let ui = thread::spawn(move ||
    {
        let mut ctx = ClipboardContext::new().unwrap();
        let timeout = time::Duration::from_millis(1);
        let mut ui_data = structs::ui_data{nav_xy: vec![(0,0)], nav_lock_encounter: false, nav_lock_combatant: false, nav_lock_filter: false, nav_lock_refresh: true, nav_main_win_scroll: (0, 0), nav_encounter_win_scroll: (5, 0), filters: String::from(""), debug: false};
        let mut update_ui = true;

        'ui: loop
        {
            send_data_request.send(Box::new(ui_data.jsonify()));
            match recieve_answer.recv_timeout(timeout)
            {
                Ok(val) =>
                {
                    jsonobject = *val;
                },
                Err(e) => {}
            }
            if !ui_data.nav_lock_encounter && ui_data.nav_lock_refresh
            {
                if jsonobject["attacks"].len() != 0 && !ui_data.is_locked()
                {
                    ui_data.nav_xy[0].0 = jsonobject["encounters"].len() as i32 - 1;
                    ui_data.nav_encounter_win_scroll.1 = 0;
                }
            }
            match input_recieve.recv_timeout(timeout)
            {
                Ok(val) => match val
                    {
                        27 => // escape
                        {
                            endwin();
                            std::process::exit(1);
                        },
                        99 | 67 =>  // C | c
                        {
                            if !ui_data.is_locked()
                            {
                                match ctx.set_contents(format!("{}", jsonobject["encounters"][ui_data.nav_xy[0].0 as usize - ui_data.nav_encounter_win_scroll.1 as usize]))//if ui_data.nav_xy[0].0 >= encounters.len() as i32 {&encounters[encounters.len()-1 as usize]} else {&encounters[ui_data.nav_xy[0].0 as usize]}))
                                {
                                    Ok(_)=>
                                    {
                                        /*This is currently linux dependant, probably not the best idea for future alerts but for now it "works" assuming one has the correct file on the system*/
                                        speak(&CString::new(format!("paplay /usr/share/sounds/freedesktop/stereo/message.oga")).unwrap());
                                    },
                                    Err(e)=>{println!("Clipboard error: {}", e);}
                                };
                            }
                            else
                            {
                                ui_data.filters.push( val as u8 as char );
                                update_ui = true;
                            }
                        },
                        KEY_UP =>
                        {
                            if ui_data.nav_xy.last().unwrap().0 > 0
                            {
                                if !ui_data.is_locked()
                                {
                                    if  ui_data.nav_encounter_win_scroll.0 - 2 < jsonobject["encounters"].len() as i32
                                    {
                                        if ui_data.nav_encounter_win_scroll.1 < jsonobject["encounters"].len() as i32 - ui_data.nav_encounter_win_scroll.0 - 2
                                        {
                                            ui_data.nav_encounter_win_scroll.1 += 1;
                                        }
                                        else
                                        {
                                            ui_data.nav_xy.last_mut().unwrap().0 -= 1;
                                        }
                                    }
                                    else
                                    {
                                        ui_data.nav_xy.last_mut().unwrap().0 -= 1;
                                    }
                                }
                                else if ui_data.nav_lock_encounter && jsonobject["combatants"].len() as i32 - ui_data.nav_main_win_scroll.0 - ui_data.nav_main_win_scroll.1 < 0 ||
                                        ui_data.nav_lock_encounter && jsonobject["combatants"].len() as i32 - ui_data.nav_main_win_scroll.0 - ui_data.nav_main_win_scroll.1 < 0
                                {
                                    ui_data.nav_main_win_scroll.1 += 1;speak(&CString::new(format!("paplay /usr/share/sounds/freedesktop/stereo/message.oga")).unwrap());
                                }
                                else
                                {
                                    ui_data.nav_xy.last_mut().unwrap().0 -= 1;
                                }
                            }
                            update_ui = true;
                        },
                        KEY_DOWN =>
                        {
                            if ui_data.nav_lock_encounter && ui_data.nav_xy[1].0 < jsonobject["combatants"].len() as i32 - 1
                            {
                                ui_data.nav_xy.last_mut().unwrap().0 += 1;
                            }
                            else if ui_data.nav_lock_combatant
                            {
                                ui_data.nav_xy.last_mut().unwrap().0 += 1;
                            }
                            else if !ui_data.is_locked() && ui_data.nav_xy.last().unwrap().0 < jsonobject["encounters"].len() as i32 - 1
                            {
                                if ui_data.nav_encounter_win_scroll.1 > 0
                                {
                                    ui_data.nav_encounter_win_scroll.1 -= 1;
                                }
                                else
                                {
                                    ui_data.nav_xy.last_mut().unwrap().0 += 1;
                                }
                            }
                            update_ui = true;
                        },/*
                        KEY_LEFT =>
                        {
                            if !ui_data.nav_lock_filter
                            {
                                if ui_data.nav_xy.last().unwrap().1 == 1 && ui_data.nav_lock_encounter && !ui_data.nav_lock_combatant
                                {
                                    ui_data.nav_xy.last().unwrap().1 = 0;
                                    update_ui = true;
                                }
                            }
                        },
                        KEY_RIGHT =>
                        {
                            if !ui_data.nav_lock_filter
                            {
                                if ui_data.nav_lock_encounter && ui_data.nav_xy.last().unwrap().0 < encounters.len() as i32
                                {
                                    ui_data.deeper();
                                    ui_data.unlock();
                                    ui_data.nav_lock_combatant = true;
                                     update_ui = true;
                                }
                            }
                        },*/
                        10 => // enter
                        {
                            if ui_data.nav_lock_filter
                            {
                                ui_data.surface();
                                ui_data.nav_lock_filter = false;
                            }
                            else if ui_data.nav_lock_encounter
                            {
                                ui_data.deeper();
                                ui_data.nav_lock_encounter = false;
                                ui_data.nav_lock_combatant = true;
                            }
                            else if !ui_data.is_locked()
                            {
                                if ui_data.nav_xy.last().unwrap().0 == jsonobject["encounters"].len() as i32
                                {
                                    ui_data.nav_xy.last_mut().unwrap().0 -= 1; // ugly code, will bug around --- needs fix
                                }
                                ui_data.deeper();
                                ui_data.nav_lock_encounter = true;
                            }
                            update_ui = true;
                        },
                        KEY_BACKSPACE =>
                        {
                            if !ui_data.nav_lock_filter
                            {
                                if ui_data.nav_lock_encounter
                                {
                                    ui_data.surface();
                                    ui_data.nav_lock_encounter = false;
                                }
                                else if ui_data.nav_lock_combatant
                                {
                                    ui_data.surface();
                                    ui_data.nav_lock_encounter = true;
                                    ui_data.nav_lock_combatant = false;
                                }
                                else  //backspace with ui_data.nav_xy having a len() of 1
                                {
                                }
                            }
                            else
                            {
                                ui_data.filters.pop();
                            }
                            update_ui = true;
                        },
                        43 => // + key
                        {
                            if !ui_data.nav_lock_filter
                            {
                                ui_data.deeper();
                                ui_data.nav_lock_filter = true;
                                update_ui = true;
                            }
                            else
                            {
                                ui_data.filters.push( val as u8 as char );
                                update_ui = true;
                            }
                        },
                        9 => // TAB key
                        {
                            if ui_data.nav_lock_refresh
                            {
                                ui_data.nav_lock_refresh = false;
                            }
                            else
                            {
                                ui_data.nav_lock_refresh = true;
                            }
                            update_ui = true;
                        },
                        _ =>
                        {
                            //ui_update(&format!("{}", val), &player_display, &mut ui_data, &encounters);
                            if ui_data.nav_lock_filter
                            {
                                ui_data.filters.push( val as u8 as char );
                                update_ui = true;
                            }
                        }
                        //ui_update(&format!("{}", val), &player_display, &mut ui_data, &encounters);}//ui_update(&format!("{}", encounters[0].attackers.len()), &player_display, &pointer, &encounters, &current_encounter);}//}
                    },
                Err(e) => {}
            }
            /*
            * parse what data the program is currently interested in and send that in a request to the Sender recieved from mmo_parser_backend
            * parse the response and update the display.
            *
            * do this procedure ONLY if a request for new data has been sent.
            *
            * poll for update every X secs.
            * OR
            * listen to updates from the parser.
            */
            if update_ui && !jsonobject["encounters"].is_empty()
            {
                structs::ui_draw(&format!(""), &player_display, &jsonobject, &mut ui_data);
                update_ui = false;
            }
        }
    });

}

/*
(1477272172)[Mon Oct 24 03:22:52 2016] YOUR Raging Whirlwind multi attacks Bonesnapper for a critical of 38996 cold damage.\r\n
(1477272172)[Mon Oct 24 03:22:52 2016] Kabernet\'s Asylum multi attacks Bonesnapper for a critical of 36622 mental damage.\r\n
(1478123041)[Wed Nov  2 22:44:01 2016] YOU hit training dummy for a critical of 377262 heat damage.
(1478123041)[Wed Nov  2 22:44:01 2016] YOU multi attack training dummy for a critical of 148320 heat damage.
(1478706458)[Wed Nov  9 16:47:38 2016] YOUR Noxious Rending IV hits training dummy for 875382 disease damage.
(1478132824)[Thu Nov  3 01:27:04 2016] Devorstator's Impatience heals Devorstator for 43947 hit points.
YOU aoe attack training dummy for a critical of 204585 heat damage.

println!("{}",buffer) <-- add this to the match X.captures() statement in the None body. Also needs to disable the code in the ui_update function.

send a request-JSON-object to the parser, this contains a wish-list of what I want.
    The response is then forwarded to the update_ui function and drawn.
        This has the benefit of being doable even if the response doesn't exactly match expectations.
    This request changes depending on user input.
        Limit how many resonses that are wanted by low+count.

*/
<|endoftext|>


<commit_before>extern crate classreader;
extern crate zip;

use classreader::*;
use std::env;
use std::fs::File;

fn main() {
    env::args().nth(1).expect("usage: javamoose <class or jar file>...");
    let mut args = env::args();
    args.next(); // Skip exe name
    for f in args {
        if f.ends_with("class") {
            process_class_file(&f);
        } else if f.ends_with("jar") {
            process_jar_file(&f);
        } else {
            println!("Ignoring unknown file type {}", f);
        }

    }
    println!("Done!");
}

fn process_class_file(file_name: &String) {
    println!("Loading class file {}", file_name);
    println!("======================================================");
    let class = ClassReader::new_from_path(&file_name).unwrap();
    process_class(&class);
}

fn process_jar_file(file_name: &String) {
    let file = File::open(file_name).expect("couldn't find a file!");
    let mut zip = zip::ZipArchive::new(file).expect("could not read JAR");
    for i in 0..zip.len() {
        let mut class_file = zip.by_index(i).unwrap();
        if class_file.name().ends_with("class") {
            println!("Reading {}", class_file.name());
            let class = ClassReader::new_from_reader(&mut class_file).unwrap();
            process_class(&class);
        }
    }
}

fn process_class(class: &Class) {
    assert_eq!(0xCAFEBABE, class.magic);
    println!("class: {}", get_class_name(&class));
    println!("method count: {}", class.methods.len());
    println!("field count:  {}", class.fields.len());
    println!("code size:    {}", get_total_code_size(&class));
    for method in &class.methods {
        println!("\tmethod: {}{}", get_string(&class, method.name_index as usize), get_string(&class, method.descriptor_index as usize));
        println!("\t\tsize:       {}", get_method_size(&method));
        println!("\t\tlines:      {}", get_method_lines(&method));
        println!("\t\tcomplexity: {}", get_method_complexity(&method));
    }

    println!("======================================================");
}

/// Get constant from a pool, correcting for java's 1-based indexes.
fn get_const(class: &Class, i: usize) -> &ConstantPoolInfo {
    &class.constant_pool[i - 1]
}

/// Get string from constant pool
fn get_string(class: &Class, index: usize) -> String {
    match get_const(class, index) {
        &ConstantPoolInfo::Utf8(ref s) => s.clone(),
        _ => "?".to_string()
    }
}

fn get_class_name(class: &Class) -> String {
    match get_const(class, class.this_class as usize) {
        &ConstantPoolInfo::Class(index) => get_string(class, index as usize),
        _ => "?".to_string()
    }
}

fn get_total_code_size(class: &Class) -> usize {
    class.methods.iter().fold(0usize, |sum, method| sum + get_method_size(method))
}

/// Compute method size in byte code instructions
/// If multiple code segments are present in a method (not a javac output) sum it up
fn get_method_size(method: &Method) -> usize {
    method.attributes.iter().fold(0usize, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => code.len(),
            _ => 0
        })
}

/// Compute method size in lines of code.
/// If multiple code segments or multiple line number attrbitues are present in a method (not a javac output) sum it up
fn get_method_lines(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref attributes, ..} => attributes.iter().fold(0, |sum, a| sum + match a {
                &Attribute::LineNumberTable(ref line_table) => {
                    let end = get_opt_line_number(line_table.last());
                    let start = get_opt_line_number(line_table.first());
                    if start > end { // TODO: Investigate when it happens
                        0
                    } else {
                        end - start
                    }
                },
                _ => 0
            }),
            _ => 0
        })

}

fn get_opt_line_number(line: Option<&LineNumber>) -> u16 {
    line.map(|x| x.line_number).unwrap_or(0)
}

fn get_method_complexity(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => get_code_complexity(code),
            _ => 0
        })
}

/// Using complexity definition from http://www.leepoint.net/principles_and_practices/complexity/complexity-java-method.html
/// Start with 1 for the method. Add one for each of the following flow-related elements that are found in the method.
/// Returns     Each return that isn't the last statement of a method.
/// Selection   if, else, case, default.
/// Loops   for, while, do-while, break, and continue.
/// Operators   &&, ||, ?, and :
/// Exceptions  catch, finally, throw, or throws clause.
/// Bytecode reference: http://www.angelibrary.com/computer/java_21days/ch32.htm
fn get_code_complexity(code: &Vec<(u32, Instruction)>) -> u16 {
    // println!("{:?}", code);
    // We start from zero to account for always-present final return - it will add the "starting" 1 for us.
    code.iter().fold(0, |sum, instruction| sum + match instruction.1 {
        Instruction::areturn => 1,
        Instruction::athrow => 1,
        Instruction::dreturn => 1,
        Instruction::freturn => 1,
        Instruction::if_acmpeq(..) => 1,
        Instruction::if_acmpne(..) => 1,
        Instruction::if_icmpeq(..) => 1,
        Instruction::if_icmpne(..) => 1,
        Instruction::if_icmplt(..) => 1,
        Instruction::if_icmpge(..) => 1,
        Instruction::if_icmpgt(..) => 1,
        Instruction::if_icmple(..) => 1,
        Instruction::ifeq(..) => 1,
        Instruction::ifne(..) => 1,
        Instruction::iflt(..) => 1,
        Instruction::ifge(..) => 1,
        Instruction::ifgt(..) => 1,
        Instruction::ifle(..) => 1,
        Instruction::ifnonnull(..) => 1,
        Instruction::ifnull(..) => 1,
        Instruction::ireturn => 1,
        Instruction::lookupswitch(_, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        Instruction::lreturn => 1,
        Instruction::return_ => 1,
        Instruction::tableswitch(_, _, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        // Subroutines in the method. Currently - do not count them towards the complexity. They are used to compile "finally", but I do not see them as branching really. Finally block is executed every time
        // Instruction::jsr(..) => 1,
        // Instruction::jsr_w(..) => 1,
        // Instruction::ret => 1,
        // Instruction::ret_w => 1,
        _ => 0
    })
}

<commit_msg>Removed debug output<commit_after>extern crate classreader;
extern crate zip;

use classreader::*;
use std::env;
use std::fs::File;

fn main() {
    env::args().nth(1).expect("usage: javamoose <class or jar file>...");
    let mut args = env::args();
    args.next(); // Skip exe name
    for f in args {
        if f.ends_with("class") {
            process_class_file(&f);
        } else if f.ends_with("jar") {
            process_jar_file(&f);
        } else {
            println!("Ignoring unknown file type {}", f);
        }

    }
    println!("Done!");
}

fn process_class_file(file_name: &String) {
    println!("Loading class file {}", file_name);
    println!("======================================================");
    let class = ClassReader::new_from_path(&file_name).unwrap();
    process_class(&class);
}

fn process_jar_file(file_name: &String) {
    let file = File::open(file_name).expect("couldn't find a file!");
    let mut zip = zip::ZipArchive::new(file).expect("could not read JAR");
    for i in 0..zip.len() {
        let mut class_file = zip.by_index(i).unwrap();
        if class_file.name().ends_with("class") {
            let class = ClassReader::new_from_reader(&mut class_file).unwrap();
            process_class(&class);
        }
    }
}

fn process_class(class: &Class) {
    assert_eq!(0xCAFEBABE, class.magic);
    println!("class: {}", get_class_name(&class));
    println!("method count: {}", class.methods.len());
    println!("field count:  {}", class.fields.len());
    println!("code size:    {}", get_total_code_size(&class));
    for method in &class.methods {
        println!("\tmethod: {}{}", get_string(&class, method.name_index as usize), get_string(&class, method.descriptor_index as usize));
        println!("\t\tsize:       {}", get_method_size(&method));
        println!("\t\tlines:      {}", get_method_lines(&method));
        println!("\t\tcomplexity: {}", get_method_complexity(&method));
    }

    println!("======================================================");
}

/// Get constant from a pool, correcting for java's 1-based indexes.
fn get_const(class: &Class, i: usize) -> &ConstantPoolInfo {
    &class.constant_pool[i - 1]
}

/// Get string from constant pool
fn get_string(class: &Class, index: usize) -> String {
    match get_const(class, index) {
        &ConstantPoolInfo::Utf8(ref s) => s.clone(),
        _ => "?".to_string()
    }
}

fn get_class_name(class: &Class) -> String {
    match get_const(class, class.this_class as usize) {
        &ConstantPoolInfo::Class(index) => get_string(class, index as usize),
        _ => "?".to_string()
    }
}

fn get_total_code_size(class: &Class) -> usize {
    class.methods.iter().fold(0usize, |sum, method| sum + get_method_size(method))
}

/// Compute method size in byte code instructions
/// If multiple code segments are present in a method (not a javac output) sum it up
fn get_method_size(method: &Method) -> usize {
    method.attributes.iter().fold(0usize, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => code.len(),
            _ => 0
        })
}

/// Compute method size in lines of code.
/// If multiple code segments or multiple line number attrbitues are present in a method (not a javac output) sum it up
fn get_method_lines(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref attributes, ..} => attributes.iter().fold(0, |sum, a| sum + match a {
                &Attribute::LineNumberTable(ref line_table) => {
                    let end = get_opt_line_number(line_table.last());
                    let start = get_opt_line_number(line_table.first());
                    if start > end { // TODO: Investigate when it happens
                        0
                    } else {
                        end - start
                    }
                },
                _ => 0
            }),
            _ => 0
        })

}

fn get_opt_line_number(line: Option<&LineNumber>) -> u16 {
    line.map(|x| x.line_number).unwrap_or(0)
}

fn get_method_complexity(method: &Method) -> u16 {
    method.attributes.iter().fold(0, |sum, a| sum + match a {
            &Attribute::Code{ref code, ..} => get_code_complexity(code),
            _ => 0
        })
}

/// Using complexity definition from http://www.leepoint.net/principles_and_practices/complexity/complexity-java-method.html
/// Start with 1 for the method. Add one for each of the following flow-related elements that are found in the method.
/// Returns     Each return that isn't the last statement of a method.
/// Selection   if, else, case, default.
/// Loops   for, while, do-while, break, and continue.
/// Operators   &&, ||, ?, and :
/// Exceptions  catch, finally, throw, or throws clause.
/// Bytecode reference: http://www.angelibrary.com/computer/java_21days/ch32.htm
fn get_code_complexity(code: &Vec<(u32, Instruction)>) -> u16 {
    // println!("{:?}", code);
    // We start from zero to account for always-present final return - it will add the "starting" 1 for us.
    code.iter().fold(0, |sum, instruction| sum + match instruction.1 {
        Instruction::areturn => 1,
        Instruction::athrow => 1,
        Instruction::dreturn => 1,
        Instruction::freturn => 1,
        Instruction::if_acmpeq(..) => 1,
        Instruction::if_acmpne(..) => 1,
        Instruction::if_icmpeq(..) => 1,
        Instruction::if_icmpne(..) => 1,
        Instruction::if_icmplt(..) => 1,
        Instruction::if_icmpge(..) => 1,
        Instruction::if_icmpgt(..) => 1,
        Instruction::if_icmple(..) => 1,
        Instruction::ifeq(..) => 1,
        Instruction::ifne(..) => 1,
        Instruction::iflt(..) => 1,
        Instruction::ifge(..) => 1,
        Instruction::ifgt(..) => 1,
        Instruction::ifle(..) => 1,
        Instruction::ifnonnull(..) => 1,
        Instruction::ifnull(..) => 1,
        Instruction::ireturn => 1,
        Instruction::lookupswitch(_, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        Instruction::lreturn => 1,
        Instruction::return_ => 1,
        Instruction::tableswitch(_, _, ref jumps) => jumps.len() as u16, // tricky - lets use the size of the jump table
        // Subroutines in the method. Currently - do not count them towards the complexity. They are used to compile "finally", but I do not see them as branching really. Finally block is executed every time
        // Instruction::jsr(..) => 1,
        // Instruction::jsr_w(..) => 1,
        // Instruction::ret => 1,
        // Instruction::ret_w => 1,
        _ => 0
    })
}

<|endoftext|>