<commit_before>//! OpenGL back-end for Piston-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;
use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::color::gamma_srgb_to_linear;
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};

// Local crate.
use draw_state;
use Texture;
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
    color_buffer: [[f32; 4]; BUFFER_SIZE],
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: GLSL) -> Self {
        use shaders::colored;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            Shaders::new().set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
                          .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            Shaders::new().set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
                          .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            if cfg!(not(target_os = "emscripten")) {
                gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            }
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            color_buffer: [[0.0; 4]; BUFFER_SIZE],
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: GLSL) -> Self {
        use shaders::textured;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            Shaders::new().set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
                          .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            Shaders::new().set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
                          .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            if cfg!(not(target_os = "emscripten")) {
                gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            }
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let c_color = CString::new("color").unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program, c_color.as_ptr())
            };
        drop(c_color);
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    // Keeps track of the current draw state.
    current_draw_state: Option<DrawState>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: OpenGL) -> Self {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_glsl();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            current_draw_state: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Sets the current draw state, by detecting changes.
    pub fn use_draw_state(&mut self, draw_state: &DrawState) {
        match self.current_draw_state {
            None => {
                draw_state::bind_scissor(draw_state.scissor);
                draw_state::bind_stencil(draw_state.stencil);
                draw_state::bind_blend(draw_state.blend);
            }
            Some(ref old_state) => {
                draw_state::bind_state(old_state, draw_state);
            }
        }
        self.current_draw_state = Some(*draw_state);
    }

    /// Unsets the current draw state.
    ///
    /// This forces the current draw state to be set on next drawing call.
    pub fn clear_draw_state(&mut self) {
        self.current_draw_state = None;
    }

    /// Draws graphics.
    pub fn draw<F, U>(&mut self, viewport: Viewport, f: F) -> U
        where
            F: FnOnce(Context, &mut Self) -> U
    {
        let rect = viewport.rect;
        let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
        self.viewport(x, y, w, h);
        self.clear_program();
        unsafe { gl::Enable(gl::FRAMEBUFFER_SRGB); }
        let c = Context::new_viewport(viewport);
        f(c, self)
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }
}

impl Graphics for GlGraphics {
    type Texture = Texture;

    fn clear_color(&mut self, color: [f32; 4]) {
        let color = gamma_srgb_to_linear(color);
        unsafe {
            let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn clear_stencil(&mut self, value: u8) {
        unsafe {
            gl::ClearStencil(value as i32);
        }
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            shader.color_buffer = [color; BUFFER_SIZE];
            shader.color.set(&shader.color_buffer);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_panic]
fn test_gl_loaded() {
    GlGraphics::new(OpenGL::V3_2);
}
<commit_msg>Pick WebGL shaders when targeting emscripten<commit_after>//! OpenGL back-end for Piston-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;
use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::color::gamma_srgb_to_linear;
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};

// Local crate.
use draw_state;
use Texture;
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: DynamicAttribute,
    color_buffer: [[f32; 4]; BUFFER_SIZE],
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: GLSL) -> Self {
        use shaders::colored;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match if cfg!(target_os = "emscripten") {
                compile_shader(gl::VERTEX_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(colored::VERTEX_GLSL_120_WEBGL))
                        .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE_WEBGL))
                        .get(glsl).unwrap())
            } else {
                compile_shader(gl::VERTEX_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
                        .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
                        .get(glsl).unwrap())
            }
        {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match if cfg!(target_os = "emscripten") {
                compile_shader(gl::FRAGMENT_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120_WEBGL))
                        .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE_WEBGL))
                        .get(glsl).unwrap())
            } else {
                compile_shader(gl::FRAGMENT_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
                        .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
                        .get(glsl).unwrap())
            }
        {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            if cfg!(not(target_os = "emscripten")) {
                gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            }
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = DynamicAttribute::rgba(
                program,
                "color",
                vao
            ).unwrap();
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            color_buffer: [[0.0; 4]; BUFFER_SIZE],
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: GLSL) -> Self {
        use shaders::textured;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match if cfg!(target_os = "emscripten") {
                compile_shader(gl::VERTEX_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(textured::VERTEX_GLSL_120_WEBGL))
                        .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE_WEBGL))
                        .get(glsl).unwrap())
            } else {
                compile_shader(gl::VERTEX_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
                        .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
                        .get(glsl).unwrap())
            }
        {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match if cfg!(target_os = "emscripten") {
                compile_shader(gl::FRAGMENT_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120_WEBGL))
                        .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE_WEBGL))
                        .get(glsl).unwrap())
            } else {
                compile_shader(gl::FRAGMENT_SHADER,
                    Shaders::new()
                        .set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
                        .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
                        .get(glsl).unwrap())
            }
        {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            if cfg!(not(target_os = "emscripten")) {
                gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            }
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let c_color = CString::new("color").unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program, c_color.as_ptr())
            };
        drop(c_color);
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    // Keeps track of the current draw state.
    current_draw_state: Option<DrawState>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: OpenGL) -> Self {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_glsl();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            current_draw_state: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Sets the current draw state, by detecting changes.
    pub fn use_draw_state(&mut self, draw_state: &DrawState) {
        match self.current_draw_state {
            None => {
                draw_state::bind_scissor(draw_state.scissor);
                draw_state::bind_stencil(draw_state.stencil);
                draw_state::bind_blend(draw_state.blend);
            }
            Some(ref old_state) => {
                draw_state::bind_state(old_state, draw_state);
            }
        }
        self.current_draw_state = Some(*draw_state);
    }

    /// Unsets the current draw state.
    ///
    /// This forces the current draw state to be set on next drawing call.
    pub fn clear_draw_state(&mut self) {
        self.current_draw_state = None;
    }

    /// Draws graphics.
    pub fn draw<F, U>(&mut self, viewport: Viewport, f: F) -> U
        where
            F: FnOnce(Context, &mut Self) -> U
    {
        let rect = viewport.rect;
        let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
        self.viewport(x, y, w, h);
        self.clear_program();
        unsafe { gl::Enable(gl::FRAMEBUFFER_SRGB); }
        let c = Context::new_viewport(viewport);
        f(c, self)
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }
}

