<commit_before>use parser;
use edit::ModeState;
use edit::ViMode;

pub enum CommonInstr {
    Done,
    Cancel,
    Clear,
    Noop
}

pub enum HistoryInstr {
    Next,
    Prev
}

pub enum MoveCursorInstr {
    Left,
    Right,
    Start,
    End
}

pub enum Instr {
    Common(CommonInstr),
    History(HistoryInstr),
    MoveCursor(MoveCursorInstr),
    MoveEndOfWordRight,
    MoveEndOfWordWsRight,
    MoveWordRight,
    MoveWordWsRight,
    MoveWordLeft,
    MoveWordWsLeft,
    MoveCharRight(char),
    MoveCharLeft(char),
    MoveBeforeCharRight(char),
    MoveBeforeCharLeft(char),
    DeleteCharLeftOfCursor,
    DeleteCharRightOfCursor,
    DeleteCharRightOfCursorOrEOF,
    DeleteLine,
    DeleteToEnd,
    ChangeLine,
    ChangeToEnd,
    Substitute,
    InsertAtCursor(String),
    ReplaceAtCursor(String),
    Insert,
    InsertStart,
    Append,
    AppendEnd,
    NormalMode,
    ReplaceMode,
    MoveCharMode(CharMoveType),
    DeleteMode,
    ChangeMode,
    Digit(u32),
    DoneOrEof
}

#[derive(Copy,Clone,PartialEq)]
pub enum CharMoveType {
    BeforeRight,
    BeforeLeft,
    Right,
    Left,
}

pub fn interpret_token(token: parser::Token, edit_mode_state: ModeState) -> Instr {
    match edit_mode_state {
        ModeState::Emacs => emacs_mode(token),
        ModeState::Vi(ViMode::Insert, _) => vi_insert_mode(token),
        ModeState::Vi(ViMode::Normal, _) => vi_normal_mode(token),
        ModeState::Vi(ViMode::Replace, _) => vi_replace_mode(token),
        ModeState::Vi(ViMode::MoveChar(move_type), _) => vi_move_char_mode(move_type, token),
        ModeState::Vi(ViMode::DeleteMoveChar(move_type), _) => vi_move_char_mode(move_type, token),
        ModeState::Vi(ViMode::ChangeMoveChar(move_type), _) => vi_move_char_mode(move_type, token),
        ModeState::Vi(ViMode::Delete, _) => vi_delete_mode(token),
        ModeState::Vi(ViMode::Change, _) => vi_change_mode(token),
    }
}

fn emacs_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Enter        => Instr::Common(CommonInstr::Done),
        parser::Token::Backspace    => Instr::DeleteCharLeftOfCursor,
        parser::Token::CtrlH        => Instr::DeleteCharLeftOfCursor,
        parser::Token::EscBracket3T => Instr::DeleteCharRightOfCursor,
        parser::Token::CtrlD        => Instr::DeleteCharRightOfCursorOrEOF,
        parser::Token::EscBracketA  => Instr::History(HistoryInstr::Prev),
        parser::Token::CtrlP        => Instr::History(HistoryInstr::Prev),
        parser::Token::EscBracketB  => Instr::History(HistoryInstr::Next),
        parser::Token::CtrlN        => Instr::History(HistoryInstr::Next),
        parser::Token::EscBracketC  => Instr::MoveCursor(MoveCursorInstr::Right),
        parser::Token::CtrlF        => Instr::MoveCursor(MoveCursorInstr::Right),
        parser::Token::EscBracketD  => Instr::MoveCursor(MoveCursorInstr::Left),
        parser::Token::CtrlB        => Instr::MoveCursor(MoveCursorInstr::Left),
        parser::Token::CtrlA        => Instr::MoveCursor(MoveCursorInstr::Start),
        parser::Token::EscBracketH  => Instr::MoveCursor(MoveCursorInstr::Start),
        parser::Token::CtrlE        => Instr::MoveCursor(MoveCursorInstr::End),
        parser::Token::EscBracketF  => Instr::MoveCursor(MoveCursorInstr::End),
        parser::Token::Text(text)   => Instr::InsertAtCursor(text),
        parser::Token::CtrlC        => Instr::Common(CommonInstr::Cancel),
        parser::Token::CtrlL        => Instr::Common(CommonInstr::Clear),
        _                           => Instr::Common(CommonInstr::Noop)
    }
}

fn vi_common(token: &parser::Token) -> Instr {
    match *token {
        parser::Token::Enter        => Instr::Common(CommonInstr::Done),
        parser::Token::CtrlD        => Instr::DoneOrEof,
        parser::Token::Esc          => Instr::NormalMode,
        parser::Token::Backspace    => Instr::DeleteCharLeftOfCursor,
        parser::Token::EscBracket3T => Instr::DeleteCharRightOfCursor,
        // movement keys
        parser::Token::EscBracketA  => Instr::History(HistoryInstr::Prev),
        parser::Token::EscBracketB  => Instr::History(HistoryInstr::Next),
        parser::Token::EscBracketC  => Instr::MoveCursor(MoveCursorInstr::Right),
        parser::Token::EscBracketD  => Instr::MoveCursor(MoveCursorInstr::Left),
        // home
        parser::Token::EscBracketH  => Instr::MoveCursor(MoveCursorInstr::Start),
        // end
        parser::Token::EscBracketF  => Instr::MoveCursor(MoveCursorInstr::End),
        parser::Token::CtrlC        => Instr::Common(CommonInstr::Cancel),
        parser::Token::CtrlL        => Instr::Common(CommonInstr::Clear),
        _                           => Instr::Common(CommonInstr::Noop),
    }
}

fn vi_insert_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(text)   => Instr::InsertAtCursor(text),
        _                           => vi_common(&token),
    }
}
fn vi_normal_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(text)   => match text.as_ref() {
            "h"                     => Instr::MoveCursor(MoveCursorInstr::Left),
            "j"                     => Instr::History(HistoryInstr::Next),
            "k"                     => Instr::History(HistoryInstr::Prev),
            "l"                     => Instr::MoveCursor(MoveCursorInstr::Right),
            "0"                     => Instr::Digit(0),
            "$"                     => Instr::MoveCursor(MoveCursorInstr::End),

            "x"                     => Instr::DeleteCharRightOfCursor,
            "s"                     => Instr::Substitute,
            "r"                     => Instr::ReplaceMode,
            "c"                     => Instr::ChangeMode,
            "C"                     => Instr::ChangeToEnd,
            "d"                     => Instr::DeleteMode,
            "D"                     => Instr::DeleteToEnd,

            "e"                     => Instr::MoveEndOfWordRight,
            "E"                     => Instr::MoveEndOfWordWsRight,
            "w"                     => Instr::MoveWordRight,
            "W"                     => Instr::MoveWordWsRight,
            "b"                     => Instr::MoveWordLeft,
            "B"                     => Instr::MoveWordWsLeft,
            "t"                     => Instr::MoveCharMode(CharMoveType::BeforeRight),
            "T"                     => Instr::MoveCharMode(CharMoveType::BeforeLeft),
            "f"                     => Instr::MoveCharMode(CharMoveType::Right),
            "F"                     => Instr::MoveCharMode(CharMoveType::Left),

            "a"                     => Instr::Append,
            "A"                     => Instr::AppendEnd,
            "i"                     => Instr::Insert,
            "I"                     => Instr::InsertStart,

            "1"                     => Instr::Digit(1),
            "2"                     => Instr::Digit(2),
            "3"                     => Instr::Digit(3),
            "4"                     => Instr::Digit(4),
            "5"                     => Instr::Digit(5),
            "6"                     => Instr::Digit(6),
            "7"                     => Instr::Digit(7),
            "8"                     => Instr::Digit(8),
            "9"                     => Instr::Digit(9),

            _                       => Instr::Common(CommonInstr::Noop),
        },
        _                           => vi_common(&token),
    }
}
fn vi_replace_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(text)   => Instr::ReplaceAtCursor(text),
        _                           => Instr::NormalMode,
    }
}
fn vi_move_char_mode(move_type: CharMoveType, token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(ref text) => match (move_type, text.chars().next()) {
            (CharMoveType::BeforeLeft, Some(c))  => Instr::MoveBeforeCharLeft(c),
            (CharMoveType::BeforeRight, Some(c)) => Instr::MoveBeforeCharRight(c),
            (CharMoveType::Left, Some(c))        => Instr::MoveCharLeft(c),
            (CharMoveType::Right, Some(c))       => Instr::MoveCharRight(c),
            (_, None)                            => Instr::NormalMode, // this is probably unreachable!()
        },
        _                           => Instr::NormalMode,
    }
}
fn vi_change_delete_common(token: &parser::Token) -> Instr {
    match *token {
        parser::Token::Text(ref text) => match text.as_ref() {
            "h"                     => Instr::MoveCursor(MoveCursorInstr::Left),
            "l"                     => Instr::MoveCursor(MoveCursorInstr::Right),
            "0"                     => Instr::Digit(0),
            "$"                     => Instr::MoveCursor(MoveCursorInstr::End),

            "e"                     => Instr::MoveEndOfWordRight,
            "E"                     => Instr::MoveEndOfWordWsRight,
            "w"                     => Instr::MoveWordRight,
            "W"                     => Instr::MoveWordWsRight,
            "b"                     => Instr::MoveWordLeft,
            "B"                     => Instr::MoveWordWsLeft,
            "t"                     => Instr::MoveCharMode(CharMoveType::BeforeRight),
            "T"                     => Instr::MoveCharMode(CharMoveType::BeforeLeft),
            "f"                     => Instr::MoveCharMode(CharMoveType::Right),
            "F"                     => Instr::MoveCharMode(CharMoveType::Left),

            "1"                     => Instr::Digit(1),
            "2"                     => Instr::Digit(2),
            "3"                     => Instr::Digit(3),
            "4"                     => Instr::Digit(4),
            "5"                     => Instr::Digit(5),
            "6"                     => Instr::Digit(6),
            "7"                     => Instr::Digit(7),
            "8"                     => Instr::Digit(8),
            "9"                     => Instr::Digit(9),
            _                       => Instr::NormalMode,
        },
        _                           => Instr::NormalMode,
    }
}
fn vi_change_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(ref text) => match text.as_ref() {
            "c"                     => Instr::ChangeLine,
            _                       => vi_change_delete_common(&token),
        },
        _                           => Instr::NormalMode,
    }
}
fn vi_delete_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(ref text) => match text.as_ref() {
            "d"                     => Instr::DeleteLine,
            _                       => vi_change_delete_common(&token),
        },
        _                           => Instr::NormalMode,
    }
}
<commit_msg>add ctrl-h and ctrl-j<commit_after>use parser;
use edit::ModeState;
use edit::ViMode;

