<commit_before>//! Requires the 'framework' feature flag be enabled in your project's
//! `Cargo.toml`.
//!
//! This can be enabled by specifying the feature in the dependency section:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/zeyla/serenity.git"
//! features = ["framework"]
//! ```

#[macro_use]
extern crate serenity;
extern crate typemap;

use serenity::prelude::*;
use serenity::model::*;
use serenity::framework::standard::{Args, Command, DispatchError, StandardFramework, help_commands};
use std::collections::HashMap;
use std::env;
use std::fmt::Write;
use std::sync::Arc;
use typemap::Key;

struct CommandCounter;

impl Key for CommandCounter {
    type Value = HashMap<String, u64>;
}

struct Handler;

impl EventHandler for Handler {
    fn on_ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler);

    {
        let mut data = client.data.lock();
        data.insert::<CommandCounter>(HashMap::default());
    }

    // Commands are equivalent to:
    // "~about"
    // "~emoji cat"
    // "~emoji dog"
    // "~multiply"
    // "~ping"
    // "~some long command"
    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        //
        // Refer to the documentation for
        // `serenity::ext::framework::Configuration` for all available
        // configurations.
        StandardFramework::new()
        .configure(|c| c
            .allow_whitespace(true)
            .on_mention(true)
            .prefix("~"))
        // Set a function to be called prior to each command execution. This
        // provides the context of the command, the message that was received,
        // and the full name of the command that will be called.
        //
        // You can not use this to determine whether a command should be
        // executed. Instead, `set_check` is provided to give you this
        // functionality.
        .before(|ctx, msg, command_name| {
            println!("Got command '{}' by user '{}'",
                     command_name,
                     msg.author.name);

            // Increment the number of times this command has been run once. If
            // the command's name does not exist in the counter, add a default
            // value of 0.
            let mut data = ctx.data.lock();
            let counter = data.get_mut::<CommandCounter>().unwrap();
            let entry = counter.entry(command_name.to_owned()).or_insert(0);
            *entry += 1;

            true // if `before` returns false, command processing doesn't happen.
        })
        // Similar to `before`, except will be called directly _after_
        // command execution.
        .after(|_, _, command_name, error| {
            match error {
                Ok(()) => println!("Processed command '{}'", command_name),
                Err(why) => println!("Command '{}' returned error {:?}", command_name, why),
            }
        })
        // Set a function that's called whenever a command's execution didn't complete for one
        // reason or another. For example, when a user has exceeded a rate-limit or a command
        // can only be performed by the bot owner.
        .on_dispatch_error(|_ctx, msg, error| {
            if let DispatchError::RateLimited(seconds) = error {
                let _ = msg.channel_id.say(&format!("Try this again in {} seconds.", seconds));
            }
        })
        // Can't be used more than once per 5 seconds:
        .simple_bucket("emoji", 5)
        // Can't be used more than 2 times per 30 seconds, with a 5 second delay:
        .bucket("complicated", 5, 30, 2)
        .command("about", |c| c.exec_str("A test bot"))
        .command("help", |c| c.exec_help(help_commands::plain))
        .command("commands", |c| c
            // Make this command use the "complicated" bucket.
            .bucket("complicated")
            .exec(commands))
        .group("Emoji", |g| g
            .prefix("emoji")
            .command("cat", |c| c
                .desc("Sends an emoji with a cat.")
                .batch_known_as(vec!["kitty", "neko"]) // Adds multiple aliases
                .bucket("emoji") // Make this command use the "emoji" bucket.
                .exec_str(":cat:")
                 // Allow only administrators to call this:
                .required_permissions(permissions::ADMINISTRATOR))
            .command("dog", |c| c
                .desc("Sends an emoji with a dog.")
                .bucket("emoji")
                .exec_str(":dog:")))
        .command("multiply", |c| c
            .known_as("*") // Lets us call ~* instead of ~multiply
            .exec(multiply))
        .command("ping", |c| c
            .check(owner_check)
            .exec_str("Pong!"))
        .command("some long command", |c| c.exec(some_long_command)));

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

// Commands can be created via the `command!` macro, to avoid manually typing
// type annotations.
//
// This may bring more features available for commands in the future. See the
// "multiply" command below for some of the power that the `command!` macro can
// bring.
command!(commands(ctx, msg, _args) {
    let mut contents = "Commands used:\n".to_owned();

    let data = ctx.data.lock();
    let counter = data.get::<CommandCounter>().unwrap();

    for (k, v) in counter {
        let _ = write!(contents, "- {name}: {amount}\n", name=k, amount=v);
    }

    if let Err(why) = msg.channel_id.say(&contents) {
        println!("Error sending message: {:?}", why);
    }
});

// A function which acts as a "check", to determine whether to call a command.
//
// In this case, this command checks to ensure you are the owner of the message
// in order for the command to be executed. If the check fails, the command is
// not called.
fn owner_check(_: &mut Context, msg: &Message, _: &mut Args, _: &Arc<Command>) -> bool {
    // Replace 7 with your ID
    msg.author.id == 7
}

command!(some_long_command(_ctx, msg, args) {
    if let Err(why) = msg.channel_id.say(&format!("Arguments: {:?}", args)) {
        println!("Error sending message: {:?}", why);
    }
});

// Using the `command!` macro, commands can be created with a certain type of
// "dynamic" type checking. This is a method of requiring that the arguments
// given match the required type, and maps those arguments to the specified
// bindings.
//
// For example, the following will be correctly parsed by the macro:
//
// `~multiply 3.7 4.3`
//
// However, the following will not, as the second argument can not be an f64:
//
// `~multiply 3.7 four`
//
// Since the argument can't be converted, the command returns early.
//
// Additionally, if not enough arguments are given (e.g. `~multiply 3`), then
// the command will return early. If additional arguments are provided, they
// will be ignored.
//
// Argument type overloading is currently not supported.
command!(multiply(_ctx, msg, args) {
    let first = args.single::<f64>().unwrap();
    let second = args.single::<f64>().unwrap();

    let res = first * second;

    if let Err(why) = msg.channel_id.say(&res.to_string()) {
        println!("Err sending product of {} and {}: {:?}", first, second, why);
    }
});
<commit_msg>Add more info on methods in framework example<commit_after>//! Requires the 'framework' feature flag be enabled in your project's
//! `Cargo.toml`.
//!
//! This can be enabled by specifying the feature in the dependency section:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/zeyla/serenity.git"
//! features = ["framework"]
//! ```

#[macro_use]
extern crate serenity;
extern crate typemap;

use serenity::prelude::*;
use serenity::model::*;
use serenity::framework::standard::{Args, Command, DispatchError, StandardFramework, help_commands};
use std::collections::HashMap;
use std::env;
use std::fmt::Write;
use std::sync::Arc;
use typemap::Key;