impl Graphics for GlGraphics {
    type Texture = Texture;

    fn clear_color(&mut self, color: [f32; 4]) {
        let color = gamma_srgb_to_linear(color);
        unsafe {
            let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn clear_stencil(&mut self, value: u8) {
        unsafe {
            gl::ClearStencil(value as i32);
        }
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            shader.color_buffer = [color; BUFFER_SIZE];
            shader.color.set(&shader.color_buffer);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_panic]
fn test_gl_loaded() {
    GlGraphics::new(OpenGL::V3_2);
}
<|endoftext|>


<commit_before>//! An HTTP implementation of Hamelin supporting GET and POST.
#![cfg_attr(feature = "hyper", feature(env, old_io, std_misc))]
#[cfg(feature = "hyper")] extern crate hamelin;
#[cfg(feature = "hyper")] extern crate hyper;

#[cfg(feature = "hyper")] use std::borrow::ToOwned;
#[cfg(feature = "hyper")] use std::env::args;
#[cfg(feature = "hyper")] use std::old_io::timer::sleep;
#[cfg(feature = "hyper")] use std::time::duration::Duration;
#[cfg(feature = "hyper")] use hamelin::Hamelin;
#[cfg(feature = "hyper")] use hyper::{Get, Post};
#[cfg(feature = "hyper")] use hyper::server::{Handler, Request, Response, Server};
#[cfg(feature = "hyper")] use hyper::uri::RequestUri::AbsolutePath;

#[cfg(feature = "hyper")]
struct HamelinHandler(Hamelin);

#[cfg(feature = "hyper")]
impl Handler for HamelinHandler {
    fn handle(&self, mut req: Request, mut res: Response) {
        let &HamelinHandler(ref hamelin) = self;
        let path = match req.uri {
            AbsolutePath(ref path) => match &req.method {
                &Post => path.to_owned(),
                &Get => path.to_owned(),
                _ => {
                    *res.status_mut() = hyper::NotFound;
                    res.start().and_then(|res| res.end()).unwrap();
                    return;
                }
            },
            _ => {
                res.start().and_then(|res| res.end()).unwrap();
                return;
            }
        };
        let mut guard = hamelin.spawn_with_env(&[("H-TYPE", "HAMELIN.RS-HTTP-POST-0.1"),
                                                 ("H-CLIENT", &path),
                                                 ("H-URI", &path)]).unwrap();
        guard.write_line(&req.read_to_string().unwrap()).unwrap();
        guard.eof().unwrap();
        sleep(Duration::milliseconds(100));
        let mut res = res.start().unwrap();
        while let Ok(line) = guard.read_line() {
            res.write_line(&line).unwrap();
        }
        res.end().unwrap();
    }
}

#[cfg(feature = "hyper")]
fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 3 {
        println!("Usage: hamelin host port command [args]");
        return;
    }
    let hamelin = Hamelin::new(&args[2], if args.len() > 3 {
        Some(&args[3..])
    } else {
        None
    });
    let server = Server::http(args[0].parse().ok().expect("Invalid IP address."),
                              args[1].parse().ok().expect("Invalid port number."));
    let _guard = server.listen(HamelinHandler(hamelin)).unwrap();
    println!("Listening on http://{}:{}/", args[0], args[1]);
}

#[cfg(not(feature = "hyper"))]
fn main() {
    println!("HTTP daemon must be compiled with hyper.");
}
<commit_msg>Simplified HTTP implementation a bit with tuple indexing.<commit_after>//! An HTTP implementation of Hamelin supporting GET and POST.
#![cfg_attr(feature = "hyper", feature(env, old_io, std_misc))]
#[cfg(feature = "hyper")] extern crate hamelin;
#[cfg(feature = "hyper")] extern crate hyper;

#[cfg(feature = "hyper")] use std::borrow::ToOwned;
#[cfg(feature = "hyper")] use std::env::args;
#[cfg(feature = "hyper")] use std::old_io::timer::sleep;
#[cfg(feature = "hyper")] use std::time::duration::Duration;
#[cfg(feature = "hyper")] use hamelin::Hamelin;
#[cfg(feature = "hyper")] use hyper::{Get, Post};
#[cfg(feature = "hyper")] use hyper::server::{Handler, Request, Response, Server};
#[cfg(feature = "hyper")] use hyper::uri::RequestUri::AbsolutePath;

#[cfg(feature = "hyper")]
struct HamelinHandler(Hamelin);

#[cfg(feature = "hyper")]
impl Handler for HamelinHandler {
    fn handle(&self, mut req: Request, mut res: Response) {
        let path = match req.uri {
            AbsolutePath(ref path) => match &req.method {
                &Post => path.to_owned(),
                &Get => path.to_owned(),
                _ => {
                    *res.status_mut() = hyper::NotFound;
                    res.start().and_then(|res| res.end()).unwrap();
                    return;
                }
            },
            _ => {
                res.start().and_then(|res| res.end()).unwrap();
                return;
            }
        };
        let mut guard = self.0.spawn_with_env(&[("H-TYPE", "HAMELIN.RS-HTTP-POST-0.1"),
                                                ("H-CLIENT", &path),
                                                ("H-URI", &path)]).unwrap();
        guard.write_line(&req.read_to_string().unwrap()).unwrap();
        guard.eof().unwrap();
        sleep(Duration::milliseconds(100));
        let mut res = res.start().unwrap();
        while let Ok(line) = guard.read_line() {
            res.write_line(&line).unwrap();
        }
        res.end().unwrap();
    }
}

#[cfg(feature = "hyper")]
fn main() {
    let args: Vec<_> = args().skip(1).collect();
    if args.len() < 3 {
        println!("Usage: hamelin host port command [args]");
        return;
    }
    let hamelin = Hamelin::new(&args[2], if args.len() > 3 {
        Some(&args[3..])
    } else {
        None
    });
    let server = Server::http(args[0].parse().ok().expect("Invalid IP address."),
                              args[1].parse().ok().expect("Invalid port number."));
    let _guard = server.listen(HamelinHandler(hamelin)).unwrap();
    println!("Listening on http://{}:{}/", args[0], args[1]);
}

#[cfg(not(feature = "hyper"))]
fn main() {
    println!("HTTP daemon must be compiled with hyper.");
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, stdin, Error, Write, BufRead, BufReader};
use std::process::exit;
use std::cmp::Ordering;
use coreutils::ArgParser;
use std::fs::File;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = r#"
NAME
    sort - sort lines of text files

SYNOPSIS
    sort [ -h | --help | -n ] [FILE]...

DESCRIPTION
    Write sorted concatenation of FILE(s) to standard output.

    With no FILE, read standard input.

OPTIONS
    -h
    --help
        display this help and exit
    -n
    --numeric-sort
        sort numerically
"#; /* @MANEND */

fn get_first_f64(a: &str) -> f64 {
    for s in a.split_whitespace() {
        match s.parse::<f64>() {
            Ok(a) => return a,
            Err(_) => (),
        }
    }
    return std::f64::NEG_INFINITY;
}

fn numeric_compare(a: &String, b: &String) -> Ordering {
    let fa = get_first_f64(a);
    let fb = get_first_f64(b);

    if fa > fb {
        Ordering::Greater
    } else if fa < fb {
        Ordering::Less
    } else {
        Ordering::Equal
    }
}

fn lines_from_stdin() -> Result<Vec<String>, Error> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let f = BufReader::new(stdin.lock());
    for line in f.lines() {
        match line {
            Ok(l) => lines.push(l),
            Err(e) => return Err(e),
        }
    }
    Ok(lines)
}

fn lines_from_files(paths: &Vec<&String>) -> Result<Vec<String>, Error> {
    let mut lines = Vec::new();

    for path in paths {
        let f = try!(File::open(path));
        let f = BufReader::new(f);
        for line in f.lines() {
            match line {
                Ok(l) => lines.push(l),
                Err(e) => return Err(e),
            }
        }
    }
    Ok(lines)
}

fn main() {

    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(2)
        .add_flag(&["n", "numeric-sort"])
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let lines = match parser.args.is_empty() {
        true => lines_from_stdin(),
        false => {
            let mut paths = Vec::new();
            for dir in parser.args.iter() {
                paths.push(dir);
            }
            lines_from_files(&paths)
        }
    };

    match lines {
        Ok(mut l) => {
            if parser.found("numeric-sort") {
                l.sort_by(numeric_compare);
            } else {
                l.sort();
            }
            for x in l {
                println!("{}", x);
            }
        }
        Err(e) => {
            let _ = write!(stderr, "{}", e);
        }
    }
}
<commit_msg>Add --unique option to sort<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, stdin, Error, Write, BufRead, BufReader};
use std::process::exit;
use std::cmp::Ordering;
use coreutils::ArgParser;
use std::fs::File;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = r#"
NAME
    sort - sort lines of text files

