<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;
mod config;
mod utils;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;
extern crate travis_after_all;
extern crate env_logger;

use docopt::Docopt;
use commit_analyzer::CommitType;
use config::ConfigBuilder;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use std::thread;
use std::time::Duration;
use travis_after_all::Build;
use utils::user_repo_from_url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [(--write | --no-write)] [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w, --write            Run with writing the changes afterwards.
      --no-write         Disable write mode.
  -r <r>, --release=<r>  Create release on GitHub and publish on crates.io (only in write mode) [default: yes]
  -b <b>, --branch=<b>   The branch on which releases should happen. [default: master]
";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr($fmt);
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: bool,
    flag_no_write: bool,
    flag_version: bool,
    flag_release: String,
    flag_branch: String,
}

fn string_to_bool(answer: &str) -> bool {
    match &answer.to_lowercase()[..] {
        "yes" | "true" | "1" => true,
        _ => false
    }
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn current_branch(repo: &git2::Repository) -> Option<String> {
    if let Ok(branch) = env::var("TRAVIS_BRANCH") {
        return Some(branch)
    }

    let head = repo.head().expect("No HEAD found for repository");

    if head.is_branch() {
        let short = head.shorthand().expect("No branch name found");
        return Some(short.into());
    }

    None
}

fn is_release_branch(current: &str, release: &str) -> bool {
    if let Ok(pr) = env::var("TRAVIS_PULL_REQUEST") {
        if pr != "false" {
            return false;
        }
    }

    current == release
}

fn main() {
    env_logger::init().expect("Can't instantiate env logger");

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

    let mut config_builder = ConfigBuilder::new();

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    // If write mode is requested OR denied,
    // adhere to the user's wish,
    // otherwise we decide based on whether we are running in CI.
    let write_mode = match (args.flag_write, args.flag_no_write) {
        (true, false) => true,
        (false, true) => false,
        _ => ci_env_set(),
    };

    let is_dry_run = !write_mode;
    let release_mode = string_to_bool(&args.flag_release);

    config_builder.write(write_mode);
    config_builder.release(release_mode);
    config_builder.branch(args.flag_branch);

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    config_builder.repository_path(repository_path.to_owned());

    // extra scope scope to make sure borrow of `repo` is dropped
    {
        let signature = match git::get_signature(&repo) {
            Ok(sig) => sig,
            Err(e) => {
                logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
                logger::stderr(r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config");
                process::exit(1);
            }
        };

        config_builder.signature(signature.to_owned());
    }

    // In case we are in write-mode AND release mode,
    // we will make sure we got all configuration settings
    if !is_dry_run && release_mode {
        let remote_or_none = repo.find_remote("origin");
        match remote_or_none {
            Ok(remote) => {
                let url = remote.url().expect("Remote URL is not valid UTF-8").to_owned();
                let (user, repo_name) = user_repo_from_url(&url)
                    .unwrap_or_else(|e| print_exit!("Could not extract user and repository name from URL: {:?}", e));
                config_builder.user(user);
                config_builder.repository_name(repo_name);

                let gh_token = env::var("GH_TOKEN")
                    .unwrap_or_else(|err| print_exit!("GH_TOKEN not set: {:?}", err));

                let cargo_token = env::var("CARGO_TOKEN")
                    .unwrap_or_else(|err| print_exit!("CARGO_TOKEN not set: {:?}", err));

                config_builder.gh_token(gh_token);
                config_builder.cargo_token(cargo_token);
            },
            Err(err) => {
                logger::warn(format!("Could not determine the origin remote url: {:?}", err));
                logger::warn("semantic-rs can't push changes or create a release on GitHub");
            }
        }
    }

    config_builder.repository(repo);
    let config = config_builder.build();

    let branch = current_branch(&config.repository)
        .unwrap_or_else(|| print_exit!("Could not determine current branch."));

    if !is_release_branch(&branch, &config.branch) {
        println!("Current branch is '{}', releases are only done from branch '{}'", branch, config.branch);
        println!("No release done from a pull request either.");
        process::exit(0);
    }

    if ci_env_set() {
        let build_run = Build::from_env()
            .unwrap_or_else(|e| print_exit!("CI mode, but can't check other builds. Error: {:?}", e));

        if !build_run.is_leader() {
            println!("Not the build leader. Nothing to do. Bye.");
            process::exit(0);
        }

        println!("I am the build leader. Waiting for other jobs to finish.");
        match build_run.wait_for_others() {
            Ok(()) => println!("Other jobs finished and succeeded. Doing my work now."),
            Err(travis_after_all::Error::FailedBuilds) => {
                print_exit!("Some builds failed. Stopping here.");
            },
            Err(e) => print_exit!("Waiting for other builds failed Reason: {:?}", e),
        }
    }

    let version = toml_file::read_from_file(&config.repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(&config.repository);
    if is_dry_run {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    else {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if is_dry_run {
        logger::stdout(format!("New version would be: {}", new_version));
        logger::stdout("Would write the following Changelog:");
        let changelog = match changelog::generate(repository_path, &version.to_string(), &new_version) {
            Ok(log) => log,
            Err(err) => {
                logger::stderr(format!("Generating Changelog failed: {:?}", err));
                process::exit(1);
            }
        };
        logger::stdout("====================================");
        logger::stdout(changelog);
        logger::stdout("====================================");
        logger::stdout("Would create annotated git tag");
    }
    else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        logger::stdout("Writing Changelog");
        changelog::write(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));

        if config.release_mode {
            logger::stdout("Updating lockfile");
            if !cargo::update_lockfile(repository_path) {
                print_exit!("`cargo fetch` failed. See above for the cargo error message.");
            }
        }

        logger::stdout("Package crate");
        if !cargo::package(repository_path) {
            print_exit!("`cargo package` failed. See above for the cargo error message.");
        }

        git::commit_files(&config, &new_version)
            .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        if config.release_mode && config.can_push() {
            logger::stdout("Pushing new commit and tag");
            git::push(&config, &tag_name)
                .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

            logger::stdout("Waiting a tiny bit, so GitHub can store the git tag");
            thread::sleep(Duration::from_secs(1));

            logger::stdout("Creating GitHub release");
            github::release(&config, &tag_name, &tag_message)
                .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));

            logger::stdout("Publishing crate on crates.io");
            if !cargo::publish(&config.repository_path, &config.cargo_token.as_ref().unwrap()) {
                print_exit!("Failed to publish on crates.io");
            }

            println!("{} v{} is released. 🚀🚀🚀", config.repository_name.unwrap(), new_version);
        }
    }
}
<commit_msg>fix: Only wait for other builds in release mode<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;
mod cargo;
mod error;
mod github;
mod config;
mod utils;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2;
extern crate clog;
extern crate hyper;
extern crate hubcaps;
extern crate url;
extern crate travis_after_all;
extern crate env_logger;

use docopt::Docopt;
use commit_analyzer::CommitType;
use config::ConfigBuilder;
use std::process;
use semver::Version;
use std::{env,fs};
use std::path::Path;
use std::error::Error;
use std::thread;
use std::time::Duration;
use travis_after_all::Build;
use utils::user_repo_from_url;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USERAGENT: &'static str = concat!("semantic-rs/", env!("CARGO_PKG_VERSION"));
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [(--write | --no-write)] [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -w, --write            Run with writing the changes afterwards.
      --no-write         Disable write mode.
  -r <r>, --release=<r>  Create release on GitHub and publish on crates.io (only in write mode) [default: yes]
  -b <b>, --branch=<b>   The branch on which releases should happen. [default: master]
";

macro_rules! print_exit {
    ($fmt:expr) => {{
        logger::stderr($fmt);
        process::exit(1);
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        logger::stderr(format!($fmt, $($arg)*));
        process::exit(1);
    }};
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_write: bool,
    flag_no_write: bool,
    flag_version: bool,
    flag_release: String,
    flag_branch: String,
}

fn string_to_bool(answer: &str) -> bool {
    match &answer.to_lowercase()[..] {
        "yes" | "true" | "1" => true,
        _ => false
    }
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

fn ci_env_set() -> bool {
    env::var("CI").is_ok()
}

fn current_branch(repo: &git2::Repository) -> Option<String> {
    if let Ok(branch) = env::var("TRAVIS_BRANCH") {
        return Some(branch)
    }

    let head = repo.head().expect("No HEAD found for repository");

    if head.is_branch() {
        let short = head.shorthand().expect("No branch name found");
        return Some(short.into());
    }

    None
}

fn is_release_branch(current: &str, release: &str) -> bool {
    if let Ok(pr) = env::var("TRAVIS_PULL_REQUEST") {
        if pr != "false" {
            return false;
        }
    }

    current == release
}

fn main() {
    env_logger::init().expect("Can't instantiate env logger");

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

    let mut config_builder = ConfigBuilder::new();

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    // If write mode is requested OR denied,
    // adhere to the user's wish,
    // otherwise we decide based on whether we are running in CI.
    let write_mode = match (args.flag_write, args.flag_no_write) {
        (true, false) => true,
        (false, true) => false,
        _ => ci_env_set(),
    };

    let is_dry_run = !write_mode;
    let release_mode = string_to_bool(&args.flag_release);

    config_builder.write(write_mode);
    config_builder.release(release_mode);
    config_builder.branch(args.flag_branch);

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let path = Path::new(&args.flag_path);
    let path = fs::canonicalize(path)
        .unwrap_or_else(|_| print_exit!("Path does not exist or a component is not a directory"));
    let repository_path = path.to_str()
        .unwrap_or_else(|| print_exit!("Path is not valid unicode"));

    let repo = match git2::Repository::open(repository_path) {
        Ok(repo) => repo,
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    config_builder.repository_path(repository_path.to_owned());

    // extra scope scope to make sure borrow of `repo` is dropped
    {
        let signature = match git::get_signature(&repo) {
            Ok(sig) => sig,
            Err(e) => {
                logger::stderr(format!("Failed to get the committer's name and email address: {}", e.description()));
                logger::stderr(r"
A release commit needs a committer name and email address.
We tried fetching it from different locations, but couldn't find one.

Committer information is taken from the following environment variables, if set:

GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL

If none is set the normal git config is tried in the following order:

Local repository config
User config
Global config");
                process::exit(1);
            }
        };

        config_builder.signature(signature.to_owned());
    }

    // In case we are in write-mode AND release mode,
    // we will make sure we got all configuration settings
    if !is_dry_run && release_mode {
        let remote_or_none = repo.find_remote("origin");
        match remote_or_none {
            Ok(remote) => {
                let url = remote.url().expect("Remote URL is not valid UTF-8").to_owned();
                let (user, repo_name) = user_repo_from_url(&url)
                    .unwrap_or_else(|e| print_exit!("Could not extract user and repository name from URL: {:?}", e));
                config_builder.user(user);
                config_builder.repository_name(repo_name);

                let gh_token = env::var("GH_TOKEN")
                    .unwrap_or_else(|err| print_exit!("GH_TOKEN not set: {:?}", err));

                let cargo_token = env::var("CARGO_TOKEN")
                    .unwrap_or_else(|err| print_exit!("CARGO_TOKEN not set: {:?}", err));

                config_builder.gh_token(gh_token);
                config_builder.cargo_token(cargo_token);
            },
            Err(err) => {
                logger::warn(format!("Could not determine the origin remote url: {:?}", err));
                logger::warn("semantic-rs can't push changes or create a release on GitHub");
            }
        }
    }

    config_builder.repository(repo);
    let config = config_builder.build();

    let branch = current_branch(&config.repository)
        .unwrap_or_else(|| print_exit!("Could not determine current branch."));

    if !is_release_branch(&branch, &config.branch) {
        println!("Current branch is '{}', releases are only done from branch '{}'", branch, config.branch);
        println!("No release done from a pull request either.");
        process::exit(0);
    }

    if config.release_mode && ci_env_set() {
        let build_run = Build::from_env()
            .unwrap_or_else(|e| print_exit!("CI mode, but can't check other builds. Error: {:?}", e));

        if !build_run.is_leader() {
            println!("Not the build leader. Nothing to do. Bye.");
            process::exit(0);
        }

        println!("I am the build leader. Waiting for other jobs to finish.");
        match build_run.wait_for_others() {
            Ok(()) => println!("Other jobs finished and succeeded. Doing my work now."),
            Err(travis_after_all::Error::FailedBuilds) => {
                print_exit!("Some builds failed. Stopping here.");
            },
            Err(e) => print_exit!("Waiting for other builds failed Reason: {:?}", e),
        }
    }

    let version = toml_file::read_from_file(&config.repository_path)
        .unwrap_or_else(|err| print_exit!("Reading `Cargo.toml` failed: {:?}", err));

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(&config.repository);
    if is_dry_run {
        logger::stdout(format!("Commits analyzed. Bump would be {:?}", bump));
    }
    else {
        logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));
    }
    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    if is_dry_run {
        logger::stdout(format!("New version would be: {}", new_version));
        logger::stdout("Would write the following Changelog:");
        let changelog = match changelog::generate(repository_path, &version.to_string(), &new_version) {
            Ok(log) => log,
            Err(err) => {
                logger::stderr(format!("Generating Changelog failed: {:?}", err));
                process::exit(1);
            }
        };
        logger::stdout("====================================");
        logger::stdout(changelog);
        logger::stdout("====================================");
        logger::stdout("Would create annotated git tag");
    }
    else {
        logger::stdout(format!("New version: {}", new_version));

        toml_file::write_new_version(repository_path, &new_version)
            .unwrap_or_else(|err| print_exit!("Writing `Cargo.toml` failed: {:?}", err));

        logger::stdout("Writing Changelog");
        changelog::write(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Writing Changelog failed: {:?}", err));

        if config.release_mode {
            logger::stdout("Updating lockfile");
            if !cargo::update_lockfile(repository_path) {
                print_exit!("`cargo fetch` failed. See above for the cargo error message.");
            }
        }

        logger::stdout("Package crate");
        if !cargo::package(repository_path) {
            print_exit!("`cargo package` failed. See above for the cargo error message.");
        }

        git::commit_files(&config, &new_version)
            .unwrap_or_else(|err| print_exit!("Committing files failed: {:?}", err));

        logger::stdout("Creating annotated git tag");
        let tag_message = changelog::generate(repository_path, &version.to_string(), &new_version)
            .unwrap_or_else(|err| print_exit!("Can't generate changelog: {:?}", err));

        let tag_name = format!("v{}", new_version);
        git::tag(&config, &tag_name, &tag_message)
            .unwrap_or_else(|err| print_exit!("Failed to create git tag: {:?}", err));

        if config.release_mode && config.can_push() {
            logger::stdout("Pushing new commit and tag");
            git::push(&config, &tag_name)
                .unwrap_or_else(|err| print_exit!("Failed to push git: {:?}", err));

            logger::stdout("Waiting a tiny bit, so GitHub can store the git tag");
            thread::sleep(Duration::from_secs(1));

            logger::stdout("Creating GitHub release");
            github::release(&config, &tag_name, &tag_message)
                .unwrap_or_else(|err| print_exit!("Failed to create GitHub release: {:?}", err));

            logger::stdout("Publishing crate on crates.io");
            if !cargo::publish(&config.repository_path, &config.cargo_token.as_ref().unwrap()) {
                print_exit!("Failed to publish on crates.io");
            }

            println!("{} v{} is released. 🚀🚀🚀", config.repository_name.unwrap(), new_version);
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! opt {
    ($opt:expr) => {
        match $opt {
            Some(item) => item,
            None => {
                return None;
            }
        }
    }
}

extern crate image;
extern crate imageproc;
extern crate rusttype;

use image::{DynamicImage, GenericImage, ImageFormat, Luma, Rgba};
use imageproc::drawing;
use imageproc::rect::Rect;
use rusttype::Scale;

#[cfg(windows)]
const DEFAULT_FONT: Option<&str> = Some("C:/Windows/Fonts/Impact.ttf");

#[cfg(macos)]
const DEFAULT_FONT: Option<&str> = Some("/Library/Fonts/Impact.ttf");

#[cfg(not(any(windows, macos)))]
const DEFAULT_FONT: Option<&str> = None;

fn main() {
    // The final value in the array here is the *opacity* of the pixel. Not the transparency.
    // Apparently, this is not CSS...
    let white_pixel = Rgba([255, 255, 255, 255]);
    let black_pixel = Rgba([0, 0, 0, 255]);

    let (image_path, text) = match read_command() {
        Some(command) => command,
        None => {
            println!("Try `annatar <image path> <text>");
            std::process::exit(1);
        }
    };

    let mut pixels = match image::open(image_path) {
        Ok(pixels) => pixels,
        _ => {
            println!("Unable to open image file");
            std::process::exit(2);
        }
    };

    let font = read_font(DEFAULT_FONT);
    let scale_factor = pixels.height() as f32 / 10.0;

    // This scales the font size itself. Using the same multiplier for both just makes it bigger
    // as the multiplier increases. Making X larger makes the font wider, while making Y larger
    // makes the font taller.
    //
    // let scale = Scale { x: height, y: height };
    //
    // The above form is equivalent to what I'm currently using:
    let scale = Scale::uniform(scale_factor);

    // Apparently, `Scale` is copy.
    let (text_width, text_height) = text_size(&text, &font, scale);

    // Seems like the coordinates x and y designate the top left corner of the region being drawn.
    // In order to center this, I'm going to have to figure out how to determine the size of the
    // region being drawn.
    let (width, height) = pixels.dimensions();

    // What follows is a little fourth grade math that attempts to stick the text at the center
    // of the bottom fifth of the image. This, by the way, is the closest I have ever come to
    // using anything I learned in Mrs. Vye's 9th grade keyboarding class. Thank God for the
    // IBM Selectric III, huh?
    let x = (width / 2) - (text_width / 2);
    let y = height - ((height / 5) - (text_height / 2));

    let mut scratch = image::ImageBuffer::from_pixel(text_width, text_height, black_pixel);
    drawing::draw_text_mut(&mut scratch, white_pixel, 0, 0, scale, &font, &text);

    // Here I set the "low threshold" and the "high threshold" for edge detection to 0.5 I have
    // not the first fucking clue what either of these thresholds is for or what sort of values
    // they might accept. I can only assume that even a drunk wallaby could detect these edges.
    for (idx, &pixel) in imageproc::edges::canny(&image::imageops::grayscale(&scratch), 255.0, 255.0).pixels().enumerate() {
        if Luma([255u8]) == pixel {
            let idx = idx as u32;
            let x = idx % text_width + x;
            let y = idx / text_width + y;

            // I bet this isn't cheap, but... meh.
            let rect = Rect::square(x as i32, y as i32, (0.1 * scale_factor) as u32);
            drawing::draw_filled_rect_mut(&mut pixels, rect, Rgba([0, 0, 0, 255]));
        }
    }

    drawing::draw_text_mut(&mut pixels, white_pixel, x, y, scale, &font, &text);

    // Here I'm printing the scratch image used for edge detection. This is pretty much just as
    // a smoke test; I'll get around to pulling it out of here eventually.
    save("scratch.png", &DynamicImage::ImageRgba8(scratch));
    save("output.png", &pixels);
}

/// Calculate the dimensions of the bounding box for a given string, font, and scale.
///
/// This works by summing the "advance width" of each glyph in the text, entirely ignoring
/// kerning as each character is considered in isolation. Because this is used primarily to
/// center text in the image, it's close enough for government work.
fn text_size(s: &str, font: &[u8], scale: Scale) -> (u32, u32) {
    use rusttype::{FontCollection, VMetrics};

    // Font collections apparently consist of a collection of fonts. That is, more than one will
    // be defined in any given bag of bytes. Life's imperfect. The common case, however, is that
    // a given bag of bytes will contain a single font, in which case this will not explode.
    let font = FontCollection::from_bytes(font).into_font().expect("Font collection contains multiple fonts.");

    let text_width = font.glyphs_for(s.chars())
        .map(|glyph| glyph.scaled(scale).h_metrics().advance_width)
        .sum::<f32>();

    // The "v-metrics" for any given letter in a font are the same for a given scale, so we don't
    // need to check this for each glyph.
    let text_height = {
        let VMetrics { ascent, descent, ..} = font.v_metrics(scale);
        (ascent - descent) as u32
    };

    // I know I'm truncating the length and this is probably wrong, but it's not wrong by enough
    // to be noticeable when you print it to an image.
    (text_width as u32, text_height)
}

fn save(path: &str, pixels: &DynamicImage) {
    use std::fs::OpenOptions;

    let mut out = OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(path).unwrap();

    pixels.save(&mut out, ImageFormat::PNG).unwrap();
}

fn read_font(path: Option<&'static str>) -> Vec<u8> {
    use std::fs::File;
    use std::io::Read;

    let path = path.expect("Unsupported platform--please annoy the maintainer until this is fixed");
    let mut file = File::open(path).expect("Default font not found");
    let mut buf = Vec::new();

    file.read_to_end(&mut buf).expect("Unable to read file");
    buf
}

fn read_command() -> Option<(String, String)> {
    let mut args = std::env::args().skip(1);
    Some((
        opt!(args.next()),
        opt!(args.next()),
    ))
}
<commit_msg>Update comments<commit_after>macro_rules! opt {
    ($opt:expr) => {
        match $opt {
            Some(item) => item,
            None => {
                return None;
            }
        }
    }
}

extern crate image;
extern crate imageproc;
extern crate rusttype;

use image::{DynamicImage, GenericImage, ImageFormat, Luma, Rgba};
use imageproc::drawing;
use imageproc::rect::Rect;
use rusttype::Scale;

#[cfg(windows)]
const DEFAULT_FONT: Option<&str> = Some("C:/Windows/Fonts/Impact.ttf");

#[cfg(macos)]
const DEFAULT_FONT: Option<&str> = Some("/Library/Fonts/Impact.ttf");

#[cfg(not(any(windows, macos)))]
const DEFAULT_FONT: Option<&str> = None;

fn main() {
    // The final value in the array here is the *opacity* of the pixel. Not the transparency.
    // Apparently, this is not CSS...
    let white_pixel = Rgba([255, 255, 255, 255]);
    let black_pixel = Rgba([0, 0, 0, 255]);

    let (image_path, text) = match read_command() {
        Some(command) => command,
        None => {
            println!("Try `annatar <image path> <text>");
            std::process::exit(1);
        }
    };

    let mut pixels = match image::open(image_path) {
        Ok(pixels) => pixels,
        _ => {
            println!("Unable to open image file");
            std::process::exit(2);
        }
    };

    let font = read_font(DEFAULT_FONT);
    let scale_factor = pixels.height() as f32 / 10.0;
    let scale = Scale::uniform(scale_factor);

    // Apparently, `Scale` is copy.
    let (text_width, text_height) = text_size(&text, &font, scale);

    // Seems like the coordinates x and y designate the top left corner of the region being drawn.
    // In order to center this, I'm going to have to figure out how to determine the size of the
    // region being drawn.
    let (width, height) = pixels.dimensions();

    // What follows is a little fourth grade math that attempts to stick the text at the center
    // of the bottom fifth of the image. This, by the way, is the closest I have ever come to
    // using anything I learned in Mrs. Vye's 9th grade keyboarding class. Thank God for the
    // IBM Selectric III, huh?
    let x = (width / 2) - (text_width / 2);
    let y = height - ((height / 5) - (text_height / 2));

    let mut scratch = image::ImageBuffer::from_pixel(text_width, text_height, black_pixel);
    drawing::draw_text_mut(&mut scratch, white_pixel, 0, 0, scale, &font, &text);

    // These thresholds are black magic to me.
    for (idx, &pixel) in imageproc::edges::canny(&image::imageops::grayscale(&scratch), 255.0, 255.0).pixels().enumerate() {
        if Luma([255u8]) == pixel {
            let idx = idx as u32;
            let x = idx % text_width + x;
            let y = idx / text_width + y;

            // I bet this isn't cheap, but... meh.
            let rect = Rect::square(x as i32, y as i32, (0.1 * scale_factor) as u32);
            drawing::draw_filled_rect_mut(&mut pixels, rect, Rgba([0, 0, 0, 255]));
        }
    }

    // Each call to `draw_text_mut` rebuilds the font, which I already built once to determine the
    // size of the text field. This is a waste of time. I bet I can improve on draw_text_whatever
    // such that it accepts a realized font rather than a bag of bits.
    drawing::draw_text_mut(&mut pixels, white_pixel, x, y, scale, &font, &text);

    // Here I'm printing the scratch image used for edge detection. This is pretty much just as
    // a smoke test; I'll get around to pulling it out of here eventually.
    save("scratch.png", &DynamicImage::ImageRgba8(scratch));
    save("output.png", &pixels);
}

/// Calculate the dimensions of the bounding box for a given string, font, and scale.
///
/// This works by summing the "advance width" of each glyph in the text, entirely ignoring
/// kerning as each character is considered in isolation. Because this is used primarily to
/// center text in the image, it's close enough for government work.
fn text_size(s: &str, font: &[u8], scale: Scale) -> (u32, u32) {
    use rusttype::{FontCollection, VMetrics};

    // Font collections apparently consist of a collection of fonts. That is, more than one will
    // be defined in any given bag of bytes. Life's imperfect. The common case, however, is that
    // a given bag of bytes will contain a single font, in which case this will not explode.
    let font = FontCollection::from_bytes(font).into_font().expect("Font collection contains multiple fonts.");

    let text_width = font.glyphs_for(s.chars())
        .map(|glyph| glyph.scaled(scale).h_metrics().advance_width)
        .sum::<f32>();

    // The "v-metrics" for any given letter in a font are the same for a given scale, so we don't
    // need to check this for each glyph.
    let text_height = {
        let VMetrics { ascent, descent, ..} = font.v_metrics(scale);
        (ascent - descent) as u32
    };

    // I know I'm truncating the length and this is probably wrong, but it's not wrong by enough
    // to be noticeable when you print it to an image.
    (text_width as u32, text_height)
}

fn save(path: &str, pixels: &DynamicImage) {
    use std::fs::OpenOptions;

    let mut out = OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(path).unwrap();

    pixels.save(&mut out, ImageFormat::PNG).unwrap();
}

fn read_font(path: Option<&'static str>) -> Vec<u8> {
    use std::fs::File;
    use std::io::Read;

    let path = path.expect("Unsupported platform--please annoy the maintainer until this is fixed");
    let mut file = File::open(path).expect("Default font not found");
    let mut buf = Vec::new();

    file.read_to_end(&mut buf).expect("Unable to read file");
    buf
}

fn read_command() -> Option<(String, String)> {
    let mut args = std::env::args().skip(1);
    Some((
        opt!(args.next()),
        opt!(args.next()),
    ))
}
<|endoftext|>


<commit_before>//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(range_contains)]
#![feature(inclusive_range_syntax)]
#![feature(io)]
#![feature(unicode)]

extern crate fontconfig;
extern crate freetype;
extern crate libc;
extern crate glutin;
extern crate cgmath;
extern crate euclid;
extern crate notify;
extern crate arrayvec;

#[macro_use]
extern crate bitflags;

#[macro_use]
mod macros;

mod list_fonts;
mod text;
mod renderer;
mod grid;
mod meter;
mod tty;
mod ansi;
mod term;

use std::collections::HashMap;
use std::io::{BufReader, Read, BufRead, Write, BufWriter};
use std::sync::Arc;
use std::fs::File;

use std::os::unix::io::{FromRawFd, AsRawFd};

use renderer::{QuadRenderer, GlyphCache, LoadGlyph};
use text::FontDesc;
use grid::Grid;
use term::Term;
use meter::Meter;

#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

#[derive(Debug)]
struct TermProps {
    width: f32,
    height: f32,
    cell_width: f32,
    cell_height: f32,
    sep_x: f32,
    sep_y: f32,
}

fn main() {
    let window = glutin::WindowBuilder::new()
                     .with_title("alacritty".into())
                     .build()
                     .unwrap();

    let (width, height) = window.get_inner_size_pixels().unwrap();
    unsafe {
        window.make_current().unwrap();
    }

    unsafe {
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::Viewport(0, 0, width as i32, height as i32);
    }

    let (dpi_x, dpi_y) = window.get_dpi().unwrap();
    let dpr = window.hidpi_factor();

    let font_size = 11.;

    let sep_x = 2;
    let sep_y = 5;

    let desc = FontDesc::new("DejaVu Sans Mono", "Book");
    let mut rasterizer = text::Rasterizer::new(dpi_x, dpi_y, dpr);

    let (cell_width, cell_height) = rasterizer.box_size_for_font(&desc, font_size);

    let num_cols = grid::num_cells_axis(cell_width, sep_x, width);
    let num_rows = grid::num_cells_axis(cell_height, sep_y, height);

    let tty = tty::new(num_rows as u8, num_cols as u8);
    tty.resize(num_rows as usize, num_cols as usize, width as usize, height as usize);
    let mut reader = tty.reader();
    let mut writer = tty.writer();

    println!("num_cols, num_rows = {}, {}", num_cols, num_rows);

    let mut grid = Grid::new(num_rows as usize, num_cols as usize);

    let props = TermProps {
        cell_width: cell_width as f32,
        sep_x: sep_x as f32,
        cell_height: cell_height as f32,
        sep_y: sep_y as f32,
        height: height as f32,
        width: width as f32,
    };

    let mut renderer = QuadRenderer::new(width, height);

    let mut glyph_cache = GlyphCache::new(rasterizer, desc, font_size);
    renderer.with_api(&props, |mut api| {
        glyph_cache.init(&mut api);
    });

    unsafe {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let (chars_tx, chars_rx) = ::std::sync::mpsc::channel();
    ::std::thread::spawn(move || {
        for c in reader.chars() {
            let c = c.unwrap();
            chars_tx.send(c);
        }
    });

    let mut terminal = Term::new(tty, grid);
    let mut meter = Meter::new();

    let mut pty_parser = ansi::Parser::new();

    'main_loop: loop {
        // Handle keyboard/mouse input and other window events
        {
            let mut writer = BufWriter::new(&writer);
            for event in window.poll_events() {
                match event {
                    glutin::Event::Closed => break 'main_loop,
                    glutin::Event::ReceivedCharacter(c) => {
                        let encoded = c.encode_utf8();
                        writer.write(encoded.as_slice());
                    },
                    glutin::Event::KeyboardInput(state, _code, key) => {
                        match state {
                            glutin::ElementState::Pressed => {
                                match key {
                                    Some(glutin::VirtualKeyCode::Up) => {
                                        writer.write("\x1b[A".as_bytes());
                                    },
                                    Some(glutin::VirtualKeyCode::Down) => {
                                        writer.write("\x1b[B".as_bytes());
                                    },
                                    Some(glutin::VirtualKeyCode::Left) => {
                                        writer.write("\x1b[D".as_bytes());
                                    },
                                    Some(glutin::VirtualKeyCode::Right) => {
                                        writer.write("\x1b[C".as_bytes());
                                    },
                                    _ => (),
                                }
                            },
                            _ => (),
                        }
                    },
                    _ => ()
                }
            }
        }

        while let Ok(c) = chars_rx.try_recv() {
            pty_parser.advance(&mut terminal, c);
        }

        unsafe {
            gl::ClearColor(0.0, 0.0, 0.00, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }

        {
            let _sampler = meter.sampler();

            renderer.with_api(&props, |mut api| {
                // Draw the grid
                api.render_grid(terminal.grid(), &mut glyph_cache);

                // Also draw the cursor
                api.render_cursor(terminal.cursor(), &mut glyph_cache);
            })
        }

        // Draw render timer
        let timing = format!("{:.3} usec", meter.average());
        let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
        renderer.with_api(&props, |mut api| {
            api.render_string(&timing[..], &mut glyph_cache, &color);
        });

        window.swap_buffers().unwrap();
    }
}

<commit_msg>Unwrap some unhandled errors<commit_after>//! Alacritty - The GPU Enhanced Terminal
#![feature(question_mark)]
#![feature(range_contains)]
#![feature(inclusive_range_syntax)]
#![feature(io)]
#![feature(unicode)]

extern crate fontconfig;
extern crate freetype;
extern crate libc;
extern crate glutin;
extern crate cgmath;
extern crate euclid;
extern crate notify;
extern crate arrayvec;

#[macro_use]
extern crate bitflags;

#[macro_use]
mod macros;

mod list_fonts;
mod text;
mod renderer;
mod grid;
mod meter;
mod tty;
mod ansi;
mod term;

use std::sync::mpsc::TryRecvError;
use std::collections::HashMap;
use std::io::{BufReader, Read, BufRead, Write, BufWriter};
use std::sync::Arc;
use std::fs::File;

use std::os::unix::io::{FromRawFd, AsRawFd};

use renderer::{QuadRenderer, GlyphCache, LoadGlyph};
use text::FontDesc;
use grid::Grid;
use term::Term;
use meter::Meter;

#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

#[derive(Debug)]
struct TermProps {
    width: f32,
    height: f32,
    cell_width: f32,
    cell_height: f32,
    sep_x: f32,
    sep_y: f32,
}

fn main() {
    let window = glutin::WindowBuilder::new()
                     .with_title("alacritty".into())
                     .build()
                     .unwrap();

    let (width, height) = window.get_inner_size_pixels().unwrap();
    unsafe {
        window.make_current().unwrap();
    }

    unsafe {
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::Viewport(0, 0, width as i32, height as i32);
    }

    let (dpi_x, dpi_y) = window.get_dpi().unwrap();
    let dpr = window.hidpi_factor();

    let font_size = 11.;

    let sep_x = 2;
    let sep_y = 5;

    let desc = FontDesc::new("DejaVu Sans Mono", "Book");
    let mut rasterizer = text::Rasterizer::new(dpi_x, dpi_y, dpr);

    let (cell_width, cell_height) = rasterizer.box_size_for_font(&desc, font_size);

    let num_cols = grid::num_cells_axis(cell_width, sep_x, width);
    let num_rows = grid::num_cells_axis(cell_height, sep_y, height);

    let tty = tty::new(num_rows as u8, num_cols as u8);
    tty.resize(num_rows as usize, num_cols as usize, width as usize, height as usize);
    let mut reader = tty.reader();
    let mut writer = tty.writer();

    println!("num_cols, num_rows = {}, {}", num_cols, num_rows);

    let mut grid = Grid::new(num_rows as usize, num_cols as usize);

    let props = TermProps {
        cell_width: cell_width as f32,
        sep_x: sep_x as f32,
        cell_height: cell_height as f32,
        sep_y: sep_y as f32,
        height: height as f32,
        width: width as f32,
    };

    let mut renderer = QuadRenderer::new(width, height);

    let mut glyph_cache = GlyphCache::new(rasterizer, desc, font_size);
    renderer.with_api(&props, |mut api| {
        glyph_cache.init(&mut api);
    });

    unsafe {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
        gl::Enable(gl::MULTISAMPLE);
    }

    let (chars_tx, chars_rx) = ::std::sync::mpsc::channel();
    ::std::thread::spawn(move || {
        for c in reader.chars() {
            let c = c.unwrap();
            chars_tx.send(c).unwrap();
        }
    });

    let mut terminal = Term::new(tty, grid);
    let mut meter = Meter::new();

    let mut pty_parser = ansi::Parser::new();

    'main_loop: loop {
        // Handle keyboard/mouse input and other window events
        {
            let mut writer = BufWriter::new(&writer);
            for event in window.poll_events() {
                match event {
                    glutin::Event::Closed => break 'main_loop,
                    glutin::Event::ReceivedCharacter(c) => {
                        let encoded = c.encode_utf8();
                        writer.write(encoded.as_slice()).unwrap();
                    },
                    glutin::Event::KeyboardInput(state, _code, key) => {
                        match state {
                            glutin::ElementState::Pressed => {
                                match key {
                                    Some(glutin::VirtualKeyCode::Up) => {
                                        writer.write("\x1b[A".as_bytes()).unwrap();
                                    },
                                    Some(glutin::VirtualKeyCode::Down) => {
                                        writer.write("\x1b[B".as_bytes()).unwrap();
                                    },
                                    Some(glutin::VirtualKeyCode::Left) => {
                                        writer.write("\x1b[D".as_bytes()).unwrap();
                                    },
                                    Some(glutin::VirtualKeyCode::Right) => {
                                        writer.write("\x1b[C".as_bytes()).unwrap();
                                    },
                                    _ => (),
                                }
                            },
                            _ => (),
                        }
                    },
                    _ => ()
                }
            }
        }

        while let Ok(c) = chars_rx.try_recv() {
            pty_parser.advance(&mut terminal, c);
        }

        unsafe {
            gl::ClearColor(0.0, 0.0, 0.00, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }

        {
            let _sampler = meter.sampler();

            renderer.with_api(&props, |mut api| {
                // Draw the grid
                api.render_grid(terminal.grid(), &mut glyph_cache);

                // Also draw the cursor
                api.render_cursor(terminal.cursor(), &mut glyph_cache);
            })
        }

        // Draw render timer
        let timing = format!("{:.3} usec", meter.average());
        let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
        renderer.with_api(&props, |mut api| {
            api.render_string(&timing[..], &mut glyph_cache, &color);
        });

        window.swap_buffers().unwrap();
    }
}

<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>connect to database<commit_after>extern crate postgres;

use postgres::{Connection, SslMode};

fn main() {
    let dsn = "postgresql://dabramov@localhost/esl_development";
    let conn = match Connection::connect(dsn, &SslMode::None) {
        Ok(conn) => conn,
        Err(e) => {
            println!("Connection error: {}", e);
            return;
        }
    };
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
//use rustwlc::types::LibinputDevice;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::types::interface::*;
use rustwlc::input::pointer;
use rustwlc::input::keyboard;
/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: output_created,
            destroyed: output_destroyed,
            focus: output_focus,
            resolution: output_resolution,

            render: OutputRenderInterface {
                pre: output_render_pre,
                post: output_render_post
            }
        },
        view: ViewInterface {
            created: view_created,
            destroyed: view_destroyed,
            focus: view_focus,
            move_to_output: view_move_to_output,
            request: RequestInterface {
                geometry: view_request_geometry,
                state: view_request_state,
                move_: view_request_move,
                resize: view_request_resize,
                render: ViewRenderInterface {
                    pre: view_request_render_pre,
                    post: view_request_render_post
                }
            }
        },
        keyboard: KeyboardInterface {
            key: keyboard_key
        },
        pointer: PointerInterface {
            button: pointer_button,
            scroll: pointer_scroll,
            motion: pointer_motion
        },
        touch: TouchInterface {
            touch: touch_touch
        },
        compositor: CompositorInterface {
            ready: compositor_ready
        },
        input: InputInterface {
            created: input_created,
            destroyed: input_destroyed
        }
    };
    // Interfaces don't derive debug
    //println!("Created interface {:?}", interface);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    let resolution = output.get_resolution();
    //let views = output.get_views();
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created");
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput, old_size: Size, new_size: Size) {
    println!("output_resolution: {:?} to {:?}", old_size, new_size)
}

extern fn output_render_pre(output: WlcOutput) {
    println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created");
    view.bring_to_front();
    view.focus();
    render_output(view.get_output());
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed");
    //let next_up =
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {}", focused);
    //view.set_state()
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output");
}

extern fn view_request_geometry(view: WlcView, geometry: Geometry) {
    println!("view_request_geometry: call wlc_view_set_geometry({:?})", geometry);
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    println!("view_request_state: call wlc_view_set_state({:?})", state);
}

extern fn view_request_move(view: WlcView, dest: Point) {
    println!("view_request_move: to {}, start interactive mode.", dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, location);
}

extern fn view_request_render_pre(view: WlcView) {
    println!("view_request_render_pre");
}

extern fn view_request_render_post(view: WlcView) {
    println!("view_request_render_post");
}

extern fn keyboard_key(view: WlcView, time: u32, mods: KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
             time, mods, key, state);
    false
}

extern fn pointer_button(view: WlcView, button: libc::c_uint, mods: KeyboardModifiers,
                  key: u32, state: ButtonState, point: Point) -> bool {
    println!("pointer_button: key {}, point {}", key, point);

    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods: KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: Point) {
    println!("Pointer moved {} to {}", time, point);
    // TODO wlc_pointer_set_position
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: libc::c_uint, mods: KeyboardModifiers,
               touch: TouchType, key: i32, point: Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: LibinputDevice) {
    println!("input_destroyed");
}
<commit_msg>Added terrible way to try and open programs<commit_after>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
//use rustwlc::types::LibinputDevice;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::types::interface::*;
use rustwlc::input::pointer;
use rustwlc::input::keyboard;
/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: output_created,
            destroyed: output_destroyed,
            focus: output_focus,
            resolution: output_resolution,

            render: OutputRenderInterface {
                pre: output_render_pre,
                post: output_render_post
            }
        },
        view: ViewInterface {
            created: view_created,
            destroyed: view_destroyed,
            focus: view_focus,
            move_to_output: view_move_to_output,
            request: RequestInterface {
                geometry: view_request_geometry,
                state: view_request_state,
                move_: view_request_move,
                resize: view_request_resize,
                render: ViewRenderInterface {
                    pre: view_request_render_pre,
                    post: view_request_render_post
                }
            }
        },
        keyboard: KeyboardInterface {
            key: keyboard_key
        },
        pointer: PointerInterface {
            button: pointer_button,
            scroll: pointer_scroll,
            motion: pointer_motion
        },
        touch: TouchInterface {
            touch: touch_touch
        },
        compositor: CompositorInterface {
            ready: compositor_ready
        },
        input: InputInterface {
            created: input_created,
            destroyed: input_destroyed
        }
    };
    // Interfaces don't derive debug
    //println!("Created interface {:?}", interface);
    rustwlc::log_set_handler(log_callback);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

extern fn log_callback(log_type: LogType, text: *const libc::c_char) {
    let string_text = rustwlc::pointer_to_string(text);
    println!("Wlc Log: {}", string_text);
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    let resolution = output.get_resolution();
    //let views = output.get_views();
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created");
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput, old_size: Size, new_size: Size) {
    println!("output_resolution: {:?} to {:?}", old_size, new_size)
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created");
    view.bring_to_front();
    view.focus();
    render_output(view.get_output());
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed");
    //let next_up =
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {}", focused);
    //view.set_state()
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output");
}

extern fn view_request_geometry(view: WlcView, geometry: Geometry) {
    println!("view_request_geometry: call wlc_view_set_geometry({:?})", geometry);
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    println!("view_request_state: call wlc_view_set_state({:?})", state);
}

extern fn view_request_move(view: WlcView, dest: Point) {
    println!("view_request_move: to {}, start interactive mode.", dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, location);
}

extern fn view_request_render_pre(view: WlcView) {
    //println!("view_request_render_pre");
}

extern fn view_request_render_post(view: WlcView) {
    //println!("view_request_render_post");
}

extern fn keyboard_key(view: WlcView, time: u32, mods: KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    use std::process::{Command};
    println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
             time, mods, key, state);
    println!("Preparing to open the terminal...");
    rustwlc::exec("weston-terminal".to_string(), vec!["weston-terminal".to_string()]);
    // We are definitely able to open programs, they can definitely launch in the host X11 server.
    //rustwlc::exec("emacs".to_string(), vec!["emacs".to_string()]);
    //let output = std::process::Command::new("weston-terminal").output()
    //.unwrap_or_else(|e| { println!("Could not unwrap output!"); panic!("aaaa") });
    let mut child = Command::new("/bin/weston-terminal").spawn()
        .unwrap_or_else(|e| { println!("Error spawning child: {}", e); panic!("1") });

    //let ecode = child.wait().unwrap_or_else(|e| println!("Error unwrapping child"));
    //println!("Output: {}", String::from_utf8(output.stdout).unwrap_or("nope".to_string()));

    false
}

extern fn pointer_button(view: WlcView, button: libc::c_uint, mods: KeyboardModifiers,
                  key: u32, state: ButtonState, point: Point) -> bool {
    println!("pointer_button: key {}, point {}", key, point);

    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods: KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: Point) {
    //println!("Pointer moved {} to {}", time, point);
    // TODO wlc_pointer_set_position
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: libc::c_uint, mods: KeyboardModifiers,
               touch: TouchType, key: i32, point: Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: LibinputDevice) {
    println!("input_destroyed");
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::collections::HashMap;
use std::env;

include!("./sentiment.rs");

// Gets a normalized nick from a log nick.
// - Removes beginning '+' and '@'
// - Removes trailing '_' and '-'
fn get_nick(s: &str) -> &str {
    let ignored_prefixes: &[_] = &['+', '@', ' '];
    let ignored_suffixes: &[_] = &['_', '-', ' '];

    return &s.trim_left_matches(ignored_prefixes)
        .trim_right_matches(ignored_suffixes);
}

fn main() {
    // Parse arguments.
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
       panic!("Usage: {} [log file name]", args[0]);
    }
    let path = args[1].clone();

    let f = match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", path, why),
        Ok(f) => f,
    };
    let f = BufReader::new(f);

    //let mut result = HashMap::new();

    let analizer = sentiment::new("./src/wordlist.txt".to_string());

    let result = f.lines().map(|line| {
        let line = line.expect("Couldn't parse line");

        let parts = line.split("\t").collect::<Vec<&str>>();
        let who = get_nick(parts[1]).to_string();
        let comment_value = analizer.analyze(parts[2]);

        return (who, comment_value);
    }).fold(HashMap::new(), |mut res, curr| {
        if ["*", "**", "***", "--", "---", "-->", "<--", "-", "", "<-", "=!=", "<"]
            .contains(&curr.0.as_str()) {
                return res;
            }

        let val = match res.get(&curr.0) {
            Some(existing_comment_value) => existing_comment_value + curr.1,
            None => curr.1,
        };

        res.insert(curr.0, val);
        return res;
    });

    for (key, value) in result {
        print!("{} {}\n", key, value);
    }

    //print!("\n{} lines analyzed.\n", i);
}
<commit_msg>Clean up line mapping/folding<commit_after>use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::collections::HashMap;
use std::env;

include!("./sentiment.rs");

// Gets a normalized nick from a log nick.
// - Removes beginning '+' and '@'
// - Removes trailing '_' and '-'
fn get_nick(s: &str) -> &str {
    let ignored_prefixes: &[_] = &['+', '@', ' '];
    let ignored_suffixes: &[_] = &['_', '-', ' '];

    return &s.trim_left_matches(ignored_prefixes)
        .trim_right_matches(ignored_suffixes);
}

fn main() {
    // Parse arguments.
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
       panic!("Usage: {} [log file name]", args[0]);
    }
    let path = args[1].clone();

    // Read file.
    let f = match File::open(&path) {
        Err(why) => panic!("Couldn't open {}: {}", path, why),
        Ok(f) => f,
    };
    let f = BufReader::new(f);

    let analizer = sentiment::new("./src/wordlist.txt".to_string());

    // Fold all lines to a hashmap containing username -> score.
    let result = f.lines().fold(HashMap::new(), |mut res, line| {
        let line = line.expect("Couldn't parse line");

        let parts = line.split("\t").collect::<Vec<&str>>();
        let who = get_nick(parts[1]).to_string();
        let comment_value = analizer.analyze(parts[2]);

        if ["*", "**", "***", "--", "---", "-->", "<--", "-", "", "<-", "=!=", "<"]
            .contains(&who.as_str()) {
                return res;
            }

        let val = match res.get(&who) {
            Some(existing_comment_value) => existing_comment_value + comment_value,
            None => comment_value,
        };

        res.insert(who, val);
        return res;
    });

    for (key, value) in result {
        print!("{} {}\n", key, value);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
extern crate rustc_serialize;
extern crate hyper;
extern crate mio;
extern crate env_logger;
extern crate openssl;
#[macro_use]
extern crate log;
mod irc;
mod matrix;
mod bridge;
mod ssl;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt};
use std::thread;
use bridge::Bridge;
use std::env;
use std::path::Path;
use std::net::SocketAddr;
use openssl::ssl::{SslContext, SslMethod};
use openssl::x509::X509FileType;
use irc::streams::{Server, AsEvented};

struct IrcHandler {
    server: Box<Server>,
    url: String
}

impl Handler for IrcHandler {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, _event_loop: &mut EventLoop<IrcHandler>, token: Token, _: EventSet) {
        match token {
            SERVER => {
                match self.server.accept() {
                    Some(client) => {
                        let mut bridge = Bridge::new(client, self.url.trim());
                        thread::spawn(move||{
                            bridge.run()
                        });
                    },
                    None => ()
                }
            },
            _ => unreachable!("Got a really weird token in the server event loop!")
        }
    }
}

