<commit_before>use std::sync::Arc;

use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::method::Method;
use hyper::uri::RequestUri;
use serde_json;
use serde::Serialize;

use super::config::Config;
use super::memdbstash::MemDbStash;
use super::{Result, ResultExt};

struct ServerContext {
    pub config: Config,
    pub stash: MemDbStash,
}

pub struct ApiServer {
    ctx: Arc<ServerContext>,
}

type Handler = fn(&ServerContext, Request, Response);

#[derive(Serialize)]
struct ApiError {
    #[serde(rename="type")]
    pub ty: String,
    pub message: String,
}

#[derive(Serialize)]
struct HealthCheckResult {
    is_healthy: bool,
    sync_lag: u32,
}

impl ApiServer {
    pub fn new(config: &Config) -> Result<ApiServer> {
        Ok(ApiServer {
            ctx: Arc::new(ServerContext {
                config: config.clone(),
                stash: MemDbStash::new(config)?,
            }),
        })
    }

    pub fn run(&self) -> Result<()> {
        let ctx = self.ctx.clone();
        Server::http(self.ctx.config.get_http_socket_addr()?)?
            .handle(move |mut req: Request, mut resp: Response|
        {
            let handler = match req.method {
                Method::Get => {
                    if let RequestUri::AbsolutePath(ref path) = req.uri {
                        match path.as_str() {
                            "/health" => healthcheck_handler,
                            _ => not_found_handler,
                        }
                    } else {
                        bad_request_handler
                    }
                }
                _ => {
                    method_not_allowed_handler
                }
            };
            handler(&*ctx.clone(), req, resp).unwrap();
        })?;
        Ok(())
    }
}

fn respond<T: Serialize>(mut resp: Response, obj: T, status: StatusCode) -> Result<()> {
    *resp.status_mut() = status;
    let mut body : Vec<u8> = vec![];
    serde_json::to_writer(&mut body, &obj)
        .chain_err(|| "Failed to serialize response for client")?;
    resp.send(&body[..]);
    Ok(())
}

fn healthcheck_handler(ctx: &ServerContext, _: Request, mut resp: Response)
    -> Result<()>
{
    // TODO: cache this
    let state = ctx.stash.get_sync_status()?;
    respond(resp, HealthCheckResult {
        is_healthy: state.is_healthy(),
        sync_lag: state.lag(),
    }, if state.is_healthy() {
        StatusCode::Ok
    } else {
        StatusCode::ServiceUnavailable
    })
}

fn not_found_handler(_: &ServerContext, _: Request, resp: Response)
    -> Result<()>
{
    respond(resp, ApiError {
        ty: "not_found".into(),
        message: "The requested resource was not found".into()
    }, StatusCode::NotFound)
}

fn bad_request_handler(_: &ServerContext, _: Request, mut resp: Response)
    -> Result<()>
{
    respond(resp, ApiError {
        ty: "bad_request".into(),
        message: "The request could not be handled".into()
    }, StatusCode::BadRequest)
}

fn method_not_allowed_handler(_: &ServerContext, _: Request, mut resp: Response)
    -> Result<()>
{
    respond(resp, ApiError {
        ty: "method_not_allowed".into(),
        message: "The server cannot handle this method".into()
    }, StatusCode::MethodNotAllowed)
}
<commit_msg>Fixed compiler warnings<commit_after>use std::sync::Arc;

use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::method::Method;
use hyper::uri::RequestUri;
use serde_json;
use serde::Serialize;

use super::config::Config;
use super::memdbstash::MemDbStash;
use super::{Result, ResultExt};

struct ServerContext {
    pub config: Config,
    pub stash: MemDbStash,
}

pub struct ApiServer {
    ctx: Arc<ServerContext>,
}

#[derive(Serialize)]
struct ApiError {
    #[serde(rename="type")]
    pub ty: String,
    pub message: String,
}

#[derive(Serialize)]
struct HealthCheckResult {
    is_healthy: bool,
    sync_lag: u32,
}

impl ApiServer {
    pub fn new(config: &Config) -> Result<ApiServer> {
        Ok(ApiServer {
            ctx: Arc::new(ServerContext {
                config: config.clone(),
                stash: MemDbStash::new(config)?,
            }),
        })
    }

    pub fn run(&self) -> Result<()> {
        let ctx = self.ctx.clone();
        Server::http(self.ctx.config.get_http_socket_addr()?)?
            .handle(move |req: Request, resp: Response|
        {
            let handler = match req.method {
                Method::Get => {
                    if let RequestUri::AbsolutePath(ref path) = req.uri {
                        match path.as_str() {
                            "/health" => healthcheck_handler,
                            _ => not_found_handler,
                        }
                    } else {
                        bad_request_handler
                    }
                }
                _ => {
                    method_not_allowed_handler
                }
            };
            handler(&*ctx.clone(), req, resp).unwrap();
        })?;
        Ok(())
    }
}

fn respond<T: Serialize>(mut resp: Response, obj: T, status: StatusCode) -> Result<()> {
    *resp.status_mut() = status;
    let mut body : Vec<u8> = vec![];
    serde_json::to_writer(&mut body, &obj)
        .chain_err(|| "Failed to serialize response for client")?;
    resp.send(&body[..])?;
    Ok(())
}

fn healthcheck_handler(ctx: &ServerContext, _: Request, resp: Response)
    -> Result<()>
{
    // TODO: cache this
    let state = ctx.stash.get_sync_status()?;
    respond(resp, HealthCheckResult {
        is_healthy: state.is_healthy(),
        sync_lag: state.lag(),
    }, if state.is_healthy() {
        StatusCode::Ok
    } else {
        StatusCode::ServiceUnavailable
    })
}

