<commit_before>///! GIT REQ!
mod git;
mod remotes;

use anyhow::Result;
use clap::{crate_authors, crate_version, App, AppSettings, ArgMatches, YamlLoader};
use colored::*;
use git2::ErrorCode;
use lazy_static::lazy_static;
use log::{debug, error, info, trace};
use logchop::*;
use std::io::{self, stdin, stdout, Cursor, Write};
use std::{env, include_str, process};
use tabwriter::TabWriter;
use yaml_rust::Yaml;

lazy_static! {
    static ref APP_CFG: Yaml = {
        YamlLoader::load_from_str(include_str!("../cli-flags.yml"))
            .expect("Failed to load CLI config")
            .pop()
            .unwrap()
    };
}

/// Get the remote for the current project
fn get_remote(remote_name: &str, fetch_api_key: bool) -> Result<Box<dyn remotes::Remote>> {
    let remote_url = git::get_remote_url(remote_name);
    remotes::get_remote(remote_name, &remote_url, !fetch_api_key)
}

/// Get the remote, fail hard otherwise
fn get_remote_hard(remote_name: &str, fetch_api_key: bool) -> Box<dyn remotes::Remote> {
    get_remote(remote_name, fetch_api_key).unwrap_or_else(|error| {
        eprintln!(
            "{}",
            format!(
                "There was a problem finding the remote Git repo: {}",
                &error
            )
            .red()
        );
        process::exit(1);
    })
}

/// Check out the branch corresponding to the MR ID and the remote's name
fn checkout_mr(remote_name: &str, mr_id: i64) {
    info!("Getting MR: {}", mr_id);
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let remote_branch_name = remote.get_remote_req_branch(mr_id).unwrap_or_else(|error| {
        eprintln!(
            "{}",
            format!(
                "There was a problem ascertaining the branch name: {}",
                &error
            )
            .red()
        );
        process::exit(1);
    });
    debug!("Got remote branch name: {}", remote_branch_name);
    git::checkout_branch(
        remote_name,
        &remote_branch_name,
        &remote.get_local_req_branch(mr_id).unwrap(),
        remote.has_virtual_remote_branch_names(),
    )
    .info_ok("Done")
    .unwrap_or_else(|err| {
        eprintln!(
            "{}",
            format!("There was an error checking out the branch: {}", err).red()
        );
        process::exit(1)
    });
}

/// Clear the API key for the current domain
fn clear_domain_key(remote_name: &str) {
    trace!("Deleting domain key");
    let mut remote = get_remote_hard(remote_name, false);
    let deleted = match git::delete_req_config(&remote.get_domain(), "apikey") {
        Ok(_) => Ok(true),
        Err(e) => match e.code() {
            ErrorCode::NotFound => Ok(false),
            _ => Err(e),
        },
    };
    match deleted {
        Ok(_) => eprintln!("{}", "Domain key deleted!".green()),
        Err(e) => {
            error!("Git Config error: {}", e);
            eprintln!(
                "{}",
                format!(
                    "There was an error deleting the domain key: {}",
                    e.message()
                )
                .red()
            );
            process::exit(1)
        }
    }
}

/// Set the API key for the current domain
fn set_domain_key(remote_name: &str, new_key: &str) {
    trace!("Setting domain key: {}", new_key);
    let mut remote = get_remote_hard(remote_name, false);
    git::set_req_config(&remote.get_domain(), "apikey", new_key);
    eprintln!("{}", "Domain key changed!".green());
}

/// Delete the project ID entry
fn clear_project_id(remote_name: &str) {
    trace!("Deleting project ID for {}", remote_name);
    git::delete_config("projectid", remote_name);
    eprintln!("{}", "Project ID cleared!".green());
}

/// Set the project ID
fn set_project_id(remote_name: &str, new_id: &str) {
    trace!("Setting project ID: {} for remote: {}", new_id, remote_name);
    git::set_config("projectid", remote_name, new_id);
    eprintln!("{}", "New project ID set!".green());
}

/// Set the default remote for the repository
fn set_default_remote(remote_name: &str) {
    trace!("Setting default remote {}", remote_name);
    git::set_project_config("defaultremote", remote_name);
    eprintln!("{}", "New default remote set!".green());
}

/// Print the open requests
fn list_open_requests(remote_name: &str) {
    info!("Getting open requests");
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let mrs = remote.get_req_names().unwrap();
    let mut tw = TabWriter::new(io::stdout()).padding(4);
    for mr in &mrs {
        if remote.has_useful_branch_names() {
            writeln!(
                &mut tw,
                "{}\t{}\t{}",
                mr.id.to_string().green(),
                mr.source_branch.green().dimmed(),
                mr.title
            )
            .unwrap();
        } else {
            writeln!(&mut tw, "{}\t{}", mr.id.to_string().green(), mr.title).unwrap();
        }
    }
    tw.flush().unwrap();
}

/// Print a shell completion script
fn generate_completion(app: &mut App, shell_name: &str) {
    let mut buffer = Cursor::new(Vec::new());
    app.gen_completions_to("git-req", shell_name.parse().unwrap(), &mut buffer);
    let mut output = String::from_utf8(buffer.into_inner()).unwrap_or_else(|_| String::from(""));
    if shell_name == "zsh" {
        // Clap assigns the _files completor to the REQUEST_ID. This is undesirable.
        output = output.replace(":_files", ":");
    }
    print!("{}", &output);
}

/// Get the name of the remote to use for the operation
fn get_remote_name(matches: &ArgMatches) -> String {
    let default_remote_name = git::get_project_config("defaultremote").unwrap_or_else(|| {
        let new_remote_name = git::guess_default_remote_name().unwrap_or_else(|_| {
            let mut new_remote_name = String::new();
            println!("Multiple remotes detected. Enter the name of the default one.");
            for remote in git::get_remotes() {
                println!(" * {}", remote);
            }
            print!("Remote name: ");
            let _ = stdout().flush();
            stdin()
                .read_line(&mut new_remote_name)
                .expect("Did not input a name");
            trace!("New remote: {}", &new_remote_name);
            if !git::get_remotes().contains(new_remote_name.trim()) {
                panic!("Invalid remote name provided")
            }
            new_remote_name
        });
        git::set_project_config("defaultremote", &new_remote_name);
        new_remote_name
    });
    // Not using Clap's default_value because of https://github.com/clap-rs/clap/issues/1140
    matches
        .value_of("REMOTE_NAME")
        .unwrap_or(&default_remote_name)
        .to_string()
}

/// Get the Clap app for CLI matching et al.
fn build_cli<'a>() -> App<'a, 'a> {
    App::from_yaml(&APP_CFG)
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .setting(AppSettings::ArgsNegateSubcommands)
        .usage("git req [OPTIONS] [REQUEST_ID]")
}

/// Do the thing
fn main() {
    color_backtrace::install();
    let _ = env_logger::Builder::new()
        .parse_filters(&env::var("REQ_LOG").unwrap_or_default())
        .try_init();

    let mut app = build_cli();

    let matches = app.get_matches();

    if let Some(project_id) = matches.value_of("NEW_PROJECT_ID") {
        set_project_id(&get_remote_name(&matches), project_id);
    } else if matches.is_present("CLEAR_PROJECT_ID") {
        clear_project_id(&get_remote_name(&matches));
    } else if matches.is_present("LIST_MR") {
        list_open_requests(&get_remote_name(&matches));
    } else if matches.is_present("CLEAR_DOMAIN_KEY") {
        clear_domain_key(&get_remote_name(&matches));
    } else if let Some(domain_key) = matches.value_of("NEW_DOMAIN_KEY") {
        set_domain_key(&get_remote_name(&matches), domain_key);
    } else if let Some(remote_name) = matches.value_of("NEW_DEFAULT_REMOTE") {
        set_default_remote(remote_name);
    } else if let Some(shell_name) = matches.value_of("GENERATE_COMPLETIONS") {
        app = build_cli();
        generate_completion(&mut app, &shell_name);
    } else {
        checkout_mr(
            &get_remote_name(&matches),
            matches.value_of("REQUEST_ID").unwrap().parse().unwrap(),
        );
    }
}
<commit_msg>Improve error handling for non-numeric request ID inputs.<commit_after>///! GIT REQ!
mod git;
mod remotes;

use anyhow::Result;
use clap::{crate_authors, crate_version, App, AppSettings, ArgMatches, YamlLoader};
use colored::*;
use git2::ErrorCode;
use lazy_static::lazy_static;
use log::{debug, error, info, trace};
use logchop::*;
use std::io::{self, stdin, stdout, Cursor, Write};
use std::{env, include_str, process};
use tabwriter::TabWriter;
use yaml_rust::Yaml;

lazy_static! {
    static ref APP_CFG: Yaml = {
        YamlLoader::load_from_str(include_str!("../cli-flags.yml"))
            .expect("Failed to load CLI config")
            .pop()
            .unwrap()
    };
}

/// Get the remote for the current project
fn get_remote(remote_name: &str, fetch_api_key: bool) -> Result<Box<dyn remotes::Remote>> {
    let remote_url = git::get_remote_url(remote_name);
    remotes::get_remote(remote_name, &remote_url, !fetch_api_key)
}

/// Get the remote, fail hard otherwise
fn get_remote_hard(remote_name: &str, fetch_api_key: bool) -> Box<dyn remotes::Remote> {
    get_remote(remote_name, fetch_api_key).unwrap_or_else(|error| {
        eprintln!(
            "{}",
            format!(
                "There was a problem finding the remote Git repo: {}",
                &error
            )
            .red()
        );
        process::exit(1);
    })
}