pub enum CommonInstr {
    Done,
    Cancel,
    Clear,
    Noop
}

pub enum HistoryInstr {
    Next,
    Prev
}

pub enum MoveCursorInstr {
    Left,
    Right,
    Start,
    End
}

pub enum Instr {
    Common(CommonInstr),
    History(HistoryInstr),
    MoveCursor(MoveCursorInstr),
    MoveEndOfWordRight,
    MoveEndOfWordWsRight,
    MoveWordRight,
    MoveWordWsRight,
    MoveWordLeft,
    MoveWordWsLeft,
    MoveCharRight(char),
    MoveCharLeft(char),
    MoveBeforeCharRight(char),
    MoveBeforeCharLeft(char),
    DeleteCharLeftOfCursor,
    DeleteCharRightOfCursor,
    DeleteCharRightOfCursorOrEOF,
    DeleteLine,
    DeleteToEnd,
    ChangeLine,
    ChangeToEnd,
    Substitute,
    InsertAtCursor(String),
    ReplaceAtCursor(String),
    Insert,
    InsertStart,
    Append,
    AppendEnd,
    NormalMode,
    ReplaceMode,
    MoveCharMode(CharMoveType),
    DeleteMode,
    ChangeMode,
    Digit(u32),
    DoneOrEof
}

#[derive(Copy,Clone,PartialEq)]
pub enum CharMoveType {
    BeforeRight,
    BeforeLeft,
    Right,
    Left,
}

pub fn interpret_token(token: parser::Token, edit_mode_state: ModeState) -> Instr {
    match edit_mode_state {
        ModeState::Emacs => emacs_mode(token),
        ModeState::Vi(ViMode::Insert, _) => vi_insert_mode(token),
        ModeState::Vi(ViMode::Normal, _) => vi_normal_mode(token),
        ModeState::Vi(ViMode::Replace, _) => vi_replace_mode(token),
        ModeState::Vi(ViMode::MoveChar(move_type), _) => vi_move_char_mode(move_type, token),
        ModeState::Vi(ViMode::DeleteMoveChar(move_type), _) => vi_move_char_mode(move_type, token),
        ModeState::Vi(ViMode::ChangeMoveChar(move_type), _) => vi_move_char_mode(move_type, token),
        ModeState::Vi(ViMode::Delete, _) => vi_delete_mode(token),
        ModeState::Vi(ViMode::Change, _) => vi_change_mode(token),
    }
}

fn emacs_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Enter        => Instr::Common(CommonInstr::Done),
        parser::Token::Backspace    => Instr::DeleteCharLeftOfCursor,
        parser::Token::CtrlH        => Instr::DeleteCharLeftOfCursor,
        parser::Token::EscBracket3T => Instr::DeleteCharRightOfCursor,
        parser::Token::CtrlD        => Instr::DeleteCharRightOfCursorOrEOF,
        parser::Token::EscBracketA  => Instr::History(HistoryInstr::Prev),
        parser::Token::CtrlP        => Instr::History(HistoryInstr::Prev),
        parser::Token::EscBracketB  => Instr::History(HistoryInstr::Next),
        parser::Token::CtrlN        => Instr::History(HistoryInstr::Next),
        parser::Token::EscBracketC  => Instr::MoveCursor(MoveCursorInstr::Right),
        parser::Token::CtrlF        => Instr::MoveCursor(MoveCursorInstr::Right),
        parser::Token::EscBracketD  => Instr::MoveCursor(MoveCursorInstr::Left),
        parser::Token::CtrlB        => Instr::MoveCursor(MoveCursorInstr::Left),
        parser::Token::CtrlA        => Instr::MoveCursor(MoveCursorInstr::Start),
        parser::Token::EscBracketH  => Instr::MoveCursor(MoveCursorInstr::Start),
        parser::Token::CtrlE        => Instr::MoveCursor(MoveCursorInstr::End),
        parser::Token::EscBracketF  => Instr::MoveCursor(MoveCursorInstr::End),
        parser::Token::Text(text)   => Instr::InsertAtCursor(text),
        parser::Token::CtrlJ        => Instr::Common(CommonInstr::Done),
        parser::Token::CtrlC        => Instr::Common(CommonInstr::Cancel),
        parser::Token::CtrlL        => Instr::Common(CommonInstr::Clear),
        _                           => Instr::Common(CommonInstr::Noop)
    }
}

fn vi_common(token: &parser::Token) -> Instr {
    match *token {
        parser::Token::Enter        => Instr::Common(CommonInstr::Done),
        parser::Token::CtrlJ        => Instr::Common(CommonInstr::Done),
        parser::Token::CtrlD        => Instr::DoneOrEof,
        parser::Token::Esc          => Instr::NormalMode,
        parser::Token::Backspace    => Instr::DeleteCharLeftOfCursor,
        parser::Token::EscBracket3T => Instr::DeleteCharRightOfCursor,
        // movement keys
        parser::Token::EscBracketA  => Instr::History(HistoryInstr::Prev),
        parser::Token::EscBracketB  => Instr::History(HistoryInstr::Next),
        parser::Token::EscBracketC  => Instr::MoveCursor(MoveCursorInstr::Right),
        parser::Token::EscBracketD  => Instr::MoveCursor(MoveCursorInstr::Left),
        // home
        parser::Token::EscBracketH  => Instr::MoveCursor(MoveCursorInstr::Start),
        // end
        parser::Token::EscBracketF  => Instr::MoveCursor(MoveCursorInstr::End),
        parser::Token::CtrlC        => Instr::Common(CommonInstr::Cancel),
        parser::Token::CtrlL        => Instr::Common(CommonInstr::Clear),
        _                           => Instr::Common(CommonInstr::Noop),
    }
}

fn vi_insert_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(text)   => Instr::InsertAtCursor(text),
        parser::Token::CtrlH        => Instr::DeleteCharLeftOfCursor,
        _                           => vi_common(&token),
    }
}
fn vi_normal_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(text)   => match text.as_ref() {
            "h"                     => Instr::MoveCursor(MoveCursorInstr::Left),
            "j"                     => Instr::History(HistoryInstr::Next),
            "k"                     => Instr::History(HistoryInstr::Prev),
            "l"                     => Instr::MoveCursor(MoveCursorInstr::Right),
            "0"                     => Instr::Digit(0),
            "$"                     => Instr::MoveCursor(MoveCursorInstr::End),

            "x"                     => Instr::DeleteCharRightOfCursor,
            "s"                     => Instr::Substitute,
            "r"                     => Instr::ReplaceMode,
            "c"                     => Instr::ChangeMode,
            "C"                     => Instr::ChangeToEnd,
            "d"                     => Instr::DeleteMode,
            "D"                     => Instr::DeleteToEnd,

            "e"                     => Instr::MoveEndOfWordRight,
            "E"                     => Instr::MoveEndOfWordWsRight,
            "w"                     => Instr::MoveWordRight,
            "W"                     => Instr::MoveWordWsRight,
            "b"                     => Instr::MoveWordLeft,
            "B"                     => Instr::MoveWordWsLeft,
            "t"                     => Instr::MoveCharMode(CharMoveType::BeforeRight),
            "T"                     => Instr::MoveCharMode(CharMoveType::BeforeLeft),
            "f"                     => Instr::MoveCharMode(CharMoveType::Right),
            "F"                     => Instr::MoveCharMode(CharMoveType::Left),

            "a"                     => Instr::Append,
            "A"                     => Instr::AppendEnd,
            "i"                     => Instr::Insert,
            "I"                     => Instr::InsertStart,

            "1"                     => Instr::Digit(1),
            "2"                     => Instr::Digit(2),
            "3"                     => Instr::Digit(3),
            "4"                     => Instr::Digit(4),
            "5"                     => Instr::Digit(5),
            "6"                     => Instr::Digit(6),
            "7"                     => Instr::Digit(7),
            "8"                     => Instr::Digit(8),
            "9"                     => Instr::Digit(9),

            _                       => Instr::Common(CommonInstr::Noop),
        },
        _                           => vi_common(&token),
    }
}
fn vi_replace_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(text)   => Instr::ReplaceAtCursor(text),
        _                           => Instr::NormalMode,
    }
}
fn vi_move_char_mode(move_type: CharMoveType, token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(ref text) => match (move_type, text.chars().next()) {
            (CharMoveType::BeforeLeft, Some(c))  => Instr::MoveBeforeCharLeft(c),
            (CharMoveType::BeforeRight, Some(c)) => Instr::MoveBeforeCharRight(c),
            (CharMoveType::Left, Some(c))        => Instr::MoveCharLeft(c),
            (CharMoveType::Right, Some(c))       => Instr::MoveCharRight(c),
            (_, None)                            => Instr::NormalMode, // this is probably unreachable!()
        },
        _                           => Instr::NormalMode,
    }
}
fn vi_change_delete_common(token: &parser::Token) -> Instr {
    match *token {
        parser::Token::Text(ref text) => match text.as_ref() {
            "h"                     => Instr::MoveCursor(MoveCursorInstr::Left),
            "l"                     => Instr::MoveCursor(MoveCursorInstr::Right),
            "0"                     => Instr::Digit(0),
            "$"                     => Instr::MoveCursor(MoveCursorInstr::End),

            "e"                     => Instr::MoveEndOfWordRight,
            "E"                     => Instr::MoveEndOfWordWsRight,
            "w"                     => Instr::MoveWordRight,
            "W"                     => Instr::MoveWordWsRight,
            "b"                     => Instr::MoveWordLeft,
            "B"                     => Instr::MoveWordWsLeft,
            "t"                     => Instr::MoveCharMode(CharMoveType::BeforeRight),
            "T"                     => Instr::MoveCharMode(CharMoveType::BeforeLeft),
            "f"                     => Instr::MoveCharMode(CharMoveType::Right),
            "F"                     => Instr::MoveCharMode(CharMoveType::Left),

            "1"                     => Instr::Digit(1),
            "2"                     => Instr::Digit(2),
            "3"                     => Instr::Digit(3),
            "4"                     => Instr::Digit(4),
            "5"                     => Instr::Digit(5),
            "6"                     => Instr::Digit(6),
            "7"                     => Instr::Digit(7),
            "8"                     => Instr::Digit(8),
            "9"                     => Instr::Digit(9),
            _                       => Instr::NormalMode,
        },
        _                           => Instr::NormalMode,
    }
}
fn vi_change_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(ref text) => match text.as_ref() {
            "c"                     => Instr::ChangeLine,
            _                       => vi_change_delete_common(&token),
        },
        _                           => Instr::NormalMode,
    }
}
fn vi_delete_mode(token: parser::Token) -> Instr {
    match token {
        parser::Token::Text(ref text) => match text.as_ref() {
            "d"                     => Instr::DeleteLine,
            _                       => vi_change_delete_common(&token),
        },
        _                           => Instr::NormalMode,
    }
}
<|endoftext|>


