<commit_before>
use std::io;
use std::io::fs;
use std::os;
use std::io::process::{Command};
use std::path::Path;

fn format_cwd(cwd: &Path, home: &Path) -> String {
  match cwd.as_str() {
    Some(e) => {
      if home.is_ancestor_of(cwd) {
        format!("~{}", e.slice_from(home.as_vec().len()))
      } else {
        e.to_string()
      }
    },
    None => "?".to_string()
  }
}

fn main() {
  println!("ash: A shell");
  println!("Incredibly in beta");
  println!("May eat your left shoes.");
  let mut cwd = os::getcwd();
  //let mut history: Vec<&str> = Vec::new();
  //let mut historyi: uint;
  let home = match os::homedir() {
    Some(e) => e,
    None => Path::new("/")
  };
  loop {
    print!("{cwd} $ ", cwd=format_cwd(&cwd, &home));
    let rawinput = io::stdin().read_line().ok().expect("Error Occured");
    let input = rawinput.as_slice().trim();
    if input == "" { continue } //skip blank enters
    let opts: Vec<&str> = input.split_str(" ").collect();
    let (cmd, args) = (opts[0], opts.slice(1, opts.len()));
    match cmd {
      "cd" => {
        //set the current directory
        if args[0] == "~" {
          //go home
          cwd = match os::homedir() {
            Some(e) => Path::new(e),
            None => Path::new("/")
          };
          continue;
        }
        let path: Option<Path> = if args[0].starts_with("~") { // ~/projects
          match os::homedir() {
            Some(e) => {
              let dir = e.join(args[0].slice_from(2)); //[~/]
              Some(dir)
            }, //hacky but whatever
            None => Path::new_opt(args[0])
          }
        } else if args[0].starts_with(".") { // ./bin or ../ash
          Some(cwd.join(args[0]))
        } else if !args[0].starts_with("/") { //we already know it doesn't start with .
          Some(cwd.join(args[0]))
        } else {
          Path::new_opt(args[0])
        };
        match path {
          Some(new) => {
            match fs::stat(&new) {
              Ok(stat) => {
                match stat.kind {
                  TypeDirectory => {cwd = new} // why is this so unhappy
                }
              },
              Err(e) => println!("No such file or directory: \"{}\"", args[0])
            }
          }
          None => println!("Failed to locate path")
        }
      }
      _ => {
        let process = Command::new(cmd).cwd(&cwd).args(args).output();

        match process {
          Ok(output) => {
            println!("{}", String::from_utf8_lossy(output.output.as_slice()));

          },
          Err(e) => {
            println!("Error Occured: {}", e);
          },
        };
      }
    }
  }
}
<commit_msg>Use of home var in `cd ~`, added {symbol} in prompt<commit_after>
use std::io;
use std::io::fs;
use std::os;
use std::io::process::{Command};
use std::path::Path;

fn format_cwd(cwd: &Path, home: &Path) -> String {
  match cwd.as_str() {
    Some(e) => {
      if home.is_ancestor_of(cwd) {
        format!("~{}", e.slice_from(home.as_vec().len()))
      } else {
        e.to_string()
      }
    },
    None => "?".to_string()
  }
}

fn main() {
  println!("ash: A shell");
  println!("Incredibly in beta");
  println!("May eat your left shoes.");
  let mut cwd = os::getcwd();
  //let mut history: Vec<&str> = Vec::new();
  //let mut historyi: uint;
  let home = match os::homedir() {
    Some(e) => e,
    None => Path::new("/")
  };
  loop {
    print!("{cwd} {symbol} ", cwd=format_cwd(&cwd, &home), symbol="$"); //Symbol is for futureproofing
    let rawinput = io::stdin().read_line().ok().expect("Error Occured");
    let input = rawinput.as_slice().trim();
    if input == "" { continue } //skip blank enters
    let opts: Vec<&str> = input.split_str(" ").collect();
    let (cmd, args) = (opts[0], opts.slice(1, opts.len()));
    match cmd {
      "cd" => {
        //set the current directory
        if args[0] == "~" {
          //go home
          cwd = home.clone();
          continue;
        }
        let path: Option<Path> = if args[0].starts_with("~") { // ~/projects
          //this is intentionally NOT using the `home` variable
          match os::homedir() {
            Some(e) => {
              let dir = e.join(args[0].slice_from(2)); //[~/]
              Some(dir)
            }, //hacky but whatever
            None => Path::new_opt(args[0])
          }
        } else if args[0].starts_with(".") || !args[0].starts_with("/") { // ./bin or ../ash || cd src
          Some(cwd.join(args[0]))
        } else {
          Path::new_opt(args[0])
        };
        match path {
          Some(new) => {
            match fs::stat(&new) {
              Ok(stat) => {
                match stat.kind {
                  TypeDirectory => {cwd = new} // why is this so unhappy
                }
              },
              Err(e) => println!("No such file or directory: \"{}\"", args[0])
            }
          }
          None => println!("Failed to locate path")
        }
      }
      _ => {
        let process = Command::new(cmd).cwd(&cwd).args(args).output();

        match process {
          Ok(output) => {
            println!("{}", String::from_utf8_lossy(output.output.as_slice()));

          },
          Err(e) => {
            println!("Error Occured: {}", e);
          },
        };
      }
    }
  }
}
<|endoftext|>


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

extern crate neovim;
extern crate rgtk;
extern crate serialize;

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

mod projects;
mod ui;
mod utils;

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

    // constants

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

    // create the window

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

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

    // create the panes

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

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

    let mut project_tree = gtk::TreeView::new().unwrap();
    let selection = project_tree.get_selection().unwrap();
    let column_types = [glib::ffi::g_type_string, glib::ffi::g_type_string];
    let store = gtk::TreeStore::new(&column_types).unwrap();
    let model = store.get_model().unwrap();
    project_tree.set_model(&model);
    project_tree.set_headers_visible(false);

    let mut scroll_pane = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll_pane.add(&project_tree);

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

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

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

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

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

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

    // populate the project tree

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

    ::utils::create_data_dir();
    ::utils::read_prefs(&mut state);
    ::ui::update_project_tree(&mut state, &mut project_tree);

    // connect to the signals

    new_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::new_project(&mut state, &mut project_tree);
    }));
    import_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::import_project(&mut state, &mut project_tree);
    }));
    rename_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::rename_file(&mut state);
    }));
    remove_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::remove_item(&mut state);
    }));
    selection.connect(gtk::signals::Changed::new(|| {
        ::projects::update_selection(&mut state);
    }));
    project_tree.connect(gtk::signals::RowCollapsed::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::remove_expansion(&mut state, &iter);
    }));
    project_tree.connect(gtk::signals::RowExpanded::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::add_expansion(&mut state, &iter);
    }));

    // show the window

    window.show_all();
    gtk::main();
}
<commit_msg>Start work on build pane<commit_after>#![feature(globs)]
#![feature(if_let)]

extern crate neovim;
extern crate rgtk;
extern crate serialize;

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

mod projects;
mod ui;
mod utils;

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

    // constants

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

    // create the window

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

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

    // create the panes

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

    let mut proj_btns = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    proj_btns.set_size_request(-1, -1);
    proj_btns.add(&new_button);
    proj_btns.add(&import_button);
    proj_btns.add(&rename_button);
    proj_btns.add(&remove_button);

    let mut proj_tree = gtk::TreeView::new().unwrap();
    let selection = proj_tree.get_selection().unwrap();
    let column_types = [glib::ffi::g_type_string, glib::ffi::g_type_string];
    let store = gtk::TreeStore::new(&column_types).unwrap();
    let model = store.get_model().unwrap();
    proj_tree.set_model(&model);
    proj_tree.set_headers_visible(false);

    let mut scroll_pane = gtk::ScrolledWindow::new(None, None).unwrap();
    scroll_pane.add(&proj_tree);

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

    let mut proj_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    proj_pane.set_size_request(-1, -1);
    proj_pane.pack_start(&proj_btns, false, true, 0);
    proj_pane.pack_start(&scroll_pane, true, true, 0);

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

    let run_button = gtk::Button::new_with_label("Run").unwrap();
    let build_button = gtk::Button::new_with_label("Build").unwrap();
    let test_button = gtk::Button::new_with_label("Test").unwrap();
    let clean_button = gtk::Button::new_with_label("Clean").unwrap();
    let stop_button = gtk::Button::new_with_label("Stop").unwrap();

    let mut build_btns = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();
    build_btns.set_size_request(-1, -1);
    build_btns.add(&run_button);
    build_btns.add(&build_button);
    build_btns.add(&test_button);
    build_btns.add(&clean_button);
    build_btns.add(&stop_button);

    let build_term = gtk::VteTerminal::new().unwrap();

    let mut build_pane = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    build_pane.pack_start(&build_btns, false, true, 0);
    build_pane.pack_start(&build_term, true, true, 0);

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

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

    // populate the project tree

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

    ::utils::create_data_dir();
    ::utils::read_prefs(&mut state);
    ::ui::update_project_tree(&mut state, &mut proj_tree);

    // connect to the signals

    new_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::new_project(&mut state, &mut proj_tree);
    }));
    import_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::import_project(&mut state, &mut proj_tree);
    }));
    rename_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::rename_file(&mut state);
    }));
    remove_button.connect(gtk::signals::Clicked::new(|| {
        ::projects::remove_item(&mut state);
    }));
    selection.connect(gtk::signals::Changed::new(|| {
        ::projects::update_selection(&mut state);
    }));
    proj_tree.connect(gtk::signals::RowCollapsed::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::remove_expansion(&mut state, &iter);
    }));
    proj_tree.connect(gtk::signals::RowExpanded::new(|iter_raw, _| {
        let iter = gtk::TreeIter::wrap_pointer(iter_raw);
        ::projects::add_expansion(&mut state, &iter);
    }));

    // show the window

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


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#[macro_use]
extern crate glium;
extern crate cgmath;