/// Check out the branch corresponding to the MR ID and the remote's name
fn checkout_mr(remote_name: &str, mr_id: i64) {
    info!("Getting MR: {}", mr_id);
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let remote_branch_name = remote.get_remote_req_branch(mr_id).unwrap_or_else(|error| {
        eprintln!(
            "{}",
            format!(
                "There was a problem ascertaining the branch name: {}",
                &error
            )
            .red()
        );
        process::exit(1);
    });
    debug!("Got remote branch name: {}", remote_branch_name);
    git::checkout_branch(
        remote_name,
        &remote_branch_name,
        &remote.get_local_req_branch(mr_id).unwrap(),
        remote.has_virtual_remote_branch_names(),
    )
    .info_ok("Done")
    .unwrap_or_else(|err| {
        eprintln!(
            "{}",
            format!("There was an error checking out the branch: {}", err).red()
        );
        process::exit(1)
    });
}

/// Clear the API key for the current domain
fn clear_domain_key(remote_name: &str) {
    trace!("Deleting domain key");
    let mut remote = get_remote_hard(remote_name, false);
    let deleted = match git::delete_req_config(&remote.get_domain(), "apikey") {
        Ok(_) => Ok(true),
        Err(e) => match e.code() {
            ErrorCode::NotFound => Ok(false),
            _ => Err(e),
        },
    };
    match deleted {
        Ok(_) => eprintln!("{}", "Domain key deleted!".green()),
        Err(e) => {
            error!("Git Config error: {}", e);
            eprintln!(
                "{}",
                format!(
                    "There was an error deleting the domain key: {}",
                    e.message()
                )
                .red()
            );
            process::exit(1)
        }
    }
}

/// Set the API key for the current domain
fn set_domain_key(remote_name: &str, new_key: &str) {
    trace!("Setting domain key: {}", new_key);
    let mut remote = get_remote_hard(remote_name, false);
    git::set_req_config(&remote.get_domain(), "apikey", new_key);
    eprintln!("{}", "Domain key changed!".green());
}

/// Delete the project ID entry
fn clear_project_id(remote_name: &str) {
    trace!("Deleting project ID for {}", remote_name);
    git::delete_config("projectid", remote_name);
    eprintln!("{}", "Project ID cleared!".green());
}

/// Set the project ID
fn set_project_id(remote_name: &str, new_id: &str) {
    trace!("Setting project ID: {} for remote: {}", new_id, remote_name);
    git::set_config("projectid", remote_name, new_id);
    eprintln!("{}", "New project ID set!".green());
}

/// Set the default remote for the repository
fn set_default_remote(remote_name: &str) {
    trace!("Setting default remote {}", remote_name);
    git::set_project_config("defaultremote", remote_name);
    eprintln!("{}", "New default remote set!".green());
}

/// Print the open requests
fn list_open_requests(remote_name: &str) {
    info!("Getting open requests");
    let mut remote = get_remote_hard(remote_name, true);
    debug!("Found remote: {}", remote);
    let mrs = remote.get_req_names().unwrap();
    let mut tw = TabWriter::new(io::stdout()).padding(4);
    for mr in &mrs {
        if remote.has_useful_branch_names() {
            writeln!(
                &mut tw,
                "{}\t{}\t{}",
                mr.id.to_string().green(),
                mr.source_branch.green().dimmed(),
                mr.title
            )
            .unwrap();
        } else {
            writeln!(&mut tw, "{}\t{}", mr.id.to_string().green(), mr.title).unwrap();
        }
    }
    tw.flush().unwrap();
}

/// Print a shell completion script
fn generate_completion(app: &mut App, shell_name: &str) {
    let mut buffer = Cursor::new(Vec::new());
    app.gen_completions_to("git-req", shell_name.parse().unwrap(), &mut buffer);
    let mut output = String::from_utf8(buffer.into_inner()).unwrap_or_else(|_| String::from(""));
    if shell_name == "zsh" {
        // Clap assigns the _files completor to the REQUEST_ID. This is undesirable.
        output = output.replace(":_files", ":");
    }
    print!("{}", &output);
}

/// Get the name of the remote to use for the operation
fn get_remote_name(matches: &ArgMatches) -> String {
    let default_remote_name = git::get_project_config("defaultremote").unwrap_or_else(|| {
        let new_remote_name = git::guess_default_remote_name().unwrap_or_else(|_| {
            let mut new_remote_name = String::new();
            println!("Multiple remotes detected. Enter the name of the default one.");
            for remote in git::get_remotes() {
                println!(" * {}", remote);
            }
            print!("Remote name: ");
            let _ = stdout().flush();
            stdin()
                .read_line(&mut new_remote_name)
                .expect("Did not input a name");
            trace!("New remote: {}", &new_remote_name);
            if !git::get_remotes().contains(new_remote_name.trim()) {
                panic!("Invalid remote name provided")
            }
            new_remote_name
        });
        git::set_project_config("defaultremote", &new_remote_name);
        new_remote_name
    });
    // Not using Clap's default_value because of https://github.com/clap-rs/clap/issues/1140
    matches
        .value_of("REMOTE_NAME")
        .unwrap_or(&default_remote_name)
        .to_string()
}

/// Get the Clap app for CLI matching et al.
fn build_cli<'a>() -> App<'a, 'a> {
    App::from_yaml(&APP_CFG)
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .setting(AppSettings::ArgsNegateSubcommands)
        .usage("git req [OPTIONS] [REQUEST_ID]")
}

/// Do the thing
fn main() {
    color_backtrace::install();
    let _ = env_logger::Builder::new()
        .parse_filters(&env::var("REQ_LOG").unwrap_or_default())
        .try_init();

    let mut app = build_cli();

    let matches = app.get_matches();

    if let Some(project_id) = matches.value_of("NEW_PROJECT_ID") {
        set_project_id(&get_remote_name(&matches), project_id);
    } else if matches.is_present("CLEAR_PROJECT_ID") {
        clear_project_id(&get_remote_name(&matches));
    } else if matches.is_present("LIST_MR") {
        list_open_requests(&get_remote_name(&matches));
    } else if matches.is_present("CLEAR_DOMAIN_KEY") {
        clear_domain_key(&get_remote_name(&matches));
    } else if let Some(domain_key) = matches.value_of("NEW_DOMAIN_KEY") {
        set_domain_key(&get_remote_name(&matches), domain_key);
    } else if let Some(remote_name) = matches.value_of("NEW_DEFAULT_REMOTE") {
        set_default_remote(remote_name);
    } else if let Some(shell_name) = matches.value_of("GENERATE_COMPLETIONS") {
        app = build_cli();
        generate_completion(&mut app, &shell_name);
    } else {
        match matches.value_of("REQUEST_ID").unwrap().parse() {
            Ok(mr_id) => {
                checkout_mr(&get_remote_name(&matches), mr_id);
            }
            Err(_) => {
                eprintln!("{}", "Invalid request ID provided".red());
                process::exit(1);
            }
        };
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

mod request;
mod turn;
mod region;
mod superregion;

use request::Request;
use turn::Turn;
use region::Region;
use superregion::SuperRegion;

fn main()
{
	let input = io::stdin();
	let input = BufReader::new(input);
	let input = input.lines();
	let input = input
		.map(Result::unwrap)
		.filter(|s|s.len()>0)
		.map(|s|s.parse::<Request>())
		.map(Result::unwrap);

	let mut name_you = String::new();
	let mut name_other = String::new();

	let mut sup_regions: HashMap<usize,SuperRegion> = HashMap::new();
	let mut regions: HashMap<usize,Region> = HashMap::new();

	let mut armies_left = 0;

	for req in input
	{
		use request::Request::*;
		match req
		{
			ListSuperRegions(sregions) =>
			{
				sup_regions.extend(sregions.iter().map(|sr|(sr.id,sr.clone())));
			},
			ListRegions(regs) =>
			{
				regions.extend(regs.iter().map(|r|(r.id,r.clone())));
			},
			ListNeighbours(relations) =>
			{
				for (id,neighbours) in relations
				{
					regions.get_mut(&id).unwrap().neighbours.extend(neighbours.iter());
					for n in neighbours
					{
						regions.get_mut(&n).unwrap().neighbours.push(id);
					}
				}
			},
			RequestStartingRegions(_avail) =>
			{
				println!("give me randomly");
			},
			SettingNameYou(name) => name_you = name,
			SettingNameOther(name) => name_other = name,
			SettingArmies(count) =>
			{
				armies_left = count;
			},
			UpdateMap(updates) =>
			{
				for u in updates
				{
					let mut reg = regions.get_mut(&u.0).unwrap();
					reg.player = u.1;
					reg.count = u.2;
				}
			},
			TurnOther(_turns) =>
			{
				//TODO: what the hell?
			},
			TurnPlace =>
			{
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.filter(|r|r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.any(|o|o.count*2 < r.count)
					).collect::<Vec<_>>();

				let mut v = Vec::new();
				if armies_left > regs.len()
				{
					let count = armies_left / regs.len();
					for r in regs
					{
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: count,
							}
						);
						armies_left -= count;
					}
					v.push(
						Turn::Place
						{
							name: name_you.clone(),
							region: regions.values().max_by_key(|r|r.count).unwrap().id,
							count: armies_left,
						}
					);
				}
				else
				{
					for r in regs
					{
						if armies_left <= 0
						{
							break;
						}
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: 1,
							}
						);
						armies_left -= 1;
					}
				}
				let v = v.iter().map(|t|format!("{}",t)).collect::<Vec<_>>();
				println!("{}",v.join(","));
			},
			TurnArmies =>
			{
				let mut v = Vec::new();
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.map(|r|((r.id,r.count*2/3),r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.filter(|o|o.count*3 < r.count)
						.next()
						.unwrap().id))
					.collect::<Vec<_>>();
				for ((r,count),n) in regs
				{
					v.push(
						Turn::Turn
						{
							name: name_you.clone(),
							source: r,
							target: n,
							count: count,
						}
					);
				}
			},
		}
	}
}