<commit_before>use graphics::Graphics;
use graphics::character::CharacterCache;
use color::{ Color, Colorable };
use point::Point;
use ui_context::UiContext;

pub type FontSize = u32;

/// An enum for passing in label information to widget arguments.
pub enum Labeling<'a> {
    Label(&'a str, FontSize, Color),
    NoLabel,
}

/// Determine the pixel width of the final text bitmap.
#[inline]
pub fn width<C: CharacterCache>(uic: &mut UiContext<C>, size: FontSize, text: &str) -> f64 {
    text.chars().fold(0u32, |a, ch| {
        let character = uic.get_character(size, ch);
        a + character.width() as u32
    }) as f64
}

/// Determine a suitable FontSize from a given rectangle height.
#[inline]
pub fn auto_size_from_rect_height(rect_height: f64) -> FontSize {
    let size = rect_height as u32 - 832;
    if size % 2 == 0 { size } else { size - 1u32 }
}

/// A trait used for widget types that take a label.
pub trait Labelable<'a>: Sized {
    fn label(self, text: &'a str) -> Self;
    fn label_color(self, color: Color) -> Self;
    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.label_color(Color([r, g, b, a]))
    }
    fn label_font_size(self, size: FontSize) -> Self;
    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_small)
    }
    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_medium)
    }
    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_large)
    }
}

/// Label text property.
#[derive(Copy, Clone)]
pub struct LabelText<'a>(pub &'a str);

/// Label color property.
#[derive(Copy, Clone)]
pub struct LabelColor(pub Color);

/// Label font size property.
#[derive(Copy, Clone)]
pub struct LabelFontSize(pub FontSize);

/*
impl<'a, T: 'a> Labelable<'a> for T
    where
        (LabelText<'a>, T): Pair<Data = LabelText<'a>, Object = T> + SetAt,
        (LabelColor, T): Pair<Data = LabelColor, Object = T> + SetAt,
        (LabelFontSize, T): Pair<Data = LabelFontSize, Object = T> + SetAt
{
    fn label(self, text: &'a str) -> Self {
        self.set(LabelText(text))
    }

    fn label_color(self, color: Color) -> Self {
        self.set(LabelColor(color))
    }

    fn label_font_size(self, size: FontSize) -> Self {
        self.set(LabelFontSize(size))
    }
}
*/

/// A context on which the builder pattern can be implemented.
pub struct Label<'a> {
    text: &'a str,
    pos: Point,
    size: FontSize,
    maybe_color: Option<Color>,
}

impl<'a> Label<'a> {
    /// A builder method for specifying font_size.
    pub fn size(self, size: FontSize) -> Label<'a> {
        Label { size: size, ..self }
    }
}

impl<'a> Label<'a> {

    /// A label builder method to be implemented on the UiContext.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: [0.0, 0.0],
            size: 24u32,
            maybe_color: None,
        }
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    label: Label['a]
    get:
    set:
        fn (val: Position) [] { label.pos = val.0 }
    action:
}
*/

impl<'a> ::draw::Drawable for Label<'a> {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(Color::black());
        uic.draw_text(graphics, self.pos, self.size, color, self.text);
    }
}
<commit_msg>Implemented `Positionable` for `Label`<commit_after>use graphics::Graphics;
use graphics::character::CharacterCache;
use color::{ Color, Colorable };
use point::Point;
use position::Positionable;
use ui_context::UiContext;

pub type FontSize = u32;

/// An enum for passing in label information to widget arguments.
pub enum Labeling<'a> {
    Label(&'a str, FontSize, Color),
    NoLabel,
}

/// Determine the pixel width of the final text bitmap.
#[inline]
pub fn width<C: CharacterCache>(uic: &mut UiContext<C>, size: FontSize, text: &str) -> f64 {
    text.chars().fold(0u32, |a, ch| {
        let character = uic.get_character(size, ch);
        a + character.width() as u32
    }) as f64
}

/// Determine a suitable FontSize from a given rectangle height.
#[inline]
pub fn auto_size_from_rect_height(rect_height: f64) -> FontSize {
    let size = rect_height as u32 - 832;
    if size % 2 == 0 { size } else { size - 1u32 }
}

/// A trait used for widget types that take a label.
pub trait Labelable<'a>: Sized {
    fn label(self, text: &'a str) -> Self;
    fn label_color(self, color: Color) -> Self;
    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.label_color(Color([r, g, b, a]))
    }
    fn label_font_size(self, size: FontSize) -> Self;
    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_small)
    }
    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_medium)
    }
    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_large)
    }
}

/// Label text property.
#[derive(Copy, Clone)]
pub struct LabelText<'a>(pub &'a str);

/// Label color property.
#[derive(Copy, Clone)]
pub struct LabelColor(pub Color);

/// Label font size property.
#[derive(Copy, Clone)]
pub struct LabelFontSize(pub FontSize);

/*
impl<'a, T: 'a> Labelable<'a> for T
    where
        (LabelText<'a>, T): Pair<Data = LabelText<'a>, Object = T> + SetAt,
        (LabelColor, T): Pair<Data = LabelColor, Object = T> + SetAt,
        (LabelFontSize, T): Pair<Data = LabelFontSize, Object = T> + SetAt
{
    fn label(self, text: &'a str) -> Self {
        self.set(LabelText(text))
    }

    fn label_color(self, color: Color) -> Self {
        self.set(LabelColor(color))
    }

    fn label_font_size(self, size: FontSize) -> Self {
        self.set(LabelFontSize(size))
    }
}
*/

/// A context on which the builder pattern can be implemented.
pub struct Label<'a> {
    text: &'a str,
    pos: Point,
    size: FontSize,
    maybe_color: Option<Color>,
}

impl<'a> Label<'a> {
    /// A builder method for specifying font_size.
    pub fn size(self, size: FontSize) -> Label<'a> {
        Label { size: size, ..self }
    }
}

impl<'a> Label<'a> {

    /// A label builder method to be implemented on the UiContext.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: [0.0, 0.0],
            size: 24u32,
            maybe_color: None,
        }
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a> Positionable for Label<'a> {
    fn point(mut self, pos: Point) -> Self {
        self.pos = pos;
        self
    }
}

impl<'a> ::draw::Drawable for Label<'a> {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(Color::black());
        uic.draw_text(graphics, self.pos, self.size, color, self.text);
    }
}
<|endoftext|>


<commit_before>//use std::str::Chars;

//use token::{Token, String, Whitespace, Operator, AtSymbol};

pub struct CodeLexer<'a> {
    pub line: int,
    pub column: int,
    pub source: &'a str,
}