fn not_found_handler(_: &ServerContext, _: Request, resp: Response)
    -> Result<()>
{
    respond(resp, ApiError {
        ty: "not_found".into(),
        message: "The requested resource was not found".into()
    }, StatusCode::NotFound)
}

fn bad_request_handler(_: &ServerContext, _: Request, resp: Response)
    -> Result<()>
{
    respond(resp, ApiError {
        ty: "bad_request".into(),
        message: "The request could not be handled".into()
    }, StatusCode::BadRequest)
}

fn method_not_allowed_handler(_: &ServerContext, _: Request, resp: Response)
    -> Result<()>
{
    respond(resp, ApiError {
        ty: "method_not_allowed".into(),
        message: "The server cannot handle this method".into()
    }, StatusCode::MethodNotAllowed)
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use analysis;
use analysis::symbols;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use self::format::reformat_doc;
use stripper_lib::Type as SType;
use stripper_lib::{TypeStruct, write_file_name, write_item_doc};

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> TypeStruct;
    fn doc(&self) -> Option<&str>;
    fn doc_deprecated(&self) -> Option<&str>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<&str> {
                self.doc.as_ref().map(|s| &s[..])
            }

            fn doc_deprecated(&self) -> Option<&str> {
                self.doc_deprecated.as_ref().map(|s| &s[..])
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Type);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("docs.md");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(write_file_name(w, None));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        if let Some(info) = info {
            try!(create_object_doc(w, env, &info));
        }
    }

    let symbols = env.symbols.borrow();
    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, &symbols));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, symbols: &symbols::Info) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, symbols),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, symbols),
        LType::Function(ref f) => create_fn_doc(w, &f, None, symbols),
        _ => Ok(()),
    }
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &format!("{}Ext", info.name));
    let has_trait = info.has_children;
    let impl_self = if has_trait { Some(info.type_id) } else { None };
    let class: &ToStripperType;
    let functions: &[Function];
    let implements: Vec<TypeId>;

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            class = cl;
            functions = &cl.functions;
            implements = impl_self.iter()
                .chain(cl.parents.iter())
                .chain(cl.implements.iter())
                .map(|&tid| tid)
                .collect();
        }
        Type::Interface(ref iface) => {
            class = iface;
            functions = &iface.functions;
            implements = impl_self.iter()
                .chain(iface.prereq_parents.iter())
                .map(|&tid| tid)
                .collect();
        }
        _ => unreachable!(),
    }

    if class.doc().is_some() || class.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = class.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }

            try!(writeln!(w, "\n# Implements\n"));
            let implements = implements.iter()
                .filter(|&tid| !env.type_status(&tid.full_name(&env.library)).ignored())
                .map(|&tid| format!("[`{name}Ext`](trait.{name}Ext.html)",
                                    name = env.library.type_(tid).get_name()))
                .collect::<Vec<_>>();
            try!(writeln!(w, "{}", &implements.join(", ")));

            if let Some(doc) = class.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }
            Ok(())
        }));
    }

    if has_trait {
        try!(write_item_doc(w, &ty_ext, |w| {
            writeln!(w, "Trait containing all `{}` methods.", ty.name)
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), &symbols));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration, symbols: &symbols::Info) -> Result<()> {
    let ty = enum_.convert();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(doc) = enum_.doc() {
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        if let Some(doc) = enum_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        Ok(())
    }));

    for member in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member.convert();

        if member.doc().is_some() || member.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(write_item_doc(w, &sub_ty, |w| {
                if let Some(doc) = member.doc() {
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                if let Some(doc) = member.doc_deprecated() {
                    try!(writeln!(w, "\n# Deprecated\n"));
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                Ok(())
            }));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names(doc: &str, self_name: &Option<String>) -> String {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into()
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 symbols: &symbols::Info) -> Result<()> {
    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;

    let self_name: Option<String> = fn_.parameters.iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    write_item_doc(w, &sub_ty, |w| {
        if let Some(doc) = fn_.doc() {
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };
        if let Some(doc) = fn_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };

        if fn_.parameters.iter().any(|x| {
               x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
           }) {
            try!(writeln!(w, "\n# Parameters\n"));
        }
        for parameter in fn_.parameters.iter() {
            if parameter.instance_parameter || parameter.name.is_empty() {
                continue
            }
            if let Some(doc) = parameter.doc() {
                try!(writeln!(w, "## `{}`", nameutil::mangle_keywords(&parameter.name[..])));
                try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
            }
        }

        if let Some(doc) = fn_.ret.doc() {
            try!(writeln!(w, "\n# Returns\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        }
        Ok(())
    })
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T, symbols: &symbols::Info) -> Result<()> {
    let sub_ty = ty.convert();

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(write_item_doc(w, &sub_ty, |w| {
            if let Some(doc) = ty.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            if let Some(doc) = ty.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }
    Ok(())
}
<commit_msg>Document structs in doc generator<commit_after>use std::io::{Result, Write};

use analysis;
use analysis::symbols;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use nameutil;
use regex::{Captures, Regex};
use self::format::reformat_doc;
use stripper_lib::Type as SType;
use stripper_lib::{TypeStruct, write_file_name, write_item_doc};
use traits::*;

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> TypeStruct;
    fn doc(&self) -> Option<&str>;
    fn doc_deprecated(&self) -> Option<&str>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<&str> {
                self.doc.as_ref().map(|s| &s[..])
            }

            fn doc_deprecated(&self) -> Option<&str> {
                self.doc_deprecated.as_ref().map(|s| &s[..])
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Struct);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("docs.md");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(write_file_name(w, None));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if obj.status.ignored() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        if let Some(info) = info {
            if info.type_id.ns_id == MAIN {
                try!(create_object_doc(w, env, &info));
            }
        }

        if let Some(info) = analysis::record::new(env, obj) {
            if info.type_id.ns_id == MAIN {
                println!("documenting struct {}", info.name);
                let record = env.library.type_(info.type_id).to_ref_as::<Record>();
                let symbols = env.symbols.borrow();
                try!(create_record_doc(w, record, &symbols));
            }
        }
    }

    let symbols = env.symbols.borrow();
    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, &symbols));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, symbols: &symbols::Info) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, symbols),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, symbols),
        LType::Function(ref f) => create_fn_doc(w, &f, None, symbols),
        _ => Ok(()),
    }
}

