<commit_before>//FIXME: Check unicode support

use log::{Log, Change, LogEntry};

use gapbuffer::GapBuffer;

use std::cmp;
use std::collections::HashMap;
use std::io::{File, Reader, BufferedReader};

#[deriving(Copy, PartialEq, Eq, Hash, Show)]
pub enum Mark {
    Cursor(uint),           //For keeping track of cursors.
    DisplayMark(uint),      //For using in determining some display of characters.
}

#[deriving(Copy, PartialEq, Eq, Show)]
pub enum Direction {
    Up(uint), Down(uint), Left(uint), Right(uint),
    LineStart, LineEnd,
}

pub struct Buffer {
    text: GapBuffer<u8>,                    //Actual text data being edited.
    marks: HashMap<Mark, (uint, uint)>,     //Table of marked indices in the text.
                                            // KEY: mark id => VALUE : (absolute index, line index)
    log: Log,                               //History of undoable transactions.
    pub file_path: Option<Path>,            //TODO: replace with a general metadata table
}

impl Buffer {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    /// Constructor for empty buffer.
    pub fn new() -> Buffer {
        Buffer {
            file_path: None,
            text: GapBuffer::new(),
            marks: HashMap::new(),
            log: Log::new(),
        }
    }

    /// Constructor for buffer from reader.
    pub fn new_from_reader<R: Reader>(reader: R) -> Buffer {
        let mut buff = Buffer::new();
        if let Ok(contents) = BufferedReader::new(reader).read_to_string() {
            buff.text.extend(contents.bytes());
        }
        buff
    }

    /// Constructor for buffer from file.
    pub fn new_from_file(path: Path) -> Buffer {
        if let Ok(file) = File::open(&path) {
            let mut buff = Buffer::new_from_reader(file);
            buff.file_path = Some(path);
            buff
        } else { Buffer::new() }
    }

    //----- ACCESSORS ------------------------------------------------------------------------------

    ///Length of the text stored in this buffer.
    pub fn len(&self) -> uint {
        self.text.len() + 1
    }

    ///The x,y coordinates of a mark within the file. None if not a valid mark.
    pub fn get_mark_coords(&self, mark: Mark) -> Option<(uint, uint)> {
        if let Some(idx) = self.get_mark_idx(mark) {
            if let Some(line) = get_line(idx, &self.text) {
                Some((idx - line, range(0, idx).filter(|i| -> bool { self.text[*i] == b'\n' })
                                               .fold(0, |a, _| a + 1)))
            } else { None }
        } else { None }
    }

    ///The absolute index of a mark within the file. None if not a valid mark.
    pub fn get_mark_idx(&self, mark: Mark) -> Option<uint> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(idx)
            } else { None }
        } else { None }
    }

    ///Creates an iterator on the text by lines.
    pub fn lines(&self) -> Lines {
        Lines {
            buffer: self.text[],
            tail: 0,
            head: self.len()
        }
    }

    ///Creates an iterator on the text by lines that begins at the specified mark.
    pub fn lines_from(&self, mark: Mark) -> Option<Lines> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(Lines {
                    buffer: self.text[idx..],
                    tail: 0,
                    head: self.len() - idx,
                })
            } else { None }
        } else { None }
    }

    ///Returns the status text for this buffer.
    pub fn status_text(&self) -> String {
        match self.file_path {
            Some(ref path)  =>  format!("{}", path.display()),
            None            =>  format!("untitled"),
        }
    }

    //----- MUTATORS -------------------------------------------------------------------------------

    ///Sets the mark to a given absolute index. Adds a new mark or overwrites an existing mark.
    pub fn set_mark(&mut self, mark: Mark, idx: uint) {
        if let Some(line) = get_line(idx, &self.text) {
            if let Some(tuple) = self.marks.get_mut(&mark) {
                *tuple = (idx, idx - line);
                return;
            }
            self.marks.insert(mark, (idx, idx - line));
        }
    }

    //Shift a mark relative to its position according to the direction given.
    pub fn shift_mark(&mut self, mark: Mark, direction: Direction) {
        let last = self.len() - 1;
        let text = &self.text;
        if let Some(tuple) = self.marks.get_mut(&mark) {
            let (idx, line_idx) = *tuple;
            if let (Some(line), Some(line_end)) = (get_line(idx, text), get_line_end(idx, text)) {
                *tuple = match direction {
                    //For every relative motion of a mark, should return this tuple:
                    //  value 0:    the absolute index of the mark in the file
                    //  value 1:    the index of the mark in its line (unchanged by direct verticle
                    //              traversals)
                    Direction::Left(n)      =>  {
                        if idx >= n { (idx - n, idx - n - get_line(idx - n, text).unwrap()) }
                        else { (0, 0) }
                    }
                    Direction::Right(n)     =>  {
                        if idx + n < last { (idx + n, idx + n - get_line(idx + n, text).unwrap()) }
                        else { (last, last - get_line(last, text).unwrap()) }
                    }
                    Direction::Up(n)        =>  {
                        let nlines = range(0, idx).rev().filter(|i| text[*i] == b'\n')
                                                        .take(n + 1)
                                                        .collect::<Vec<uint>>();
                        if n >= nlines.len() { (0, 0) }
                        else { (cmp::min(line_idx + nlines[n] + 1, nlines[n-1]), line_idx) }
                    }
                    Direction::Down(n)      =>  {
                        let nlines = range(idx, text.len()).filter(|i| text[*i] == b'\n')
                                                           .take(n + 1)
                                                           .collect::<Vec<uint>>();
                        if n > nlines.len() { (last, last - get_line(last, text).unwrap())
                        } else if n == nlines.len() {
                            (cmp::min(line_idx + nlines[n-1] + 1, last), line_idx)
                        } else { (cmp::min(line_idx + nlines[n-1] + 1, nlines[n]), line_idx) }
                    }
                    Direction::LineStart    =>  { (line, 0) }
                    Direction::LineEnd      =>  { (line_end, line_end - line) }
                }
            }
        }
    }
    ///Remove the char at the mark.
    pub fn remove_char(&mut self, mark: Mark) -> Option<u8> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if let Some(ch) = self.text.remove(idx) {
                let mut transaction = self.log.start(idx);
                transaction.log(Change::Remove(idx, ch), idx);
                Some(ch)
            } else { None }
        } else { None }
    }

    ///Insert a char at the mark.
    pub fn insert_char(&mut self, mark: Mark, ch: u8) {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            self.text.insert(idx, ch);
            let mut transaction = self.log.start(idx);
            transaction.log(Change::Insert(idx, ch), idx);
        }
    }

    pub fn redo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.redo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

    pub fn undo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.undo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

}

//Returns the index of the first character of the line the mark is in.
//Newline prior to mark (EXCLUSIVE) + 1.
//None iff mark is outside of the len of text.
fn get_line(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(0, mark + 1).filter(|idx| *idx == 0 || text[*idx - 1] == b'\n').max()
    } else { None }
}

//Returns the index of the newline character at the end of the line mark is in.
//Newline after mark (INCLUSIVE).
//None iff mark is outside the len of text.
fn get_line_end(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(mark, text.len()).filter(|idx| *idx == text.len() - 1 ||text[*idx] == b'\n').min()
    } else { None }
}

//Performs a transaction on the passed in buffer.
fn commit(transaction: &LogEntry, text: &mut GapBuffer<u8>) {
    for change in transaction.changes.iter() {
        match change {
            &Change::Insert(idx, ch) => {
                text.insert(idx, ch);
            }
            &Change::Remove(idx, _) => {
                text.remove(idx);
            }
        }
    }
}

//----- ITERATE BY LINES ---------------------------------------------------------------------------

pub struct Lines<'a> {
    buffer: &'a [u8],
    tail: uint,
    head: uint,
}

impl<'a> Iterator<&'a [u8]> for Lines<'a> {

    fn next(&mut self) -> Option<&'a [u8]> {
        if self.tail != self.head {

            let old_tail = self.tail;
            //update tail to either the first char after the next \n or to self.head
            self.tail = range(old_tail, self.head).filter(|idx| -> bool {
                *idx + 1 == self.head || self.buffer[*idx] == b'\n'
            }).min().unwrap() + 1;
            if self.tail == self.head { Some(self.buffer[old_tail..self.tail-1]) }
            else { Some(self.buffer[old_tail..self.tail]) }

        } else { None }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        //TODO: this is technically correct but a better estimate could be implemented
        (1, Some(self.head))
    }

}

//----- TESTS --------------------------------------------------------------------------------------

#[cfg(test)]
mod test {

    use buffer::{Buffer, Direction, Mark};

    fn setup_buffer(testcase: &'static str) -> Buffer {
        let mut buffer = Buffer::new();
        buffer.text.extend(testcase.bytes());
        buffer.set_mark(Mark::Cursor(0), 0);
        buffer
    }

    #[test]
    fn test_insert() {
        let mut buffer = setup_buffer("");
        buffer.insert_char(Mark::Cursor(0), b'A');
        assert_eq!(buffer.len(), 2);
        assert_eq!(buffer.lines().next().unwrap(), [b'A']);
    }

    #[test]
    fn test_remove() {
        let mut buffer = setup_buffer("ABCD");
        buffer.remove_char(Mark::Cursor(0));

        assert_eq!(buffer.len(), 4);
        assert_eq!(buffer.lines().next().unwrap(), [b'B', b'C', b'D']);
    }