impl<'a> CodeLexer<'a> {
    pub fn new(source: &'a str, line: int, column: int) -> CodeLexer<'a> {
        CodeLexer {
            line: line,
            column: column,
            source: source,
        }
    }

    pub fn is_keyword(&self, identifier: &str) -> bool {
        match identifier {
            "if" |
            "for" |
            "model" |
            "while" => true,
            _ => false
        }
    }

    pub fn accept_identifier(&self, source: &str) -> String {
        let mut first = true;
        source.chars().take_while(|c| {
            match *c {
                'A' .. 'Z' |
                'a' .. 'z' |
                '_' => {
                    first = false;
                    true
                },
                '0' .. '9' if !first => true,
                _ => false
            }
        }).collect::<String>()
    }

    pub fn end_of_block(&self, start_char: char, end_char: char) -> Option<uint> {
        let mut scope = 0i;
        let mut in_quote: Option<char> = None;
        for (index, c) in self.source.chars().enumerate() {
            if c == '\'' || c == '"' {
                in_quote = match in_quote {
                    None => Some(c),
                    Some(q) if q == c => None,
                    _ => in_quote
                };
            }

            match in_quote {
                None => {
                    if c == start_char {
                        scope += 1;
                    }
                    else if c == end_char {
                        scope -= 1;
                        if scope <= 0 {
                            return Some(index);
                        }
                    }
                },
                _ => ()
            };
        }

        None
    }

    pub fn next_instance_of(&self, search_char: char) -> Option<uint> {
        self.source.chars().position(|c| {
            c == search_char
        })
    }

    pub fn end_of_code_block(&self) -> Option<uint> {
        self.end_of_block('{', '}')
    }

    pub fn end_of_code_statement(&self) -> Option<uint> {
        self.next_instance_of(';')
    }

    pub fn block_delimiters(&self) -> (Option<uint>, Option<uint>) {
        (self.next_instance_of('{'), self.end_of_block('{', '}'))
    }
}

pub struct HtmlLexer<'a> {
    pub line: int,
    pub column: int,
    pub source: &'a str,
}

impl<'a> HtmlLexer<'a> {
    pub fn new(source: &'a str, line: int, column: int) -> HtmlLexer<'a> {
        HtmlLexer {
            line: line,
            column: column,
            source: source,
        }
    }

    fn is_valid_email_char(&self, c: char) -> bool {
        match c {
            'A' .. 'Z' |
            'a' .. 'z' |
            '0' .. '9' => true,
            _ => false
        }
    }

    fn is_valid_transition(&self, index: uint) -> bool {
        if index == 0 {
            return true;
        }

        if index == self.source.len() - 1 {
            return false;
        }

        if self.is_valid_email_char(self.source.char_at(index - 1)) &&
            self.is_valid_email_char(self.source.char_at(index + 1)) {
                return false;
        }

        //if self.source.char_at(index - 1) == '@' ||
        //    self.source.char_at(index + 1) == '@' {
        //        return false;
        //}

        true
    }

    pub fn next_transition(&mut self) -> Option<uint> {
        for (index, c) in self.source.chars().enumerate() {
            if c == '@' && self.is_valid_transition(index) {
                return Some(index)
            }
        }

        None
    }
}
<commit_msg>Update for rust changes<commit_after>//use std::str::Chars;

//use token::{Token, String, Whitespace, Operator, AtSymbol};

pub struct CodeLexer<'a> {
    pub line: int,
    pub column: int,
    pub source: &'a str,
}

impl<'a> CodeLexer<'a> {
    pub fn new(source: &'a str, line: int, column: int) -> CodeLexer<'a> {
        CodeLexer {
            line: line,
            column: column,
            source: source,
        }
    }

    pub fn is_keyword(&self, identifier: &str) -> bool {
        match identifier {
            "if" |
            "for" |
            "model" |
            "while" => true,
            _ => false
        }
    }

    pub fn accept_identifier(&self, source: &str) -> String {
        source.chars().enumerate().take_while(|&(index, c)| {
            match c {
                'A' ... 'Z' |
                'a' ... 'z' |
                '_' => {
                    true
                },
                '0' ... '9' if index > 0 => true,
                _ => false
            }
        }).map(|(_, c)| c).collect::<String>()
    }

    pub fn end_of_block(&self, start_char: char, end_char: char) -> Option<uint> {
        let mut scope = 0i;
        let mut in_quote: Option<char> = None;
        for (index, c) in self.source.chars().enumerate() {
            if c == '\'' || c == '"' {
                in_quote = match in_quote {
                    None => Some(c),
                    Some(q) if q == c => None,
                    _ => in_quote
                };
            }

            match in_quote {
                None => {
                    if c == start_char {
                        scope += 1;
                    }
                    else if c == end_char {
                        scope -= 1;
                        if scope <= 0 {
                            return Some(index);
                        }
                    }
                },
                _ => ()
            };
        }

        None
    }

    pub fn next_instance_of(&self, search_char: char) -> Option<uint> {
        self.source.chars().position(|c| {
            c == search_char
        })
    }

    pub fn end_of_code_block(&self) -> Option<uint> {
        self.end_of_block('{', '}')
    }

    pub fn end_of_code_statement(&self) -> Option<uint> {
        self.next_instance_of(';')
    }

    pub fn block_delimiters(&self) -> (Option<uint>, Option<uint>) {
        (self.next_instance_of('{'), self.end_of_block('{', '}'))
    }
}

pub struct HtmlLexer<'a> {
    pub line: int,
    pub column: int,
    pub source: &'a str,
}

impl<'a> HtmlLexer<'a> {
    pub fn new(source: &'a str, line: int, column: int) -> HtmlLexer<'a> {
        HtmlLexer {
            line: line,
            column: column,
            source: source,
        }
    }

    fn is_valid_email_char(&self, c: char) -> bool {
        match c {
            'A' ... 'Z' |
            'a' ... 'z' |
            '0' ... '9' => true,
            _ => false
        }
    }

    fn is_valid_transition(&self, index: uint) -> bool {
        if index == 0 {
            return true;
        }

        if index == self.source.len() - 1 {
            return false;
        }

        if self.is_valid_email_char(self.source.char_at(index - 1)) &&
            self.is_valid_email_char(self.source.char_at(index + 1)) {
                return false;
        }

        //if self.source.char_at(index - 1) == '@' ||
        //    self.source.char_at(index + 1) == '@' {
        //        return false;
        //}

        true
    }

    pub fn next_transition(&mut self) -> Option<uint> {
        for (index, c) in self.source.chars().enumerate() {
            if c == '@' && self.is_valid_transition(index) {
                return Some(index)
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>use nalgebra::Point2;
use std::collections::HashSet;
use std::ops::{Deref, DerefMut};

use event::{ElementState, Event, MouseButton, Reactor};

pub trait ToInputState {
    type Element: Copy;
    type State: InputState<Self::Element>;

    fn to_state(&self) -> Self::State;
}

pub trait InputState<E>
    where E: Copy
{
    fn state(&self, element: E) -> ElementState;
}

pub struct ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: InputState<E>,
          E: Copy
{
    input: T,
    state: T::State,
}

impl<E, T> ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: Default + InputState<E>,
          E: Copy
{
    pub fn new(input: T) -> Self {
        ElementTransition {
            input: input,
            state: T::State::default(),
        }
    }

    pub fn transition(&self, element: T::Element) -> Option<ElementState> {
        match (self.state.state(element), self.input.state(element)) {
            (ElementState::Released, ElementState::Pressed) => Some(ElementState::Pressed),
            (ElementState::Pressed, ElementState::Released) => Some(ElementState::Released),
            _ => None
        }
    }

    pub fn snapshot(&mut self) {
        self.state = self.input.to_state();
    }
}

impl<E, T> Deref for ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: Default + InputState<E>,
          E: Copy
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.input
    }
}

impl<E, T> DerefMut for ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: Default + InputState<E>,
          E: Copy
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.input
    }
}

impl<E, T> Reactor for ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: Default + InputState<E>,
          E: Copy
{
    fn react(&mut self, event: &Event) {
        self.input.react(event);
    }
}

pub struct Mouse {
    position: Point2<u32>,
    buttons: MouseState,
}

impl Mouse {
    pub fn new() -> Self {
        Mouse {
            position: Point2::origin(),
            buttons: MouseState::new(),
        }
    }

    pub fn position(&self) -> &Point2<u32> {
        &self.position
    }
}

impl InputState<MouseButton> for Mouse {
    fn state(&self, button: MouseButton) -> ElementState {
        self.buttons.state(button)
    }
}

impl Reactor for Mouse {
    fn react(&mut self, event: &Event) {
        match *event {
            Event::MouseInput(ElementState::Pressed, button) => {
                self.buttons.0.insert(button);
            }
            Event::MouseInput(ElementState::Released, button) => {
                self.buttons.0.remove(&button);
            }
            Event::MouseMoved(x, y) => {
                self.position = Point2::new(x as u32, y as u32);
            }
            _ => {}
        }
    }
}

impl ToInputState for Mouse {
    type Element = MouseButton;
    type State = MouseState;

    fn to_state(&self) -> Self::State {
        self.buttons.clone()
    }
}

#[derive(Clone)]
pub struct MouseState(HashSet<MouseButton>);

impl MouseState {
    pub fn new() -> Self {
        MouseState(HashSet::new())
    }
}

impl Default for MouseState {
    fn default() -> Self {
        MouseState::new()
    }
}

impl InputState<MouseButton> for MouseState {
    fn state(&self, button: MouseButton) -> ElementState {
        if self.0.contains(&button) {
            ElementState::Pressed
        }
        else {
            ElementState::Released
        }
    }
}
<commit_msg>Do not require `Default` for input state.<commit_after>use nalgebra::Point2;
use std::collections::HashSet;
use std::ops::{Deref, DerefMut};

use event::{ElementState, Event, MouseButton, Reactor};

pub trait ToInputState {
    type Element: Copy;
    type State: InputState<Self::Element>;

    fn to_state(&self) -> Self::State;
}

pub trait InputState<E>
    where E: Copy
{
    fn state(&self, element: E) -> ElementState;
}

pub struct ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: InputState<E>,
          E: Copy
{
    input: T,
    state: T::State,
}

impl<E, T> ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: InputState<E>,
          E: Copy
{
    pub fn new(input: T) -> Self {
        ElementTransition {
            state: input.to_state(),
            input: input,
        }
    }

    pub fn transition(&self, element: T::Element) -> Option<ElementState> {
        match (self.state.state(element), self.input.state(element)) {
            (ElementState::Released, ElementState::Pressed) => Some(ElementState::Pressed),
            (ElementState::Pressed, ElementState::Released) => Some(ElementState::Released),
            _ => None
        }
    }

    pub fn snapshot(&mut self) {
        self.state = self.input.to_state();
    }
}

impl<E, T> Deref for ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: InputState<E>,
          E: Copy
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.input
    }
}