struct CommandCounter;

impl Key for CommandCounter {
    type Value = HashMap<String, u64>;
}

struct Handler;

impl EventHandler for Handler {
    fn on_ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect(
        "Expected a token in the environment",
    );
    let mut client = Client::new(&token, Handler);

    {
        let mut data = client.data.lock();
        data.insert::<CommandCounter>(HashMap::default());
    }

    // Commands are equivalent to:
    // "~about"
    // "~emoji cat"
    // "~emoji dog"
    // "~multiply"
    // "~ping"
    // "~some long command"
    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        //
        // Refer to the documentation for
        // `serenity::ext::framework::Configuration` for all available
        // configurations.
        StandardFramework::new()
        .configure(|c| c
            .allow_whitespace(true)
            .on_mention(true)
            .prefix("~")
            // You can set multiple delimiters via delimiters()
            // or just one via delimiter(",")
            // If you set multiple delimiters, the order you list them
            // decides their priority (from first to last).
            //
            // In this case, if "," would be first, a message would never
            // be delimited at ", ", forcing you to trim your arguments if you
            // want to avoid whitespaces at the start of each.
            .delimiters(vec![", ", ","]))

        // Set a function to be called prior to each command execution. This
        // provides the context of the command, the message that was received,
        // and the full name of the command that will be called.
        //
        // You can not use this to determine whether a command should be
        // executed. Instead, `set_check` is provided to give you this
        // functionality.
        .before(|ctx, msg, command_name| {
            println!("Got command '{}' by user '{}'",
                     command_name,
                     msg.author.name);

            // Increment the number of times this command has been run once. If
            // the command's name does not exist in the counter, add a default
            // value of 0.
            let mut data = ctx.data.lock();
            let counter = data.get_mut::<CommandCounter>().unwrap();
            let entry = counter.entry(command_name.to_owned()).or_insert(0);
            *entry += 1;

            true // if `before` returns false, command processing doesn't happen.
        })
        // Similar to `before`, except will be called directly _after_
        // command execution.
        .after(|_, _, command_name, error| {
            match error {
                Ok(()) => println!("Processed command '{}'", command_name),
                Err(why) => println!("Command '{}' returned error {:?}", command_name, why),
            }
        })
        // Set a function that's called whenever a command's execution didn't complete for one
        // reason or another. For example, when a user has exceeded a rate-limit or a command
        // can only be performed by the bot owner.
        .on_dispatch_error(|_ctx, msg, error| {
            if let DispatchError::RateLimited(seconds) = error {
                let _ = msg.channel_id.say(&format!("Try this again in {} seconds.", seconds));
            }
        })
        // Can't be used more than once per 5 seconds:
        .simple_bucket("emoji", 5)
        // Can't be used more than 2 times per 30 seconds, with a 5 second delay:
        .bucket("complicated", 5, 30, 2)
        .command("about", |c| c.exec_str("A test bot"))
        .command("help", |c| c.exec_help(help_commands::plain))
        .command("commands", |c| c
            // Make this command use the "complicated" bucket.
            .bucket("complicated")
            .exec(commands))
        .group("Emoji", |g| g
            .prefix("emoji")
            .command("cat", |c| c
                .desc("Sends an emoji with a cat.")
                .batch_known_as(vec!["kitty", "neko"]) // Adds multiple aliases
                .bucket("emoji") // Make this command use the "emoji" bucket.
                .exec_str(":cat:")
                 // Allow only administrators to call this:
                .required_permissions(permissions::ADMINISTRATOR))
            .command("dog", |c| c
                .desc("Sends an emoji with a dog.")
                .bucket("emoji")
                .exec_str(":dog:")))
        .command("multiply", |c| c
            .known_as("*") // Lets us call ~* instead of ~multiply
            .exec(multiply))
        .command("ping", |c| c
            .check(owner_check)
            .exec_str("Pong!"))
        .command("role", |c| c
            .exec(about_role)
            // Limits the usage of this command to roles named:
            .allowed_roles(vec!["mods", "ultimate neko"]))
        .command("some long command", |c| c.exec(some_long_command)),
    );

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

// Commands can be created via the `command!` macro, to avoid manually typing
// type annotations.
//
// This may bring more features available for commands in the future. See the
// "multiply" command below for some of the power that the `command!` macro can
// bring.
command!(commands(ctx, msg, _args) {
    let mut contents = "Commands used:\n".to_owned();

    let data = ctx.data.lock();
    let counter = data.get::<CommandCounter>().unwrap();

    for (k, v) in counter {
        let _ = write!(contents, "- {name}: {amount}\n", name=k, amount=v);
    }

    if let Err(why) = msg.channel_id.say(&contents) {
        println!("Error sending message: {:?}", why);
    }
});

// A function which acts as a "check", to determine whether to call a command.
//
// In this case, this command checks to ensure you are the owner of the message
// in order for the command to be executed. If the check fails, the command is
// not called.
fn owner_check(_: &mut Context, msg: &Message, _: &mut Args, _: &Arc<Command>) -> bool {
    // Replace 7 with your ID
    msg.author.id == 7
}

command!(some_long_command(_ctx, msg, args) {
    if let Err(why) = msg.channel_id.say(&format!("Arguments: {:?}", args)) {
        println!("Error sending message: {:?}", why);
    }
});

command!(about_role(_ctx, msg, args) {
    let potential_role_name = args.full();

    if let Some(guild) = msg.guild() {
        // `role_by_name()` allows us to attempt attaining a reference to a role
        // via its name.
        if let Some(role) = guild.read().unwrap().role_by_name(&potential_role_name) {
            if let Err(why) = msg.channel_id.say(&format!("Role-ID: {}", role.id)) {
                println!("Error sending message: {:?}", why);
            }

            return Ok(());
        }
    }

    if let Err(why) = msg.channel_id.say(
                      &format!("Could not find role named: {:?}", potential_role_name)) {
        println!("Error sending message: {:?}", why);
    }
});

// Using the `command!` macro, commands can be created with a certain type of
// "dynamic" type checking. This is a method of requiring that the arguments
// given match the required type, and maps those arguments to the specified
// bindings.
//
// For example, the following will be correctly parsed by the macro:
//
// `~multiply 3.7 4.3`
//
// However, the following will not, as the second argument can not be an f64:
//
// `~multiply 3.7 four`
//
// Since the argument can't be converted, the command returns early.
//
// Additionally, if not enough arguments are given (e.g. `~multiply 3`), then
// the command will return early. If additional arguments are provided, they
// will be ignored.
//
// Argument type overloading is currently not supported.
command!(multiply(_ctx, msg, args) {
    let first = args.single::<f64>().unwrap();
    let second = args.single::<f64>().unwrap();

    let res = first * second;

    if let Err(why) = msg.channel_id.say(&res.to_string()) {
        println!("Err sending product of {} and {}: {:?}", first, second, why);
    }
});
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::FromIterator;
use std::ops::Deref;