<commit_msg>enable backtrace<commit_after>use std::io;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

mod request;
mod turn;
mod region;
mod superregion;

use request::Request;
use turn::Turn;
use region::Region;
use superregion::SuperRegion;

fn main()
{
	std::env::set_var("RUST_BACKTRACE","1");
	let input = io::stdin();
	let input = BufReader::new(input);
	let input = input.lines();
	let input = input
		.map(Result::unwrap)
		.filter(|s|s.len()>0)
		.map(|s|s.parse::<Request>())
		.map(Result::unwrap);

	let mut name_you = String::new();
	let mut name_other = String::new();

	let mut sup_regions: HashMap<usize,SuperRegion> = HashMap::new();
	let mut regions: HashMap<usize,Region> = HashMap::new();

	let mut armies_left = 0;

	for req in input
	{
		use request::Request::*;
		match req
		{
			ListSuperRegions(sregions) =>
			{
				sup_regions.extend(sregions.iter().map(|sr|(sr.id,sr.clone())));
			},
			ListRegions(regs) =>
			{
				regions.extend(regs.iter().map(|r|(r.id,r.clone())));
			},
			ListNeighbours(relations) =>
			{
				for (id,neighbours) in relations
				{
					regions.get_mut(&id).unwrap().neighbours.extend(neighbours.iter());
					for n in neighbours
					{
						regions.get_mut(&n).unwrap().neighbours.push(id);
					}
				}
			},
			RequestStartingRegions(_avail) =>
			{
				println!("give me randomly");
			},
			SettingNameYou(name) => name_you = name,
			SettingNameOther(name) => name_other = name,
			SettingArmies(count) =>
			{
				armies_left = count;
			},
			UpdateMap(updates) =>
			{
				for u in updates
				{
					let mut reg = regions.get_mut(&u.0).unwrap();
					reg.player = u.1;
					reg.count = u.2;
				}
			},
			TurnOther(_turns) =>
			{
				//TODO: what the hell?
			},
			TurnPlace =>
			{
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.filter(|r|r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.any(|o|o.count*2 < r.count)
					).collect::<Vec<_>>();

				let mut v = Vec::new();
				if armies_left > regs.len()
				{
					let count = armies_left / regs.len();
					for r in regs
					{
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: count,
							}
						);
						armies_left -= count;
					}
					v.push(
						Turn::Place
						{
							name: name_you.clone(),
							region: regions.values().max_by_key(|r|r.count).unwrap().id,
							count: armies_left,
						}
					);
				}
				else
				{
					for r in regs
					{
						if armies_left <= 0
						{
							break;
						}
						v.push(
							Turn::Place
							{
								name: name_you.clone(),
								region: r.id,
								count: 1,
							}
						);
						armies_left -= 1;
					}
				}
				let v = v.iter().map(|t|format!("{}",t)).collect::<Vec<_>>();
				println!("{}",v.join(","));
			},
			TurnArmies =>
			{
				let mut v = Vec::new();
				let regs = regions.values()
					.filter(|r|r.player.eq(&name_you))
					.map(|r|((r.id,r.count*2/3),r.neighbours.iter()
						.map(|o|regions.get(o))
						.map(Option::unwrap)
						.filter(|o|o.player != name_you)
						.filter(|o|o.count*3 < r.count)
						.next()
						.unwrap().id))
					.collect::<Vec<_>>();
				for ((r,count),n) in regs
				{
					v.push(
						Turn::Turn
						{
							name: name_you.clone(),
							source: r,
							target: n,
							count: count,
						}
					);
				}
			},
		}
	}
}

<|endoftext|>


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

use rgtk::*;
use std::collections::HashSet;

mod projects;
mod utils;

fn main() {
    gtk::init();

    // constants

    let width = 1242;
    let height = 768;
    let editor_height = ((height as f32) * 0.8) as i32;

    // window

    let mut window = gtk::Window::new(gtk::window_type::TopLevel).unwrap();
    window.set_title("SolidOak");
    window.set_window_position(gtk::window_position::Center);
    window.set_default_size(width, height);

    window.connect(gtk::signals::DeleteEvent::new(|_| {
        gtk::main_quit();
        true
    }));

    // project pane

    let new_project_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut project_buttons = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    project_buttons.set_size_request(-1, -1);
    project_buttons.add(&new_project_button);
    project_buttons.add(&import_button);
    project_buttons.add(&rename_button);
    project_buttons.add(&remove_button);

    let mut project_tree = gtk::TreeView::new().unwrap();
    let column_types = vec![glib::ffi::g_type_string];
    let tree_store = gtk::TreeStore::new(column_types).unwrap();
    let model = tree_store.get_model().unwrap();
    project_tree.set_model(&model);

    let mut project_pane = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    project_pane.set_size_request(-1, -1);
    project_pane.pack_start(&project_buttons, false, true, 0);
    project_pane.pack_start(&project_tree, true, true, 0);

    // editor pane

    let editor_pane = gtk::TextView::new().unwrap();
    editor_pane.set_size_request(-1, editor_height);

    // build pane

    let build_pane = gtk::TextView::new().unwrap();

    // content

    let mut content = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    content.pack_start(&editor_pane, false, true, 0);
    content.pack_start(&build_pane, true, true, 0);

    // hbox

    let mut hbox = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&project_pane, false, true, 0);
    hbox.pack_start(&content, true, true, 0);
    window.add(&hbox);

    // state

    let mut state = ::utils::State{
        projects: HashSet::new(),
        expansions: HashSet::new(),
        selection: None,
        tree_model: &model
    };

    // connections

    new_project_button.connect(gtk::signals::Clicked::new(|| {::projects::new_project(&mut state)}));
    import_button.connect(gtk::signals::Clicked::new(|| {::projects::import_project(&mut state)}));
    rename_button.connect(gtk::signals::Clicked::new(|| {::projects::rename_project(&mut state)}));
    remove_button.connect(gtk::signals::Clicked::new(|| {::projects::remove_project(&mut state)}));

    // show window

    window.show_all();
    gtk::main();
}
<commit_msg>Show text in project tree<commit_after>#![feature(globs)]
extern crate rgtk;

use rgtk::*;
use std::collections::HashSet;

mod projects;
mod utils;