impl<E, T> DerefMut for ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: InputState<E>,
          E: Copy
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.input
    }
}

impl<E, T> Reactor for ElementTransition<E, T>
    where T: InputState<E> + Reactor + ToInputState<Element = E>,
          T::State: InputState<E>,
          E: Copy
{
    fn react(&mut self, event: &Event) {
        self.input.react(event);
    }
}

pub struct Mouse {
    position: Point2<u32>,
    buttons: MouseState,
}

impl Mouse {
    pub fn new() -> Self {
        Mouse {
            position: Point2::origin(),
            buttons: MouseState::new(),
        }
    }

    pub fn position(&self) -> &Point2<u32> {
        &self.position
    }
}

impl InputState<MouseButton> for Mouse {
    fn state(&self, button: MouseButton) -> ElementState {
        self.buttons.state(button)
    }
}

impl Reactor for Mouse {
    fn react(&mut self, event: &Event) {
        match *event {
            Event::MouseInput(ElementState::Pressed, button) => {
                self.buttons.0.insert(button);
            }
            Event::MouseInput(ElementState::Released, button) => {
                self.buttons.0.remove(&button);
            }
            Event::MouseMoved(x, y) => {
                self.position = Point2::new(x as u32, y as u32);
            }
            _ => {}
        }
    }
}

impl ToInputState for Mouse {
    type Element = MouseButton;
    type State = MouseState;

    fn to_state(&self) -> Self::State {
        self.buttons.clone()
    }
}

#[derive(Clone)]
pub struct MouseState(HashSet<MouseButton>);

impl MouseState {
    pub fn new() -> Self {
        MouseState(HashSet::new())
    }
}