use syntax::ast;
use syntax::ptr::P;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>,
}

impl<'a> BuildSetters<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
      -> BuildSetters<'a> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a> node::RegVisitor for BuildSetters<'a> {
  fn visit_prim_reg<'b>(&'b mut self, path: &Vec<String>,
      reg: &'b node::Reg, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::Access::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(reg.name.span, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types, dead_code)]
    pub struct $name<'a> {
      value: $packed_ty,
      mask: $packed_ty,
      write_only: bool,
      reg: &'a $reg_ty,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  P(item)
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg)
                 -> P<ast::ImplItem> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(reg.name.span, utils::path_ident(cx, path));
  let setter_ident = utils::setter_name(cx, path);
  utils::unwrap_impl_item(quote_item!(cx,
    impl<'a> $setter_ident<'a> {
      #[doc="Create a new updater"]
      pub fn new(reg: &'a $reg_ty) -> $setter_ident<'a> {
        $setter_ident {
          value: 0,
          mask: 0,
          write_only: false,
          reg: reg,
        }
      }
    }
  ).unwrap())
}

fn build_new_ignoring_state<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg) -> P<ast::ImplItem> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(reg.name.span, utils::path_ident(cx, path));
  let setter_ident = utils::setter_name(cx, path);
  utils::unwrap_impl_item(quote_item!(cx,
    impl<'a> $setter_ident<'a> {
      #[doc="Create a new updater that ignores current state"]
      pub fn new_ignoring_state(reg: &'a $reg_ty) -> $setter_ident<'a> {
        $setter_ident {
          value: 0,
          mask: 0,
          write_only: true,
          reg: reg,
        }
      }
    }
  ).unwrap())
}

fn build_drop(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ident = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::Access::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::Access::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, if self.write_only { 0 } else { self.reg.value.get() })
    };

  let item = quote_item!(cx,
    #[doc = "This performs the register update"]
    impl<'a> Drop for $setter_ident<'a> {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done(ctx: &ExtCtxt, path: &Vec<String>) -> P<ast::ImplItem> {
  let setter_ident = utils::setter_name(ctx, path);
  utils::unwrap_impl_item(quote_item!(ctx,
    impl<'a> $setter_ident<'a> {
      #[doc = "Commit changes to register. Allows for chaining of set"]
      pub fn done(self) {}
    }
  ).unwrap())
}

fn build_impl(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
              fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path, reg);
  let new_is = build_new_ignoring_state(cx, path, reg);
  let setter_ident = utils::setter_name(cx, path);
  let methods: Vec<P<ast::ImplItem>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done = build_done(cx, path);
  quote_item!(cx,
    #[allow(dead_code)]
    impl<'a> $setter_ident<'a> {
      $new
      $new_is
      $methods
      $done
    }
  ).unwrap()
}

fn build_field_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  field: &node::Field) -> Option<P<ast::ImplItem>>
{
  match field.access {
    node::Access::ReadOnly => None,
    node::Access::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> P<ast::ImplItem>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from("set_")+field.name.node.as_str()).as_str());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field));
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self,
                            new_value: $field_ty) -> &'b mut $setter_ty<'a> {
          self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self,
                            idx: usize,
                            new_value: $field_ty) -> &'b mut $setter_ty<'a> {
          self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  }
}

fn build_field_clear_fn(cx: &ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::ImplItem>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from("clear_")+field.name.node.as_str()).as_str());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self) -> &'b mut $setter_ty<'a> {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self, idx: usize) -> &'b mut $setter_ty<'a> {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  }
}
<commit_msg>Updated ioreg/builder/setter.rs<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::FromIterator;
use std::ops::Deref;

use syntax::ast;
use syntax::ptr::P;
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>,
}

impl<'a> BuildSetters<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
      -> BuildSetters<'a> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a> node::RegVisitor for BuildSetters<'a> {
  fn visit_prim_reg<'b>(&'b mut self, path: &Vec<String>,
      reg: &'b node::Reg, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::Access::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(reg.name.span, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => d.node.name.to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types, dead_code)]
    pub struct $name<'a> {
      value: $packed_ty,
      mask: $packed_ty,
      write_only: bool,
      reg: &'a $reg_ty,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  P(item)
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg)
                 -> P<ast::ImplItem> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(reg.name.span, utils::path_ident(cx, path));
  let setter_ident = utils::setter_name(cx, path);
  utils::unwrap_impl_item(quote_item!(cx,
    impl<'a> $setter_ident<'a> {
      #[doc="Create a new updater"]
      pub fn new(reg: &'a $reg_ty) -> $setter_ident<'a> {
        $setter_ident {
          value: 0,
          mask: 0,
          write_only: false,
          reg: reg,
        }
      }
    }
  ).unwrap())
}

fn build_new_ignoring_state<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg) -> P<ast::ImplItem> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(reg.name.span, utils::path_ident(cx, path));
  let setter_ident = utils::setter_name(cx, path);
  utils::unwrap_impl_item(quote_item!(cx,
    impl<'a> $setter_ident<'a> {
      #[doc="Create a new updater that ignores current state"]
      pub fn new_ignoring_state(reg: &'a $reg_ty) -> $setter_ident<'a> {
        $setter_ident {
          value: 0,
          mask: 0,
          write_only: true,
          reg: reg,
        }
      }
    }
  ).unwrap())
}

fn build_drop(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ident = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::Access::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::Access::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, if self.write_only { 0 } else { self.reg.value.get() })
    };

  let item = quote_item!(cx,
    #[doc = "This performs the register update"]
    impl<'a> Drop for $setter_ident<'a> {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done(ctx: &ExtCtxt, path: &Vec<String>) -> P<ast::ImplItem> {
  let setter_ident = utils::setter_name(ctx, path);
  utils::unwrap_impl_item(quote_item!(ctx,
    impl<'a> $setter_ident<'a> {
      #[doc = "Commit changes to register. Allows for chaining of set"]
      pub fn done(self) {}
    }
  ).unwrap())
}

fn build_impl(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
              fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path, reg);
  let new_is = build_new_ignoring_state(cx, path, reg);
  let setter_ident = utils::setter_name(cx, path);
  let methods: Vec<P<ast::ImplItem>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done = build_done(cx, path);
  quote_item!(cx,
    #[allow(dead_code)]
    impl<'a> $setter_ident<'a> {
      $new
      $new_is
      $methods
      $done
    }
  ).unwrap()
}

fn build_field_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  field: &node::Field) -> Option<P<ast::ImplItem>>
{
  match field.access {
    node::Access::ReadOnly => None,
    node::Access::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> P<ast::ImplItem>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from("set_")+field.name.node.as_str()).as_str());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field));
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => d.node.name.to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self,
                            new_value: $field_ty) -> &'b mut $setter_ty<'a> {
          self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self,
                            idx: usize,
                            new_value: $field_ty) -> &'b mut $setter_ty<'a> {
          self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  }
}

