<commit_before>// Copyright (c) 2017-2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![deny(bare_trait_objects)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::cast_ptr_alignment)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::verbose_bit_mask)]
#![allow(clippy::unreadable_literal)]
#![allow(clippy::many_single_char_names)]

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

mod common;
mod decoder;
mod error;
mod muxer;
mod stats;

use crate::common::*;
use crate::error::*;
use crate::stats::*;
use rav1e::prelude::*;

use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use crate::muxer::*;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::Write;
use std::sync::Arc;

struct Source<D: Decoder> {
  limit: usize,
  count: usize,
  input: D,
  #[cfg(all(unix, feature = "signal-hook"))]
  exit_requested: Arc<std::sync::atomic::AtomicBool>,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(
    &mut self, ctx: &mut Context<T>, video_info: VideoDetails,
  ) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }

    #[cfg(all(unix, feature = "signal-hook"))]
    {
      if self.exit_requested.load(std::sync::atomic::Ordering::SeqCst) {
        ctx.flush();
        return;
      }
    }

    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!"),
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>, output_file: &mut dyn Muxer, source: &mut Source<D>,
  pass1file: Option<&mut File>, pass2file: Option<&mut File>,
  buffer: &mut [u8], buf_pos: &mut usize,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
) -> Result<Option<Vec<FrameSummary>>, CliError> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let mut pass1file = pass1file;
  let mut pass2file = pass2file;
  // Submit first pass data to pass 2.
  if let Some(passfile) = pass2file.as_mut() {
    loop {
      let mut bytes = ctx.twopass_bytes_needed();
      if bytes == 0 {
        break;
      }
      // Read in some more bytes, if necessary.
      bytes = bytes.min(buffer.len() - *buf_pos);
      if bytes > 0 {
        passfile
          .read_exact(&mut buffer[*buf_pos..*buf_pos + bytes])
          .expect("Could not read frame data from two-pass data file!");
      }
      // And pass them off.
      let consumed = ctx
        .twopass_in(&buffer[*buf_pos..*buf_pos + bytes])
        .expect("Error submitting pass data in second pass.");
      // If the encoder consumed the whole buffer, reset it.
      if consumed >= bytes {
        *buf_pos = 0;
      } else {
        *buf_pos += consumed;
      }
    }
  }
  // Extract first pass data from pass 1.
  // We call this before encoding any frames to ensure we are in 2-pass mode
  //  and to get the placeholder header data.
  if let Some(passfile) = pass1file.as_mut() {
    if let Some(outbuf) = ctx.twopass_out() {
      passfile
        .write_all(outbuf)
        .expect("Unable to write to two-pass data file.");
    }
  }

  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      output_file.write_frame(
        pkt.input_frameno as u64,
        pkt.data.as_ref(),
        pkt.frame_type,
      );
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) =
        (y4m_enc.as_mut(), &pkt.rec)
      {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      if let Some(passfile) = pass1file.as_mut() {
        if let Some(outbuf) = ctx.twopass_out() {
          // The last block of data we get is the summary data that needs to go
          //  at the start of the pass file.
          // Seek to the start so we can write it there.
          passfile
            .seek(std::io::SeekFrom::Start(0))
            .expect("Unable to seek in two-pass data file.");
          passfile
            .write_all(outbuf)
            .expect("Unable to write to two-pass data file.");
        }
      }
      return Ok(None);
    }
    e @ Err(EncoderStatus::Failure) => {
      let _ = e.map_err(|e| e.context("Failed to encode video"))?;
    }
    e @ Err(EncoderStatus::NotReady) => {
      let _ = e.map_err(|e| {
        e.context("Mismanaged handling of two-pass stats data")
      })?;
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Ok(Some(frame_summaries))
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  output: &mut dyn Muxer, source: &mut Source<D>,
  pass1file_name: Option<&String>, pass2file_name: Option<&String>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>,
) -> Result<(), CliError> {
  let mut ctx: Context<T> =
    cfg.new_context().map_err(|e| e.context("Invalid encoder settings"))?;

  let mut pass2file = pass2file_name.map(|f| {
    File::open(f).unwrap_or_else(|_| {
      panic!("Unable to open \"{}\" for reading two-pass data.", f)
    })
  });
  let mut pass1file = pass1file_name.map(|f| {
    File::create(f).unwrap_or_else(|_| {
      panic!("Unable to open \"{}\" for writing two-pass data.", f)
    })
  });

  let mut buffer: [u8; 80] = [0; 80];
  let mut buf_pos = 0;

  while let Some(frame_info) = process_frame(
    &mut ctx,
    &mut *output,
    source,
    pass1file.as_mut(),
    pass2file.as_mut(),
    &mut buffer,
    &mut buf_pos,
    y4m_enc.as_mut(),
  )? {
    for frame in frame_info {
      progress.add_frame(frame.clone());
      if verbose {
        info!("{} - {}", frame, progress);
      } else {
        // Print a one-line progress indicator that overrides itself with every update
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }
  if !verbose {
    // Clear out the temporary progress indicator
    eprint!("\r");
  }
  progress.print_summary(verbose);
  Ok(())
}

fn main() {
  #[cfg(feature = "tracing")]
  use rust_hawktracer::*;
  better_panic::install();
  init_logger();

  #[cfg(feature = "tracing")]
  let instance = HawktracerInstance::new();
  #[cfg(feature = "tracing")]
  let _listener = instance.create_listener(HawktracerListenerType::ToFile {
    file_path: "trace.bin".into(),
    buffer_size: 4096,
  });

  match run() {
    Ok(()) => {}
    Err(e) => error::print_error(&e),
  }
}

fn init_logger() {
  if env::var("RUST_LOG").is_err() {
    env::set_var("RUST_LOG", "info");
  }
  pretty_env_logger::init();
}

fn run() -> Result<(), error::CliError> {
  let mut cli = parse_cli()?;
  let mut y4m_dec =
    y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(
          video_info.time_base.den as usize,
          video_info.time_base.num as usize,
        ),
      )
      .with_colorspace(y4m_dec.get_colorspace())
      .write_header(rec)
      .unwrap(),
    ),
    None => None,
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;

  // If no pixel range is specified via CLI, assume limited,
  // as it is the default for the Y4M format.
  if !cli.color_range_specified {
    cli.enc.pixel_range = PixelRange::Limited;
  }

  if !cli.override_time_base {
    cli.enc.time_base = video_info.time_base;
  }

  let cfg = Config { enc: cli.enc, threads: cli.threads };

  cli.io.output.write_header(
    video_info.width,
    video_info.height,
    cli.enc.time_base.den as usize,
    cli.enc.time_base.num as usize,
  );

  info!(
    "Using y4m decoder: {}x{}p @ {}/{} fps, {}, {}-bit",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num,
    video_info.chroma_sampling,
    video_info.bit_depth
  );
  info!("Encoding settings: {}", cfg.enc);

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
    cfg.enc.show_psnr,
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  #[cfg(all(unix, feature = "signal-hook"))]
  let exit_requested = {
    use std::sync::atomic::*;
    let e = Arc::new(AtomicBool::from(false));

    fn setup_signal(sig: i32, e: Arc<AtomicBool>) {
      unsafe {
        signal_hook::register(sig, move || {
          if e.load(Ordering::SeqCst) {
            std::process::exit(128 + sig);
          }
          e.store(true, Ordering::SeqCst);
          info!("Exit requested, flushing.");
        })
        .expect("Cannot register the signal hooks");
      }
    }

    setup_signal(signal_hook::SIGTERM, e.clone());
    setup_signal(signal_hook::SIGQUIT, e.clone());
    setup_signal(signal_hook::SIGINT, e.clone());

    e
  };

  #[cfg(all(unix, feature = "signal-hook"))]
  let mut source =
    Source { limit: cli.limit, input: y4m_dec, count: 0, exit_requested };
  #[cfg(not(all(unix, feature = "signal-hook")))]
  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg,
      cli.verbose,
      progress,
      &mut *cli.io.output,
      &mut source,
      cli.pass1file_name.as_ref(),
      cli.pass2file_name.as_ref(),
      y4m_enc,
    )?
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg,
      cli.verbose,
      progress,
      &mut *cli.io.output,
      &mut source,
      cli.pass1file_name.as_ref(),
      cli.pass2file_name.as_ref(),
      y4m_enc,
    )?
  }

  Ok(())
}
<commit_msg>Relax the y4m allocation limit<commit_after>// Copyright (c) 2017-2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![deny(bare_trait_objects)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::cast_ptr_alignment)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::verbose_bit_mask)]
#![allow(clippy::unreadable_literal)]
#![allow(clippy::many_single_char_names)]

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

