<commit_before>use ammonia::{Builder, UrlRelative};
use comrak;
use htmlescape::encode_minimal;
use std::borrow::Cow;
use url::Url;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
struct MarkdownRenderer<'a> {
    html_sanitizer: Builder<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    ///
    /// Per `readme_to_html`, `base_url` is the base URL prepended to any
    /// relative links in the input document.  See that function for more detail.
    fn new(base_url: Option<&'a str>) -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "id", "target"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let allowed_classes = [
            (
                "code",
                [
                    "language-bash",
                    "language-clike",
                    "language-glsl",
                    "language-go",
                    "language-ini",
                    "language-javascript",
                    "language-json",
                    "language-markup",
                    "language-protobuf",
                    "language-ruby",
                    "language-rust",
                    "language-scss",
                    "language-sql",
                    "yaml",
                ].iter()
                    .cloned()
                    .collect(),
            ),
        ].iter()
            .cloned()
            .collect();

        let sanitizer_base_url = base_url.map(|s| s.to_string());

        // Constrain the type of the closures given to the HTML sanitizer.
        fn constrain_closure<F>(f: F) -> F
        where
            F: for<'a> Fn(&'a str) -> Option<Cow<'a, str>> + Send + Sync,
        {
            f
        }

        let unrelative_url_sanitizer = constrain_closure(|url| {
            // We have no base URL; allow fragment links only.
            if url.starts_with('#') {
                return Some(Cow::Borrowed(url));
            }

            None
        });

        let relative_url_sanitizer = constrain_closure(move |url| {
            // sanitizer_base_url is Some(String); use it to fix the relative URL.
            if url.starts_with('#') {
                return Some(Cow::Borrowed(url));
            }

            let mut new_url = sanitizer_base_url.clone().unwrap();
            if !new_url.ends_with('/') {
                new_url.push('/');
            }
            if new_url.ends_with(".git/") {
                let offset = new_url.len() - 5;
                new_url.drain(offset..offset + 4);
            }
            new_url += "blob/master";
            if !url.starts_with('/') {
                new_url.push('/');
            }
            new_url += url;
            Some(Cow::Owned(new_url))
        });

        let use_relative = if let Some(base_url) = base_url {
            if let Ok(url) = Url::parse(base_url) {
                url.host_str() == Some("github.com") || url.host_str() == Some("gitlab.com")
                    || url.host_str() == Some("bitbucket.org")
            } else {
                false
            }
        } else {
            false
        };

        let mut html_sanitizer = Builder::new();
        html_sanitizer
            .link_rel(Some("nofollow noopener noreferrer"))
            .tags(tags)
            .tag_attributes(tag_attributes)
            .allowed_classes(allowed_classes)
            .url_relative(if use_relative {
                UrlRelative::Custom(Box::new(relative_url_sanitizer))
            } else {
                UrlRelative::Custom(Box::new(unrelative_url_sanitizer))
            })
            .id_prefix(Some("user-content-"));

        MarkdownRenderer { html_sanitizer }
    }

    /// Renders the given markdown to HTML using the current settings.
    fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ext_header_ids: Some("user-content-".to_string()),
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered).to_string())
    }
}

/// Renders Markdown text to sanitized HTML with a given `base_url`.
/// See `readme_to_html` for the interpretation of `base_url`.
fn markdown_to_html(text: &str, base_url: Option<&str>) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new(base_url);
    renderer.to_html(text)
}

/// Any readme with a filename ending in one of these extensions will be rendered as Markdown.
/// Note we also render a readme as Markdown if _no_ extension is on the filename.
static MARKDOWN_EXTENSIONS: [&'static str; 7] = [
    ".md",
    ".markdown",
    ".mdown",
    ".mdwn",
    ".mkd",
    ".mkdn",
    ".mkdown",
];