fn main() {
    gtk::init();

    // constants

    let width = 1242;
    let height = 768;
    let editor_height = ((height as f32) * 0.8) as i32;

    // window

    let mut window = gtk::Window::new(gtk::window_type::TopLevel).unwrap();
    window.set_title("SolidOak");
    window.set_window_position(gtk::window_position::Center);
    window.set_default_size(width, height);

    window.connect(gtk::signals::DeleteEvent::new(|_| {
        gtk::main_quit();
        true
    }));

    // project pane

    let new_project_button = gtk::Button::new_with_label("New Project").unwrap();
    let import_button = gtk::Button::new_with_label("Import").unwrap();
    let rename_button = gtk::Button::new_with_label("Rename").unwrap();
    let remove_button = gtk::Button::new_with_label("Remove").unwrap();

    let mut project_buttons = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    project_buttons.set_size_request(-1, -1);
    project_buttons.add(&new_project_button);
    project_buttons.add(&import_button);
    project_buttons.add(&rename_button);
    project_buttons.add(&remove_button);

    let mut project_tree = gtk::TreeView::new().unwrap();
    let column_types = vec![glib::ffi::g_type_string];
    let store = gtk::ListStore::new(column_types).unwrap();
    let model = store.get_model().unwrap();
    project_tree.set_model(&model);
    project_tree.set_headers_visible(false);

    let column = gtk::TreeViewColumn::new().unwrap();
    project_tree.append_column(&column);

    let cell = gtk::CellRendererText::new().unwrap();
    column.pack_start(&cell, true);
    column.add_attribute(&cell, "text", 0);

    let mut raw_iter = gtk::ffi::C_GtkTreeIter;
    let iter = gtk::TreeIter::wrap_pointer(&mut raw_iter);
    model.get_iter_first(&iter);
    store.append(&iter);
    store.set_column_text(&iter, 0, "Hello, world!");

    let mut project_pane = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    project_pane.set_size_request(-1, -1);
    project_pane.pack_start(&project_buttons, false, true, 0);
    project_pane.pack_start(&project_tree, true, true, 0);

    // editor pane

    let editor_pane = gtk::TextView::new().unwrap();
    editor_pane.set_size_request(-1, editor_height);

    // build pane

    let build_pane = gtk::TextView::new().unwrap();

    // content

    let mut content = gtk::Box::new(gtk::orientation::Vertical, 0).unwrap();
    content.pack_start(&editor_pane, false, true, 0);
    content.pack_start(&build_pane, true, true, 0);

    // hbox

    let mut hbox = gtk::Box::new(gtk::orientation::Horizontal, 0).unwrap();
    hbox.pack_start(&project_pane, false, true, 0);
    hbox.pack_start(&content, true, true, 0);
    window.add(&hbox);

    // state

    let mut state = ::utils::State{
        projects: HashSet::new(),
        expansions: HashSet::new(),
        selection: None,
        tree_model: &model
    };

    // connections

    new_project_button.connect(gtk::signals::Clicked::new(|| {::projects::new_project(&mut state)}));
    import_button.connect(gtk::signals::Clicked::new(|| {::projects::import_project(&mut state)}));
    rename_button.connect(gtk::signals::Clicked::new(|| {::projects::rename_project(&mut state)}));
    remove_button.connect(gtk::signals::Clicked::new(|| {::projects::remove_project(&mut state)}));

    // show window

    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate schemamama;
extern crate schemamama_postgres;
extern crate postgres;
mod schema;

#[macro_use]
extern crate log;
extern crate log4rs;

extern crate iron;
extern crate router;
extern crate logger;

use iron::prelude::*;
use iron::status;
use router::Router;
use logger::Logger;
use std::io::Read;
use iron::modifiers::Redirect;

use std::env;
use std::ops::Deref;

extern crate uuid;
use uuid::Uuid;
extern crate serde_json;
use serde_json::{Map, Value};

extern crate r2d2;
extern crate r2d2_postgres;
extern crate persistent;
use persistent::Read as PRead;
use postgres::rows::{Row, RowIndex};
use postgres::types::FromSql;

#[macro_use]mod db;
#[macro_use]mod server_id;

use std::error::Error;
use std::fmt::{self, Debug};
#[derive(Debug)]
struct StringError(String);

impl Error for StringError {
    fn description(&self) -> &str {
        &*self.0
    }
}

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

struct Log {
    id: Uuid,
    owner: Uuid,
    next: Option<Uuid>,
    prev: Option<Uuid>,
    data: Value,
}

fn log_status(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

fn new_log(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    let id = Uuid::new_v4();
    let hyphenated = id.hyphenated().to_string();
    let server_id = get_server_id!(&req).deref();
    let stmt = conn.prepare("SELECT id from log WHERE next is null LIMIT 1").expect("prepare failure");
    let results = stmt.query(&[]).expect("last select works");
    let previous = if results.is_empty() {
        None
    } else {
        let row = results.get(0);
        let id: Uuid = row.get("id");
        Some(id)
    };
    conn.execute("UPDATE log set next = $1 where owner = $2 and next is null",
                 &[&id, server_id])
        .expect("update worked");
    conn.execute("INSERT INTO log (id, owner, data, prev) VALUES ($1, $2, $3, $4)",
                 &[&id, server_id, &json, &previous])
        .expect("insert worked");
    let new_url = {
        let req_url = req.url.clone();
        let base_url = req_url.into_generic_url();
        base_url.join(&format!("/log/{}", &hyphenated)).expect("join url works")
    };
    Ok(Response::with((status::Found,
                       Redirect(iron::Url::from_generic_url(new_url).expect("URL parsed ok")))))
}

fn get_with_null<I, T>(row: &Row, index: I) -> Option<T> where I: RowIndex, T: FromSql {
    match row.get_opt(index) {
        Some(val) => {
            match val {
                Ok(val) => Some(val),
                Err(_) => None
            }
        },
        None => None
    }
}

fn get_log(req: &mut Request) -> IronResult<Response> {
    let ref query = req.extensions
        .get::<Router>()
        .unwrap()
        .find("entry_id")
        .unwrap_or("/");
    let query_id = Uuid::parse_str(&query).expect("Dodgy UUID");
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("SELECT owner, next, prev, data from log where id=$1").expect("prepare failure");
    let results = stmt.query(&[&query_id]).expect("bad query");
    if results.is_empty() {
        Ok(Response::with((status::NotFound, format!("No log {}", query))))
    } else {
        let row = results.get(0);
        let data: Value = row.get("data");
        let mut map = Map::new();
        let owner: Uuid = row.get("owner");
        let next: Option<Uuid> = get_with_null(&row, "next");
        let prev: Option<Uuid> = get_with_null(&row, "prev");
        map.insert(String::from("owner"),
                   serde_json::to_value(&owner.to_string()));
        map.insert(String::from("prev"),
                   serde_json::to_value(&prev.map(|x| x.to_string())));
        map.insert(String::from("next"),
                   serde_json::to_value(&next.map(|x| x.to_string())));
        map.insert(String::from("data"), data);
        let value = Value::Object(map);
        Ok(Response::with((status::Ok, serde_json::ser::to_string(&value).unwrap())))
    }
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).unwrap();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    schema::up(&conn).unwrap();
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = Router::new();
    router.get("/log", log_status);
    router.post("/log", new_log);
    router.get("/log/:entry_id", get_log);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link_before(PRead::<server_id::ServerId>::one(server_id::setup()));
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Potboiler booted");
    Iron::new(chain).http("localhost:8000").unwrap();
}
<commit_msg>Fix get_with_null formatting<commit_after>#[macro_use]
extern crate schemamama;
extern crate schemamama_postgres;
extern crate postgres;
mod schema;

#[macro_use]
extern crate log;
extern crate log4rs;

extern crate iron;
extern crate router;
extern crate logger;

use iron::prelude::*;
use iron::status;
use router::Router;
use logger::Logger;
use std::io::Read;
use iron::modifiers::Redirect;

use std::env;
use std::ops::Deref;

extern crate uuid;
use uuid::Uuid;
extern crate serde_json;
use serde_json::{Map, Value};

extern crate r2d2;
extern crate r2d2_postgres;
extern crate persistent;
use persistent::Read as PRead;
use postgres::rows::{Row, RowIndex};
use postgres::types::FromSql;

#[macro_use]mod db;
#[macro_use]mod server_id;

use std::error::Error;
use std::fmt::{self, Debug};
#[derive(Debug)]
struct StringError(String);

impl Error for StringError {
    fn description(&self) -> &str {
        &*self.0
    }
}

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

struct Log {
    id: Uuid,
    owner: Uuid,
    next: Option<Uuid>,
    prev: Option<Uuid>,
    data: Value,
}

fn log_status(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

fn new_log(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    let id = Uuid::new_v4();
    let hyphenated = id.hyphenated().to_string();
    let server_id = get_server_id!(&req).deref();
    let stmt = conn.prepare("SELECT id from log WHERE next is null LIMIT 1").expect("prepare failure");
    let results = stmt.query(&[]).expect("last select works");
    let previous = if results.is_empty() {
        None
    } else {
        let row = results.get(0);
        let id: Uuid = row.get("id");
        Some(id)
    };
    conn.execute("UPDATE log set next = $1 where owner = $2 and next is null",
                 &[&id, server_id])
        .expect("update worked");
    conn.execute("INSERT INTO log (id, owner, data, prev) VALUES ($1, $2, $3, $4)",
                 &[&id, server_id, &json, &previous])
        .expect("insert worked");
    let new_url = {
        let req_url = req.url.clone();
        let base_url = req_url.into_generic_url();
        base_url.join(&format!("/log/{}", &hyphenated)).expect("join url works")
    };
    Ok(Response::with((status::Found,
                       Redirect(iron::Url::from_generic_url(new_url).expect("URL parsed ok")))))
}

fn get_with_null<I, T>(row: &Row, index: I) -> Option<T>
    where I: RowIndex,
          T: FromSql
{
    match row.get_opt(index) {
        Some(val) => {
            match val {
                Ok(val) => Some(val),
                Err(_) => None,
            }
        }
        None => None,
    }
}

fn get_log(req: &mut Request) -> IronResult<Response> {
    let ref query = req.extensions
        .get::<Router>()
        .unwrap()
        .find("entry_id")
        .unwrap_or("/");
    let query_id = Uuid::parse_str(&query).expect("Dodgy UUID");
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("SELECT owner, next, prev, data from log where id=$1").expect("prepare failure");
    let results = stmt.query(&[&query_id]).expect("bad query");
    if results.is_empty() {
        Ok(Response::with((status::NotFound, format!("No log {}", query))))
    } else {
        let row = results.get(0);
        let data: Value = row.get("data");
        let mut map = Map::new();
        let owner: Uuid = row.get("owner");
        let next: Option<Uuid> = get_with_null(&row, "next");
        let prev: Option<Uuid> = get_with_null(&row, "prev");
        map.insert(String::from("owner"),
                   serde_json::to_value(&owner.to_string()));
        map.insert(String::from("prev"),
                   serde_json::to_value(&prev.map(|x| x.to_string())));
        map.insert(String::from("next"),
                   serde_json::to_value(&next.map(|x| x.to_string())));
        map.insert(String::from("data"), data);
        let value = Value::Object(map);
        Ok(Response::with((status::Ok, serde_json::ser::to_string(&value).unwrap())))
    }
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).unwrap();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    schema::up(&conn).unwrap();
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = Router::new();
    router.get("/log", log_status);
    router.post("/log", new_log);
    router.get("/log/:entry_id", get_log);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link_before(PRead::<server_id::ServerId>::one(server_id::setup()));
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Potboiler booted");
    Iron::new(chain).http("localhost:8000").unwrap();
}
<|endoftext|>


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

extern crate getopts;
extern crate image;

use getopts::Options;
use std::default::Default;
use std::old_io::fs::File;
use std::os::args;

mod css;
mod dom;
mod html;
mod layout;
mod style;
mod painting;
mod pdf;

fn main() {
    // Parse command-line options:
    let mut opts = Options::new();
    opts.optopt("h", "html", "HTML document", "FILENAME");
    opts.optopt("c", "css", "CSS stylesheet", "FILENAME");
    opts.optopt("o", "output", "Output file", "FILENAME");
    opts.optopt("f", "format", "Output file format", "png | pdf");

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

    let png = match matches.opt_str("f") {
        None => true,
        Some(format) => match &*format {
            "png" => true,
            "pdf" => false,
            _ => panic!("Unknow output format: {}", format),
        }
    };

    // Read input files:
    let read_source = |&: arg_filename: Option<String>, default_filename: &str| {
        let path = match arg_filename {
            Some(ref filename) => &**filename,
            None => default_filename,
        };
        File::open(&Path::new(path)).read_to_string().unwrap()
    };
    let html = read_source(matches.opt_str("h"), "examples/test.html");
    let css  = read_source(matches.opt_str("c"), "examples/test.css");

    // Since we don't have an actual window, hard-code the "viewport" size.
    let initial_containing_block = layout::Dimensions {
        content: layout::Rect { x: 0.0, y: 0.0, width: 800.0, height: 600.0 },
        padding: Default::default(),
        border: Default::default(),
        margin: Default::default(),
    };

    // Parsing and rendering:
    let root_node = html::parse(html);
    let stylesheet = css::parse(css);
    let style_root = style::style_tree(&root_node, &stylesheet);
    let layout_root = layout::layout_tree(&style_root, initial_containing_block);

    // Create the output file:
    let default_filename = if png { "output.png" } else { "output.pdf" };
    let filename = matches.opt_str("o").unwrap_or(default_filename.to_string());
    let mut file = File::create(&Path::new(&*filename)).unwrap();

    let result_ok;
    if png {
        let canvas = painting::paint(&layout_root, initial_containing_block.content);

        // Save an image:
        let (w, h) = (canvas.width as u32, canvas.height as u32);
        let buffer: Vec<image::Rgba<u8>> = unsafe { std::mem::transmute(canvas.pixels) };
        let img = image::ImageBuffer::from_fn(w, h, Box::new(|&: x: u32, y: u32| buffer[(y * w + x) as usize]));

        result_ok = image::ImageRgba8(img).save(file, image::PNG).is_ok();
    } else {
        result_ok = pdf::render(&layout_root, initial_containing_block.content, &mut file).is_ok();
    }

    if result_ok {
        println!("Saved output as {}", filename)
    } else {
        println!("Error saving output as {}", filename)
    }

    // Debug output:
    // println!("{}", layout_root.dimensions);
    // println!("{}", display_list);
}
<commit_msg>Use new std::env::args<commit_after>#![feature(core, std_misc, collections, env, path, io, os)]

extern crate getopts;
extern crate image;

use getopts::Options;
use std::default::Default;
use std::old_io::fs::File;
use std::env::args;

mod css;
mod dom;
mod html;
mod layout;
mod style;
mod painting;
mod pdf;

fn main() {
    // Parse command-line options:
    let mut opts = Options::new();
    opts.optopt("h", "html", "HTML document", "FILENAME");
    opts.optopt("c", "css", "CSS stylesheet", "FILENAME");
    opts.optopt("o", "output", "Output file", "FILENAME");
    opts.optopt("f", "format", "Output file format", "png | pdf");

    let params: Vec<String> = args().skip(1).filter_map(|s| s.into_string().ok()).collect();
    let matches = match opts.parse(&*params) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };

    let png = match matches.opt_str("f") {
        None => true,
        Some(format) => match &*format {
            "png" => true,
            "pdf" => false,
            _ => panic!("Unknow output format: {}", format),
        }
    };

    // Read input files:
    let read_source = |&: arg_filename: Option<String>, default_filename: &str| {
        let path = match arg_filename {
            Some(ref filename) => &**filename,
            None => default_filename,
        };
        File::open(&Path::new(path)).read_to_string().unwrap()
    };
    let html = read_source(matches.opt_str("h"), "examples/test.html");
    let css  = read_source(matches.opt_str("c"), "examples/test.css");

    // Since we don't have an actual window, hard-code the "viewport" size.
    let initial_containing_block = layout::Dimensions {
        content: layout::Rect { x: 0.0, y: 0.0, width: 800.0, height: 600.0 },
        padding: Default::default(),
        border: Default::default(),
        margin: Default::default(),
    };

    // Parsing and rendering:
    let root_node = html::parse(html);
    let stylesheet = css::parse(css);
    let style_root = style::style_tree(&root_node, &stylesheet);
    let layout_root = layout::layout_tree(&style_root, initial_containing_block);

    // Create the output file:
    let default_filename = if png { "output.png" } else { "output.pdf" };
    let filename = matches.opt_str("o").unwrap_or(default_filename.to_string());
    let mut file = File::create(&Path::new(&*filename)).unwrap();

    let result_ok;
    if png {
        let canvas = painting::paint(&layout_root, initial_containing_block.content);

        // Save an image:
        let (w, h) = (canvas.width as u32, canvas.height as u32);
        let buffer: Vec<image::Rgba<u8>> = unsafe { std::mem::transmute(canvas.pixels) };
        let img = image::ImageBuffer::from_fn(w, h, Box::new(|&: x: u32, y: u32| buffer[(y * w + x) as usize]));

        result_ok = image::ImageRgba8(img).save(file, image::PNG).is_ok();
    } else {
        result_ok = pdf::render(&layout_root, initial_containing_block.content, &mut file).is_ok();
    }

    if result_ok {
        println!("Saved output as {}", filename)
    } else {
        println!("Error saving output as {}", filename)
    }

    // Debug output:
    // println!("{}", layout_root.dimensions);
    // println!("{}", display_list);
}
<|endoftext|>