fn create_object_doc(w: &mut Write, env: &Env, info: &analysis::object::Info) -> Result<()> {
    let symbols = env.symbols.borrow();
    let ty = TypeStruct::new(SType::Struct, &info.name);
    let ty_ext = TypeStruct::new(SType::Trait, &format!("{}Ext", info.name));
    let has_trait = info.has_children;
    let impl_self = if has_trait { Some(info.type_id) } else { None };
    let class: &ToStripperType;
    let functions: &[Function];
    let implements: Vec<TypeId>;

    match *env.library.type_(info.type_id) {
        Type::Class(ref cl) => {
            class = cl;
            functions = &cl.functions;
            implements = impl_self.iter()
                .chain(cl.parents.iter())
                .chain(cl.implements.iter())
                .map(|&tid| tid)
                .collect();
        }
        Type::Interface(ref iface) => {
            class = iface;
            functions = &iface.functions;
            implements = impl_self.iter()
                .chain(iface.prereq_parents.iter())
                .map(|&tid| tid)
                .collect();
        }
        _ => unreachable!(),
    }

    if class.doc().is_some() || class.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = class.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }

            try!(writeln!(w, "\n# Implements\n"));
            let implements = implements.iter()
                .filter(|&tid| !env.type_status(&tid.full_name(&env.library)).ignored())
                .map(|&tid| format!("[`{name}Ext`](trait.{name}Ext.html)",
                                    name = env.library.type_(tid).get_name()))
                .collect::<Vec<_>>();
            try!(writeln!(w, "{}", &implements.join(", ")));

            if let Some(doc) = class.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, &symbols)));
            }
            Ok(())
        }));
    }

    if has_trait {
        try!(write_item_doc(w, &ty_ext, |w| {
            writeln!(w, "Trait containing all `{}` methods.", ty.name)
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in functions {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), &symbols));
    }
    Ok(())
}