use std::path::PathBuf;

use glium::{ Surface};
use glium::glutin::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode};

use cgmath::{Vector3, Point3};

mod camera;
mod input;
mod renderer;
mod scene;

use camera::Camera;
use input::InputState;

/// Get the root directory of the project
fn get_project_root() -> PathBuf {
    let exe_dir = std::env::current_exe().unwrap();
    let mut parent_dir = exe_dir.parent().unwrap();
    // This fails if the executable is not in the project tree
    while !parent_dir.ends_with("rusty") {
        parent_dir = parent_dir.parent().unwrap();
    }
    parent_dir.to_path_buf()
}

fn main() {
    let mut events_loop = glium::glutin::EventsLoop::new();
    let window = glium::glutin::WindowBuilder::new();
    let context = glium::glutin::ContextBuilder::new().with_depth_buffer(24);
    let display = glium::Display::new(window, context, &events_loop).expect("Failed to create display");

    let root_path = get_project_root();
    // TODO: Enable use of arbitrary scene
    let scenes = vec!("scenes/plane.obj",
                      "scenes/cornell/cornell.obj",
                      "scenes/cornell/cornell_chesterfield.obj",
                      "scenes/cornell-box/CornellBox-Original.obj",
                      "scenes/cornell-box/CornellBox-Glossy.obj",
                      "scenes/cornell-box/CornellBox-Water.obj",
                      "scenes/nanosuit/nanosuit.obj",
                      "scenes/sibenik/sibenik.obj");
    let mut scene = scene::Scene::new(&root_path.join(scenes[0]), &display);
    let gl_renderer = renderer::GLRenderer::new(&display);
    let pt_renderer = renderer::PTRenderer::new(&display);

    let mut input = InputState::new();
    let mut camera = Camera::new(Point3::from(scene.get_center())
                                 + scene.get_size() * Vector3::new(0.0, 0.0, 1.0f32),
                                 Vector3::new(0.0, 0.0, -1.0f32));
    camera.set_scale(scene.get_size());
    let mut trace = false;

    loop {
        let mut target = display.draw();

        let (width, height) = target.get_dimensions();
        // Don't draw if the window is minimized
        if width != 0 && height != 0 {
            let camera_to_clip = camera.get_camera_to_clip(width, height);
            let world_to_camera = camera.get_world_to_camera();

            target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
            if trace {
                pt_renderer.render(&scene, &mut target, &display, width as usize, height as usize, &camera);
            } else {
                gl_renderer.render(&scene, &mut target, camera_to_clip * world_to_camera);
            }
        }
        target.finish().unwrap();

        { // TODO clean this up
        let event_handler = |event| {
            input.update(&event);
            match event {
                Event::WindowEvent{event: WindowEvent::KeyboardInput{input, ..}, ..} => {
                    match input {
                        KeyboardInput{state: ElementState::Pressed,
                                      virtual_keycode: Some(VirtualKeyCode::Space), ..}
                        => trace = !trace,
                        // Get number pressed based on the keycode
                        KeyboardInput{state: ElementState::Pressed, scancode, ..} => {
                            let i = scancode as usize - 2;
                            if 0 < i && i < scenes.len() {
                                scene = scene::Scene::new(&root_path.join(scenes[i]), &display);
                                camera.set_position(Point3::from(scene.get_center())
                                                    + scene.get_size() * Vector3::new(0.0, 0.0, 1.0f32),
                                                    Vector3::new(0.0, 0.0, -1.0f32));
                                camera.set_scale(scene.get_size());
                            }
                        },
                        _ => ()
                    }
                }
                Event::WindowEvent{event: WindowEvent::Closed, ..} => std::process::exit(0),
                _ => ()
            }
        };
        events_loop.poll_events(event_handler);
        }
        camera.process_input(&input);
        input.reset_deltas();
    }
}
<commit_msg>Remove useless curly braces<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#[macro_use]
extern crate glium;
extern crate cgmath;

use std::path::PathBuf;

use glium::Surface;
use glium::glutin::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode};

use cgmath::{Vector3, Point3};

mod camera;
mod input;
mod renderer;
mod scene;

use camera::Camera;
use input::InputState;

/// Get the root directory of the project
fn get_project_root() -> PathBuf {
    let exe_dir = std::env::current_exe().unwrap();
    let mut parent_dir = exe_dir.parent().unwrap();
    // This fails if the executable is not in the project tree
    while !parent_dir.ends_with("rusty") {
        parent_dir = parent_dir.parent().unwrap();
    }
    parent_dir.to_path_buf()
}

