<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::*;
use rand::{Rng, SeedableRng};
use std::{
    io::{self, Write},
    num::NonZeroUsize,
    process,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// TODO going to remove random seed once cluster deployment supports re-run genesis
use rand::rngs::OsRng;

#[derive(Debug, StructOpt)]
#[structopt(about = "Forged in Fire")]
pub struct Options {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(long, default_value = "1", env = "RUST_TEST_THREADS")]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    /// Number of threads used for running tests in parallel
    test_threads: NonZeroUsize,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    nocapture: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests
    ignored: bool,
    #[structopt(long)]
    /// Include ignored tests when listing or running tests
    include_ignored: bool,
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(long, possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
}

impl Options {
    pub fn from_args() -> Self {
        StructOpt::from_args()
    }
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn forge_main<F: Factory>(tests: ForgeConfig<'_>, factory: F, options: &Options) -> Result<()> {
    let forge = Forge::new(options, tests, factory);

    if options.list {
        forge.list()?;

        return Ok(());
    }

    match forge.run() {
        Ok(()) => Ok(()),
        Err(_) => process::exit(101), // Exit with a non-zero exit code if tests failed
    }
}

pub struct ForgeConfig<'cfg> {
    public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    admin_tests: &'cfg [&'cfg dyn AdminTest],
    network_tests: &'cfg [&'cfg dyn NetworkTest],
}

impl<'cfg> ForgeConfig<'cfg> {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_public_usage_tests(
        mut self,
        public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    ) -> Self {
        self.public_usage_tests = public_usage_tests;
        self
    }

    pub fn with_admin_tests(mut self, admin_tests: &'cfg [&'cfg dyn AdminTest]) -> Self {
        self.admin_tests = admin_tests;
        self
    }

    pub fn with_network_tests(mut self, network_tests: &'cfg [&'cfg dyn NetworkTest]) -> Self {
        self.network_tests = network_tests;
        self
    }

    pub fn number_of_tests(&self) -> usize {
        self.public_usage_tests.len() + self.admin_tests.len() + self.network_tests.len()
    }

    pub fn all_tests(&self) -> impl Iterator<Item = &'cfg dyn Test> + 'cfg {
        self.public_usage_tests
            .iter()
            .map(|t| t as &dyn Test)
            .chain(self.admin_tests.iter().map(|t| t as &dyn Test))
            .chain(self.network_tests.iter().map(|t| t as &dyn Test))
    }
}

impl<'cfg> Default for ForgeConfig<'cfg> {
    fn default() -> Self {
        Self {
            public_usage_tests: &[],
            admin_tests: &[],
            network_tests: &[],
        }
    }
}

pub struct Forge<'cfg, F> {
    options: &'cfg Options,
    tests: ForgeConfig<'cfg>,
    factory: F,
}

impl<'cfg, F: Factory> Forge<'cfg, F> {
    pub fn new(options: &'cfg Options, tests: ForgeConfig<'cfg>, factory: F) -> Self {
        Self {
            options,
            tests,
            factory,
        }
    }

    pub fn list(&self) -> Result<()> {
        for test in self.filter_tests(self.tests.all_tests()) {
            println!("{}: test", test.name());
        }

        if self.options.format == Format::Pretty {
            println!();
            println!(
                "{} tests",
                self.filter_tests(self.tests.all_tests()).count()
            );
        }

        Ok(())
    }

    pub fn run(&self) -> Result<()> {
        let test_count = self.filter_tests(self.tests.all_tests()).count();
        let filtered_out = test_count.saturating_sub(self.tests.all_tests().count());

        let mut summary = TestSummary::new(test_count, filtered_out);
        summary.write_starting_msg()?;

        if test_count > 0 {
            let mut rng = ::rand::rngs::StdRng::from_seed(OsRng.gen());
            let mut swarm = self.factory.launch_swarm(1);

            // Run PublicUsageTests
            for test in self.filter_tests(self.tests.public_usage_tests.iter()) {
                let mut public_ctx = PublicUsageContext::new(
                    CoreContext::from_rng(&mut rng),
                    swarm.chain_info().into_public_info(),
                );
                let result = run_test(|| test.run(&mut public_ctx));
                summary.handle_result(test.name().to_owned(), result)?;
            }

            // Run AdminTests
            for test in self.filter_tests(self.tests.admin_tests.iter()) {
                let mut admin_ctx =
                    AdminContext::new(CoreContext::from_rng(&mut rng), swarm.chain_info());
                let result = run_test(|| test.run(&mut admin_ctx));
                summary.handle_result(test.name().to_owned(), result)?;
            }

            for test in self.filter_tests(self.tests.network_tests.iter()) {
                let report = TestReport::new();
                let mut network_ctx =
                    NetworkContext::new(CoreContext::from_rng(&mut rng), &mut *swarm, report);
                let result = run_test(|| test.run(&mut network_ctx));
                summary.handle_result(test.name().to_owned(), result)?;
            }
        }

        summary.write_summary()?;

        if summary.success() {
            Ok(())
        } else {
            Err(anyhow::anyhow!("Tests Failed"))
        }
    }

    fn filter_tests<'a, T: Test, I: Iterator<Item = T> + 'a>(
        &'a self,
        tests: I,
    ) -> impl Iterator<Item = T> + 'a {
        tests
            // Filter by ignored
            .filter(
                move |test| match (self.options.include_ignored, self.options.ignored) {
                    (true, _) => true, // Don't filter anything
                    (false, true) => test.ignored(),
                    (false, false) => !test.ignored(),
                },
            )
            // Filter by test name
            .filter(move |test| {
                if let Some(filter) = &self.options.filter {
                    if self.options.filter_exact {
                        test.name() == &filter[..]
                    } else {
                        test.name().contains(&filter[..])
                    }
                } else {
                    true
                }
            })
    }
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_test<F: FnOnce() -> Result<()>>(f: F) -> TestResult {
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) {
        Ok(Ok(())) => TestResult::Ok,
        Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
        Err(_) => TestResult::Failed,
    }
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}
<commit_msg>forge: add initial_validator_count parameter to ForgeConfig<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::*;
use rand::{Rng, SeedableRng};
use std::{
    io::{self, Write},
    num::NonZeroUsize,
    process,
};
use structopt::{clap::arg_enum, StructOpt};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
// TODO going to remove random seed once cluster deployment supports re-run genesis
use rand::rngs::OsRng;

#[derive(Debug, StructOpt)]
#[structopt(about = "Forged in Fire")]
pub struct Options {
    /// The FILTER string is tested against the name of all tests, and only those tests whose names
    /// contain the filter are run.
    filter: Option<String>,
    #[structopt(long = "exact")]
    /// Exactly match filters rather than by substring
    filter_exact: bool,
    #[structopt(long, default_value = "1", env = "RUST_TEST_THREADS")]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    /// Number of threads used for running tests in parallel
    test_threads: NonZeroUsize,
    #[structopt(short = "q", long)]
    /// Output minimal information
    quiet: bool,
    #[structopt(long)]
    /// NO-OP: unsupported option, exists for compatibility with the default test harness
    nocapture: bool,
    #[structopt(long)]
    /// List all tests
    list: bool,
    #[structopt(long)]
    /// List or run ignored tests
    ignored: bool,
    #[structopt(long)]
    /// Include ignored tests when listing or running tests
    include_ignored: bool,
    /// Configure formatting of output:
    ///   pretty = Print verbose output;
    ///   terse = Display one character per test;
    ///   (json is unsupported, exists for compatibility with the default test harness)
    #[structopt(long, possible_values = &Format::variants(), default_value, case_insensitive = true)]
    format: Format,
}

impl Options {
    pub fn from_args() -> Self {
        StructOpt::from_args()
    }
}

arg_enum! {
    #[derive(Debug, Eq, PartialEq)]
    pub enum Format {
        Pretty,
        Terse,
        Json,
    }
}

impl Default for Format {
    fn default() -> Self {
        Format::Pretty
    }
}

pub fn forge_main<F: Factory>(tests: ForgeConfig<'_>, factory: F, options: &Options) -> Result<()> {
    let forge = Forge::new(options, tests, factory);

    if options.list {
        forge.list()?;

        return Ok(());
    }

    match forge.run() {
        Ok(()) => Ok(()),
        Err(_) => process::exit(101), // Exit with a non-zero exit code if tests failed
    }
}