fn create_record_doc(w: &mut Write, record: &Record, symbols: &symbols::Info) -> Result<()> {
    let ty = record.convert();

    if record.doc().is_some() || record.doc_deprecated().is_some() {
        try!(write_item_doc(w, &ty, |w| {
            if let Some(doc) = record.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }

            if let Some(doc) = record.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };
    for function in &record.functions {
        try!(create_fn_doc(w, &function, Some(Box::new(ty.clone())), &symbols));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration, symbols: &symbols::Info) -> Result<()> {
    let ty = enum_.convert();

    try!(write_item_doc(w, &ty, |w| {
        if let Some(doc) = enum_.doc() {
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        if let Some(doc) = enum_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
        }
        Ok(())
    }));

    for member in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member.convert();

        if member.doc().is_some() || member.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(write_item_doc(w, &sub_ty, |w| {
                if let Some(doc) = member.doc() {
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                if let Some(doc) = member.doc_deprecated() {
                    try!(writeln!(w, "\n# Deprecated\n"));
                    try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
                }
                Ok(())
            }));
        }
    }
    Ok(())
}

lazy_static! {
    static ref PARAM_NAME: Regex = Regex::new(r"@(\w+)\b").unwrap();
}

fn fix_param_names(doc: &str, self_name: &Option<String>) -> String {
    PARAM_NAME.replace_all(doc, |caps: &Captures| {
        if let Some(ref self_name) = *self_name {
            if &caps[1] == self_name {
                return "@self".into()
            }
        }
        format!("@{}", nameutil::mangle_keywords(&caps[1]))
    })
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 symbols: &symbols::Info) -> Result<()> {
    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;

    let self_name: Option<String> = fn_.parameters.iter()
        .find(|p| p.instance_parameter)
        .map(|p| p.name.clone());

    write_item_doc(w, &sub_ty, |w| {
        if let Some(doc) = fn_.doc() {
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };
        if let Some(doc) = fn_.doc_deprecated() {
            try!(writeln!(w, "\n# Deprecated\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        };

        if fn_.parameters.iter().any(|x| {
               x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
           }) {
            try!(writeln!(w, "\n# Parameters\n"));
        }
        for parameter in fn_.parameters.iter() {
            if parameter.instance_parameter || parameter.name.is_empty() {
                continue
            }
            if let Some(doc) = parameter.doc() {
                try!(writeln!(w, "## `{}`", nameutil::mangle_keywords(&parameter.name[..])));
                try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
            }
        }

        if let Some(doc) = fn_.ret.doc() {
            try!(writeln!(w, "\n# Returns\n"));
            try!(writeln!(w, "{}", reformat_doc(&fix_param_names(doc, &self_name), symbols)));
        }
        Ok(())
    })
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T, symbols: &symbols::Info) -> Result<()> {
    let sub_ty = ty.convert();

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(write_item_doc(w, &sub_ty, |w| {
            if let Some(doc) = ty.doc() {
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            if let Some(doc) = ty.doc_deprecated() {
                try!(writeln!(w, "\n# Deprecated\n"));
                try!(writeln!(w, "{}", reformat_doc(doc, symbols)));
            }
            Ok(())
        }));
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::path::{Path, PathBuf};

use analysis;
use env::Env;
use file_saver::*;
use nameutil::*;
use super::general;

pub fn generate(env: &Env) {
    let root_path = PathBuf::from(&env.config.target_path).join("src").join("auto");

    let mut mod_rs: Vec<String> = Vec::new();
    let mut traits: Vec<String> = Vec::new();

    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        println!("Analyzing {:?}", obj.name);
        let class_analysis = analysis::widget::new(env, obj);
        if class_analysis.has_ignored_parents {
            println!("Skipping {:?}, it has ignored parents", obj.name);
            continue;
        }

        let path = root_path.join(file_name(&class_analysis.full_name));
        println!("Generating file {:?}", path);

        save_to_file(path, env.config.make_backup,
            &mut |w| super::widget::generate(w, env, &class_analysis));

        let mod_name = module_name(split_namespace_name(&class_analysis.full_name).1);
        super::widget::generate_reexports(env, &class_analysis, &mod_name, &mut mod_rs,
            &mut traits);
    }

    generate_mod_rs(env, &root_path, mod_rs, traits);
}

fn generate_mod_rs(env: &Env, root_path: &Path, mod_rs: Vec<String>, traits: Vec<String>) {
    let path = root_path.join("mod.rs");
    save_to_file(path, env.config.make_backup, &mut |w| {
        try!(general::start_comments(w, &env.config));
        try!(general::write_vec(w, &mod_rs));
        try!(writeln!(w, ""));
        try!(writeln!(w, "pub mod traits {{"));
        try!(general::write_vec(w, &traits));
        writeln!(w, "}}")
    });
}
<commit_msg>Replace printlns with log macros<commit_after>use std::io::Write;
use std::path::{Path, PathBuf};

use analysis;
use env::Env;
use file_saver::*;
use nameutil::*;
use super::general;

pub fn generate(env: &Env) {
    let root_path = PathBuf::from(&env.config.target_path).join("src").join("auto");

    let mut mod_rs: Vec<String> = Vec::new();
    let mut traits: Vec<String> = Vec::new();

    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        info!("Analyzing {:?}", obj.name);
        let class_analysis = analysis::widget::new(env, obj);
        if class_analysis.has_ignored_parents {
            warn!("Skipping {:?}, it has ignored parents", obj.name);
            continue;
        }

        let path = root_path.join(file_name(&class_analysis.full_name));
        info!("Generating file {:?}", path);

        save_to_file(path, env.config.make_backup,
            &mut |w| super::widget::generate(w, env, &class_analysis));

        let mod_name = module_name(split_namespace_name(&class_analysis.full_name).1);
        super::widget::generate_reexports(env, &class_analysis, &mod_name, &mut mod_rs,
            &mut traits);
    }

    generate_mod_rs(env, &root_path, mod_rs, traits);
}

fn generate_mod_rs(env: &Env, root_path: &Path, mod_rs: Vec<String>, traits: Vec<String>) {
    let path = root_path.join("mod.rs");
    save_to_file(path, env.config.make_backup, &mut |w| {
        try!(general::start_comments(w, &env.config));
        try!(general::write_vec(w, &mod_rs));
        try!(writeln!(w, ""));
        try!(writeln!(w, "pub mod traits {{"));
        try!(general::write_vec(w, &traits));
        writeln!(w, "}}")
    });
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

mod board;

pub use self::board::Board;

pub struct Model {
    pub board: Board,
    pub last_move: Move,
    pub turn: Color,
    pub game_result: GameResult,
    pub selected_piece: Option<FieldCoord>,
    pub available_moves: Option<Vec<FieldCoord>>,
    pub exchanging: bool,
    undo_stack: Vec<(Board, Move, Color, GameResult)>,
    redo_stack: Vec<(Board, Move, Color, GameResult)>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Color::White,
            selected_piece: None,
            last_move: Move::None,
            available_moves: None,
            exchanging: false,
            game_result: GameResult::InProgress,
            undo_stack: vec![],
            redo_stack: vec![],
        }
    }
    pub fn switch_turns(&mut self) {
        self.turn = self.turn.switch();
    }
    pub fn can_undo(&self) -> bool {
        !self.undo_stack.is_empty()
    }
    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }
    pub fn commit_move(&mut self) {
        self.undo_stack
            .push((self.board, self.last_move, self.turn, self.game_result));
        self.redo_stack.clear();
    }
    pub fn undo_move(&mut self) {
        if let Some((board, last_move, turn, game_result)) = self.undo_stack.pop() {
            self.redo_stack
                .push((self.board, self.last_move, self.turn, self.game_result));

            self.board = board;
            self.last_move = last_move;
            self.turn = turn;
            self.game_result = game_result;

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn redo_move(&mut self) {
        if let Some((board, last_move, turn, game_result)) = self.redo_stack.pop() {
            self.undo_stack
                .push((self.board, self.last_move, self.turn, self.game_result));

            self.board = board;
            self.last_move = last_move;
            self.turn = turn;
            self.game_result = game_result;

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn clear_selection(&mut self) {
        self.selected_piece = None;
        self.available_moves = None;
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn switch(&self) -> Color {
        match *self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(Clone, Copy)]
pub enum Move {
    Exchange(FieldCoord),
    Move(FieldCoord, FieldCoord),
    None,
}

#[derive(Clone, Copy, PartialEq)]
pub enum GameResult {
    InProgress,
    Win(Color),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i32, y: i32) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<commit_msg>Use std::mem::replace for undo/redo<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::mem;

mod board;

pub use self::board::Board;

pub struct Model {
    pub board: Board,
    pub last_move: Move,
    pub turn: Color,
    pub game_result: GameResult,
    pub selected_piece: Option<FieldCoord>,
    pub available_moves: Option<Vec<FieldCoord>>,
    pub exchanging: bool,
    undo_stack: Vec<(Board, Move, Color, GameResult)>,
    redo_stack: Vec<(Board, Move, Color, GameResult)>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Color::White,
            selected_piece: None,
            last_move: Move::None,
            available_moves: None,
            exchanging: false,
            game_result: GameResult::InProgress,
            undo_stack: vec![],
            redo_stack: vec![],
        }
    }
    pub fn switch_turns(&mut self) {
        self.turn = self.turn.switch();
    }
    pub fn can_undo(&self) -> bool {
        !self.undo_stack.is_empty()
    }
    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }
    pub fn commit_move(&mut self) {
        self.undo_stack
            .push((self.board, self.last_move, self.turn, self.game_result));
        self.redo_stack.clear();
    }
    pub fn undo_move(&mut self) {
        if let Some((board, last_move, turn, game_result)) = self.undo_stack.pop() {
            self.redo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
                mem::replace(&mut self.turn, turn),
                mem::replace(&mut self.game_result, game_result),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn redo_move(&mut self) {
        if let Some((board, last_move, turn, game_result)) = self.redo_stack.pop() {
            self.undo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
                mem::replace(&mut self.turn, turn),
                mem::replace(&mut self.game_result, game_result),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn clear_selection(&mut self) {
        self.selected_piece = None;
        self.available_moves = None;
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn switch(&self) -> Color {
        match *self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(Clone, Copy)]
pub enum Move {
    Exchange(FieldCoord),
    Move(FieldCoord, FieldCoord),
    None,
}

#[derive(Clone, Copy, PartialEq)]
pub enum GameResult {
    InProgress,
    Win(Color),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i32, y: i32) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(install);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(rustc);
    $mac!(search);
    $mac!(test);
    $mac!(uninstall);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Auto merge of #2103 - takkanm:add_install_help, r=alexcrichton<commit_after>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(install);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(rustc);
    $mac!(search);
    $mac!(test);
    $mac!(uninstall);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>extern crate aoc;

fn main() {
    let input = aoc::read_file("input/day02");

    let mut total_paper = 0;
    let mut total_ribbon = 0;

    for line in input.lines() {
        let mut dimensions: Vec<i32> = line.split('x').map(|s| s.parse().unwrap()).collect();

        // Smallest side.
        dimensions.sort();
        total_paper += dimensions[0] * dimensions[1];

        // Surface area.
        total_paper += 2 * (dimensions[0] * dimensions[1] +
                            dimensions[0] * dimensions[2] +
                            dimensions[1] * dimensions[2]);

        // Wrapping ribbon.
        total_ribbon += 2 * (dimensions[0] + dimensions[1]);

        // Bow ribbon.
        total_ribbon += dimensions[0] * dimensions[1] * dimensions[2];
    }

    println!("The total amount of paper needed is {} square feet.", total_paper);
    println!("The total amount of ribbon needed is {} square feet.", total_ribbon);
}
<commit_msg>Simplify day 2 code.<commit_after>extern crate aoc;

fn main() {
    let input = aoc::read_file("input/day02");

    let mut total_paper = 0;
    let mut total_ribbon = 0;

    for line in input.lines() {
        let mut dimensions: Vec<i32> = line.split('x').map(|s| s.parse().unwrap()).collect();
        dimensions.sort();
        let d1 = dimensions[0];
        let d2 = dimensions[1];
        let d3 = dimensions[2];

        // Smallest side.
        total_paper += d1 * d2;

        // Surface area.
        total_paper += 2 * (d1*d2 + d1*d3 + d2*d3);

        // Wrapping ribbon.
        total_ribbon += 2 * (d1 + d2);

        // Bow ribbon.
        total_ribbon += d1 * d2 * d3;
    }

    println!("The total amount of paper needed is {} square feet.", total_paper);
    println!("The total amount of ribbon needed is {} square feet.", total_ribbon);
}
<|endoftext|>


<commit_before>//! Implementations of the callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
#![allow(deprecated)] // keysyms

use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::{ButtonState, KeyboardModifiers, KeyState, KeyboardLed, ScrollAxis, Size,
                     Point, Geometry, ResizeEdge, ViewState, VIEW_ACTIVATED, VIEW_RESIZING,
                     MOD_NONE, MOD_CTRL, RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};
use rustwlc::input::{pointer, keyboard};

use super::keys::{self, KeyPress, KeyEvent};
use super::layout::{try_lock_tree, try_lock_action, Action, ContainerType, MovementError, TreeError};
use super::layout::commands::set_performing_action;
use super::lua::{self, LuaQuery};

/// If the event is handled by way-cooler
const EVENT_BLOCKED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

const LEFT_CLICK: u32 = 0x110;
const RIGHT_CLICK: u32 = 0x111;

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
        }).is_ok()
    } else {
        false
    }
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                                old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
           output, *old_size_ptr, *new_size_ptr);
    // Update the resolution of the output and its children
    let scale = 1;
    output.set_resolution(*new_size_ptr, scale);
    if let Ok(mut tree) = try_lock_tree() {
        tree.layout_active_of(ContainerType::Output)
            .expect("Could not layout active output");
    }
}

pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    if view.get_class().as_str() == "Background" {
        info!("Setting background: {}", view.get_title());
        view.send_to_back();
        view.set_mask(1);
        let output = view.get_output();
        let resolution = output.get_resolution()
            .expect("Couldn't get output resolution");
        let fullscreen = Geometry {
            origin: Point { x: 0, y: 0 },
            size: resolution
        };
        view.set_geometry(ResizeEdge::empty(), fullscreen);
        return true
    }
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_view(view).and_then(|_| {
            if view.get_class() == "Background" {
                return Ok(())
            }
            tree.set_active_view(view).or_else(|_| {
                // We still want to focus on the window that appeared
                // Might need to change later, in case this focus grabbing
                // gets annoying / becomes a security issue.
                view.focus();
                Ok(())
            })
        }).is_ok()
    } else {
        false
    }
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
    if let Ok(mut tree) = try_lock_tree() {
        tree.remove_view(view).unwrap_or_else(|err| {
            match err {
                TreeError::ViewNotFound(_) => {},
                _ => {
                    error!("Error in view_destroyed: {:?}", err);
                }
            }
        });
    } else {
        error!("Could not delete view {:?}", view);
    }
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
    if let Ok(mut tree) = try_lock_tree() {
        match tree.set_active_view(current) {
            Ok(_) => {},
            Err(err) => {
                error!("Could not set {:?} to be active view: {:?}", current, err);
            }
        }
    }
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, _dest: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.set_active_view(view) {
            error!("view_request_move error: {:?}", err);
        }
    }
}

pub extern fn view_request_resize(view: WlcView, edge: ResizeEdge, point: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        match try_lock_action() {
            Ok(guard) => {
                if guard.is_some() {
                    if let Some(id) = tree.lookup_view(view) {
                        if let Err(err) = tree.resize_container(id, edge, *point) {
                            error!("Problem: Command returned error: {:#?}", err);
                        }
                    }
                }
            },
            _ => {}
        }
    }
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                           key: u32, state: KeyState) -> bool {
    let empty_mods: KeyboardModifiers = KeyboardModifiers {
            mods: MOD_NONE,
            leds: KeyboardLed::empty()
    };
    let sym = keyboard::get_keysym_for_key(key, empty_mods);
    let press = KeyPress::new(mods.mods, sym);

    if state == KeyState::Pressed {
        if let Some(action) = keys::get(&press) {
            debug!("[key] Found an action for {}", press);
            match action {
                KeyEvent::Command(func) => {
                    func();
                },
                KeyEvent::Lua => {
                    match lua::send(LuaQuery::HandleKey(press)) {
                        Ok(_) => {},
                        Err(err) => {
                            // We may want to wait for Lua's reply from
                            // keypresses; for example if the table is tampered
                            // with or Lua is restarted or Lua has an error.
                            // ATM Lua asynchronously logs this but in the future
                            // an error popup/etc is a good idea.
                            error!("Error sending keypress: {:?}", err);
                        }
                    }
                }
            }
            return EVENT_BLOCKED
        }
    }

    return EVENT_PASS_THROUGH
}

pub extern fn view_request_geometry(_view: WlcView, _geometry: &Geometry) {
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                             state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if button == LEFT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).unwrap_or_else(|_| {
                    // still focus on view, even if not in tree.
                    view.focus();
                });
                if mods.mods.contains(MOD_CTRL) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            // TODO Make this set in the config file and read here.
            if mods.mods.contains(MOD_CTRL) {
                let action = Action {
                    view: view,
                    grab: *point,
                    edges: ResizeEdge::empty()
                };
                set_performing_action(Some(action));
                let geometry = view.get_geometry()
                    .expect("Could not get geometry of the view");
                let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                {
                    let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                        .unwrap_or(Action {
                            view: view,
                            grab: *point,
                            edges: ResizeEdge::empty()
                        });
                    let flag_x = if point.x < halfw {
                        RESIZE_LEFT
                    } else if point.x > halfw {
                        RESIZE_RIGHT
                    } else {
                        ResizeEdge::empty()
                    };

                    let flag_y = if point.y < halfh {
                        RESIZE_TOP
                    } else if point.y > halfh {
                        RESIZE_BOTTOM
                    } else {
                        ResizeEdge::empty()
                    };

                    action.edges = flag_x | flag_y;
                    set_performing_action(Some(action));
                }
                view.set_state(VIEW_RESIZING, true);
                return EVENT_BLOCKED
            }
        }
    } else {
        if let Ok(lock) = try_lock_action() {
            match *lock {
                Some(action) => {
                    let view = action.view;
                    if view.get_state().contains(VIEW_RESIZING) {
                        view.set_state(VIEW_RESIZING, false);
                    }
                },
                _ => {}
            }
        }
        set_performing_action(None);
    }
    EVENT_PASS_THROUGH
}