fn main() {
    let mut events_loop = glium::glutin::EventsLoop::new();
    let window = glium::glutin::WindowBuilder::new();
    let context = glium::glutin::ContextBuilder::new().with_depth_buffer(24);
    let display = glium::Display::new(window, context, &events_loop).expect("Failed to create display");

    let root_path = get_project_root();
    // TODO: Enable use of arbitrary scene
    let scenes = vec!("scenes/plane.obj",
                      "scenes/cornell/cornell.obj",
                      "scenes/cornell/cornell_chesterfield.obj",
                      "scenes/cornell-box/CornellBox-Original.obj",
                      "scenes/cornell-box/CornellBox-Glossy.obj",
                      "scenes/cornell-box/CornellBox-Water.obj",
                      "scenes/nanosuit/nanosuit.obj",
                      "scenes/sibenik/sibenik.obj");
    let mut scene = scene::Scene::new(&root_path.join(scenes[0]), &display);
    let gl_renderer = renderer::GLRenderer::new(&display);
    let pt_renderer = renderer::PTRenderer::new(&display);

    let mut input = InputState::new();
    let mut camera = Camera::new(Point3::from(scene.get_center())
                                 + scene.get_size() * Vector3::new(0.0, 0.0, 1.0f32),
                                 Vector3::new(0.0, 0.0, -1.0f32));
    camera.set_scale(scene.get_size());
    let mut trace = false;

    loop {
        let mut target = display.draw();

        let (width, height) = target.get_dimensions();
        // Don't draw if the window is minimized
        if width != 0 && height != 0 {
            let camera_to_clip = camera.get_camera_to_clip(width, height);
            let world_to_camera = camera.get_world_to_camera();

            target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
            if trace {
                pt_renderer.render(&scene, &mut target, &display, width as usize, height as usize, &camera);
            } else {
                gl_renderer.render(&scene, &mut target, camera_to_clip * world_to_camera);
            }
        }
        target.finish().unwrap();

        { // TODO clean this up
        let event_handler = |event| {
            input.update(&event);
            match event {
                Event::WindowEvent{event: WindowEvent::KeyboardInput{input, ..}, ..} => {
                    match input {
                        KeyboardInput{state: ElementState::Pressed,
                                      virtual_keycode: Some(VirtualKeyCode::Space), ..}
                        => trace = !trace,
                        // Get number pressed based on the keycode
                        KeyboardInput{state: ElementState::Pressed, scancode, ..} => {
                            let i = scancode as usize - 2;
                            if 0 < i && i < scenes.len() {
                                scene = scene::Scene::new(&root_path.join(scenes[i]), &display);
                                camera.set_position(Point3::from(scene.get_center())
                                                    + scene.get_size() * Vector3::new(0.0, 0.0, 1.0f32),
                                                    Vector3::new(0.0, 0.0, -1.0f32));
                                camera.set_scale(scene.get_size());
                            }
                        },
                        _ => ()
                    }
                }
                Event::WindowEvent{event: WindowEvent::Closed, ..} => std::process::exit(0),
                _ => ()
            }
        };
        events_loop.poll_events(event_handler);
        }
        camera.process_input(&input);
        input.reset_deltas();
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

mod game;
mod ai;
mod human_ai;
mod constants;
mod helpers;
mod general_analysis;
use game::{VictoryStats, GameStructure};
use ai::{SogoAI};
use constants::{LINES, PARALLELOGRAMS, PLUSSES};
use std::rc::Rc;

extern crate kiss3d;
extern crate glfw;
extern crate nalgebra as na;

use na::{Vector3, Point3, Point2};
use glfw::{Action, MouseButton, WindowEvent, Key};
use kiss3d::window::Window;
use kiss3d::light::Light;
use kiss3d::camera::{ArcBall, Camera};
use kiss3d::scene::SceneNode;

use game::{GameState, PlayerColor};

const BALL_DIAMMETER : f32 = 0.6;
const PLATE_HEIGHT : f32 = 0.4;
const ROD_LENGTH : f32 = 3.6; // In units of pieces.

/// Calculates the center of the piece in virtual 3D coordinates.
fn piece_position(x: i32, y: i32, z: i32) -> Vector3<f32> {
    return Vector3::new((x as f32)-1.5, (y as f32 + 0.5) * BALL_DIAMMETER *0.97, (z as f32)-1.5);
}

fn prepare_window() -> Window {
    let mut window = Window::new("Sogo");
    window.set_framerate_limit(Some(60));
    window.set_background_color(0.3, 0.3, 0.3);
    window.set_light(Light::StickToCamera);

    window
}

fn prepare_camera() -> ArcBall {
    let position        = Point3::new(6.0f32, 6.0, 6.0);
    let looking_towards = Point3::new(0.0f32, 1.5, 0.0);

    let mut camera = ArcBall::new(position, looking_towards);

    camera.rebind_drag_button(None);
    camera.rebind_rotate_button(Some(glfw::MouseButtonRight));

    camera
}

/// Creates the plate with 16 rods.
/// The scene's origin is located at the center of the plate's top
fn prepare_board() -> SceneNode {
    let mut node = SceneNode::new_empty();

    let mut plate     = node.add_cube(5.0, PLATE_HEIGHT, 5.0);
    plate.prepend_to_local_translation(&Vector3::new(0.0, -PLATE_HEIGHT/2.0, 0.0));
    plate.set_color(0.78, 0.65, 0.48);

    for i in 0..4 {
        for j in 0..4 {
            let height = BALL_DIAMMETER * ROD_LENGTH;
            let mut cylinder = node.add_cylinder(0.07f32, height);
            cylinder.prepend_to_local_translation(&Vector3::new((i as f32)-1.5, height/2.0, (j as f32)-1.5));
            cylinder.set_color(0.87, 0.72, 0.53);
        }
    }

    node
}

/// Creates a new 3D gamepiece and places it at the supplied position.
fn add_piece(scene : &mut SceneNode, x : i32, y : i32, z : i32, color : PlayerColor) -> SceneNode {
    let mut piece = scene.add_sphere(BALL_DIAMMETER/2.0);
    piece.prepend_to_local_translation(&piece_position(x, y, z));
    match color {
        PlayerColor::White => piece.set_color(1.0, 1.0, 1.0),
        PlayerColor::Black => piece.set_color(0.0, 0.0, 0.0),
    }

    piece
}

/// Creates a new 3D gamepiece and places it at the supplied position.
fn add_hint(scene : &mut SceneNode, x : i32, z : i32, color : PlayerColor) -> SceneNode {
    let mut piece = scene.add_sphere(BALL_DIAMMETER/2.0);
    piece.prepend_to_local_translation(&piece_position(x, 0, z));
    piece.prepend_to_local_translation(&Vector3::new(0.0, BALL_DIAMMETER * ROD_LENGTH, 0.0));
    match color {
        PlayerColor::White => piece.set_color(1.0, 1.0, 1.0),
        PlayerColor::Black => piece.set_color(0.0, 0.0, 0.0),
    }

    piece
}

fn placement_coordinate(window : &Window, camera : &ArcBall, cursor_position : (f64, f64)) -> Option<(i32, i32)> {
    let (x, y) = cursor_position;
    let (anchor, direction) = camera.unproject(&Point2::new(x as f32, y as f32), &window.size());
    // Fixme: might divide by zero.
    let lambda = ((BALL_DIAMMETER * 3.6f32) - anchor.y) / direction.y;
    let x_value = (anchor.x + lambda * direction.x + 1.5).round() as i32;
    let z_value = (anchor.z + lambda * direction.z + 1.5).round() as i32;

    if 0 <= x_value && x_value < 4 && 0 <= z_value && z_value < 4 {
        Some((x_value, z_value))
    } else {
        None
    }
}

fn main() {
    let structure = Rc::new(GameStructure::new(&LINES));
    let mut state = GameState::new(&structure);
    let mut history = ActionHistory::new();

    let mut window = prepare_window();
    let mut camera = prepare_camera();

    window.scene_mut().add_child(prepare_board());

    let mut current_placement_candidate = None;
    let mut placement_hint : Option<SceneNode> = None;

    let mut p2 = ai::TreeJudgementAI::new(structure.clone(), 3);
    // ai::MonteCarloAI::new(structure.clone(), 1000);

    while window.render_with_camera(&mut camera) {
        for event in window.events().iter() {
            match event.value {
                WindowEvent::CursorPos(x, y) => {
                    let new_placement_candidate = placement_coordinate(&window, &camera, (x, y));
                    if current_placement_candidate != new_placement_candidate {
                        // Destroy the current placement hint object.
                        if let Some(mut node) = placement_hint {
                            node.unlink(); // removes the node from the parent scene.
                            placement_hint = None
                        }
                        // Create new placement hint object, if applicable.
                        if let Some((x, y)) = new_placement_candidate {
                            if state.z_value(x as i8, y as i8) != None {
                                placement_hint = Some(add_hint(window.scene_mut(), x, y, state.current_color));
                            }
                        }
                        current_placement_candidate = new_placement_candidate;
                    }
                },
                WindowEvent::MouseButton(MouseButton::Button1, Action::Release, _) => {
                    if let Some((x_value, z_value)) = current_placement_candidate {
                        let height = state.z_value(x_value as i8, z_value as i8);
                        match height {
                            Some(y_value) => {
                                // Add a new piece to the board.
                                let new_piece = add_piece(window.scene_mut(), x_value, y_value as i32, z_value, state.current_color);
                                let action = game::Action::new(x_value as i8, z_value as i8);
                                state.execute_action(&structure, &action);
                                history.add(action, new_piece);

                                // Ask the enemy AI to move
                                let enemy_action = p2.decide_action(&state);
                                let (x, z) = enemy_action.unwrap();
                                let height = state.z_value(x, z).unwrap();
                                let new_piece = add_piece(window.scene_mut(), x as i32, height as i32, z as i32, state.current_color);
                                state.execute_action(&structure, &enemy_action);
                                history.add(enemy_action, new_piece);
                            },
                            None => {},
                        }
                    }
                },
                WindowEvent::Key(Key::Left, _, Action::Release, _) => {
                    history.undo();
                    state = history.game_state(&structure);
                },
                WindowEvent::Key(Key::Right, _, Action::Release, _) => {
                    history.redo(window.scene_mut());
                    state = history.game_state(&structure);
                },
                _ => { }
            }
        }
    }
}

struct ActionHistory {
    actions : Vec<(game::Action, SceneNode)>,
    // The current times is the amount of actions passed.
    // I.e. actions[current_time] is not executed and may not exist.
    // The current_time should never be larger than actions.len().
    current_time : usize,
}

impl ActionHistory {
    fn new() -> ActionHistory {
        ActionHistory {
            actions : Vec::new(),
            current_time : 0,
        }
    }
    /// Adds a new action to the ActionHistory.
    /// Stored actions after current_time are discarded.
    fn add(&mut self, action : game::Action, node : SceneNode) {
        while self.actions.len() > self.current_time {
            // The old nodes are already unlinked from their parents (not displayed).
            self.actions.pop();
        }
        self.actions.push((action, node));
        self.current_time += 1;
    }
    /// Creates a new GameState from scratch and applies all recorded actions up to current_time.
    /// This is in contrast to the 3D spheres which are individually created and removed.
    /// This function does not affect the graphical output at all.
    fn game_state(&self, structure : &GameStructure) -> GameState {
        let mut state = GameState::new(structure);
        for time in 0..self.actions.len() {
            if time >= self.current_time {
                break;
            }
            state.execute_action(structure, &self.actions[time].0);
        }
        state
    }
    fn undo(&mut self) {
        if self.current_time > 0 {
            self.current_time -= 1;
            self.actions[self.current_time].1.unlink();
        }
    }
    // The redo function need a SceneNode while the undo function doesn't because we need to know
    // the parent in order to relink the sphere. Unlink works without.
    fn redo(&mut self, scene : &mut SceneNode) {
        if self.current_time < self.actions.len() {
            // The Scene Node contains data: Rc<RefCell<SceneNodeData>>, so cloning it does just
            // return a new reference to the same data.
            scene.add_child(self.actions[self.current_time].1.clone());
            self.current_time += 1;
        }
    }
}

/*
#[allow(dead_code)]
fn run_all_matches(endurance : Vec<i32>, precision : i32) -> Vec<Vec<(i32, i32, f32)>> {
    let structure = Rc::new(GameStructure::new(&PARALLELOGRAMS));
    let mut result = Vec::new();
    for i in 0..endurance.len() {
        let mut result_row = Vec::new();
        for j in 0..endurance.len() {
            let mut result_cell = VictoryStats::new();
            println!("Comparing {:?} to {:?}", endurance[i], endurance[j]);
            let mut p1 = ai::MonteCarloAI::new(structure.clone(), endurance[i]);
            let mut p2 = ai::MonteCarloAI::new(structure.clone(), endurance[j]);
            for i in 0..precision {
                println!("    Game {} of {}", i, precision);
                let state = ai::run_match(&structure, &mut p1, &mut p2);
                match state.victory_state {
                    game::VictoryState::Win(game::PlayerColor::White) => result_cell.white += 1,
                    game::VictoryState::Win(game::PlayerColor::Black) => result_cell.black += 1,
                    game::VictoryState::Draw      => result_cell.draws  += 1,
                    game::VictoryState::Undecided => (),
                }
            }
            result_row.push(calculate_rank_difference(result_cell));
        }
        result.push(result_row);
    }
    println!("{:?}", result);
    return result;
}

#[allow(dead_code)]
fn calculate_rank_difference(stats : VictoryStats) -> (i32, i32, f32) {
    let white_loss_frequency = (stats.black as f32) / ((stats.black as f32) + (stats.white as f32));
    return (stats.white, stats.black, (1.0/white_loss_frequency - 1.0).ln());
}

fn main() {
    let structure = Rc::new(GameStructure::new(&LINES));

    /*let mut tree = ai::MCTreeAI::new(structure.clone(), 1000);
    for _ in 0..10000 {
        tree.simulate_playout();
    }
    tree.root.print_some_info();*/

    //run_all_matches(vec![500, 1000, 1500], 10);

    //let mut p1 = ai::MCTreeAI::new(structure.clone(), 10000);
    let mut p1 = ai::MonteCarloAI::new(structure.clone(), 30000);
    //let mut p2 = ai::MonteCarloAI::new(structure.clone(), 1000);
    //let p2 = ai::TreeJudgementAI::new(structure.clone(), 3);
    //let p1 = ai::RandomSogoAI::new();
    //let p1 = ai::TreeJudgementAI::new(4);
    let mut p2 = human_ai::HumanPlayer::Active;
    let mut statics = VictoryStats { white : 0, black : 0, draws : 0};
    for i in 0..40 {
        println!("Game {}.", i);
        let state = ai::run_match(&structure, &mut p1, &mut p2);
        match state.victory_state {
            game::VictoryState::Win(game::PlayerColor::White) => statics.white += 1,
            game::VictoryState::Win(game::PlayerColor::Black) => statics.black += 1,
            game::VictoryState::Draw      => statics.draws  += 1,
            game::VictoryState::Undecided => (),

        }
        //println!("The game took {:?} turns and ended with {:?}.", state.age, state.victory_state);
        //human_ai::print_gamestate(&state);
    }
    println!("There were {} white and {} black wins as well as {} draws.", statics.white, statics.black, statics.draws);
    //*/
}
 */ */
<commit_msg>remove general_analysis.<commit_after>#[cfg(test)]
mod tests;

mod game;
mod ai;
mod human_ai;
mod constants;
mod helpers;
// mod general_analysis;
use game::{VictoryStats, GameStructure};
use ai::{SogoAI};
use constants::{LINES, PARALLELOGRAMS, PLUSSES};
use std::rc::Rc;

extern crate kiss3d;
extern crate glfw;
extern crate nalgebra as na;

use na::{Vector3, Point3, Point2};
use glfw::{Action, MouseButton, WindowEvent, Key};
use kiss3d::window::Window;
use kiss3d::light::Light;
use kiss3d::camera::{ArcBall, Camera};
use kiss3d::scene::SceneNode;

use game::{GameState, PlayerColor};

const BALL_DIAMMETER : f32 = 0.6;
const PLATE_HEIGHT : f32 = 0.4;
const ROD_LENGTH : f32 = 3.6; // In units of pieces.

/// Calculates the center of the piece in virtual 3D coordinates.
fn piece_position(x: i32, y: i32, z: i32) -> Vector3<f32> {
    return Vector3::new((x as f32)-1.5, (y as f32 + 0.5) * BALL_DIAMMETER *0.97, (z as f32)-1.5);
}

fn prepare_window() -> Window {
    let mut window = Window::new("Sogo");
    window.set_framerate_limit(Some(60));
    window.set_background_color(0.3, 0.3, 0.3);
    window.set_light(Light::StickToCamera);

    window
}

fn prepare_camera() -> ArcBall {
    let position        = Point3::new(6.0f32, 6.0, 6.0);
    let looking_towards = Point3::new(0.0f32, 1.5, 0.0);

    let mut camera = ArcBall::new(position, looking_towards);

    camera.rebind_drag_button(None);
    camera.rebind_rotate_button(Some(glfw::MouseButtonRight));

    camera
}

/// Creates the plate with 16 rods.
/// The scene's origin is located at the center of the plate's top
fn prepare_board() -> SceneNode {
    let mut node = SceneNode::new_empty();

    let mut plate     = node.add_cube(5.0, PLATE_HEIGHT, 5.0);
    plate.prepend_to_local_translation(&Vector3::new(0.0, -PLATE_HEIGHT/2.0, 0.0));
    plate.set_color(0.78, 0.65, 0.48);

    for i in 0..4 {
        for j in 0..4 {
            let height = BALL_DIAMMETER * ROD_LENGTH;
            let mut cylinder = node.add_cylinder(0.07f32, height);
            cylinder.prepend_to_local_translation(&Vector3::new((i as f32)-1.5, height/2.0, (j as f32)-1.5));
            cylinder.set_color(0.87, 0.72, 0.53);
        }
    }

    node
}

/// Creates a new 3D gamepiece and places it at the supplied position.
fn add_piece(scene : &mut SceneNode, x : i32, y : i32, z : i32, color : PlayerColor) -> SceneNode {
    let mut piece = scene.add_sphere(BALL_DIAMMETER/2.0);
    piece.prepend_to_local_translation(&piece_position(x, y, z));
    match color {
        PlayerColor::White => piece.set_color(1.0, 1.0, 1.0),
        PlayerColor::Black => piece.set_color(0.0, 0.0, 0.0),
    }

    piece
}

/// Creates a new 3D gamepiece and places it at the supplied position.
fn add_hint(scene : &mut SceneNode, x : i32, z : i32, color : PlayerColor) -> SceneNode {
    let mut piece = scene.add_sphere(BALL_DIAMMETER/2.0);
    piece.prepend_to_local_translation(&piece_position(x, 0, z));
    piece.prepend_to_local_translation(&Vector3::new(0.0, BALL_DIAMMETER * ROD_LENGTH, 0.0));
    match color {
        PlayerColor::White => piece.set_color(1.0, 1.0, 1.0),
        PlayerColor::Black => piece.set_color(0.0, 0.0, 0.0),
    }

    piece
}

fn placement_coordinate(window : &Window, camera : &ArcBall, cursor_position : (f64, f64)) -> Option<(i32, i32)> {
    let (x, y) = cursor_position;
    let (anchor, direction) = camera.unproject(&Point2::new(x as f32, y as f32), &window.size());
    // Fixme: might divide by zero.
    let lambda = ((BALL_DIAMMETER * 3.6f32) - anchor.y) / direction.y;
    let x_value = (anchor.x + lambda * direction.x + 1.5).round() as i32;
    let z_value = (anchor.z + lambda * direction.z + 1.5).round() as i32;

    if 0 <= x_value && x_value < 4 && 0 <= z_value && z_value < 4 {
        Some((x_value, z_value))
    } else {
        None
    }
}

fn main() {
    let structure = Rc::new(GameStructure::new(&LINES));
    let mut state = GameState::new(&structure);
    let mut history = ActionHistory::new();

    let mut window = prepare_window();
    let mut camera = prepare_camera();

    window.scene_mut().add_child(prepare_board());

    let mut current_placement_candidate = None;
    let mut placement_hint : Option<SceneNode> = None;

    let mut p2 = ai::TreeJudgementAI::new(structure.clone(), 3);
    // ai::MonteCarloAI::new(structure.clone(), 1000);

    while window.render_with_camera(&mut camera) {
        for event in window.events().iter() {
            match event.value {
                WindowEvent::CursorPos(x, y) => {
                    let new_placement_candidate = placement_coordinate(&window, &camera, (x, y));
                    if current_placement_candidate != new_placement_candidate {
                        // Destroy the current placement hint object.
                        if let Some(mut node) = placement_hint {
                            node.unlink(); // removes the node from the parent scene.
                            placement_hint = None
                        }
                        // Create new placement hint object, if applicable.
                        if let Some((x, y)) = new_placement_candidate {
                            if state.z_value(x as i8, y as i8) != None {
                                placement_hint = Some(add_hint(window.scene_mut(), x, y, state.current_color));
                            }
                        }
                        current_placement_candidate = new_placement_candidate;
                    }
                },
                WindowEvent::MouseButton(MouseButton::Button1, Action::Release, _) => {
                    if let Some((x_value, z_value)) = current_placement_candidate {
                        let height = state.z_value(x_value as i8, z_value as i8);
                        match height {
                            Some(y_value) => {
                                // Add a new piece to the board.
                                let new_piece = add_piece(window.scene_mut(), x_value, y_value as i32, z_value, state.current_color);
                                let action = game::Action::new(x_value as i8, z_value as i8);
                                state.execute_action(&structure, &action);
                                history.add(action, new_piece);

                                // Ask the enemy AI to move
                                let enemy_action = p2.decide_action(&state);
                                let (x, z) = enemy_action.unwrap();
                                let height = state.z_value(x, z).unwrap();
                                let new_piece = add_piece(window.scene_mut(), x as i32, height as i32, z as i32, state.current_color);
                                state.execute_action(&structure, &enemy_action);
                                history.add(enemy_action, new_piece);
                            },
                            None => {},
                        }
                    }
                },
                WindowEvent::Key(Key::Left, _, Action::Release, _) => {
                    history.undo();
                    state = history.game_state(&structure);
                },
                WindowEvent::Key(Key::Right, _, Action::Release, _) => {
                    history.redo(window.scene_mut());
                    state = history.game_state(&structure);
                },
                _ => { }
            }
        }
    }
}

struct ActionHistory {
    actions : Vec<(game::Action, SceneNode)>,
    // The current times is the amount of actions passed.
    // I.e. actions[current_time] is not executed and may not exist.
    // The current_time should never be larger than actions.len().
    current_time : usize,
}

impl ActionHistory {
    fn new() -> ActionHistory {
        ActionHistory {
            actions : Vec::new(),
            current_time : 0,
        }
    }
    /// Adds a new action to the ActionHistory.
    /// Stored actions after current_time are discarded.
    fn add(&mut self, action : game::Action, node : SceneNode) {
        while self.actions.len() > self.current_time {
            // The old nodes are already unlinked from their parents (not displayed).
            self.actions.pop();
        }
        self.actions.push((action, node));
        self.current_time += 1;
    }
    /// Creates a new GameState from scratch and applies all recorded actions up to current_time.
    /// This is in contrast to the 3D spheres which are individually created and removed.
    /// This function does not affect the graphical output at all.
    fn game_state(&self, structure : &GameStructure) -> GameState {
        let mut state = GameState::new(structure);
        for time in 0..self.actions.len() {
            if time >= self.current_time {
                break;
            }
            state.execute_action(structure, &self.actions[time].0);
        }
        state
    }
    fn undo(&mut self) {
        if self.current_time > 0 {
            self.current_time -= 1;
            self.actions[self.current_time].1.unlink();
        }
    }
    // The redo function need a SceneNode while the undo function doesn't because we need to know
    // the parent in order to relink the sphere. Unlink works without.
    fn redo(&mut self, scene : &mut SceneNode) {
        if self.current_time < self.actions.len() {
            // The Scene Node contains data: Rc<RefCell<SceneNodeData>>, so cloning it does just
            // return a new reference to the same data.
            scene.add_child(self.actions[self.current_time].1.clone());
            self.current_time += 1;
        }
    }
}

/*
#[allow(dead_code)]
fn run_all_matches(endurance : Vec<i32>, precision : i32) -> Vec<Vec<(i32, i32, f32)>> {
    let structure = Rc::new(GameStructure::new(&PARALLELOGRAMS));
    let mut result = Vec::new();
    for i in 0..endurance.len() {
        let mut result_row = Vec::new();
        for j in 0..endurance.len() {
            let mut result_cell = VictoryStats::new();
            println!("Comparing {:?} to {:?}", endurance[i], endurance[j]);
            let mut p1 = ai::MonteCarloAI::new(structure.clone(), endurance[i]);
            let mut p2 = ai::MonteCarloAI::new(structure.clone(), endurance[j]);
            for i in 0..precision {
                println!("    Game {} of {}", i, precision);
                let state = ai::run_match(&structure, &mut p1, &mut p2);
                match state.victory_state {
                    game::VictoryState::Win(game::PlayerColor::White) => result_cell.white += 1,
                    game::VictoryState::Win(game::PlayerColor::Black) => result_cell.black += 1,
                    game::VictoryState::Draw      => result_cell.draws  += 1,
                    game::VictoryState::Undecided => (),
                }
            }
            result_row.push(calculate_rank_difference(result_cell));
        }
        result.push(result_row);
    }
    println!("{:?}", result);
    return result;
}

#[allow(dead_code)]
fn calculate_rank_difference(stats : VictoryStats) -> (i32, i32, f32) {
    let white_loss_frequency = (stats.black as f32) / ((stats.black as f32) + (stats.white as f32));
    return (stats.white, stats.black, (1.0/white_loss_frequency - 1.0).ln());
}

fn main() {
    let structure = Rc::new(GameStructure::new(&LINES));

    /*let mut tree = ai::MCTreeAI::new(structure.clone(), 1000);
    for _ in 0..10000 {
        tree.simulate_playout();
    }
    tree.root.print_some_info();*/

    //run_all_matches(vec![500, 1000, 1500], 10);

    //let mut p1 = ai::MCTreeAI::new(structure.clone(), 10000);
    let mut p1 = ai::MonteCarloAI::new(structure.clone(), 30000);
    //let mut p2 = ai::MonteCarloAI::new(structure.clone(), 1000);
    //let p2 = ai::TreeJudgementAI::new(structure.clone(), 3);
    //let p1 = ai::RandomSogoAI::new();
    //let p1 = ai::TreeJudgementAI::new(4);
    let mut p2 = human_ai::HumanPlayer::Active;
    let mut statics = VictoryStats { white : 0, black : 0, draws : 0};
    for i in 0..40 {
        println!("Game {}.", i);
        let state = ai::run_match(&structure, &mut p1, &mut p2);
        match state.victory_state {
            game::VictoryState::Win(game::PlayerColor::White) => statics.white += 1,
            game::VictoryState::Win(game::PlayerColor::Black) => statics.black += 1,
            game::VictoryState::Draw      => statics.draws  += 1,
            game::VictoryState::Undecided => (),

        }
        //println!("The game took {:?} turns and ended with {:?}.", state.age, state.victory_state);
        //human_ai::print_gamestate(&state);
    }
    println!("There were {} white and {} black wins as well as {} draws.", statics.white, statics.black, statics.draws);
    //*/
}
 */ */