const SERVER: Token = Token(0);

fn main() {
    env_logger::init().unwrap();
    let addr: SocketAddr = match env::args().nth(2) {
        Some(arg) => arg,
        None => "127.0.0.1:8001".to_string()
    }.parse().unwrap();
    let url =  env::args().nth(1).unwrap();
    let use_ssl = match addr {
        SocketAddr::V4(ref a) =>
            a.ip().octets() != [127, 0, 0, 1],
        _ => true
    };
    let server: Box<Server> = if use_ssl {
        let mut ssl = SslContext::new(SslMethod::Sslv23).expect("SSL setup failed");
        ssl.set_certificate_file(Path::new("pto.crt"), X509FileType::PEM).expect("Could not load pto.crt");
        ssl.set_private_key_file(Path::new("pto.key"), X509FileType::PEM).expect("Could not load pto.key");
        Box::new(ssl::SslServer::new(&addr, ssl))
    } else {
        warn!("SSL IS DISABLED!! IRC LOGINS ARE IN THE CLEAR AND UNENCRYPTED");
        Box::new(ssl::TcpServer::new(&addr))
    };
    info!("Listening on {}", addr);
    let mut events = EventLoop::new().unwrap();
    events.register(server.as_evented(), SERVER, EventSet::all(), PollOpt::edge()).unwrap();
    events.run(&mut IrcHandler{
        server: server,
        url: url
    }).unwrap();
}
<commit_msg>main: rewrite ssl code to be clearer<commit_after>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
extern crate rustc_serialize;
extern crate hyper;
extern crate mio;
extern crate env_logger;
extern crate openssl;
#[macro_use]
extern crate log;
mod irc;
mod matrix;
mod bridge;
mod ssl;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt};
use std::thread;
use bridge::Bridge;
use std::env;
use std::path::Path;
use std::net::SocketAddr;
use openssl::ssl::{SslContext, SslMethod};
use openssl::x509::X509FileType;
use irc::streams::{Server, AsEvented};