pub extern fn pointer_scroll(_view: WlcView, _time: u32,
                         _mods_ptr: &KeyboardModifiers, _axis: ScrollAxis,
                         _heights: [f64; 2]) -> bool {
    EVENT_PASS_THROUGH
}

pub extern fn pointer_motion(view: WlcView, _time: u32, point: &Point) -> bool {
    let mut result = EVENT_PASS_THROUGH;
    let mut maybe_action = None;
    {
        if let Ok(action_lock) = try_lock_action() {
            maybe_action = action_lock.clone();
        }
    }
    match maybe_action {
        None => result = EVENT_PASS_THROUGH,
        Some(action) => {
            if action.edges.bits() != 0 {
                if let Ok(mut tree) = try_lock_tree() {
                    // TODO Change to id of _view
                    // Need to implement a map of view to uuid first though...
                    if let Some(active_id) = tree.lookup_view(view) {
                        match tree.resize_container(active_id, action.edges, *point) {
                            // Return early here to not set the pointer
                            Ok(_) => return EVENT_BLOCKED,
                            Err(err) => error!("Error: {:#?}", err)
                        }
                    }
                }
            } else {
                if let Ok(mut tree) = try_lock_tree() {
                    match tree.try_drag_active(*point) {
                        Ok(_) => result = EVENT_BLOCKED,
                        Err(TreeError::PerformingAction(_)) |
                        Err(TreeError::Movement(MovementError::NotFloating(_))) => result = EVENT_PASS_THROUGH,
                        Err(err) => {
                            error!("Error: {:#?}", err);
                            result = EVENT_PASS_THROUGH
                        }
                    }
                }
            }
        }
    }
    pointer::set_position(*point);
    result
}

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    info!("Initializing Lua...");
    lua::init();
    keys::init();
}