pub struct ForgeConfig<'cfg> {
    public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    admin_tests: &'cfg [&'cfg dyn AdminTest],
    network_tests: &'cfg [&'cfg dyn NetworkTest],

    /// The initial number of validators to spawn when the test harness creates a swarm
    initial_validator_count: NonZeroUsize,
}

impl<'cfg> ForgeConfig<'cfg> {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_public_usage_tests(
        mut self,
        public_usage_tests: &'cfg [&'cfg dyn PublicUsageTest],
    ) -> Self {
        self.public_usage_tests = public_usage_tests;
        self
    }

    pub fn with_admin_tests(mut self, admin_tests: &'cfg [&'cfg dyn AdminTest]) -> Self {
        self.admin_tests = admin_tests;
        self
    }

    pub fn with_network_tests(mut self, network_tests: &'cfg [&'cfg dyn NetworkTest]) -> Self {
        self.network_tests = network_tests;
        self
    }

    pub fn with_initial_validator_count(mut self, initial_validator_count: NonZeroUsize) -> Self {
        self.initial_validator_count = initial_validator_count;
        self
    }

    pub fn number_of_tests(&self) -> usize {
        self.public_usage_tests.len() + self.admin_tests.len() + self.network_tests.len()
    }

    pub fn all_tests(&self) -> impl Iterator<Item = &'cfg dyn Test> + 'cfg {
        self.public_usage_tests
            .iter()
            .map(|t| t as &dyn Test)
            .chain(self.admin_tests.iter().map(|t| t as &dyn Test))
            .chain(self.network_tests.iter().map(|t| t as &dyn Test))
    }
}

impl<'cfg> Default for ForgeConfig<'cfg> {
    fn default() -> Self {
        Self {
            public_usage_tests: &[],
            admin_tests: &[],
            network_tests: &[],
            initial_validator_count: NonZeroUsize::new(1).unwrap(),
        }
    }
}

pub struct Forge<'cfg, F> {
    options: &'cfg Options,
    tests: ForgeConfig<'cfg>,
    factory: F,
}

impl<'cfg, F: Factory> Forge<'cfg, F> {
    pub fn new(options: &'cfg Options, tests: ForgeConfig<'cfg>, factory: F) -> Self {
        Self {
            options,
            tests,
            factory,
        }
    }

    pub fn list(&self) -> Result<()> {
        for test in self.filter_tests(self.tests.all_tests()) {
            println!("{}: test", test.name());
        }

        if self.options.format == Format::Pretty {
            println!();
            println!(
                "{} tests",
                self.filter_tests(self.tests.all_tests()).count()
            );
        }

        Ok(())
    }

    pub fn run(&self) -> Result<()> {
        let test_count = self.filter_tests(self.tests.all_tests()).count();
        let filtered_out = test_count.saturating_sub(self.tests.all_tests().count());

        let mut summary = TestSummary::new(test_count, filtered_out);
        summary.write_starting_msg()?;

        if test_count > 0 {
            let mut rng = ::rand::rngs::StdRng::from_seed(OsRng.gen());
            let mut swarm = self
                .factory
                .launch_swarm(self.tests.initial_validator_count.get());

            // Run PublicUsageTests
            for test in self.filter_tests(self.tests.public_usage_tests.iter()) {
                let mut public_ctx = PublicUsageContext::new(
                    CoreContext::from_rng(&mut rng),
                    swarm.chain_info().into_public_info(),
                );
                let result = run_test(|| test.run(&mut public_ctx));
                summary.handle_result(test.name().to_owned(), result)?;
            }

            // Run AdminTests
            for test in self.filter_tests(self.tests.admin_tests.iter()) {
                let mut admin_ctx =
                    AdminContext::new(CoreContext::from_rng(&mut rng), swarm.chain_info());
                let result = run_test(|| test.run(&mut admin_ctx));
                summary.handle_result(test.name().to_owned(), result)?;
            }

            for test in self.filter_tests(self.tests.network_tests.iter()) {
                let report = TestReport::new();
                let mut network_ctx =
                    NetworkContext::new(CoreContext::from_rng(&mut rng), &mut *swarm, report);
                let result = run_test(|| test.run(&mut network_ctx));
                summary.handle_result(test.name().to_owned(), result)?;
            }
        }

        summary.write_summary()?;

        if summary.success() {
            Ok(())
        } else {
            Err(anyhow::anyhow!("Tests Failed"))
        }
    }

    fn filter_tests<'a, T: Test, I: Iterator<Item = T> + 'a>(
        &'a self,
        tests: I,
    ) -> impl Iterator<Item = T> + 'a {
        tests
            // Filter by ignored
            .filter(
                move |test| match (self.options.include_ignored, self.options.ignored) {
                    (true, _) => true, // Don't filter anything
                    (false, true) => test.ignored(),
                    (false, false) => !test.ignored(),
                },
            )
            // Filter by test name
            .filter(move |test| {
                if let Some(filter) = &self.options.filter {
                    if self.options.filter_exact {
                        test.name() == &filter[..]
                    } else {
                        test.name().contains(&filter[..])
                    }
                } else {
                    true
                }
            })
    }
}

enum TestResult {
    Ok,
    Failed,
    FailedWithMsg(String),
}

fn run_test<F: FnOnce() -> Result<()>>(f: F) -> TestResult {
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) {
        Ok(Ok(())) => TestResult::Ok,
        Ok(Err(e)) => TestResult::FailedWithMsg(format!("{:?}", e)),
        Err(_) => TestResult::Failed,
    }
}

struct TestSummary {
    stdout: StandardStream,
    total: usize,
    filtered_out: usize,
    passed: usize,
    failed: Vec<String>,
}

impl TestSummary {
    fn new(total: usize, filtered_out: usize) -> Self {
        Self {
            stdout: StandardStream::stdout(ColorChoice::Auto),
            total,
            filtered_out,
            passed: 0,
            failed: Vec::new(),
        }
    }

    fn handle_result(&mut self, name: String, result: TestResult) -> io::Result<()> {
        write!(self.stdout, "test {} ... ", name)?;
        match result {
            TestResult::Ok => {
                self.passed += 1;
                self.write_ok()?;
            }
            TestResult::Failed => {
                self.failed.push(name);
                self.write_failed()?;
            }
            TestResult::FailedWithMsg(msg) => {
                self.failed.push(name);
                self.write_failed()?;
                writeln!(self.stdout)?;

                write!(self.stdout, "Error: {}", msg)?;
            }
        }
        writeln!(self.stdout)?;
        Ok(())
    }

    fn write_ok(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
        write!(self.stdout, "ok")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_failed(&mut self) -> io::Result<()> {
        self.stdout
            .set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(self.stdout, "FAILED")?;
        self.stdout.reset()?;
        Ok(())
    }

    fn write_starting_msg(&mut self) -> io::Result<()> {
        writeln!(self.stdout)?;
        writeln!(
            self.stdout,
            "running {} tests",
            self.total - self.filtered_out
        )?;
        Ok(())
    }

    fn write_summary(&mut self) -> io::Result<()> {
        // Print out the failing tests
        if !self.failed.is_empty() {
            writeln!(self.stdout)?;
            writeln!(self.stdout, "failures:")?;
            for name in &self.failed {
                writeln!(self.stdout, "    {}", name)?;
            }
        }

        writeln!(self.stdout)?;
        write!(self.stdout, "test result: ")?;
        if self.failed.is_empty() {
            self.write_ok()?;
        } else {
            self.write_failed()?;
        }
        writeln!(
            self.stdout,
            ". {} passed; {} failed; {} filtered out",
            self.passed,
            self.failed.len(),
            self.filtered_out
        )?;
        writeln!(self.stdout)?;
        Ok(())
    }

    fn success(&self) -> bool {
        self.failed.is_empty()
    }
}
<|endoftext|>


<commit_before>//! Semantic Tokens helpers

use std::ops;

use lsp_types::{
    Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens,
    SemanticTokensEdit,
};

macro_rules! define_semantic_token_types {
    ($(($ident:ident, $string:literal)),*$(,)?) => {
        $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)*

        pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[
            SemanticTokenType::CLASS,
            SemanticTokenType::COMMENT,
            SemanticTokenType::ENUM_MEMBER,
            SemanticTokenType::ENUM,
            SemanticTokenType::FUNCTION,
            SemanticTokenType::INTERFACE,
            SemanticTokenType::KEYWORD,
            SemanticTokenType::MACRO,
            SemanticTokenType::METHOD,
            SemanticTokenType::NAMESPACE,
            SemanticTokenType::NUMBER,
            SemanticTokenType::OPERATOR,
            SemanticTokenType::PARAMETER,
            SemanticTokenType::PROPERTY,
            SemanticTokenType::REGEXP,
            SemanticTokenType::STRING,
            SemanticTokenType::STRUCT,
            SemanticTokenType::TYPE_PARAMETER,
            SemanticTokenType::TYPE,
            SemanticTokenType::VARIABLE,
            $($ident),*
        ];
    };
}