struct IrcHandler {
    server: Box<Server>,
    url: String
}

impl Handler for IrcHandler {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, _event_loop: &mut EventLoop<IrcHandler>, token: Token, _: EventSet) {
        match token {
            SERVER => {
                match self.server.accept() {
                    Some(client) => {
                        let mut bridge = Bridge::new(client, self.url.trim());
                        thread::spawn(move||{
                            bridge.run()
                        });
                    },
                    None => ()
                }
            },
            _ => unreachable!("Got a really weird token in the server event loop!")
        }
    }
}

const SERVER: Token = Token(0);

fn main() {
    env_logger::init().unwrap();
    let addr: SocketAddr = match env::args().nth(2) {
        Some(arg) => arg,
        None => "127.0.0.1:8001".to_string()
    }.parse().unwrap();
    let url =  env::args().nth(1).unwrap();
    let is_loopback = match addr {
        SocketAddr::V4(ref a) => {
            a.ip().octets() == [127, 0, 0, 1]
        },
        _ => true
    };
    let server: Box<Server> = if !is_loopback {
        let mut ssl = SslContext::new(SslMethod::Sslv23).expect("SSL setup failed");
        ssl.set_certificate_file(Path::new("pto.crt"), X509FileType::PEM).expect("Could not load pto.crt");
        ssl.set_private_key_file(Path::new("pto.key"), X509FileType::PEM).expect("Could not load pto.key");
        Box::new(ssl::SslServer::new(&addr, ssl))
    } else {
        warn!("SSL IS DISABLED!! IRC LOGINS ARE IN THE CLEAR AND UNENCRYPTED");
        Box::new(ssl::TcpServer::new(&addr))
    };
    info!("Listening on {}", addr);
    let mut events = EventLoop::new().unwrap();
    events.register(server.as_evented(), SERVER, EventSet::all(), PollOpt::edge()).unwrap();
    events.run(&mut IrcHandler{
        server: server,
        url: url
    }).unwrap();
}
<|endoftext|>