pub extern fn compositor_terminating() {
    info!("Compositor terminating!");
    lua::send(lua::LuaQuery::Terminate).ok();
    if let Ok(mut tree) = try_lock_tree() {
        if tree.destroy_tree().is_err() {
            error!("Could not destroy tree");
        }
    }

}

pub fn init() {
    use rustwlc::callback;

    callback::output_created(output_created);
    callback::output_destroyed(output_destroyed);
    callback::output_focus(output_focus);
    callback::output_resolution(output_resolution);
    callback::view_created(view_created);
    callback::view_destroyed(view_destroyed);
    callback::view_focus(view_focus);
    callback::view_move_to_output(view_move_to_output);
    callback::view_request_geometry(view_request_geometry);
    callback::view_request_state(view_request_state);
    callback::view_request_move(view_request_move);
    callback::view_request_resize(view_request_resize);
    callback::keyboard_key(keyboard_key);
    callback::pointer_button(pointer_button);
    callback::pointer_scroll(pointer_scroll);
    callback::pointer_motion(pointer_motion);
    callback::compositor_ready(compositor_ready);
    callback::compositor_terminate(compositor_terminating);
    trace!("Registered wlc callbacks");
}
<commit_msg>New views are maximized, Fixes #198<commit_after>//! Implementations of the callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
#![allow(deprecated)] // keysyms