SYNOPSIS
    sort [ -h | --help | -n ] [FILE]...

DESCRIPTION
    Write sorted concatenation of FILE(s) to standard output.

    With no FILE, read standard input.

OPTIONS
    -h
    --help
        display this help and exit
    -n
    --numeric-sort
        sort numerically
"#; /* @MANEND */

fn get_first_f64(a: &str) -> f64 {
    for s in a.split_whitespace() {
        match s.parse::<f64>() {
            Ok(a) => return a,
            Err(_) => (),
        }
    }
    return std::f64::NEG_INFINITY;
}

fn numeric_compare(a: &String, b: &String) -> Ordering {
    let fa = get_first_f64(a);
    let fb = get_first_f64(b);

    if fa > fb {
        Ordering::Greater
    } else if fa < fb {
        Ordering::Less
    } else {
        Ordering::Equal
    }
}

fn lines_from_stdin() -> Result<Vec<String>, Error> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let f = BufReader::new(stdin.lock());
    for line in f.lines() {
        match line {
            Ok(l) => lines.push(l),
            Err(e) => return Err(e),
        }
    }
    Ok(lines)
}

fn lines_from_files(paths: &Vec<&String>) -> Result<Vec<String>, Error> {
    let mut lines = Vec::new();

    for path in paths {
        let f = try!(File::open(path));
        let f = BufReader::new(f);
        for line in f.lines() {
            match line {
                Ok(l) => lines.push(l),
                Err(e) => return Err(e),
            }
        }
    }
    Ok(lines)
}