<commit_before>#![crate_id = "risp"]
#![crate_type = "bin"]

//! A Lisp interpreter.

extern crate libc;
extern crate getopts;
extern crate collections;

use std::os;
use libc::c_char;
use std::c_str::CString;
use interp::{interp, Environment};
use getopts::{optopt, getopts};
use collections::HashMap;

pub mod interp;

#[link(name = "linenoise")]
extern {
    fn linenoise(p: *c_char) -> *c_char;
    fn linenoiseHistoryAdd(l: *c_char);
}

/// Attempts to read input from a user using linenoise. Returns an option,
/// Some(StrBuf) for success, or None if EOF (^D) is entered.
pub fn rust_linenoise(prompt: &str) -> Option<StrBuf> {
    if prompt.len() == 0 {
        return None
    }

    let c_prompt = prompt.to_c_str();

    c_prompt.with_ref(|c_buf| {
        unsafe {
            let ret_str = CString::new(linenoise(c_buf), true);
            if ret_str.is_not_null() {
                ret_str.as_str().map(|ret_str| ret_str.to_strbuf())
            } else {
                None
            }
        }
    })
}

/// Adds a string to a history buffer.
pub fn rust_add_history(line: &str) {
    if line.len() == 0 {
        return
    }

    let c_line = line.to_c_str();
    c_line.with_ref(|c_line| {
        unsafe {
            linenoiseHistoryAdd(c_line);
        }
    });
}