<|endoftext|>


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

use std::cmp::min;
use std::env::args;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use libc::types::os::arch::c95::c_int;
use libc::consts::os::posix88::SIGINT;
use libc::funcs::posix01::signal::signal;

static mut exit: bool = false;

type Map = Vec<Vec<Cell>>;

struct Cell {
	alive:	bool,
	lives:	bool,
}

fn print_usage() {
	println!("usage: gol genmap SIZE_V SIZE_H  (generates an empty map)");
	println!("       gol play FILE [TIME_MS]   (plays the game)\n");
	println!("       maps: must be rectangular");
	println!("             '·' is a dead cell, anything else is a living cell");
	println!("         ^C: exit");
}

fn print_new_map(size_args: &[String]) {
	let sizev = size_args[0].parse::<usize>().unwrap();
	let sizeh = size_args[1].parse::<usize>().unwrap();
	let map_line = std::iter::repeat('·').take(sizeh).collect::<String>();
	for _ in 0..sizev { println!("{}", map_line); }
}

fn get_map(filename: &String) -> Option<Map> {
	let file = match File::open(filename) {
		Ok(file)	=> file,
		Err(error)	=> { println!("{}: {}", filename, error); return None },
	};
	let reader = BufReader::new(file);
	Some(reader.lines().map(|l| l.unwrap().chars().map(|c| match c { '·' => Cell { alive: false, lives: false }, _ => Cell { alive: true, lives: true } }).collect()).collect())
}