    #[test]
    fn test_set_mark() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 2);
    }

    #[test]
    fn test_shift_down() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Down(2));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (2, 2));
    }

    #[test]
    fn test_shift_right() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::Right(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_up() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 10);
        buffer.shift_mark(Mark::Cursor(0), Direction::Up(1));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (1, 1));
    }

    #[test]
    fn test_shift_left() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_linestart() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::LineStart);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 0);
    }

    #[test]
    fn test_shift_lineend() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::LineEnd);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 3);
    }

    #[test]
    fn test_to_lines() {
        let buffer = setup_buffer("Test\nA\nTest");
        let mut lines = buffer.lines();

        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'A',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn test_to_lines_from() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 6);
        let mut lines = buffer.lines_from(Mark::Cursor(0)).unwrap();

        assert_eq!(lines.next().unwrap(), [b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

}
<commit_msg>Fixed a small bug.<commit_after>//FIXME: Check unicode support

use log::{Log, Change, LogEntry};

use gapbuffer::GapBuffer;

use std::cmp;
use std::collections::HashMap;
use std::io::{File, Reader, BufferedReader};

#[deriving(Copy, PartialEq, Eq, Hash, Show)]
pub enum Mark {
    Cursor(uint),           //For keeping track of cursors.
    DisplayMark(uint),      //For using in determining some display of characters.
}

#[deriving(Copy, PartialEq, Eq, Show)]
pub enum Direction {
    Up(uint), Down(uint), Left(uint), Right(uint),
    LineStart, LineEnd,
}

pub struct Buffer {
    text: GapBuffer<u8>,                    //Actual text data being edited.
    marks: HashMap<Mark, (uint, uint)>,     //Table of marked indices in the text.
                                            // KEY: mark id => VALUE : (absolute index, line index)
    log: Log,                               //History of undoable transactions.
    pub file_path: Option<Path>,            //TODO: replace with a general metadata table
}

impl Buffer {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    /// Constructor for empty buffer.
    pub fn new() -> Buffer {
        Buffer {
            file_path: None,
            text: GapBuffer::new(),
            marks: HashMap::new(),
            log: Log::new(),
        }
    }

    /// Constructor for buffer from reader.
    pub fn new_from_reader<R: Reader>(reader: R) -> Buffer {
        let mut buff = Buffer::new();
        if let Ok(contents) = BufferedReader::new(reader).read_to_string() {
            buff.text.extend(contents.bytes());
        }
        buff
    }

    /// Constructor for buffer from file.
    pub fn new_from_file(path: Path) -> Buffer {
        if let Ok(file) = File::open(&path) {
            let mut buff = Buffer::new_from_reader(file);
            buff.file_path = Some(path);
            buff
        } else { Buffer::new() }
    }

    //----- ACCESSORS ------------------------------------------------------------------------------

    ///Length of the text stored in this buffer.
    pub fn len(&self) -> uint {
        self.text.len() + 1
    }

    ///The x,y coordinates of a mark within the file. None if not a valid mark.
    pub fn get_mark_coords(&self, mark: Mark) -> Option<(uint, uint)> {
        if let Some(idx) = self.get_mark_idx(mark) {
            if let Some(line) = get_line(idx, &self.text) {
                Some((idx - line, range(0, idx).filter(|i| -> bool { self.text[*i] == b'\n' })
                                               .fold(0, |a, _| a + 1)))
            } else { None }
        } else { None }
    }

    ///The absolute index of a mark within the file. None if not a valid mark.
    pub fn get_mark_idx(&self, mark: Mark) -> Option<uint> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(idx)
            } else { None }
        } else { None }
    }

    ///Creates an iterator on the text by lines.
    pub fn lines(&self) -> Lines {
        Lines {
            buffer: self.text[],
            tail: 0,
            head: self.len()
        }
    }

    ///Creates an iterator on the text by lines that begins at the specified mark.
    pub fn lines_from(&self, mark: Mark) -> Option<Lines> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if idx < self.len() {
                Some(Lines {
                    buffer: self.text[idx..],
                    tail: 0,
                    head: self.len() - idx,
                })
            } else { None }
        } else { None }
    }

    ///Returns the status text for this buffer.
    pub fn status_text(&self) -> String {
        match self.file_path {
            Some(ref path)  =>  format!("{}", path.display()),
            None            =>  format!("untitled"),
        }
    }

    //----- MUTATORS -------------------------------------------------------------------------------

    ///Sets the mark to a given absolute index. Adds a new mark or overwrites an existing mark.
    pub fn set_mark(&mut self, mark: Mark, idx: uint) {
        if let Some(line) = get_line(idx, &self.text) {
            if let Some(tuple) = self.marks.get_mut(&mark) {
                *tuple = (idx, idx - line);
                return;
            }
            self.marks.insert(mark, (idx, idx - line));
        }
    }

    //Shift a mark relative to its position according to the direction given.
    pub fn shift_mark(&mut self, mark: Mark, direction: Direction) {
        let last = self.len() - 1;
        let text = &self.text;
        if let Some(tuple) = self.marks.get_mut(&mark) {
            let (idx, line_idx) = *tuple;
            if let (Some(line), Some(line_end)) = (get_line(idx, text), get_line_end(idx, text)) {
                *tuple = match direction {
                    //For every relative motion of a mark, should return this tuple:
                    //  value 0:    the absolute index of the mark in the file
                    //  value 1:    the index of the mark in its line (unchanged by direct verticle
                    //              traversals)
                    Direction::Left(n)      =>  {
                        if idx >= n { (idx - n, idx - n - get_line(idx - n, text).unwrap()) }
                        else { (0, 0) }
                    }
                    Direction::Right(n)     =>  {
                        if idx + n < last { (idx + n, idx + n - get_line(idx + n, text).unwrap()) }
                        else { (last, last - get_line(last, text).unwrap()) }
                    }
                    Direction::Up(n)        =>  {
                        let nlines = range(0, idx).rev().filter(|i| text[*i] == b'\n')
                                                        .take(n + 1)
                                                        .collect::<Vec<uint>>();
                        if n == nlines.len() { (cmp::min(line_idx, nlines[0]), line_idx) }
                        else if n > nlines.len() { (0, 0) }
                        else { (cmp::min(line_idx + nlines[n] + 1, nlines[n-1]), line_idx) }
                    }
                    Direction::Down(n)      =>  {
                        let nlines = range(idx, text.len()).filter(|i| text[*i] == b'\n')
                                                           .take(n + 1)
                                                           .collect::<Vec<uint>>();
                        if n > nlines.len() { (last, last - get_line(last, text).unwrap())
                        } else if n == nlines.len() {
                            (cmp::min(line_idx + nlines[n-1] + 1, last), line_idx)
                        } else { (cmp::min(line_idx + nlines[n-1] + 1, nlines[n]), line_idx) }
                    }
                    Direction::LineStart    =>  { (line, 0) }
                    Direction::LineEnd      =>  { (line_end, line_end - line) }
                }
            }
        }
    }
    ///Remove the char at the mark.
    pub fn remove_char(&mut self, mark: Mark) -> Option<u8> {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            if let Some(ch) = self.text.remove(idx) {
                let mut transaction = self.log.start(idx);
                transaction.log(Change::Remove(idx, ch), idx);
                Some(ch)
            } else { None }
        } else { None }
    }

    ///Insert a char at the mark.
    pub fn insert_char(&mut self, mark: Mark, ch: u8) {
        if let Some(&(idx, _)) = self.marks.get(&mark) {
            self.text.insert(idx, ch);
            let mut transaction = self.log.start(idx);
            transaction.log(Change::Insert(idx, ch), idx);
        }
    }

    pub fn redo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.redo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

    pub fn undo(&mut self) -> Option<&LogEntry> {
        if let Some(transaction) = self.log.undo() {
            commit(transaction, &mut self.text);
            Some(transaction)
        } else { None }
    }

}

//Returns the index of the first character of the line the mark is in.
//Newline prior to mark (EXCLUSIVE) + 1.
//None iff mark is outside of the len of text.
fn get_line(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(0, mark + 1).filter(|idx| *idx == 0 || text[*idx - 1] == b'\n').max()
    } else { None }
}

//Returns the index of the newline character at the end of the line mark is in.
//Newline after mark (INCLUSIVE).
//None iff mark is outside the len of text.
fn get_line_end(mark: uint, text: &GapBuffer<u8>) -> Option<uint> {
    if mark <= text.len() {
        range(mark, text.len() + 1).filter(|idx| *idx == text.len() ||text[*idx] == b'\n').min()
    } else { None }
}

//Performs a transaction on the passed in buffer.
fn commit(transaction: &LogEntry, text: &mut GapBuffer<u8>) {
    for change in transaction.changes.iter() {
        match change {
            &Change::Insert(idx, ch) => {
                text.insert(idx, ch);
            }
            &Change::Remove(idx, _) => {
                text.remove(idx);
            }
        }
    }
}

//----- ITERATE BY LINES ---------------------------------------------------------------------------

pub struct Lines<'a> {
    buffer: &'a [u8],
    tail: uint,
    head: uint,
}

impl<'a> Iterator<&'a [u8]> for Lines<'a> {

    fn next(&mut self) -> Option<&'a [u8]> {
        if self.tail != self.head {

            let old_tail = self.tail;
            //update tail to either the first char after the next \n or to self.head
            self.tail = range(old_tail, self.head).filter(|idx| -> bool {
                *idx + 1 == self.head || self.buffer[*idx] == b'\n'
            }).min().unwrap() + 1;
            if self.tail == self.head { Some(self.buffer[old_tail..self.tail-1]) }
            else { Some(self.buffer[old_tail..self.tail]) }

        } else { None }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        //TODO: this is technically correct but a better estimate could be implemented
        (1, Some(self.head))
    }

}