use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::{ButtonState, KeyboardModifiers, KeyState, KeyboardLed, ScrollAxis, Size,
                     Point, Geometry, ResizeEdge, ViewState, VIEW_ACTIVATED, VIEW_RESIZING, VIEW_MAXIMIZED,
                     MOD_NONE, MOD_CTRL, RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};
use rustwlc::input::{pointer, keyboard};

use super::keys::{self, KeyPress, KeyEvent};
use super::layout::{try_lock_tree, try_lock_action, Action, ContainerType, MovementError, TreeError};
use super::layout::commands::set_performing_action;
use super::lua::{self, LuaQuery};

/// If the event is handled by way-cooler
const EVENT_BLOCKED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

const LEFT_CLICK: u32 = 0x110;
const RIGHT_CLICK: u32 = 0x111;

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
        }).is_ok()
    } else {
        false
    }
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                                old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
           output, *old_size_ptr, *new_size_ptr);
    // Update the resolution of the output and its children
    let scale = 1;
    output.set_resolution(*new_size_ptr, scale);
    if let Ok(mut tree) = try_lock_tree() {
        tree.layout_active_of(ContainerType::Output)
            .expect("Could not layout active output");
    }
}

pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    if view.get_class().as_str() == "Background" {
        info!("Setting background: {}", view.get_title());
        view.send_to_back();
        view.set_mask(1);
        let output = view.get_output();
        let resolution = output.get_resolution()
            .expect("Couldn't get output resolution");
        let fullscreen = Geometry {
            origin: Point { x: 0, y: 0 },
            size: resolution
        };
        view.set_geometry(ResizeEdge::empty(), fullscreen);
        return true
    }
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_view(view).and_then(|_| {
            if view.get_class() == "Background" {
                return Ok(())
            }
            view.set_state(VIEW_MAXIMIZED, true);
            tree.set_active_view(view).or_else(|_| {
                // We still want to focus on the window that appeared
                // Might need to change later, in case this focus grabbing
                // gets annoying / becomes a security issue.
                view.focus();
                Ok(())
            })
        }).is_ok()
    } else {
        false
    }
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
    if let Ok(mut tree) = try_lock_tree() {
        tree.remove_view(view).unwrap_or_else(|err| {
            match err {
                TreeError::ViewNotFound(_) => {},
                _ => {
                    error!("Error in view_destroyed: {:?}", err);
                }
            }
        });
    } else {
        error!("Could not delete view {:?}", view);
    }
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
    if let Ok(mut tree) = try_lock_tree() {
        match tree.set_active_view(current) {
            Ok(_) => {},
            Err(err) => {
                error!("Could not set {:?} to be active view: {:?}", current, err);
            }
        }
    }
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, _dest: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.set_active_view(view) {
            error!("view_request_move error: {:?}", err);
        }
    }
}