fn main() {
    let mut global_env = Environment{ variables: HashMap::new() };
    let args: Vec<StrBuf> = os::args().iter().map(|x| x.to_strbuf()).collect();

    let program = args.get(0).clone();

    let opts = [
        optopt("n", "noninteractive", "non-interactive mode", "INPUT STRING"),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m)   => { m }
        Err(f)  => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("n") {
        match matches.opt_str("n") {
            Some(sexpr) => {
                let msg = interp(sexpr.to_str(), &global_env);
                println!("{}", msg);
                return
            }
            None    => {
                println!("Bad expr");
                return
            }
        }
    }

    loop {
        let mut expr = match rust_linenoise(">>> ") {
            Some(val)   => { val.as_slice().trim().to_str() },
            None    => { "".to_str() } //I hate ~str
        };

        let mut okay_expr = true;

        if expr.as_slice().starts_with("(") || expr.len() == 0 {
            let count_parens = |expr: &str| -> (uint, uint, bool) {
                let (mut lparens, mut rparens) = (0, 0);
                for c in expr.chars() {
                    if c == '(' {
                        if lparens == rparens && lparens != 0 {
                            return (lparens, rparens, false)
                        } else {
                            lparens += 1
                        }
                    } else if c == ')' {
                        if rparens >= lparens && rparens != 0 {
                            return (lparens, rparens, false)
                        } else {
                            rparens += 1
                        }
                    }
                }

                (lparens, rparens, true)
            };

            loop {
                let (lparens, rparens, okay_expr_tmp) = count_parens(expr.as_slice());
                if lparens == 0 && rparens == 0 && expr.len() > 1 {
                    break
                }

                if okay_expr_tmp == false {
                    okay_expr = false;
                    break
                }
                if lparens == rparens && lparens != 0 {
                    break
                }

                let expr_part = match rust_linenoise(" ") {
                    Some(val)   => { val.to_str() },
                    None    => { continue }
                };
                expr = expr.append("\n");
                expr = expr.append(expr_part.as_slice());
            }
        }

        if okay_expr == false {
            println!("Bad expression");
            continue
        }
        rust_add_history(expr.as_slice());

        match expr.as_slice() {
            "(exit)" | "exit" | ",q"    => { break },
            _   => { }
        }

        let msg = interp(expr.as_slice().trim().to_str(), &global_env);
        //holy hell I hate this
        println!("{}", msg);
    }
}
<commit_msg>Added a message for how to quit.<commit_after>#![crate_id = "risp"]
#![crate_type = "bin"]