/// Renders a readme to sanitized HTML.  An appropriate rendering method is chosen depending
/// on the extension of the supplied `filename`.
///
/// The returned text will not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// The `base_url` parameter will be used as the base for any relative links found in the
/// Markdown, as long as its host part is github.com, gitlab.com, or bitbucket.org.  The
/// supplied URL will be used as a directory base whether or not the relative link is
/// prefixed with '/'.  If `None` is passed, relative links will be omitted.
///
/// # Examples
///
/// ```
/// use render::render_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = readme_to_html(text, "README.md", None)?;
/// ```
pub fn readme_to_html(text: &str, filename: &str, base_url: Option<&str>) -> CargoResult<String> {
    let filename = filename.to_lowercase();

    if !filename.contains('.') || MARKDOWN_EXTENSIONS.iter().any(|e| filename.ends_with(e)) {
        return markdown_to_html(text, base_url);
    }

    Ok(encode_minimal(text).replace("\n", "
\n"))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknown_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
foo_readme
\n
alert(\'Hello World\')
\n");
    }

    #[test]
    fn text_with_inline_javascript() {
        let text =
            r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme\\n\\nCrate page
\n"
        );
    }

    // See https://github.com/kivikakk/comrak/issues/37. This panic happened
    // in comrak 0.1.8 but was fixed in 0.1.9.
    #[test]
    fn text_with_fancy_single_quotes() {
        let text = r#"wb’"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
wb’
\n");
    }

    #[test]
    fn code_block_with_syntax_highlighting() {
        let code_block = r#"```rust \
                            println!("Hello World"); \
                           ```"#;
        let result = markdown_to_html(code_block, None).unwrap();
        assert!(result.contains(""));
    }

    #[test]
    fn text_with_forbidden_class_attribute() {
        let text = "
Hello World!
";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
Hello World!
\n");
    }

    #[test]
    fn relative_links() {
        let absolute = "[hi](/hi)";
        let relative = "[there](there)";

        for host in &["github.com", "gitlab.com", "bitbucket.org"] {
            for (&extra_slash, &dot_git) in [true, false].iter().zip(&[true, false]) {
                let url = format!(
                    "https://{}/rust-lang/test{}{}",
                    host,
                    if dot_git { ".git" } else { "" },
                    if extra_slash { "/" } else { "" },
                );

                let result = markdown_to_html(absolute, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "
hi
\n",
                        host
                    )
                );

                let result = markdown_to_html(relative, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "
there
\n",
                        host
                    )
                );
            }
        }

        let result = markdown_to_html(absolute, Some("https://google.com/")).unwrap();
        assert_eq!(
            result,
            "
hi
\n"
        );
    }

    #[test]
    fn absolute_links_dont_get_resolved() {
        let readme_text =
            "[![Crates.io](https://img.shields.io/crates/v/clap.svg)](https://crates.io/crates/clap)";
        let repository = "https://github.com/kbknapp/clap-rs/";
        let result = markdown_to_html(readme_text, Some(&repository)).unwrap();

        assert_eq!(
            result,
            "

\n"
        );
    }

    #[test]
    fn readme_to_html_renders_markdown() {
        for f in &["README", "readme.md", "README.MARKDOWN", "whatever.mkd"] {
            assert_eq!(
                readme_to_html("*lobster*", f, None).unwrap(),
                "
lobster
\n"
            );
        }
    }

    #[test]
    fn readme_to_html_renders_other_things() {
        for f in &["readme.exe", "readem.org", "blah.adoc"] {
            assert_eq!(
                readme_to_html("\n\nis my friend\n", f, None).unwrap(),
                "<script>lobster</script>
\n
\nis my friend
\n"
            );
        }
    }

    #[test]
    fn header_has_tags() {
        let text = "# My crate\n\nHello, world!\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
My crate
\n
Hello, world!
\n"
        );
    }

    #[test]
    fn manual_anchor_is_sanitized() {
        let text =
            "
My crate
\n
Hello, world!
\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
My crate
\n
Hello, world!
\n"
        );
    }
}
<commit_msg>Use /raw/ rather than /blob/ URLs for images<commit_after>use ammonia::{Builder, UrlRelative};
use comrak;
use htmlescape::encode_minimal;
use std::borrow::Cow;
use std::path::Path;
use url::Url;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
struct MarkdownRenderer<'a> {
    html_sanitizer: Builder<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    ///
    /// Per `readme_to_html`, `base_url` is the base URL prepended to any
    /// relative links in the input document.  See that function for more detail.
    fn new(base_url: Option<&'a str>) -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "id", "target"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let allowed_classes = [
            (
                "code",
                [
                    "language-bash",
                    "language-clike",
                    "language-glsl",
                    "language-go",
                    "language-ini",
                    "language-javascript",
                    "language-json",
                    "language-markup",
                    "language-protobuf",
                    "language-ruby",
                    "language-rust",
                    "language-scss",
                    "language-sql",
                    "yaml",
                ].iter()
                    .cloned()
                    .collect(),
            ),
        ].iter()
            .cloned()
            .collect();

        let sanitizer_base_url = base_url.map(|s| s.to_string());

        // Constrain the type of the closures given to the HTML sanitizer.
        fn constrain_closure<F>(f: F) -> F
        where
            F: for<'a> Fn(&'a str) -> Option<Cow<'a, str>> + Send + Sync,
        {
            f
        }

        let unrelative_url_sanitizer = constrain_closure(|url| {
            // We have no base URL; allow fragment links only.
            if url.starts_with('#') {
                return Some(Cow::Borrowed(url));
            }

            None
        });

        fn is_media_url(url: &str) -> bool {
            Path::new(url)
                .extension()
                .and_then(|e| e.to_str())
                .map_or(false, |e| match e {
                    "png" | "svg" | "jpg" | "jpeg" | "gif" | "mp4" | "webm" | "ogg" => true,
                    _ => false,
                })
        }

        let relative_url_sanitizer = constrain_closure(move |url| {
            // sanitizer_base_url is Some(String); use it to fix the relative URL.
            if url.starts_with('#') {
                return Some(Cow::Borrowed(url));
            }

            let mut new_url = sanitizer_base_url.clone().unwrap();
            if !new_url.ends_with('/') {
                new_url.push('/');
            }
            if new_url.ends_with(".git/") {
                let offset = new_url.len() - 5;
                new_url.drain(offset..offset + 4);
            }
            // Assumes GitHub's URL scheme. GitHub renders text and markdown
            // better in the "blob" view, but images need to be served raw.
            new_url += if is_media_url(url) {
                "raw/master"
            } else {
                "blob/master"
            };
            if !url.starts_with('/') {
                new_url.push('/');
            }
            new_url += url;
            Some(Cow::Owned(new_url))
        });

        let use_relative = if let Some(base_url) = base_url {
            if let Ok(url) = Url::parse(base_url) {
                url.host_str() == Some("github.com") || url.host_str() == Some("gitlab.com")
                    || url.host_str() == Some("bitbucket.org")
            } else {
                false
            }
        } else {
            false
        };

        let mut html_sanitizer = Builder::new();
        html_sanitizer
            .link_rel(Some("nofollow noopener noreferrer"))
            .tags(tags)
            .tag_attributes(tag_attributes)
            .allowed_classes(allowed_classes)
            .url_relative(if use_relative {
                UrlRelative::Custom(Box::new(relative_url_sanitizer))
            } else {
                UrlRelative::Custom(Box::new(unrelative_url_sanitizer))
            })
            .id_prefix(Some("user-content-"));

        MarkdownRenderer { html_sanitizer }
    }

    /// Renders the given markdown to HTML using the current settings.
    fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ext_header_ids: Some("user-content-".to_string()),
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered).to_string())
    }
}

/// Renders Markdown text to sanitized HTML with a given `base_url`.
/// See `readme_to_html` for the interpretation of `base_url`.
fn markdown_to_html(text: &str, base_url: Option<&str>) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new(base_url);
    renderer.to_html(text)
}

/// Any readme with a filename ending in one of these extensions will be rendered as Markdown.
/// Note we also render a readme as Markdown if _no_ extension is on the filename.
static MARKDOWN_EXTENSIONS: [&'static str; 7] = [
    ".md",
    ".markdown",
    ".mdown",
    ".mdwn",
    ".mkd",
    ".mkdn",
    ".mkdown",
];

/// Renders a readme to sanitized HTML.  An appropriate rendering method is chosen depending
/// on the extension of the supplied `filename`.
///
/// The returned text will not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// The `base_url` parameter will be used as the base for any relative links found in the
/// Markdown, as long as its host part is github.com, gitlab.com, or bitbucket.org.  The
/// supplied URL will be used as a directory base whether or not the relative link is
/// prefixed with '/'.  If `None` is passed, relative links will be omitted.
///
/// # Examples
///
/// ```
/// use render::render_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = readme_to_html(text, "README.md", None)?;
/// ```
pub fn readme_to_html(text: &str, filename: &str, base_url: Option<&str>) -> CargoResult<String> {
    let filename = filename.to_lowercase();

    if !filename.contains('.') || MARKDOWN_EXTENSIONS.iter().any(|e| filename.ends_with(e)) {
        return markdown_to_html(text, base_url);
    }

    Ok(encode_minimal(text).replace("\n", "
\n"))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknown_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
foo_readme
\n
alert(\'Hello World\')
\n");
    }

    #[test]
    fn text_with_inline_javascript() {
        let text =
            r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme\\n\\nCrate page
\n"
        );
    }

    // See https://github.com/kivikakk/comrak/issues/37. This panic happened
    // in comrak 0.1.8 but was fixed in 0.1.9.
    #[test]
    fn text_with_fancy_single_quotes() {
        let text = r#"wb’"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
wb’
\n");
    }

    #[test]
    fn code_block_with_syntax_highlighting() {
        let code_block = r#"```rust \
                            println!("Hello World"); \
                           ```"#;
        let result = markdown_to_html(code_block, None).unwrap();
        assert!(result.contains(""));
    }

    #[test]
    fn text_with_forbidden_class_attribute() {
        let text = "
Hello World!
";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
Hello World!
\n");
    }

    #[test]
    fn relative_links() {
        let absolute = "[hi](/hi)";
        let relative = "[there](there)";
        let image = "![alt](img.png)";

        for host in &["github.com", "gitlab.com", "bitbucket.org"] {
            for (&extra_slash, &dot_git) in [true, false].iter().zip(&[true, false]) {
                let url = format!(
                    "https://{}/rust-lang/test{}{}",
                    host,
                    if dot_git { ".git" } else { "" },
                    if extra_slash { "/" } else { "" },
                );

                let result = markdown_to_html(absolute, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "
hi
\n",
                        host
                    )
                );

                let result = markdown_to_html(relative, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "
there
\n",
                        host
                    )
                );

                let result = markdown_to_html(image, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "

\n",
                        host
                    )
                );
            }
        }

        let result = markdown_to_html(absolute, Some("https://google.com/")).unwrap();
        assert_eq!(
            result,
            "
hi
\n"
        );
    }

    #[test]
    fn absolute_links_dont_get_resolved() {
        let readme_text =
            "[![Crates.io](https://img.shields.io/crates/v/clap.svg)](https://crates.io/crates/clap)";
        let repository = "https://github.com/kbknapp/clap-rs/";
        let result = markdown_to_html(readme_text, Some(&repository)).unwrap();

        assert_eq!(
            result,
            "

\n"
        );
    }

    #[test]
    fn readme_to_html_renders_markdown() {
        for f in &["README", "readme.md", "README.MARKDOWN", "whatever.mkd"] {
            assert_eq!(
                readme_to_html("*lobster*", f, None).unwrap(),
                "
lobster
\n"
            );
        }
    }

    #[test]
    fn readme_to_html_renders_other_things() {
        for f in &["readme.exe", "readem.org", "blah.adoc"] {
            assert_eq!(
                readme_to_html("\n\nis my friend\n", f, None).unwrap(),
                "<script>lobster</script>
\n
\nis my friend
\n"
            );
        }
    }

    #[test]
    fn header_has_tags() {
        let text = "# My crate\n\nHello, world!\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
My crate
\n
Hello, world!
\n"
        );
    }

    #[test]
    fn manual_anchor_is_sanitized() {
        let text =
            "
My crate
\n
Hello, world!
\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
My crate
\n
Hello, world!
\n"
        );
    }
}
<|endoftext|>


<commit_before>extern crate termion;

use termion::raw::*;
use termion::clear;
use termion::color;
use termion::input::MouseTerminal;

use actor::*;
use floor::*;
use world::*;
use primitive::*;

use std::io::{Write, stdout};
use std::sync::*;
use std::thread;
use std::time::Duration;

fn render_floor<W : Write>(screen : &mut W, floor: &Floor) {
    for row in &floor.tiles {
        let mut line = String::new();
        for tile in row {
            if let Some(ref wall) = tile.wall {
                line.push_str(wall);
            } else {
                line.push_str(" "); // U-2027
                //line.push_str("‧"); // U-2027
            }
        }
        write!(screen, "{}\n\r", line).unwrap(); // U-2502
    }
}

fn goto_cursor_coord(coord : &Coord) -> termion::cursor::Goto {
    // Coordinate translation naively assumes floor is being rendered at 1,1
    termion::cursor::Goto(coord.col+1, coord.row+1)
}

pub fn render_loop(world_mutex : Arc<Mutex<World>>, stop : Arc<Mutex<bool>>, dirty_coord_rx : mpsc::Receiver<Coord>) {
    let mut screen = MouseTerminal::from(stdout().into_raw_mode().unwrap());
    // Hide the cursor, clear the screen
    write!(screen, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();

    {
        write!(screen, "{}", termion::cursor::Goto(1, 1)).unwrap();
        let world = world_mutex.lock().unwrap();
        render_floor(&mut screen, &world.floor);
    }

    // Render Loop
    loop {
        // Time to stop?
        {
            let stop = stop.lock().unwrap();
            if *stop {
                break;
            }
        }

        let world = world_mutex.lock().unwrap();

        // Redraw any dirty world coordinates
        while let Ok(coord) = dirty_coord_rx.try_recv() {
            write!(screen, "{}{}", goto_cursor_coord(&coord), world.floor.get_symbol(&coord)).unwrap();
        }

        // Render Player
        write!(screen, "{}", goto_cursor_coord(&world.player.coord())).unwrap();
        write!(screen, "{}", &world.player.symbol()).unwrap();

        // Render Monsters
        for monster in &world.monsters {
            write!(screen, "{}", goto_cursor_coord(monster.coord())).unwrap();
            write!(screen, "{}", monster.symbol()).unwrap();
        }

        // Bottom text
        write!(screen, "{}", termion::cursor::Goto(1, (world.floor.rows+1) as u16)).unwrap();
        write!(screen, "{}\n\r\n\r", world.floor.name).unwrap(); // Dungeon Name
        for msg in &world.messages {
            write!(screen, "{}{}", color::Fg(color::LightWhite), msg).unwrap();
            write!(screen, "{}{}\n\r", color::Fg(color::Reset), clear::UntilNewline).unwrap();
        }

        screen.flush().unwrap();

        // Don't render too hot.
        thread::sleep(Duration::from_millis(50));
    }

    // Nice cleanup: Move cursor below the world, so we can see how we finished
    {
        let world = world_mutex.lock().unwrap();
        write!(screen, "{}", goto_cursor_coord(&Coord::at(0, (world.floor.rows+7) as u16))).unwrap();
    }
    print!("{}", termion::cursor::Show);
    screen.flush().unwrap();
}

<commit_msg>simplify<commit_after>extern crate termion;

use termion::raw::*;
use termion::clear;
use termion::color;
use termion::input::MouseTerminal;

use actor::*;
use floor::*;
use world::*;
use primitive::*;

use std::io::{Write, stdout};
use std::sync::*;
use std::thread;
use std::time::Duration;

fn render_floor<W : Write>(screen : &mut W, floor: &Floor) {
    for row in &floor.tiles {
        let mut line = String::new();
        for tile in row {
            if let Some(ref wall) = tile.wall {
                line.push_str(wall);
            } else {
                line.push_str(" "); // U-2027
                //line.push_str("‧"); // U-2027
            }
        }
        write!(screen, "{}\n\r", line).unwrap(); // U-2502
    }
}

fn goto_cursor_coord(coord : &Coord) -> termion::cursor::Goto {
    // Coordinate translation naively assumes floor is being rendered at 1,1
    termion::cursor::Goto(coord.col+1, coord.row+1)
}

pub fn render_loop(world_mutex : Arc<Mutex<World>>, stop : Arc<Mutex<bool>>, dirty_coord_rx : mpsc::Receiver<Coord>) {
    let mut screen = MouseTerminal::from(stdout().into_raw_mode().unwrap());
    // Hide the cursor, clear the screen
    write!(screen, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();

    {
        write!(screen, "{}", termion::cursor::Goto(1, 1)).unwrap();
        let world = world_mutex.lock().unwrap();
        render_floor(&mut screen, &world.floor);
    }

    // Render Loop
    loop {
        // Time to stop?
        {
            let stop = stop.lock().unwrap();
            if *stop {
                break;
            }
        }

        let world = world_mutex.lock().unwrap();

        // Redraw any dirty world coordinates
        while let Ok(coord) = dirty_coord_rx.try_recv() {
            write!(screen, "{}{}", goto_cursor_coord(&coord), world.floor.get_symbol(&coord)).unwrap();
        }

        // Render Player
        write!(screen, "{}", goto_cursor_coord(&world.player.coord())).unwrap();
        write!(screen, "{}", &world.player.symbol()).unwrap();

        // Render Monsters
        for monster in &world.monsters {
            write!(screen, "{}", goto_cursor_coord(monster.coord())).unwrap();
            write!(screen, "{}", monster.symbol()).unwrap();
        }

        // Bottom text
        write!(screen, "{}", termion::cursor::Goto(1, (world.floor.rows+1) as u16)).unwrap();
        write!(screen, "{}\n\r\n\r", world.floor.name).unwrap(); // Dungeon Name
        for msg in &world.messages {
            write!(screen, "{}{}", color::Fg(color::LightWhite), msg).unwrap();
            write!(screen, "{}{}\n\r", color::Fg(color::Reset), clear::UntilNewline).unwrap();
        }

        screen.flush().unwrap();

        // Don't render too hot.
        thread::sleep(Duration::from_millis(50));
    }

    // Nice cleanup: Move cursor below the world, so we can see how we finished
    {
        let world = world_mutex.lock().unwrap();
        write!(screen, "{}", goto_cursor_coord(&Coord { col: 0, row: (world.floor.rows+7) as u16})).unwrap();
    }
    print!("{}", termion::cursor::Show);
    screen.flush().unwrap();
}

<|endoftext|>


<commit_before>extern crate fuse;
extern crate time;
extern crate libc;
extern crate serialize;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (i, key) in self.tree.keys().enumerate() {
                    reply.add(1, i as u64, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let data = json::from_str("{\"foo\": \"bar\", \"answer\": 42}").unwrap();
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem { tree: tree.clone() };
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(fs, &mountpoint, &[]);
}
<commit_msg>Fixed inode and offset numbers.<commit_after>extern crate fuse;
extern crate time;
extern crate libc;
extern crate serialize;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};
use serialize::json;

struct JsonFilesystem {
    tree: json::Object,
}

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
                for (i, key) in self.tree.keys().enumerate() {
                    let inode: u64 = 2 + i as u64;
                    let offset: u64 = 2 + i as u64;
                    reply.add(inode, offset, FileType::RegularFile, &PosixPath::new(key));
                }
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let data = json::from_str("{\"foo\": \"bar\", \"answer\": 42}").unwrap();
    let tree = data.as_object().unwrap();
    let fs = JsonFilesystem { tree: tree.clone() };
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(fs, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>use std::mem;

use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use convert::{ IntoSV, FromSV };

pub struct SV(Owned<raw::SV>);

impl SV {
    method! { simple fn iv() -> IV = sv_iv() }
    method! { simple fn uv() -> UV = sv_uv() }
    method! { simple fn nv() -> NV = sv_nv() }

    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl FromSV for IV {
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for SV {
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl IntoSV for IV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl<'a> IntoSV for &'a str {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        use std::ffi::CString;
        let buf = CString::new(self).unwrap();
        unsafe {
            let svp = pthx.new_sv_pvn(buf.as_ptr(), self.len() as raw::STRLEN, raw::SVf_UTF8 as raw::U32);
            SV::from_raw(pthx, svp)
        }
    }
}
<commit_msg>Fix in string converison.<commit_after>use std::mem;

use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use convert::{ IntoSV, FromSV };

pub struct SV(Owned<raw::SV>);

impl SV {
    method! { simple fn iv() -> IV = sv_iv() }
    method! { simple fn uv() -> UV = sv_uv() }
    method! { simple fn nv() -> NV = sv_nv() }

    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl FromSV for IV {
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for SV {
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl IntoSV for IV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl<'a> IntoSV for &'a str {
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        use std::ffi::CString;
        let buf = CString::new(self).unwrap();
        unsafe {
            let svp = pthx.new_sv_pvn(buf.as_ptr(), self.len() as raw::STRLEN, raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}
<|endoftext|>


<commit_before>//! Error module.
//! Contains traits and Constants for error printing.

use std::fmt;
use std::fmt::Debug;
use position::span::Span;
extern crate ansi_term;
use self::ansi_term::Color::*;
use self::ansi_term::Color;

/// Color code for errors used throughout entire error reporting system.
///
#[deprecated(since = "0.5.0")]
pub const ERROR_COLORS: [Color; 4] = [
    Red, Cyan, Green, Cyan,
];

/// Enum for error levels.
#[derive(Debug, Copy, Clone)]
pub enum ErrorLevel {Warning, Error}

impl fmt::Display for ErrorLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &ErrorLevel::Warning => Yellow,
            &ErrorLevel::Error   => Red,
        }.paint(format!("{:?}", self)))
    }
}

/// Color for names which are printed by the compiler.
pub const NAME_COLOR: Color = Green;

/// Color for modules when printed by the compiler.
pub const MODULE_COLOR: Color = Cyan;

/// Color for dividing bars used when displaying errors.
pub const BAR_COLOR: Color = Cyan;

/// Color for info line displayed.
pub const INFO_COLOR: Color = Blue;

/// Color for underlining arrows for error spans.
pub const ARROW_COLOR: Color = Red;

/// Color for source code that is displayed in error reporting.
pub const CONTENT_COLOR: Color = Green;

/// Trait for Errors. Any error used throughout the wright compiler/interpreter must implement
/// this trait for consistency.
pub trait Error<'source> : Debug + Sized {
    /// Return the name of the error.
    fn get_name(&self)   -> &str;

    /// Return the module or location the error came from.
    fn get_module(&self) -> &str;

    /// Returns the error level.
    fn get_level(&self) -> ErrorLevel;

    /// Returns a vector of the content spans of the offending content.
    ///
    /// If there are no spans (the vector is empty) then line numbers will not
    /// be used in error reporting.
    ///
    /// Spans must be single line only. (The error is invalid otherwise.)
    fn get_spans(&self)  -> &Vec<Span>;

    /// Return information about the error.
    ///
    /// The first entry is displayed as the error information at the top of the error
    /// and the following ones are displayed next to the the underlining string for each span.
    ///
    /// Any additional information (past the appropriate number for the given set of spans)
    /// will not show up in the error report.
    ///
    /// If the vector is empty or too short then each informative will default to an empty string
    /// except for the first one, which defaults to "An error occurred."
    fn get_info(&self)   -> &Vec<&str>;

    /// Return a reference to the source code of the module (file) containing the error.
    ///
    /// The error will be invalid if the source is not long enough to contain the errors found.
    fn get_lines(&self)  -> &'source Vec<&'source str>;

    /// Check to see if the error is valid.
    /// (Checks to make sure there are the appropriate numbers of spans,
    /// informatics, and source lines).
    ///
    /// # Errors
    /// - If any of the spans from get_spans are multiple lines.
    /// - If any of the spans are outside of the of the source module/file.
    fn validate(&self) -> Result<(), ()> {
        if !self.get_spans()
            .iter()
            .all(|span| !span.is_multiple_lines()) {return Err(());}
        if self.get_spans().len() > 0 && self.get_spans().last().unwrap()
            .get_end().get_line() > self.get_lines().len() {return Err(());}
        Ok(())
    }

    /// Turn error into one which can be displayed.
    /// (ErrorToDisplay implements fmt::Display)
    ///
    /// # Panics
    /// Panics if validate() returns an Err().
    fn get_displayable(&self) ->  ErrorToDisplay<'source> {
        self.validate().unwrap();
        let result = ErrorToDisplay {
            level:         self.get_level(),
            name:          self.get_name().to_string(),
            module:        self.get_module().to_string(),
            line_info:     ErrorToDisplay::get_line_info(self.get_spans()),
            error_info:    self.get_info().iter().map(|s| s.to_string()).collect(),
            source_lines:  self.get_lines(),
            spans:         self.get_spans().clone(),
        };
        return result;
    }

    /// Displays a given error via the get_displayable method.
    ///
    /// # Panics
    /// Panics if validate() returns and Err().
    fn display(&self) {
        self.get_displayable().display();
    }
}

#[derive(Debug, Clone)]
/// ErrorToDisplay is an intermediate type used to go from a raw error
/// into a format that can be printed easily.
pub struct ErrorToDisplay<'source> {
    level:          ErrorLevel,
    name:           String,
    module:         String,
    line_info:      String,
    error_info:     Vec<String>,
    source_lines:   &'source Vec<&'source str>,
    spans:          Vec<Span>,
}

impl<'source> ErrorToDisplay<'source> {
    /// Prints this error into the terminal.
    pub fn display(&self) {
        println!("{}", self);
    }
    // not pub because it doesn't need to be and it is pretty specific.
    /// Takes vec of spans and uses it to set line info.
    fn get_line_info(span_vec: &Vec<Span>) -> String {
        if span_vec.is_empty() {"".to_string()}
        else {
            format!("on line {}.", span_vec.last().unwrap().get_start().get_line())
        }
    }
}

impl<'source> fmt::Display for ErrorToDisplay<'source> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let width = 5;
        let five = " ".repeat(width);
        let bar = BAR_COLOR.paint("|");
        let info = self.clone().error_info;
        let mut info_iter = info.iter();
        let mut span_iter = self.spans.iter();
        write!(f, "{level}: {n} in {m} {l_info}\n{f}{info}\n{f} {b}\n",
            level = format!("{}", self.level),
            n = NAME_COLOR.paint(self.name.clone()),
            m = MODULE_COLOR.paint(self.module.clone()),
            l_info = self.line_info,
            f = five,
            b = bar,
            info = INFO_COLOR.paint(info_iter.next()
                .unwrap_or(&"An Error Occurred.".to_string())
                .as_str()),
        )?;
        while let Some(span) = span_iter.next() {
            let current_line: &str = self.source_lines
                .get(span.get_start()
                    .get_line()-1)
                .unwrap().trim_right();
            let mut arrow_line = String::new();
            current_line.chars().take(span.get_start().get_col()).for_each(|c| {
                match c {
                    '\t' => arrow_line.push('\t'),
                    _    => arrow_line.push(' '),
                }
            });
            arrow_line.push_str("^".repeat(span.get_end().get_col()-span.get_start().get_col())
                .as_str());
            write!(f, "{prev:>w$} {b} {p_line}\n{cur:>w$} {b} {c_line}\n{f} {b} {a_line} {info}",
                prev = span.get_start().get_line()-1,
                cur = span.get_start().get_line(),
                p_line = CONTENT_COLOR.paint(
                    self.source_lines.get(span.get_start().get_line()-2).unwrap().trim_right()),
                c_line = CONTENT_COLOR.paint(current_line),
                w = width,
                b = bar,
                f = five,
                a_line = ARROW_COLOR.paint(arrow_line),
                info = INFO_COLOR.paint(info_iter.next()
                    .unwrap_or(&"".to_string())
                    .as_str()),
            )?;
        }
        write!(f, "{} {}", five, bar)
    }
}<commit_msg>Fix minor issue<commit_after>//! Error module.
//! Contains traits and Constants for error printing.

use std::fmt;
use std::fmt::Debug;
use position::span::Span;
extern crate ansi_term;
use self::ansi_term::Color::*;
use self::ansi_term::Color;

/// Color code for errors used throughout entire error reporting system.
///
#[deprecated(since = "0.5.0")]
pub const ERROR_COLORS: [Color; 4] = [
    Red, Cyan, Green, Cyan,
];

/// Enum for error levels.
#[derive(Debug, Copy, Clone)]
pub enum ErrorLevel {Warning, Error}

impl fmt::Display for ErrorLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &ErrorLevel::Warning => Yellow,
            &ErrorLevel::Error   => Red,
        }.paint(format!("{:?}", self)))
    }
}

/// Color for names which are printed by the compiler.
pub const NAME_COLOR: Color = Green;

/// Color for modules when printed by the compiler.
pub const MODULE_COLOR: Color = Cyan;

/// Color for dividing bars used when displaying errors.
pub const BAR_COLOR: Color = Cyan;

/// Color for info line displayed.
pub const INFO_COLOR: Color = Blue;

/// Color for underlining arrows for error spans.
pub const ARROW_COLOR: Color = Red;

/// Color for source code that is displayed in error reporting.
pub const CONTENT_COLOR: Color = Green;

/// Trait for Errors. Any error used throughout the wright compiler/interpreter must implement
/// this trait for consistency.
pub trait Error<'source> : Debug + Sized {
    /// Return the name of the error.
    fn get_name(&self)   -> &str;

    /// Return the module or location the error came from.
    fn get_module(&self) -> &str;

    /// Returns the error level.
    fn get_level(&self) -> ErrorLevel;

    /// Returns a vector of the content spans of the offending content.
    ///
    /// If there are no spans (the vector is empty) then line numbers will not
    /// be used in error reporting. (The entire source will be printed.)
    ///
    /// Spans must be single line only. (The error is invalid otherwise.)
    fn get_spans(&self)  -> &Vec<Span>;

    /// Return information about the error.
    ///
    /// The first entry is displayed as the error information at the top of the error
    /// and the following ones are displayed next to the the underlining string for each span.
    ///
    /// Any additional information (past the appropriate number for the given set of spans)
    /// will not show up in the error report.
    ///
    /// If the vector is empty or too short then each informative will default to an empty string
    /// except for the first one, which defaults to "An error occurred."
    fn get_info(&self)   -> &Vec<&str>;

    /// Return a reference to the source code of the module (file) containing the error.
    /// Or the source of the error if it was not in code.
    ///
    /// If line numbers are not being used, the full source returned by this
    /// function will be printed.
    ///
    /// The error will be invalid if the source is not long enough to contain the errors found.
    fn get_lines(&self)  -> &'source Vec<&'source str>;

    /// Check to see if the error is valid.
    /// (Checks to make sure there are the appropriate numbers of spans,
    /// informatics, and source lines).
    ///
    /// # Errors
    /// - If any of the spans from get_spans are multiple lines.
    /// - If any of the spans are outside of the of the source module/file.
    fn validate(&self) -> Result<(), ()> {
        if !self.get_spans()
            .iter()
            .all(|span| !span.is_multiple_lines()) {return Err(());}
        if self.get_spans().len() > 0 && self.get_spans().last().unwrap()
            .get_end().get_line() > self.get_lines().len() {return Err(());}
        Ok(())
    }

    /// Turn error into one which can be displayed.
    /// (ErrorToDisplay implements fmt::Display)
    ///
    /// # Panics
    /// Panics if validate() returns an Err().
    fn get_displayable(&self) ->  ErrorToDisplay<'source> {
        self.validate().unwrap();
        let result = ErrorToDisplay {
            level:         self.get_level(),
            name:          self.get_name().to_string(),
            module:        self.get_module().to_string(),
            line_info:     ErrorToDisplay::get_line_info(self.get_spans()),
            error_info:    self.get_info().iter().map(|s| s.to_string()).collect(),
            source_lines:  self.get_lines(),
            spans:         self.get_spans().clone(),
        };
        return result;
    }

    /// Displays a given error via the get_displayable method.
    ///
    /// # Panics
    /// Panics if validate() returns and Err().
    fn display(&self) {
        self.get_displayable().display();
    }
}

#[derive(Debug, Clone)]
/// ErrorToDisplay is an intermediate type used to go from a raw error
/// into a format that can be printed easily.
pub struct ErrorToDisplay<'source> {
    level:          ErrorLevel,
    name:           String,
    module:         String,
    line_info:      String,
    error_info:     Vec<String>,
    source_lines:   &'source Vec<&'source str>,
    spans:          Vec<Span>,
}

impl<'source> ErrorToDisplay<'source> {
    /// Prints this error into the terminal.
    pub fn display(&self) {
        println!("{}", self);
    }
    // not pub because it doesn't need to be and it is pretty specific.
    /// Takes vec of spans and uses it to set line info.
    fn get_line_info(span_vec: &Vec<Span>) -> String {
        if span_vec.is_empty() {"".to_string()}
        else {
            format!("on line {}.", span_vec.last().unwrap().get_start().get_line())
        }
    }
}

impl<'source> fmt::Display for ErrorToDisplay<'source> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let width = 5;
        let five = " ".repeat(width);
        let bar = BAR_COLOR.paint("|");
        let info = self.clone().error_info;
        let mut info_iter = info.iter();
        let no_span = self.spans.is_empty();
        let mut span_iter = self.spans.iter();
        writeln!(f, "{level}: {n} in {m} {l_info}\n{f}{info}\n{f} {b}",
            level = format!("{}", self.level),
            n = NAME_COLOR.paint(self.name.clone()),
            m = MODULE_COLOR.paint(self.module.clone()),
            l_info = self.line_info,
            f = five,
            b = bar,
            info = INFO_COLOR.paint(info_iter.next()
                .unwrap_or(&"An Error Occurred.".to_string())
                .as_str()),
        )?;
        while let Some(span) = span_iter.next() {
            let current_line: &str = self.source_lines
                .get(span.get_start()
                    .get_line()-1)
                .unwrap().trim_right();
            let mut arrow_line = String::new();
            current_line.chars().take(span.get_start().get_col()).for_each(|c| {
                match c {
                    '\t' => arrow_line.push('\t'),
                    _    => arrow_line.push(' '),
                }
            });
            arrow_line.push_str("^".repeat(span.get_end().get_col()-span.get_start().get_col())
                .as_str());
            writeln!(f, "{prev:>w$} {b} {p_line}\n{cur:>w$} {b} {c_line}\n{f} {b} {a_line} {info}",
                prev = span.get_start().get_line()-1,
                cur = span.get_start().get_line(),
                p_line = CONTENT_COLOR.paint(
                    self.source_lines.get(span.get_start().get_line()-2).unwrap().trim_right()),
                c_line = CONTENT_COLOR.paint(current_line),
                w = width,
                b = bar,
                f = five,
                a_line = ARROW_COLOR.paint(arrow_line),
                info = INFO_COLOR.paint(info_iter.next()
                    .unwrap_or(&"".to_string())
                    .as_str()),
            )?;
        }
        if no_span {
            for line in self.source_lines {
                writeln!(f, "{f} {b} {l}",
                    f= five,
                    b = bar,
                    l = CONTENT_COLOR.paint(*line),
                )?;
            }
        }
        writeln!(f, "{} {}", five, bar)
    }
}<|endoftext|>


<commit_before>use std;
use std::cmp;
use std::io::stdout;
use std::io::Write;
use std::thread;
use std::time;

use termion;
use termion::clear;
use termion::cursor;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;

use serde_json;

use core::Core;
use view::View;

pub struct Screen {
    pub stdout: MouseTerminal<RawTerminal<std::io::Stdout>>,
    pub size: (u16, u16),
}

impl Screen {
    pub fn new() -> Screen {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    pub fn draw(&mut self, view: &View) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();

        let range = 0..(cmp::min(view.lines.len(), self.size.1 as usize));
        for (lineno, line) in range.zip(view.lines.iter()) {
            write!(self.stdout, "{}", line.text.clone().unwrap()).unwrap();
            self.scroll(0, lineno as u64);
        }
    }

    pub fn scroll(&mut self, col: u64, line: u64) {
        write!(self.stdout, "{}", cursor::Goto((col + 1) as u16, (line + 1) as u16)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn update(&mut self, core: &mut Core) {
        // TODO(#27): check if terminal size changed. If so, send a `render_line` command to the
        // backend, and a `scroll` command for future updates.
        if let Ok(msg) = core.update_rx.try_recv() {
            let msg_list = msg.as_array().unwrap();
            let (method, params) = (msg_list[0].as_str().unwrap(),
                                    msg_list[1].as_object().unwrap());
            match method {
                "update" => {
                    let update = serde_json::from_value(params.get("update").unwrap().clone())
                        .unwrap();
                    core.update(&update);

                    let view = core.view();
                    self.draw(&view);
                }
                "scroll_to" => {
                    let (col, line) = (params.get("col").unwrap().as_u64().unwrap(),
                                       params.get("line").unwrap().as_u64().unwrap());
                    self.scroll(col, line);
                }
                "set_style" => {
                    // TODO:(#26): ???
                }
                _ => {
                    info!("Unknown request from backend {:?}", method);
                }
            }
        } else {
            thread::sleep(time::Duration::from_millis(10));
        }
    }
}
<commit_msg>use alternate screen buffer<commit_after>use std;
use std::cmp;
use std::io::stdout;
use std::io::Write;
use std::thread;
use std::time;

use termion;
use termion::clear;
use termion::cursor;
use termion::input::MouseTerminal;
use termion::screen::AlternateScreen;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;

use serde_json;

use core::Core;
use view::View;

pub struct Screen {
    pub stdout: MouseTerminal<AlternateScreen<RawTerminal<std::io::Stdout>>>,
    pub size: (u16, u16),
}

impl Screen {
    pub fn new() -> Screen {
        let stdout = MouseTerminal::from(AlternateScreen::from(stdout().into_raw_mode().unwrap()));
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    pub fn draw(&mut self, view: &View) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();

        let range = 0..(cmp::min(view.lines.len(), self.size.1 as usize));
        for (lineno, line) in range.zip(view.lines.iter()) {
            write!(self.stdout, "{}", line.text.clone().unwrap()).unwrap();
            self.scroll(0, lineno as u64);
        }
    }

    pub fn scroll(&mut self, col: u64, line: u64) {
        write!(self.stdout, "{}", cursor::Goto((col + 1) as u16, (line + 1) as u16)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn init(&mut self) {
        write!(self.stdout, "{}", clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn update(&mut self, core: &mut Core) {
        // TODO(#27): check if terminal size changed. If so, send a `render_line` command to the
        // backend, and a `scroll` command for future updates.
        if let Ok(msg) = core.update_rx.try_recv() {
            let msg_list = msg.as_array().unwrap();
            let (method, params) = (msg_list[0].as_str().unwrap(),
                                    msg_list[1].as_object().unwrap());
            match method {
                "update" => {
                    let update = serde_json::from_value(params.get("update").unwrap().clone())
                        .unwrap();
                    core.update(&update);

                    let view = core.view();
                    self.draw(&view);
                }
                "scroll_to" => {
                    let (col, line) = (params.get("col").unwrap().as_u64().unwrap(),
                                       params.get("line").unwrap().as_u64().unwrap());
                    self.scroll(col, line);
                }
                "set_style" => {
                    // TODO:(#26): ???
                }
                _ => {
                    info!("Unknown request from backend {:?}", method);
                }
            }
        } else {
            thread::sleep(time::Duration::from_millis(10));
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parser and serializer for the [`application/x-www-form-urlencoded` syntax](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

#[macro_use]
extern crate matches;

use percent_encoding::{percent_decode, percent_encode_byte};
use std::borrow::{Borrow, Cow};
use std::str;

use crate::query_encoding::decode_utf8_lossy;
pub use crate::query_encoding::EncodingOverride;

mod query_encoding;

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// The names and values are percent-decoded. For instance, `%23first=%25try%25` will be
/// converted to `[("#first", "%try%")]`.
#[inline]
pub fn parse(input: &[u8]) -> Parse<'_> {
    Parse { input }
}
/// The return type of `parse()`.
#[derive(Copy, Clone)]
pub struct Parse<'a> {
    input: &'a [u8],
}

impl<'a> Iterator for Parse<'a> {
    type Item = (Cow<'a, str>, Cow<'a, str>);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.input.is_empty() {
                return None;
            }
            let mut split2 = self.input.splitn(2, |&b| b == b'&');
            let sequence = split2.next().unwrap();
            self.input = split2.next().unwrap_or(&[][..]);
            if sequence.is_empty() {
                continue;
            }
            let mut split2 = sequence.splitn(2, |&b| b == b'=');
            let name = split2.next().unwrap();
            let value = split2.next().unwrap_or(&[][..]);
            return Some((decode(name), decode(value)));
        }
    }
}

fn decode(input: &[u8]) -> Cow<'_, str> {
    let replaced = replace_plus(input);
    decode_utf8_lossy(match percent_decode(&replaced).into() {
        Cow::Owned(vec) => Cow::Owned(vec),
        Cow::Borrowed(_) => replaced,
    })
}

/// Replace b'+' with b' '
fn replace_plus(input: &[u8]) -> Cow<'_, [u8]> {
    match input.iter().position(|&b| b == b'+') {
        None => Cow::Borrowed(input),
        Some(first_position) => {
            let mut replaced = input.to_owned();
            replaced[first_position] = b' ';
            for byte in &mut replaced[first_position + 1..] {
                if *byte == b'+' {
                    *byte = b' ';
                }
            }
            Cow::Owned(replaced)
        }
    }
}

impl<'a> Parse<'a> {
    /// Return a new iterator that yields pairs of `String` instead of pairs of `Cow<str>`.
    pub fn into_owned(self) -> ParseIntoOwned<'a> {
        ParseIntoOwned { inner: self }
    }
}

/// Like `Parse`, but yields pairs of `String` instead of pairs of `Cow<str>`.
pub struct ParseIntoOwned<'a> {
    inner: Parse<'a>,
}

impl<'a> Iterator for ParseIntoOwned<'a> {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner
            .next()
            .map(|(k, v)| (k.into_owned(), v.into_owned()))
    }
}

/// The [`application/x-www-form-urlencoded` byte serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
///
/// Return an iterator of `&str` slices.
pub fn byte_serialize(input: &[u8]) -> ByteSerialize<'_> {
    ByteSerialize { bytes: input }
}

/// Return value of `byte_serialize()`.
#[derive(Debug)]
pub struct ByteSerialize<'a> {
    bytes: &'a [u8],
}

fn byte_serialized_unchanged(byte: u8) -> bool {
    matches!(byte, b'*' | b'-' | b'.' | b'0' ..= b'9' | b'A' ..= b'Z' | b'_' | b'a' ..= b'z')
}

impl<'a> Iterator for ByteSerialize<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some((&first, tail)) = self.bytes.split_first() {
            if !byte_serialized_unchanged(first) {
                self.bytes = tail;
                return Some(if first == b' ' {
                    "+"
                } else {
                    percent_encode_byte(first)
                });
            }
            let position = tail.iter().position(|&b| !byte_serialized_unchanged(b));
            let (unchanged_slice, remaining) = match position {
                // 1 for first_byte + i unchanged in tail
                Some(i) => self.bytes.split_at(1 + i),
                None => (self.bytes, &[][..]),
            };
            self.bytes = remaining;
            // This unsafe is appropriate because we have already checked these
            // bytes in byte_serialized_unchanged, which checks for a subset
            // of UTF-8. So we know these bytes are valid UTF-8, and doing
            // another UTF-8 check would be wasteful.
            Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.bytes.is_empty() {
            (0, Some(0))
        } else {
            (1, Some(self.bytes.len()))
        }
    }
}

/// The [`application/x-www-form-urlencoded` serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-serializer).
pub struct Serializer<'a, T: Target> {
    target: Option<T>,
    start_position: usize,
    encoding: EncodingOverride<'a>,
}

pub trait Target {
    fn as_mut_string(&mut self) -> &mut String;
    fn finish(self) -> Self::Finished;
    type Finished;
}

impl Target for String {
    fn as_mut_string(&mut self) -> &mut String {
        self
    }
    fn finish(self) -> Self {
        self
    }
    type Finished = Self;
}

impl<'a> Target for &'a mut String {
    fn as_mut_string(&mut self) -> &mut String {
        &mut **self
    }
    fn finish(self) -> Self {
        self
    }
    type Finished = Self;
}

impl<'a, T: Target> Serializer<'a, T> {
    /// Create a new `application/x-www-form-urlencoded` serializer for the given target.
    ///
    /// If the target is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn new(target: T) -> Self {
        Self::for_suffix(target, 0)
    }

    /// Create a new `application/x-www-form-urlencoded` serializer
    /// for a suffix of the given target.
    ///
    /// If that suffix is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn for_suffix(mut target: T, start_position: usize) -> Self {
        if target.as_mut_string().len() < start_position {
            panic!(
                "invalid length {} for target of length {}",
                start_position,
                target.as_mut_string().len()
            );
        }

        Serializer {
            target: Some(target),
            start_position,
            encoding: None,
        }
    }

    /// Remove any existing name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn clear(&mut self) -> &mut Self {
        string(&mut self.target).truncate(self.start_position);
        self
    }

    /// Set the character encoding to be used for names and values before percent-encoding.
    pub fn encoding_override(&mut self, new: EncodingOverride<'a>) -> &mut Self {
        self.encoding = new;
        self
    }

    /// Serialize and append a name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
        append_pair(
            string(&mut self.target),
            self.start_position,
            self.encoding,
            name,
            value,
        );
        self
    }

    /// Serialize and append a name of parameter without any value.
    ///
    /// Panics if called after `.finish()`.
    pub fn append_key_only(&mut self, name: &str) -> &mut Self {
        append_key_only(
            string(&mut self.target),
            self.start_position,
            self.encoding,
            name,
        );
        self
    }

    /// Serialize and append a number of name/value pairs.
    ///
    /// This simply calls `append_pair` repeatedly.
    /// This can be more convenient, so the user doesn’t need to introduce a block
    /// to limit the scope of `Serializer`’s borrow of its string.
    ///
    /// Panics if called after `.finish()`.
    pub fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self
    where
        I: IntoIterator,
        I::Item: Borrow<(K, V)>,
        K: AsRef<str>,
        V: AsRef<str>,
    {
        {
            let string = string(&mut self.target);
            for pair in iter {
                let &(ref k, ref v) = pair.borrow();
                append_pair(
                    string,
                    self.start_position,
                    self.encoding,
                    k.as_ref(),
                    v.as_ref(),
                );
            }
        }
        self
    }

    /// Serialize and append a number of names without values.
    ///
    /// This simply calls `append_key_only` repeatedly.
    /// This can be more convenient, so the user doesn’t need to introduce a block
    /// to limit the scope of `Serializer`’s borrow of its string.
    ///
    /// Panics if called after `.finish()`.
    pub fn extend_keys_only<I, K>(&mut self, iter: I) -> &mut Self
    where
        I: IntoIterator,
        I::Item: Borrow<K>,
        K: AsRef<str>,
    {
        {
            let string = string(&mut self.target);
            for key in iter {
                let ref k = key.borrow();
                append_key_only(
                    string,
                    self.start_position,
                    self.encoding,
                    k.as_ref(),
                );
            }
        }
        self
    }

    /// If this serializer was constructed with a string, take and return that string.
    ///
    /// ```rust
    /// use form_urlencoded;
    /// let encoded: String = form_urlencoded::Serializer::new(String::new())
    ///     .append_pair("foo", "bar & baz")
    ///     .append_pair("saison", "Été+hiver")
    ///     .finish();
    /// assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver");
    /// ```
    ///
    /// Panics if called more than once.
    pub fn finish(&mut self) -> T::Finished {
        self.target
            .take()
            .expect("url::form_urlencoded::Serializer double finish")
            .finish()
    }
}

fn append_separator_if_needed(string: &mut String, start_position: usize) {
    if string.len() > start_position {
        string.push('&')
    }
}

fn string<T: Target>(target: &mut Option<T>) -> &mut String {
    target
        .as_mut()
        .expect("url::form_urlencoded::Serializer finished")
        .as_mut_string()
}

fn append_pair(
    string: &mut String,
    start_position: usize,
    encoding: EncodingOverride<'_>,
    name: &str,
    value: &str,
) {
    append_separator_if_needed(string, start_position);
    append_encoded(name, string, encoding);
    string.push('=');
    append_encoded(value, string, encoding);
}

fn append_key_only(
    string: &mut String,
    start_position: usize,
    encoding: EncodingOverride,
    name: &str,
) {
    append_separator_if_needed(string, start_position);
    append_encoded(name, string, encoding);
}

fn append_encoded(s: &str, string: &mut String, encoding: EncodingOverride<'_>) {
    string.extend(byte_serialize(&query_encoding::encode(encoding, s)))
}
<commit_msg>chore: fix formatting/clippy issues after merged PR<commit_after>// Copyright 2013-2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parser and serializer for the [`application/x-www-form-urlencoded` syntax](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

#[macro_use]
extern crate matches;

use percent_encoding::{percent_decode, percent_encode_byte};
use std::borrow::{Borrow, Cow};
use std::str;

use crate::query_encoding::decode_utf8_lossy;
pub use crate::query_encoding::EncodingOverride;

mod query_encoding;

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// The names and values are percent-decoded. For instance, `%23first=%25try%25` will be
/// converted to `[("#first", "%try%")]`.
#[inline]
pub fn parse(input: &[u8]) -> Parse<'_> {
    Parse { input }
}
/// The return type of `parse()`.
#[derive(Copy, Clone)]
pub struct Parse<'a> {
    input: &'a [u8],
}

impl<'a> Iterator for Parse<'a> {
    type Item = (Cow<'a, str>, Cow<'a, str>);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.input.is_empty() {
                return None;
            }
            let mut split2 = self.input.splitn(2, |&b| b == b'&');
            let sequence = split2.next().unwrap();
            self.input = split2.next().unwrap_or(&[][..]);
            if sequence.is_empty() {
                continue;
            }
            let mut split2 = sequence.splitn(2, |&b| b == b'=');
            let name = split2.next().unwrap();
            let value = split2.next().unwrap_or(&[][..]);
            return Some((decode(name), decode(value)));
        }
    }
}

fn decode(input: &[u8]) -> Cow<'_, str> {
    let replaced = replace_plus(input);
    decode_utf8_lossy(match percent_decode(&replaced).into() {
        Cow::Owned(vec) => Cow::Owned(vec),
        Cow::Borrowed(_) => replaced,
    })
}