define_semantic_token_types![
    (ANGLE, "angle"),
    (ARITHMETIC, "arithmetic"),
    (ATTRIBUTE_BRACKET, "attributeBracket"),
    (BITWISE, "bitwise"),
    (BOOLEAN, "boolean"),
    (BRACE, "brace"),
    (BRACKET, "bracket"),
    (BUILTIN_ATTRIBUTE, "builtinAttribute"),
    (BUILTIN_TYPE, "builtinType"),
    (CHAR, "character"),
    (COLON, "colon"),
    (COMMA, "comma"),
    (COMPARISON, "comparison"),
    (CONST_PARAMETER, "constParameter"),
    (DERIVE, "derive"),
    (DERIVE_HELPER, "deriveHelper"),
    (DOT, "dot"),
    (ESCAPE_SEQUENCE, "escapeSequence"),
    (FORMAT_SPECIFIER, "formatSpecifier"),
    (GENERIC, "generic"),
    (LABEL, "label"),
    (LIFETIME, "lifetime"),
    (LOGICAL, "logical"),
    (MACRO_BANG, "macroBang"),
    (PARENTHESIS, "parenthesis"),
    (PUNCTUATION, "punctuation"),
    (SELF_KEYWORD, "selfKeyword"),
    (SELF_TYPE_KEYWORD, "selfTypeKeyword"),
    (SEMICOLON, "semicolon"),
    (TYPE_ALIAS, "typeAlias"),
    (TOOL_MODULE, "toolModule"),
    (UNION, "union"),
    (UNRESOLVED_REFERENCE, "unresolvedReference"),
];

macro_rules! define_semantic_token_modifiers {
    ($(($ident:ident, $string:literal)),*$(,)?) => {
        $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)*

        pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[
            SemanticTokenModifier::DOCUMENTATION,
            SemanticTokenModifier::DECLARATION,
            SemanticTokenModifier::STATIC,
            SemanticTokenModifier::DEFAULT_LIBRARY,
            $($ident),*
        ];
    };
}

define_semantic_token_modifiers![
    (ASYNC, "async"),
    (ATTRIBUTE_MODIFIER, "attribute"),
    (CALLABLE, "callable"),
    (CONSTANT, "constant"),
    (CONSUMING, "consuming"),
    (CONTROL_FLOW, "controlFlow"),
    (CRATE_ROOT, "crateRoot"),
    (INJECTED, "injected"),
    (INTRA_DOC_LINK, "intraDocLink"),
    (LIBRARY, "library"),
    (MUTABLE, "mutable"),
    (PUBLIC, "public"),
    (REFERENCE, "reference"),
    (TRAIT_MODIFIER, "trait"),
    (UNSAFE, "unsafe"),
];

#[derive(Default)]
pub(crate) struct ModifierSet(pub(crate) u32);

impl ops::BitOrAssign<SemanticTokenModifier> for ModifierSet {
    fn bitor_assign(&mut self, rhs: SemanticTokenModifier) {
        let idx = SUPPORTED_MODIFIERS.iter().position(|it| it == &rhs).unwrap();
        self.0 |= 1 << idx;
    }
}

/// Tokens are encoded relative to each other.
///
/// This is a direct port of <https://github.com/microsoft/vscode-languageserver-node/blob/f425af9de46a0187adb78ec8a46b9b2ce80c5412/server/src/sematicTokens.proposed.ts#L45>
pub(crate) struct SemanticTokensBuilder {
    id: String,
    prev_line: u32,
    prev_char: u32,
    data: Vec<SemanticToken>,
}

impl SemanticTokensBuilder {
    pub(crate) fn new(id: String) -> Self {
        SemanticTokensBuilder { id, prev_line: 0, prev_char: 0, data: Default::default() }
    }

    /// Push a new token onto the builder
    pub(crate) fn push(&mut self, range: Range, token_index: u32, modifier_bitset: u32) {
        let mut push_line = range.start.line as u32;
        let mut push_char = range.start.character as u32;

        if !self.data.is_empty() {
            push_line -= self.prev_line;
            if push_line == 0 {
                push_char -= self.prev_char;
            }
        }

        // A token cannot be multiline
        let token_len = range.end.character - range.start.character;

        let token = SemanticToken {
            delta_line: push_line,
            delta_start: push_char,
            length: token_len as u32,
            token_type: token_index,
            token_modifiers_bitset: modifier_bitset,
        };

        self.data.push(token);

        self.prev_line = range.start.line as u32;
        self.prev_char = range.start.character as u32;
    }

    pub(crate) fn build(self) -> SemanticTokens {
        SemanticTokens { result_id: Some(self.id), data: self.data }
    }
}

pub(crate) fn diff_tokens(old: &[SemanticToken], new: &[SemanticToken]) -> Vec<SemanticTokensEdit> {
    let offset = new.iter().zip(old.iter()).take_while(|&(n, p)| n == p).count();

    let (_, old) = old.split_at(offset);
    let (_, new) = new.split_at(offset);

    let offset_from_end =
        new.iter().rev().zip(old.iter().rev()).take_while(|&(n, p)| n == p).count();

    let (old, _) = old.split_at(old.len() - offset_from_end);
    let (new, _) = new.split_at(new.len() - offset_from_end);

    if old.is_empty() && new.is_empty() {
        vec![]
    } else {
        // The lsp data field is actually a byte-diff but we
        // travel in tokens so `start` and `delete_count` are in multiples of the
        // serialized size of `SemanticToken`.
        vec![SemanticTokensEdit {
            start: 5 * offset as u32,
            delete_count: 5 * old.len() as u32,
            data: Some(new.into()),
        }]
    }
}

pub(crate) fn type_index(ty: SemanticTokenType) -> u32 {
    SUPPORTED_TYPES.iter().position(|it| *it == ty).unwrap() as u32
}

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

    fn from(t: (u32, u32, u32, u32, u32)) -> SemanticToken {
        SemanticToken {
            delta_line: t.0,
            delta_start: t.1,
            length: t.2,
            token_type: t.3,
            token_modifiers_bitset: t.4,
        }
    }

    #[test]
    fn test_diff_insert_at_end() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(
            edits[0],
            SemanticTokensEdit {
                start: 10,
                delete_count: 0,
                data: Some(vec![from((11, 12, 13, 14, 15))])
            }
        );
    }

    #[test]
    fn test_diff_insert_at_beginning() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(
            edits[0],
            SemanticTokensEdit {
                start: 0,
                delete_count: 0,
                data: Some(vec![from((11, 12, 13, 14, 15))])
            }
        );
    }

    #[test]
    fn test_diff_insert_in_middle() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [
            from((1, 2, 3, 4, 5)),
            from((10, 20, 30, 40, 50)),
            from((60, 70, 80, 90, 100)),
            from((6, 7, 8, 9, 10)),
        ];

        let edits = diff_tokens(&before, &after);
        assert_eq!(
            edits[0],
            SemanticTokensEdit {
                start: 5,
                delete_count: 0,
                data: Some(vec![from((10, 20, 30, 40, 50)), from((60, 70, 80, 90, 100))])
            }
        );
    }

    #[test]
    fn test_diff_remove_from_end() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(edits[0], SemanticTokensEdit { start: 10, delete_count: 5, data: Some(vec![]) });
    }

    #[test]
    fn test_diff_remove_from_beginning() {
        let before = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(edits[0], SemanticTokensEdit { start: 0, delete_count: 5, data: Some(vec![]) });
    }

    #[test]
    fn test_diff_remove_from_middle() {
        let before = [
            from((1, 2, 3, 4, 5)),
            from((10, 20, 30, 40, 50)),
            from((60, 70, 80, 90, 100)),
            from((6, 7, 8, 9, 10)),
        ];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(edits[0], SemanticTokensEdit { start: 5, delete_count: 10, data: Some(vec![]) });
    }
}
<commit_msg>Register decorator token type to avoid panic<commit_after>//! Semantic Tokens helpers