//----- TESTS --------------------------------------------------------------------------------------

#[cfg(test)]
mod test {

    use buffer::{Buffer, Direction, Mark};

    fn setup_buffer(testcase: &'static str) -> Buffer {
        let mut buffer = Buffer::new();
        buffer.text.extend(testcase.bytes());
        buffer.set_mark(Mark::Cursor(0), 0);
        buffer
    }

    #[test]
    fn test_insert() {
        let mut buffer = setup_buffer("");
        buffer.insert_char(Mark::Cursor(0), b'A');
        assert_eq!(buffer.len(), 2);
        assert_eq!(buffer.lines().next().unwrap(), [b'A']);
    }

    #[test]
    fn test_remove() {
        let mut buffer = setup_buffer("ABCD");
        buffer.remove_char(Mark::Cursor(0));

        assert_eq!(buffer.len(), 4);
        assert_eq!(buffer.lines().next().unwrap(), [b'B', b'C', b'D']);
    }

    #[test]
    fn test_set_mark() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 2);
    }

    #[test]
    fn test_shift_down() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Down(2));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (2, 2));
    }

    #[test]
    fn test_shift_right() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::Right(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_up() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 10);
        buffer.shift_mark(Mark::Cursor(0), Direction::Up(1));

        assert_eq!(buffer.get_mark_coords(Mark::Cursor(0)).unwrap(), (1, 1));
    }

    #[test]
    fn test_shift_left() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 1);
    }

    #[test]
    fn test_shift_linestart() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 2);
        buffer.shift_mark(Mark::Cursor(0), Direction::LineStart);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 0);
    }

    #[test]
    fn test_shift_lineend() {
        let mut buffer = setup_buffer("Test");
        buffer.shift_mark(Mark::Cursor(0), Direction::LineEnd);

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 4);
    }

    #[test]
    fn test_to_lines() {
        let buffer = setup_buffer("Test\nA\nTest");
        let mut lines = buffer.lines();

        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'A',b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn test_to_lines_from() {
        let mut buffer = setup_buffer("Test\nA\nTest");
        buffer.set_mark(Mark::Cursor(0), 6);
        let mut lines = buffer.lines_from(Mark::Cursor(0)).unwrap();

        assert_eq!(lines.next().unwrap(), [b'\n']);
        assert_eq!(lines.next().unwrap(), [b'T',b'e',b's',b't']);
    }

    #[test]
    fn move_from_final_position() {
        let mut buffer = setup_buffer("Test");
        buffer.set_mark(Mark::Cursor(0), 4);
        buffer.shift_mark(Mark::Cursor(0), Direction::Left(1));

        assert_eq!(buffer.get_mark_idx(Mark::Cursor(0)).unwrap(), 3);
    }

}
<|endoftext|>


<commit_before>//! The module contains an implementation of a simple HTTP/2 client.

use super::super::http::connection::ClientConnection;
use super::super::http::connection::HttpConnection;
use super::super::http::connection::HttpConnect;
use super::super::http::transport::TransportStream;
use super::super::http::session::{DefaultSession, Stream};
use super::super::http::{StreamId, HttpResult, HttpError, Response, Header, Request};

/// A struct implementing a simple HTTP/2 client.
///
/// This client works as an HTTP/1.1 client with a Keep-Alive connection and
/// pipelining might work.
///
/// Multiple requests can be queued up (and sent to the server) by calling
/// `request` multiple times, before any `get_response`.
///
/// Once a `get_response` is issued, the client blocks until it receives the
/// response for the particular request that was referenced in the `get_response`
/// call.
///
/// Therefore, by doing `request` -> `get_response` we can use the HTTP/2
/// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by
/// queuing up a sequence of requests and then "joining" over them by calling
/// `get_response` for each of them.
///
/// The responses that are returned by the client are very raw representations
/// of the response.
///
/// # Notes
///
/// - For now (temporarily) no requests with bodies are supported.
/// - For now, only HTTP/2 over a cleartext TCP connection is supported.
/// - A direct HTTP/2 connection is used (not an upgrade of an HTTP/1.1
///   connection)
///
/// # Examples
///
/// Issue a simple GET request using the helper `get` method. Premade connection
/// passed to the client.
///
/// ```no_run
/// use std::net::TcpStream;
/// use solicit::http::HttpScheme;
/// use solicit::http::connection::HttpConnection;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let conn = HttpConnection::new(TcpStream::connect(&("http2bin.org", 80)).unwrap(),
///                                HttpScheme::Http,
///                                "http2bin.org".into());
/// let mut client = SimpleClient::with_connection(conn).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a simple GET request using the helper `get` method. Pass a connector
/// to establish a new connection.
///
/// ```no_run
/// use solicit::http::connection::CleartextConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let connector = CleartextConnector { host: "http2bin.org" };
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a GET request over `https` using the `TlsConnector`
///
/// ```no_run
/// use solicit::http::connection::TlsConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let path = "/path/to/certs.pem";
/// let connector = TlsConnector::new("http2bin.org", &path);
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/get", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
#[unstable = "This is unstable"]
pub struct SimpleClient<S> where S: TransportStream {
    /// The underlying `ClientConnection` that the client uses
    conn: ClientConnection<S, DefaultSession>,
    /// Holds the ID that can be assigned to the next stream to be opened by the
    /// client.
    next_stream_id: u32,
}

impl<S> SimpleClient<S> where S: TransportStream {
    /// Create a new `SimpleClient` instance that will use the given `HttpConnection`
    /// to communicate to the server.
    ///
    /// It assumes that the connection is in an uninitialized state and will try
    /// to send the client preface and make sure it receives the server preface
    /// before returning.
    pub fn with_connection(conn: HttpConnection<S>) -> HttpResult<SimpleClient<S>> {
        let mut client = SimpleClient {
            conn: ClientConnection::with_connection(conn, DefaultSession::new()),
            next_stream_id: 1,
        };

        try!(client.init());

        Ok(client)
    }

    /// A convenience constructor that first tries to establish an HTTP/2
    /// connection by using the given connector instance (an implementation of
    /// the `HttpConnect` trait).
    ///
    /// # Panics
    ///
    /// Currently, it panics if the connector returns an error.
    pub fn with_connector<C>(connector: C) -> HttpResult<SimpleClient<S>>
            where C: HttpConnect<Stream=S> {
        let conn = connector.connect().ok().unwrap();
        SimpleClient::with_connection(conn)
    }

    /// Internal helper method that performs the initialization of the client's
    /// connection.
    #[inline]
    fn init(&mut self) -> HttpResult<()> {
        self.conn.init()
    }

    /// Send a request to the server. Blocks until the entire request has been
    /// sent.
    ///
    /// The request is described by the method, the path on which it should be
    /// invoked and the "real" headers that should be included. Clients should
    /// never put pseudo-headers in the `headers` parameter, as those are
    /// automatically included based on metadata.
    ///
    /// # Returns
    ///
    /// If the full request is successfully sent, returns the ID of the stream
    /// on which the request was sent. Clients can use this ID to refer to the
    /// response.
    ///
    /// Any IO errors are propagated.
    pub fn request(&mut self, method: &[u8], path: &[u8], extras: &[Header])
            -> HttpResult<StreamId> {
        let stream_id = self.new_stream();
        let mut headers: Vec<Header> = vec![
            (b":method".to_vec(), method.to_vec()),
            (b":path".to_vec(), path.to_vec()),
            (b":authority".to_vec(), self.conn.host().as_bytes().to_vec()),
            (b":scheme".to_vec(), self.conn.scheme().as_bytes().to_vec()),
        ];
        headers.extend(extras.to_vec().into_iter());

        try!(self.conn.send_request(Request {
            stream_id: stream_id,
            headers: headers,
            body: Vec::new(),
        }));

        Ok(stream_id)
    }

    /// Gets the response for the stream with the given ID. If a valid stream ID
    /// is given, it blocks until a response is received.
    ///
    /// # Returns
    ///
    /// A `Response` if the response can be successfully read.
    ///
    /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol
    /// also stop processing and are returned to the client.
    pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult<Response> {
        match self.conn.session.get_stream(stream_id) {
            None => return Err(HttpError::UnknownStreamId),
            Some(_) => {},
        };
        loop {
            if let Some(stream) = self.conn.session.get_stream(stream_id) {
                if stream.is_closed() {
                    return Ok(Response {
                        stream_id: stream.id(),
                        headers: stream.headers.clone().unwrap(),
                        body: stream.body.clone(),
                    });
                }
            }
            try!(self.handle_next_frame());
        }
    }

    /// Performs a GET request on the given path. This is a shortcut method for
    /// calling `request` followed by `get_response` for the returned stream ID.
    pub fn get(&mut self, path: &[u8], extra_headers: &[Header])
            -> HttpResult<Response> {
        let stream_id = try!(self.request(b"GET", path, extra_headers));
        self.get_response(stream_id)
    }

    /// Internal helper method that initializes a new stream and returns its
    /// ID once done.
    fn new_stream(&mut self) -> StreamId {
        let stream_id = self.get_next_stream_id();
        self.conn.session.new_stream(stream_id);

        stream_id
    }

    /// Internal helper method that gets the next valid stream ID number.
    fn get_next_stream_id(&mut self) -> StreamId {
        let ret = self.next_stream_id;
        self.next_stream_id += 2;

        ret
    }