fn main() {

    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(2)
        .add_flag(&["n", "numeric-sort"])
        .add_flag(&["u", "unique"])
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let lines = match parser.args.is_empty() {
        true => lines_from_stdin(),
        false => {
            let mut paths = Vec::new();
            for dir in parser.args.iter() {
                paths.push(dir);
            }
            lines_from_files(&paths)
        }
    };

    match lines {
        Ok(mut l) => {
            if parser.found("numeric-sort") {
                l.sort_by(numeric_compare);
            } else {
                l.sort();
            }
            if parser.found("unique") {
                l.dedup();
            }
            for x in l {
                println!("{}", x);
            }
        }
        Err(e) => {
            let _ = write!(stderr, "{}", e);
        }
    }
}
<|endoftext|>


<commit_before>use super::{
    general::{cfg_deprecated, doc_hidden, version_condition},
    signal_body,
    trampoline::{self, func_string},
};
use crate::{
    analysis,
    chunk::Chunk,
    consts::TYPE_PARAMETERS_START,
    env::Env,
    library,
    writer::{primitives::tabs, ToCode},
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::signals::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    let commented = analysis.trampoline.is_err();
    let comment_prefix = if commented { "//" } else { "" };
    let pub_prefix = if in_trait { "" } else { "pub " };

    let function_type = function_type_string(env, analysis, true);
    let declaration = declaration(analysis, &function_type);
    let suffix = if only_declaration { ";" } else { " {" };

    writeln!(w)?;
    if !in_trait || only_declaration {
        cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
    }
    version_condition(w, env, analysis.version, commented, indent)?;
    doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix
    )?;

    if !only_declaration {
        if !commented {
            if let Ok(ref trampoline) = analysis.trampoline {
                trampoline::generate(w, env, trampoline, in_trait, 2)?;
            }
        }
        match function_type {
            Some(_) => {
                let body = body(analysis, in_trait).to_code(env);
                for s in body {
                    writeln!(w, "{}{}", tabs(indent), s)?;
                }
            }
            _ => {
                if let Err(ref errors) = analysis.trampoline {
                    for error in errors {
                        writeln!(w, "{}{}\t{}", tabs(indent), comment_prefix, error)?;
                    }
                    writeln!(w, "{}{}}}", tabs(indent), comment_prefix)?;
                } else {
                    writeln!(
                        w,
                        "{}{}\tTODO: connect to trampoline\n{0}{1}}}",
                        tabs(indent),
                        comment_prefix
                    )?;
                }
            }
        }
    }

    if function_type.is_none() {
        // Signal incomplete, can't generate emit
        return Ok(());
    }

    if let Some(ref emit_name) = analysis.action_emit_name {
        writeln!(w)?;
        if !in_trait || only_declaration {
            cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
        }
        version_condition(w, env, analysis.version, commented, indent)?;

        let function_type = function_type_string(env, analysis, false);

        writeln!(
            w,
            "{}{}{}fn {}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            emit_name,
            function_type.unwrap(),
            suffix
        )?;

        if !only_declaration {
            let trampoline = match analysis.trampoline.as_ref() {
                Ok(trampoline) => trampoline,
                Err(_) => panic!(
                    "Internal error: can't find trampoline for signal '{}'",
                    analysis.signal_name,
                ),
            };
            let mut args = String::with_capacity(100);

            for (pos, par) in trampoline.parameters.rust_parameters.iter().enumerate() {
                // Skip the self parameter
                if pos == 0 {
                    continue;
                }

                if pos > 1 {
                    args.push_str(", ");
                }
                args.push('&');
                args.push_str(&par.name);
            }

            writeln!(
                w,
                "{}let {} = unsafe {{ glib::Object::from_glib_borrow(self.to_glib_none().0 as *mut gobject_sys::GObject).emit(\"{}\", &[{}]).unwrap() }};",
                tabs(indent + 1),
                if trampoline.ret.typ != Default::default() {
                    "res"
                } else {
                    "_"
                },
                analysis.signal_name,
                args,
            )?;

            if trampoline.ret.typ != Default::default() {
                if trampoline.ret.nullable == library::Nullable(true) {
                    writeln!(w, "{}res.unwrap().get()", tabs(indent + 1),)?;
                } else {
                    writeln!(w, "{}res.unwrap().get().unwrap()", tabs(indent + 1),)?;
                }
            }
            writeln!(w, "{}}}", tabs(indent))?;
        }
    }

    Ok(())
}