//! A Lisp interpreter.

extern crate libc;
extern crate getopts;
extern crate collections;

use std::os;
use libc::c_char;
use std::c_str::CString;
use interp::{interp, Environment};
use getopts::{optopt, getopts};
use collections::HashMap;

pub mod interp;

#[link(name = "linenoise")]
extern {
    fn linenoise(p: *c_char) -> *c_char;
    fn linenoiseHistoryAdd(l: *c_char);
}

/// Attempts to read input from a user using linenoise. Returns an option,
/// Some(StrBuf) for success, or None if EOF (^D) is entered.
pub fn rust_linenoise(prompt: &str) -> Option<StrBuf> {
    if prompt.len() == 0 {
        return None
    }

    let c_prompt = prompt.to_c_str();

    c_prompt.with_ref(|c_buf| {
        unsafe {
            let ret_str = CString::new(linenoise(c_buf), true);
            if ret_str.is_not_null() {
                ret_str.as_str().map(|ret_str| ret_str.to_strbuf())
            } else {
                None
            }
        }
    })
}

/// Adds a string to a history buffer.
pub fn rust_add_history(line: &str) {
    if line.len() == 0 {
        return
    }

    let c_line = line.to_c_str();
    c_line.with_ref(|c_line| {
        unsafe {
            linenoiseHistoryAdd(c_line);
        }
    });
}