    /// Internal helper method that triggers the client to handle the next
    /// frame off the HTTP/2 connection.
    #[inline]
    fn handle_next_frame(&mut self) -> HttpResult<()> {
        self.conn.handle_next_frame()
    }
}
<commit_msg>Remove the useless #[unstable] marker<commit_after>//! The module contains an implementation of a simple HTTP/2 client.

use super::super::http::connection::ClientConnection;
use super::super::http::connection::HttpConnection;
use super::super::http::connection::HttpConnect;
use super::super::http::transport::TransportStream;
use super::super::http::session::{DefaultSession, Stream};
use super::super::http::{StreamId, HttpResult, HttpError, Response, Header, Request};

/// A struct implementing a simple HTTP/2 client.
///
/// This client works as an HTTP/1.1 client with a Keep-Alive connection and
/// pipelining might work.
///
/// Multiple requests can be queued up (and sent to the server) by calling
/// `request` multiple times, before any `get_response`.
///
/// Once a `get_response` is issued, the client blocks until it receives the
/// response for the particular request that was referenced in the `get_response`
/// call.
///
/// Therefore, by doing `request` -> `get_response` we can use the HTTP/2
/// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by
/// queuing up a sequence of requests and then "joining" over them by calling
/// `get_response` for each of them.
///
/// The responses that are returned by the client are very raw representations
/// of the response.
///
/// # Notes
///
/// - For now (temporarily) no requests with bodies are supported.
/// - For now, only HTTP/2 over a cleartext TCP connection is supported.
/// - A direct HTTP/2 connection is used (not an upgrade of an HTTP/1.1
///   connection)
///
/// # Examples
///
/// Issue a simple GET request using the helper `get` method. Premade connection
/// passed to the client.
///
/// ```no_run
/// use std::net::TcpStream;
/// use solicit::http::HttpScheme;
/// use solicit::http::connection::HttpConnection;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let conn = HttpConnection::new(TcpStream::connect(&("http2bin.org", 80)).unwrap(),
///                                HttpScheme::Http,
///                                "http2bin.org".into());
/// let mut client = SimpleClient::with_connection(conn).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a simple GET request using the helper `get` method. Pass a connector
/// to establish a new connection.
///
/// ```no_run
/// use solicit::http::connection::CleartextConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let connector = CleartextConnector { host: "http2bin.org" };
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
///
/// Issue a GET request over `https` using the `TlsConnector`
///
/// ```no_run
/// use solicit::http::connection::TlsConnector;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let path = "/path/to/certs.pem";
/// let connector = TlsConnector::new("http2bin.org", &path);
/// let mut client = SimpleClient::with_connector(connector).unwrap();
/// let response = client.get(b"/get", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
pub struct SimpleClient<S> where S: TransportStream {
    /// The underlying `ClientConnection` that the client uses
    conn: ClientConnection<S, DefaultSession>,
    /// Holds the ID that can be assigned to the next stream to be opened by the
    /// client.
    next_stream_id: u32,
}

impl<S> SimpleClient<S> where S: TransportStream {
    /// Create a new `SimpleClient` instance that will use the given `HttpConnection`
    /// to communicate to the server.
    ///
    /// It assumes that the connection is in an uninitialized state and will try
    /// to send the client preface and make sure it receives the server preface
    /// before returning.
    pub fn with_connection(conn: HttpConnection<S>) -> HttpResult<SimpleClient<S>> {
        let mut client = SimpleClient {
            conn: ClientConnection::with_connection(conn, DefaultSession::new()),
            next_stream_id: 1,
        };

        try!(client.init());

        Ok(client)
    }

    /// A convenience constructor that first tries to establish an HTTP/2
    /// connection by using the given connector instance (an implementation of
    /// the `HttpConnect` trait).
    ///
    /// # Panics
    ///
    /// Currently, it panics if the connector returns an error.
    pub fn with_connector<C>(connector: C) -> HttpResult<SimpleClient<S>>
            where C: HttpConnect<Stream=S> {
        let conn = connector.connect().ok().unwrap();
        SimpleClient::with_connection(conn)
    }

    /// Internal helper method that performs the initialization of the client's
    /// connection.
    #[inline]
    fn init(&mut self) -> HttpResult<()> {
        self.conn.init()
    }

    /// Send a request to the server. Blocks until the entire request has been
    /// sent.
    ///
    /// The request is described by the method, the path on which it should be
    /// invoked and the "real" headers that should be included. Clients should
    /// never put pseudo-headers in the `headers` parameter, as those are
    /// automatically included based on metadata.
    ///
    /// # Returns
    ///
    /// If the full request is successfully sent, returns the ID of the stream
    /// on which the request was sent. Clients can use this ID to refer to the
    /// response.
    ///
    /// Any IO errors are propagated.
    pub fn request(&mut self, method: &[u8], path: &[u8], extras: &[Header])
            -> HttpResult<StreamId> {
        let stream_id = self.new_stream();
        let mut headers: Vec<Header> = vec![
            (b":method".to_vec(), method.to_vec()),
            (b":path".to_vec(), path.to_vec()),
            (b":authority".to_vec(), self.conn.host().as_bytes().to_vec()),
            (b":scheme".to_vec(), self.conn.scheme().as_bytes().to_vec()),
        ];
        headers.extend(extras.to_vec().into_iter());

        try!(self.conn.send_request(Request {
            stream_id: stream_id,
            headers: headers,
            body: Vec::new(),
        }));

        Ok(stream_id)
    }

    /// Gets the response for the stream with the given ID. If a valid stream ID
    /// is given, it blocks until a response is received.
    ///
    /// # Returns
    ///
    /// A `Response` if the response can be successfully read.
    ///
    /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol
    /// also stop processing and are returned to the client.
    pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult<Response> {
        match self.conn.session.get_stream(stream_id) {
            None => return Err(HttpError::UnknownStreamId),
            Some(_) => {},
        };
        loop {
            if let Some(stream) = self.conn.session.get_stream(stream_id) {
                if stream.is_closed() {
                    return Ok(Response {
                        stream_id: stream.id(),
                        headers: stream.headers.clone().unwrap(),
                        body: stream.body.clone(),
                    });
                }
            }
            try!(self.handle_next_frame());
        }
    }

    /// Performs a GET request on the given path. This is a shortcut method for
    /// calling `request` followed by `get_response` for the returned stream ID.
    pub fn get(&mut self, path: &[u8], extra_headers: &[Header])
            -> HttpResult<Response> {
        let stream_id = try!(self.request(b"GET", path, extra_headers));
        self.get_response(stream_id)
    }

    /// Internal helper method that initializes a new stream and returns its
    /// ID once done.
    fn new_stream(&mut self) -> StreamId {
        let stream_id = self.get_next_stream_id();
        self.conn.session.new_stream(stream_id);

        stream_id
    }

    /// Internal helper method that gets the next valid stream ID number.
    fn get_next_stream_id(&mut self) -> StreamId {
        let ret = self.next_stream_id;
        self.next_stream_id += 2;

        ret
    }

    /// Internal helper method that triggers the client to handle the next
    /// frame off the HTTP/2 connection.
    #[inline]
    fn handle_next_frame(&mut self) -> HttpResult<()> {
        self.conn.handle_next_frame()
    }
}
<|endoftext|>


<commit_before>use {
    futures::prelude::*,
    jsonrpc_core::IoHandler,
    lsp_types::{Hover, HoverContents, HoverParams, MarkedString},
};

use crate::{completion, rpc::LanguageServerCommand, BoxFuture};

use super::*;

struct HoverCommand(RootedThread);
impl LanguageServerCommand<HoverParams> for HoverCommand {
    type Future = BoxFuture<Self::Output, ServerError<()>>;
    type Output = Option<Hover>;
    type Error = ();
    fn execute(&self, change: HoverParams) -> BoxFuture<Option<Hover>, ServerError<()>> {
        let thread = self.0.clone();
        async move {
            retrieve_expr(
                &thread,
                &change.text_document_position_params.text_document.uri,
                |module| {
                    let expr = module.expr.expr();

                    let source = &module.source;
                    let byte_index = position_to_byte_index(
                        &source,
                        &change.text_document_position_params.position,
                    )?;

                    let db = thread.get_database();
                    let env = db.as_env();
                    let (_, metadata_map) = gluon::check::metadata::metadata(&env, &expr);
                    let opt_metadata =
                        completion::get_metadata(&metadata_map, source.span(), expr, byte_index);
                    let extract = (completion::TypeAt { env: &env }, completion::SpanAt);
                    Ok(
                        completion::completion(extract, source.span(), expr, byte_index)
                            .map(|(typ, span)| {
                                let contents = match opt_metadata.and_then(|m| m.comment.as_ref()) {
                                    Some(comment) => MarkedString::String(format!(
                                        "{}\n\n{}",
                                        typ, comment.content
                                    )),
                                    None => MarkedString::from_language_code(
                                        "gluon".into(),
                                        format!("{}", typ),
                                    ),
                                };
                                Some(Hover {
                                    contents: HoverContents::Scalar(contents),
                                    range: byte_span_to_range(&source, span).ok(),
                                })
                            })
                            .unwrap_or_else(|()| None),
                    )
                },
            )
            .await
        }
        .boxed()
    }

    fn invalid_params(&self) -> Option<Self::Error> {
        None
    }
}

pub fn register(io: &mut IoHandler, thread: &RootedThread) {
    io.add_async_method(request!("textDocument/hover"), HoverCommand(thread.clone()));
}
<commit_msg>Render hover response as markdown when possible<commit_after>use {
    futures::prelude::*,
    jsonrpc_core::IoHandler,
    lsp_types::{Hover, HoverContents, HoverParams, MarkedString},
};