fn iterate(map: &mut Map) {
	let i_max = map.len();
	let j_max = map[0].len();
	let mut live_neighbours: usize;
	for i in 0..i_max { for j in 0..j_max {
		live_neighbours = 0;
		for m in i.saturating_sub(1)..min(i + 2, i_max) {
			for n in j.saturating_sub(1)..min(j + 2, j_max) {
				if map[m][n].alive && (m != i || n !=  j) { live_neighbours += 1; }
			}}
		if !map[i][j].alive { if live_neighbours == 3  { map[i][j].lives = true } }
		else if live_neighbours < 2 || 3 < live_neighbours { map[i][j].lives = false }
	}}
	for i in 0..map.len() { for j in 0..map[0].len() {
		map[i][j].alive = map[i][j].lives;
	}}
}

fn display_map(map: &Map) {
	let mut screen = String::with_capacity(map.len() * (map[0].len() * 3 + 1) + 7);
	screen.push_str("\x1B[2J\x1B[H"); // clears screen and moves cursor to 1;1
	for i in 0..map.len() {
		for j in 0..map[0].len() {
			if map[i][j].alive { screen.push_str(" X"); }
			else { screen.push_str(" ·"); }
		}
		screen.push('\n');
	}
	print!("{}{}x{}, ", screen, map.len(), map[0].len());
}

fn play_map(filename: &String, pause_time_ms: u32) {
	unsafe { let handler = interrupt as *const u64; signal(SIGINT, handler as u64); }
	let mut map = get_map(filename).unwrap();
	let size_row = map[0].len();
	for row in map.iter() { if row.len() != size_row { println!("error: map is not a rectangle"); return } }
	let mut niter = 0usize;
	print!("\x1B[?47h\x1B[?25l"); // saves screen and hides cursor
	loop {
		display_map(&map);
		println!("iteration: {}", niter);
		iterate(&mut map);
		niter += 1;
		std::thread::sleep_ms(pause_time_ms);
		unsafe { if exit { print!("\x1B[?47l\x1B[?25h"); return } } // restores screen and shows cursor
	}
}

fn interrupt(_: c_int) {
	unsafe { exit = true; }
}

fn main() {
	let args: Vec<_> = args().collect();
	if args.len() == 4 && args[1] == "genmap" { print_new_map(&args[2..4]); }
	else if args.len() == 3 && args[1] == "play" { play_map(&args[2], 400); }
	else if args.len() == 4 && args[1] == "play" { play_map(&args[2], args[3].parse::<u32>().unwrap()); }
	else { print_usage(); }
}
<commit_msg>dusting<commit_after>#![feature(libc)]
extern crate libc;

use std::cmp::min;
use std::io::BufRead;
use std::io::BufReader;
use libc::types::os::arch::c95::c_int;
use libc::consts::os::posix88::SIGINT;
use libc::funcs::posix01::signal::signal;

static mut exit: bool = false;

type Map = Vec<Vec<Cell>>;

struct Cell {
	alive:	bool,
	lives:	bool,
}

fn print_usage() {
	println!("usage: gol genmap SIZE_V SIZE_H  (generates an empty map)");
	println!("       gol play FILE [TIME_MS]   (plays the game)\n");
	println!("       maps: must be rectangular");
	println!("             '·' is a dead cell, anything else is a living cell");
	println!("         ^C: exit");
}