/// Replace b'+' with b' '
fn replace_plus(input: &[u8]) -> Cow<'_, [u8]> {
    match input.iter().position(|&b| b == b'+') {
        None => Cow::Borrowed(input),
        Some(first_position) => {
            let mut replaced = input.to_owned();
            replaced[first_position] = b' ';
            for byte in &mut replaced[first_position + 1..] {
                if *byte == b'+' {
                    *byte = b' ';
                }
            }
            Cow::Owned(replaced)
        }
    }
}

impl<'a> Parse<'a> {
    /// Return a new iterator that yields pairs of `String` instead of pairs of `Cow<str>`.
    pub fn into_owned(self) -> ParseIntoOwned<'a> {
        ParseIntoOwned { inner: self }
    }
}

/// Like `Parse`, but yields pairs of `String` instead of pairs of `Cow<str>`.
pub struct ParseIntoOwned<'a> {
    inner: Parse<'a>,
}

impl<'a> Iterator for ParseIntoOwned<'a> {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner
            .next()
            .map(|(k, v)| (k.into_owned(), v.into_owned()))
    }
}

/// The [`application/x-www-form-urlencoded` byte serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
///
/// Return an iterator of `&str` slices.
pub fn byte_serialize(input: &[u8]) -> ByteSerialize<'_> {
    ByteSerialize { bytes: input }
}