use crate::{completion, rpc::LanguageServerCommand, BoxFuture};

use super::*;

struct HoverCommand(RootedThread);
impl LanguageServerCommand<HoverParams> for HoverCommand {
    type Future = BoxFuture<Self::Output, ServerError<()>>;
    type Output = Option<Hover>;
    type Error = ();
    fn execute(&self, change: HoverParams) -> BoxFuture<Option<Hover>, ServerError<()>> {
        let thread = self.0.clone();
        async move {
            retrieve_expr(
                &thread,
                &change.text_document_position_params.text_document.uri,
                |module| {
                    let expr = module.expr.expr();

                    let source = &module.source;
                    let byte_index = position_to_byte_index(
                        &source,
                        &change.text_document_position_params.position,
                    )?;

                    let db = thread.get_database();
                    let env = db.as_env();
                    let (_, metadata_map) = gluon::check::metadata::metadata(&env, &expr);
                    let opt_metadata =
                        completion::get_metadata(&metadata_map, source.span(), expr, byte_index);
                    let extract = (completion::TypeAt { env: &env }, completion::SpanAt);
                    Ok(
                        completion::completion(extract, source.span(), expr, byte_index)
                            .map(|(typ, span)| {
                                let contents = match opt_metadata.and_then(|m| m.comment.as_ref()) {
                                    Some(comment) => HoverContents::Markup(MarkupContent {
                                        kind: MarkupKind::Markdown,
                                        value: format!("{}\n\n{}", typ, comment.content),
                                    }),
                                    None => {
                                        HoverContents::Scalar(MarkedString::from_language_code(
                                            "gluon".into(),
                                            format!("{}", typ),
                                        ))
                                    }
                                };
                                Some(Hover {
                                    contents,
                                    range: byte_span_to_range(&source, span).ok(),
                                })
                            })
                            .unwrap_or_else(|()| None),
                    )
                },
            )
            .await
        }
        .boxed()
    }

    fn invalid_params(&self) -> Option<Self::Error> {
        None
    }
}

pub fn register(io: &mut IoHandler, thread: &RootedThread) {
    io.add_async_method(request!("textDocument/hover"), HoverCommand(thread.clone()));
}
<|endoftext|>


<commit_before>use futures::{Async, AsyncSink, Future};

use lb::{Connector, Duplex, Src, Dst, WithAddr};
use std::{f32, io};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::Instant;
use tacho::{self, Timing};

struct Pending {
    connect: Box<Future<Item = Dst, Error = io::Error>>,
    start_t: Instant,
}

struct Established {
    dst: Dst,
    start_t: Instant,
}

struct Active {
    duplex: Duplex,
    start_t: Instant,
}

struct Stats {
    failures: tacho::CounterKey,
    successes: tacho::CounterKey,
    connect_latency_us: tacho::StatKey,
    connection_ready_ms: tacho::StatKey,
    connection_active_ms: tacho::StatKey,
    tx_metrics: tacho::Metrics,
    rx_metrics: tacho::Metrics,
}
impl Stats {
    fn new(metrics: tacho::Metrics) -> Stats {
        let tx_metrics = metrics.clone().labeled("direction".into(), "tx".into());
        let rx_metrics = metrics.clone().labeled("direction".into(), "tx".into());
        Stats {
            connect_latency_us: metrics.scope().timing_us("connect_latency_us".into()),
            connection_ready_ms: metrics.scope().timing_ms("connection_ready_ms".into()),
            connection_active_ms: metrics.scope().timing_ms("connection_active_ms".into()),
            failures: metrics.scope().counter("failure_count".into()),
            successes: metrics.scope().counter("success_count".into()),
            tx_metrics: tx_metrics,
            rx_metrics: rx_metrics,
        }
    }
}

/// A single possibly-available load balancing endpoint.
pub struct Endpoint {
    addr: SocketAddr,
    weight: f32,
    retired: bool,

    /// Pending connection attempts.
    pending: VecDeque<Pending>,

    /// Connections that have been established but are not yet in
    /// active use.
    established: VecDeque<Established>,

    /// Active TCP streams. The stream completed
    active: VecDeque<Active>,

    stats: Stats,
}

impl Endpoint {
    pub fn new(a: SocketAddr, w: f32, metrics: tacho::Metrics) -> Endpoint {
        Endpoint {
            addr: a,
            weight: w,
            retired: false,
            pending: VecDeque::new(),
            established: VecDeque::new(),
            active: VecDeque::new(),
            stats: Stats::new(metrics),
        }
    }

    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    pub fn weight(&self) -> f32 {
        self.weight
    }

    pub fn set_weight(&mut self, w: f32) {
        self.weight = w;
    }

    pub fn is_retired(&self) -> bool {
        self.retired
    }

    pub fn retire(&mut self) {
        for _ in 0..self.pending.len() {
            drop(self.pending.pop_front());
        }
        for _ in 0..self.established.len() {
            drop(self.established.pop_front());
        }
        self.retired = true;
    }

    pub fn unretire(&mut self) {
        self.retired = false;
    }

    pub fn conns_pending(&self) -> usize {
        self.pending.len()
    }

    pub fn conns_established(&self) -> usize {
        self.established.len()
    }

    pub fn conns_active(&self) -> usize {
        self.active.len()
    }

    pub fn is_ready(&self) -> bool {
        !self.established.is_empty()
    }

    pub fn is_active(&self) -> bool {
        !self.active.is_empty()
    }

    /// Scores the endpoint.
    ///
    /// Uses the number of active connections, combined with the endpoint's weight, to
    /// produce a load score. A lightly-loaded, heavily-weighted endpoint will receive a
    /// score close to 0.0. An endpoint that cannot currently handle events produces a
    /// score of `f32::INFINITY`.
    ///
    /// TODO: Should this be extracted into a configurable strategy?
    pub fn load(&self) -> f32 {
        if !self.is_ready() {
            // If the endpoint is not ready to serve requests, it should not be
            // considered.
            f32::INFINITY
        } else {
            (1.0 + self.conns_active() as f32) / self.weight
        }
    }

    /// Initiate a new connection
    pub fn init_connection<C: Connector>(&mut self, c: &C) {
        debug!("initiating connection to {}", self.addr);
        self.pending.push_back(Pending {
            start_t: tacho::Timing::start(),
            connect: c.connect(&self.addr),
        });
    }

    /// Checks the state of connections for this endpoint.
    ///
    /// When active streams have been completed, they are removed. When pending
    /// connections have been established, they are stored to be dispatched.
    pub fn poll_connections(&mut self, rec: &mut tacho::Recorder) -> io::Result<()> {
        trace!("{}: {} connections established",
               self.addr,
               self.established.len());
        self.poll_active(rec);
        self.poll_pending(rec);
        Ok(())
    }

    fn poll_active(&mut self, rec: &mut tacho::Recorder) {
        let sz = self.active.len();
        trace!("{}: checking {} active streams", self.addr, sz);
        for i in 0..sz {
            let mut active = self.active.pop_front().unwrap();
            trace!("{}: polling active stream {}/{}: {}",
                   self.addr,
                   i + 1,
                   sz,
                   active.duplex.src_addr);
            match active.duplex.poll() {
                Ok(Async::NotReady) => {
                    trace!("{}: still active from {}",
                           self.addr,
                           active.duplex.src_addr);
                    self.active.push_back(active);
                }
                Ok(Async::Ready(())) => {
                    trace!("{}: completed from {}", self.addr, active.duplex.src_addr);
                    rec.incr(&self.stats.successes, 1);
                    rec.add(&self.stats.connection_active_ms, active.start_t.elapsed_ms());
                    drop(active);
                }
                Err(e) => {
                    info!("{}: failed from {}: {}",
                          self.addr,
                          active.duplex.src_addr,
                          e);
                    rec.incr(&self.stats.failures, 1);
                    rec.add(&self.stats.connection_active_ms,
                            active.start_t.elapsed_ms());
                    drop(active);
                }
            }
        }
    }

    fn poll_pending(&mut self, rec: &mut tacho::Recorder) {
        let sz = self.pending.len();
        trace!("{}: polling {} pending streams", self.addr, sz);
        for _ in 0..sz {
            let mut pending = self.pending.pop_front().unwrap();
            match pending.connect.poll() {
                Ok(Async::NotReady) => {
                    self.pending.push_back(pending);
                }
                Ok(Async::Ready(dst)) => {
                    trace!("{}: connection established", self.addr);
                    rec.add(&self.stats.connect_latency_us, pending.start_t.elapsed_us());
                    self.established.push_back(Established {
                        dst: dst,
                        start_t: tacho::Timing::start(),
                    });
                }
                Err(e) => {
                    info!("{}: cannot establish connection: {}", self.addr, e);
                }
            }
        }
    }