fn print_new_map(size_args: &[String]) {
	let sizev = size_args[0].parse::<usize>().unwrap();
	let sizeh = size_args[1].parse::<usize>().unwrap();
	let map_line = std::iter::repeat('·').take(sizeh).collect::<String>();
	for _ in 0..sizev { println!("{}", map_line); }
}

fn get_map(filename: &String) -> Option<Map> {
	let file = match std::fs::File::open(filename) {
		Ok(file)	=> file,
		Err(error)	=> { println!("{}: {}", filename, error); return None },
	};
	let reader = BufReader::new(file);
	Some(reader.lines().map(|l| l.unwrap().chars().map(|c| match c { '·' => Cell { alive: false, lives: false }, _ => Cell { alive: true, lives: true } }).collect()).collect())
}

fn iterate(map: &mut Map) {
	let i_max = map.len();
	let j_max = map[0].len();
	let mut live_neighbours: usize;
	for i in 0..i_max { for j in 0..j_max {
		live_neighbours = 0;
		for m in i.saturating_sub(1)..min(i + 2, i_max) {
			for n in j.saturating_sub(1)..min(j + 2, j_max) {
				if map[m][n].alive && (m != i || n !=  j) { live_neighbours += 1; }
			}}
		if !map[i][j].alive { if live_neighbours == 3  { map[i][j].lives = true } }
		else if live_neighbours < 2 || 3 < live_neighbours { map[i][j].lives = false }
	}}
	for i in 0..map.len() { for j in 0..map[0].len() {
		map[i][j].alive = map[i][j].lives;
	}}
}

fn display_map(map: &Map) {
	let mut screen = String::with_capacity(map.len() * (map[0].len() * 3 + 1) + 7);
	screen.push_str("\x1B[2J\x1B[H"); // clears screen and moves cursor to 1;1
	for i in 0..map.len() {
		for j in 0..map[0].len() {
			if map[i][j].alive { screen.push_str(" X"); }
			else { screen.push_str(" ·"); }
		}
		screen.push('\n');
	}
	print!("{}{}x{}, ", screen, map.len(), map[0].len());
}

fn play_map(filename: &String, pause_time_ms: u32) {
	unsafe { let handler = interrupt as *const u64; signal(SIGINT, handler as u64); }
	let mut map = get_map(filename).unwrap();
	let size_row = map[0].len();
	for row in map.iter() { if row.len() != size_row { println!("error: map is not a rectangle"); return } }
	let mut niter = 0usize;
	print!("\x1B[?47h\x1B[?25l"); // saves screen and hides cursor
	loop {
		display_map(&map);
		println!("iteration: {}", niter);
		iterate(&mut map);
		niter += 1;
		std::thread::sleep_ms(pause_time_ms);
		unsafe { if exit { print!("\x1B[?47l\x1B[?25h"); return } } // restores screen and shows cursor
	}
}

fn interrupt(_: c_int) {
	unsafe { exit = true; }
}