fn function_type_string(
    env: &Env,
    analysis: &analysis::signals::Info,
    closure: bool,
) -> Option<String> {
    if analysis.trampoline.is_err() {
        return None;
    }

    let trampoline = match analysis.trampoline.as_ref() {
        Ok(trampoline) => trampoline,
        Err(_) => panic!(
            "Internal error: can't find trampoline for signal '{}'",
            analysis.signal_name
        ),
    };

    let type_ = func_string(
        env,
        trampoline,
        if closure {
            Some((TYPE_PARAMETERS_START, "Self"))
        } else {
            Some((TYPE_PARAMETERS_START, "self"))
        },
        closure,
    );
    Some(type_)
}

fn declaration(analysis: &analysis::signals::Info, function_type: &Option<String>) -> String {
    let bounds = bounds(function_type);
    let param_str = "&self, f: F";
    let return_str = " -> SignalHandlerId";
    format!(
        "fn {}<{}>({}){}",
        analysis.connect_name, bounds, param_str, return_str
    )
}

fn bounds(function_type: &Option<String>) -> String {
    match *function_type {
        Some(ref type_) => format!("F: {}", type_),
        _ => "Unsupported or ignored types".to_owned(),
    }
}

fn body(analysis: &analysis::signals::Info, in_trait: bool) -> Chunk {
    let mut builder = signal_body::Builder::new();

    builder
        .signal_name(&analysis.signal_name)
        .trampoline_name(&analysis.trampoline.as_ref().unwrap().name)
        .in_trait(in_trait);

    builder.generate()
}
<commit_msg>Migrate signal emiters to new signature for `Value::get`<commit_after>use super::{
    general::{cfg_deprecated, doc_hidden, version_condition},
    signal_body,
    trampoline::{self, func_string},
};
use crate::{
    analysis,
    chunk::Chunk,
    consts::TYPE_PARAMETERS_START,
    env::Env,
    library,
    writer::{primitives::tabs, ToCode},
};
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::signals::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    let commented = analysis.trampoline.is_err();
    let comment_prefix = if commented { "//" } else { "" };
    let pub_prefix = if in_trait { "" } else { "pub " };

    let function_type = function_type_string(env, analysis, true);
    let declaration = declaration(analysis, &function_type);
    let suffix = if only_declaration { ";" } else { " {" };

    writeln!(w)?;
    if !in_trait || only_declaration {
        cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
    }
    version_condition(w, env, analysis.version, commented, indent)?;
    doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix
    )?;

    if !only_declaration {
        if !commented {
            if let Ok(ref trampoline) = analysis.trampoline {
                trampoline::generate(w, env, trampoline, in_trait, 2)?;
            }
        }
        match function_type {
            Some(_) => {
                let body = body(analysis, in_trait).to_code(env);
                for s in body {
                    writeln!(w, "{}{}", tabs(indent), s)?;
                }
            }
            _ => {
                if let Err(ref errors) = analysis.trampoline {
                    for error in errors {
                        writeln!(w, "{}{}\t{}", tabs(indent), comment_prefix, error)?;
                    }
                    writeln!(w, "{}{}}}", tabs(indent), comment_prefix)?;
                } else {
                    writeln!(
                        w,
                        "{}{}\tTODO: connect to trampoline\n{0}{1}}}",
                        tabs(indent),
                        comment_prefix
                    )?;
                }
            }
        }
    }

    if function_type.is_none() {
        // Signal incomplete, can't generate emit
        return Ok(());
    }

    if let Some(ref emit_name) = analysis.action_emit_name {
        writeln!(w)?;
        if !in_trait || only_declaration {
            cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
        }
        version_condition(w, env, analysis.version, commented, indent)?;

        let function_type = function_type_string(env, analysis, false);

        writeln!(
            w,
            "{}{}{}fn {}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            emit_name,
            function_type.unwrap(),
            suffix
        )?;

        if !only_declaration {
            let trampoline = match analysis.trampoline.as_ref() {
                Ok(trampoline) => trampoline,
                Err(_) => panic!(
                    "Internal error: can't find trampoline for signal '{}'",
                    analysis.signal_name,
                ),
            };
            let mut args = String::with_capacity(100);

            for (pos, par) in trampoline.parameters.rust_parameters.iter().enumerate() {
                // Skip the self parameter
                if pos == 0 {
                    continue;
                }

                if pos > 1 {
                    args.push_str(", ");
                }
                args.push('&');
                args.push_str(&par.name);
            }

            writeln!(
                w,
                "{}let {} = unsafe {{ glib::Object::from_glib_borrow(self.to_glib_none().0 as *mut gobject_sys::GObject).emit(\"{}\", &[{}]).unwrap() }};",
                tabs(indent + 1),
                if trampoline.ret.typ != Default::default() {
                    "res"
                } else {
                    "_"
                },
                analysis.signal_name,
                args,
            )?;

            if trampoline.ret.typ != Default::default() {
                let unwrap = if trampoline.ret.nullable == library::Nullable(true) {
                    ""
                } else {
                    ".unwrap()"
                };

                writeln!(
                    w,
                    "{}res.unwrap().get().expect(\"Return Value for `{}`\"){}",
                    tabs(indent + 1),
                    emit_name,
                    unwrap,
                )?;
            }
            writeln!(w, "{}}}", tabs(indent))?;
        }
    }

    Ok(())
}