    /// Attempts to begin transmiting from the the `Src` to this endpoint.
    ///
    /// If no connections have been established, the Upstrea is returned in an
    /// `Async::NotReady` so that the caller may try another endpoint.
    pub fn transmit(&mut self,
                    src: Src,
                    buf: Rc<RefCell<Vec<u8>>>,
                    rec: &mut tacho::Recorder)
                    -> AsyncSink<Src> {
        match self.established.pop_front() {
            None => {
                {
                    let Src(ref src) = src;
                    trace!("no connections to {} from {}", self.addr, src.addr());
                }
                AsyncSink::NotReady(src)
            }
            Some(established) => {
                let Src(src) = src;
                let Dst(dst) = established.dst;
                rec.add(&self.stats.connection_ready_ms,
                        established.start_t.elapsed_ms());
                trace!("transmitting to {} from {}", self.addr, src.addr());
                let tx_metrics = self.stats.tx_metrics.clone();
                let rx_metrics = self.stats.rx_metrics.clone();
                self.active.push_front(Active {
                    duplex: Duplex::new(src, dst, buf, tx_metrics, rx_metrics),
                    start_t: tacho::Timing::start(),
                });
                AsyncSink::Ready
            }
        }
    }
}
<commit_msg>Fix typo on rx_metrics direction label. (#31)<commit_after>use futures::{Async, AsyncSink, Future};

use lb::{Connector, Duplex, Src, Dst, WithAddr};
use std::{f32, io};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::Instant;
use tacho::{self, Timing};

struct Pending {
    connect: Box<Future<Item = Dst, Error = io::Error>>,
    start_t: Instant,
}

struct Established {
    dst: Dst,
    start_t: Instant,
}

struct Active {
    duplex: Duplex,
    start_t: Instant,
}

struct Stats {
    failures: tacho::CounterKey,
    successes: tacho::CounterKey,
    connect_latency_us: tacho::StatKey,
    connection_ready_ms: tacho::StatKey,
    connection_active_ms: tacho::StatKey,
    tx_metrics: tacho::Metrics,
    rx_metrics: tacho::Metrics,
}
impl Stats {
    fn new(metrics: tacho::Metrics) -> Stats {
        let tx_metrics = metrics.clone().labeled("direction".into(), "tx".into());
        let rx_metrics = metrics.clone().labeled("direction".into(), "rx".into());
        Stats {
            connect_latency_us: metrics.scope().timing_us("connect_latency_us".into()),
            connection_ready_ms: metrics.scope().timing_ms("connection_ready_ms".into()),
            connection_active_ms: metrics.scope().timing_ms("connection_active_ms".into()),
            failures: metrics.scope().counter("failure_count".into()),
            successes: metrics.scope().counter("success_count".into()),
            tx_metrics: tx_metrics,
            rx_metrics: rx_metrics,
        }
    }
}

/// A single possibly-available load balancing endpoint.
pub struct Endpoint {
    addr: SocketAddr,
    weight: f32,
    retired: bool,

    /// Pending connection attempts.
    pending: VecDeque<Pending>,

    /// Connections that have been established but are not yet in
    /// active use.
    established: VecDeque<Established>,

    /// Active TCP streams. The stream completed
    active: VecDeque<Active>,

    stats: Stats,
}

impl Endpoint {
    pub fn new(a: SocketAddr, w: f32, metrics: tacho::Metrics) -> Endpoint {
        Endpoint {
            addr: a,
            weight: w,
            retired: false,
            pending: VecDeque::new(),
            established: VecDeque::new(),
            active: VecDeque::new(),
            stats: Stats::new(metrics),
        }
    }

    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    pub fn weight(&self) -> f32 {
        self.weight
    }

    pub fn set_weight(&mut self, w: f32) {
        self.weight = w;
    }

    pub fn is_retired(&self) -> bool {
        self.retired
    }

    pub fn retire(&mut self) {
        for _ in 0..self.pending.len() {
            drop(self.pending.pop_front());
        }
        for _ in 0..self.established.len() {
            drop(self.established.pop_front());
        }
        self.retired = true;
    }

    pub fn unretire(&mut self) {
        self.retired = false;
    }

    pub fn conns_pending(&self) -> usize {
        self.pending.len()
    }

    pub fn conns_established(&self) -> usize {
        self.established.len()
    }

    pub fn conns_active(&self) -> usize {
        self.active.len()
    }

    pub fn is_ready(&self) -> bool {
        !self.established.is_empty()
    }

    pub fn is_active(&self) -> bool {
        !self.active.is_empty()
    }

    /// Scores the endpoint.
    ///
    /// Uses the number of active connections, combined with the endpoint's weight, to
    /// produce a load score. A lightly-loaded, heavily-weighted endpoint will receive a
    /// score close to 0.0. An endpoint that cannot currently handle events produces a
    /// score of `f32::INFINITY`.
    ///
    /// TODO: Should this be extracted into a configurable strategy?
    pub fn load(&self) -> f32 {
        if !self.is_ready() {
            // If the endpoint is not ready to serve requests, it should not be
            // considered.
            f32::INFINITY
        } else {
            (1.0 + self.conns_active() as f32) / self.weight
        }
    }

    /// Initiate a new connection
    pub fn init_connection<C: Connector>(&mut self, c: &C) {
        debug!("initiating connection to {}", self.addr);
        self.pending.push_back(Pending {
            start_t: tacho::Timing::start(),
            connect: c.connect(&self.addr),
        });
    }

    /// Checks the state of connections for this endpoint.
    ///
    /// When active streams have been completed, they are removed. When pending
    /// connections have been established, they are stored to be dispatched.
    pub fn poll_connections(&mut self, rec: &mut tacho::Recorder) -> io::Result<()> {
        trace!("{}: {} connections established",
               self.addr,
               self.established.len());
        self.poll_active(rec);
        self.poll_pending(rec);
        Ok(())
    }

    fn poll_active(&mut self, rec: &mut tacho::Recorder) {
        let sz = self.active.len();
        trace!("{}: checking {} active streams", self.addr, sz);
        for i in 0..sz {
            let mut active = self.active.pop_front().unwrap();
            trace!("{}: polling active stream {}/{}: {}",
                   self.addr,
                   i + 1,
                   sz,
                   active.duplex.src_addr);
            match active.duplex.poll() {
                Ok(Async::NotReady) => {
                    trace!("{}: still active from {}",
                           self.addr,
                           active.duplex.src_addr);
                    self.active.push_back(active);
                }
                Ok(Async::Ready(())) => {
                    trace!("{}: completed from {}", self.addr, active.duplex.src_addr);
                    rec.incr(&self.stats.successes, 1);
                    rec.add(&self.stats.connection_active_ms, active.start_t.elapsed_ms());
                    drop(active);
                }
                Err(e) => {
                    info!("{}: failed from {}: {}",
                          self.addr,
                          active.duplex.src_addr,
                          e);
                    rec.incr(&self.stats.failures, 1);
                    rec.add(&self.stats.connection_active_ms,
                            active.start_t.elapsed_ms());
                    drop(active);
                }
            }
        }
    }

    fn poll_pending(&mut self, rec: &mut tacho::Recorder) {
        let sz = self.pending.len();
        trace!("{}: polling {} pending streams", self.addr, sz);
        for _ in 0..sz {
            let mut pending = self.pending.pop_front().unwrap();
            match pending.connect.poll() {
                Ok(Async::NotReady) => {
                    self.pending.push_back(pending);
                }
                Ok(Async::Ready(dst)) => {
                    trace!("{}: connection established", self.addr);
                    rec.add(&self.stats.connect_latency_us, pending.start_t.elapsed_us());
                    self.established.push_back(Established {
                        dst: dst,
                        start_t: tacho::Timing::start(),
                    });
                }
                Err(e) => {
                    info!("{}: cannot establish connection: {}", self.addr, e);
                }
            }
        }
    }

    /// Attempts to begin transmiting from the the `Src` to this endpoint.
    ///
    /// If no connections have been established, the Upstrea is returned in an
    /// `Async::NotReady` so that the caller may try another endpoint.
    pub fn transmit(&mut self,
                    src: Src,
                    buf: Rc<RefCell<Vec<u8>>>,
                    rec: &mut tacho::Recorder)
                    -> AsyncSink<Src> {
        match self.established.pop_front() {
            None => {
                {
                    let Src(ref src) = src;
                    trace!("no connections to {} from {}", self.addr, src.addr());
                }
                AsyncSink::NotReady(src)
            }
            Some(established) => {
                let Src(src) = src;
                let Dst(dst) = established.dst;
                rec.add(&self.stats.connection_ready_ms,
                        established.start_t.elapsed_ms());
                trace!("transmitting to {} from {}", self.addr, src.addr());
                let tx_metrics = self.stats.tx_metrics.clone();
                let rx_metrics = self.stats.rx_metrics.clone();
                self.active.push_front(Active {
                    duplex: Duplex::new(src, dst, buf, tx_metrics, rx_metrics),
                    start_t: tacho::Timing::start(),
                });
                AsyncSink::Ready
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::cell::{Cell, RefCell};
use lexer::{LexTokenIterator, Catcodes, Token, LexerToken, ZeroCopyStreamer};

#[derive(Debug)]
pub struct Lexer<'a> {
    streamer: ZeroCopyStreamer<'a>,
    catcodes: Catcodes,
    // Used by `peek_next` function.
    peeked: RefCell<VecDeque<LexerToken<'a>>>,
    peek_offset: Cell<usize>,
}

impl<'a> LexTokenIterator<'a> for Lexer<'a> {
    fn next(&self) -> Option<LexerToken<'a>> {
        self.reset_peek();

        // Check if we have peeked element before tokenizing the input.
        if self.peeked.borrow().is_empty() {
            Some(self.tokenize_element())
        } else {
            Some(self.peeked.borrow_mut().pop_front().unwrap())
        }
    }

    fn peek_next(&self) -> Option<Token<'a>> {
        // Check if we need to tokenize from a new input or we can use
        // tokenized data.
        if self.peek_offset.get() == self.peeked.borrow().len() {
            self.peek_offset.set(self.peek_offset.get() + 1);
            // Get the newest token.
            let token = self.tokenize_element();
            self.peeked.borrow_mut().push_back(token);

            let peeked = self.peeked.borrow();
            Some(peeked.back().unwrap().elem().clone())
        } else if self.peek_offset.get() < self.peeked.borrow().len() {
            self.peek_offset.set(self.peek_offset.get() + 1);

            let peeked = self.peeked.borrow();
            Some(
                peeked
                    .get(self.peek_offset.get() - 1)
                    .unwrap()
                    .elem()
                    .clone(),
            )
        } else {
            unreachable!();
        }
    }

    fn reset_peek(&self) {
        self.peek_offset.set(0);
    }

    fn set_catcode(&mut self, catcodes: Catcodes) {
        self.catcodes = catcodes;
    }
}

impl<'a> Lexer<'a> {
    pub fn new(input: &'a str) -> Self {
        Lexer {
            streamer: ZeroCopyStreamer::new(input),
            catcodes: Catcodes::default(),
            peeked: RefCell::new(VecDeque::new()),
            peek_offset: Cell::new(0),
        }
    }

    fn tokenize_element(&self) -> LexerToken<'a> {
        let pos = self.streamer.get_pos();

        let elem = match self.streamer.peek_char() {
            Some(v) if self.catcodes.is_begin_group(v) => {
                self.streamer.read_char();
                Token::BeginGroup
            }
            Some(v) if self.catcodes.is_end_group(v) => {
                self.streamer.read_char();
                Token::EndGroup
            }
            Some(v) if self.catcodes.is_math_shift(v) => {
                self.streamer.read_char();
                Token::MathShift
            }
            Some(v) if self.catcodes.is_alignement_tab(v) => {
                self.streamer.read_char();
                Token::AlignementTab
            }
            Some(v) if self.catcodes.is_subscript(v) => {
                self.streamer.read_char();
                Token::SubScript
            }
            Some(v) if self.catcodes.is_superscript(v) => {
                self.streamer.read_char();
                Token::SuperScript
            }
            Some(v) if self.catcodes.is_active(v) => {
                self.streamer.read_char();
                Token::Active
            }
            Some(v) if self.catcodes.is_macro_param(v) => {
                self.streamer.read_char();
                Token::MacroParam
            }

            Some(v) if self.catcodes.is_end_of_line(v) => {
                self.streamer.read_char();
                self.streamer.set_newline();
                Token::LineBreak
            }
            Some(v) if self.catcodes.is_control_sequence(v) => {
                // Consume the `\` char.
                self.streamer.read_char();
                self.elem_control_sequence()
            }
            Some(v) if self.catcodes.is_space(v) => {
                match self.streamer.peek_char() {
                    Some(v) if v.is_alphabetic() => Token::Text(self.text()),
                    _ => {
                        self.streamer.read_char();
                        Token::Space
                    }
                }
            }
            Some(v) if self.catcodes.is_letter(v) => Token::Text(self.text()),
            Some(v) if v.is_numeric() => Token::Number(self.number()),
            Some(v) if self.catcodes.is_comment(v) => {
                Token::Comment(
                    self.streamer
                        .take_while(|x| !self.catcodes.is_end_of_line(x)),
                )
            }
            Some(v) => {
                self.streamer.read_char();
                Token::SpecialChar(v)
            }

            None => Token::EndOfFile,
        };
        LexerToken::new(elem, pos)
    }

    // Match everything that begin by the control sequence character
    // (in most case: `\`).
    fn elem_control_sequence(&self) -> Token<'a> {
        match self.streamer.peek_char() {
            Some(v) if self.catcodes.is_escaped_char(v) => {
                self.streamer.read_char();
                Token::EscapedChar(v)
            }
            Some(v) if self.catcodes.is_other_character(v) => {
                self.streamer.read_char();
                Token::SpecialChar(v)
            }
            Some(v) if self.catcodes.is_letter(v) => {
                Token::Command(self.streamer.take_while(|x| self.catcodes.is_letter(x)))
            }
            _ => unreachable!(),
        }
    }

    // TODO: handle negative number?
    fn number(&self) -> i32 {
        self.streamer
            .take_while(|x| x.is_numeric())
            .parse()
            .unwrap()
    }

    fn text(&self) -> &'a str {
        self.streamer.take_while(|x| {
            !self.catcodes.is_control_sequence(x) && !self.catcodes.is_end_of_line(x) &&
                !self.catcodes.is_escaped_char(x)
        })
    }
}
<commit_msg>change lexing rules to match better to TeX's one<commit_after>use std::collections::VecDeque;
use std::cell::{Cell, RefCell};
use lexer::{LexTokenIterator, Catcodes, Token, LexerToken, ZeroCopyStreamer};