fn build_field_clear_fn(cx: &ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::ImplItem>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from("clear_")+field.name.node.as_str()).as_str());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => d.node.name.to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self) -> &'b mut $setter_ty<'a> {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    utils::unwrap_impl_item(quote_item!(cx,
      impl<'a> $setter_ty<'a> {
        $doc_attr
        pub fn $fn_name<'b>(&'b mut self, idx: usize) -> &'b mut $setter_ty<'a> {
          self.value |= $mask << $shift;
          self.mask |= $mask << $shift;
          self
        }
      }
    ).unwrap())
  }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
// (c) Mitchell Mebane <mitchell.mebane@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) clrtoeol dircolors eightbit endcode fnmatch leftcode multihardlink rightcode setenv sgid suid colorterm

use std::borrow::Borrow;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};

use clap::{crate_version, Arg, Command};
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError, UUsageError};

mod options {
    pub const BOURNE_SHELL: &str = "bourne-shell";
    pub const C_SHELL: &str = "c-shell";
    pub const PRINT_DATABASE: &str = "print-database";
    pub const PRINT_LS_COLORS: &str = "print-ls-colors";
    pub const FILE: &str = "FILE";
}

static USAGE: &str = "{} [OPTION]... [FILE]";
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
static LONG_HELP: &str = "
 If FILE is specified, read it to determine which colors to use for which
 file types and extensions.  Otherwise, a precompiled database is used.
 For details on the format of these files, run 'dircolors --print-database'
";

mod colors;
use self::colors::INTERNAL_DB;

#[derive(PartialEq, Debug)]
pub enum OutputFmt {
    Shell,
    CShell,
    Display,
    Unknown,
}

pub fn guess_syntax() -> OutputFmt {
    use std::path::Path;
    match env::var("SHELL") {
        Ok(ref s) if !s.is_empty() => {
            let shell_path: &Path = s.as_ref();
            if let Some(name) = shell_path.file_name() {
                if name == "csh" || name == "tcsh" {
                    OutputFmt::CShell
                } else {
                    OutputFmt::Shell
                }
            } else {
                OutputFmt::Shell
            }
        }
        _ => OutputFmt::Unknown,
    }
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let matches = uu_app().get_matches_from(&args);

    let files = matches
        .values_of(options::FILE)
        .map_or(vec![], |file_values| file_values.collect());

    // clap provides .conflicts_with / .conflicts_with_all, but we want to
    // manually handle conflicts so we can match the output of GNU coreutils
    if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL))
        && (matches.is_present(options::PRINT_DATABASE)
            || matches.is_present(options::PRINT_LS_COLORS))
    {
        return Err(UUsageError::new(
            1,
            "the options to output dircolors' internal database and\nto select a shell \
             syntax are mutually exclusive",
        ));
    }

    if matches.is_present(options::PRINT_DATABASE) && matches.is_present(options::PRINT_LS_COLORS) {
        return Err(UUsageError::new(
            1,
            "options --print-database and --print-ls-colors are mutually exclusive",
        ));
    }

    if matches.is_present(options::PRINT_DATABASE) {
        if !files.is_empty() {
            return Err(UUsageError::new(
                1,
                format!(
                    "extra operand {}\nfile operands cannot be combined with \
                     --print-database (-p)",
                    files[0].quote()
                ),
            ));
        }
        println!("{}", INTERNAL_DB);
        return Ok(());
    }

    let mut out_format = if matches.is_present(options::C_SHELL) {
        OutputFmt::CShell
    } else if matches.is_present(options::BOURNE_SHELL) {
        OutputFmt::Shell
    } else if matches.is_present(options::PRINT_LS_COLORS) {
        OutputFmt::Display
    } else {
        OutputFmt::Unknown
    };

    if out_format == OutputFmt::Unknown {
        match guess_syntax() {
            OutputFmt::Unknown => {
                return Err(USimpleError::new(
                    1,
                    "no SHELL environment variable, and no shell type option given",
                ));
            }
            fmt => out_format = fmt,
        }
    }

    let result;
    if files.is_empty() {
        result = parse(INTERNAL_DB.lines(), &out_format, "");
    } else if files.len() > 1 {
        return Err(UUsageError::new(
            1,
            format!("extra operand {}", files[1].quote()),
        ));
    } else if files[0].eq("-") {
        let fin = BufReader::new(std::io::stdin());
        result = parse(fin.lines().filter_map(Result::ok), &out_format, files[0]);
    } else {
        match File::open(files[0]) {
            Ok(f) => {
                let fin = BufReader::new(f);
                result = parse(fin.lines().filter_map(Result::ok), &out_format, files[0]);
            }
            Err(e) => {
                return Err(USimpleError::new(
                    1,
                    format!("{}: {}", files[0].maybe_quote(), e),
                ));
            }
        }
    }

    match result {
        Ok(s) => {
            println!("{}", s);
            Ok(())
        }
        Err(s) => {
            return Err(USimpleError::new(1, s));
        }
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(SUMMARY)
        .after_help(LONG_HELP)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::BOURNE_SHELL)
                .long("sh")
                .short('b')
                .visible_alias("bourne-shell")
                .overrides_with(options::C_SHELL)
                .help("output Bourne shell code to set LS_COLORS")
                .display_order(1),
        )
        .arg(
            Arg::new(options::C_SHELL)
                .long("csh")
                .short('c')
                .visible_alias("c-shell")
                .overrides_with(options::BOURNE_SHELL)
                .help("output C shell code to set LS_COLORS")
                .display_order(2),
        )
        .arg(
            Arg::new(options::PRINT_DATABASE)
                .long("print-database")
                .short('p')
                .help("print the byte counts")
                .display_order(3),
        )
        .arg(
            Arg::new(options::PRINT_LS_COLORS)
                .long("print-ls-colors")
                .help("output fully escaped colors for display")
                .display_order(4),
        )
        .arg(
            Arg::new(options::FILE)
                .hide(true)
                .value_hint(clap::ValueHint::FilePath)
                .multiple_occurrences(true),
        )
}

pub trait StrUtils {
    /// Remove comments and trim whitespace
    fn purify(&self) -> &Self;
    /// Like split_whitespace() but only produce 2 components
    fn split_two(&self) -> (&str, &str);
    fn fnmatch(&self, pattern: &str) -> bool;
}