use std::ops;

use lsp_types::{
    Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens,
    SemanticTokensEdit,
};

macro_rules! define_semantic_token_types {
    ($(($ident:ident, $string:literal)),*$(,)?) => {
        $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)*

        pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[
            SemanticTokenType::CLASS,
            SemanticTokenType::COMMENT,
            SemanticTokenType::ENUM_MEMBER,
            SemanticTokenType::ENUM,
            SemanticTokenType::FUNCTION,
            SemanticTokenType::INTERFACE,
            SemanticTokenType::KEYWORD,
            SemanticTokenType::MACRO,
            SemanticTokenType::METHOD,
            SemanticTokenType::NAMESPACE,
            SemanticTokenType::NUMBER,
            SemanticTokenType::OPERATOR,
            SemanticTokenType::PARAMETER,
            SemanticTokenType::PROPERTY,
            SemanticTokenType::REGEXP,
            SemanticTokenType::STRING,
            SemanticTokenType::STRUCT,
            SemanticTokenType::TYPE_PARAMETER,
            SemanticTokenType::TYPE,
            SemanticTokenType::VARIABLE,
            SemanticTokenType::DECORATOR,
            $($ident),*
        ];
    };
}

define_semantic_token_types![
    (ANGLE, "angle"),
    (ARITHMETIC, "arithmetic"),
    (ATTRIBUTE_BRACKET, "attributeBracket"),
    (BITWISE, "bitwise"),
    (BOOLEAN, "boolean"),
    (BRACE, "brace"),
    (BRACKET, "bracket"),
    (BUILTIN_ATTRIBUTE, "builtinAttribute"),
    (BUILTIN_TYPE, "builtinType"),
    (CHAR, "character"),
    (COLON, "colon"),
    (COMMA, "comma"),
    (COMPARISON, "comparison"),
    (CONST_PARAMETER, "constParameter"),
    (DERIVE, "derive"),
    (DERIVE_HELPER, "deriveHelper"),
    (DOT, "dot"),
    (ESCAPE_SEQUENCE, "escapeSequence"),
    (FORMAT_SPECIFIER, "formatSpecifier"),
    (GENERIC, "generic"),
    (LABEL, "label"),
    (LIFETIME, "lifetime"),
    (LOGICAL, "logical"),
    (MACRO_BANG, "macroBang"),
    (PARENTHESIS, "parenthesis"),
    (PUNCTUATION, "punctuation"),
    (SELF_KEYWORD, "selfKeyword"),
    (SELF_TYPE_KEYWORD, "selfTypeKeyword"),
    (SEMICOLON, "semicolon"),
    (TYPE_ALIAS, "typeAlias"),
    (TOOL_MODULE, "toolModule"),
    (UNION, "union"),
    (UNRESOLVED_REFERENCE, "unresolvedReference"),
];

macro_rules! define_semantic_token_modifiers {
    ($(($ident:ident, $string:literal)),*$(,)?) => {
        $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)*

        pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[
            SemanticTokenModifier::DOCUMENTATION,
            SemanticTokenModifier::DECLARATION,
            SemanticTokenModifier::STATIC,
            SemanticTokenModifier::DEFAULT_LIBRARY,
            $($ident),*
        ];
    };
}

define_semantic_token_modifiers![
    (ASYNC, "async"),
    (ATTRIBUTE_MODIFIER, "attribute"),
    (CALLABLE, "callable"),
    (CONSTANT, "constant"),
    (CONSUMING, "consuming"),
    (CONTROL_FLOW, "controlFlow"),
    (CRATE_ROOT, "crateRoot"),
    (INJECTED, "injected"),
    (INTRA_DOC_LINK, "intraDocLink"),
    (LIBRARY, "library"),
    (MUTABLE, "mutable"),
    (PUBLIC, "public"),
    (REFERENCE, "reference"),
    (TRAIT_MODIFIER, "trait"),
    (UNSAFE, "unsafe"),
];

#[derive(Default)]
pub(crate) struct ModifierSet(pub(crate) u32);

impl ops::BitOrAssign<SemanticTokenModifier> for ModifierSet {
    fn bitor_assign(&mut self, rhs: SemanticTokenModifier) {
        let idx = SUPPORTED_MODIFIERS.iter().position(|it| it == &rhs).unwrap();
        self.0 |= 1 << idx;
    }
}

/// Tokens are encoded relative to each other.
///
/// This is a direct port of <https://github.com/microsoft/vscode-languageserver-node/blob/f425af9de46a0187adb78ec8a46b9b2ce80c5412/server/src/sematicTokens.proposed.ts#L45>
pub(crate) struct SemanticTokensBuilder {
    id: String,
    prev_line: u32,
    prev_char: u32,
    data: Vec<SemanticToken>,
}

impl SemanticTokensBuilder {
    pub(crate) fn new(id: String) -> Self {
        SemanticTokensBuilder { id, prev_line: 0, prev_char: 0, data: Default::default() }
    }

    /// Push a new token onto the builder
    pub(crate) fn push(&mut self, range: Range, token_index: u32, modifier_bitset: u32) {
        let mut push_line = range.start.line as u32;
        let mut push_char = range.start.character as u32;

        if !self.data.is_empty() {
            push_line -= self.prev_line;
            if push_line == 0 {
                push_char -= self.prev_char;
            }
        }

        // A token cannot be multiline
        let token_len = range.end.character - range.start.character;

        let token = SemanticToken {
            delta_line: push_line,
            delta_start: push_char,
            length: token_len as u32,
            token_type: token_index,
            token_modifiers_bitset: modifier_bitset,
        };

        self.data.push(token);

        self.prev_line = range.start.line as u32;
        self.prev_char = range.start.character as u32;
    }

    pub(crate) fn build(self) -> SemanticTokens {
        SemanticTokens { result_id: Some(self.id), data: self.data }
    }
}

pub(crate) fn diff_tokens(old: &[SemanticToken], new: &[SemanticToken]) -> Vec<SemanticTokensEdit> {
    let offset = new.iter().zip(old.iter()).take_while(|&(n, p)| n == p).count();

    let (_, old) = old.split_at(offset);
    let (_, new) = new.split_at(offset);

    let offset_from_end =
        new.iter().rev().zip(old.iter().rev()).take_while(|&(n, p)| n == p).count();

    let (old, _) = old.split_at(old.len() - offset_from_end);
    let (new, _) = new.split_at(new.len() - offset_from_end);

    if old.is_empty() && new.is_empty() {
        vec![]
    } else {
        // The lsp data field is actually a byte-diff but we
        // travel in tokens so `start` and `delete_count` are in multiples of the
        // serialized size of `SemanticToken`.
        vec![SemanticTokensEdit {
            start: 5 * offset as u32,
            delete_count: 5 * old.len() as u32,
            data: Some(new.into()),
        }]
    }
}