<commit_before>// TODO: (Optional) Add theme system
// TODO: (Optional) Add globals with theme system
// TODO: (Optional) Copy empty directories
extern crate rustc_serialize;
extern crate handlebars;
extern crate walkdir;
extern crate sqlite;
extern crate toml;

mod stylish_templater;
mod templates;
mod utilities;
mod sqldbs;

use std::env::args;

fn main() {
    let args: Vec<_> = args().collect();
    if let Some(db_path) = args.get(2) {
        if args.get(1) == Some(&String::from("--templatedb")) {
            stylish_templater::template_db(db_path);
        }
    } else {
        if args.len() == 1 || args[1] == "--templates" {
            templates::load();
        }
        if args.len() == 1 || args[1] == "--sqldbs" {
            sqldbs::load();
        }
    }
}
<commit_msg>Moved temporary TODO messages to an actual todo list.<commit_after>extern crate rustc_serialize;
extern crate handlebars;
extern crate walkdir;
extern crate sqlite;
extern crate toml;

mod stylish_templater;
mod templates;
mod utilities;
mod sqldbs;

use std::env::args;

fn main() {
    let args: Vec<_> = args().collect();
    if let Some(db_path) = args.get(2) {
        if args.get(1) == Some(&String::from("--templatedb")) {
            stylish_templater::template_db(db_path);
        }
    } else {
        if args.len() == 1 || args[1] == "--templates" {
            templates::load();
        }
        if args.len() == 1 || args[1] == "--sqldbs" {
            sqldbs::load();
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate getopts;
extern crate gist;

use getopts::Options;
use rustc_serialize::json;

use std::env;
use std::process;
use std::io::{self, Write};

use gist::gist::Gist;
use gist::gist::gist_file::GistFile;

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

const DEFAULT_GIST_NAME: &'static str = "Untitled";
const E_HELP: i32 = 1;
const E_FATAL: i32 = 2;

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String,
}

fn print_usage(program: &str, opts: Options) {
    let brief = opts.short_usage(program);
    print!("{}", opts.usage(&brief));
    process::exit(E_HELP);
}

fn print_version(program: &str) {
    println!("{} {}", program, VERSION);
    process::exit(E_HELP);
}

fn fatal(msg: &str) {
    io::stderr().write(msg.as_bytes()).ok();
    process::exit(E_FATAL);
}

fn parse_args(args: Vec<String>) -> getopts::Matches {
    let mut opts = Options::new();
    opts.optopt("f", "file", "set file name", "NAME");
    opts.optflag("p", "public", "make public");
    opts.optflag("a", "anonymous", "make anonymous");
    opts.optflag("h", "help", "print this");
    opts.optflag("v", "version", "show version");

    let params = opts.parse(&args[1..]).ok().expect("Unknown flag.");
    if params.opt_present("h") {
        print_usage(&args[0].clone(), opts);
    }
    if params.opt_present("v") {
        print_version(&args[0].clone());
    }

    params
}

fn main() {
    let params = parse_args(env::args().collect());
    let is_public = params.opt_present("p");
    let is_anonymous = params.opt_present("a");
    let filename = match params.opt_str("f") {
        Some(name) => name,
        None => DEFAULT_GIST_NAME.to_string(),
    };
    let mut gist = Gist::new(is_public, is_anonymous);

    // Read from stdin, unless we receive a bunch of filenames.
    if params.free.is_empty() {
        let mut g = GistFile::new(filename);
        if g.read_stdin().is_ok() {
            gist.add_file(g);
        }
    } else {
        for file_param in params.free {
            let mut g = GistFile::new(file_param);
            match g.read_file() {
                Ok(_) => gist.add_file(g),
                Err(e) => fatal(&e.to_string()),
            }
        }
    }

    if !gist.is_empty() {
        match gist.create() {
            Ok(r) => {
                let gist: GistResponse = json::decode(&r).unwrap();
                println!("{}", gist.html_url);
            }
            Err(e) => fatal(&e.to_string()),
        }
    }
}
<commit_msg>Add -d flag to set optional description<commit_after>extern crate rustc_serialize;
extern crate getopts;
extern crate gist;

use getopts::Options;
use rustc_serialize::json;

use std::env;
use std::process;
use std::io::{self, Write};

use gist::gist::Gist;
use gist::gist::gist_file::GistFile;

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

const DEFAULT_GIST_NAME: &'static str = "Untitled";
const E_HELP: i32 = 1;
const E_FATAL: i32 = 2;

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String,
}

fn print_usage(program: &str, opts: Options) {
    let brief = opts.short_usage(program);
    print!("{}", opts.usage(&brief));
    process::exit(E_HELP);
}

fn print_version(program: &str) {
    println!("{} {}", program, VERSION);
    process::exit(E_HELP);
}

fn fatal(msg: &str) {
    io::stderr().write(msg.as_bytes()).ok();
    process::exit(E_FATAL);
}

fn parse_args(args: Vec<String>) -> getopts::Matches {
    let mut opts = Options::new();
    opts.optopt("f", "file", "set file name", "NAME");
    opts.optopt("d", "desc", "set description", "DESC");
    opts.optflag("p", "public", "make public");
    opts.optflag("a", "anonymous", "make anonymous");
    opts.optflag("h", "help", "print this");
    opts.optflag("v", "version", "show version");

    let params = opts.parse(&args[1..]).ok().expect("Unknown flag.");
    if params.opt_present("h") {
        print_usage(&args[0].clone(), opts);
    }
    if params.opt_present("v") {
        print_version(&args[0].clone());
    }

    params
}

fn main() {
    let params = parse_args(env::args().collect());
    let is_public = params.opt_present("p");
    let is_anonymous = params.opt_present("a");
    let desc = params.opt_str("d");
    let filename = match params.opt_str("f") {
        Some(name) => name,
        None => DEFAULT_GIST_NAME.to_string(),
    };
    let mut gist = Gist::new(is_public, is_anonymous, desc);

    // Read from stdin, unless we receive a bunch of filenames.
    if params.free.is_empty() {
        let mut g = GistFile::new(filename);
        if g.read_stdin().is_ok() {
            gist.add_file(g);
        }
    } else {
        for file_param in params.free {
            let mut g = GistFile::new(file_param);
            match g.read_file() {
                Ok(_) => gist.add_file(g),
                Err(e) => fatal(&e.to_string()),
            }
        }
    }

    if !gist.is_empty() {
        match gist.create() {
            Ok(r) => {
                let gist: GistResponse = json::decode(&r).unwrap();
                println!("{}", gist.html_url);
            }
            Err(e) => fatal(&e.to_string()),
        }
    }
}
<|endoftext|>


<commit_before>use ra_parser::{TokenSource};
use ra_syntax::{classify_literal, SmolStr, SyntaxKind, SyntaxKind::*};
use std::cell::{RefCell};

// A Sequece of Token,
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) enum TokenSeq<'a> {
    Subtree(&'a tt::Subtree),
    Seq(&'a [tt::TokenTree]),
}

impl<'a> From<&'a tt::Subtree> for TokenSeq<'a> {
    fn from(s: &'a tt::Subtree) -> TokenSeq<'a> {
        TokenSeq::Subtree(s)
    }
}

impl<'a> From<&'a [tt::TokenTree]> for TokenSeq<'a> {
    fn from(s: &'a [tt::TokenTree]) -> TokenSeq<'a> {
        TokenSeq::Seq(s)
    }
}

#[derive(Debug)]
enum DelimToken<'a> {
    Delim(&'a tt::Delimiter, bool),
    Token(&'a tt::TokenTree),
    End,
}

impl<'a> TokenSeq<'a> {
    fn get(&self, pos: usize) -> DelimToken<'a> {
        match self {
            TokenSeq::Subtree(subtree) => {
                let len = subtree.token_trees.len() + 2;
                match pos {
                    p if p >= len => DelimToken::End,
                    p if p == len - 1 => DelimToken::Delim(&subtree.delimiter, true),
                    0 => DelimToken::Delim(&subtree.delimiter, false),
                    p => DelimToken::Token(&subtree.token_trees[p - 1]),
                }
            }
            TokenSeq::Seq(tokens) => {
                tokens.get(pos).map(DelimToken::Token).unwrap_or(DelimToken::End)
            }
        }
    }

    fn len(&self) -> usize {
        match self {
            TokenSeq::Subtree(subtree) => subtree.token_trees.len() + 2,
            TokenSeq::Seq(tokens) => tokens.len(),
        }
    }

    fn child_slice(&self, pos: usize) -> &[tt::TokenTree] {
        match self {
            TokenSeq::Subtree(subtree) => &subtree.token_trees[pos - 1..],
            TokenSeq::Seq(tokens) => &tokens[pos..],
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
struct TtToken {
    pub kind: SyntaxKind,
    pub is_joint_to_next: bool,
    pub text: SmolStr,
    pub n_tokens: usize,
}

#[derive(Debug, Clone, Eq, PartialEq)]
enum WalkCursor {
    Token(usize, TtToken),
    Eof,
}

#[derive(Debug)]
struct SubTreeWalker<'a> {
    pos: usize,
    stack: Vec<(TokenSeq<'a>, usize)>,
    cursor: WalkCursor,
    last_steps: Vec<usize>,
    ts: TokenSeq<'a>,
}

impl<'a> SubTreeWalker<'a> {
    fn new(ts: TokenSeq<'a>) -> SubTreeWalker {
        let mut res = SubTreeWalker {
            pos: 0,
            stack: vec![],
            cursor: WalkCursor::Eof,
            last_steps: vec![],
            ts,
        };

        res.reset();
        res
    }

    fn is_eof(&self) -> bool {
        self.cursor == WalkCursor::Eof
    }

    fn reset(&mut self) {
        self.pos = 0;
        self.stack = vec![];
        self.last_steps = vec![];

        self.cursor = match self.ts.get(0) {
            DelimToken::Token(token) => match token {
                tt::TokenTree::Subtree(subtree) => {
                    let ts = TokenSeq::from(subtree);
                    self.stack.push((ts, 0));
                    WalkCursor::Token(0, convert_delim(subtree.delimiter, false))
                }
                tt::TokenTree::Leaf(leaf) => {
                    let next_tokens = self.ts.child_slice(0);
                    WalkCursor::Token(0, convert_leaf(&next_tokens, leaf))
                }
            },
            DelimToken::Delim(delim, is_end) => {
                assert!(!is_end);
                WalkCursor::Token(0, convert_delim(*delim, false))
            }
            DelimToken::End => WalkCursor::Eof,
        }
    }

    fn current(&self) -> Option<&TtToken> {
        match &self.cursor {
            WalkCursor::Token(_, t) => Some(t),
            WalkCursor::Eof => None,
        }
    }

    fn top(&self) -> &TokenSeq {
        self.stack.last().map(|(t, _)| t).unwrap_or(&self.ts)
    }

    /// Move cursor backward by 1 step
    fn backward(&mut self) {
        if self.last_steps.is_empty() {
            return;
        }

        self.pos -= 1;
        let last_step = self.last_steps.pop().unwrap();

        self.cursor = match self.cursor {
            WalkCursor::Token(idx, _) => self.walk_token(idx, last_step, true),
            WalkCursor::Eof => {
                let len = self.top().len();
                self.walk_token(len, last_step, true)
            }
        }
    }

    /// Move cursor forward by 1 step
    fn forward(&mut self) {
        if self.is_eof() {
            return;
        }
        self.pos += 1;

        let step = self.current().map(|x| x.n_tokens).unwrap_or(1);
        self.last_steps.push(step);

        if let WalkCursor::Token(u, _) = self.cursor {
            self.cursor = self.walk_token(u, step, false)
        }
    }

    /// Traversal child token
    fn walk_token(&mut self, pos: usize, offset: usize, backward: bool) -> WalkCursor {
        let top = self.stack.last().map(|(t, _)| t).unwrap_or(&self.ts);

        if backward && pos < offset {
            let (_, last_idx) = self.stack.pop().unwrap();
            return self.walk_token(last_idx, offset, backward);
        }

        let pos = if backward { pos - offset } else { pos + offset };

        match top.get(pos) {
            DelimToken::Token(token) => match token {
                tt::TokenTree::Subtree(subtree) => {
                    let ts = TokenSeq::from(subtree);
                    let new_idx = if backward { ts.len() - 1 } else { 0 };
                    self.stack.push((ts, pos));
                    WalkCursor::Token(new_idx, convert_delim(subtree.delimiter, backward))
                }
                tt::TokenTree::Leaf(leaf) => {
                    let next_tokens = top.child_slice(pos);
                    WalkCursor::Token(pos, convert_leaf(&next_tokens, leaf))
                }
            },
            DelimToken::Delim(delim, is_end) => {
                WalkCursor::Token(pos, convert_delim(*delim, is_end))
            }
            DelimToken::End => {
                // it is the top level
                if let Some((_, last_idx)) = self.stack.pop() {
                    assert!(!backward);
                    self.walk_token(last_idx, offset, backward)
                } else {
                    WalkCursor::Eof
                }
            }
        }
    }
}

pub(crate) trait Querier {
    fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr, bool);
}

// A wrapper class for ref cell
#[derive(Debug)]
pub(crate) struct WalkerOwner<'a> {
    walker: RefCell<SubTreeWalker<'a>>,
    cached: RefCell<Vec<Option<TtToken>>>,
}

impl<'a> WalkerOwner<'a> {
    fn new<I: Into<TokenSeq<'a>>>(ts: I) -> Self {
        WalkerOwner {
            walker: RefCell::new(SubTreeWalker::new(ts.into())),
            cached: RefCell::new(Vec::with_capacity(10)),
        }
    }

    fn get<'b>(&self, pos: usize) -> Option<TtToken> {
        let mut cached = self.cached.borrow_mut();
        if pos < cached.len() {
            return cached[pos].clone();
        }

        while pos >= cached.len() {
            let len = cached.len();
            cached.push({
                self.set_pos(len);
                let walker = self.walker.borrow();
                walker.current().cloned()
            });
        }

        return cached[pos].clone();
    }

    fn set_pos(&self, pos: usize) {
        let mut walker = self.walker.borrow_mut();
        while pos > walker.pos && !walker.is_eof() {
            walker.forward();
        }
        while pos < walker.pos {
            walker.backward();
        }
    }

    fn collect_token_trees(&mut self, n: usize) -> Vec<&tt::TokenTree> {
        let mut res = vec![];
        let mut walker = self.walker.borrow_mut();
        walker.reset();

        while walker.pos < n {
            if let WalkCursor::Token(u, tt) = &walker.cursor {
                // We only collect the topmost child
                if walker.stack.len() == 0 {
                    for i in 0..tt.n_tokens {
                        if let DelimToken::Token(token) = walker.ts.get(u + i) {
                            res.push(token);
                        }
                    }
                } else if walker.stack.len() == 1 {
                    if let DelimToken::Delim(_, is_end) = walker.top().get(*u) {
                        if !is_end {
                            let (_, last_idx) = &walker.stack[0];
                            if let DelimToken::Token(token) = walker.ts.get(*last_idx) {
                                res.push(token);
                            }
                        }
                    }
                }
            }

            walker.forward();
        }

        res
    }
}