impl StrUtils for str {
    fn purify(&self) -> &Self {
        let mut line = self;
        for (n, _) in self
            .as_bytes()
            .iter()
            .enumerate()
            .filter(|(_, c)| **c == b'#')
        {
            // Ignore the content after '#'
            // only if it is preceded by at least one whitespace
            match self[..n].chars().last() {
                Some(c) if c.is_whitespace() => {
                    line = &self[..n - c.len_utf8()];
                    break;
                }
                None => {
                    // n == 0
                    line = &self[..0];
                    break;
                }
                _ => (),
            }
        }
        line.trim()
    }

    fn split_two(&self) -> (&str, &str) {
        if let Some(b) = self.find(char::is_whitespace) {
            let key = &self[..b];
            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
                (key, &self[b + e..])
            } else {
                (key, "")
            }
        } else {
            ("", "")
        }
    }

    fn fnmatch(&self, pat: &str) -> bool {
        pat.parse::<glob::Pattern>().unwrap().matches(self)
    }
}

#[derive(PartialEq)]
enum ParseState {
    Global,
    Matched,
    Continue,
    Pass,
}

use std::collections::HashMap;
use uucore::{format_usage, InvalidEncodingHandling};

fn parse<T>(lines: T, fmt: &OutputFmt, fp: &str) -> Result<String, String>
where
    T: IntoIterator,
    T::Item: Borrow<str>,
{
    // 1790 > $(dircolors | wc -m)
    let mut result = String::with_capacity(1790);
    match fmt {
        OutputFmt::Shell => result.push_str("LS_COLORS='"),
        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
        OutputFmt::Display => (),
        _ => unreachable!(),
    }

    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
    table.insert("normal", "no");
    table.insert("norm", "no");
    table.insert("file", "fi");
    table.insert("reset", "rs");
    table.insert("dir", "di");
    table.insert("lnk", "ln");
    table.insert("link", "ln");
    table.insert("symlink", "ln");
    table.insert("orphan", "or");
    table.insert("missing", "mi");
    table.insert("fifo", "pi");
    table.insert("pipe", "pi");
    table.insert("sock", "so");
    table.insert("blk", "bd");
    table.insert("block", "bd");
    table.insert("chr", "cd");
    table.insert("char", "cd");
    table.insert("door", "do");
    table.insert("exec", "ex");
    table.insert("left", "lc");
    table.insert("leftcode", "lc");
    table.insert("right", "rc");
    table.insert("rightcode", "rc");
    table.insert("end", "ec");
    table.insert("endcode", "ec");
    table.insert("suid", "su");
    table.insert("setuid", "su");
    table.insert("sgid", "sg");
    table.insert("setgid", "sg");
    table.insert("sticky", "st");
    table.insert("other_writable", "ow");
    table.insert("owr", "ow");
    table.insert("sticky_other_writable", "tw");
    table.insert("owt", "tw");
    table.insert("capability", "ca");
    table.insert("multihardlink", "mh");
    table.insert("clrtoeol", "cl");

    let term = env::var("TERM").unwrap_or_else(|_| "none".to_owned());
    let term = term.as_str();

    let mut state = ParseState::Global;

    for (num, line) in lines.into_iter().enumerate() {
        let num = num + 1;
        let line = line.borrow().purify();
        if line.is_empty() {
            continue;
        }

        let (key, val) = line.split_two();
        if val.is_empty() {
            return Err(format!(
                "{}:{}: invalid line;  missing second token",
                fp.maybe_quote(),
                num
            ));
        }
        let lower = key.to_lowercase();

        if lower == "term" || lower == "colorterm" {
            if term.fnmatch(val) {
                state = ParseState::Matched;
            } else if state != ParseState::Matched {
                state = ParseState::Pass;
            }
        } else {
            if state == ParseState::Matched {
                // prevent subsequent mismatched TERM from
                // cancelling the input
                state = ParseState::Continue;
            }
            if state != ParseState::Pass {
                if key.starts_with('.') {
                    if *fmt == OutputFmt::Display {
                        result.push_str(format!("\x1b[{1}m*{0}\t{1}\x1b[0m\n", key, val).as_str());
                    } else {
                        result.push_str(format!("*{}={}:", key, val).as_str());
                    }
                } else if key.starts_with('*') {
                    if *fmt == OutputFmt::Display {
                        result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", key, val).as_str());
                    } else {
                        result.push_str(format!("{}={}:", key, val).as_str());
                    }
                } else if lower == "options" || lower == "color" || lower == "eightbit" {
                    // Slackware only. Ignore
                } else if let Some(s) = table.get(lower.as_str()) {
                    if *fmt == OutputFmt::Display {
                        result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", s, val).as_str());
                    } else {
                        result.push_str(format!("{}={}:", s, val).as_str());
                    }
                } else {
                    return Err(format!(
                        "{}:{}: unrecognized keyword {}",
                        fp.maybe_quote(),
                        num,
                        key
                    ));
                }
            }
        }
    }

    match fmt {
        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
        OutputFmt::CShell => result.push('\''),
        OutputFmt::Display => {
            // remove latest "\n"
            result.pop();
        }
        _ => unreachable!(),
    }

    Ok(result)
}
<commit_msg>dircolors: update error message<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
// (c) Mitchell Mebane <mitchell.mebane@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) clrtoeol dircolors eightbit endcode fnmatch leftcode multihardlink rightcode setenv sgid suid colorterm

use std::borrow::Borrow;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};

use clap::{crate_version, Arg, Command};
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError, UUsageError};

mod options {
    pub const BOURNE_SHELL: &str = "bourne-shell";
    pub const C_SHELL: &str = "c-shell";
    pub const PRINT_DATABASE: &str = "print-database";
    pub const PRINT_LS_COLORS: &str = "print-ls-colors";
    pub const FILE: &str = "FILE";
}

static USAGE: &str = "{} [OPTION]... [FILE]";
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
static LONG_HELP: &str = "
 If FILE is specified, read it to determine which colors to use for which
 file types and extensions.  Otherwise, a precompiled database is used.
 For details on the format of these files, run 'dircolors --print-database'
";

mod colors;
use self::colors::INTERNAL_DB;

#[derive(PartialEq, Debug)]
pub enum OutputFmt {
    Shell,
    CShell,
    Display,
    Unknown,
}