/// Return value of `byte_serialize()`.
#[derive(Debug)]
pub struct ByteSerialize<'a> {
    bytes: &'a [u8],
}

fn byte_serialized_unchanged(byte: u8) -> bool {
    matches!(byte, b'*' | b'-' | b'.' | b'0' ..= b'9' | b'A' ..= b'Z' | b'_' | b'a' ..= b'z')
}

impl<'a> Iterator for ByteSerialize<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some((&first, tail)) = self.bytes.split_first() {
            if !byte_serialized_unchanged(first) {
                self.bytes = tail;
                return Some(if first == b' ' {
                    "+"
                } else {
                    percent_encode_byte(first)
                });
            }
            let position = tail.iter().position(|&b| !byte_serialized_unchanged(b));
            let (unchanged_slice, remaining) = match position {
                // 1 for first_byte + i unchanged in tail
                Some(i) => self.bytes.split_at(1 + i),
                None => (self.bytes, &[][..]),
            };
            self.bytes = remaining;
            // This unsafe is appropriate because we have already checked these
            // bytes in byte_serialized_unchanged, which checks for a subset
            // of UTF-8. So we know these bytes are valid UTF-8, and doing
            // another UTF-8 check would be wasteful.
            Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.bytes.is_empty() {
            (0, Some(0))
        } else {
            (1, Some(self.bytes.len()))
        }
    }
}