impl<'a> Querier for WalkerOwner<'a> {
    fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr, bool) {
        self.get(uidx)
            .map(|tkn| (tkn.kind, tkn.text, tkn.is_joint_to_next))
            .unwrap_or_else(|| (SyntaxKind::EOF, "".into(), false))
    }
}

pub(crate) struct SubtreeTokenSource<'a> {
    walker: WalkerOwner<'a>,
}

impl<'a> SubtreeTokenSource<'a> {
    pub fn new<I: Into<TokenSeq<'a>>>(ts: I) -> SubtreeTokenSource<'a> {
        SubtreeTokenSource { walker: WalkerOwner::new(ts) }
    }

    pub fn querier<'b>(&'a self) -> &'b WalkerOwner<'a>
    where
        'a: 'b,
    {
        &self.walker
    }

    pub(crate) fn bump_n(&mut self, parsed_tokens: usize) -> Vec<&tt::TokenTree> {
        let res = self.walker.collect_token_trees(parsed_tokens);
        res
    }
}

impl<'a> TokenSource for SubtreeTokenSource<'a> {
    fn token_kind(&self, pos: usize) -> SyntaxKind {
        if let Some(tok) = self.walker.get(pos) {
            tok.kind
        } else {
            SyntaxKind::EOF
        }
    }
    fn is_token_joint_to_next(&self, pos: usize) -> bool {
        match self.walker.get(pos) {
            Some(t) => t.is_joint_to_next,
            _ => false,
        }
    }
    fn is_keyword(&self, pos: usize, kw: &str) -> bool {
        match self.walker.get(pos) {
            Some(t) => t.text == *kw,
            _ => false,
        }
    }
}