pub fn guess_syntax() -> OutputFmt {
    use std::path::Path;
    match env::var("SHELL") {
        Ok(ref s) if !s.is_empty() => {
            let shell_path: &Path = s.as_ref();
            if let Some(name) = shell_path.file_name() {
                if name == "csh" || name == "tcsh" {
                    OutputFmt::CShell
                } else {
                    OutputFmt::Shell
                }
            } else {
                OutputFmt::Shell
            }
        }
        _ => OutputFmt::Unknown,
    }
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let matches = uu_app().get_matches_from(&args);

    let files = matches
        .values_of(options::FILE)
        .map_or(vec![], |file_values| file_values.collect());

    // clap provides .conflicts_with / .conflicts_with_all, but we want to
    // manually handle conflicts so we can match the output of GNU coreutils
    if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL))
        && (matches.is_present(options::PRINT_DATABASE)
            || matches.is_present(options::PRINT_LS_COLORS))
    {
        return Err(UUsageError::new(
            1,
            "the options to output non shell syntax,\n\
             and to select a shell syntax are mutually exclusive",
        ));
    }

    if matches.is_present(options::PRINT_DATABASE) && matches.is_present(options::PRINT_LS_COLORS) {
        return Err(UUsageError::new(
            1,
            "options --print-database and --print-ls-colors are mutually exclusive",
        ));
    }

    if matches.is_present(options::PRINT_DATABASE) {
        if !files.is_empty() {
            return Err(UUsageError::new(
                1,
                format!(
                    "extra operand {}\nfile operands cannot be combined with \
                     --print-database (-p)",
                    files[0].quote()
                ),
            ));
        }
        println!("{}", INTERNAL_DB);
        return Ok(());
    }

    let mut out_format = if matches.is_present(options::C_SHELL) {
        OutputFmt::CShell
    } else if matches.is_present(options::BOURNE_SHELL) {
        OutputFmt::Shell
    } else if matches.is_present(options::PRINT_LS_COLORS) {
        OutputFmt::Display
    } else {
        OutputFmt::Unknown
    };

    if out_format == OutputFmt::Unknown {
        match guess_syntax() {
            OutputFmt::Unknown => {
                return Err(USimpleError::new(
                    1,
                    "no SHELL environment variable, and no shell type option given",
                ));
            }
            fmt => out_format = fmt,
        }
    }

    let result;
    if files.is_empty() {
        result = parse(INTERNAL_DB.lines(), &out_format, "");
    } else if files.len() > 1 {
        return Err(UUsageError::new(
            1,
            format!("extra operand {}", files[1].quote()),
        ));
    } else if files[0].eq("-") {
        let fin = BufReader::new(std::io::stdin());
        result = parse(fin.lines().filter_map(Result::ok), &out_format, files[0]);
    } else {
        match File::open(files[0]) {
            Ok(f) => {
                let fin = BufReader::new(f);
                result = parse(fin.lines().filter_map(Result::ok), &out_format, files[0]);
            }
            Err(e) => {
                return Err(USimpleError::new(
                    1,
                    format!("{}: {}", files[0].maybe_quote(), e),
                ));
            }
        }
    }

    match result {
        Ok(s) => {
            println!("{}", s);
            Ok(())
        }
        Err(s) => {
            return Err(USimpleError::new(1, s));
        }
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(SUMMARY)
        .after_help(LONG_HELP)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(options::BOURNE_SHELL)
                .long("sh")
                .short('b')
                .visible_alias("bourne-shell")
                .overrides_with(options::C_SHELL)
                .help("output Bourne shell code to set LS_COLORS")
                .display_order(1),
        )
        .arg(
            Arg::new(options::C_SHELL)
                .long("csh")
                .short('c')
                .visible_alias("c-shell")
                .overrides_with(options::BOURNE_SHELL)
                .help("output C shell code to set LS_COLORS")
                .display_order(2),
        )
        .arg(
            Arg::new(options::PRINT_DATABASE)
                .long("print-database")
                .short('p')
                .help("print the byte counts")
                .display_order(3),
        )
        .arg(
            Arg::new(options::PRINT_LS_COLORS)
                .long("print-ls-colors")
                .help("output fully escaped colors for display")
                .display_order(4),
        )
        .arg(
            Arg::new(options::FILE)
                .hide(true)
                .value_hint(clap::ValueHint::FilePath)
                .multiple_occurrences(true),
        )
}

pub trait StrUtils {
    /// Remove comments and trim whitespace
    fn purify(&self) -> &Self;
    /// Like split_whitespace() but only produce 2 components
    fn split_two(&self) -> (&str, &str);
    fn fnmatch(&self, pattern: &str) -> bool;
}

impl StrUtils for str {
    fn purify(&self) -> &Self {
        let mut line = self;
        for (n, _) in self
            .as_bytes()
            .iter()
            .enumerate()
            .filter(|(_, c)| **c == b'#')
        {
            // Ignore the content after '#'
            // only if it is preceded by at least one whitespace
            match self[..n].chars().last() {
                Some(c) if c.is_whitespace() => {
                    line = &self[..n - c.len_utf8()];
                    break;
                }
                None => {
                    // n == 0
                    line = &self[..0];
                    break;
                }
                _ => (),
            }
        }
        line.trim()
    }

    fn split_two(&self) -> (&str, &str) {
        if let Some(b) = self.find(char::is_whitespace) {
            let key = &self[..b];
            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
                (key, &self[b + e..])
            } else {
                (key, "")
            }
        } else {
            ("", "")
        }
    }

    fn fnmatch(&self, pat: &str) -> bool {
        pat.parse::<glob::Pattern>().unwrap().matches(self)
    }
}

#[derive(PartialEq)]
enum ParseState {
    Global,
    Matched,
    Continue,
    Pass,
}

use std::collections::HashMap;
use uucore::{format_usage, InvalidEncodingHandling};