/// The [`application/x-www-form-urlencoded` serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-serializer).
pub struct Serializer<'a, T: Target> {
    target: Option<T>,
    start_position: usize,
    encoding: EncodingOverride<'a>,
}

pub trait Target {
    fn as_mut_string(&mut self) -> &mut String;
    fn finish(self) -> Self::Finished;
    type Finished;
}

impl Target for String {
    fn as_mut_string(&mut self) -> &mut String {
        self
    }
    fn finish(self) -> Self {
        self
    }
    type Finished = Self;
}

impl<'a> Target for &'a mut String {
    fn as_mut_string(&mut self) -> &mut String {
        &mut **self
    }
    fn finish(self) -> Self {
        self
    }
    type Finished = Self;
}

impl<'a, T: Target> Serializer<'a, T> {
    /// Create a new `application/x-www-form-urlencoded` serializer for the given target.
    ///
    /// If the target is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn new(target: T) -> Self {
        Self::for_suffix(target, 0)
    }

    /// Create a new `application/x-www-form-urlencoded` serializer
    /// for a suffix of the given target.
    ///
    /// If that suffix is non-empty,
    /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
    pub fn for_suffix(mut target: T, start_position: usize) -> Self {
        if target.as_mut_string().len() < start_position {
            panic!(
                "invalid length {} for target of length {}",
                start_position,
                target.as_mut_string().len()
            );
        }

        Serializer {
            target: Some(target),
            start_position,
            encoding: None,
        }
    }

    /// Remove any existing name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn clear(&mut self) -> &mut Self {
        string(&mut self.target).truncate(self.start_position);
        self
    }

    /// Set the character encoding to be used for names and values before percent-encoding.
    pub fn encoding_override(&mut self, new: EncodingOverride<'a>) -> &mut Self {
        self.encoding = new;
        self
    }

    /// Serialize and append a name/value pair.
    ///
    /// Panics if called after `.finish()`.
    pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
        append_pair(
            string(&mut self.target),
            self.start_position,
            self.encoding,
            name,
            value,
        );
        self
    }

    /// Serialize and append a name of parameter without any value.
    ///
    /// Panics if called after `.finish()`.
    pub fn append_key_only(&mut self, name: &str) -> &mut Self {
        append_key_only(
            string(&mut self.target),
            self.start_position,
            self.encoding,
            name,
        );
        self
    }

    /// Serialize and append a number of name/value pairs.
    ///
    /// This simply calls `append_pair` repeatedly.
    /// This can be more convenient, so the user doesn’t need to introduce a block
    /// to limit the scope of `Serializer`’s borrow of its string.
    ///
    /// Panics if called after `.finish()`.
    pub fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self
    where
        I: IntoIterator,
        I::Item: Borrow<(K, V)>,
        K: AsRef<str>,
        V: AsRef<str>,
    {
        {
            let string = string(&mut self.target);
            for pair in iter {
                let &(ref k, ref v) = pair.borrow();
                append_pair(
                    string,
                    self.start_position,
                    self.encoding,
                    k.as_ref(),
                    v.as_ref(),
                );
            }
        }
        self
    }

    /// Serialize and append a number of names without values.
    ///
    /// This simply calls `append_key_only` repeatedly.
    /// This can be more convenient, so the user doesn’t need to introduce a block
    /// to limit the scope of `Serializer`’s borrow of its string.
    ///
    /// Panics if called after `.finish()`.
    pub fn extend_keys_only<I, K>(&mut self, iter: I) -> &mut Self
    where
        I: IntoIterator,
        I::Item: Borrow<K>,
        K: AsRef<str>,
    {
        {
            let string = string(&mut self.target);
            for key in iter {
                let k = key.borrow().as_ref();
                append_key_only(string, self.start_position, self.encoding, k);
            }
        }
        self
    }

    /// If this serializer was constructed with a string, take and return that string.
    ///
    /// ```rust
    /// use form_urlencoded;
    /// let encoded: String = form_urlencoded::Serializer::new(String::new())
    ///     .append_pair("foo", "bar & baz")
    ///     .append_pair("saison", "Été+hiver")
    ///     .finish();
    /// assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver");
    /// ```
    ///
    /// Panics if called more than once.
    pub fn finish(&mut self) -> T::Finished {
        self.target
            .take()
            .expect("url::form_urlencoded::Serializer double finish")
            .finish()
    }
}