impl InputState<MouseButton> for MouseState {
    fn state(&self, button: MouseButton) -> ElementState {
        if self.0.contains(&button) {
            ElementState::Pressed
        }
        else {
            ElementState::Released
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use {KeyboardControllable, Key, MouseControllable, MouseButton};

use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{
    borrow::Cow,
    ffi::CString,
    ptr
};

const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
type Window  = c_int;
type Xdo     = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
    fn xdo_send_keysequence_window(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
    fn xdo_send_keysequence_window_down(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
    fn xdo_send_keysequence_window_up(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
}

fn mousebutton(button: MouseButton) -> c_int {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo,
    delay: u64
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
unsafe impl Send for Enigo {}

impl Default for Enigo {
    /// Create a new Enigo instance
    fn default() -> Self {
        Self {
            xdo: unsafe { xdo_new(ptr::null()) },
            delay: DEFAULT_DELAY
        }
    }
}
impl Enigo {
    /// Get the delay per keypress.
    /// Default value is 12000.
    /// This is Linux-specific.
    pub fn delay(&self) -> u64 {
        self.delay
    }
    /// Set the delay per keypress.
    /// This is Linux-specific.
    pub fn set_delay(&mut self, delay: u64) {
        self.delay = delay;
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x as c_int, y as c_int);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::Owned(c.to_string());
    }
    #[allow(deprecated)] // I mean duh, we still need to support deprecated keys until they're removed
    Cow::Borrowed(match key {
        Key::Alt => "Alt",
        Key::Backspace => "Backspace",
        Key::CapsLock => "CapsLock",
        Key::Control => "Control",
        Key::Delete => "Delete",
        Key::DownArrow => "DownArrow",
        Key::End => "End",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "PageDown",
        Key::PageUp => "PageUp",
        Key::Raw(_) => unimplemented!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "Space",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",

        Key::Command |
        Key::Super |
        Key::Windows |
        Key::Meta => "Meta"
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
}
<commit_msg>Added support for non-alphanumeric characters to linux. Also fixed Backspace for linux<commit_after>extern crate libc;

use {KeyboardControllable, Key, MouseControllable, MouseButton};

use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{
    borrow::Cow,
    ffi::CString,
    ptr
};

const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
type Window  = c_int;
type Xdo     = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
    fn xdo_send_keysequence_window(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
    fn xdo_send_keysequence_window_down(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
    fn xdo_send_keysequence_window_up(xdo: Xdo, window: Window, string: *const c_char, delay: useconds_t) -> c_int;
}

fn mousebutton(button: MouseButton) -> c_int {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo,
    delay: u64
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
unsafe impl Send for Enigo {}

impl Default for Enigo {
    /// Create a new Enigo instance
    fn default() -> Self {
        Self {
            xdo: unsafe { xdo_new(ptr::null()) },
            delay: DEFAULT_DELAY
        }
    }
}
impl Enigo {
    /// Get the delay per keypress.
    /// Default value is 12000.
    /// This is Linux-specific.
    pub fn delay(&self) -> u64 {
        self.delay
    }
    /// Set the delay per keypress.
    /// This is Linux-specific.
    pub fn set_delay(&mut self, delay: u64) {
        self.delay = delay;
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x as c_int, y as c_int);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::Owned(match c {
            '/' => "slash".to_string(),
            '?' => "question".to_string(),
            '.' => "period".to_string(),
            '>' => "greater".to_string(),
            ',' => "comma".to_string(),
            '<' => "less".to_string(),
            ':' => "colon".to_string(),
            ';' => "semicolon".to_string(),
            '"' => "quotedbl".to_string(),
            '\'' => "apostrophe".to_string(),
            '[' => "bracketleft".to_string(),
            ']' => "bracketright".to_string(),
            '{' => "braceleft".to_string(),
            '}' => "braceright".to_string(),
            '\\' => "backslash".to_string(),
            '|' => "bar".to_string(),
            '-' => "minus".to_string(),
            '_' => "underscore".to_string(),
            '+' => "plus".to_string(),
            '=' => "equal".to_string(),
            '`' => "grave".to_string(),
            '~' => "asciitilde".to_string(),
            '!' => "exclam".to_string(),
            '@' => "at".to_string(),
            '#' => "numbersign".to_string(),
            '$' => "dollar".to_string(),
            '%' => "percent".to_string(),
            '^' => "asciicircum".to_string(),
            '&' => "ampersand".to_string(),
            '*' => "asterisk".to_string(),
            '(' => "parenleft".to_string(),
            ')' => "parenright".to_string(),
            _ => c.to_string()
        });
    }
    #[allow(deprecated)] // I mean duh, we still need to support deprecated keys until they're removed
    Cow::Borrowed(match key {
        Key::Alt => "Alt",
        Key::Backspace => "BackSpace",
        Key::CapsLock => "CapsLock",
        Key::Control => "Control",
        Key::Delete => "Delete",
        Key::DownArrow => "DownArrow",
        Key::End => "End",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "PageDown",
        Key::PageUp => "PageUp",
        Key::Raw(_) => unimplemented!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "Space",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",

        Key::Command |
        Key::Super |
        Key::Windows |
        Key::Meta => "Meta"
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), self.delay as useconds_t);
        }
    }
}
<|endoftext|>


<commit_before>use ast::{TIdent, TNumber, TString, TSemicolon, TComment, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TBinOp, TAssignOp, TUnaryOp, TArrow};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use ast::{CompEqual, CompStrictEqual, CompNotEqual, CompStrictNotEqual, CompLessThan, CompGreaterThan, CompLessThanOrEqual, CompGreaterThanOrEqual};
use ast::{LogAnd, LogOr};
use ast::{UnaryNot};
use ast::{BinNum, BinBit, BinComp, BinLog};
use ast::{Token, TokenData};
use std::io::{BufReader, BufferedReader, Buffer, IoResult, EndOfFile};
use std::strbuf::StrBuf;
use std::char::from_u32;
use std::num::from_str_radix;
#[deriving(Clone, Eq)]
/// The type of string used
pub enum StringType {
	/// `"` - Double-quoted
	DoubleQuote,
	/// `'` - Single-quoted
	SingleQuote
}
#[deriving(Clone, Eq)]
/// The type of comment used
pub enum CommentType {
	/// `/*...*/` - A multi-line comment
	MultiLineComment,
	/// `//...` - A single-line comment
	SingleLineComment
}
#[deriving(Clone, Eq)]
/// The type of number used
pub enum NumberType {
	/// A decimal number, such as `3.1415`
	DecimalNumber,
	/// A hexadecimal number, such as `0xFF00FF`
	HexadecimalNumber,
	/// An octal number, such as `011`
	OctalNumber
}
/// A Javascript lexer
pub struct Lexer<B> {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The current line number in the script
	line_number : uint,
	/// The current column number in the script
	column_number : uint,
	/// The reader
	buffer: B,
	/// The peeked character buffer
	peek_buffer: StrBuf
}
impl<B:Buffer> Lexer<B> {
	/// Creates a new lexer with empty buffers
	pub fn new(buffer: B) -> Lexer<B> {
		return Lexer {
			tokens: Vec::new(),
			line_number: 1,
			column_number: 0,
			buffer: buffer,
			peek_buffer: StrBuf::new()
		};
	}
	fn push_token(&mut self, tk:TokenData) {
		self.tokens.push(Token::new(tk, self.line_number, self.column_number))
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(script:&str) -> Vec<Token> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		let mut lexer = Lexer::new(buf_reader);
		lexer.lex().unwrap();
		lexer.tokens
	}
	fn next(&mut self) -> IoResult<char> {
		if self.peek_buffer.len() == 0 {
			self.buffer.read_char()
		} else {
			Ok(match self.peek_buffer.pop_char() {
				Some(v) => v,
				None => unreachable!()
			})
		}
	}
	fn peek_for(&mut self, peek:char) -> bool {
		if self.peek_buffer.len() > 0 {
			let matched = self.peek_buffer.as_slice().char_at(self.peek_buffer.len() - 1) == peek;
			if matched {
				self.peek_buffer.pop_char();
			}
			matched
		} else {
			match self.buffer.read_char() {
				Ok(ch) if ch == peek => {
					self.column_number += 1;
					true
				},
				Ok(ch) if ch != peek => {
					self.peek_buffer.push_char(ch);
					false
				},
				_ => false
			}
		}
	}
	/// Processes an input stream from the `buffer` into a vector of tokens
	pub fn lex(&mut self) -> IoResult<()> {
		loop {
			let ch = match self.next() {
				Ok(ch) => ch,
				Err(ref err) if err.kind == EndOfFile => break,
				Err(err) => return Err(err)
			};
			self.column_number += 1;
			match ch {
				'"' | '\'' => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\'' if ch == '\'' => {
								break;
							},
							'"' if ch == '"' => {
								break;
							},
							'\\' => {
								let escape = try!(self.next());
								if escape != '\n' {
									let escaped_ch = match escape {
										'n' => '\n',
										'r' => '\r',
										't' => '\t',
										'b' => '\x08',
										'f' => '\x0c',
										'0' => '\0',
										'x' => {
											let mut nums = StrBuf::with_capacity(2);
											for _ in range(0, 2) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 2;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'u' => {
											let mut nums = StrBuf::new();
											for _ in range(0, 4) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 4;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'\'' | '"' => escape,
										_ => fail!("{}:{}: Invalid escape `{}`", self.line_number, self.column_number, ch)
									};
									buf.push_char(escaped_ch);
								}
							},
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TString(buf))
				},
				'0' if self.peek_for('x') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							ch if ch.is_digit_radix(16) => buf.push_char(ch),
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str_radix(buf.as_slice(), 16).unwrap()));
				},
				'0' => {
					let mut buf = StrBuf::new();
					let mut gone_decimal = false;
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_digit_radix(8) => buf.push_char(ch),
							'8' | '9' | '.' => {
								gone_decimal = true;
								buf.push_char(ch);
							},
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(if gone_decimal {
						from_str(buf.as_slice())
					} else {
						from_str_radix(buf.as_slice(), 8)
					}.unwrap()));
				},
				_ if ch.is_digit() => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							'.' => buf.push_char(ch),
							_ if ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str(buf.as_slice()).unwrap()));
				},
				_ if ch.is_alphabetic() || ch == '$' || ch == '_' => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_alphabetic() || ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TIdent(buf));
				},
				';' => {
					self.push_token(TSemicolon);
				},
				':' => {
					self.push_token(TColon);
				},
				'.' => {
					self.push_token(TDot);
				},
				'(' => {
					self.push_token(TOpenParen);
				},
				')' => {
					self.push_token(TCloseParen);
				},
				',' => {
					self.push_token(TComma);
				},
				'{' => {
					self.push_token(TOpenBlock);
				},
				'}' => {
					self.push_token(TCloseBlock);
				},
				'[' => {
					self.push_token(TOpenArray);
				},
				']' => {
					self.push_token(TCloseArray);
				},
				'?' => {
					self.push_token(TQuestion);
				},
				'/' if self.peek_for('/') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('*') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							'*' if self.peek_for('/') => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpDiv)));
				},
				'/' => {
					self.push_token(TBinOp(BinNum(OpDiv)));
				},
				'*' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMul)));
				},
				'*' => {
					self.push_token(TBinOp(BinNum(OpMul)));
				},
				'+' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpAdd)));
				},
				'+' => {
					self.push_token(TBinOp(BinNum(OpAdd)));
				},
				'-' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpSub)));
				},
				'-' => {
					self.push_token(TBinOp(BinNum(OpSub)));
				},
				'%' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMod)));
				},
				'%' => {
					self.push_token(TBinOp(BinNum(OpMod)));
				},
				'|' if self.peek_for('|') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogOr)));
					} else {
						self.push_token(TBinOp(BinLog(LogOr)));
					}
				},
				'|' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitOr)));
				},
				'|' => {
					self.push_token(TBinOp(BinBit(BitOr)));
				},
				'&' if self.peek_for('&') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogAnd)));
					} else {
						self.push_token(TBinOp(BinLog(LogAnd)));
					}
				},
				'&' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitAnd)));
				},
				'&' => {
					self.push_token(TBinOp(BinBit(BitAnd)));
				},
				'^' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitXor)));
				},
				'^' => {
					self.push_token(TBinOp(BinBit(BitXor)));
				},
				'=' if self.peek_for('>') => {
					self.push_token(TArrow);
				},
				'=' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompEqual)));
					}
				},
				'=' => {
					self.push_token(TEqual);
				},
				'<' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompLessThanOrEqual)));
				},
				'<' if self.peek_for('<') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShl)));
					} else {
						self.push_token(TBinOp(BinBit(BitShl)));
					}
				},
				'<' => {
					self.push_token(TBinOp(BinComp(CompLessThan)));
				},
				'>' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompGreaterThanOrEqual)));
				},
				'>' if self.peek_for('>') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShr)));
					} else {
						self.push_token(TBinOp(BinBit(BitShr)));
					}
				},
				'>' => {
					self.push_token(TBinOp(BinComp(CompGreaterThan)));
				},
				'!' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictNotEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompNotEqual)));
					}
				},
				'!' => {
					self.push_token(TUnaryOp(UnaryNot));
				},
				'\n' => {
					self.line_number += 1;
					self.column_number = 0;
				},
				'\r' => {
					self.column_number = 0;
				},
				' ' => (),
				ch => fail!("{}:{}: Unexpected '{}'", self.line_number, self.column_number, ch)
			};
		}
		Ok(())
	}
}<commit_msg>Accept '_' in identifiers<commit_after>use ast::{TIdent, TNumber, TString, TSemicolon, TComment, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TBinOp, TAssignOp, TUnaryOp, TArrow};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use ast::{CompEqual, CompStrictEqual, CompNotEqual, CompStrictNotEqual, CompLessThan, CompGreaterThan, CompLessThanOrEqual, CompGreaterThanOrEqual};
use ast::{LogAnd, LogOr};
use ast::{UnaryNot};
use ast::{BinNum, BinBit, BinComp, BinLog};
use ast::{Token, TokenData};
use std::io::{BufReader, BufferedReader, Buffer, IoResult, EndOfFile};
use std::strbuf::StrBuf;
use std::char::from_u32;
use std::num::from_str_radix;
#[deriving(Clone, Eq)]
/// The type of string used
pub enum StringType {
	/// `"` - Double-quoted
	DoubleQuote,
	/// `'` - Single-quoted
	SingleQuote
}
#[deriving(Clone, Eq)]
/// The type of comment used
pub enum CommentType {
	/// `/*...*/` - A multi-line comment
	MultiLineComment,
	/// `//...` - A single-line comment
	SingleLineComment
}
#[deriving(Clone, Eq)]
/// The type of number used
pub enum NumberType {
	/// A decimal number, such as `3.1415`
	DecimalNumber,
	/// A hexadecimal number, such as `0xFF00FF`
	HexadecimalNumber,
	/// An octal number, such as `011`
	OctalNumber
}
/// A Javascript lexer
pub struct Lexer<B> {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The current line number in the script
	line_number : uint,
	/// The current column number in the script
	column_number : uint,
	/// The reader
	buffer: B,
	/// The peeked character buffer
	peek_buffer: StrBuf
}
impl<B:Buffer> Lexer<B> {
	/// Creates a new lexer with empty buffers
	pub fn new(buffer: B) -> Lexer<B> {
		return Lexer {
			tokens: Vec::new(),
			line_number: 1,
			column_number: 0,
			buffer: buffer,
			peek_buffer: StrBuf::new()
		};
	}
	fn push_token(&mut self, tk:TokenData) {
		self.tokens.push(Token::new(tk, self.line_number, self.column_number))
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(script:&str) -> Vec<Token> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		let mut lexer = Lexer::new(buf_reader);
		lexer.lex().unwrap();
		lexer.tokens
	}
	fn next(&mut self) -> IoResult<char> {
		if self.peek_buffer.len() == 0 {
			self.buffer.read_char()
		} else {
			Ok(match self.peek_buffer.pop_char() {
				Some(v) => v,
				None => unreachable!()
			})
		}
	}
	fn peek_for(&mut self, peek:char) -> bool {
		if self.peek_buffer.len() > 0 {
			let matched = self.peek_buffer.as_slice().char_at(self.peek_buffer.len() - 1) == peek;
			if matched {
				self.peek_buffer.pop_char();
			}
			matched
		} else {
			match self.buffer.read_char() {
				Ok(ch) if ch == peek => {
					self.column_number += 1;
					true
				},
				Ok(ch) if ch != peek => {
					self.peek_buffer.push_char(ch);
					false
				},
				_ => false
			}
		}
	}
	/// Processes an input stream from the `buffer` into a vector of tokens
	pub fn lex(&mut self) -> IoResult<()> {
		loop {
			let ch = match self.next() {
				Ok(ch) => ch,
				Err(ref err) if err.kind == EndOfFile => break,
				Err(err) => return Err(err)
			};
			self.column_number += 1;
			match ch {
				'"' | '\'' => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\'' if ch == '\'' => {
								break;
							},
							'"' if ch == '"' => {
								break;
							},
							'\\' => {
								let escape = try!(self.next());
								if escape != '\n' {
									let escaped_ch = match escape {
										'n' => '\n',
										'r' => '\r',
										't' => '\t',
										'b' => '\x08',
										'f' => '\x0c',
										'0' => '\0',
										'x' => {
											let mut nums = StrBuf::with_capacity(2);
											for _ in range(0, 2) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 2;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'u' => {
											let mut nums = StrBuf::new();
											for _ in range(0, 4) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 4;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'\'' | '"' => escape,
										_ => fail!("{}:{}: Invalid escape `{}`", self.line_number, self.column_number, ch)
									};
									buf.push_char(escaped_ch);
								}
							},
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TString(buf))
				},
				'0' if self.peek_for('x') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							ch if ch.is_digit_radix(16) => buf.push_char(ch),
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str_radix(buf.as_slice(), 16).unwrap()));
				},
				'0' => {
					let mut buf = StrBuf::new();
					let mut gone_decimal = false;
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_digit_radix(8) => buf.push_char(ch),
							'8' | '9' | '.' => {
								gone_decimal = true;
								buf.push_char(ch);
							},
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(if gone_decimal {
						from_str(buf.as_slice())
					} else {
						from_str_radix(buf.as_slice(), 8)
					}.unwrap()));
				},
				_ if ch.is_digit() => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							'.' => buf.push_char(ch),
							_ if ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str(buf.as_slice()).unwrap()));
				},
				_ if ch.is_alphabetic() || ch == '$' || ch == '_' => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_alphabetic() || ch.is_digit() || ch == '_' => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TIdent(buf));
				},
				';' => {
					self.push_token(TSemicolon);
				},
				':' => {
					self.push_token(TColon);
				},
				'.' => {
					self.push_token(TDot);
				},
				'(' => {
					self.push_token(TOpenParen);
				},
				')' => {
					self.push_token(TCloseParen);
				},
				',' => {
					self.push_token(TComma);
				},
				'{' => {
					self.push_token(TOpenBlock);
				},
				'}' => {
					self.push_token(TCloseBlock);
				},
				'[' => {
					self.push_token(TOpenArray);
				},
				']' => {
					self.push_token(TCloseArray);
				},
				'?' => {
					self.push_token(TQuestion);
				},
				'/' if self.peek_for('/') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('*') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							'*' if self.peek_for('/') => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpDiv)));
				},
				'/' => {
					self.push_token(TBinOp(BinNum(OpDiv)));
				},
				'*' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMul)));
				},
				'*' => {
					self.push_token(TBinOp(BinNum(OpMul)));
				},
				'+' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpAdd)));
				},
				'+' => {
					self.push_token(TBinOp(BinNum(OpAdd)));
				},
				'-' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpSub)));
				},
				'-' => {
					self.push_token(TBinOp(BinNum(OpSub)));
				},
				'%' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMod)));
				},
				'%' => {
					self.push_token(TBinOp(BinNum(OpMod)));
				},
				'|' if self.peek_for('|') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogOr)));
					} else {
						self.push_token(TBinOp(BinLog(LogOr)));
					}
				},
				'|' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitOr)));
				},
				'|' => {
					self.push_token(TBinOp(BinBit(BitOr)));
				},
				'&' if self.peek_for('&') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogAnd)));
					} else {
						self.push_token(TBinOp(BinLog(LogAnd)));
					}
				},
				'&' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitAnd)));
				},
				'&' => {
					self.push_token(TBinOp(BinBit(BitAnd)));
				},
				'^' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitXor)));
				},
				'^' => {
					self.push_token(TBinOp(BinBit(BitXor)));
				},
				'=' if self.peek_for('>') => {
					self.push_token(TArrow);
				},
				'=' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompEqual)));
					}
				},
				'=' => {
					self.push_token(TEqual);
				},
				'<' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompLessThanOrEqual)));
				},
				'<' if self.peek_for('<') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShl)));
					} else {
						self.push_token(TBinOp(BinBit(BitShl)));
					}
				},
				'<' => {
					self.push_token(TBinOp(BinComp(CompLessThan)));
				},
				'>' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompGreaterThanOrEqual)));
				},
				'>' if self.peek_for('>') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShr)));
					} else {
						self.push_token(TBinOp(BinBit(BitShr)));
					}
				},
				'>' => {
					self.push_token(TBinOp(BinComp(CompGreaterThan)));
				},
				'!' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictNotEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompNotEqual)));
					}
				},
				'!' => {
					self.push_token(TUnaryOp(UnaryNot));
				},
				'\n' => {
					self.line_number += 1;
					self.column_number = 0;
				},
				'\r' => {
					self.column_number = 0;
				},
				' ' => (),
				ch => fail!("{}:{}: Unexpected '{}'", self.line_number, self.column_number, ch)
			};
		}
		Ok(())
	}
}<|endoftext|>