fn main() {
	let args: Vec<_> = std::env::args().collect();
	if args.len() == 4 && args[1] == "genmap" { print_new_map(&args[2..4]); }
	else if args.len() == 3 && args[1] == "play" { play_map(&args[2], 400); }
	else if args.len() == 4 && args[1] == "play" { play_map(&args[2], args[3].parse::<u32>().unwrap()); }
	else { print_usage(); }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#![cfg_attr(feature = "lints", allow(should_implement_trait))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![deny(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate clap;
extern crate toml;
extern crate semver;
extern crate tempdir;
#[cfg(feature = "color")]
extern crate ansi_term;
extern crate tabwriter;

#[macro_use]
mod macros;
mod config;
mod lockfile;
mod deps;
mod error;
mod fmt;

use std::io::{Write, stdout};
#[cfg(feature="debug")]
use std::env;

use clap::{App, AppSettings, Arg, SubCommand};
use tabwriter::TabWriter;

use config::Config;
use lockfile::Lockfile;
use error::CliError;
use fmt::Format;

pub type CliResult<T> = Result<T, CliError>;

fn main() {
    debugln!("executing; cmd=cargo-outdated; args={:?}",
             env::args().collect::<Vec<_>>());
    let m = App::new("cargo-outdated")
        .author("Kevin K. <kbknapp@gmail.com>")
        .about("Displays information about project dependency versions")
        .version(&*format!("v{}", crate_version!()))
    // We have to lie about our binary name since this will be a third party
    // subcommand for cargo
        .bin_name("cargo")
    // Global version uses the version we supplied (Cargo.toml) for all subcommands
    // as well
        .settings(&[AppSettings::GlobalVersion,
                    AppSettings::SubcommandRequired])
    // We use a subcommand because parsed after `cargo` is sent to the third party
    // plugin
    // which will be interpreted as a subcommand/positional arg by clap
        .subcommand(SubCommand::with_name("outdated")
            .about("Displays information about project dependency versions")
            .args_from_usage(
                "-p, --package [PKG]...    'Package to inspect for updates'
                -v, --verbose             'Print verbose output'
                -d, --depth [DEPTH]       'How deep in the dependency chain to search{n}\
                                           (Defaults to all dependencies when omitted)'")
    // We separate -R so we can addd a conflicting argument
            .arg(Arg::from_usage(
                "-R, --root-deps-only  'Only check root dependencies (Equivilant to --depth=1)'")
                .conflicts_with("DEPTH")))
        .get_matches();

    if let Some(m) = m.subcommand_matches("outdated") {
        let cfg = Config::from_matches(m);
        if let Err(e) = execute(cfg) {
            e.exit();
        }
    }
}

fn execute(cfg: Config) -> CliResult<()> {
    debugln!("executing; execute; cfg={:?}", cfg);

    verbose!(cfg, "Parsing {}...", Format::Warning("Cargo.lock"));
    let mut lf = try!(Lockfile::new());
    verboseln!(cfg, "{}", Format::Good("Done"));

    match lf.get_updates(&cfg) {
        Ok(Some(res)) => {
            println!("The following dependencies have newer versions available:\n");
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "\tName\tProject Ver\tSemVer Compat\tLatest Ver\n")
                .unwrap_or_else(|e| panic!("write! error: {}", e));
            for (d_name, d) in res.iter() {
                write!(&mut tw,
                       "\t{}\t   {}\t   {}\t  {}\n",
                       d_name,
                       d.project_ver,
                       d.semver_ver
                        .as_ref()
                        .unwrap_or(&String::from("  --  ")),
                       d.latest_ver
                        .as_ref()
                        .unwrap_or(&String::from("  --  ")))
                    .unwrap();
            }
            tw.flush().unwrap_or_else(|e| panic!("failed to flush TabWriter: {}", e));
            write!(stdout(),
                   "{}",
                   String::from_utf8(tw.unwrap())
                       .unwrap_or_else(|e| panic!("from_utf8 error: {}", e)))
                .unwrap_or_else(|e| panic!("write! error: {}", e));
            Ok(())
        }
        Ok(None) => {
            println!("All dependencies are up to date, yay!");
            Ok(())
        }
        Err(e) => Err(e),
    }
}
<commit_msg>docs: adds crate level docs<commit_after>//!
//! A cargo subcommand for checking the latest version on crates.io of a particular dependency
//!
//! ## About
//!
//! `cargo-outdated` is a very early proof-of-concept for displaying when dependencies have newer versions available.
//!
//! ## Compiling
//!
//! Follow these instructions to compile `cargo-outdated`, then skip down to Installation.
//!
//! 1. Ensure you have current version of `cargo` and [Rust](https://www.rust-lang.org) installed
//! 2. Clone the project `$ git clone https://github.com/kbknapp/cargo-outdated && cd cargo-outdated`
//! 3. Build the project `$ cargo build --release`
//! 4. Once complete, the binary will be located at `target/release/cargo-outdated`
//!
//! ## Installation and Usage
//!
//! All you need to do is place `cargo-outdated` somewhere in your `$PATH`. Then run `cargo outdated` anywhere in your project directory. For full details see below.
//!
//! ### Linux / OS X
//!
//! You have two options, place `cargo-outdated` into a directory that is already located in your `$PATH` variable (To see which directories those are, open a terminal and type `echo "${PATH//:/\n}"`, the quotation marks are important), or you can add a custom directory to your `$PATH`
//!
//! **Option 1**
//! If you have write permission to a directory listed in your `$PATH` or you have root permission (or via `sudo`), simply copy the `cargo-outdated` to that directory `# sudo cp cargo-outdated /usr/local/bin`
//!
//! **Option 2**
//! If you do not have root, `sudo`, or write permission to any directory already in `$PATH` you can create a directory inside your home directory, and add that. Many people use `$HOME/.bin` to keep it hidden (and not clutter your home directory), or `$HOME/bin` if you want it to be always visible. Here is an example to make the directory, add it to `$PATH`, and copy `cargo-outdated` there.
//!
//! Simply change `bin` to whatever you'd like to name the directory, and `.bashrc` to whatever your shell startup file is (usually `.bashrc`, `.bash_profile`, or `.zshrc`)
//!
//! ```ignore
//! $ mkdir ~/bin
//! $ echo "export PATH=$PATH:$HOME/bin" >> ~/.bashrc
//! $ cp cargo-outdated ~/bin
//! $ source ~/.bashrc
//! ```
//!
//! ### Windows
//!
//! On Windows 7/8 you can add directory to the `PATH` variable by opening a command line as an administrator and running
//!
//! ```ignore
//! C:\> setx path "%path%;C:\path\to\cargo-outdated\binary"
//! ```
//!
//! Otherwise, ensure you have the `cargo-outdated` binary in the directory which you operating in the command line from, because Windows automatically adds your current directory to PATH (i.e. if you open a command line to `C:\my_project\` to use `cargo-outdated` ensure `cargo-outdated.exe` is inside that directory as well).
//!
//!
//! ### Options
//!
//! There are a few options for using `cargo-outdated` which should be somewhat self explanitory.
//!
//! ```ignore
//! USAGE:
//!     cargo outdated [FLAGS] [OPTIONS]
//!
//! FLAGS:
//!     -h, --help              Prints help information
//!     -R, --root-deps-only    Only check root dependencies (Equivilant to --depth=1)
//!     -V, --version           Prints version information
//!     -v, --verbose           Print verbose output
//!
//! OPTIONS:
//!     -d, --depth <DEPTH>       How deep in the dependency chain to search
//!                               (Defaults to all dependencies when omitted)
//!     -p, --package <PKG>...    Package to inspect for updates
//! ```
//!
//! ## License
//!
//! `cargo-outdated` is released under the terms of the MIT license. See the LICENSE-MIT file for the details.
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#![cfg_attr(feature = "lints", allow(should_implement_trait))]
#![cfg_attr(feature = "lints", deny(warnings))]
#![deny(missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate clap;
extern crate toml;
extern crate semver;
extern crate tempdir;
#[cfg(feature = "color")]
extern crate ansi_term;
extern crate tabwriter;

#[macro_use]
mod macros;
mod config;
mod lockfile;
mod deps;
mod error;
mod fmt;

use std::io::{Write, stdout};
#[cfg(feature="debug")]
use std::env;

use clap::{App, AppSettings, Arg, SubCommand};
use tabwriter::TabWriter;

use config::Config;
use lockfile::Lockfile;
use error::CliError;
use fmt::Format;

/// Convenience type to return a result or a `CliError`
pub type CliResult<T> = Result<T, CliError>;

fn main() {
    debugln!("executing; cmd=cargo-outdated; args={:?}",
             env::args().collect::<Vec<_>>());
    let m = App::new("cargo-outdated")
        .author("Kevin K. <kbknapp@gmail.com>")
        .about("Displays information about project dependency versions")
        .version(&*format!("v{}", crate_version!()))
    // We have to lie about our binary name since this will be a third party
    // subcommand for cargo
        .bin_name("cargo")
    // Global version uses the version we supplied (Cargo.toml) for all subcommands
    // as well
        .settings(&[AppSettings::GlobalVersion,
                    AppSettings::SubcommandRequired])
    // We use a subcommand because parsed after `cargo` is sent to the third party
    // plugin
    // which will be interpreted as a subcommand/positional arg by clap
        .subcommand(SubCommand::with_name("outdated")
            .about("Displays information about project dependency versions")
            .args_from_usage(
                "-p, --package [PKG]...    'Package to inspect for updates'
                -v, --verbose             'Print verbose output'
                -d, --depth [DEPTH]       'How deep in the dependency chain to search{n}\
                                           (Defaults to all dependencies when omitted)'")
    // We separate -R so we can addd a conflicting argument
            .arg(Arg::from_usage(
                "-R, --root-deps-only  'Only check root dependencies (Equivilant to --depth=1)'")
                .conflicts_with("DEPTH")))
        .get_matches();

    if let Some(m) = m.subcommand_matches("outdated") {
        let cfg = Config::from_matches(m);
        if let Err(e) = execute(cfg) {
            e.exit();
        }
    }
}

fn execute(cfg: Config) -> CliResult<()> {
    debugln!("executing; execute; cfg={:?}", cfg);

    verbose!(cfg, "Parsing {}...", Format::Warning("Cargo.lock"));
    let mut lf = try!(Lockfile::new());
    verboseln!(cfg, "{}", Format::Good("Done"));

    match lf.get_updates(&cfg) {
        Ok(Some(res)) => {
            println!("The following dependencies have newer versions available:\n");
            let mut tw = TabWriter::new(vec![]);
            write!(&mut tw, "\tName\tProject Ver\tSemVer Compat\tLatest Ver\n")
                .unwrap_or_else(|e| panic!("write! error: {}", e));
            for (d_name, d) in res.iter() {
                write!(&mut tw,
                       "\t{}\t   {}\t   {}\t  {}\n",
                       d_name,
                       d.project_ver,
                       d.semver_ver
                        .as_ref()
                        .unwrap_or(&String::from("  --  ")),
                       d.latest_ver
                        .as_ref()
                        .unwrap_or(&String::from("  --  ")))
                    .unwrap();
            }
            tw.flush().unwrap_or_else(|e| panic!("failed to flush TabWriter: {}", e));
            write!(stdout(),
                   "{}",
                   String::from_utf8(tw.unwrap())
                       .unwrap_or_else(|e| panic!("from_utf8 error: {}", e)))
                .unwrap_or_else(|e| panic!("write! error: {}", e));
            Ok(())
        }
        Ok(None) => {
            println!("All dependencies are up to date, yay!");
            Ok(())
        }
        Err(e) => Err(e),
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate cobalt;
extern crate getopts;
extern crate env_logger;
extern crate notify;
extern crate ghp;

#[macro_use]
extern crate nickel;

#[macro_use]
extern crate log;

use getopts::Options;
use std::env;
use std::fs;
use cobalt::Config;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;
use nickel::{Nickel, Options as NickelOptions, StaticFilesHandler};
use ghp::import_dir;

use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;
use std::thread;

fn print_version() {
    println!("0.2.0");
}

fn print_usage(opts: Options) {
    let usage = concat!("\n\tbuild -- build the cobalt project at the source dir",
                        "\n\tserve -- build and serve the cobalt project at the source dir",
                        "\n\twatch -- build, serve, and watch the project at the source dir");
    println!("{}", opts.usage(usage));
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();

    opts.optopt("s", "source", "Source folder, Default: ./", "");
    opts.optopt("d", "destination", "Destination folder, Default: ./", "");
    opts.optopt("c",
                "config",
                "Config file to use, Default: .cobalt.yml",
                "");
    opts.optopt("l",
                "layouts",
                "\tLayout templates folder, Default: _layouts/",
                "");
    opts.optopt("p", "posts", "Posts folder, Default: _posts/", "");
    opts.optopt("P", "port", "Port to serve from, Default: 3000", "");

    opts.optflag("", "debug", "Log verbose (debug level) information");
    opts.optflag("", "trace", "Log ultra-verbose (trace level) information");
    opts.optflag("", "silent", "Suppress all output");
    opts.optflag("h", "help", "Print this help menu");
    opts.optflag("v", "version", "Display version");

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

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    if matches.opt_present("version") {
        print_version();
        return;
    }

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);
    builder.filter(None, LogLevelFilter::Info);

    if matches.opt_present("debug") {
        builder.filter(None, LogLevelFilter::Debug);
    }

    if matches.opt_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.opt_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = match matches.opt_str("config") {
        Some(config) => config,
        None => "./.cobalt.yml".to_owned(),
    };

    // Fetch config information if available
    let mut config: Config = if fs::metadata(&config_path).is_ok() {
        info!("Using config file {}", &config_path);

        match Config::from_file(&config_path) {
            Ok(config) => config,
            Err(e) => {
                error!("Error reading config file:");
                error!("{}", e);
                std::process::exit(1);
            }
        }
    } else {
        Default::default()
    };

    if let Some(source) = matches.opt_str("s") {
        config.source = source;
    };

    if let Some(dest) = matches.opt_str("d") {
        config.dest = dest;
    };

    if let Some(layouts) = matches.opt_str("layouts") {
        config.layouts = layouts;
    };

    if let Some(posts) = matches.opt_str("posts") {
        config.posts = posts;
    };

    let command = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(opts);
        return;
    };

    // Check for port and set port variable to it
    let port = matches.opt_str("port").unwrap_or("3000".to_owned());

    match command.as_ref() {
        "build" => {
            build(&config);
        }

        "serve" => {
            build(&config);
            serve(&config.dest, &port);
        }

        "watch" => {
            build(&config);

            let dest = config.dest.clone();
            thread::spawn(move || {
                serve(&dest, &port);
            });

            let (tx, rx) = channel();
            let w: Result<RecommendedWatcher, Error> = Watcher::new(tx);

            match w {
                Ok(mut watcher) => {
                    // TODO: clean up this unwrap
                    watcher.watch(&config.source).unwrap();
                    info!("Watching {:?} for changes", &config.source);

                    loop {
                        match rx.recv() {
                            Ok(val) => {
                                trace!("file changed {:?}", val);
                                info!("Rebuilding cobalt site...");
                                build(&config);
                            }

                            Err(e) => {
                                error!("[Notify Error]: {}", e);
                                std::process::exit(1);
                            }
                        }
                    }
                }
                Err(e) => {
                    error!("[Notify Error]: {}", e);
                    std::process::exit(1);
                }
            }
        }

        "doc-upload" => {
            info!("Importing {} to gh-pages", &config.dest);

            let meta = match fs::metadata(&config.dest) {
                Ok(data) => data,

                Err(e) => {
                    error!("{}", e);
                    error!("Import not successful");
                    std::process::exit(1);
                }
            };

            if meta.is_dir() {
                match import_dir(&config.dest, "gh-pages", "cobalt site upload") {
                    Ok(_) => info!("Import successful"),
                    Err(e) => {
                        error!("{}", e);
                        error!("Import not successful");
                        std::process::exit(1);
                    }
                }
            } else {
                error!("Build dir is not a directory: {}", &config.dest);
                error!("Import not successful");
                std::process::exit(1);
            }
        }

        _ => {
            print_usage(opts);
            return;
        }
    }
}

fn build(config: &Config) {
    info!("Building from {} into {}", config.source, config.dest);
    match cobalt::build(&config) {
        Ok(_) => info!("Build successful"),
        Err(e) => {
            error!("{}", e);
            error!("Build not successful");
            std::process::exit(1);
        }
    };
}

fn serve(dest: &str, port: &str) {
    info!("Serving {:?} through static file server", dest);
    let mut server = Nickel::new();
    server.options = NickelOptions::default().output_on_listen(false);

    server.utilize(StaticFilesHandler::new(dest));

    let ip = "127.0.0.1:".to_owned() + port;
    info!("Server Listening on {}", &ip);
    info!("Ctrl-c to stop the server");
    server.listen(&*ip);
}
<commit_msg>small naming fixes<commit_after>#![deny(warnings)]

extern crate cobalt;
extern crate getopts;
extern crate env_logger;
extern crate notify;
extern crate ghp;

#[macro_use]
extern crate nickel;

#[macro_use]
extern crate log;

use getopts::Options;
use std::env;
use std::fs;
use cobalt::Config;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;
use nickel::{Nickel, Options as NickelOptions, StaticFilesHandler};
use ghp::import_dir;

use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;
use std::thread;

fn print_version() {
    println!("0.2.0");
}

fn print_usage(opts: Options) {
    let usage = concat!("\n\tbuild -- build the cobalt project at the source dir",
                        "\n\tserve -- build and serve the cobalt project at the source dir",
                        "\n\twatch -- build, serve, and watch the project at the source dir",
                        "\n\tupload -- moves the contents of the dest folder to the gh-pages branch");
    println!("{}", opts.usage(usage));
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();

    opts.optopt("s", "source", "Source folder, Default: ./", "");
    opts.optopt("d", "destination", "Destination folder, Default: ./", "");
    opts.optopt("c",
                "config",
                "Config file to use, Default: .cobalt.yml",
                "");
    opts.optopt("l",
                "layouts",
                "\tLayout templates folder, Default: _layouts/",
                "");
    opts.optopt("p", "posts", "Posts folder, Default: _posts/", "");
    opts.optopt("P", "port", "Port to serve from, Default: 3000", "");

    opts.optflag("", "debug", "Log verbose (debug level) information");
    opts.optflag("", "trace", "Log ultra-verbose (trace level) information");
    opts.optflag("", "silent", "Suppress all output");
    opts.optflag("h", "help", "Print this help menu");
    opts.optflag("v", "version", "Display version");

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

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    if matches.opt_present("version") {
        print_version();
        return;
    }

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);
    builder.filter(None, LogLevelFilter::Info);

    if matches.opt_present("debug") {
        builder.filter(None, LogLevelFilter::Debug);
    }

    if matches.opt_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.opt_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = match matches.opt_str("config") {
        Some(config) => config,
        None => "./.cobalt.yml".to_owned(),
    };

    // Fetch config information if available
    let mut config: Config = if fs::metadata(&config_path).is_ok() {
        info!("Using config file {}", &config_path);

        match Config::from_file(&config_path) {
            Ok(config) => config,
            Err(e) => {
                error!("Error reading config file:");
                error!("{}", e);
                std::process::exit(1);
            }
        }
    } else {
        Default::default()
    };

    if let Some(source) = matches.opt_str("s") {
        config.source = source;
    };

    if let Some(dest) = matches.opt_str("d") {
        config.dest = dest;
    };

    if let Some(layouts) = matches.opt_str("layouts") {
        config.layouts = layouts;
    };

    if let Some(posts) = matches.opt_str("posts") {
        config.posts = posts;
    };

    let command = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(opts);
        return;
    };

    // Check for port and set port variable to it
    let port = matches.opt_str("port").unwrap_or("3000".to_owned());

    match command.as_ref() {
        "build" => {
            build(&config);
        }

        "serve" => {
            build(&config);
            serve(&config.dest, &port);
        }

        "watch" => {
            build(&config);

            let dest = config.dest.clone();
            thread::spawn(move || {
                serve(&dest, &port);
            });

            let (tx, rx) = channel();
            let w: Result<RecommendedWatcher, Error> = Watcher::new(tx);

            match w {
                Ok(mut watcher) => {
                    // TODO: clean up this unwrap
                    watcher.watch(&config.source).unwrap();
                    info!("Watching {:?} for changes", &config.source);

                    loop {
                        match rx.recv() {
                            Ok(val) => {
                                trace!("file changed {:?}", val);
                                info!("Rebuilding cobalt site...");
                                build(&config);
                            }

                            Err(e) => {
                                error!("[Notify Error]: {}", e);
                                std::process::exit(1);
                            }
                        }
                    }
                }
                Err(e) => {
                    error!("[Notify Error]: {}", e);
                    std::process::exit(1);
                }
            }
        }

        "upload" => {
            info!("Importing {} to gh-pages", &config.dest);

            let meta = match fs::metadata(&config.dest) {
                Ok(data) => data,

                Err(e) => {
                    error!("{}", e);
                    error!("Import not successful");
                    std::process::exit(1);
                }
            };

            if meta.is_dir() {
                match import_dir(&config.dest, "gh-pages", "cobalt site upload") {
                    Ok(_) => info!("Import successful"),
                    Err(e) => {
                        error!("{}", e);
                        error!("Import not successful");
                        std::process::exit(1);
                    }
                }
            } else {
                error!("Build dir is not a directory: {}", &config.dest);
                error!("Import not successful");
                std::process::exit(1);
            }
        }

        _ => {
            print_usage(opts);
            return;
        }
    }
}