fn function_type_string(
    env: &Env,
    analysis: &analysis::signals::Info,
    closure: bool,
) -> Option<String> {
    if analysis.trampoline.is_err() {
        return None;
    }

    let trampoline = match analysis.trampoline.as_ref() {
        Ok(trampoline) => trampoline,
        Err(_) => panic!(
            "Internal error: can't find trampoline for signal '{}'",
            analysis.signal_name
        ),
    };

    let type_ = func_string(
        env,
        trampoline,
        if closure {
            Some((TYPE_PARAMETERS_START, "Self"))
        } else {
            Some((TYPE_PARAMETERS_START, "self"))
        },
        closure,
    );
    Some(type_)
}

fn declaration(analysis: &analysis::signals::Info, function_type: &Option<String>) -> String {
    let bounds = bounds(function_type);
    let param_str = "&self, f: F";
    let return_str = " -> SignalHandlerId";
    format!(
        "fn {}<{}>({}){}",
        analysis.connect_name, bounds, param_str, return_str
    )
}

fn bounds(function_type: &Option<String>) -> String {
    match *function_type {
        Some(ref type_) => format!("F: {}", type_),
        _ => "Unsupported or ignored types".to_owned(),
    }
}

fn body(analysis: &analysis::signals::Info, in_trait: bool) -> Chunk {
    let mut builder = signal_body::Builder::new();

    builder
        .signal_name(&analysis.signal_name)
        .trampoline_name(&analysis.trampoline.as_ref().unwrap().name)
        .in_trait(in_trait);

    builder.generate()
}
<|endoftext|>


<commit_before>use dirs;
use std::fs;
use std::path::PathBuf;