pub(crate) fn type_index(ty: SemanticTokenType) -> u32 {
    SUPPORTED_TYPES.iter().position(|it| *it == ty).unwrap() as u32
}

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

    fn from(t: (u32, u32, u32, u32, u32)) -> SemanticToken {
        SemanticToken {
            delta_line: t.0,
            delta_start: t.1,
            length: t.2,
            token_type: t.3,
            token_modifiers_bitset: t.4,
        }
    }

    #[test]
    fn test_diff_insert_at_end() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(
            edits[0],
            SemanticTokensEdit {
                start: 10,
                delete_count: 0,
                data: Some(vec![from((11, 12, 13, 14, 15))])
            }
        );
    }

    #[test]
    fn test_diff_insert_at_beginning() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(
            edits[0],
            SemanticTokensEdit {
                start: 0,
                delete_count: 0,
                data: Some(vec![from((11, 12, 13, 14, 15))])
            }
        );
    }

    #[test]
    fn test_diff_insert_in_middle() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [
            from((1, 2, 3, 4, 5)),
            from((10, 20, 30, 40, 50)),
            from((60, 70, 80, 90, 100)),
            from((6, 7, 8, 9, 10)),
        ];

        let edits = diff_tokens(&before, &after);
        assert_eq!(
            edits[0],
            SemanticTokensEdit {
                start: 5,
                delete_count: 0,
                data: Some(vec![from((10, 20, 30, 40, 50)), from((60, 70, 80, 90, 100))])
            }
        );
    }

    #[test]
    fn test_diff_remove_from_end() {
        let before = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10)), from((11, 12, 13, 14, 15))];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(edits[0], SemanticTokensEdit { start: 10, delete_count: 5, data: Some(vec![]) });
    }

    #[test]
    fn test_diff_remove_from_beginning() {
        let before = [from((11, 12, 13, 14, 15)), from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(edits[0], SemanticTokensEdit { start: 0, delete_count: 5, data: Some(vec![]) });
    }

    #[test]
    fn test_diff_remove_from_middle() {
        let before = [
            from((1, 2, 3, 4, 5)),
            from((10, 20, 30, 40, 50)),
            from((60, 70, 80, 90, 100)),
            from((6, 7, 8, 9, 10)),
        ];
        let after = [from((1, 2, 3, 4, 5)), from((6, 7, 8, 9, 10))];

        let edits = diff_tokens(&before, &after);
        assert_eq!(edits[0], SemanticTokensEdit { start: 5, delete_count: 10, data: Some(vec![]) });
    }
}
<|endoftext|>


<commit_before>//! Highlights the files given on the command line, in parallel.
//! Prints the highlighted output to stdout.

#[macro_use] extern crate lazy_static;
extern crate rayon;
extern crate syntect;

use syntect::parsing::SyntaxSet;
use syntect::highlighting::{ThemeSet, Style};
use syntect::easy::HighlightFile;
use rayon::prelude::*;

use std::fs::File;
use std::io::{BufReader, BufRead};

thread_local! {
    static SYNTAX_SET: SyntaxSet = SyntaxSet::load_defaults_newlines();
}

lazy_static! {
    static ref THEME_SET: ThemeSet = ThemeSet::load_defaults();
}

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

    if files.is_empty() {
        println!("Please provide some files to highlight.");
        return;
    }

    // We first collect the contents of the files...
    let contents: Vec<Vec<String>> = files.par_iter()
        .map(|filename| {
            let mut lines = Vec::new();
            // We use `String::new()` and `read_line()` instead of `BufRead::lines()`
            // in order to preserve the newlines and get better highlighting.
            let mut line = String::new();
            let mut reader = BufReader::new(File::open(filename).unwrap());
            while reader.read_line(&mut line).unwrap() > 0 {
                lines.push(line);
                line = String::new();
            }
            lines
        })
        .collect();

    // ...so that the highlighted regions have valid lifetimes...
    let regions: Vec<Vec<(Style, &str)>> = files.par_iter()
        .zip(&contents)
        .map(|(filename, contents)| {
            SYNTAX_SET.with(|ss| {
                let mut regions = Vec::new();
                let theme = &THEME_SET.themes["base16-ocean.dark"];
                let mut highlighter = HighlightFile::new(filename, ss, theme).unwrap();

                for line in contents {
                    for region in highlighter.highlight_lines.highlight(line) {
                        regions.push(region);
                    }
                }

                regions
            })
        })
        .collect();

    // ...and then print them all out.
    for file_regions in regions {
        print!("{}", syntect::util::as_24_bit_terminal_escaped(&file_regions[..], true));
    }
}
<commit_msg>Simplify parsyncat example now that SyntaxSet is Send + Sync<commit_after>//! Highlights the files given on the command line, in parallel.
//! Prints the highlighted output to stdout.

extern crate rayon;
extern crate syntect;

use syntect::parsing::SyntaxSet;
use syntect::highlighting::{ThemeSet, Style};
use syntect::easy::HighlightFile;
use rayon::prelude::*;

use std::fs::File;
use std::io::{BufReader, BufRead};

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

    if files.is_empty() {
        println!("Please provide some files to highlight.");
        return;
    }

    let syntax_set = SyntaxSet::load_defaults_newlines();
    let theme_set = ThemeSet::load_defaults();

    // We first collect the contents of the files...
    let contents: Vec<Vec<String>> = files.par_iter()
        .map(|filename| {
            let mut lines = Vec::new();
            // We use `String::new()` and `read_line()` instead of `BufRead::lines()`
            // in order to preserve the newlines and get better highlighting.
            let mut line = String::new();
            let mut reader = BufReader::new(File::open(filename).unwrap());
            while reader.read_line(&mut line).unwrap() > 0 {
                lines.push(line);
                line = String::new();
            }
            lines
        })
        .collect();

    // ...so that the highlighted regions have valid lifetimes...
    let regions: Vec<Vec<(Style, &str)>> = files.par_iter()
        .zip(&contents)
        .map(|(filename, contents)| {
            let mut regions = Vec::new();
            let theme = &theme_set.themes["base16-ocean.dark"];
            let mut highlighter = HighlightFile::new(filename, &syntax_set, theme).unwrap();

            for line in contents {
                for region in highlighter.highlight_lines.highlight(line) {
                    regions.push(region);
                }
            }

            regions
        })
        .collect();

    // ...and then print them all out.
    for file_regions in regions {
        print!("{}", syntect::util::as_24_bit_terminal_escaped(&file_regions[..], true));
    }
}
<|endoftext|>


<commit_before>mod support;

use std::{
    collections::HashMap,
    time::Instant,
};

use lsp_types::{
    CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, DidOpenTextDocumentParams, TextDocumentItem, TextDocumentPositionParams
};
use ra_lsp_server::req::{
    CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion,
    DidOpenTextDocument, OnEnter,
};
use serde_json::json;
use tempfile::TempDir;

use crate::support::{project, Project};

const LOG: &'static str = "";
const PROFILE: &'static str = "*@3>100";

#[test]
fn completes_items_from_standard_library() {
    let project_start = Instant::now();
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
use std::collections::Spam;
"#,
    );
    server.wait_until_workspace_is_loaded();
    eprintln!("loading took    {:?}", project_start.elapsed());
    let completion_start = Instant::now();
    let res = server.send_request::<Completion>(CompletionParams {
        text_document: server.doc_id("src/lib.rs"),
        context: None,
        position: Position::new(0, 23),
    });
    assert!(format!("{}", res).contains("HashMap"));
    eprintln!("completion took {:?}", completion_start.elapsed());
}