#[derive(Debug)]
pub struct Lexer<'a> {
    streamer: ZeroCopyStreamer<'a>,
    catcodes: Catcodes,
    // Used by `peek_next` function.
    peeked: RefCell<VecDeque<LexerToken<'a>>>,
    peek_offset: Cell<usize>,
}

impl<'a> LexTokenIterator<'a> for Lexer<'a> {
    fn next(&self) -> Option<LexerToken<'a>> {
        self.reset_peek();

        // Check if we have peeked element before tokenizing the input.
        if self.peeked.borrow().is_empty() {
            Some(self.tokenize_element())
        } else {
            Some(self.peeked.borrow_mut().pop_front().unwrap())
        }
    }

    fn peek_next(&self) -> Option<Token<'a>> {
        // Check if we need to tokenize from a new input or we can use
        // tokenized data.
        if self.peek_offset.get() == self.peeked.borrow().len() {
            self.peek_offset.set(self.peek_offset.get() + 1);
            // Get the newest token.
            let token = self.tokenize_element();
            self.peeked.borrow_mut().push_back(token);

            let peeked = self.peeked.borrow();
            Some(peeked.back().unwrap().elem().clone())
        } else if self.peek_offset.get() < self.peeked.borrow().len() {
            self.peek_offset.set(self.peek_offset.get() + 1);

            let peeked = self.peeked.borrow();
            Some(
                peeked
                    .get(self.peek_offset.get() - 1)
                    .unwrap()
                    .elem()
                    .clone(),
            )
        } else {
            unreachable!();
        }
    }

    fn reset_peek(&self) {
        self.peek_offset.set(0);
    }

    fn set_catcode(&mut self, catcodes: Catcodes) {
        self.catcodes = catcodes;
    }
}

impl<'a> Lexer<'a> {
    pub fn new(input: &'a str) -> Self {
        Lexer {
            streamer: ZeroCopyStreamer::new(input),
            catcodes: Catcodes::default(),
            peeked: RefCell::new(VecDeque::new()),
            peek_offset: Cell::new(0),
        }
    }

    fn tokenize_element(&self) -> LexerToken<'a> {
        let pos = self.streamer.get_pos();