fn append_separator_if_needed(string: &mut String, start_position: usize) {
    if string.len() > start_position {
        string.push('&')
    }
}

fn string<T: Target>(target: &mut Option<T>) -> &mut String {
    target
        .as_mut()
        .expect("url::form_urlencoded::Serializer finished")
        .as_mut_string()
}

fn append_pair(
    string: &mut String,
    start_position: usize,
    encoding: EncodingOverride<'_>,
    name: &str,
    value: &str,
) {
    append_separator_if_needed(string, start_position);
    append_encoded(name, string, encoding);
    string.push('=');
    append_encoded(value, string, encoding);
}

fn append_key_only(
    string: &mut String,
    start_position: usize,
    encoding: EncodingOverride,
    name: &str,
) {
    append_separator_if_needed(string, start_position);
    append_encoded(name, string, encoding);
}

fn append_encoded(s: &str, string: &mut String, encoding: EncodingOverride<'_>) {
    string.extend(byte_serialize(&query_encoding::encode(encoding, s)))
}
<|endoftext|>


<commit_before>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::Ordering;
use score::Score;

struct Search {
    config: Configuration,
    current: uint,
    query: String,
    selection: String,
    result: Vec<String>,
}

impl Search {
    fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();

        Search::new(config, query, 0)
    }

    fn new(config: Configuration, query: String, index: uint) -> Search {
        let result = Search::filter(query.as_slice(), &config.choices.clone());

        Search { config: config,
                 current: index,
                 query: query,
                 selection: result[index].to_string(),
                 result: result }
    }

    fn new_for_index(self, index: uint) -> Search {
        Search::new(self.config, self.query, index)
    }

    fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut filtered = choices.iter().filter_map( |choice| {
            let quality = Score::score(choice.as_slice(), query);
            if quality > 0.0 {
                Some((quality, choice.to_string()))
            } else {
                None
            }
        }).collect::<Vec<(f32, String)>>();

        filtered.sort_by( |&(quality_a, _), &(quality_b, _)| {
            quality_a.partial_cmp(&quality_b).unwrap_or(Ordering::Equal).reverse()
        });

        filtered.iter().map( |&(_, ref choice)| choice.to_string() ).collect::<Vec<String>>()
    }

    fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    fn append_to_search(self, input: String) -> Search {
        let mut new_query = self.query;
        new_query.push_str(input.as_slice());
        Search::new(self.config, new_query, self.current)
    }

    fn next_index(&self) -> uint {
        let next_index = self.current + 1;

        if next_index >= self.config.visible_limit { 0 } else { next_index }
    }

    fn prev_index(&self) -> uint {
        if self.current == 0 { self.config.visible_limit - 1 } else  { self.current - 1 }
    }
}