pub fn create_dir(path: &PathBuf, after_create: &dyn Fn()) {
    if path.exists() {
        println!("A directory already exists at {}.", path.to_string_lossy())
    } else {
        println!("Creating directory at {}.", path.to_string_lossy());
        match fs::create_dir_all(&path) {
            Ok(_) => after_create(),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }
}

pub fn create_file(path: &PathBuf, after_create: &dyn Fn()) {
    if path.exists() {
        println!("A file already exists at {}.", path.to_string_lossy())
    } else {
        println!("Creating file at {}.", path.to_string_lossy());
        match fs::File::create(&path) {
            Ok(_) => after_create(),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }
}

pub fn vim_plugins() -> PathBuf {
    let vim_plugins_path = home()
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    return vim_plugins_path;
}

pub fn vim_configuration() -> PathBuf {
    let vim_configuration_path = home().join(".vimrc");

    return vim_configuration_path;
}

pub fn repos() -> PathBuf {
    let repos_path = home().join("repos");

    return repos_path;
}

fn home() -> PathBuf {
    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    return home_path;
}
<commit_msg>Fix lint warnings<commit_after>use dirs;
use std::fs;
use std::path::PathBuf;

pub fn create_dir(path: &PathBuf, after_create: &dyn Fn()) {
    if path.exists() {
        println!("A directory already exists at {}.", path.to_string_lossy())
    } else {
        println!("Creating directory at {}.", path.to_string_lossy());
        match fs::create_dir_all(&path) {
            Ok(_) => after_create(),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }
}

pub fn create_file(path: &PathBuf, after_create: &dyn Fn()) {
    if path.exists() {
        println!("A file already exists at {}.", path.to_string_lossy())
    } else {
        println!("Creating file at {}.", path.to_string_lossy());
        match fs::File::create(&path) {
            Ok(_) => after_create(),
            Err(error) => panic!("There was a problem: {:?}", error),
        }
    }
}

pub fn vim_plugins() -> PathBuf {
    home()
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start")
}

pub fn vim_configuration() -> PathBuf {
    home().join(".vimrc")
}

pub fn repos() -> PathBuf {
    home().join("repos")
}

fn home() -> PathBuf {
    match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    }
}
<|endoftext|>


<commit_before>
use clap::ArgMatches;

use doapi::{DoManager, DoRequest};

use config::Config;
use message::CliMessage;

pub fn run(m: &ArgMatches, cfg: &mut Config) {
    if m.is_present("verbose") { cfg.verbose = true; }
    if m.is_present("nosend") { cfg.no_send = true; }
    let domgr = DoManager::with_token(&cfg.auth[..]);
    match m.subcommand() {
        ("regions", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.regions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.regions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Regions.display();
            match domgr.regions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for reg in v.iter() {
                        CliMessage::Region.display();
                        println!("\t{}\n", &reg.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo regions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("sizes", Some(m))           => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.sizes()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.sizes().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Sizes.display();
            match domgr.sizes().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for siz in v.iter() {
                        CliMessage::Size.display();
                        println!("\t{}\n", &siz.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo sizes to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("images", Some(m))          => {
            let request = if m.is_present("applications") {
                domgr.images().applications()
            } else if m.is_present("distributions") {
                domgr.images().distributions()
            } else if m.is_present("private") {
                domgr.images().private()
            } else if m.is_present("available") {
                domgr.images().available()
            } else {
                domgr.images()
            };
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &request.to_string()
                        .replace("\n", "\n\t")[..]
                ).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match request.retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Images.display();
            match request.retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for img in v.iter() {
                        CliMessage::ImageList.display();
                        println!("\t{}\n", &img.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo images to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("ssh-keys", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.ssh_keys()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.ssh_keys().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::SshKeys.display();
            match domgr.ssh_keys().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for k in v.iter() {
                        CliMessage::AnonSshKey.display();
                        println!("\t{}\n", &k.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo SSH keys to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("droplets", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.droplets()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.droplets().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Droplets.display();
            match domgr.droplets().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::AnonDroplet.display();
                        println!("\t{}", &d.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo droplets to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("domains", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.domains()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.domains().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Domains.display();
            match domgr.domains().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::Domains.display();
                        println!("\t{}", d);
                    }
                    if v.is_empty() { println!("\tNo domains to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("account-actions", Some(m)) => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.account()
                         .actions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.account().actions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Actions.display();
            match domgr.account().actions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for act in v.iter() {
                        CliMessage::Action.display();
                        println!("\t{}", act);
                    }
                    if v.is_empty() { println!("\tNo account actions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        _                      => unreachable!()
    }
}
<commit_msg>imp: fixes list account-actions and list domains output<commit_after>
use clap::ArgMatches;

use doapi::{DoManager, DoRequest};

use config::Config;
use message::CliMessage;

pub fn run(m: &ArgMatches, cfg: &mut Config) {
    if m.is_present("verbose") { cfg.verbose = true; }
    if m.is_present("nosend") { cfg.no_send = true; }
    let domgr = DoManager::with_token(&cfg.auth[..]);
    match m.subcommand() {
        ("regions", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.regions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.regions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Regions.display();
            match domgr.regions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for reg in v.iter() {
                        CliMessage::Region.display();
                        println!("\t{}\n", &reg.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo regions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("sizes", Some(m))           => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.sizes()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.sizes().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Sizes.display();
            match domgr.sizes().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for siz in v.iter() {
                        CliMessage::Size.display();
                        println!("\t{}\n", &siz.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo sizes to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("images", Some(m))          => {
            let request = if m.is_present("applications") {
                domgr.images().applications()
            } else if m.is_present("distributions") {
                domgr.images().distributions()
            } else if m.is_present("private") {
                domgr.images().private()
            } else if m.is_present("available") {
                domgr.images().available()
            } else {
                domgr.images()
            };
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &request.to_string()
                        .replace("\n", "\n\t")[..]
                ).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match request.retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Images.display();
            match request.retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for img in v.iter() {
                        CliMessage::ImageList.display();
                        println!("\t{}\n", &img.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo images to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("ssh-keys", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.ssh_keys()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.ssh_keys().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::SshKeys.display();
            match domgr.ssh_keys().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for k in v.iter() {
                        CliMessage::AnonSshKey.display();
                        println!("\t{}\n", &k.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo SSH keys to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("droplets", Some(m))        => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.droplets()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.droplets().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Droplets.display();
            match domgr.droplets().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::AnonDroplet.display();
                        println!("\t{}", &d.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo droplets to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("domains", Some(m))         => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.domains()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.domains().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Domains.display();
            match domgr.domains().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for d in v.iter() {
                        CliMessage::Domains.display();
                        println!("\t{}\n", &d.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo domains to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        ("account-actions", Some(m)) => {
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::Request(
                    &domgr.account()
                         .actions()
                         .to_string()
                         .replace("\n", "\n\t")[..]).display();
            }
            if cfg.no_send || m.is_present("nosend") { return }
            if cfg.verbose || m.is_present("verbose") {
                CliMessage::JsonResponse.display();
                match domgr.account().actions().retrieve_json() {
                    Ok(s)  => {
                        CliMessage::Success.display();
                        println!("\n\t{}\n", s);
                    },
                    Err(e) => {
                        CliMessage::Failure.display();
                        println!("\n\t{}\n", e);
                    }
                }
            }
            CliMessage::Actions.display();
            match domgr.account().actions().retrieve() {
                Ok(v) => {
                    CliMessage::Success.display();
                    for act in v.iter() {
                        CliMessage::Action.display();
                        println!("\t{}\n", &act.to_string()[..].replace("\n", "\n\t"));
                    }
                    if v.is_empty() { println!("\tNo account actions to dipslay"); }
                },
                Err(e) => {
                    CliMessage::Failure.display();
                    println!("{}\n", e);
                }
            }
        },
        _                      => unreachable!()
    }
}
<|endoftext|>


<commit_before>use ast::Ast;
use std::fmt;

/**
 * Representation of commands for AST
 */

#[derive(Debug, Clone)]
pub enum Command {
    // stdio
    Out,            //w
    In,             //e
    // Manipulate <value>
    Put,            // put value in selected memory
    Yank,           // y value from selected memory
    Ins(Type),      // i<string>
    Incr,           // a
    Decr,           // x
    // Manipulate <pointer> / <value>
    Mark(char),     // '<char>
    Ind(char),      // `<char>
    NMar,           // ] :- increase <pointer> to next mark
    PMar,           // [ :- decrease <pointer> to previous mark
    NInd,           // } :- increase <index>
    PInd,           // { :- decrease <index>
    // Program Flow (jumps)
    BLine,          // ^ Jump to beginning of current line
    Line,           // New line used for Down and Up commands
    Down,           // j :- jump down <int> lines
    Up,             // k :- jump up <int> lines
    Next(Box<Command>),     // f<char> :- jump forward in line to <int>th <char> if exists
    Prev(Box<Command>),     // F<char> :- jump back in line to <int>th <char> if exists
    Con,            // ? :- do jump if <value> == <int>
    NCon,           // ; :- do jump if <value> != <int>
    Int(u64),       // set <int> to direct integer
    VInt,           // v :- copy <value> to <int>
    Rep,            // . :- do last command or Grp <int> times
    LP,             // ( :- start Grp
    // Group of commands inside () for loops
    Grp(Ast),
    Comment,        //comment
    Nil,            // invalid command
}

impl Command {
    pub fn from_char(inp: char) -> Command {
        match inp {
            'w' => Command::Out,
            'e' => Command::In,
            'p' => Command::Put,
            'y' => Command::Yank,
            'i' => Command::Ins(Type::C('a')),
            'a' => Command::Incr,
            'x' => Command::Decr,
            '\'' => Command::Mark('a'),
            '`' => Command::Ind('a'),
            ']' => Command::NMar,
            '[' => Command::PMar,
            '}' => Command::NInd,
            '{' => Command::PInd,
            '^' => Command::BLine,
            '\n' => Command::Line,
            'j' => Command::Down,
            'k' => Command::Up,
            'f' => Command::Next(Box::new(Command::Nil)),
            'F' => Command::Prev(Box::new(Command::Nil)),
            '?' => Command::Con,
            '!' => Command::NCon,
            '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => Command::Int(inp as u64),
            'v' => Command::VInt,
            '.' => Command::Rep,
            '(' => Command::LP,
            '/' => Command::Comment,
            _ => Command::Nil,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Type {
    S(String),
    I(i64),
    C(char),
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.clone() {
            Type::S(data) => write!(f, "{}", data),
            Type::I(data) => write!(f, "{}", data),
            Type::C(data) => write!(f, "{}", data),
        }
    }
}
<commit_msg>tidied up match statement in commands<commit_after>use ast::Ast;
use std::fmt;

/**
 * Representation of commands for AST
 */

#[derive(Debug, Clone)]
pub enum Command {
    // stdio
    Out,            //w
    In,             //e
    // Manipulate <value>
    Put,            // put value in selected memory
    Yank,           // y value from selected memory
    Ins(Type),      // i<string>
    Incr,           // a
    Decr,           // x
    // Manipulate <pointer> / <value>
    Mark(char),     // '<char>
    Ind(char),      // `<char>
    NMar,           // ] :- increase <pointer> to next mark
    PMar,           // [ :- decrease <pointer> to previous mark
    NInd,           // } :- increase <index>
    PInd,           // { :- decrease <index>
    // Program Flow (jumps)
    BLine,          // ^ Jump to beginning of current line
    Line,           // New line used for Down and Up commands
    Down,           // j :- jump down <int> lines
    Up,             // k :- jump up <int> lines
    Next(Box<Command>),     // f<char> :- jump forward in line to <int>th <char> if exists
    Prev(Box<Command>),     // F<char> :- jump back in line to <int>th <char> if exists
    Con,            // ? :- do jump if <value> == <int>
    NCon,           // ; :- do jump if <value> != <int>
    Int(u64),       // set <int> to direct integer
    VInt,           // v :- copy <value> to <int>
    Rep,            // . :- do last command or Grp <int> times
    LP,             // ( :- start Grp
    // Group of commands inside () for loops
    Grp(Ast),
    Comment,        //comment
    Nil,            // invalid command
}

impl Command {
    pub fn from_char(inp: char) -> Command {
        match inp {
            'w' => Command::Out,
            'e' => Command::In,
            'p' => Command::Put,
            'y' => Command::Yank,
            'i' => Command::Ins(Type::C('a')),
            'a' => Command::Incr,
            'x' => Command::Decr,
            '\'' => Command::Mark('a'),
            '`' => Command::Ind('a'),
            ']' => Command::NMar,
            '[' => Command::PMar,
            '}' => Command::NInd,
            '{' => Command::PInd,
            '^' => Command::BLine,
            '\n' => Command::Line,
            'j' => Command::Down,
            'k' => Command::Up,
            'f' => Command::Next(Box::new(Command::Nil)),
            'F' => Command::Prev(Box::new(Command::Nil)),
            '?' => Command::Con,
            '!' => Command::NCon,
            '0'...'9' => Command::Int(inp as u64),
            'v' => Command::VInt,
            '.' => Command::Rep,
            '(' => Command::LP,
            '/' => Command::Comment,
            _ => Command::Nil,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Type {
    S(String),
    I(i64),
    C(char),
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.clone() {
            Type::S(data) => write!(f, "{}", data),
            Type::I(data) => write!(f, "{}", data),
            Type::C(data) => write!(f, "{}", data),
        }
    }
}
<|endoftext|>