fn main() {
    let mut global_env = Environment{ variables: HashMap::new() };
    let args: Vec<StrBuf> = os::args().iter().map(|x| x.to_strbuf()).collect();

    let program = args.get(0).clone();

    let opts = [
        optopt("n", "noninteractive", "non-interactive mode", "INPUT STRING"),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m)   => { m }
        Err(f)  => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("n") {
        match matches.opt_str("n") {
            Some(sexpr) => {
                let msg = interp(sexpr.to_str(), &global_env);
                println!("{}", msg);
                return
            }
            None    => {
                println!("Bad expr");
                return
            }
        }
    }

    println!("Enter ``,q'', exit or (exit) at any time to exit.");

    loop {
        let mut expr = match rust_linenoise(">>> ") {
            Some(val)   => { val.as_slice().trim().to_str() },
            None    => { "".to_str() } //I hate ~str
        };

        let mut okay_expr = true;

        if expr.as_slice().starts_with("(") || expr.len() == 0 {
            let count_parens = |expr: &str| -> (uint, uint, bool) {
                let (mut lparens, mut rparens) = (0, 0);
                for c in expr.chars() {
                    if c == '(' {
                        if lparens == rparens && lparens != 0 {
                            return (lparens, rparens, false)
                        } else {
                            lparens += 1
                        }
                    } else if c == ')' {
                        if rparens >= lparens && rparens != 0 {
                            return (lparens, rparens, false)
                        } else {
                            rparens += 1
                        }
                    }
                }

                (lparens, rparens, true)
            };

            loop {
                let (lparens, rparens, okay_expr_tmp) = count_parens(expr.as_slice());
                if lparens == 0 && rparens == 0 && expr.len() > 1 {
                    break
                }

                if okay_expr_tmp == false {
                    okay_expr = false;
                    break
                }
                if lparens == rparens && lparens != 0 {
                    break
                }

                let expr_part = match rust_linenoise(" ") {
                    Some(val)   => { val.to_str() },
                    None    => { continue }
                };
                expr = expr.append("\n");
                expr = expr.append(expr_part.as_slice());
            }
        }

        if okay_expr == false {
            println!("Bad expression");
            continue
        }
        rust_add_history(expr.as_slice());

        match expr.as_slice() {
            "(exit)" | "exit" | ",q"    => { break },
            _   => { }
        }

        let msg = interp(expr.as_slice().trim().to_str(), &global_env);
        //holy hell I hate this
        println!("{}", msg);
    }
}
<|endoftext|>