pub(crate) struct TokenPeek<'a, I>
where
    I: Iterator<Item = &'a tt::TokenTree>,
{
    iter: itertools::MultiPeek<I>,
}

// helper function
fn to_punct(tt: &tt::TokenTree) -> Option<&tt::Punct> {
    if let tt::TokenTree::Leaf(tt::Leaf::Punct(pp)) = tt {
        return Some(pp);
    }
    None
}

impl<'a, I> TokenPeek<'a, I>
where
    I: Iterator<Item = &'a tt::TokenTree>,
{
    pub fn new(iter: I) -> Self {
        TokenPeek { iter: itertools::multipeek(iter) }
    }

    pub fn current_punct2(&mut self, p: &tt::Punct) -> Option<((char, char), bool)> {
        if p.spacing != tt::Spacing::Joint {
            return None;
        }

        self.iter.reset_peek();
        let p1 = to_punct(self.iter.peek()?)?;
        Some(((p.char, p1.char), p1.spacing == tt::Spacing::Joint))
    }

    pub fn current_punct3(&mut self, p: &tt::Punct) -> Option<((char, char, char), bool)> {
        self.current_punct2(p).and_then(|((p0, p1), last_joint)| {
            if !last_joint {
                None
            } else {
                let p2 = to_punct(*self.iter.peek()?)?;
                Some(((p0, p1, p2.char), p2.spacing == tt::Spacing::Joint))
            }
        })
    }
}

// FIXME: Remove this function
fn convert_multi_char_punct<'b, I>(
    p: &tt::Punct,
    iter: &mut TokenPeek<'b, I>,
) -> Option<(SyntaxKind, bool, &'static str, usize)>
where
    I: Iterator<Item = &'b tt::TokenTree>,
{
    if let Some((m, is_joint_to_next)) = iter.current_punct3(p) {
        if let Some((kind, text)) = match m {
            _ => None,
        } {
            return Some((kind, is_joint_to_next, text, 3));
        }
    }

    if let Some((m, is_joint_to_next)) = iter.current_punct2(p) {
        if let Some((kind, text)) = match m {
            _ => None,
        } {
            return Some((kind, is_joint_to_next, text, 2));
        }
    }

    None
}

fn convert_delim(d: tt::Delimiter, closing: bool) -> TtToken {
    let (kinds, texts) = match d {
        tt::Delimiter::Parenthesis => ([L_PAREN, R_PAREN], "()"),
        tt::Delimiter::Brace => ([L_CURLY, R_CURLY], "{}"),
        tt::Delimiter::Bracket => ([L_BRACK, R_BRACK], "[]"),
        tt::Delimiter::None => ([L_DOLLAR, R_DOLLAR], ""),
    };

    let idx = closing as usize;
    let kind = kinds[idx];
    let text = if texts.len() > 0 { &texts[idx..texts.len() - (1 - idx)] } else { "" };
    TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text), n_tokens: 1 }
}

fn convert_literal(l: &tt::Literal) -> TtToken {
    let kind =
        classify_literal(&l.text).map(|tkn| tkn.kind).unwrap_or_else(|| match l.text.as_ref() {
            "true" => SyntaxKind::TRUE_KW,
            "false" => SyntaxKind::FALSE_KW,
            _ => panic!("Fail to convert given literal {:#?}", &l),
        });

    TtToken { kind, is_joint_to_next: false, text: l.text.clone(), n_tokens: 1 }
}

fn convert_ident(ident: &tt::Ident) -> TtToken {
    let kind = if let Some('\'') = ident.text.chars().next() {
        LIFETIME
    } else {
        SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT)
    };

    TtToken { kind, is_joint_to_next: false, text: ident.text.clone(), n_tokens: 1 }
}

fn convert_punct(p: &tt::Punct, next_tokens: &[tt::TokenTree]) -> TtToken {
    let mut iter = next_tokens.iter();
    iter.next();
    let mut peek = TokenPeek::new(iter);

    if let Some((kind, is_joint_to_next, text, size)) = convert_multi_char_punct(p, &mut peek) {
        TtToken { kind, is_joint_to_next, text: text.into(), n_tokens: size }
    } else {
        let kind = match p.char {
            // lexer may produce combpund tokens for these ones
            '.' => DOT,
            ':' => COLON,
            '=' => EQ,
            '!' => EXCL,
            '-' => MINUS,
            c => SyntaxKind::from_char(c).unwrap(),
        };
        let text = {
            let mut buf = [0u8; 4];
            let s: &str = p.char.encode_utf8(&mut buf);
            SmolStr::new(s)
        };
        TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text, n_tokens: 1 }
    }
}

fn convert_leaf(tokens: &[tt::TokenTree], leaf: &tt::Leaf) -> TtToken {
    match leaf {
        tt::Leaf::Literal(l) => convert_literal(l),
        tt::Leaf::Ident(ident) => convert_ident(ident),
        tt::Leaf::Punct(punct) => convert_punct(punct, tokens),
    }
}
<commit_msg>Remove unused code in subtree_source<commit_after>use ra_parser::{TokenSource};
use ra_syntax::{classify_literal, SmolStr, SyntaxKind, SyntaxKind::*};
use std::cell::{RefCell};