#[cfg(test)]

#[test]
fn it_selects_the_first_choice_by_default() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.selection, "one");
}

fn one_two_three() -> Vec<String> {
    vec!["one".to_string(),
         "two".to_string(),
         "three".to_string()]
}

#[test]
fn it_selets_the_second_when_down_is_called() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_end_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.down().down().down().down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_top_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);

    assert_eq!(search.up().up().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_visible_limit() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, Some(2));
    let search = Search::blank(config);

    assert_eq!(search.down().down().down().selection, "two");
}

#[test]
fn it_moves_down_the_filtered_search_results() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t".to_string()).down().selection, "three");
}

#[test]
fn it_moves_down_the_filtered_search_results_twice() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t".to_string())
               .append_to_search("w".to_string()).selection, "two");
}
<commit_msg>Avoid unnecessary clone<commit_after>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::Ordering;
use score::Score;

struct Search {
    config: Configuration,
    current: uint,
    query: String,
    selection: String,
    result: Vec<String>,
}

impl Search {
    fn blank(config: Configuration) -> Search {
        let query = config.initial_search.clone();
        Search::new(config, query, 0)
    }

    fn new(config: Configuration, query: String, index: uint) -> Search {
        let result = Search::filter(query.as_slice(), &config.choices);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: result[index].to_string(),
                 result: result }
    }

    fn new_for_index(self, index: uint) -> Search {
        Search::new(self.config, self.query, index)
    }

    fn filter(query: &str, choices: &Vec<String>) -> Vec<String> {
        let mut filtered = choices.iter().filter_map( |choice| {
            let quality = Score::score(choice.as_slice(), query);
            if quality > 0.0 {
                Some((quality, choice.to_string()))
            } else {
                None
            }
        }).collect::<Vec<(f32, String)>>();

        filtered.sort_by( |&(quality_a, _), &(quality_b, _)| {
            quality_a.partial_cmp(&quality_b).unwrap_or(Ordering::Equal).reverse()
        });

        filtered.iter().map( |&(_, ref choice)| choice.to_string() ).collect::<Vec<String>>()
    }

    fn down(self) -> Search {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    fn up(self) -> Search {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    fn append_to_search(self, input: &str) -> Search {
        let mut new_query = self.query;
        new_query.push_str(input.as_slice());
        Search::new(self.config, new_query, self.current)
    }

    fn next_index(&self) -> uint {
        let next_index = self.current + 1;

        if next_index >= self.config.visible_limit { 0 } else { next_index }
    }

    fn prev_index(&self) -> uint {
        if self.current == 0 { self.config.visible_limit - 1 } else  { self.current - 1 }
    }
}

#[cfg(test)]

#[test]
fn it_selects_the_first_choice_by_default() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.selection, "one");
}

fn one_two_three() -> Vec<String> {
    vec!["one".to_string(),
         "two".to_string(),
         "three".to_string()]
}

#[test]
fn it_selets_the_second_when_down_is_called() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_end_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.down().down().down().down().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_top_of_list() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.up().up().selection, "two");
}

#[test]
fn it_loop_around_when_reaching_visible_limit() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, Some(2));
    let search = Search::blank(config);
    assert_eq!(search.down().down().down().selection, "two");
}

#[test]
fn it_moves_down_the_filtered_search_results() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t").down().selection, "three");
}

#[test]
fn it_moves_down_the_filtered_search_results_twice() {
    let input =  one_two_three();

    let config = Configuration::from_inputs(input, None, None);
    let search = Search::blank(config);
    assert_eq!(search.append_to_search("t").append_to_search("w").selection, "two");
}
<|endoftext|>