#[test]
fn test_runnables_no_project() {
    let server = project(
        r"
//- lib.rs
#[test]
fn foo() {
}
",
    );
    server.wait_until_workspace_is_loaded();
    server.request::<Runnables>(
        RunnablesParams { text_document: server.doc_id("lib.rs"), position: None },
        json!([
          {
            "args": [ "test", "--", "foo", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "cwd": null,
            "label": "test foo",
            "range": {
              "end": { "character": 1, "line": 2 },
              "start": { "character": 0, "line": 0 }
            }
          },
          {
            "args": [
              "check",
              "--all"
            ],
            "bin": "cargo",
            "env": {},
            "cwd": null,
            "label": "cargo check --all",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]),
    );
}

#[test]
fn test_runnables_project() {
    let code = r#"
//- foo/Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- foo/src/lib.rs
pub fn foo() {}

//- foo/tests/spam.rs
#[test]
fn test_eggs() {}

//- bar/Cargo.toml
[package]
name = "bar"
version = "0.0.0"

//- bar/src/main.rs
fn main() {}
"#;

    let server = Project::with_fixture(code).root("foo").root("bar").server();

    server.wait_until_workspace_is_loaded();
    server.request::<Runnables>(
        RunnablesParams {
            text_document: server.doc_id("foo/tests/spam.rs"),
            position: None,
        },
        json!([
          {
            "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "label": "test test_eggs",
            "range": {
              "end": { "character": 17, "line": 1 },
              "start": { "character": 0, "line": 0 }
            },
            "cwd": server.path().join("foo")
          },
          {
            "args": [
              "check",
              "--package",
              "foo",
              "--test",
              "spam"
            ],
            "bin": "cargo",
            "env": {},
            "cwd": server.path().join("foo"),
            "label": "cargo check -p foo",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ])
    );
}

#[test]
fn test_format_document() {
    let server = project(
        r#"
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {
}

pub use std::collections::HashMap;
"#,
    );
    server.wait_until_workspace_is_loaded();

    server.request::<Formatting>(
        DocumentFormattingParams {
            text_document: server.doc_id("src/lib.rs"),
            options: FormattingOptions {
                tab_size: 4,
                insert_spaces: false,
                properties: HashMap::new(),
            },
        },
        json!([
            {
                "newText": r#"mod bar;

fn main() {}

pub use std::collections::HashMap;
"#,
                "range": {
                    "end": {
                        "character": 0,
                        "line": 6
                    },
                    "start": {
                        "character": 0,
                        "line": 0
                    }
                }
            }
        ]),
    );
}

#[test]
fn test_missing_module_code_action() {
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {}
"#,
    );
    server.wait_until_workspace_is_loaded();
    let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None };
    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(0, 4), Position::new(0, 7)),
            context: empty_context(),
        },
        json!([
          {
            "command": {
              "arguments": [
                {
                  "cursorPosition": null,
                  "label": "create module",
                  "workspaceEdit": {
                    "documentChanges": [
                      {
                        "kind": "create",
                        "uri": "file:///[..]/src/bar.rs"
                      }
                    ]
                  }
                }
              ],
              "command": "rust-analyzer.applySourceChange",
              "title": "create module"
            },
            "title": "create module"
          }
        ]),
    );

    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(2, 4), Position::new(2, 7)),
            context: empty_context(),
        },
        json!([]),
    );
}

#[test]
fn test_missing_module_code_action_in_json_project() {
    let tmp_dir = TempDir::new().unwrap();

    let path = tmp_dir.path();

    let project = json!({
        "roots": [path],
        "crates": [ { "root_module": path.join("src/lib.rs"), "deps": [], "edition": "2015" } ]
    });

    let code = format!(
        r#"
//- rust-project.json
{PROJECT}

//- src/lib.rs
mod bar;

fn main() {{}}
"#,
        PROJECT = project.to_string(),
    );

    let server = Project::with_fixture(&code).tmp_dir(tmp_dir).server();

    server.wait_until_workspace_is_loaded();
    let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None };
    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(0, 4), Position::new(0, 7)),
            context: empty_context(),
        },
        json!([
          {
            "command": {
              "arguments": [
                {
                  "cursorPosition": null,
                  "label": "create module",
                  "workspaceEdit": {
                    "documentChanges": [
                      {
                        "kind": "create",
                        "uri": "file:///[..]/src/bar.rs"
                      }
                    ]
                  }
                }
              ],
              "command": "rust-analyzer.applySourceChange",
              "title": "create module"
            },
            "title": "create module"
          }
        ]),
    );

    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(2, 4), Position::new(2, 7)),
            context: empty_context(),
        },
        json!([]),
    );
}

#[test]
fn diagnostics_dont_block_typing() {
    let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
    let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
    let server = project(&format!(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
{}

{}

fn main() {{}}
"#,
        librs, libs
    ));
    server.wait_until_workspace_is_loaded();
    for i in 0..10 {
        server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
            text_document: TextDocumentItem {
                uri: server.doc_id(&format!("src/m{}.rs", i)).uri,
                language_id: "rust".to_string(),
                version: 0,
                text: "/// Docs\nfn foo() {}".to_string(),
            },
        });
    }
    let start = std::time::Instant::now();
    server.request::<OnEnter>(
        TextDocumentPositionParams {
            text_document: server.doc_id("src/m0.rs"),
            position: Position { line: 0, character: 5 },
        },
        json!({
          "cursorPosition": {
            "position": { "character": 4, "line": 1 },
            "textDocument": { "uri": "file:///[..]src/m0.rs" }
          },
          "label": "on enter",
          "workspaceEdit": {
            "documentChanges": [
              {
                "edits": [
                  {
                    "newText": "\n/// ",
                    "range": {
                      "end": { "character": 5, "line": 0 },
                      "start": { "character": 5, "line": 0 }
                    }
                  }
                ],
                "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null }
              }
            ]
          }
        }),
    );
    let elapsed = start.elapsed();
    assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed);
}
<commit_msg>silnce profiling in tests<commit_after>mod support;

use std::{
    collections::HashMap,
    time::Instant,
};

use lsp_types::{
    CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, DidOpenTextDocumentParams, TextDocumentItem, TextDocumentPositionParams
};
use ra_lsp_server::req::{
    CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion,
    DidOpenTextDocument, OnEnter,
};
use serde_json::json;
use tempfile::TempDir;

use crate::support::{project, Project};

const LOG: &'static str = "";
const PROFILE: &'static str = "";
// const PROFILE: &'static str = "*@3>100";

#[test]
fn completes_items_from_standard_library() {
    let project_start = Instant::now();
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
use std::collections::Spam;
"#,
    );
    server.wait_until_workspace_is_loaded();
    eprintln!("loading took    {:?}", project_start.elapsed());
    let completion_start = Instant::now();
    let res = server.send_request::<Completion>(CompletionParams {
        text_document: server.doc_id("src/lib.rs"),
        context: None,
        position: Position::new(0, 23),
    });
    assert!(format!("{}", res).contains("HashMap"));
    eprintln!("completion took {:?}", completion_start.elapsed());
}

#[test]
fn test_runnables_no_project() {
    let server = project(
        r"
//- lib.rs
#[test]
fn foo() {
}
",
    );
    server.wait_until_workspace_is_loaded();
    server.request::<Runnables>(
        RunnablesParams { text_document: server.doc_id("lib.rs"), position: None },
        json!([
          {
            "args": [ "test", "--", "foo", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "cwd": null,
            "label": "test foo",
            "range": {
              "end": { "character": 1, "line": 2 },
              "start": { "character": 0, "line": 0 }
            }
          },
          {
            "args": [
              "check",
              "--all"
            ],
            "bin": "cargo",
            "env": {},
            "cwd": null,
            "label": "cargo check --all",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]),
    );
}

#[test]
fn test_runnables_project() {
    let code = r#"
//- foo/Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- foo/src/lib.rs
pub fn foo() {}

//- foo/tests/spam.rs
#[test]
fn test_eggs() {}

//- bar/Cargo.toml
[package]
name = "bar"
version = "0.0.0"

//- bar/src/main.rs
fn main() {}
"#;

    let server = Project::with_fixture(code).root("foo").root("bar").server();

    server.wait_until_workspace_is_loaded();
    server.request::<Runnables>(
        RunnablesParams {
            text_document: server.doc_id("foo/tests/spam.rs"),
            position: None,
        },
        json!([
          {
            "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--nocapture" ],
            "bin": "cargo",
            "env": { "RUST_BACKTRACE": "short" },
            "label": "test test_eggs",
            "range": {
              "end": { "character": 17, "line": 1 },
              "start": { "character": 0, "line": 0 }
            },
            "cwd": server.path().join("foo")
          },
          {
            "args": [
              "check",
              "--package",
              "foo",
              "--test",
              "spam"
            ],
            "bin": "cargo",
            "env": {},
            "cwd": server.path().join("foo"),
            "label": "cargo check -p foo",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ])
    );
}

#[test]
fn test_format_document() {
    let server = project(
        r#"
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {
}

pub use std::collections::HashMap;
"#,
    );
    server.wait_until_workspace_is_loaded();

    server.request::<Formatting>(
        DocumentFormattingParams {
            text_document: server.doc_id("src/lib.rs"),
            options: FormattingOptions {
                tab_size: 4,
                insert_spaces: false,
                properties: HashMap::new(),
            },
        },
        json!([
            {
                "newText": r#"mod bar;

fn main() {}

pub use std::collections::HashMap;
"#,
                "range": {
                    "end": {
                        "character": 0,
                        "line": 6
                    },
                    "start": {
                        "character": 0,
                        "line": 0
                    }
                }
            }
        ]),
    );
}

#[test]
fn test_missing_module_code_action() {
    let server = project(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
mod bar;

fn main() {}
"#,
    );
    server.wait_until_workspace_is_loaded();
    let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None };
    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(0, 4), Position::new(0, 7)),
            context: empty_context(),
        },
        json!([
          {
            "command": {
              "arguments": [
                {
                  "cursorPosition": null,
                  "label": "create module",
                  "workspaceEdit": {
                    "documentChanges": [
                      {
                        "kind": "create",
                        "uri": "file:///[..]/src/bar.rs"
                      }
                    ]
                  }
                }
              ],
              "command": "rust-analyzer.applySourceChange",
              "title": "create module"
            },
            "title": "create module"
          }
        ]),
    );

    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(2, 4), Position::new(2, 7)),
            context: empty_context(),
        },
        json!([]),
    );
}