<commit_before>use libc::c_int;

use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::ptr::null;

use ReadsMemory;
use slice::MemorySlice;
use error::*;

pub struct MemReader {
  pid: u32
}

impl MemReader {
  pub fn new(pid: u32) -> Result<MemReader> {
    Ok(MemReader {
      pid: pid
    })
  }

  fn get_memory_file(&self) -> Result<File> {
    File::open(&format!("/proc/{}/mem", self.pid)).map_err(|e| MemReaderError::Io(e))
  }
}

impl ReadsMemory for MemReader {
  fn read_bytes(&self, address: usize, n: usize) -> Result<Vec<u8>> {
    let mut file = self.get_memory_file()?;
    file.seek(SeekFrom::Start(address as u64)).map_err(|e| MemReaderError::Io(e))?;
    let mut bytes: Vec<u8> = vec![0; n];
    file.read_exact(&mut bytes).map_err(|e| MemReaderError::Io(e))?;
    Ok(bytes)
  }
}

impl ProvidesSlices for MemReader {
  fn address_slice(&self, start: usize, end: usize) -> MemorySlice {
    MemorySlice::new(self, start, end)
  }

  fn address_slice_len(&self, start: usize, n: usize) -> MemorySlice {
    MemorySlice::new(self, start, start + n)
  }
}
<commit_msg>fix: add import and remove unused from linux<commit_after>use std::fs::File;
use std::io::{Read, Seek, SeekFrom};

use {ReadsMemory, ProvidesSlices};
use slice::MemorySlice;
use error::*;

pub struct MemReader {
  pid: u32
}

impl MemReader {
  pub fn new(pid: u32) -> Result<MemReader> {
    Ok(MemReader {
      pid: pid
    })
  }

  fn get_memory_file(&self) -> Result<File> {
    File::open(&format!("/proc/{}/mem", self.pid)).map_err(|e| MemReaderError::Io(e))
  }
}

impl ReadsMemory for MemReader {
  fn read_bytes(&self, address: usize, n: usize) -> Result<Vec<u8>> {
    let mut file = self.get_memory_file()?;
    file.seek(SeekFrom::Start(address as u64)).map_err(|e| MemReaderError::Io(e))?;
    let mut bytes: Vec<u8> = vec![0; n];
    file.read_exact(&mut bytes).map_err(|e| MemReaderError::Io(e))?;
    Ok(bytes)
  }
}

impl ProvidesSlices for MemReader {
  fn address_slice(&self, start: usize, end: usize) -> MemorySlice {
    MemorySlice::new(self, start, end)
  }

  fn address_slice_len(&self, start: usize, n: usize) -> MemorySlice {
    MemorySlice::new(self, start, start + n)
  }
}
<|endoftext|>