fn build(config: &Config) {
    info!("Building from {} into {}", config.source, config.dest);
    match cobalt::build(&config) {
        Ok(_) => info!("Build successful"),
        Err(e) => {
            error!("{}", e);
            error!("Build not successful");
            std::process::exit(1);
        }
    };
}

fn serve(dest: &str, port: &str) {
    info!("Serving {:?} through static file server", dest);
    let mut server = Nickel::new();
    server.options = NickelOptions::default().output_on_listen(false);

    server.utilize(StaticFilesHandler::new(dest));

    let ip = "127.0.0.1:".to_owned() + port;
    info!("Server Listening on {}", &ip);
    info!("Ctrl-c to stop the server");
    server.listen(&*ip);
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(libc)]
#![feature(nll)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
#![feature(rustc_private)]
#![feature(specialization)]
#![feature(stmt_expr_attributes)]
#![recursion_limit = "256"]

extern crate libc;
extern crate proc_macro;

#[macro_use]
extern crate rustc;
#[macro_use]
extern crate rustc_data_structures;

pub use rmeta::{provide, provide_extern};

mod dependency_format;
mod foreign_modules;
mod link_args;
mod native_libs;
mod rmeta;

pub mod creader;
pub mod dynamic_lib;
pub mod locator;

pub fn validate_crate_name(
    sess: Option<&rustc::session::Session>,
    s: &str,
    sp: Option<rustc_span::Span>,
) {
    let mut err_count = 0;
    {
        let mut say = |s: &str| {
            match (sp, sess) {
                (_, None) => bug!("{}", s),
                (Some(sp), Some(sess)) => sess.span_err(sp, s),
                (None, Some(sess)) => sess.err(s),
            }
            err_count += 1;
        };
        if s.is_empty() {
            say("crate name must not be empty");
        }
        for c in s.chars() {
            if c.is_alphanumeric() {
                continue;
            }
            if c == '_' {
                continue;
            }
            say(&format!("invalid character `{}` in crate name: `{}`", c, s));
        }
    }

    if err_count > 0 {
        sess.unwrap().abort_if_errors();
    }
}
<commit_msg>Remove unused feature gates from librustc_metadata<commit_after>#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(proc_macro_internals)]
#![feature(specialization)]
#![feature(stmt_expr_attributes)]
#![recursion_limit = "256"]

extern crate libc;
extern crate proc_macro;

#[macro_use]
extern crate rustc;
#[macro_use]
extern crate rustc_data_structures;

pub use rmeta::{provide, provide_extern};

mod dependency_format;
mod foreign_modules;
mod link_args;
mod native_libs;
mod rmeta;

pub mod creader;
pub mod dynamic_lib;
pub mod locator;

pub fn validate_crate_name(
    sess: Option<&rustc::session::Session>,
    s: &str,
    sp: Option<rustc_span::Span>,
) {
    let mut err_count = 0;
    {
        let mut say = |s: &str| {
            match (sp, sess) {
                (_, None) => bug!("{}", s),
                (Some(sp), Some(sess)) => sess.span_err(sp, s),
                (None, Some(sess)) => sess.err(s),
            }
            err_count += 1;
        };
        if s.is_empty() {
            say("crate name must not be empty");
        }
        for c in s.chars() {
            if c.is_alphanumeric() {
                continue;
            }
            if c == '_' {
                continue;
            }
            say(&format!("invalid character `{}` in crate name: `{}`", c, s));
        }
    }

    if err_count > 0 {
        sess.unwrap().abort_if_errors();
    }
}
<|endoftext|>