#[test]
fn test_missing_module_code_action_in_json_project() {
    let tmp_dir = TempDir::new().unwrap();

    let path = tmp_dir.path();

    let project = json!({
        "roots": [path],
        "crates": [ { "root_module": path.join("src/lib.rs"), "deps": [], "edition": "2015" } ]
    });

    let code = format!(
        r#"
//- rust-project.json
{PROJECT}

//- src/lib.rs
mod bar;

fn main() {{}}
"#,
        PROJECT = project.to_string(),
    );

    let server = Project::with_fixture(&code).tmp_dir(tmp_dir).server();

    server.wait_until_workspace_is_loaded();
    let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None };
    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(0, 4), Position::new(0, 7)),
            context: empty_context(),
        },
        json!([
          {
            "command": {
              "arguments": [
                {
                  "cursorPosition": null,
                  "label": "create module",
                  "workspaceEdit": {
                    "documentChanges": [
                      {
                        "kind": "create",
                        "uri": "file:///[..]/src/bar.rs"
                      }
                    ]
                  }
                }
              ],
              "command": "rust-analyzer.applySourceChange",
              "title": "create module"
            },
            "title": "create module"
          }
        ]),
    );

    server.request::<CodeActionRequest>(
        CodeActionParams {
            text_document: server.doc_id("src/lib.rs"),
            range: Range::new(Position::new(2, 4), Position::new(2, 7)),
            context: empty_context(),
        },
        json!([]),
    );
}

#[test]
fn diagnostics_dont_block_typing() {
    let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
    let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
    let server = project(&format!(
        r#"
//- Cargo.toml
[package]
name = "foo"
version = "0.0.0"

//- src/lib.rs
{}

{}

fn main() {{}}
"#,
        librs, libs
    ));
    server.wait_until_workspace_is_loaded();
    for i in 0..10 {
        server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
            text_document: TextDocumentItem {
                uri: server.doc_id(&format!("src/m{}.rs", i)).uri,
                language_id: "rust".to_string(),
                version: 0,
                text: "/// Docs\nfn foo() {}".to_string(),
            },
        });
    }
    let start = std::time::Instant::now();
    server.request::<OnEnter>(
        TextDocumentPositionParams {
            text_document: server.doc_id("src/m0.rs"),
            position: Position { line: 0, character: 5 },
        },
        json!({
          "cursorPosition": {
            "position": { "character": 4, "line": 1 },
            "textDocument": { "uri": "file:///[..]src/m0.rs" }
          },
          "label": "on enter",
          "workspaceEdit": {
            "documentChanges": [
              {
                "edits": [
                  {
                    "newText": "\n/// ",
                    "range": {
                      "end": { "character": 5, "line": 0 },
                      "start": { "character": 5, "line": 0 }
                    }
                  }
                ],
                "textDocument": { "uri": "file:///[..]src/m0.rs", "version": null }
              }
            ]
          }
        }),
    );
    let elapsed = start.elapsed();
    assert!(elapsed.as_millis() < 2000, "typing enter took {:?}", elapsed);
}
<|endoftext|>


<commit_before>#[link(name="cat", vers="1.0.0", author="Seldaek")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern mod extra;

use std::os;
use std::io::{stdin, stderr, stdout, Writer, Reader};
use extra::getopts::groups;

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("A", "show-all", "equivalent to -vET"),
        groups::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        groups::optflag("e", "", "equivalent to -vE"),
        groups::optflag("E", "show-ends", "display $ at end of each line"),
        groups::optflag("n", "number", "number all output lines"),
        groups::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        groups::optflag("t", "", "equivalent to -vT"),
        groups::optflag("T", "show-tabs", "display TAB characters as ^I"),
        groups::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            stderr().write_line("Invalid options");
            stderr().write_line(f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };
    if matches.opt_present("help") {
        println("cat 1.0.0");
        println("");
        println("Usage:");
        println(format!("  {0:s} [OPTION]... [FILE]...", program));
        println("");
        print(groups::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println("");
        println("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if matches.opt_present("version") {
        println("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("number") {
        number_mode = NumberAll;
    }
    if matches.opt_present("number-nonblank") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present([~"show-nonprinting", ~"show-all", ~"t", ~"e"]);
    let show_ends = matches.opts_present([~"show-ends", ~"show-all", ~"e"]);
    let show_tabs = matches.opts_present([~"show-tabs",  ~"show-all", ~"t"]);
    let squeeze_blank = matches.opt_present("squeeze-blank");
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        let mut counter: uint = 1;
        let is_numbering = number == NumberAll || number == NumberNonEmpty;

        for path in files.iter() {
            let reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { continue }
            };

            let mut at_line_start = true;
            loop {
                let buf = reader.read_bytes(2);
                for byte in buf.iter() {
                    if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                        writer.write_str(format!("{0:6u}\t", counter));
                        counter += 1;
                        at_line_start = false;
                    }
                    if is_numbering && *byte == LF {
                        at_line_start = true;
                    }
                    if show_tabs && *byte == TAB {
                        writer.write(bytes!("^I"));
                    } else if show_ends && *byte == LF {
                        writer.write(bytes!("$\n"));
                    } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                        let mut byte = *byte;
                        if byte >= 128 {
                            writer.write(bytes!("M-"));
                            byte = byte - 128;
                        }
                        if byte < 32 {
                            writer.write(['^' as u8, byte + 64]);
                        } else if byte == 127 {
                            writer.write(['^' as u8, byte - 64]);
                        } else {
                            writer.write([byte]);
                        }
                    } else {
                        writer.write([*byte]);
                    }
                }

                if reader.eof() {
                    break;
                }
            }
        }

        return;
    }

    // passthru mode
    for path in files.iter() {
        let reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        loop {
            writer.write(reader.read_bytes(100000));
            if reader.eof() {
                break;
            }
        }
    }
}

fn open(path: ~str) -> Option<@Reader> {
    if "-" == path {
        return Some(stdin());
    }

    match std::io::file_reader(&std::path::Path::new(path.as_slice())) {
        Ok(fd) => return Some(fd),
        Err(e) => {
            stderr().write_line(format!("cat: {0:s}: {1:s}", path, e));
            os::set_exit_status(1);
        }
    }

    None
}
<commit_msg>Add managed boxes feature to fix the build on latest master<commit_after>#[link(name="cat", vers="1.0.0", author="Seldaek")];
#[feature(managed_boxes)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern mod extra;