<commit_before>pub const TELESCOPE: u8 = 0x20;
pub const TINGLE_TUNER: u8 = 0x21;
pub const WIND_WAKER: u8 = 0x22;
pub const SPOILS_BAG: u8 = 0x24;
pub const GRAPPLING_HOOK: u8 = 0x25;
pub const PICTO_BOX: u8 = 0x26;
pub const BOW: u8 = 0x27;
pub const IRON_BOOTS: u8 = 0x29;
pub const MAGIC_ARMOR: u8 = 0x2A;
pub const BAIT_BAG: u8 = 0x2C;
pub const BOOMERANG: u8 = 0x2D;
pub const HOOKSHOT: u8 = 0x2F;
pub const DELIVERY_BAG: u8 = 0x30;
pub const BOMBS: u8 = 0x31;
pub const SKULL_HAMMER: u8 = 0x33;
pub const DEKU_LEAF: u8 = 0x34;
pub const BOW_WITH_FIRE_AND_ICE_ARROWS: u8 = 0x35;
pub const BOW_WITH_LIGHT_ARROWS: u8 = 0x36;
pub const NORMAL_SWORD: u8 = 0x38;
pub const UNCHARGED_MASTER_SWORD: u8 = 0x39;
pub const HALF_CHARGED_MASTER_SWORD: u8 = 0x3A;
pub const NORMAL_SHIELD: u8 = 0x3B;
pub const MIRROR_SHIELD: u8 = 0x3C;
pub const FULLY_CHARGED_MASTER_SWORD: u8 = 0x3E;
pub const EMPTY_BOTTLE: u8 = 0x50;
pub const RED_POTION: u8 = 0x51;
pub const GREEN_POTION: u8 = 0x52;
pub const BLUE_POTION: u8 = 0x53;
pub const ELIXIR_SOUP_HALF: u8 = 0x54;
pub const ELIXIR_SOUP: u8 = 0x55;
pub const WATER: u8 = 0x56;
pub const FAIRY: u8 = 0x57;
pub const FOREST_FIREFLY: u8 = 0x58;
pub const FOREST_WATER: u8 = 0x59;
pub const SAIL: u8 = 0x78;
<commit_msg>Add the remaining items<commit_after>pub const JOY_PENDANT: u8 = 0x1F;
pub const TELESCOPE: u8 = 0x20;
pub const TINGLE_TUNER: u8 = 0x21;
pub const WIND_WAKER: u8 = 0x22;
pub const PICTO_BOX: u8 = 0x23;
pub const SPOILS_BAG: u8 = 0x24;
pub const GRAPPLING_HOOK: u8 = 0x25;
pub const DELUXE_PICTO_BOX: u8 = 0x26;
pub const BOW: u8 = 0x27;
pub const POWER_BRACELETS: u8 = 0x28; // also 0x2e
pub const IRON_BOOTS: u8 = 0x29;
pub const MAGIC_ARMOR: u8 = 0x2A;
pub const WATER_BOOTS: u8 = 0x2B;
pub const BAIT_BAG: u8 = 0x2C;
pub const BOOMERANG: u8 = 0x2D;
pub const HOOKSHOT: u8 = 0x2F;
pub const DELIVERY_BAG: u8 = 0x30;
pub const BOMBS: u8 = 0x31;
pub const TUNIC: u8 = 0x32; // also 0x37
pub const SKULL_HAMMER: u8 = 0x33;
pub const DEKU_LEAF: u8 = 0x34;
pub const BOW_WITH_FIRE_AND_ICE_ARROWS: u8 = 0x35;
pub const BOW_WITH_LIGHT_ARROWS: u8 = 0x36;
pub const HEROS_SWORD: u8 = 0x38;
pub const UNCHARGED_MASTER_SWORD: u8 = 0x39;
pub const HALF_CHARGED_MASTER_SWORD: u8 = 0x3A;
pub const HEROS_SHIELD: u8 = 0x3B;
pub const MIRROR_SHIELD: u8 = 0x3C;
pub const FULLY_CHARGED_MASTER_SWORD: u8 = 0x3E;
pub const PIRATES_CHARM: u8 = 0x42;
pub const HEROS_CHARM: u8 = 0x43;
pub const SKULL_NECKLACE: u8 = 0x45;
pub const BOKO_BABA_SEED: u8 = 0x46;
pub const GOLDEN_FEATHER: u8 = 0x47;
pub const KNIGHTS_CREST: u8 = 0x48;
pub const RED_CHU_JELLY: u8 = 0x49;
pub const GREEN_CHU_JELLY: u8 = 0x4A;
pub const BLUE_CHU_JELLY: u8 = 0x4B;
pub const MAP: u8 = 0x4C;
pub const COMPASS: u8 = 0x4D;
pub const BIG_KEY: u8 = 0x4E;
pub const EMPTY_BOTTLE: u8 = 0x50;
pub const RED_POTION: u8 = 0x51;
pub const GREEN_POTION: u8 = 0x52;
pub const BLUE_POTION: u8 = 0x53;
pub const ELIXIR_SOUP_HALF: u8 = 0x54;
pub const ELIXIR_SOUP: u8 = 0x55;
pub const WATER: u8 = 0x56;
pub const FAIRY: u8 = 0x57;
pub const FOREST_FIREFLY: u8 = 0x58;
pub const FOREST_WATER: u8 = 0x59;
pub const TRIFORCE_PIECE_1: u8 = 0x61;
pub const TRIFORCE_PIECE_2: u8 = 0x62;
pub const TRIFORCE_PIECE_3: u8 = 0x63;
pub const TRIFORCE_PIECE_4: u8 = 0x64;
pub const TRIFORCE_PIECE_5: u8 = 0x65;
pub const TRIFORCE_PIECE_6: u8 = 0x66;
pub const TRIFORCE_PIECE_7: u8 = 0x67;
pub const TRIFORCE_PIECE_8: u8 = 0x68;
pub const NAYRUS_PEARL: u8 = 0x69;
pub const DINS_PEARL: u8 = 0x6A;
pub const FARORES_PEARL: u8 = 0x6B;
pub const SAIL: u8 = 0x78;
pub const TRIFORCE_CHART: u8 = 0x79;
pub const ALL_PURPOSE_BAIT: u8 = 0x82;
pub const HYOI_PEAR: u8 = 0x83;
pub const TOWN_FLOWER: u8 = 0x8C;
pub const SEA_FLOWER: u8 = 0x8D;
pub const EXOTIC_FLOWER: u8 = 0x8E;
pub const HEROS_FLAG: u8 = 0x8F;
pub const BIG_CATCH_FLAG: u8 = 0x90;
pub const BIG_SALE_FLAG: u8 = 0x91;
pub const PINWHEEL: u8 = 0x92;
pub const SICKLE_MOON_FLAG: u8 = 0x93;
pub const SKULL_TOWER_IDOL: u8 = 0x94;
pub const FOUNTAIN_IDOL: u8 = 0x95;
pub const POSTMAN_STATUE: u8 = 0x96;
pub const SHOP_GURU_STATUE: u8 = 0x97;
pub const FATHERS_LETTER: u8 = 0x98;
pub const NOTE_TO_MOM: u8 = 0x99;
pub const MAGGIES_LETTER: u8 = 0x9A;
pub const MOBLINS_LETTER: u8 = 0x9B;
pub const CABANA_DEED: u8 = 0x9C;
pub const COMPLIMENTARY_ID: u8 = 0x9D;
pub const FILL_UP_COUPON: u8 = 0x9E;
pub const GOLDEN_TINGLE_HEAD: u8 = 0xA3;
pub const EMPTY: u8 = 0xFF;
<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::str;

pub enum TokenKind {
    Identifier,
    IntNumber,
    FloatNumber,
    String,
    Char,
    Symbol,
    Newline,
    End,
}

pub struct Token {
    pub kind: TokenKind,
    pub val: String,
    pub line: i32,
}

impl Token {
    pub fn new(kind: TokenKind, val: &str, line: i32) -> Token {
        Token {
            kind: kind,
            val: val.to_string(),
            line: line,
        }
    }
}

pub struct Lexer<'a> {
    cur_line: i32,
    filename: String,
    peek: iter::Peekable<str::Chars<'a>>,
}

impl<'a> Lexer<'a> {
    pub fn new(filename: String, input: &'a str) -> Lexer<'a> {
        let l = Lexer {
            cur_line: 0,
            filename: filename.to_string(),
            peek: input.chars().peekable(),
        };
        l
    }
    pub fn get_filename(self) -> String {
        self.filename
    }

    pub fn read_identifier(&mut self) -> Token {
        let mut ident = String::new();
        loop {
            match self.peek.peek() {
                Some(&c) => {
                    match c {
                        'a'...'z' | 'A'...'Z' | '_' | '0'...'9' => ident.push(c),
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek.next();
        }
        Token {
            kind: TokenKind::Identifier,
            val: ident,
            line: self.cur_line,
        }
    }
    pub fn read_newline(&mut self) -> Token {
        self.peek.next();
        Token {
            kind: TokenKind::Newline,
            val: "".to_string(),
            line: self.cur_line,
        }
    }
    pub fn read_symbol(&mut self) -> Token {
        let c = self.peek.next();
        let mut sym = String::new();
        sym.push(c.unwrap());
        Token::new(TokenKind::Symbol, sym.as_str(), self.cur_line)
    }

    pub fn read_token(&mut self) -> Option<Token> {
        // TODO: tentatively
        let ret = match self.peek.peek() {
            Some(&c) => {
                match c {
                    'a'...'z' | 'A'...'Z' | '_' => Some(self.read_identifier()),
                    ' ' | '\t' => {
                        self.peek.next();
                        self.read_token()
                    }
                    '\n' => Some(self.read_newline()),
                    _ => Some(self.read_symbol()),
                }
            }
            None => None as Option<Token>,
        };
        ret
    }
}
<commit_msg>refine code<commit_after>use std::io::{BufRead, BufReader};
use std::io;
use std::io::prelude::*;
use std::iter;
use std::str;

pub enum TokenKind {
    Identifier,
    IntNumber,
    FloatNumber,
    String,
    Char,
    Symbol,
    Newline,
    End,
}

pub struct Token {
    pub kind: TokenKind,
    pub val: String,
    pub line: i32,
}

impl Token {
    pub fn new(kind: TokenKind, val: &str, line: i32) -> Token {
        Token {
            kind: kind,
            val: val.to_string(),
            line: line,
        }
    }
}

pub struct Lexer<'a> {
    cur_line: i32,
    filename: String,
    peek: iter::Peekable<str::Chars<'a>>,
}

impl<'a> Lexer<'a> {
    pub fn new(filename: String, input: &'a str) -> Lexer<'a> {
        let l = Lexer {
            cur_line: 0,
            filename: filename.to_string(),
            peek: input.chars().peekable(),
        };
        l
    }
    pub fn get_filename(self) -> String {
        self.filename
    }

    pub fn read_identifier(&mut self) -> Token {
        let mut ident = String::new();
        loop {
            match self.peek.peek() {
                Some(&c) => {
                    match c {
                        'a'...'z' | 'A'...'Z' | '_' | '0'...'9' => ident.push(c),
                        _ => break,
                    }
                }
                _ => break,
            };
            self.peek.next();
        }
        Token::new(TokenKind::Identifier, ident, self.cur_line);
    }
    pub fn read_newline(&mut self) -> Token {
        self.peek.next();
        Token::new(TokenKind::Newline, "".to_string(), self.cur_line);
    }
    pub fn read_symbol(&mut self) -> Token {
        let c = self.peek.next();
        let mut sym = String::new();
        sym.push(c.unwrap());
        Token::new(TokenKind::Symbol, sym.as_str(), self.cur_line)
    }

    pub fn read_token(&mut self) -> Option<Token> {
        // TODO: tentatively
        let ret = match self.peek.peek() {
            Some(&c) => {
                match c {
                    'a'...'z' | 'A'...'Z' | '_' => Some(self.read_identifier()),
                    ' ' | '\t' => {
                        self.peek.next();
                        self.read_token()
                    }
                    '\n' => Some(self.read_newline()),
                    _ => Some(self.read_symbol()),
                }
            }
            None => None as Option<Token>,
        };
        ret
    }
}
<|endoftext|>