fn parse<T>(lines: T, fmt: &OutputFmt, fp: &str) -> Result<String, String>
where
    T: IntoIterator,
    T::Item: Borrow<str>,
{
    // 1790 > $(dircolors | wc -m)
    let mut result = String::with_capacity(1790);
    match fmt {
        OutputFmt::Shell => result.push_str("LS_COLORS='"),
        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
        OutputFmt::Display => (),
        _ => unreachable!(),
    }

    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
    table.insert("normal", "no");
    table.insert("norm", "no");
    table.insert("file", "fi");
    table.insert("reset", "rs");
    table.insert("dir", "di");
    table.insert("lnk", "ln");
    table.insert("link", "ln");
    table.insert("symlink", "ln");
    table.insert("orphan", "or");
    table.insert("missing", "mi");
    table.insert("fifo", "pi");
    table.insert("pipe", "pi");
    table.insert("sock", "so");
    table.insert("blk", "bd");
    table.insert("block", "bd");
    table.insert("chr", "cd");
    table.insert("char", "cd");
    table.insert("door", "do");
    table.insert("exec", "ex");
    table.insert("left", "lc");
    table.insert("leftcode", "lc");
    table.insert("right", "rc");
    table.insert("rightcode", "rc");
    table.insert("end", "ec");
    table.insert("endcode", "ec");
    table.insert("suid", "su");
    table.insert("setuid", "su");
    table.insert("sgid", "sg");
    table.insert("setgid", "sg");
    table.insert("sticky", "st");
    table.insert("other_writable", "ow");
    table.insert("owr", "ow");
    table.insert("sticky_other_writable", "tw");
    table.insert("owt", "tw");
    table.insert("capability", "ca");
    table.insert("multihardlink", "mh");
    table.insert("clrtoeol", "cl");

    let term = env::var("TERM").unwrap_or_else(|_| "none".to_owned());
    let term = term.as_str();

    let mut state = ParseState::Global;

    for (num, line) in lines.into_iter().enumerate() {
        let num = num + 1;
        let line = line.borrow().purify();
        if line.is_empty() {
            continue;
        }

        let (key, val) = line.split_two();
        if val.is_empty() {
            return Err(format!(
                "{}:{}: invalid line;  missing second token",
                fp.maybe_quote(),
                num
            ));
        }
        let lower = key.to_lowercase();

        if lower == "term" || lower == "colorterm" {
            if term.fnmatch(val) {
                state = ParseState::Matched;
            } else if state != ParseState::Matched {
                state = ParseState::Pass;
            }
        } else {
            if state == ParseState::Matched {
                // prevent subsequent mismatched TERM from
                // cancelling the input
                state = ParseState::Continue;
            }
            if state != ParseState::Pass {
                if key.starts_with('.') {
                    if *fmt == OutputFmt::Display {
                        result.push_str(format!("\x1b[{1}m*{0}\t{1}\x1b[0m\n", key, val).as_str());
                    } else {
                        result.push_str(format!("*{}={}:", key, val).as_str());
                    }
                } else if key.starts_with('*') {
                    if *fmt == OutputFmt::Display {
                        result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", key, val).as_str());
                    } else {
                        result.push_str(format!("{}={}:", key, val).as_str());
                    }
                } else if lower == "options" || lower == "color" || lower == "eightbit" {
                    // Slackware only. Ignore
                } else if let Some(s) = table.get(lower.as_str()) {
                    if *fmt == OutputFmt::Display {
                        result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", s, val).as_str());
                    } else {
                        result.push_str(format!("{}={}:", s, val).as_str());
                    }
                } else {
                    return Err(format!(
                        "{}:{}: unrecognized keyword {}",
                        fp.maybe_quote(),
                        num,
                        key
                    ));
                }
            }
        }
    }

    match fmt {
        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
        OutputFmt::CShell => result.push('\''),
        OutputFmt::Display => {
            // remove latest "\n"
            result.pop();
        }
        _ => unreachable!(),
    }

    Ok(result)
}
<|endoftext|>


<commit_before>//! Completion tests for use trees.
use expect_test::{expect, Expect};

use crate::tests::completion_list;

fn check(ra_fixture: &str, expect: Expect) {
    let actual = completion_list(ra_fixture);
    expect.assert_eq(&actual)
}