mod common;
mod decoder;
mod error;
mod muxer;
mod stats;

use crate::common::*;
use crate::error::*;
use crate::stats::*;
use rav1e::prelude::*;

use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use crate::muxer::*;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::Write;
use std::sync::Arc;

struct Source<D: Decoder> {
  limit: usize,
  count: usize,
  input: D,
  #[cfg(all(unix, feature = "signal-hook"))]
  exit_requested: Arc<std::sync::atomic::AtomicBool>,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(
    &mut self, ctx: &mut Context<T>, video_info: VideoDetails,
  ) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }

    #[cfg(all(unix, feature = "signal-hook"))]
    {
      if self.exit_requested.load(std::sync::atomic::Ordering::SeqCst) {
        ctx.flush();
        return;
      }
    }

    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!"),
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>, output_file: &mut dyn Muxer, source: &mut Source<D>,
  pass1file: Option<&mut File>, pass2file: Option<&mut File>,
  buffer: &mut [u8], buf_pos: &mut usize,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
) -> Result<Option<Vec<FrameSummary>>, CliError> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let mut pass1file = pass1file;
  let mut pass2file = pass2file;
  // Submit first pass data to pass 2.
  if let Some(passfile) = pass2file.as_mut() {
    loop {
      let mut bytes = ctx.twopass_bytes_needed();
      if bytes == 0 {
        break;
      }
      // Read in some more bytes, if necessary.
      bytes = bytes.min(buffer.len() - *buf_pos);
      if bytes > 0 {
        passfile
          .read_exact(&mut buffer[*buf_pos..*buf_pos + bytes])
          .expect("Could not read frame data from two-pass data file!");
      }
      // And pass them off.
      let consumed = ctx
        .twopass_in(&buffer[*buf_pos..*buf_pos + bytes])
        .expect("Error submitting pass data in second pass.");
      // If the encoder consumed the whole buffer, reset it.
      if consumed >= bytes {
        *buf_pos = 0;
      } else {
        *buf_pos += consumed;
      }
    }
  }
  // Extract first pass data from pass 1.
  // We call this before encoding any frames to ensure we are in 2-pass mode
  //  and to get the placeholder header data.
  if let Some(passfile) = pass1file.as_mut() {
    if let Some(outbuf) = ctx.twopass_out() {
      passfile
        .write_all(outbuf)
        .expect("Unable to write to two-pass data file.");
    }
  }

  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      output_file.write_frame(
        pkt.input_frameno as u64,
        pkt.data.as_ref(),
        pkt.frame_type,
      );
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) =
        (y4m_enc.as_mut(), &pkt.rec)
      {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      if let Some(passfile) = pass1file.as_mut() {
        if let Some(outbuf) = ctx.twopass_out() {
          // The last block of data we get is the summary data that needs to go
          //  at the start of the pass file.
          // Seek to the start so we can write it there.
          passfile
            .seek(std::io::SeekFrom::Start(0))
            .expect("Unable to seek in two-pass data file.");
          passfile
            .write_all(outbuf)
            .expect("Unable to write to two-pass data file.");
        }
      }
      return Ok(None);
    }
    e @ Err(EncoderStatus::Failure) => {
      let _ = e.map_err(|e| e.context("Failed to encode video"))?;
    }
    e @ Err(EncoderStatus::NotReady) => {
      let _ = e.map_err(|e| {
        e.context("Mismanaged handling of two-pass stats data")
      })?;
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Ok(Some(frame_summaries))
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  output: &mut dyn Muxer, source: &mut Source<D>,
  pass1file_name: Option<&String>, pass2file_name: Option<&String>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>,
) -> Result<(), CliError> {
  let mut ctx: Context<T> =
    cfg.new_context().map_err(|e| e.context("Invalid encoder settings"))?;

  let mut pass2file = pass2file_name.map(|f| {
    File::open(f).unwrap_or_else(|_| {
      panic!("Unable to open \"{}\" for reading two-pass data.", f)
    })
  });
  let mut pass1file = pass1file_name.map(|f| {
    File::create(f).unwrap_or_else(|_| {
      panic!("Unable to open \"{}\" for writing two-pass data.", f)
    })
  });

  let mut buffer: [u8; 80] = [0; 80];
  let mut buf_pos = 0;

  while let Some(frame_info) = process_frame(
    &mut ctx,
    &mut *output,
    source,
    pass1file.as_mut(),
    pass2file.as_mut(),
    &mut buffer,
    &mut buf_pos,
    y4m_enc.as_mut(),
  )? {
    for frame in frame_info {
      progress.add_frame(frame.clone());
      if verbose {
        info!("{} - {}", frame, progress);
      } else {
        // Print a one-line progress indicator that overrides itself with every update
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }
  if !verbose {
    // Clear out the temporary progress indicator
    eprint!("\r");
  }
  progress.print_summary(verbose);
  Ok(())
}

fn main() {
  #[cfg(feature = "tracing")]
  use rust_hawktracer::*;
  better_panic::install();
  init_logger();

  #[cfg(feature = "tracing")]
  let instance = HawktracerInstance::new();
  #[cfg(feature = "tracing")]
  let _listener = instance.create_listener(HawktracerListenerType::ToFile {
    file_path: "trace.bin".into(),
    buffer_size: 4096,
  });

  match run() {
    Ok(()) => {}
    Err(e) => error::print_error(&e),
  }
}

fn init_logger() {
  if env::var("RUST_LOG").is_err() {
    env::set_var("RUST_LOG", "info");
  }
  pretty_env_logger::init();
}

fn run() -> Result<(), error::CliError> {
  let mut cli = parse_cli()?;
  // Maximum frame size by specification + maximum y4m header
  let limit = y4m::Limits { bytes: 64 * 64 * 4096 * 2304 + 1024 };
  let mut y4m_dec = y4m::Decoder::new_with_limits(&mut cli.io.input, limit)
    .expect("cannot decode the input");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(
          video_info.time_base.den as usize,
          video_info.time_base.num as usize,
        ),
      )
      .with_colorspace(y4m_dec.get_colorspace())
      .write_header(rec)
      .unwrap(),
    ),
    None => None,
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;

  // If no pixel range is specified via CLI, assume limited,
  // as it is the default for the Y4M format.
  if !cli.color_range_specified {
    cli.enc.pixel_range = PixelRange::Limited;
  }

  if !cli.override_time_base {
    cli.enc.time_base = video_info.time_base;
  }

  let cfg = Config { enc: cli.enc, threads: cli.threads };

  cli.io.output.write_header(
    video_info.width,
    video_info.height,
    cli.enc.time_base.den as usize,
    cli.enc.time_base.num as usize,
  );

  info!(
    "Using y4m decoder: {}x{}p @ {}/{} fps, {}, {}-bit",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num,
    video_info.chroma_sampling,
    video_info.bit_depth
  );
  info!("Encoding settings: {}", cfg.enc);

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
    cfg.enc.show_psnr,
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  #[cfg(all(unix, feature = "signal-hook"))]
  let exit_requested = {
    use std::sync::atomic::*;
    let e = Arc::new(AtomicBool::from(false));

    fn setup_signal(sig: i32, e: Arc<AtomicBool>) {
      unsafe {
        signal_hook::register(sig, move || {
          if e.load(Ordering::SeqCst) {
            std::process::exit(128 + sig);
          }
          e.store(true, Ordering::SeqCst);
          info!("Exit requested, flushing.");
        })
        .expect("Cannot register the signal hooks");
      }
    }

    setup_signal(signal_hook::SIGTERM, e.clone());
    setup_signal(signal_hook::SIGQUIT, e.clone());
    setup_signal(signal_hook::SIGINT, e.clone());

    e
  };

  #[cfg(all(unix, feature = "signal-hook"))]
  let mut source =
    Source { limit: cli.limit, input: y4m_dec, count: 0, exit_requested };
  #[cfg(not(all(unix, feature = "signal-hook")))]
  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg,
      cli.verbose,
      progress,
      &mut *cli.io.output,
      &mut source,
      cli.pass1file_name.as_ref(),
      cli.pass2file_name.as_ref(),
      y4m_enc,
    )?
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg,
      cli.verbose,
      progress,
      &mut *cli.io.output,
      &mut source,
      cli.pass1file_name.as_ref(),
      cli.pass2file_name.as_ref(),
      y4m_enc,
    )?
  }

  Ok(())
}
<|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_MAXIMIZED, VIEW_ACTIVATED, VIEW_RESIZING, VIEW_FULLSCREEN,
                     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, FocusError};
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() {
        let result = tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
                .map(|_| tree.layout_active_of(ContainerType::Output))
        });
        match result {
            // If the output exists, we just couldn't add it to the tree because
            // it's already there. That's OK
            Ok(_) | Err(TreeError::OutputExists(_)) => true,
            _ => false
        }
    } 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 {
    debug!("view_created: {:?}: \"{}\"", view, view.get_title());
    if view.get_class().as_str() == "Background" {
        debug!("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);
        if let Ok(mut tree) = try_lock_tree() {
            let outputs = tree.outputs();
            return tree.add_background(view, outputs.as_slice()).is_ok();
        }
        return false
    }
    if let Ok(mut tree) = try_lock_tree() {
        let result = tree.add_view(view).and_then(|_| {
            view.set_state(VIEW_MAXIMIZED, true);
            match tree.set_active_view(view) {
                // If blocked by fullscreen, we don't focus on purpose
                Err(TreeError::Focus(FocusError::BlockedByFullscreen(_, _))) => Ok(()),
                result => result
            }
        });
        if result.is_err() {
            warn!("Could not add {:?}. Reason: {:?}", view, result);
        }
        result.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, toggle: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    if state == VIEW_FULLSCREEN {
        if let Ok(mut tree) = try_lock_tree() {
            if let Some(id) = tree.lookup_view(view) {
                tree.set_fullscreen(id, toggle)
                    .expect("The ID was related to a non-view, somehow!");
                match tree.container_in_active_workspace(id) {
                    Ok(true) => {
                        tree.layout_active_of(ContainerType::Workspace)
                            .unwrap_or_else(|err| {
                                error!("Could not layout active workspace for view {:?}: {:?}",
                                        view, err)
                            });
                    },
                    Ok(false) => {},
                    Err(err) => error!("Could not set {:?} fullscreen: {:?}", view, err)
                }
            } else {
                warn!("Could not find view {:?} in tree", view);
            }
        }
    }
}

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) {
            info!("[key] Found an action for {}, blocking event", 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 {
        let mouse_mod = keys::mouse_modifier();
        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(mouse_mod) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            info!("User right clicked w/ mods \"{:?}\" on {:?}", mods, view);
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            if mods.mods.contains(mouse_mod) {
                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() {
            let unknown = format!("unknown ({})", button);
            info!("User released {:?} mouse button",
                  match button {
                      RIGHT_CLICK => "right",
                      LEFT_CLICK => "left",
                      _ => unknown.as_str()
                  });
            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 extern fn view_pre_render(view: WlcView) {
    if let Ok(mut tree) = try_lock_tree() {
        tree.render_borders(view).unwrap_or_else(|err| {
            warn!("Error while rendering borders: {:?}", err);
        })
    }
}

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);
    callback::view_render_pre(view_pre_render);
    trace!("Registered wlc callbacks");
}
<commit_msg>Don't warn if view not found for rendering<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_MAXIMIZED, VIEW_ACTIVATED, VIEW_RESIZING, VIEW_FULLSCREEN,
                     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, FocusError};
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() {
        let result = tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
                .map(|_| tree.layout_active_of(ContainerType::Output))
        });
        match result {
            // If the output exists, we just couldn't add it to the tree because
            // it's already there. That's OK
            Ok(_) | Err(TreeError::OutputExists(_)) => true,
            _ => false
        }
    } 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 {
    debug!("view_created: {:?}: \"{}\"", view, view.get_title());
    if view.get_class().as_str() == "Background" {
        debug!("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);
        if let Ok(mut tree) = try_lock_tree() {
            let outputs = tree.outputs();
            return tree.add_background(view, outputs.as_slice()).is_ok();
        }
        return false
    }
    if let Ok(mut tree) = try_lock_tree() {
        let result = tree.add_view(view).and_then(|_| {
            view.set_state(VIEW_MAXIMIZED, true);
            match tree.set_active_view(view) {
                // If blocked by fullscreen, we don't focus on purpose
                Err(TreeError::Focus(FocusError::BlockedByFullscreen(_, _))) => Ok(()),
                result => result
            }
        });
        if result.is_err() {
            warn!("Could not add {:?}. Reason: {:?}", view, result);
        }
        result.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, toggle: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    if state == VIEW_FULLSCREEN {
        if let Ok(mut tree) = try_lock_tree() {
            if let Some(id) = tree.lookup_view(view) {
                tree.set_fullscreen(id, toggle)
                    .expect("The ID was related to a non-view, somehow!");
                match tree.container_in_active_workspace(id) {
                    Ok(true) => {
                        tree.layout_active_of(ContainerType::Workspace)
                            .unwrap_or_else(|err| {
                                error!("Could not layout active workspace for view {:?}: {:?}",
                                        view, err)
                            });
                    },
                    Ok(false) => {},
                    Err(err) => error!("Could not set {:?} fullscreen: {:?}", view, err)
                }
            } else {
                warn!("Could not find view {:?} in tree", view);
            }
        }
    }
}

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) {
            info!("[key] Found an action for {}, blocking event", 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 {
        let mouse_mod = keys::mouse_modifier();
        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(mouse_mod) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            info!("User right clicked w/ mods \"{:?}\" on {:?}", mods, view);
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            if mods.mods.contains(mouse_mod) {
                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() {
            let unknown = format!("unknown ({})", button);
            info!("User released {:?} mouse button",
                  match button {
                      RIGHT_CLICK => "right",
                      LEFT_CLICK => "left",
                      _ => unknown.as_str()
                  });
            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 extern fn view_pre_render(view: WlcView) {
    if let Ok(mut tree) = try_lock_tree() {
        tree.render_borders(view).unwrap_or_else(|err| {
            match err {
                // TODO Only filter if background or bar
                TreeError::ViewNotFound(_) => {},
                err => warn!("Error while rendering borders: {:?}", err)
            }
        })
    }
}

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);
    callback::view_render_pre(view_pre_render);
    trace!("Registered wlc callbacks");
}
<|endoftext|>


<commit_before>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate regex;
extern crate rustc_serialize;
extern crate semver;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::env;
use std::io;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use core::shell::ColorConfig::{Auto};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub fn execute_main_without_stdin<T, V>(
                                      exec: fn(T, &Config) -> CliResult<Option<V>>,
                                      options_first: bool,
                                      usage: &str)
    where V: Encodable, T: Decodable
{
    process::<V, _>(|rest, shell| {
        call_main_without_stdin(exec, shell, usage, rest, options_first)
    });
}

pub fn call_main_without_stdin<T, V>(
            exec: fn(T, &Config) -> CliResult<Option<V>>,
            shell: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable
{
    let flags = try!(flags_from_args::<T>(usage, args, options_first));
    exec(flags, shell)
}

fn process<V, F>(mut callback: F)
    where F: FnMut(&[String], &Config) -> CliResult<Option<V>>,
          V: Encodable
{
    let mut config = None;
    let result = (|| {
        config = Some(try!(Config::default()));
        let args: Vec<_> = try!(env::args_os().map(|s| {
            s.into_string().map_err(|s| {
                human(format!("invalid unicode in argument: {:?}", s))
            })
        }).collect());
        callback(&args, config.as_ref().unwrap())
    })();
    let mut verbose_shell = shell(Verbose, Auto);
    let mut shell = config.as_ref().map(|s| s.shell());
    let shell = shell.as_mut().map(|s| &mut **s).unwrap_or(&mut verbose_shell);
    process_executed(result, shell)
}

pub fn process_executed<T>(result: CliResult<Option<T>>, shell: &mut MultiShell)
    where T: Encodable
{
    match result {
        Err(e) => handle_error(e, shell),
        Ok(Some(encodable)) => {
            let encoded = json::encode(&encodable).unwrap();
            println!("{}", encoded);
        }
        Ok(None) => {}
    }
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<T>(usage: &str, args: &[String],
                          options_first: bool) -> CliResult<T>
    where T: Decodable
{
    let docopt = Docopt::new(usage).unwrap()
                                   .options_first(options_first)
                                   .argv(args.iter().map(|s| &s[..]))
                                   .help(true);
    docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })
}
<commit_msg>Minor, rename function parameter<commit_after>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate regex;
extern crate rustc_serialize;
extern crate semver;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::env;
use std::io;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use core::shell::ColorConfig::{Auto};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub fn execute_main_without_stdin<T, V>(
                                      exec: fn(T, &Config) -> CliResult<Option<V>>,
                                      options_first: bool,
                                      usage: &str)
    where V: Encodable, T: Decodable
{
    process::<V, _>(|rest, config| {
        call_main_without_stdin(exec, config, usage, rest, options_first)
    });
}

pub fn call_main_without_stdin<T, V>(
            exec: fn(T, &Config) -> CliResult<Option<V>>,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable
{
    let flags = try!(flags_from_args::<T>(usage, args, options_first));
    exec(flags, config)
}

fn process<V, F>(mut callback: F)
    where F: FnMut(&[String], &Config) -> CliResult<Option<V>>,
          V: Encodable
{
    let mut config = None;
    let result = (|| {
        config = Some(try!(Config::default()));
        let args: Vec<_> = try!(env::args_os().map(|s| {
            s.into_string().map_err(|s| {
                human(format!("invalid unicode in argument: {:?}", s))
            })
        }).collect());
        callback(&args, config.as_ref().unwrap())
    })();
    let mut verbose_shell = shell(Verbose, Auto);
    let mut shell = config.as_ref().map(|s| s.shell());
    let shell = shell.as_mut().map(|s| &mut **s).unwrap_or(&mut verbose_shell);
    process_executed(result, shell)
}

pub fn process_executed<T>(result: CliResult<Option<T>>, shell: &mut MultiShell)
    where T: Encodable
{
    match result {
        Err(e) => handle_error(e, shell),
        Ok(Some(encodable)) => {
            let encoded = json::encode(&encodable).unwrap();
            println!("{}", encoded);
        }
        Ok(None) => {}
    }
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<T>(usage: &str, args: &[String],
                          options_first: bool) -> CliResult<T>
    where T: Decodable
{
    let docopt = Docopt::new(usage).unwrap()
                                   .options_first(options_first)
                                   .argv(args.iter().map(|s| &s[..]))
                                   .help(true);
    docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })
}
<|endoftext|>


<commit_before>use super::utils;

use clap::{arg, error::Error, error::ErrorKind, value_parser, Arg, Command};

#[track_caller]
fn assert_error<F: clap::error::ErrorFormatter>(
    err: Error<F>,
    expected_kind: ErrorKind,
    expected_output: &str,
    stderr: bool,
) {
    let actual_output = err.to_string();
    assert_eq!(
        stderr,
        err.use_stderr(),
        "Should Use STDERR failed. Should be {} but is {}",
        stderr,
        err.use_stderr()
    );
    assert_eq!(expected_kind, err.kind());
    utils::assert_eq(expected_output, actual_output)
}

#[test]
fn app_error() {
    static MESSAGE: &str = "error: Failed for mysterious reasons

Usage: test [OPTIONS] --all

For more information try '--help'
";
    let cmd = Command::new("test")
        .arg(
            Arg::new("all")
                .short('a')
                .long("all")
                .required(true)
                .action(clap::ArgAction::SetTrue)
                .help("Also do versioning for private crates (will not be published)"),
        )
        .arg(
            Arg::new("exact")
                .long("exact")
                .help("Specify inter dependency version numbers exactly with `=`"),
        )
        .arg(
            Arg::new("no_git_commit")
                .long("no-git-commit")
                .help("Do not commit version changes"),
        )
        .arg(
            Arg::new("no_git_push")
                .long("no-git-push")
                .help("Do not push generated commit and tags to git remote"),
        );
    let mut cmd = cmd;
    let expected_kind = ErrorKind::InvalidValue;
    let err = cmd.error(expected_kind, "Failed for mysterious reasons");
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
fn value_validation_has_newline() {
    let res = Command::new("test")
        .arg(
            arg!(<PORT>)
                .value_parser(value_parser!(usize))
                .help("Network port to use"),
        )
        .try_get_matches_from(["test", "foo"]);

    assert!(res.is_err());
    let err = res.unwrap_err();
    assert!(
        err.to_string().ends_with('\n'),
        "Errors should have a trailing newline, got {:?}",
        err.to_string()
    );
}

#[test]
fn kind_prints_help() {
    let cmd = Command::new("test");
    let res = cmd
        .try_get_matches_from(["test", "--help"])
        .map_err(|e| e.apply::<clap::error::KindFormatter>());
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::DisplayHelp;
    static MESSAGE: &str = "\
Usage: test

Options:
  -h, --help  Print help information
";
    assert_error(err, expected_kind, MESSAGE, false);
}

#[test]
fn kind_formats_validation_error() {
    let cmd = Command::new("test");
    let res = cmd
        .try_get_matches_from(["test", "unused"])
        .map_err(|e| e.apply::<clap::error::KindFormatter>());
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found an argument which wasn't expected or isn't valid in this context
";
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
#[cfg(feature = "error-context")]
fn rich_formats_validation_error() {
    let cmd = Command::new("test");
    let res = cmd.try_get_matches_from(["test", "unused"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found argument 'unused' which wasn't expected, or isn't valid in this context

Usage: test

For more information try '--help'
";
    assert_error(err, expected_kind, MESSAGE, true);
}
<commit_msg>test(error): Show good/bad trailing suggestions<commit_after>use super::utils;

use clap::{arg, error::Error, error::ErrorKind, value_parser, Arg, Command};

#[track_caller]
fn assert_error<F: clap::error::ErrorFormatter>(
    err: Error<F>,
    expected_kind: ErrorKind,
    expected_output: &str,
    stderr: bool,
) {
    let actual_output = err.to_string();
    assert_eq!(
        stderr,
        err.use_stderr(),
        "Should Use STDERR failed. Should be {} but is {}",
        stderr,
        err.use_stderr()
    );
    assert_eq!(expected_kind, err.kind());
    utils::assert_eq(expected_output, actual_output)
}

#[test]
fn app_error() {
    static MESSAGE: &str = "error: Failed for mysterious reasons

Usage: test [OPTIONS] --all

For more information try '--help'
";
    let cmd = Command::new("test")
        .arg(
            Arg::new("all")
                .short('a')
                .long("all")
                .required(true)
                .action(clap::ArgAction::SetTrue)
                .help("Also do versioning for private crates (will not be published)"),
        )
        .arg(
            Arg::new("exact")
                .long("exact")
                .help("Specify inter dependency version numbers exactly with `=`"),
        )
        .arg(
            Arg::new("no_git_commit")
                .long("no-git-commit")
                .help("Do not commit version changes"),
        )
        .arg(
            Arg::new("no_git_push")
                .long("no-git-push")
                .help("Do not push generated commit and tags to git remote"),
        );
    let mut cmd = cmd;
    let expected_kind = ErrorKind::InvalidValue;
    let err = cmd.error(expected_kind, "Failed for mysterious reasons");
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
fn value_validation_has_newline() {
    let res = Command::new("test")
        .arg(
            arg!(<PORT>)
                .value_parser(value_parser!(usize))
                .help("Network port to use"),
        )
        .try_get_matches_from(["test", "foo"]);

    assert!(res.is_err());
    let err = res.unwrap_err();
    assert!(
        err.to_string().ends_with('\n'),
        "Errors should have a trailing newline, got {:?}",
        err.to_string()
    );
}

#[test]
fn kind_prints_help() {
    let cmd = Command::new("test");
    let res = cmd
        .try_get_matches_from(["test", "--help"])
        .map_err(|e| e.apply::<clap::error::KindFormatter>());
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::DisplayHelp;
    static MESSAGE: &str = "\
Usage: test

Options:
  -h, --help  Print help information
";
    assert_error(err, expected_kind, MESSAGE, false);
}

#[test]
fn kind_formats_validation_error() {
    let cmd = Command::new("test");
    let res = cmd
        .try_get_matches_from(["test", "unused"])
        .map_err(|e| e.apply::<clap::error::KindFormatter>());
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found an argument which wasn't expected or isn't valid in this context
";
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
#[cfg(feature = "error-context")]
fn rich_formats_validation_error() {
    let cmd = Command::new("test");
    let res = cmd.try_get_matches_from(["test", "unused"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found argument 'unused' which wasn't expected, or isn't valid in this context

Usage: test

For more information try '--help'
";
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
#[cfg(feature = "error-context")]
fn suggest_trailing() {
    let cmd = Command::new("rg").arg(arg!([PATTERN]));

    let res = cmd.try_get_matches_from(["rg", "--foo"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found argument '--foo' which wasn't expected, or isn't valid in this context

  If you tried to supply '--foo' as a value rather than a flag, use '-- --foo'

Usage: rg [PATTERN]

For more information try '--help'
";
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
#[cfg(feature = "error-context")]
fn trailing_already_in_use() {
    let cmd = Command::new("rg").arg(arg!([PATTERN]));

    let res = cmd.try_get_matches_from(["rg", "--", "--foo", "--foo"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found argument '--foo' which wasn't expected, or isn't valid in this context

  If you tried to supply '--foo' as a value rather than a flag, use '-- --foo'

Usage: rg [PATTERN]

For more information try '--help'
";
    assert_error(err, expected_kind, MESSAGE, true);
}

#[test]
#[cfg(feature = "error-context")]
fn cant_use_trailing() {
    let cmd = Command::new("test");

    let res = cmd.try_get_matches_from(["test", "--foo"]);
    assert!(res.is_err());
    let err = res.unwrap_err();
    let expected_kind = ErrorKind::UnknownArgument;
    static MESSAGE: &str = "\
error: Found argument '--foo' which wasn't expected, or isn't valid in this context

  If you tried to supply '--foo' as a value rather than a flag, use '-- --foo'

Usage: test

For more information try '--help'
";
    assert_error(err, expected_kind, MESSAGE, true);
}
<|endoftext|>


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

const CHARS_PER_LINE: usize = 78;
const SPACE: u8 = 32;
const LF: u8 = 10;

// This is a *very* naive algorithm. It assumes the cursor is
// currently at column 0, and that the string to be printed is
// ASCII, among other things. It's good enough for our needs
// and much more lightweight than the current crates.io
// alternative, `textwrap`, which has a lot of dependencies.
pub fn writeln_with_wrapping(s: &str) {
  let stdout = io::stdout();
  let mut handle = stdout.lock();
  let bytes = s.as_bytes();
  let mut column = 0;
  let mut last_space = 0;
  let mut i = 0;

  for &c in bytes.iter() {
    i += 1;
    if c == SPACE || c == LF {
      handle.write(&bytes[last_space..i]).unwrap();
      if c == SPACE {
        column += i - last_space;
      } else {
        column = 0;
      }
      last_space = i;
    }
    if column + (i - last_space) > CHARS_PER_LINE {
      handle.write(b"\n").unwrap();
      column = 0;
    }
  }

  handle.write(&bytes[last_space..i]).unwrap();
  handle.write(b"\n").unwrap();
}
<commit_msg>Make word wrap support words longer than CHARS_PER_LINE.<commit_after>use std::io::{self, Write};

const CHARS_PER_LINE: usize = 78;
const SPACE: u8 = 32;
const LF: u8 = 10;

// This is a *very* naive algorithm. It assumes the cursor is
// currently at column 0, and that the string to be printed is
// ASCII, among other things. It's good enough for our needs
// and much more lightweight than the current crates.io
// alternative, `textwrap`, which has a lot of dependencies.
pub fn writeln_with_wrapping(s: &str) {
  let stdout = io::stdout();
  let mut handle = stdout.lock();
  let bytes = s.as_bytes();
  let mut column = 0;
  let mut last_space = 0;
  let mut i = 0;

  for &c in bytes.iter() {
    i += 1;
    if c == SPACE || c == LF {
      handle.write(&bytes[last_space..i]).unwrap();
      if c == SPACE {
        column += i - last_space;
      } else {
        column = 0;
      }
      last_space = i;
    }
    if column + (i - last_space) >= CHARS_PER_LINE {
      if column == 0 {
        // Ack, we've got a really long word that exceeds the
        // length of a single line. Just write it out, breaking
        // it at the end of the line.
        handle.write(&bytes[last_space..i]).unwrap();
        last_space = i;
      }
      handle.write(b"\n").unwrap();
      column = 0;
    }
  }

  handle.write(&bytes[last_space..i]).unwrap();
  handle.write(b"\n").unwrap();
}
<|endoftext|>


<commit_before>// Bitcoin secp256k1 bindings
// Written in 2014 by
//   Dawid Ciężarkiewicz
//   Andrew Poelstra
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! Constants

/// The size (in bytes) of a nonce
pub static NONCE_SIZE: uint = 32;

/// The size (in bytes) of a secret key
pub static SECRET_KEY_SIZE: uint = 32;

/// The size (in bytes) of an uncompressed public key
pub static UNCOMPRESSED_PUBLIC_KEY_SIZE: uint = 65;

/// The size (in bytes) of a compressed public key
pub static COMPRESSED_PUBLIC_KEY_SIZE: uint = 33;

/// The maximum size of a signature
pub static MAX_SIGNATURE_SIZE: uint = 72;

/// The maximum size of a compact signature
pub static MAX_COMPACT_SIGNATURE_SIZE: uint = 64;

<commit_msg>Add curve order and generator coordinates to constants<commit_after>// Bitcoin secp256k1 bindings
// Written in 2014 by
//   Dawid Ciężarkiewicz
//   Andrew Poelstra
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! Constants

/// The size (in bytes) of a nonce
pub static NONCE_SIZE: uint = 32;

/// The size (in bytes) of a secret key
pub static SECRET_KEY_SIZE: uint = 32;

/// The size (in bytes) of an uncompressed public key
pub static UNCOMPRESSED_PUBLIC_KEY_SIZE: uint = 65;

/// The size (in bytes) of a compressed public key
pub static COMPRESSED_PUBLIC_KEY_SIZE: uint = 33;

/// The maximum size of a signature
pub static MAX_SIGNATURE_SIZE: uint = 72;

/// The maximum size of a compact signature
pub static MAX_COMPACT_SIGNATURE_SIZE: uint = 64;

/// The order of the secp256k1 curve
pub static CURVE_ORDER: [u8, ..32] = [
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
    0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
    0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
];

/// The X coordinate of the generator
pub static GENERATOR_X: [u8, ..32] = [
    0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac,
    0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07,
    0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9,
    0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98
];

/// The Y coordinate of the generator
pub static GENERATOR_Y: [u8, ..32] = [
    0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65,
    0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8,
    0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19,
    0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8
];

<|endoftext|>