pub extern fn view_request_resize(view: WlcView, edge: ResizeEdge, point: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        match try_lock_action() {
            Ok(guard) => {
                if guard.is_some() {
                    if let Some(id) = tree.lookup_view(view) {
                        if let Err(err) = tree.resize_container(id, edge, *point) {
                            error!("Problem: Command returned error: {:#?}", err);
                        }
                    }
                }
            },
            _ => {}
        }
    }
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                           key: u32, state: KeyState) -> bool {
    let empty_mods: KeyboardModifiers = KeyboardModifiers {
            mods: MOD_NONE,
            leds: KeyboardLed::empty()
    };
    let sym = keyboard::get_keysym_for_key(key, empty_mods);
    let press = KeyPress::new(mods.mods, sym);

    if state == KeyState::Pressed {
        if let Some(action) = keys::get(&press) {
            debug!("[key] Found an action for {}", press);
            match action {
                KeyEvent::Command(func) => {
                    func();
                },
                KeyEvent::Lua => {
                    match lua::send(LuaQuery::HandleKey(press)) {
                        Ok(_) => {},
                        Err(err) => {
                            // We may want to wait for Lua's reply from
                            // keypresses; for example if the table is tampered
                            // with or Lua is restarted or Lua has an error.
                            // ATM Lua asynchronously logs this but in the future
                            // an error popup/etc is a good idea.
                            error!("Error sending keypress: {:?}", err);
                        }
                    }
                }
            }
            return EVENT_BLOCKED
        }
    }

    return EVENT_PASS_THROUGH
}

pub extern fn view_request_geometry(_view: WlcView, _geometry: &Geometry) {
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                             state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if button == LEFT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).unwrap_or_else(|_| {
                    // still focus on view, even if not in tree.
                    view.focus();
                });
                if mods.mods.contains(MOD_CTRL) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            // TODO Make this set in the config file and read here.
            if mods.mods.contains(MOD_CTRL) {
                let action = Action {
                    view: view,
                    grab: *point,
                    edges: ResizeEdge::empty()
                };
                set_performing_action(Some(action));
                let geometry = view.get_geometry()
                    .expect("Could not get geometry of the view");
                let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                {
                    let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                        .unwrap_or(Action {
                            view: view,
                            grab: *point,
                            edges: ResizeEdge::empty()
                        });
                    let flag_x = if point.x < halfw {
                        RESIZE_LEFT
                    } else if point.x > halfw {
                        RESIZE_RIGHT
                    } else {
                        ResizeEdge::empty()
                    };

                    let flag_y = if point.y < halfh {
                        RESIZE_TOP
                    } else if point.y > halfh {
                        RESIZE_BOTTOM
                    } else {
                        ResizeEdge::empty()
                    };

                    action.edges = flag_x | flag_y;
                    set_performing_action(Some(action));
                }
                view.set_state(VIEW_RESIZING, true);
                return EVENT_BLOCKED
            }
        }
    } else {
        if let Ok(lock) = try_lock_action() {
            match *lock {
                Some(action) => {
                    let view = action.view;
                    if view.get_state().contains(VIEW_RESIZING) {
                        view.set_state(VIEW_RESIZING, false);
                    }
                },
                _ => {}
            }
        }
        set_performing_action(None);
    }
    EVENT_PASS_THROUGH
}

pub extern fn pointer_scroll(_view: WlcView, _time: u32,
                         _mods_ptr: &KeyboardModifiers, _axis: ScrollAxis,
                         _heights: [f64; 2]) -> bool {
    EVENT_PASS_THROUGH
}

pub extern fn pointer_motion(view: WlcView, _time: u32, point: &Point) -> bool {
    let mut result = EVENT_PASS_THROUGH;
    let mut maybe_action = None;
    {
        if let Ok(action_lock) = try_lock_action() {
            maybe_action = action_lock.clone();
        }
    }
    match maybe_action {
        None => result = EVENT_PASS_THROUGH,
        Some(action) => {
            if action.edges.bits() != 0 {
                if let Ok(mut tree) = try_lock_tree() {
                    // TODO Change to id of _view
                    // Need to implement a map of view to uuid first though...
                    if let Some(active_id) = tree.lookup_view(view) {
                        match tree.resize_container(active_id, action.edges, *point) {
                            // Return early here to not set the pointer
                            Ok(_) => return EVENT_BLOCKED,
                            Err(err) => error!("Error: {:#?}", err)
                        }
                    }
                }
            } else {
                if let Ok(mut tree) = try_lock_tree() {
                    match tree.try_drag_active(*point) {
                        Ok(_) => result = EVENT_BLOCKED,
                        Err(TreeError::PerformingAction(_)) |
                        Err(TreeError::Movement(MovementError::NotFloating(_))) => result = EVENT_PASS_THROUGH,
                        Err(err) => {
                            error!("Error: {:#?}", err);
                            result = EVENT_PASS_THROUGH
                        }
                    }
                }
            }
        }
    }
    pointer::set_position(*point);
    result
}

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    info!("Initializing Lua...");
    lua::init();
    keys::init();
}

pub extern fn compositor_terminating() {
    info!("Compositor terminating!");
    lua::send(lua::LuaQuery::Terminate).ok();
    if let Ok(mut tree) = try_lock_tree() {
        if tree.destroy_tree().is_err() {
            error!("Could not destroy tree");
        }
    }

}

pub fn init() {
    use rustwlc::callback;

    callback::output_created(output_created);
    callback::output_destroyed(output_destroyed);
    callback::output_focus(output_focus);
    callback::output_resolution(output_resolution);
    callback::view_created(view_created);
    callback::view_destroyed(view_destroyed);
    callback::view_focus(view_focus);
    callback::view_move_to_output(view_move_to_output);
    callback::view_request_geometry(view_request_geometry);
    callback::view_request_state(view_request_state);
    callback::view_request_move(view_request_move);
    callback::view_request_resize(view_request_resize);
    callback::keyboard_key(keyboard_key);
    callback::pointer_button(pointer_button);
    callback::pointer_scroll(pointer_scroll);
    callback::pointer_motion(pointer_motion);
    callback::compositor_ready(compositor_ready);
    callback::compositor_terminate(compositor_terminating);
    trace!("Registered wlc callbacks");
}
<|endoftext|>