#[test]
fn use_tree_start() {
    cov_mark::check!(unqualified_path_only_modules_in_import);
    check(
        r#"
//- /lib.rs crate:main deps:other_crate
use f$0

struct Foo;
mod foo {}
//- /other_crate/lib.rs crate:other_crate
// nothing here
"#,
        expect![[r#"
            md foo
            md other_crate
            kw self::
            kw super::
            kw crate::
        "#]],
    );
}

#[test]
fn dont_complete_current_use() {
    cov_mark::check!(dont_complete_current_use);
    check(r#"use self::foo$0;"#, expect![[r#""#]]);
    check(
        r#"
mod foo { pub struct S; }
use self::{foo::*, bar$0};
"#,
        expect![[r#"
            st S
            md foo
        "#]],
    );
}

#[test]
fn nested_use_tree() {
    check(
        r#"
mod foo {
    pub mod bar {
        pub struct FooBar;
    }
}
use foo::{bar::$0}
"#,
        expect![[r#"
            st FooBar
        "#]],
    );
    check(
        r#"
mod foo {
    pub mod bar {
        pub struct FooBar;
    }
}
use foo::{$0}
"#,
        expect![[r#"
            kw self
            md bar
        "#]],
    );
}

#[test]
fn deeply_nested_use_tree() {
    check(
        r#"
mod foo {
    pub mod bar {
        pub mod baz {
            pub struct FooBarBaz;
        }
    }
}
use foo::{bar::{baz::$0}}
"#,
        expect![[r#"
            st FooBarBaz
        "#]],
    );
    check(
        r#"
mod foo {
    pub mod bar {
        pub mod baz {
            pub struct FooBarBaz;
        }
    }
}
use foo::{bar::{$0}}
"#,
        expect![[r#"
            kw self
            md baz
        "#]],
    );
}

#[test]
fn plain_qualified_use_tree() {
    check(
        r#"
use foo::$0

mod foo {
    struct Private;
    pub struct Foo;
    macro_rules! foo_ { {} => {} }
    pub use foo_ as foo;
}
struct Bar;
"#,
        expect![[r#"
            st Foo
            ma foo macro_rules! foo_
        "#]],
    );
}

#[test]
fn enum_plain_qualified_use_tree() {
    cov_mark::check!(enum_plain_qualified_use_tree);
    check(
        r#"
use Foo::$0

enum Foo { Variant }
impl Foo {
    const CONST: () = ()
    fn func() {}
}
"#,
        expect![[r#"
            ev Variant ()
        "#]],
    );
}

#[test]
fn self_qualified_use_tree() {
    check(
        r#"
use self::$0

mod foo {}
struct Bar;
"#,
        expect![[r#"
            md foo
            st Bar
        "#]],
    );
}

#[test]
fn super_qualified_use_tree() {
    check(
        r#"
mod bar {
    use super::$0
}

mod foo {}
struct Bar;
"#,
        expect![[r#"
            kw super::
            st Bar
            md bar
            md foo
        "#]],
    );
}

#[test]
fn super_super_qualified_use_tree() {
    check(
        r#"
mod a {
    const A: usize = 0;
    mod b {
        const B: usize = 0;
        mod c { use super::super::$0 }
    }
}
"#,
        expect![[r#"
            kw super::
            md b
            ct A
        "#]],
    );
}

#[test]
fn crate_qualified_use_tree() {
    check(
        r#"
use crate::$0

mod foo {}
struct Bar;
"#,
        expect![[r#"
            md foo
            st Bar
        "#]],
    );
}

#[test]
fn extern_crate_qualified_use_tree() {
    check(
        r#"
//- /lib.rs crate:main deps:other_crate
use other_crate::$0
//- /other_crate/lib.rs crate:other_crate
pub struct Foo;
pub mod foo {}
"#,
        expect![[r#"
            st Foo
            md foo
        "#]],
    );
}

#[test]
fn pub_use_tree() {
    check(
        r#"
pub struct X;
pub mod bar {}
pub use $0;
"#,
        expect![[r#"
            md bar
            kw self::
            kw super::
            kw crate::
        "#]],
    );
}

#[test]
fn use_tree_braces_at_start() {
    check(
        r#"
struct X;
mod bar {}
use {$0};
"#,
        expect![[r#"
            md bar
            kw self::
            kw super::
            kw crate::
        "#]],
    );
}

#[test]
fn impl_prefix_does_not_add_fn_snippet() {
    // regression test for 7222
    check(
        r#"
mod foo {
    pub fn bar(x: u32) {}
}
use self::foo::impl$0
"#,
        expect![[r#"
            fn bar fn(u32)
        "#]],
    );
}
<commit_msg>Add missing test for use completions<commit_after>//! Completion tests for use trees.
use expect_test::{expect, Expect};

use crate::tests::completion_list;

fn check(ra_fixture: &str, expect: Expect) {
    let actual = completion_list(ra_fixture);
    expect.assert_eq(&actual)
}

#[test]
fn use_tree_start() {
    cov_mark::check!(unqualified_path_only_modules_in_import);
    check(
        r#"
//- /lib.rs crate:main deps:other_crate
use f$0

struct Foo;
mod foo {}
//- /other_crate/lib.rs crate:other_crate
// nothing here
"#,
        expect![[r#"
            md foo
            md other_crate
            kw self::
            kw super::
            kw crate::
        "#]],
    );
}

#[test]
fn use_tree_start_abs() {
    cov_mark::check!(use_tree_crate_roots_only);
    check(
        r#"
//- /lib.rs crate:main deps:other_crate
use ::f$0

struct Foo;
mod foo {}
//- /other_crate/lib.rs crate:other_crate
// nothing here
"#,
        expect![[r#"
            md other_crate
        "#]],
    );
}

#[test]
fn dont_complete_current_use() {
    cov_mark::check!(dont_complete_current_use);
    check(r#"use self::foo$0;"#, expect![[r#""#]]);
    check(
        r#"
mod foo { pub struct S; }
use self::{foo::*, bar$0};
"#,
        expect![[r#"
            st S
            md foo
        "#]],
    );
}

#[test]
fn nested_use_tree() {
    check(
        r#"
mod foo {
    pub mod bar {
        pub struct FooBar;
    }
}
use foo::{bar::$0}
"#,
        expect![[r#"
            st FooBar
        "#]],
    );
    check(
        r#"
mod foo {
    pub mod bar {
        pub struct FooBar;
    }
}
use foo::{$0}
"#,
        expect![[r#"
            kw self
            md bar
        "#]],
    );
}

#[test]
fn deeply_nested_use_tree() {
    check(
        r#"
mod foo {
    pub mod bar {
        pub mod baz {
            pub struct FooBarBaz;
        }
    }
}
use foo::{bar::{baz::$0}}
"#,
        expect![[r#"
            st FooBarBaz
        "#]],
    );
    check(
        r#"
mod foo {
    pub mod bar {
        pub mod baz {
            pub struct FooBarBaz;
        }
    }
}
use foo::{bar::{$0}}
"#,
        expect![[r#"
            kw self
            md baz
        "#]],
    );
}

#[test]
fn plain_qualified_use_tree() {
    check(
        r#"
use foo::$0

mod foo {
    struct Private;
    pub struct Foo;
    macro_rules! foo_ { {} => {} }
    pub use foo_ as foo;
}
struct Bar;
"#,
        expect![[r#"
            st Foo
            ma foo macro_rules! foo_
        "#]],
    );
}

#[test]
fn enum_plain_qualified_use_tree() {
    cov_mark::check!(enum_plain_qualified_use_tree);
    check(
        r#"
use Foo::$0

enum Foo { Variant }
impl Foo {
    const CONST: () = ()
    fn func() {}
}
"#,
        expect![[r#"
            ev Variant ()
        "#]],
    );
}

#[test]
fn self_qualified_use_tree() {
    check(
        r#"
use self::$0

mod foo {}
struct Bar;
"#,
        expect![[r#"
            md foo
            st Bar
        "#]],
    );
}

#[test]
fn super_qualified_use_tree() {
    check(
        r#"
mod bar {
    use super::$0
}

mod foo {}
struct Bar;
"#,
        expect![[r#"
            kw super::
            st Bar
            md bar
            md foo
        "#]],
    );
}

#[test]
fn super_super_qualified_use_tree() {
    check(
        r#"
mod a {
    const A: usize = 0;
    mod b {
        const B: usize = 0;
        mod c { use super::super::$0 }
    }
}
"#,
        expect![[r#"
            kw super::
            md b
            ct A
        "#]],
    );
}

#[test]
fn crate_qualified_use_tree() {
    check(
        r#"
use crate::$0

mod foo {}
struct Bar;
"#,
        expect![[r#"
            md foo
            st Bar
        "#]],
    );
}

#[test]
fn extern_crate_qualified_use_tree() {
    check(
        r#"
//- /lib.rs crate:main deps:other_crate
use other_crate::$0
//- /other_crate/lib.rs crate:other_crate
pub struct Foo;
pub mod foo {}
"#,
        expect![[r#"
            st Foo
            md foo
        "#]],
    );
}

#[test]
fn pub_use_tree() {
    check(
        r#"
pub struct X;
pub mod bar {}
pub use $0;
"#,
        expect![[r#"
            md bar
            kw self::
            kw super::
            kw crate::
        "#]],
    );
}

#[test]
fn use_tree_braces_at_start() {
    check(
        r#"
struct X;
mod bar {}
use {$0};
"#,
        expect![[r#"
            md bar
            kw self::
            kw super::
            kw crate::
        "#]],
    );
}

#[test]
fn impl_prefix_does_not_add_fn_snippet() {
    // regression test for 7222
    check(
        r#"
mod foo {
    pub fn bar(x: u32) {}
}
use self::foo::impl$0
"#,
        expect![[r#"
            fn bar fn(u32)
        "#]],
    );
}
<|endoftext|>


<commit_before>// compile-pass

use std::num::NonZeroU8;

const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
const Y: u8 = X.get();

fn main() {
}<commit_msg>Update src/test/ui/consts/const-nonzero.rs<commit_after>// compile-pass

use std::num::NonZeroU8;

const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
const Y: u8 = X.get();

fn main() {
}
<|endoftext|>