<commit_before>// Worklog is for recording your hours.
//

extern crate chrono;
extern crate csv;
extern crate getopts;
extern crate rustc_serialize;

mod error;
mod timeclock;
mod util;

use chrono::*;
use error::WorklogError;
use getopts::Options;
use std::env;
use std::error::Error;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::PathBuf;
use timeclock::direction::Direction;

#[cfg(target_family = "unix")]
static CSV_FILE_NAME: &'static str = ".worklog.csv";
#[cfg(target_family = "windows")]
static CSV_FILE_NAME: &'static str = "worklog.csv";

// TODO This belongs in a config file somewhere
const WEEKSTART: i64 = Weekday::Sat as i64;

fn print_csv_entries<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    for rec in csv_entries {
        println!("{}", rec);
    }
    Ok(())
}

fn print_full_summary<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let entries = timeclock::pair_time_entries(csv_entries);
    let records = timeclock::collect_date_records(entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        total_hours += rec.hours();
        println!("{}", rec);
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

fn print_short_summary<R: Read>(file: R,
                                since: Date<FixedOffset>)
                                -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let entries = timeclock::pair_time_entries(csv_entries);
    let records = timeclock::collect_date_records(entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        if rec.date() >= since {
            total_hours += rec.hours();
            println!("{}", rec);
        }
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

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

/// Get the path for the csv data file
fn get_csv_path() -> Result<PathBuf, WorklogError> {
    let mut data_path = match env::home_dir() {
        Some(path) => path,
        None => {
            return Err(env::VarError::NotPresent).map_err(WorklogError::Env)
        }
    };

    data_path.push(CSV_FILE_NAME);
    return Ok(data_path);
}

fn main0() -> Result<i8, WorklogError> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflagopt("i", "in", "in time", "TIME");
    opts.optflagopt("o", "out", "out time", "TIME");
    opts.optopt("m", "memo", "the memo", "MEMO");
    opts.optflag("s", "summary", "show the full summary");
    opts.optflag("e", "entries", "show all entries");
    opts.optflag("h", "help", "print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    let csv_path = try!(get_csv_path());

    let csv_file = try!(OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(csv_path));

    if matches.opt_present("h") {
        print_usage(&program, opts);

    } else if matches.opts_present(&["i".to_owned(), "o".to_owned()]) {
        // The ridiculous array above isn't my fault.

        // Reject --in and --out if present at the same time
        if matches.opt_present("i") && matches.opt_present("o") {
            println!("--in or --out, not both");
            return Ok(1);
        }

        let dir = match matches.opt_present("i") {
            true => Direction::In,
            false => Direction::Out,
        };

        let time = matches.opt_str("i")
            .or(matches.opt_str("o"))
            .or(Some("now".to_owned()))
            .unwrap();
        let time = try!(util::parse_multi_time_fmt(&time));

        let memo = matches.opt_str("m").or(Some("".to_owned())).unwrap();
        timeclock::mark_time(dir, time, memo, csv_file);

        println!("Clocked {:#} at {}", dir, time.format("%F %I:%M %P"));

    } else if matches.opt_present("s") {
        try!(print_full_summary(&csv_file));

    } else if matches.opt_present("e") {
        try!(print_csv_entries(&csv_file));

    } else {
        let days_back = (-WEEKSTART + 7) % 7;
        let start_date = util::now().date() - Duration::days(days_back);
        try!(print_short_summary(&csv_file, start_date));
    }

    Ok(0)
}

fn main() {
    match main0() {
        Ok(_) => {}
        Err(err) => println!("Whoops! {}", err.description()),
    };
}
<commit_msg>Don't call discription when displaying errors<commit_after>// Worklog is for recording your hours.
//

extern crate chrono;
extern crate csv;
extern crate getopts;
extern crate rustc_serialize;

mod error;
mod timeclock;
mod util;

use chrono::*;
use error::WorklogError;
use getopts::Options;
use std::env;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::PathBuf;
use timeclock::direction::Direction;

#[cfg(target_family = "unix")]
static CSV_FILE_NAME: &'static str = ".worklog.csv";
#[cfg(target_family = "windows")]
static CSV_FILE_NAME: &'static str = "worklog.csv";

// TODO This belongs in a config file somewhere
const WEEKSTART: i64 = Weekday::Sat as i64;

fn print_csv_entries<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    for rec in csv_entries {
        println!("{}", rec);
    }
    Ok(())
}

fn print_full_summary<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let entries = timeclock::pair_time_entries(csv_entries);
    let records = timeclock::collect_date_records(entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        total_hours += rec.hours();
        println!("{}", rec);
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

fn print_short_summary<R: Read>(file: R,
                                since: Date<FixedOffset>)
                                -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let entries = timeclock::pair_time_entries(csv_entries);
    let records = timeclock::collect_date_records(entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        if rec.date() >= since {
            total_hours += rec.hours();
            println!("{}", rec);
        }
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

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

/// Get the path for the csv data file
fn get_csv_path() -> Result<PathBuf, WorklogError> {
    let mut data_path = match env::home_dir() {
        Some(path) => path,
        None => {
            return Err(env::VarError::NotPresent).map_err(WorklogError::Env)
        }
    };

    data_path.push(CSV_FILE_NAME);
    return Ok(data_path);
}

fn main0() -> Result<i8, WorklogError> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflagopt("i", "in", "in time", "TIME");
    opts.optflagopt("o", "out", "out time", "TIME");
    opts.optopt("m", "memo", "the memo", "MEMO");
    opts.optflag("s", "summary", "show the full summary");
    opts.optflag("e", "entries", "show all entries");
    opts.optflag("h", "help", "print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    let csv_path = try!(get_csv_path());

    let csv_file = try!(OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(csv_path));

    if matches.opt_present("h") {
        print_usage(&program, opts);

    } else if matches.opts_present(&["i".to_owned(), "o".to_owned()]) {
        // The ridiculous array above isn't my fault.

        // Reject --in and --out if present at the same time
        if matches.opt_present("i") && matches.opt_present("o") {
            println!("--in or --out, not both");
            return Ok(1);
        }

        let dir = match matches.opt_present("i") {
            true => Direction::In,
            false => Direction::Out,
        };

        let time = matches.opt_str("i")
            .or(matches.opt_str("o"))
            .or(Some("now".to_owned()))
            .unwrap();
        let time = try!(util::parse_multi_time_fmt(&time));

        let memo = matches.opt_str("m").or(Some("".to_owned())).unwrap();
        timeclock::mark_time(dir, time, memo, csv_file);

        println!("Clocked {:#} at {}", dir, time.format("%F %I:%M %P"));

    } else if matches.opt_present("s") {
        try!(print_full_summary(&csv_file));

    } else if matches.opt_present("e") {
        try!(print_csv_entries(&csv_file));

    } else {
        let days_back = (-WEEKSTART + 7) % 7;
        let start_date = util::now().date() - Duration::days(days_back);
        try!(print_short_summary(&csv_file, start_date));
    }

    Ok(0)
}

fn main() {
    match main0() {
        Ok(_) => {}
        Err(err) => println!("Whoops! {}", err),
    };
}
<|endoftext|>


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

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;

use xml::reader::EventReader;
use fromxml::{parse_root};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }

    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Register>,
    }

    struct Interrupt {
        name: String,
        value:Option<uint>,
    }

    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }

    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }

    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }

    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    println!("ioregs!({} = {{", peripheral.name);
    for register in peripheral.registers.iter() {
        write_register(register);
    }
    println!("}}")
}

fn write_register(register: &Register) {
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {}", en.name, en.value);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = parser.events();
    let device: Device = parse_root(&mut iter).unwrap();

    write_device(&device);
}
<commit_msg>Sort registers by offset<commit_after>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;
use std::num::from_str_radix;

use xml::reader::EventReader;
use fromxml::{parse_root};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }

    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Register>,
    }

    struct Interrupt {
        name: String,
        value:Option<uint>,
    }

    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }

    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }

    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }

    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn parse_num(s: &str) -> Option<u32> {
    if s.slice_to(2) == "0x" {
        from_str_radix(s.slice_from(2), 16)
    } else {
        from_str_radix(s, 10)
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    let mut registers: Vec<_> = peripheral.registers.iter().collect();

    registers.as_mut_slice().sort_by(|a, b| {
        let a = a.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        let b = b.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        a.cmp(&b)
    });

    println!("ioregs!({} = {{", peripheral.name);
    for &register in registers.iter() {
        write_register(register);
    }
    println!("}}")
}

fn write_register(register: &Register) {
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {}", en.name, en.value);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = parser.events();
    let device: Device = parse_root(&mut iter).unwrap();

    write_device(&device);
}
<|endoftext|>