use std::os;
use std::io::{stdin, stderr, stdout, Writer, Reader};
use extra::getopts::groups;

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("A", "show-all", "equivalent to -vET"),
        groups::optflag("b", "number-nonblank", "number nonempty output lines, overrides -n"),
        groups::optflag("e", "", "equivalent to -vE"),
        groups::optflag("E", "show-ends", "display $ at end of each line"),
        groups::optflag("n", "number", "number all output lines"),
        groups::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        groups::optflag("t", "", "equivalent to -vT"),
        groups::optflag("T", "show-tabs", "display TAB characters as ^I"),
        groups::optflag("v", "show-nonprinting", "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            stderr().write_line("Invalid options");
            stderr().write_line(f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };
    if matches.opt_present("help") {
        println("cat 1.0.0");
        println("");
        println("Usage:");
        println(format!("  {0:s} [OPTION]... [FILE]...", program));
        println("");
        print(groups::usage("Concatenate FILE(s), or standard input, to standard output.", opts));
        println("");
        println("With no FILE, or when FILE is -, read standard input.");
        return;
    }
    if matches.opt_present("version") {
        println("cat 1.0.0");
        return;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("number") {
        number_mode = NumberAll;
    }
    if matches.opt_present("number-nonblank") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present([~"show-nonprinting", ~"show-all", ~"t", ~"e"]);
    let show_ends = matches.opts_present([~"show-ends", ~"show-all", ~"e"]);
    let show_tabs = matches.opts_present([~"show-tabs",  ~"show-all", ~"t"]);
    let squeeze_blank = matches.opt_present("squeeze-blank");
    let mut files = matches.free;
    if files.is_empty() {
        files = ~[~"-"];
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
}

#[deriving(Eq)]
pub enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

static TAB: u8 = '\t' as u8;
static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;

#[cfg(windows)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF || byte == CR
}

#[cfg(unix)]
fn is_newline_char(byte: u8) -> bool {
    byte == LF
}

pub fn exec(files: ~[~str], number: NumberingMode, show_nonprint: bool, show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
    let writer = stdout();

    if NumberNone != number || show_nonprint || show_ends || show_tabs || squeeze_blank {
        let mut counter: uint = 1;
        let is_numbering = number == NumberAll || number == NumberNonEmpty;

        for path in files.iter() {
            let reader = match open(path.to_owned()) {
                Some(f) => f,
                None => { continue }
            };

            let mut at_line_start = true;
            loop {
                let buf = reader.read_bytes(2);
                for byte in buf.iter() {
                    if at_line_start && (number == NumberAll || (number == NumberNonEmpty && !is_newline_char(*byte))) {
                        writer.write_str(format!("{0:6u}\t", counter));
                        counter += 1;
                        at_line_start = false;
                    }
                    if is_numbering && *byte == LF {
                        at_line_start = true;
                    }
                    if show_tabs && *byte == TAB {
                        writer.write(bytes!("^I"));
                    } else if show_ends && *byte == LF {
                        writer.write(bytes!("$\n"));
                    } else if show_nonprint && (*byte < 32 || *byte >= 127) && !is_newline_char(*byte) {
                        let mut byte = *byte;
                        if byte >= 128 {
                            writer.write(bytes!("M-"));
                            byte = byte - 128;
                        }
                        if byte < 32 {
                            writer.write(['^' as u8, byte + 64]);
                        } else if byte == 127 {
                            writer.write(['^' as u8, byte - 64]);
                        } else {
                            writer.write([byte]);
                        }
                    } else {
                        writer.write([*byte]);
                    }
                }

                if reader.eof() {
                    break;
                }
            }
        }

        return;
    }

    // passthru mode
    for path in files.iter() {
        let reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        loop {
            writer.write(reader.read_bytes(100000));
            if reader.eof() {
                break;
            }
        }
    }
}

fn open(path: ~str) -> Option<@Reader> {
    if "-" == path {
        return Some(stdin());
    }

    match std::io::file_reader(&std::path::Path::new(path.as_slice())) {
        Ok(fd) => return Some(fd),
        Err(e) => {
            stderr().write_line(format!("cat: {0:s}: {1:s}", path, e));
            os::set_exit_status(1);
        }
    }

    None
}
<|endoftext|>


<commit_before>use system::*;

pub struct TileData
{
    pub data: Vec<u8>,
    pub mem_loc: u16,
}

impl TileData
{
    pub fn new() -> TileData
    {
        return TileData
        {
            data: vec![0; 64],
            mem_loc: 0
        }
    }
}

pub fn get_tile_data(tile_index: u8, system_data: &mut SystemData) -> TileData
{
    let mut tile_data = TileData::new();
    tile_data.mem_loc = 0x8000 + (tile_index * 16);
    for byte_pair in 0..8
    {
        for bit in 0..8
        {

        }
    }
    return tile_data;
}

pub fn update_gpu(system_data_original: &mut SystemData, registers_original: &mut Registers, gpu_registers_original: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let mut gpu_registers = gpu_registers_original;
    LCD_Y_Coordinate_Update(&mut system_data, &mut gpu_registers);
}

pub fn LCD_Y_Coordinate_Update(system_data: &mut SystemData, gpu_registers: &mut GPU_Registers)
{
    gpu_registers.ly_cycle_count += system_data.cycles as u32;
    gpu_registers.ly_sub_cycle_count += system_data.cycles as u16;
    if (gpu_registers.ly_cycle_count >= 70224)
    {
        gpu_registers.ly_cycle_count -= 70224;
    }
    if (gpu_registers.ly_sub_cycle_count >= 456)
    {
        gpu_registers.ly_register += 1;
        if gpu_registers.ly_register == 154
        {
            gpu_registers.ly_register = 0;
        }
        system_data.mem_map[0xFF44] = gpu_registers.ly_register;
        gpu_registers.ly_sub_cycle_count -= 456;
    }
}    <commit_msg>gets tile data<commit_after>use system::*;

pub struct TileData
{
    pub data: Vec<u8>,
}

impl TileData
{
    pub fn new() -> TileData
    {
        return TileData
        {
            data: vec![0; 64],
        }
    }
}

pub fn get_tile_data(tile_index: u8, system_data: &mut SystemData) -> TileData
{
    let mut tile_data = TileData::new();
    let mem_loc: u16 = 0x8000 + (tile_index as u16 * 16);
    println!("{:x}", mem_loc);
    for byte_pair in 0..8
    {
        for bit in 0..8
        {
            let upper_bit: u8 = (system_data.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize] >> (7 - bit)) & 0x01;
            let lower_bit: u8 = (system_data.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize + 1] >> (7 - bit)) & 0x01;
            tile_data.data[(byte_pair as usize * 8) + bit as usize] = (upper_bit << 1) | lower_bit;
        }
    }
    return tile_data;
}

pub fn update_gpu(system_data_original: &mut SystemData, registers_original: &mut Registers, gpu_registers_original: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let mut gpu_registers = gpu_registers_original;
    LCD_Y_Coordinate_Update(&mut system_data, &mut gpu_registers);
}

pub fn LCD_Y_Coordinate_Update(system_data: &mut SystemData, gpu_registers: &mut GPU_Registers)
{
    gpu_registers.ly_cycle_count += system_data.cycles as u32;
    gpu_registers.ly_sub_cycle_count += system_data.cycles as u16;
    if (gpu_registers.ly_cycle_count >= 70224)
    {
        gpu_registers.ly_cycle_count -= 70224;
    }
    if (gpu_registers.ly_sub_cycle_count >= 456)
    {
        gpu_registers.ly_register += 1;
        if gpu_registers.ly_register == 154
        {
            gpu_registers.ly_register = 0;
        }
        system_data.mem_map[0xFF44] = gpu_registers.ly_register;
        gpu_registers.ly_sub_cycle_count -= 456;
    }
}

#[cfg(test)]
mod gpu_tests
{
    use system::get_system_data;
    use gpu::gpu::*;

    #[test]
    fn get_tile_data_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        system_data.mem_map[0x8000] = 0b00001111;
        system_data.mem_map[0x8001] = 0b00110011;
        system_data.mem_map[0x8002] = 0b11110000;
        system_data.mem_map[0x8003] = 0b11001100;
        let tile_data = get_tile_data(0, &mut system_data);
        for i in 0..4
        {
            assert_eq!(tile_data.data[i as usize * 2], i);
            assert_eq!(tile_data.data[(i as usize * 2) + 1 ], i);
        }
        for i in 0..4
        {
            assert_eq!(tile_data.data[8 + (i as usize * 2)], 3 - i);
            assert_eq!(tile_data.data[(8 + (i as usize * 2)) + 1], 3 - i);
        }
    }
}
<|endoftext|>