// A Sequece of Token,
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) enum TokenSeq<'a> {
    Subtree(&'a tt::Subtree),
    Seq(&'a [tt::TokenTree]),
}

impl<'a> From<&'a tt::Subtree> for TokenSeq<'a> {
    fn from(s: &'a tt::Subtree) -> TokenSeq<'a> {
        TokenSeq::Subtree(s)
    }
}

impl<'a> From<&'a [tt::TokenTree]> for TokenSeq<'a> {
    fn from(s: &'a [tt::TokenTree]) -> TokenSeq<'a> {
        TokenSeq::Seq(s)
    }
}

#[derive(Debug)]
enum DelimToken<'a> {
    Delim(&'a tt::Delimiter, bool),
    Token(&'a tt::TokenTree),
    End,
}

impl<'a> TokenSeq<'a> {
    fn get(&self, pos: usize) -> DelimToken<'a> {
        match self {
            TokenSeq::Subtree(subtree) => {
                let len = subtree.token_trees.len() + 2;
                match pos {
                    p if p >= len => DelimToken::End,
                    p if p == len - 1 => DelimToken::Delim(&subtree.delimiter, true),
                    0 => DelimToken::Delim(&subtree.delimiter, false),
                    p => DelimToken::Token(&subtree.token_trees[p - 1]),
                }
            }
            TokenSeq::Seq(tokens) => {
                tokens.get(pos).map(DelimToken::Token).unwrap_or(DelimToken::End)
            }
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
struct TtToken {
    pub kind: SyntaxKind,
    pub is_joint_to_next: bool,
    pub text: SmolStr,
}

#[derive(Debug, Clone, Eq, PartialEq)]
enum WalkCursor {
    Token(usize, TtToken),
    Eof,
}

#[derive(Debug)]
struct SubTreeWalker<'a> {
    pos: usize,
    stack: Vec<(TokenSeq<'a>, usize)>,
    cursor: WalkCursor,
    ts: TokenSeq<'a>,
}

impl<'a> SubTreeWalker<'a> {
    fn new(ts: TokenSeq<'a>) -> SubTreeWalker {
        let mut res = SubTreeWalker { pos: 0, stack: vec![], cursor: WalkCursor::Eof, ts };

        res.reset();
        res
    }

    fn is_eof(&self) -> bool {
        self.cursor == WalkCursor::Eof
    }

    fn reset(&mut self) {
        self.pos = 0;
        self.stack = vec![];

        self.cursor = match self.ts.get(0) {
            DelimToken::Token(token) => match token {
                tt::TokenTree::Subtree(subtree) => {
                    let ts = TokenSeq::from(subtree);
                    self.stack.push((ts, 0));
                    WalkCursor::Token(0, convert_delim(subtree.delimiter, false))
                }
                tt::TokenTree::Leaf(leaf) => WalkCursor::Token(0, convert_leaf(leaf)),
            },
            DelimToken::Delim(delim, is_end) => {
                assert!(!is_end);
                WalkCursor::Token(0, convert_delim(*delim, false))
            }
            DelimToken::End => WalkCursor::Eof,
        }
    }

    fn current(&self) -> Option<&TtToken> {
        match &self.cursor {
            WalkCursor::Token(_, t) => Some(t),
            WalkCursor::Eof => None,
        }
    }

    fn top(&self) -> &TokenSeq {
        self.stack.last().map(|(t, _)| t).unwrap_or(&self.ts)
    }

    /// Move cursor forward by 1 step
    fn forward(&mut self) {
        if self.is_eof() {
            return;
        }
        self.pos += 1;

        if let WalkCursor::Token(u, _) = self.cursor {
            self.cursor = self.walk_token(u)
        }
    }

    /// Traversal child token
    fn walk_token(&mut self, pos: usize) -> WalkCursor {
        let top = self.stack.last().map(|(t, _)| t).unwrap_or(&self.ts);
        let pos = pos + 1;

        match top.get(pos) {
            DelimToken::Token(token) => match token {
                tt::TokenTree::Subtree(subtree) => {
                    let ts = TokenSeq::from(subtree);
                    self.stack.push((ts, pos));
                    WalkCursor::Token(0, convert_delim(subtree.delimiter, false))
                }
                tt::TokenTree::Leaf(leaf) => WalkCursor::Token(pos, convert_leaf(leaf)),
            },
            DelimToken::Delim(delim, is_end) => {
                WalkCursor::Token(pos, convert_delim(*delim, is_end))
            }
            DelimToken::End => {
                // it is the top level
                if let Some((_, last_idx)) = self.stack.pop() {
                    self.walk_token(last_idx)
                } else {
                    WalkCursor::Eof
                }
            }
        }
    }
}

pub(crate) trait Querier {
    fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr, bool);
}

// A wrapper class for ref cell
#[derive(Debug)]
pub(crate) struct WalkerOwner<'a> {
    walker: RefCell<SubTreeWalker<'a>>,
    cached: RefCell<Vec<Option<TtToken>>>,
}

impl<'a> WalkerOwner<'a> {
    fn new<I: Into<TokenSeq<'a>>>(ts: I) -> Self {
        WalkerOwner {
            walker: RefCell::new(SubTreeWalker::new(ts.into())),
            cached: RefCell::new(Vec::with_capacity(10)),
        }
    }

    fn get<'b>(&self, pos: usize) -> Option<TtToken> {
        let mut cached = self.cached.borrow_mut();
        if pos < cached.len() {
            return cached[pos].clone();
        }

        while pos >= cached.len() {
            self.set_pos(cached.len());
            let walker = self.walker.borrow();
            cached.push(walker.current().cloned());
        }

        return cached[pos].clone();
    }

    fn set_pos(&self, pos: usize) {
        let mut walker = self.walker.borrow_mut();
        assert!(walker.pos <= pos);

        while pos > walker.pos && !walker.is_eof() {
            walker.forward();
        }
    }

    fn collect_token_trees(&mut self, n: usize) -> Vec<&tt::TokenTree> {
        let mut res = vec![];
        let mut walker = self.walker.borrow_mut();
        walker.reset();

        while walker.pos < n {
            if let WalkCursor::Token(u, _) = &walker.cursor {
                // We only collect the topmost child
                if walker.stack.len() == 0 {
                    if let DelimToken::Token(token) = walker.ts.get(*u) {
                        res.push(token);
                    }
                }
                // Check whether the second level is a subtree
                // if so, collect its parent which is topmost child
                else if walker.stack.len() == 1 {
                    if let DelimToken::Delim(_, is_end) = walker.top().get(*u) {
                        if !is_end {
                            let (_, last_idx) = &walker.stack[0];
                            if let DelimToken::Token(token) = walker.ts.get(*last_idx) {
                                res.push(token);
                            }
                        }
                    }
                }
            }

            walker.forward();
        }

        res
    }
}

impl<'a> Querier for WalkerOwner<'a> {
    fn token(&self, uidx: usize) -> (SyntaxKind, SmolStr, bool) {
        self.get(uidx)
            .map(|tkn| (tkn.kind, tkn.text, tkn.is_joint_to_next))
            .unwrap_or_else(|| (SyntaxKind::EOF, "".into(), false))
    }
}

pub(crate) struct SubtreeTokenSource<'a> {
    walker: WalkerOwner<'a>,
}

impl<'a> SubtreeTokenSource<'a> {
    pub fn new<I: Into<TokenSeq<'a>>>(ts: I) -> SubtreeTokenSource<'a> {
        SubtreeTokenSource { walker: WalkerOwner::new(ts) }
    }

    pub fn querier<'b>(&'a self) -> &'b WalkerOwner<'a>
    where
        'a: 'b,
    {
        &self.walker
    }

    pub(crate) fn bump_n(&mut self, parsed_tokens: usize) -> Vec<&tt::TokenTree> {
        let res = self.walker.collect_token_trees(parsed_tokens);
        res
    }
}

impl<'a> TokenSource for SubtreeTokenSource<'a> {
    fn token_kind(&self, pos: usize) -> SyntaxKind {
        if let Some(tok) = self.walker.get(pos) {
            tok.kind
        } else {
            SyntaxKind::EOF
        }
    }
    fn is_token_joint_to_next(&self, pos: usize) -> bool {
        match self.walker.get(pos) {
            Some(t) => t.is_joint_to_next,
            _ => false,
        }
    }
    fn is_keyword(&self, pos: usize, kw: &str) -> bool {
        match self.walker.get(pos) {
            Some(t) => t.text == *kw,
            _ => false,
        }
    }
}

fn convert_delim(d: tt::Delimiter, closing: bool) -> TtToken {
    let (kinds, texts) = match d {
        tt::Delimiter::Parenthesis => ([L_PAREN, R_PAREN], "()"),
        tt::Delimiter::Brace => ([L_CURLY, R_CURLY], "{}"),
        tt::Delimiter::Bracket => ([L_BRACK, R_BRACK], "[]"),
        tt::Delimiter::None => ([L_DOLLAR, R_DOLLAR], ""),
    };

    let idx = closing as usize;
    let kind = kinds[idx];
    let text = if texts.len() > 0 { &texts[idx..texts.len() - (1 - idx)] } else { "" };
    TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text) }
}

fn convert_literal(l: &tt::Literal) -> TtToken {
    let kind =
        classify_literal(&l.text).map(|tkn| tkn.kind).unwrap_or_else(|| match l.text.as_ref() {
            "true" => SyntaxKind::TRUE_KW,
            "false" => SyntaxKind::FALSE_KW,
            _ => panic!("Fail to convert given literal {:#?}", &l),
        });

    TtToken { kind, is_joint_to_next: false, text: l.text.clone() }
}

fn convert_ident(ident: &tt::Ident) -> TtToken {
    let kind = if let Some('\'') = ident.text.chars().next() {
        LIFETIME
    } else {
        SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT)
    };

    TtToken { kind, is_joint_to_next: false, text: ident.text.clone() }
}

fn convert_punct(p: &tt::Punct) -> TtToken {
    let kind = match p.char {
        // lexer may produce combpund tokens for these ones
        '.' => DOT,
        ':' => COLON,
        '=' => EQ,
        '!' => EXCL,
        '-' => MINUS,
        c => SyntaxKind::from_char(c).unwrap(),
    };
    let text = {
        let mut buf = [0u8; 4];
        let s: &str = p.char.encode_utf8(&mut buf);
        SmolStr::new(s)
    };
    TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text }
}

fn convert_leaf(leaf: &tt::Leaf) -> TtToken {
    match leaf {
        tt::Leaf::Literal(l) => convert_literal(l),
        tt::Leaf::Ident(ident) => convert_ident(ident),
        tt::Leaf::Punct(punct) => convert_punct(punct),
    }
}
<|endoftext|>


<commit_before>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

#[macro_use]
mod error_macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        mod arch {
            pub enum Feature {
                Null
            }
        }
    }
}
pub use self::arch::Feature;

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(target_os = "freebsd")] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}
pub use self::os::check_for;
<commit_msg>Document how miri support works<commit_after>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

#[macro_use]
mod error_macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        mod arch {
            pub enum Feature {
                Null
            }
        }
    }
}
pub use self::arch::Feature;

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(target_os = "freebsd")] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}
pub use self::os::check_for;
<|endoftext|>