        let elem = match self.streamer.peek_char() {
            Some(v) if self.catcodes.is_begin_group(v) => {
                self.streamer.read_char();
                Token::BeginGroup
            }
            Some(v) if self.catcodes.is_end_group(v) => {
                self.streamer.read_char();
                Token::EndGroup
            }
            Some(v) if self.catcodes.is_math_shift(v) => {
                self.streamer.read_char();
                Token::MathShift
            }
            Some(v) if self.catcodes.is_alignement_tab(v) => {
                self.streamer.read_char();
                Token::AlignementTab
            }
            Some(v) if self.catcodes.is_subscript(v) => {
                self.streamer.read_char();
                Token::SubScript
            }
            Some(v) if self.catcodes.is_superscript(v) => {
                self.streamer.read_char();
                Token::SuperScript
            }
            Some(v) if self.catcodes.is_active(v) => {
                self.streamer.read_char();
                Token::Active
            }
            Some(v) if self.catcodes.is_macro_param(v) => {
                self.streamer.read_char();
                Token::MacroParam
            }

            Some(v) if self.catcodes.is_end_of_line(v) => {
                self.streamer.read_char();
                self.streamer.set_newline();
                Token::LineBreak
            }
            Some(v) if self.catcodes.is_control_sequence(v) => {
                // Consume the `\` char.
                self.streamer.read_char();
                self.elem_control_sequence()
            }
            Some(v) if self.catcodes.is_space(v) => {
                match self.streamer.peek_char() {
                    Some(v) if v.is_alphabetic() => Token::Text(self.text()),
                    _ => {
                        self.streamer.read_char();
                        Token::Space
                    }
                }
            }
            Some(v) if self.catcodes.is_letter(v) => Token::Text(self.text()),
            Some(v) if v.is_numeric() => Token::Number(self.number()),
            Some(v) if self.catcodes.is_comment(v) => {
                Token::Comment(
                    self.streamer
                        .take_while(|x| !self.catcodes.is_end_of_line(x)),
                )
            }
            Some(v) => {
                self.streamer.read_char();
                Token::SpecialChar(v)
            }

            None => Token::EndOfFile,
        };
        LexerToken::new(elem, pos)
    }

    // Match everything that begin by the control sequence character
    // (in most case: `\`).
    fn elem_control_sequence(&self) -> Token<'a> {
        match self.streamer.peek_char() {
            Some(v) if self.catcodes.is_escaped_char(v) => {
                self.streamer.read_char();
                Token::EscapedChar(v)
            }
            Some(v) if self.catcodes.is_other_character(v) => {
                self.streamer.read_char();
                Token::SpecialChar(v)
            }
            Some(v) if self.catcodes.is_letter(v) => {
                Token::Command(self.streamer.take_while(|x| x.is_alphabetic()))
            }
            _ => unreachable!(),
        }
    }

    // TODO: handle negative number?
    fn number(&self) -> i32 {
        self.streamer
            .take_while(|x| x.is_numeric())
            .parse()
            .unwrap()
    }

    fn text(&self) -> &'a str {
        self.streamer
            .take_while(|x| self.catcodes.is_letter(x) || self.catcodes.is_space(x))
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use clap::{Arg, App, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .subcommand(SubCommand::with_name("status")
                   .about("Show the current status. Remind of not-yet-done habits, shows upcoming. Default if no command is passed. Also alias for 'today --future'")
                   .version("0.1")
                   )

        .subcommand(SubCommand::with_name("create")
                   .about("Create a new Habit")
                   .version("0.1")
                   .arg(Arg::with_name("create-name")
                        .index(1)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("Name of the new habit"))
                   .arg(Arg::with_name("create-date")
                        .index(2)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("DATE")
                        .help("Date when the first instance should be done"))
                   .arg(Arg::with_name("create-date-recurr-spec")
                        .index(3)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("RECURRENCE-SPEC")
                        .help("Spec how the habit should recur (eg: 'weekly', 'monthly', '5days', '12hours')"))
                   .arg(Arg::with_name("create-comment")
                        .index(4)
                        .multiple(true)
                        .required(true)
                        .takes_value(true)
                        .value_name("COMMENT")
                        .help("Comment for the habit"))
                   )

        .subcommand(SubCommand::with_name("delete")
                   .about("Delete a Habit (and its instances)")
                   .version("0.1")
                   .arg(Arg::with_name("delete-instances")
                        .long("instances")
                        .short("I")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("Delete instances as well"))
                   .arg(Arg::with_name("delete-yes")
                        .long("yes")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("Do not ask for confirmation"))
                   .arg(Arg::with_name("delete-name")
                        .index(1)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("Name of the habit"))
                   )

        .subcommand(SubCommand::with_name("list")
                   .about("List Habits")
                   .version("0.1")
                   .arg(Arg::with_name("list-long")
                        .long("long")
                        .short("l")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("List with details (how many instances)"))
                   )

        .subcommand(SubCommand::with_name("show")
                   .about("Show a Habit and its instances")
                   .version("0.1")
                   .arg(Arg::with_name("show-name")
                        .index(1)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("Name of the habit to show"))
                   )

        .subcommand(SubCommand::with_name("today")
                   .about("List habits which are due today (default command)")
                   .version("0.1")
                   .arg(Arg::with_name("today-show-future")
                        .long("future")
                        .short("f")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("Also show the future"))
                   .arg(Arg::with_name("today-show-next-n")
                        .long("show")
                        .short("s")
                        .multiple(false)
                        .required(false)
                        .takes_value(true)
                        .value_name("N")
                        .help("Show the N next relevant entries. Default = 5"))
                   )

        .subcommand(SubCommand::with_name("done")
                    .about("Mark one or more habits (which are pending) as done")
                    .version("0.1")
                    .arg(Arg::with_name("done-name")
                        .index(1)
                        .multiple(true)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("The names of the habits to be marked as done."))
                    )
}
<commit_msg>Change UI. Positional args are not possible here<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use clap::{Arg, App, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .subcommand(SubCommand::with_name("status")
                   .about("Show the current status. Remind of not-yet-done habits, shows upcoming. Default if no command is passed. Also alias for 'today --future'")
                   .version("0.1")
                   )

        .subcommand(SubCommand::with_name("create")
                   .about("Create a new Habit")
                   .version("0.1")
                   .arg(Arg::with_name("create-name")
                        .long("name")
                        .short("n")
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("Name of the new habit"))
                   .arg(Arg::with_name("create-date")
                        .long("date")
                        .short("d")
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("DATE")
                        .help("Date when the first instance should be done"))
                   .arg(Arg::with_name("create-date-recurr-spec")
                        .long("recurr")
                        .short("r")
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("RECURRENCE-SPEC")
                        .help("Spec how the habit should recur (eg: 'weekly', 'monthly', '5days', '12hours')"))
                   .arg(Arg::with_name("create-until")
                        .long("until")
                        .short("u")
                        .multiple(false)
                        .required(false)
                        .takes_value(true)
                        .value_name("UNTIL")
                        .help("Until-Date for the habit"))

                   .arg(Arg::with_name("create-comment")
                        .long("comment")
                        .short("c")
                        .multiple(true)
                        .required(true)
                        .takes_value(true)
                        .value_name("COMMENT")
                        .help("Comment for the habit"))
                   )

        .subcommand(SubCommand::with_name("delete")
                   .about("Delete a Habit (and its instances)")
                   .version("0.1")
                   .arg(Arg::with_name("delete-instances")
                        .long("instances")
                        .short("I")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("Delete instances as well"))
                   .arg(Arg::with_name("delete-yes")
                        .long("yes")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("Do not ask for confirmation"))
                   .arg(Arg::with_name("delete-name")
                        .index(1)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("Name of the habit"))
                   )

        .subcommand(SubCommand::with_name("list")
                   .about("List Habits")
                   .version("0.1")
                   .arg(Arg::with_name("list-long")
                        .long("long")
                        .short("l")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("List with details (how many instances)"))
                   )

        .subcommand(SubCommand::with_name("show")
                   .about("Show a Habit and its instances")
                   .version("0.1")
                   .arg(Arg::with_name("show-name")
                        .index(1)
                        .multiple(false)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("Name of the habit to show"))
                   )

        .subcommand(SubCommand::with_name("today")
                   .about("List habits which are due today (default command)")
                   .version("0.1")
                   .arg(Arg::with_name("today-show-future")
                        .long("future")
                        .short("f")
                        .multiple(false)
                        .required(false)
                        .takes_value(false)
                        .help("Also show the future"))
                   .arg(Arg::with_name("today-show-next-n")
                        .long("show")
                        .short("s")
                        .multiple(false)
                        .required(false)
                        .takes_value(true)
                        .value_name("N")
                        .help("Show the N next relevant entries. Default = 5"))
                   )

        .subcommand(SubCommand::with_name("done")
                    .about("Mark one or more habits (which are pending) as done")
                    .version("0.1")
                    .arg(Arg::with_name("done-name")
                        .index(1)
                        .multiple(true)
                        .required(true)
                        .takes_value(true)
                        .value_name("NAME")
                        .help("The names of the habits to be marked as done."))
                    )
}
<|endoftext|>


<commit_before>/*!
`SHA-256`.

There has been considerable degradation of public confidence in the
security conjectures for many hash functions, including `SHA-256`.
However, for the moment, there do not appear to be alternatives that
inspire satisfactory levels of confidence. One can hope that NIST's
SHA-3 competition will improve the situation.
*/
use std::libc::{c_ulonglong, c_int};
use std::vec::raw::{to_mut_ptr, to_ptr};

#[link(name = "sodium")]
#[link_args = "-lsodium"]
extern {
    fn crypto_hash_sha256(h: *mut u8,
                          m: *u8,
                          mlen: c_ulonglong) -> c_int;
}

pub static HASHBYTES: uint = 32;
pub static BLOCKBYTES: uint = 64;

/**
 * Digest-structure
 */
pub struct Digest([u8, ..HASHBYTES]);

/**
 * `hash` hashes a message `m`. It returns a hash `h`.
 */
#[fixed_stack_segment]
pub fn hash(m: &[u8]) -> ~Digest {
    unsafe {
        let mut h = ~Digest([0, ..HASHBYTES]);
        crypto_hash_sha256(to_mut_ptr(**h), to_ptr(m), m.len() as c_ulonglong);
        h
    }
}
<commit_msg>added simple test vectors for sha256<commit_after>/*!
`SHA-256`.

There has been considerable degradation of public confidence in the
security conjectures for many hash functions, including `SHA-256`.
However, for the moment, there do not appear to be alternatives that
inspire satisfactory levels of confidence. One can hope that NIST's
SHA-3 competition will improve the situation.
*/
use std::libc::{c_ulonglong, c_int};
use std::vec::raw::{to_mut_ptr, to_ptr};

#[link(name = "sodium")]
#[link_args = "-lsodium"]
extern {
    fn crypto_hash_sha256(h: *mut u8,
                          m: *u8,
                          mlen: c_ulonglong) -> c_int;
}

pub static HASHBYTES: uint = 32;
pub static BLOCKBYTES: uint = 64;

/**
 * Digest-structure
 */
pub struct Digest([u8, ..HASHBYTES]);

/**
 * `hash` hashes a message `m`. It returns a hash `h`.
 */
#[fixed_stack_segment]
pub fn hash(m: &[u8]) -> ~Digest {
    unsafe {
        let mut h = ~Digest([0, ..HASHBYTES]);
        crypto_hash_sha256(to_mut_ptr(**h), to_ptr(m), m.len() as c_ulonglong);
        h
    }
}

#[test]
fn test_vector_1() {
    let x = [];
    let h_expected = ~Digest([0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
                              0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
                              0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
                              0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55]);
    let h = hash(x);
    assert!((**h) == (**h_expected));
}

#[test]
fn test_vector_2() {
    let x = [0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63,
             0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20,
             0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70,
             0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74,
             0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20,
             0x64, 0x6f, 0x67];
    let h_expected = ~Digest([0xd7, 0xa8, 0xfb, 0xb3, 0x07, 0xd7, 0x80, 0x94,
                              0x69, 0xca, 0x9a, 0xbc, 0xb0, 0x08, 0x2e, 0x4f,
                              0x8d, 0x56, 0x51, 0xe4, 0x6d, 0x3c, 0xdb, 0x76,
                              0x2d, 0x02, 0xd0, 0xbf, 0x37, 0xc9, 0xe5, 0x92]);
    let h = hash(x);
    assert!((**h) == (**h_expected));
}
<|endoftext|>