<commit_before>// Copyright 2016 Walter Kuppens.
//
// 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.

use debugger::parser;
use getopts::Options;
use io::log;
use nes::nes::NES;
use utils::arithmetic;
use std::io::{self, Write, stderr, stdout};
use std::sync::mpsc::{SyncSender, Receiver};
use std::thread;
use std::time::Duration;

#[derive(Debug)]
enum Command {
    Help,
    Exit,
    Stop,
    Continue,
    Dump,
    ObjDump,
}

struct CommandWithArguments {
    command: Command,
    args: Vec<String>,
}

pub struct Debugger {
    sender:   SyncSender<u8>,
    receiver: Receiver<String>,
    stepping: bool,
    shutdown: bool,
}

impl Debugger {
    pub fn new(sender: SyncSender<u8>, receiver: Receiver<String>) -> Self {
        Self {
            sender: sender,
            receiver: receiver,
            stepping: true,
            shutdown: false,
        }
    }

    /// Steps the CPU forward a single instruction, as well as executing any PPU
    /// and sound functionality that happens in-between.
    pub fn step(&mut self, nes: &mut NES) -> bool {
        // Input is received from another thread so the emulator can run without
        // the debugger prompt blocking it.
        match self.receiver.try_recv() {
            Ok(input) => {
                if let Some(command) = self.interpret(input.clone()) {
                    self.execute_command(command, nes);
                } else {
                    if input.len() > 0 {
                        writeln!(stderr(), "nes-rs: unknown command specified").unwrap();
                    }
                }

                // Tell input thread to continue and display prompt.
                if let Err(_) = self.sender.send(0) {
                    // Receiver was probably destroyed in spin-down.
                }
            },
            Err(_) => {}, // Ignore empty and disconnect errors.
        };

        // If the debugger is in stepping mode, continue execution like normal,
        // otherwise the CPU and other peripherals should not update. In the
        // meantime, sleep the host CPU while we wait for input.
        if self.stepping {
            nes.step();
        } else {
            thread::sleep(Duration::from_millis(16));
        }

        self.shutdown
    }

    /// Parse a raw input string into a list of arguments and a command. This
    /// function also maps command names to their respective enums.
    fn interpret(&self, input: String) -> Option<CommandWithArguments> {
        let mut stderr = io::stderr();
        let args = match parser::input_to_arguments(input) {
            Ok(args) => args,
            Err(e) => {
                writeln!(stderr, "nes-rs: {}", e).unwrap();
                return None;
            },
        };

        let command = {
            let raw_command = if args.len() > 0 {
                &args[0]
            } else {
                return None;
            };

            // Map command strings to the command enum type.
            match raw_command.to_lowercase().as_str() {
                // Full commands.
                "help"     => Command::Help,
                "exit"     => Command::Exit,
                "stop"     => Command::Stop,
                "continue" => Command::Continue,
                "dump"     => Command::Dump,
                "objdump"  => Command::ObjDump,
                // Aliases.
                "s"  => Command::Stop,
                "c"  => Command::Continue,
                "d"  => Command::Dump,
                "od" => Command::ObjDump,
                // Unknown command.
                _ => {
                    return None;
                },
            }
        };

        Some({
            CommandWithArguments {
                command: command,
                args: args,
            }
        })
    }

    /// Executes the correct debugger command based on the enum passed.
    fn execute_command(&mut self, command: CommandWithArguments, nes: &mut NES) {
        match command.command {
            Command::Help => self.execute_help(),
            Command::Exit => self.execute_exit(),
            Command::Stop => self.execute_stop(nes),
            Command::Continue => self.execute_continue(nes),
            Command::Dump => self.execute_dump(nes, &command.args),
            Command::ObjDump => self.execute_objdump(nes, &command.args),
        };
    }

    /// Shows friendly help text for information about using the debugger.
    fn execute_help(&self) {
        writeln!(stderr(), "
Welcome to the nes-rs debugger!

This subshell provides access to a few different commands that allow you to
modify and observe the state of the virtual machine. At the moment there is a
very limited set of commands and more may be added in the future.

Supported commands: help | stop | continue | dump
"
        ).unwrap();
    }

    /// Stops the virtual machine by setting the shutdown flag.
    fn execute_exit(&mut self) {
        self.shutdown = true;
    }

    /// Stops execution of the CPU and PPU to allow the human some time to debug
    /// a problem or stare at hex codes all day to look like a l33t haxor.
    fn execute_stop(&mut self, nes: &mut NES) {
        log::log("debugger", "Stopping execution now...", &nes.runtime_options);
        self.stepping = false;
    }

    /// Starts execution if it's stopped.
    fn execute_continue(&mut self, nes: &mut NES) {
        log::log("debugger", "Starting execution now...", &nes.runtime_options);
        self.stepping = true;
    }

    /// Allows dumping memory or program code at a specified memory address.
    /// Memory can be dumped as hex or instructions depending on the address.
    /// Dumping hex is easy if word length is assumed, however instructions are a
    /// whole other beast.
    ///
    /// Since instructions can be varying lengths, you can interpret them in
    /// different ways depending on your offset (i.e the argument of an opcode
    /// being used as an opcode due to a misplaced pc). We just read forwards so
    /// we don't have to worry about this problem, if we need to read backwards
    /// just check the log for a pc smaller than the current one and guess the
    /// peek value.
    fn execute_dump(&mut self, nes: &mut NES, args: &Vec<String>) {
        const USAGE: &'static str = "Usage: dump [OPTION]... [ADDRESS]";

        let mut opts = Options::new();
        opts.optopt("p", "peek", "how far forward should memory be dumped", "NUMBER");

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => m,
            Err(f) => {
                writeln!(stderr(), "dump: {}", f).unwrap();
                writeln!(stderr(), "{}", opts.usage(USAGE)).unwrap();
                return;
            },
        };

        // Peek allows specifying how much information to dump.
        let peek = match matches.opt_str("peek") {
            Some(arg) => {
                match arg.parse::<i32>() {
                    Ok(p) => p,
                    Err(e) => {
                        writeln!(stderr(), "dump: {}", e).unwrap();
                        writeln!(stderr(), "{}", opts.usage(USAGE)).unwrap();
                        return;
                    },
                }
            },
            None => 10,
        };

        // Parse hex representation of a memory address at free argument.
        let addr = if !matches.free.is_empty() {
            let arg = matches.free[0].clone();
            if let Some(hex) = arithmetic::hex_to_u16(&arg) {
                hex
            } else {
                writeln!(stderr(), "dump: cannot parse address: {}", arg).unwrap();
                return;
            }
        } else {
            writeln!(stderr(), "dump: no address specified").unwrap();
            writeln!(stderr(), "{}", opts.usage(USAGE)).unwrap();
            return;
        };

        println!("address: {}, peek: {}", addr, peek);
    }

    fn execute_objdump(&mut self, nes: &mut NES, args: &Vec<String>) {
        const USAGE: &'static str = "Usage: objdump [OPTION]... [ADDRESS]";

        let mut opts = Options::new();
        opts.optopt("p", "peek", "how far forward should memory be dumped", "NUMBER");
    }
}
<commit_msg>Implemented hexdump debugger command<commit_after>// Copyright 2016 Walter Kuppens.
//
// 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.

use debugger::parser;
use getopts::Options;
use io::log;
use nes::nes::NES;
use utils::arithmetic;
use std::io::{self, Write, stderr, stdout};
use std::sync::mpsc::{SyncSender, Receiver};
use std::thread;
use std::time::Duration;

#[derive(Debug)]
enum Command {
    Help,
    Exit,
    Stop,
    Continue,
    Dump,
    ObjDump,
}

struct CommandWithArguments {
    command: Command,
    args: Vec<String>,
}

pub struct Debugger {
    sender:   SyncSender<u8>,
    receiver: Receiver<String>,
    stepping: bool,
    shutdown: bool,
}

impl Debugger {
    pub fn new(sender: SyncSender<u8>, receiver: Receiver<String>) -> Self {
        Self {
            sender: sender,
            receiver: receiver,
            stepping: true,
            shutdown: false,
        }
    }

    /// Steps the CPU forward a single instruction, as well as executing any PPU
    /// and sound functionality that happens in-between.
    pub fn step(&mut self, nes: &mut NES) -> bool {
        // Input is received from another thread so the emulator can run without
        // the debugger prompt blocking it.
        match self.receiver.try_recv() {
            Ok(input) => {
                if let Some(command) = self.interpret(input.clone()) {
                    self.execute_command(command, nes);
                } else {
                    if input.len() > 0 {
                        writeln!(stderr(), "nes-rs: unknown command specified").unwrap();
                    }
                }

                // Tell input thread to continue and display prompt.
                if let Err(_) = self.sender.send(0) {
                    // Receiver was probably destroyed in spin-down.
                }
            },
            Err(_) => {}, // Ignore empty and disconnect errors.
        };

        // If the debugger is in stepping mode, continue execution like normal,
        // otherwise the CPU and other peripherals should not update. In the
        // meantime, sleep the host CPU while we wait for input.
        if self.stepping {
            nes.step();
        } else {
            thread::sleep(Duration::from_millis(16));
        }

        self.shutdown
    }

    /// Parse a raw input string into a list of arguments and a command. This
    /// function also maps command names to their respective enums.
    fn interpret(&self, input: String) -> Option<CommandWithArguments> {
        let mut stderr = io::stderr();
        let args = match parser::input_to_arguments(input) {
            Ok(args) => args,
            Err(e) => {
                writeln!(stderr, "nes-rs: {}", e).unwrap();
                return None;
            },
        };

        let command = {
            let raw_command = if args.len() > 0 {
                &args[0]
            } else {
                return None;
            };

            // Map command strings to the command enum type.
            match raw_command.to_lowercase().as_str() {
                // Full commands.
                "help"     => Command::Help,
                "exit"     => Command::Exit,
                "stop"     => Command::Stop,
                "continue" => Command::Continue,
                "dump"     => Command::Dump,
                "objdump"  => Command::ObjDump,
                // Aliases.
                "s"  => Command::Stop,
                "c"  => Command::Continue,
                "d"  => Command::Dump,
                "od" => Command::ObjDump,
                // Unknown command.
                _ => {
                    return None;
                },
            }
        };

        Some({
            CommandWithArguments {
                command: command,
                args: args,
            }
        })
    }

    /// Executes the correct debugger command based on the enum passed.
    fn execute_command(&mut self, command: CommandWithArguments, nes: &mut NES) {
        match command.command {
            Command::Help => self.execute_help(),
            Command::Exit => self.execute_exit(),
            Command::Stop => self.execute_stop(nes),
            Command::Continue => self.execute_continue(nes),
            Command::Dump => self.execute_dump(nes, &command.args),
            Command::ObjDump => self.execute_objdump(nes, &command.args),
        };
    }

    /// Shows friendly help text for information about using the debugger.
    fn execute_help(&self) {
        writeln!(stderr(), "
Welcome to the nes-rs debugger!

This subshell provides access to a few different commands that allow you to
modify and observe the state of the virtual machine. At the moment there is a
very limited set of commands and more may be added in the future.

Supported commands: help | stop | continue | dump
"
        ).unwrap();
    }

    /// Stops the virtual machine by setting the shutdown flag.
    fn execute_exit(&mut self) {
        self.shutdown = true;
    }

    /// Stops execution of the CPU and PPU to allow the human some time to debug
    /// a problem or stare at hex codes all day to look like a l33t haxor.
    fn execute_stop(&mut self, nes: &mut NES) {
        log::log("debugger", "Stopping execution now...", &nes.runtime_options);
        self.stepping = false;
    }

    /// Starts execution if it's stopped.
    fn execute_continue(&mut self, nes: &mut NES) {
        log::log("debugger", "Starting execution now...", &nes.runtime_options);
        self.stepping = true;
    }

    /// Allows dumping memory or program code at a specified memory address. All
    /// values are assumed to be 8-bit words.
    fn execute_dump(&mut self, nes: &mut NES, args: &Vec<String>) {
        const USAGE: &'static str = "Usage: dump [OPTION]... [ADDRESS]";

        let mut opts = Options::new();
        opts.optopt("p", "peek", "how far forward should memory be dumped", "NUMBER");

        let matches = match opts.parse(&args[1..]) {
            Ok(m) => m,
            Err(f) => {
                writeln!(stderr(), "dump: {}", f).unwrap();
                writeln!(stderr(), "{}", opts.usage(USAGE)).unwrap();
                return;
            },
        };

        // Peek allows specifying how much information to dump.
        let peek = match matches.opt_str("peek") {
            Some(arg) => {
                match arg.parse::<u16>() {
                    Ok(p) => p,
                    Err(e) => {
                        writeln!(stderr(), "dump: {}", e).unwrap();
                        writeln!(stderr(), "{}", opts.usage(USAGE)).unwrap();
                        return;
                    },
                }
            },
            None => 10,
        };

        // Parse hex representation of a memory address at free argument if
        // available, otherwise the address will be the program counter.
        let addr = if !matches.free.is_empty() {
            let arg = matches.free[0].clone();
            if let Some(hex) = arithmetic::hex_to_u16(&arg) {
                hex
            } else {
                writeln!(stderr(), "dump: cannot parse address: {}", arg).unwrap();
                return;
            }
        } else {
            nes.cpu.pc
        };

        for idx in 0..peek {
            let peek_offset = addr.wrapping_add(idx * 16);
            let mut bytes: [u8; 16] = [0; 16];
            for offset in 0..16 {
                let current_addr = (peek_offset.wrapping_add(offset)) as usize;
                let value = nes.memory.read_u8_unrestricted(current_addr);
                bytes[offset as usize] = value;
            }

            // Print the memory address for for the first byte in the line.
            print!("{:04x}  ", peek_offset);

            // Print out 2 lines of 8-bit bytes showing 8 bytes each.
            for offset in 0..8 {
                print!("{:02x} ", bytes[offset]);
            }
            print!(" ");
            for offset in 0..8 {
                print!("{:02x} ", bytes[offset + 8]);
            }

            // Print out an ASCII representation of the bytes.
            print!(" ");
            for offset in 0..16 {
                let value = bytes[offset];
                let human_char = if value >= 0x20 && value <= 0x7E {
                    value as char
                } else {
                    '.'
                };
                print!("{}", human_char);
            }
            print!("\n");

            stdout().flush().unwrap();
        }
    }

    /// Similar to dump, but will interpret data as instructions.
    fn execute_objdump(&mut self, nes: &mut NES, args: &Vec<String>) {
        const USAGE: &'static str = "Usage: objdump [OPTION]... [ADDRESS]";

        let mut opts = Options::new();
        opts.optopt("p", "peek", "how far forward should memory be dumped", "NUMBER");

        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use screen::*;
use context::Context;
use piston_window::{self, PistonWindow};

pub struct Battle {
    main_menu: bool,
}

impl Battle {
    pub fn new(_window: &PistonWindow, _context: &mut Context) -> Self {
        Battle { main_menu: false }
    }
}

impl Screen for Battle {
    fn on_input(&mut self, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        use piston_window::{Input, Button, Key};

        let mut result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Escape) => {
                        result.push(InputResult::PushScreen(Box::new(MainMenu::new(&window, context))));
                    }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Escape) => {
                        self.main_menu = false;
                    }
                    _ => {}
                }
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, _args: &piston_window::RenderArgs, window: &PistonWindow) {
        window.draw_2d(|_context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);
        });
    }

    fn on_update(&mut self, _args: &piston_window::UpdateArgs) {}
}
<commit_msg>Battle: main_menu field has been removed<commit_after>use screen::*;
use context::Context;
use piston_window::{self, PistonWindow};

pub struct Battle;

impl Battle {
    pub fn new(_window: &PistonWindow, _context: &mut Context) -> Self {
        Battle
    }
}

impl Screen for Battle {
    fn on_input(&mut self, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        use piston_window::{Input, Button, Key};

        let mut result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Escape) => {
                        result.push(InputResult::PushScreen(Box::new(MainMenu::new(&window, context))));
                    }
                    _ => {}
                }
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, _args: &piston_window::RenderArgs, window: &PistonWindow) {
        window.draw_2d(|_context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);
        });
    }

    fn on_update(&mut self, _args: &piston_window::UpdateArgs) {}
}
<|endoftext|>


<commit_before>use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::punctuation::Punctuations;
use syntax::ast::expr::*;

#[allow(dead_code)]
enum OldExpr {
    Integer(IntegerAST),
    UInteger(UIntegerAST),
    Float(FloatAST),
}

#[allow(dead_code)]
struct IntegerAST {
    val: i64,
}

#[allow(dead_code)]
struct UIntegerAST {
    val: u64,
}

#[allow(dead_code)]
struct FloatAST {
    val: f64,
}

pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indentation: usize,
    run_codegen: bool,
    ast_root: ExprWrapper
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        let expr = Box::new(Expr::BlockExpr(Vec::new()));
        let wrapper = ExprWrapper::new(expr, 0, 0, 0, 0);

        Parser {
            lexer: tokenizer,
            indentation: 0,
            run_codegen: true,
            ast_root: wrapper
        }
    }

    // Get the next token from the lexer
    fn next_token(&mut self) -> Token {
        self.lexer.get_tok()
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&mut self, msg: &str) {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        self.run_codegen = false;

        println!("Error on line: {} col: {}, {}", start_line, start_column, msg);

        // Skip to the end of the line (at Indent token) and allow parsing to continue
        loop {
            // Note: This consumes the Indent token, which probably isnt ideal.
            match self.next_token() {
                Indent(_) => break,
                EOF => break,
                _ => ()
            }
        }
    }

    fn expect_error(&mut self, reason: &str, expect: &str, got: &str) {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got));
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&mut self, depth: usize) -> Option<OldExpr> {
        if self.indentation == depth {
            return None;
        }

        self.write_error("Incorrect indentation level");

        None
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    fn parse_declaration(&mut self) -> Option<OldExpr> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();

                match token1 {
                    // Punctuation(punc) => {
                    //     match punc {
                    //         punctuation::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Punctuation here"))
                    //     }
                    // }
                    Punctuation(Punctuations::Equals) => {
                        return self.parse_expression();
                    },
                    _ => self.write_error("Invalid sequence")
                }
            },
            Error(msg) => self.write_error(&msg),
            _ => self.expect_error("", "a variable name", "something else")
        }

        None
    }

    fn expect_token(&mut self, token: Token) -> bool {
        if self.next_token() != token {
            self.expect_error("", "", "");

            return false;
        }

        true
    }

    // Parses a print function/statement
    fn parse_print_fn(&mut self) -> Option<ExprWrapper> {
        if !self.expect_token(Punctuation(Punctuations::ParenOpen)) {
            return None;
        }

        // Parse 1+ args here

        if !self.expect_token(Punctuation(Punctuations::ParenClose)) {
            return None;
        }

        // Return the ast of the print function
        None
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Option<ExprWrapper> {
        match keyword {
//            Keywords::Def => {
//                self.parse_declaration()
//            },
            Keywords::Print => {
                self.parse_print_fn()
            },
            _ => {
                self.write_error(&format!("Unsupported keyword {:?}.", keyword));
                None
            }
        }
    }

    fn parse_expression(&self) -> Option<OldExpr> {
        None
    }

    // Parse numbers into their correct representation
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Option<OldExpr> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        Some(OldExpr::Integer(IntegerAST { val: value }))
    }

    // Parse the file
    #[allow(unused_variables)]
    pub fn parse(&mut self) {
        self.start();

        // Generate AST
        loop {
            // Parse the token into the next node of the AST
            let token = self.next_token();

            // Debug:
            println!("{:?}", token);

            match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
//                    self.parse_expression()
                    panic!("Unimplemented top level token 'Identifier'");
                },
                Indent(depth) => {
                    // ToDo: Keep track of indentation level when preceeding a statement
                    // Might need look ahead to see if next token is Comment or Indent
                    // which means you didn't actually dedent.
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    if let Some(exprwrapper) = self.handle_keywords(keyword) {
                        if let &mut Expr::BlockExpr(ref mut vec) = self.ast_root.get_expr() {
                            vec.push(exprwrapper);
                        }
                    }
                },
                Punctuation(punc) => {
                    panic!("Unimplemented top level token 'Punctuation'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                },
                Error(err) => {
                    self.write_error(&err);
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => break
            };
        }

        // Do semantic analysis on AST

        // Run codegen when no errors have been found
        if self.run_codegen {
            self.ast_root.gen_code();
        }
    }
}
<commit_msg>Removed extra space<commit_after>use syntax::lexer::Tokenizer;
use syntax::core::tokens::Token;
use syntax::core::tokens::Token::*;
use syntax::core::keywords::Keywords;
use syntax::core::punctuation::Punctuations;
use syntax::ast::expr::*;

#[allow(dead_code)]
enum OldExpr {
    Integer(IntegerAST),
    UInteger(UIntegerAST),
    Float(FloatAST),
}

#[allow(dead_code)]
struct IntegerAST {
    val: i64,
}

#[allow(dead_code)]
struct UIntegerAST {
    val: u64,
}

#[allow(dead_code)]
struct FloatAST {
    val: f64,
}

pub struct Parser<TokType: Tokenizer> {
    lexer: TokType,
    indentation: usize,
    run_codegen: bool,
    ast_root: ExprWrapper
}

impl<TokType: Tokenizer> Parser<TokType> {
    pub fn new(tokenizer: TokType) -> Parser<TokType> {
        let expr = Box::new(Expr::BlockExpr(Vec::new()));
        let wrapper = ExprWrapper::new(expr, 0, 0, 0, 0);

        Parser {
            lexer: tokenizer,
            indentation: 0,
            run_codegen: true,
            ast_root: wrapper
        }
    }

    // Get the next token from the lexer
    fn next_token(&mut self) -> Token {
        self.lexer.get_tok()
    }

    // Create an error from the current lexer's
    // state, and a message
    fn write_error(&mut self, msg: &str) {
        let (start_line, start_column, _, _) = self.lexer.get_error_pos();

        self.run_codegen = false;

        println!("Error on line: {} col: {}, {}", start_line, start_column, msg);

        // Skip to the end of the line (at Indent token) and allow parsing to continue
        loop {
            // Note: This consumes the Indent token, which probably isnt ideal.
            match self.next_token() {
                Indent(_) => break,
                EOF => break,
                _ => ()
            }
        }
    }

    fn expect_error(&mut self, reason: &str, expect: &str, got: &str) {
        self.write_error(&format!("{}. Expected {}, but got {}", reason, expect, got));
    }

    // Perform any necessary on-start actions
    fn start(&self) {
        // Start code gen startup

        // Implicit imports

        // Generate code for implicit top level function definition
    }

    // Ensures that the indentation matches the current level of indentation
    #[allow(dead_code)]
    fn check_indentation(&mut self, depth: usize) -> Option<OldExpr> {
        if self.indentation == depth {
            return None;
        }

        self.write_error("Incorrect indentation level");

        None
    }

    // Parses a variable or constant declaration
    #[allow(unused_variables)]
    fn parse_declaration(&mut self) -> Option<OldExpr> {
        let token = self.next_token();
        match token {
            Identifier(name) => {
                let token1 = self.next_token();

                match token1 {
                    // Punctuation(punc) => {
                    //     match punc {
                    //         punctuation::Assign => {
                    //             self.parse_expression()
                    //         }
                    //         _ => Err(self.write_error("Invalid Punctuation here"))
                    //     }
                    // }
                    Punctuation(Punctuations::Equals) => {
                        return self.parse_expression();
                    },
                    _ => self.write_error("Invalid sequence")
                }
            },
            Error(msg) => self.write_error(&msg),
            _ => self.expect_error("", "a variable name", "something else")
        }

        None
    }

    fn expect_token(&mut self, token: Token) -> bool {
        if self.next_token() != token {
            self.expect_error("", "", "");

            return false;
        }

        true
    }

    // Parses a print function/statement
    fn parse_print_fn(&mut self) -> Option<ExprWrapper> {
        if !self.expect_token(Punctuation(Punctuations::ParenOpen)) {
            return None;
        }

        // Parse 1+ args here

        if !self.expect_token(Punctuation(Punctuations::ParenClose)) {
            return None;
        }

        // Return the ast of the print function
        None
    }

    // Handles top-level keywords to start parsing them
    fn handle_keywords(&mut self, keyword: Keywords) -> Option<ExprWrapper> {
        match keyword {
//            Keywords::Def => {
//                self.parse_declaration()
//            },
            Keywords::Print => {
                self.parse_print_fn()
            },
            _ => {
                self.write_error(&format!("Unsupported keyword {:?}.", keyword));
                None
            }
        }
    }

    fn parse_expression(&self) -> Option<OldExpr> {
        None
    }

    // Parse numbers into their correct representation
    #[allow(dead_code)]
    fn parse_number(&mut self, num: &str) -> Option<OldExpr> {
        println!("{}", num);
        let value = 0;
        // This would normally check the ending on the thing slash information
        // about the number to pick int, uint, or float
        Some(OldExpr::Integer(IntegerAST { val: value }))
    }

    // Parse the file
    #[allow(unused_variables)]
    pub fn parse(&mut self) {
        self.start();

        // Generate AST
        loop {
            // Parse the token into the next node of the AST
            let token = self.next_token();

            // Debug:
            println!("{:?}", token);

            match token {
                Numeric(string, type_) => {
                    panic!("Unimplemented top level token 'Numeric'");
                },
                Identifier(repr) => {
//                    self.parse_expression()
                    panic!("Unimplemented top level token 'Identifier'");
                },
                Indent(depth) => {
                    // ToDo: Keep track of indentation level when preceeding a statement
                    // Might need look ahead to see if next token is Comment or Indent
                    // which means you didn't actually dedent.
                },
                BoolLiteral(lit) => {
                    panic!("Unimplemented top level token 'BoolLiteral'");
                },
                CharLiteral(lit) => {
                    panic!("Unimplemented top level token 'CharLiteral'");
                },
                StrLiteral(lit) => {
                    panic!("Unimplemented top level token 'StrLiteral'");
                },
                Keyword(keyword) => {
                    if let Some(exprwrapper) = self.handle_keywords(keyword) {
                        if let &mut Expr::BlockExpr(ref mut vec) = self.ast_root.get_expr() {
                            vec.push(exprwrapper);
                        }
                    }
                },
                Punctuation(punc) => {
                    panic!("Unimplemented top level token 'Punctuation'");
                },
                Comment(text) => {
                    // ToDo: Docstring, else ignore
                },
                Error(err) => {
                    self.write_error(&err);
                },
                Type(type_) => {
                    panic!("Unimplemented top level token 'Type'");
                },
                EOF => break
            };
        }

        // Do semantic analysis on AST

        // Run codegen when no errors have been found
        if self.run_codegen {
            self.ast_root.gen_code();
        }
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Tagged stream
//!
//! A tagged stream recursively applies tags to regions of an input stream. A stream consisting of a single tag forms a tree,
//! so this stream type is useful for representing the parsed represention of an input.
//!
//! The simplest form of tagged stream is one that's just a set of untagged symbols. This can be created using the `TaggedStream::from_reader`
//! method.
//!
//! ```
//! # use concordance::*;
//! #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
//! enum SomeTag {
//!     Identifier
//! };
//!
//! let simple_tagged : TaggedStream<char, SomeTag> = TaggedStream::from_reader(&mut "Hello, world".read_symbols());
//! ```
//!

use std::slice::Iter;
use std::ops::Index;
use std::ops::Range;

use super::symbol_reader::*;

///
/// Represents a symbol in a tagged stream.
///
/// A symbol can either be a sequence of untagged base symbols, or it can be a tag (which itself can contain any number of tagged symbol)
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TagSymbol<Base: Clone, Tag: Clone> {
    /// An untagged element in this stream
    Untagged(Base),

    /// A tagged region of the stream
    Tagged(Tag, TaggedStream<Base, Tag>)
}

///
/// Represents a stream of tagged symbols
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TaggedStream<Base: Clone, Tag: Clone> {
    /// The data in this stream
    data: Vec<TagSymbol<Base, Tag>>
}

impl<Base: Clone, Tag: Clone> TaggedStream<Base, Tag> {
    ///
    /// Creates a basic tagged stream from a source of the base symbol
    ///
    pub fn from_reader(reader: &mut SymbolReader<Base>) -> TaggedStream<Base, Tag> {
        // Read from the reader into an array
        let mut symbols = vec![];

        while let Some(next_symbol) = reader.next_symbol() {
            symbols.push(TagSymbol::Untagged(next_symbol));
        }

        // Generate a simple tagged stream from the result
        TaggedStream { data: symbols }
    }

    ///
    /// The number of symbols in this stream
    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }

    ///
    /// Replaces a range in this stream with a tag
    ///
    pub fn tag(&mut self, tag: Tag, range: Range<usize>) {
        // Create a tag to replace the range
        let replaced_symbols    = self.data[range.clone()].to_vec();
        let tag_symbol          = TagSymbol::Tagged(tag, TaggedStream { data: replaced_symbols });

        // Draining seems to be for reading a range but does double duty for deleting a range?
        // I don't think rust has a way to replace a range in a vector, or at least not one that's easy to find in the docs.
        self.data.drain(range.clone());

        // Draining then inserting is inefficient compared to flat out replacing items :-/ This may be possible but the vec docs aren't very easy to read
        self.data.insert(range.start, tag_symbol);
    }

    ///
    /// Creates a tag symbol by tagging a particular range within this stream
    ///
    pub fn tag_range(&self, range: Range<usize>, tag: Tag) -> TagSymbol<Base, Tag> {
        let tag_data = self.data[range].to_vec();

        TagSymbol::Tagged(tag, TaggedStream { data: tag_data })
    }

    ///
    /// Applies tags to the specified ranges in this stream
    ///
    /// The tag ranges must be in ascending order and must not overlap
    ///
    pub fn with_tags<I>(&self, tags: I) -> TaggedStream<Base, Tag>
        where I : Iterator<Item=(Range<usize>, Tag)> {
        // The data that will make up the new stream
        let mut new_stream = vec![];

        // The last processed range (we haven't processed any range yet, so this starts at 0..0)
        let mut last_range = 0..0;

        // Build up the result from the tag list and the last range
        for tag in tags {
            // Fetch the information for this tag and check ordering
            let (next_range, next_tag)  = tag;
            let end                     = last_range.end;

            if end > next_range.start {
                panic!("Tags for with_tags must be sorted in order");
            }

            // Sometimes need to leave some data from this stream untagged
            if end < next_range.start {
                new_stream.extend(self.data[end..next_range.start].iter().cloned());
            }

            // Push the tag
            new_stream.push(self.tag_range(next_range.clone(), next_tag));

            // Update state
            last_range = next_range;
        }

        // Append anything left in the stream
        if last_range.end < self.data.len() {
            new_stream.extend(self.data[last_range.end..self.data.len()].iter().cloned());
        }

        // Final result
        TaggedStream { data: new_stream }
    }
}

impl<Base: Clone, Tag: Clone> Index<usize> for TaggedStream<Base, Tag> {
    type Output = TagSymbol<Base, Tag>;

    fn index(&self, index: usize) -> &TagSymbol<Base, Tag> {
        &self.data[index]
    }
}

impl<'a, Base: Clone, Tag: Clone> SymbolSource<'a, TagSymbol<Base, Tag>> for &'a TaggedStream<Base, Tag> {
    type SymbolReader = Iter<'a, TagSymbol<Base, Tag>>;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader {
        self.data.read_symbols()
    }
}

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

    #[test]
    fn can_tag_range() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let mut tagged: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());

        tagged.tag(Tags::Hello, 0..5);
        tagged.tag(Tags::World, 1..6);

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_tag_everything_with_tags() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..5, Tags::Hello), (5..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_middle() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..4, Tags::Hello), (6..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 4);
        assert!(tagged[1] == TagSymbol::Untagged('o'));
        assert!(tagged[2] == TagSymbol::Untagged('W'));

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[3] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('o'));
            assert!(stream[1] == TagSymbol::Untagged('r'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_end() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..5, Tags::Hello)].iter().cloned());

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        assert!(tagged[1] == TagSymbol::Untagged('W'));
        assert!(tagged[2] == TagSymbol::Untagged('o'));
        assert!(tagged[3] == TagSymbol::Untagged('r'));
        assert!(tagged[4] == TagSymbol::Untagged('l'));
        assert!(tagged[5] == TagSymbol::Untagged('d'));
    }

    #[test]
    fn with_tags_preserves_start() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(5..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[5] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }

        assert!(tagged[0] == TagSymbol::Untagged('H'));
        assert!(tagged[1] == TagSymbol::Untagged('e'));
        assert!(tagged[2] == TagSymbol::Untagged('l'));
        assert!(tagged[3] == TagSymbol::Untagged('l'));
        assert!(tagged[4] == TagSymbol::Untagged('o'));
    }
}
<commit_msg>Rust is smart enough to bind the missing tag type when we apply tags to the stream, so add that to our demo code<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Tagged stream
//!
//! A tagged stream recursively applies tags to regions of an input stream. A stream consisting of a single tag forms a tree,
//! so this stream type is useful for representing the parsed represention of an input.
//!
//! The simplest form of tagged stream is one that's just a set of untagged symbols. This can be created using the `TaggedStream::from_reader`
//! method.
//!
//! ```
//! # use concordance::*;
//! #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
//! enum SomeTag {
//!     Identifier
//! };
//!
//! let simple_tagged = TaggedStream::from_reader(&mut "Hello, world".read_symbols());
//! let with_tag      = simple_tagged.with_tags(vec![(0..5, SomeTag::Identifier)].iter().cloned());
//! ```
//!

use std::slice::Iter;
use std::ops::Index;
use std::ops::Range;

use super::symbol_reader::*;

///
/// Represents a symbol in a tagged stream.
///
/// A symbol can either be a sequence of untagged base symbols, or it can be a tag (which itself can contain any number of tagged symbol)
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TagSymbol<Base: Clone, Tag: Clone> {
    /// An untagged element in this stream
    Untagged(Base),

    /// A tagged region of the stream
    Tagged(Tag, TaggedStream<Base, Tag>)
}

///
/// Represents a stream of tagged symbols
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TaggedStream<Base: Clone, Tag: Clone> {
    /// The data in this stream
    data: Vec<TagSymbol<Base, Tag>>
}

impl<Base: Clone, Tag: Clone> TaggedStream<Base, Tag> {
    ///
    /// Creates a basic tagged stream from a source of the base symbol
    ///
    pub fn from_reader(reader: &mut SymbolReader<Base>) -> TaggedStream<Base, Tag> {
        // Read from the reader into an array
        let mut symbols = vec![];

        while let Some(next_symbol) = reader.next_symbol() {
            symbols.push(TagSymbol::Untagged(next_symbol));
        }

        // Generate a simple tagged stream from the result
        TaggedStream { data: symbols }
    }

    ///
    /// The number of symbols in this stream
    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }

    ///
    /// Replaces a range in this stream with a tag
    ///
    pub fn tag(&mut self, tag: Tag, range: Range<usize>) {
        // Create a tag to replace the range
        let replaced_symbols    = self.data[range.clone()].to_vec();
        let tag_symbol          = TagSymbol::Tagged(tag, TaggedStream { data: replaced_symbols });

        // Draining seems to be for reading a range but does double duty for deleting a range?
        // I don't think rust has a way to replace a range in a vector, or at least not one that's easy to find in the docs.
        self.data.drain(range.clone());

        // Draining then inserting is inefficient compared to flat out replacing items :-/ This may be possible but the vec docs aren't very easy to read
        self.data.insert(range.start, tag_symbol);
    }

    ///
    /// Creates a tag symbol by tagging a particular range within this stream
    ///
    pub fn tag_range(&self, range: Range<usize>, tag: Tag) -> TagSymbol<Base, Tag> {
        let tag_data = self.data[range].to_vec();

        TagSymbol::Tagged(tag, TaggedStream { data: tag_data })
    }

    ///
    /// Applies tags to the specified ranges in this stream
    ///
    /// The tag ranges must be in ascending order and must not overlap
    ///
    pub fn with_tags<I>(&self, tags: I) -> TaggedStream<Base, Tag>
        where I : Iterator<Item=(Range<usize>, Tag)> {
        // The data that will make up the new stream
        let mut new_stream = vec![];

        // The last processed range (we haven't processed any range yet, so this starts at 0..0)
        let mut last_range = 0..0;

        // Build up the result from the tag list and the last range
        for tag in tags {
            // Fetch the information for this tag and check ordering
            let (next_range, next_tag)  = tag;
            let end                     = last_range.end;

            if end > next_range.start {
                panic!("Tags for with_tags must be sorted in order");
            }

            // Sometimes need to leave some data from this stream untagged
            if end < next_range.start {
                new_stream.extend(self.data[end..next_range.start].iter().cloned());
            }

            // Push the tag
            new_stream.push(self.tag_range(next_range.clone(), next_tag));

            // Update state
            last_range = next_range;
        }

        // Append anything left in the stream
        if last_range.end < self.data.len() {
            new_stream.extend(self.data[last_range.end..self.data.len()].iter().cloned());
        }

        // Final result
        TaggedStream { data: new_stream }
    }
}

impl<Base: Clone, Tag: Clone> Index<usize> for TaggedStream<Base, Tag> {
    type Output = TagSymbol<Base, Tag>;

    fn index(&self, index: usize) -> &TagSymbol<Base, Tag> {
        &self.data[index]
    }
}

impl<'a, Base: Clone, Tag: Clone> SymbolSource<'a, TagSymbol<Base, Tag>> for &'a TaggedStream<Base, Tag> {
    type SymbolReader = Iter<'a, TagSymbol<Base, Tag>>;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader {
        self.data.read_symbols()
    }
}

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

    #[test]
    fn can_tag_range() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let mut tagged: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());

        tagged.tag(Tags::Hello, 0..5);
        tagged.tag(Tags::World, 1..6);

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_tag_everything_with_tags() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..5, Tags::Hello), (5..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_middle() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..4, Tags::Hello), (6..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 4);
        assert!(tagged[1] == TagSymbol::Untagged('o'));
        assert!(tagged[2] == TagSymbol::Untagged('W'));

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[3] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('o'));
            assert!(stream[1] == TagSymbol::Untagged('r'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_end() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..5, Tags::Hello)].iter().cloned());

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        assert!(tagged[1] == TagSymbol::Untagged('W'));
        assert!(tagged[2] == TagSymbol::Untagged('o'));
        assert!(tagged[3] == TagSymbol::Untagged('r'));
        assert!(tagged[4] == TagSymbol::Untagged('l'));
        assert!(tagged[5] == TagSymbol::Untagged('d'));
    }

    #[test]
    fn with_tags_preserves_start() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(5..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[5] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }

        assert!(tagged[0] == TagSymbol::Untagged('H'));
        assert!(tagged[1] == TagSymbol::Untagged('e'));
        assert!(tagged[2] == TagSymbol::Untagged('l'));
        assert!(tagged[3] == TagSymbol::Untagged('l'));
        assert!(tagged[4] == TagSymbol::Untagged('o'));
    }
}
<|endoftext|>


<commit_before>/// eventbox is a simple abstract of event handling
///
/// The concept is:
///
/// An eventbox stores a vector of events, the order does not mather.
///
/// 1. the sender and receiver of a/some events share an eventbox
/// 2. when some event happans, the sender push the event/value into the eventbox.
/// 3. Meanwhile the receiver is waiting(blocked).
/// 4. When some event happen, eventbox will notify the receiver.
///
/// # Examples
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// use fzf_rs::util::eventbox::EventBox;
/// let mut eb = Arc::new(EventBox::new());
/// let mut eb2 = eb.clone();
///
/// thread::spawn(move || {
///     eb2.set(10, Box::new(20));
/// });
///
/// let val: i32 = *eb.wait_for(10).downcast().unwrap();
/// assert_eq!(20, val);
/// ```

use std::sync::{Condvar, Mutex};
use std::collections::HashMap;
use std::any::Any;
use std::mem;

pub type EventType = i32;

pub type Value = Box<Any + 'static + Send>;
pub type Events = HashMap<EventType, Value>;

struct EventData {
    events: Events,
    ignore: Events,
}

pub struct EventBox {
    mutex: Mutex<EventData>,
    cond: Condvar,
}

impl EventBox {
    pub fn new() -> Self {
        EventBox {
            mutex: Mutex::new(EventData{events: HashMap::new(), ignore: HashMap::new()}),
            cond: Condvar::new(),
        }
    }

    /// wait: wait for an event(any) to fire
    /// if any event is triggered, run callback on events vector
    pub fn wait(&self) -> Events {
        let mut data = self.mutex.lock().unwrap();
        let events = mem::replace(&mut data.events, HashMap::new());
        let num_of_events = events.len();
        if num_of_events == 0 {
            let _ = self.cond.wait(data);
        }
        events
    }

    /// set: fires an event
    pub fn set(&self, e: EventType, value: Value) {
        let mut data = self.mutex.lock().unwrap();
        {
            let val = data.events.entry(e).or_insert(Box::new(0));
            *val = value;
        }
        if !data.ignore.contains_key(&e) {
            self.cond.notify_all();
        }
    }

    /// clear the event map
    pub fn clear(&self) {
        let mut data = self.mutex.lock().unwrap();
        data.events.clear();
    }

    // peek at the event box to check whether event had been set or not
    pub fn peek(&self, event: EventType) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.contains_key(&event)
    }

    // remove events from ignore table
    pub fn watch(&self, events: &Vec<EventType>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.remove(e);
        }
    }

    // add events from ignore table
    pub fn unwatch(&self, events: &Vec<EventType>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.insert(*e, Box::new(true));
        }
    }

    pub fn wait_for(&self, event: EventType) -> Value {
        'event_found: loop {
            for (e, val) in self.wait() {
                if e == event {
                    return val
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread;
    use std::sync::{Arc, Mutex};
    use std::mem;
    use std::time::Duration;

    #[test]
    fn test_wait() {
        const NUM_OF_EVENTS: i32 = 4;

        // create `NUM_OF_EVENTS` threads that set the return value to
        // their thread number, the sum up the value and compare it in
        // the main thread.

        let mut eb = Arc::new(EventBox::new());
        let mut counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            let mut count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
            thread::sleep(Duration::from_millis(100));
        }

        let mut total: i32 = 0;
        for (e, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_wait_for() {
        let mut eb = Arc::new(EventBox::new());
        let mut eb2 = eb.clone();

        thread::spawn(move || {
            eb2.set(10, Box::new(20));
        });

        let val: i32 = *eb.wait_for(10).downcast().unwrap();
        assert_eq!(20, val);
    }

    #[test]
    fn test_unwatch_set() {
        const NUM_OF_EVENTS: i32 = 4;
        let mut eb = Arc::new(EventBox::new());

        // this time, we ignore event NO. NUM_OF_EVENTS
        // note that unwatch will not trigger the event notification, but the
        // value are actually set.
        eb.unwatch(&vec![NUM_OF_EVENTS]);

        let mut counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            let mut count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
            thread::sleep(Duration::from_millis(100));
        }

        let mut total: i32 = 0;
        for (e, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_unwatch_notify() {
        // unwatched event will not trigger notification

        let eb = Arc::new(EventBox::new());

        eb.unwatch(&vec![1]);

        let eb_clone1 = eb.clone();

        let which_one = Arc::new(Mutex::new(1));
        let which_one_clone = which_one.clone();

        let wait = thread::spawn(move || {
            for (e, val) in eb.wait() {
                let mut data = which_one.lock().unwrap();
                assert_eq!(2, *data);
            }
        });

        thread::spawn(move || {
            eb_clone1.set(1, Box::new(1));

            // to ensure that the `wait` in main thread have time to trigger.
            // of course, the expected behavior is that it will not.
            thread::sleep(Duration::from_millis(100));

            let mut data = which_one_clone.lock().unwrap();
            *data = 2;
            eb_clone1.set(2, Box::new(2));
        });

        wait.join();
    }
}
<commit_msg>[util] add generic type support for eventbox<commit_after>/// eventbox is a simple abstract of event handling
///
/// The concept is:
///
/// An eventbox stores a vector of events, the order does not mather.
///
/// 1. the sender and receiver of a/some events share an eventbox
/// 2. when some event happans, the sender push the event/value into the eventbox.
/// 3. Meanwhile the receiver is waiting(blocked).
/// 4. When some event happen, eventbox will notify the receiver.
///
/// # Examples
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// use fzf_rs::util::eventbox::EventBox;
/// let mut eb = Arc::new(EventBox::new());
/// let mut eb2 = eb.clone();
///
/// thread::spawn(move || {
///     eb2.set(10, Box::new(20));
/// });
///
/// let val: i32 = *eb.wait_for(10).downcast().unwrap();
/// assert_eq!(20, val);
/// ```

use std::sync::{Condvar, Mutex};
use std::collections::HashMap;
use std::any::Any;
use std::mem;
use std::hash::Hash;

pub type Value = Box<Any + 'static + Send>;
pub type Events<T> = HashMap<T, Value>;

struct EventData<T> {
    events: Events<T>,
    ignore: Events<T>,
}

pub struct EventBox<T> {
    mutex: Mutex<EventData<T>>,
    cond: Condvar,
}

impl<T: Hash + Eq + Copy> EventBox<T> {
    pub fn new() -> Self {
        EventBox {
            mutex: Mutex::new(EventData{events: HashMap::new(), ignore: HashMap::new()}),
            cond: Condvar::new(),
        }
    }

    /// wait: wait for an event(any) to fire
    /// if any event is triggered, run callback on events vector
    pub fn wait(&self) -> Events<T> {
        let mut data = self.mutex.lock().unwrap();
        let events = mem::replace(&mut data.events, HashMap::new());
        let num_of_events = events.len();
        if num_of_events == 0 {
            let _ = self.cond.wait(data);
        }
        events
    }

    /// set: fires an event
    pub fn set(&self, e: T, value: Value) {
        let mut data = self.mutex.lock().unwrap();
        {
            let val = data.events.entry(e).or_insert(Box::new(0));
            *val = value;
        }
        if !data.ignore.contains_key(&e) {
            self.cond.notify_all();
        }
    }

    /// clear the event map
    pub fn clear(&self) {
        let mut data = self.mutex.lock().unwrap();
        data.events.clear();
    }

    // peek at the event box to check whether event had been set or not
    pub fn peek(&self, event: T) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.contains_key(&event)
    }

    // remove events from ignore table
    pub fn watch(&self, events: &Vec<T>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.remove(e);
        }
    }

    // add events from ignore table
    pub fn unwatch(&self, events: &Vec<T>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.insert(*e, Box::new(true));
        }
    }

    pub fn wait_for(&self, event: T) -> Value {
        'event_found: loop {
            for (e, val) in self.wait() {
                if e == event {
                    return val
                }
            }
        }
    }

    pub fn is_empty(&self) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.len() == 0
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread;
    use std::sync::{Arc, Mutex};
    use std::time::Duration;

    #[test]
    fn test_wait() {
        const NUM_OF_EVENTS: i32 = 4;

        // create `NUM_OF_EVENTS` threads that set the return value to
        // their thread number, the sum up the value and compare it in
        // the main thread.

        let eb = Arc::new(EventBox::new());
        let counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            thread::sleep(Duration::from_millis(100));
            let count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
        }

        let mut total: i32 = 0;
        for (_, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_wait_for() {
        let eb = Arc::new(EventBox::new());
        let eb2 = eb.clone();

        thread::spawn(move || {
            eb2.set(10, Box::new(20));
        });

        let val: i32 = *eb.wait_for(10).downcast().unwrap();
        assert_eq!(20, val);
    }

    #[test]
    fn test_unwatch_set() {
        const NUM_OF_EVENTS: i32 = 4;
        let eb = Arc::new(EventBox::new());

        // this time, we ignore event NO. NUM_OF_EVENTS
        // note that unwatch will not trigger the event notification, but the
        // value are actually set.
        eb.unwatch(&vec![NUM_OF_EVENTS]);

        let counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            thread::sleep(Duration::from_millis(100));
            let count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
        }

        let mut total: i32 = 0;
        for (_, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_unwatch_notify() {
        // unwatched event will not trigger notification

        let eb = Arc::new(EventBox::new());

        eb.unwatch(&vec![1]);

        let eb_clone1 = eb.clone();

        let which_one = Arc::new(Mutex::new(1));
        let which_one_clone = which_one.clone();

        let wait = thread::spawn(move || {
            for (_, _) in eb.wait() {
                let mut data = which_one.lock().unwrap();
                assert_eq!(2, *data);
            }
        });

        thread::spawn(move || {
            eb_clone1.set(1, Box::new(1));

            // to ensure that the `wait` in main thread have time to trigger.
            // of course, the expected behavior is that it will not.
            thread::sleep(Duration::from_millis(100));

            let mut data = which_one_clone.lock().unwrap();
            *data = 2;
            eb_clone1.set(2, Box::new(2));
        });

        wait.join();
    }
}
<|endoftext|>


<commit_before>use direction;
use event::*;
use menu::{MenuItem, MenuTree};
use rect::Rect;
use std::rc::Rc;
use theme::ColorStyle;
use unicode_width::UnicodeWidthStr;
use vec::Vec2;
use view::{Position, View};
use views::{MenuPopup, OnEventView};
use Cursive;
use Printer;

/// Current state of the menubar
#[derive(PartialEq, Debug)]
enum State {
    /// The menubar is inactive.
    Inactive,
    /// The menubar is actively selected.
    ///
    /// It will receive input.
    Selected,
    /// The menubar is still visible, but a submenu is open.
    ///
    /// It will not receive input.
    Submenu,
}

/// Shows a single-line list of items, with pop-up menus when one is selected.
///
/// The [`Cursive`] root already includes a menubar
/// that you just need to configure.
///
/// [`Cursive`]: ../struct.Cursive.html#method.menubar
pub struct Menubar {
    /// Menu items in this menubar.
    root: MenuTree,

    /// TODO: move this out of this view.
    pub autohide: bool,
    focus: usize,

    // TODO: make Menubar impl View and take out the State management
    state: State,
}

new_default!(Menubar);

impl Menubar {
    /// Creates a new, empty menubar.
    pub fn new() -> Self {
        Menubar {
            root: MenuTree::new(),
            autohide: true,
            state: State::Inactive,
            focus: 0,
        }
    }

    /// Hides the menubar.
    fn hide(&mut self) {
        self.state = State::Inactive;
    }

    /// True if we should be receiving events.
    pub fn receive_events(&self) -> bool {
        self.state == State::Selected
    }

    /// True if some submenus are visible.
    pub fn has_submenu(&self) -> bool {
        self.state == State::Submenu
    }

    /// Returns `true` if we should be drawn.
    pub fn visible(&self) -> bool {
        !self.autohide || self.state != State::Inactive
    }

    /// Adds a new item to the menubar.
    ///
    /// The item will use the given title, and on selection, will open a
    /// popup-menu with the given menu tree.
    pub fn add_subtree<S>(&mut self, title: S, menu: MenuTree) -> &mut Self
    where
        S: Into<String>,
    {
        let i = self.root.len();
        self.insert_subtree(i, title, menu)
    }

    /// Adds a delimiter to the menubar.
    pub fn add_delimiter(&mut self) -> &mut Self {
        let i = self.root.len();
        self.insert_delimiter(i)
    }

    /// Adds a leaf node to the menubar.
    pub fn add_leaf<S, F>(&mut self, title: S, cb: F) -> &mut Self
    where
        S: Into<String>,
        F: 'static + Fn(&mut Cursive),
    {
        let i = self.root.len();
        self.insert_leaf(i, title, cb)
    }

    /// Insert a new item at the given position.
    pub fn insert_subtree<S>(
        &mut self, i: usize, title: S, menu: MenuTree,
    ) -> &mut Self
    where
        S: Into<String>,
    {
        self.root.insert_subtree(i, title, menu);
        self
    }

    /// Inserts a new delimiter at the given position.
    ///
    /// It will show up as `|`.
    pub fn insert_delimiter(&mut self, i: usize) -> &mut Self {
        self.root.insert_delimiter(i);
        self
    }

    /// Inserts a new leaf node at the given position.
    ///
    /// It will be directly actionable.
    pub fn insert_leaf<S, F>(&mut self, i: usize, title: S, cb: F) -> &mut Self
    where
        S: Into<String>,
        F: 'static + Fn(&mut Cursive),
    {
        self.root.insert_leaf(i, title, cb);
        self
    }

    /// Removes all menu items from this menubar.
    pub fn clear(&mut self) {
        self.root.clear();
        self.focus = 0;
    }

    /// Returns the number of items in this menubar.
    pub fn len(&self) -> usize {
        self.root.len()
    }

    /// Returns `true` if this menubar is empty.
    pub fn is_empty(&self) -> bool {
        self.root.is_empty()
    }

    /// Returns the item at the given position.
    ///
    /// Returns `None` if `i > self.len()`
    pub fn get_subtree(&mut self, i: usize) -> Option<&mut MenuTree> {
        self.root.get_subtree(i)
    }

    /// Looks for an item with the given label.
    pub fn find_subtree(&mut self, label: &str) -> Option<&mut MenuTree> {
        self.root.find_subtree(label)
    }

    /// Returns the position of the item with the given label.
    ///
    /// Returns `None` if no such label was found.
    pub fn find_position(&mut self, label: &str) -> Option<usize> {
        self.root.find_position(label)
    }

    /// Remove the item at the given position.
    pub fn remove(&mut self, i: usize) {
        self.root.remove(i);
    }

    fn child_at(&self, x: usize) -> Option<usize> {
        if x == 0 {
            return None;
        }
        let mut offset = 1;

        for (i, child) in self.root.children.iter().enumerate() {
            offset += child.label().width() + 2;
            if x < offset {
                return Some(i);
            }
        }

        None
    }

    fn select_child(&mut self, open_only: bool) -> EventResult {
        match self.root.children[self.focus] {
            MenuItem::Leaf(_, ref cb) if !open_only => {
                EventResult::Consumed(Some(cb.clone()))
            }
            MenuItem::Subtree(_, ref tree) => {
                // First, we need a new Rc to send the callback,
                // since we don't know when it will be called.
                let menu = Rc::clone(tree);

                self.state = State::Submenu;
                let offset = Vec2::new(
                    self.root.children[..self.focus]
                        .iter()
                        .map(|child| child.label().width() + 2)
                        .sum(),
                    if self.autohide { 1 } else { 0 },
                );
                // Since the closure will be called multiple times,
                // we also need a new Rc on every call.
                EventResult::with_cb(move |s| {
                    show_child(s, offset, Rc::clone(&menu))
                })
            }
            _ => EventResult::Ignored,
        }
    }
}

fn show_child(s: &mut Cursive, offset: Vec2, menu: Rc<MenuTree>) {
    // Adds a new layer located near the item title with the menu popup.
    // Also adds two key callbacks on this new view, to handle `left` and
    // `right` key presses.
    // (If the view itself listens for a `left` or `right` press, it will
    // consume it before our OnEventView. This means sub-menus can properly
    // be entered.)
    s.screen_mut().add_layer_at(
        Position::absolute(offset),
        OnEventView::new(
            MenuPopup::new(menu)
                .on_dismiss(|s| s.select_menubar())
                .on_action(|s| s.menubar().state = State::Inactive),
        ).on_event(Key::Right, |s| {
            s.pop_layer();
            s.select_menubar();
            // Act as if we sent "Right" then "Down"
            s.menubar().on_event(Event::Key(Key::Right)).process(s);
            if let EventResult::Consumed(Some(cb)) =
                s.menubar().on_event(Event::Key(Key::Down))
            {
                cb(s);
            }
        })
            .on_event(Key::Left, |s| {
                s.pop_layer();
                s.select_menubar();
                // Act as if we sent "Left" then "Down"
                s.menubar().on_event(Event::Key(Key::Left)).process(s);
                if let EventResult::Consumed(Some(cb)) =
                    s.menubar().on_event(Event::Key(Key::Down))
                {
                    cb(s);
                }
            }),
    );
}

impl View for Menubar {
    fn draw(&self, printer: &Printer) {
        // Draw the bar at the top
        printer.with_color(ColorStyle::primary(), |printer| {
            printer.print_hline((0, 0), printer.size.x, " ");
        });

        // TODO: draw the rest
        let mut offset = 1;
        for (i, item) in self.root.children.iter().enumerate() {
            let title = item.label();

            // We don't want to show HighlightInactive when we're not selected,
            // because it's ugly on the menubar.
            let selected =
                (self.state != State::Inactive) && (i == self.focus);
            printer.with_selection(selected, |printer| {
                printer.print((offset, 0), &format!(" {} ", title));
            });
            offset += title.width() + 2;
        }
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Key(Key::Esc) => {
                self.hide();
                return EventResult::with_cb(|s| s.clear());
            }
            Event::Key(Key::Left) => loop {
                if self.focus > 0 {
                    self.focus -= 1;
                } else {
                    self.focus = self.root.len() - 1;
                }
                if !self.root.children[self.focus].is_delimiter() {
                    break;
                }
            },
            Event::Key(Key::Right) => loop {
                if self.focus + 1 < self.root.len() {
                    self.focus += 1;
                } else {
                    self.focus = 0;
                }
                if !self.root.children[self.focus].is_delimiter() {
                    break;
                }
            },
            Event::Key(Key::Down) => {
                return self.select_child(true);
            }
            Event::Key(Key::Enter) => {
                return self.select_child(false);
            }
            Event::Mouse {
                event: MouseEvent::Press(btn),
                position,
                offset,
            }
                if position.fits(offset) && position.y == offset.y =>
            {
                if let Some(child) = position
                    .checked_sub(offset)
                    .and_then(|pos| self.child_at(pos.x))
                {
                    if !self.root.children[child].is_delimiter() {
                        self.focus = child;
                        if btn == MouseButton::Left {
                            return self.select_child(true);
                        }
                    }
                }
            }
            Event::Mouse {
                event: MouseEvent::Release(btn),
                position,
                offset,
            }
                if position.fits(offset) && position.y == offset.y =>
            {
                if let Some(child) = position
                    .checked_sub(offset)
                    .and_then(|pos| self.child_at(pos.x))
                {
                    if self.focus == child
                        && btn == MouseButton::Left
                        && self.root.children[child].is_leaf()
                    {
                        return self.select_child(false);
                    }
                }
            }
            Event::Mouse {
                event: MouseEvent::Press(_),
                ..
            } => {
                self.hide();
                return EventResult::with_cb(|s| s.clear());
            }
            _ => return EventResult::Ignored,
        }
        EventResult::Consumed(None)
    }

    fn take_focus(&mut self, _: direction::Direction) -> bool {
        self.state = State::Selected;
        true
    }

    fn required_size(&mut self, _: Vec2) -> Vec2 {
        // TODO: scroll the options if the screen is too small?

        // We add 2 to the length of every label for marin.
        // Also, we add 1 at the beginning.
        // (See the `draw()` method)
        let width = self
            .root
            .children
            .iter()
            .map(|item| item.label().len() + 2)
            .sum();

        Vec2::new(width, 1)
    }

    fn important_area(&self, _: Vec2) -> Rect {
        if self.root.is_empty() {
            return Rect::from((0, 0));
        }

        // X position is 1 (margin before the first item) + sum of widths
        // And each item has a 2 cells padding.
        let x = 1 + self.root.children[..self.focus]
            .iter()
            .map(|child| child.label().width() + 2)
            .sum::<usize>();

        let width = self.root.children[self.focus].label().width();

        Rect::from_size((x, 0), (width, 1))
    }
}
<commit_msg>Lose menubar focus after leaf action<commit_after>use direction;
use event::*;
use menu::{MenuItem, MenuTree};
use rect::Rect;
use std::rc::Rc;
use theme::ColorStyle;
use unicode_width::UnicodeWidthStr;
use vec::Vec2;
use view::{Position, View};
use views::{MenuPopup, OnEventView};
use Cursive;
use Printer;

/// Current state of the menubar
#[derive(PartialEq, Debug)]
enum State {
    /// The menubar is inactive.
    Inactive,
    /// The menubar is actively selected.
    ///
    /// It will receive input.
    Selected,
    /// The menubar is still visible, but a submenu is open.
    ///
    /// It will not receive input.
    Submenu,
}

/// Shows a single-line list of items, with pop-up menus when one is selected.
///
/// The [`Cursive`] root already includes a menubar
/// that you just need to configure.
///
/// [`Cursive`]: ../struct.Cursive.html#method.menubar
pub struct Menubar {
    /// Menu items in this menubar.
    root: MenuTree,

    /// TODO: move this out of this view.
    pub autohide: bool,
    focus: usize,

    // TODO: make Menubar impl View and take out the State management
    state: State,
}

new_default!(Menubar);

impl Menubar {
    /// Creates a new, empty menubar.
    pub fn new() -> Self {
        Menubar {
            root: MenuTree::new(),
            autohide: true,
            state: State::Inactive,
            focus: 0,
        }
    }

    /// Hides the menubar.
    fn hide(&mut self) {
        self.state = State::Inactive;
    }

    /// True if we should be receiving events.
    pub fn receive_events(&self) -> bool {
        self.state == State::Selected
    }

    /// True if some submenus are visible.
    pub fn has_submenu(&self) -> bool {
        self.state == State::Submenu
    }

    /// Returns `true` if we should be drawn.
    pub fn visible(&self) -> bool {
        !self.autohide || self.state != State::Inactive
    }

    /// Adds a new item to the menubar.
    ///
    /// The item will use the given title, and on selection, will open a
    /// popup-menu with the given menu tree.
    pub fn add_subtree<S>(&mut self, title: S, menu: MenuTree) -> &mut Self
    where
        S: Into<String>,
    {
        let i = self.root.len();
        self.insert_subtree(i, title, menu)
    }

    /// Adds a delimiter to the menubar.
    pub fn add_delimiter(&mut self) -> &mut Self {
        let i = self.root.len();
        self.insert_delimiter(i)
    }

    /// Adds a leaf node to the menubar.
    pub fn add_leaf<S, F>(&mut self, title: S, cb: F) -> &mut Self
    where
        S: Into<String>,
        F: 'static + Fn(&mut Cursive),
    {
        let i = self.root.len();
        self.insert_leaf(i, title, cb)
    }

    /// Insert a new item at the given position.
    pub fn insert_subtree<S>(
        &mut self, i: usize, title: S, menu: MenuTree,
    ) -> &mut Self
    where
        S: Into<String>,
    {
        self.root.insert_subtree(i, title, menu);
        self
    }

    /// Inserts a new delimiter at the given position.
    ///
    /// It will show up as `|`.
    pub fn insert_delimiter(&mut self, i: usize) -> &mut Self {
        self.root.insert_delimiter(i);
        self
    }

    /// Inserts a new leaf node at the given position.
    ///
    /// It will be directly actionable.
    pub fn insert_leaf<S, F>(&mut self, i: usize, title: S, cb: F) -> &mut Self
    where
        S: Into<String>,
        F: 'static + Fn(&mut Cursive),
    {
        self.root.insert_leaf(i, title, cb);
        self
    }

    /// Removes all menu items from this menubar.
    pub fn clear(&mut self) {
        self.root.clear();
        self.focus = 0;
    }

    /// Returns the number of items in this menubar.
    pub fn len(&self) -> usize {
        self.root.len()
    }

    /// Returns `true` if this menubar is empty.
    pub fn is_empty(&self) -> bool {
        self.root.is_empty()
    }

    /// Returns the item at the given position.
    ///
    /// Returns `None` if `i > self.len()`
    pub fn get_subtree(&mut self, i: usize) -> Option<&mut MenuTree> {
        self.root.get_subtree(i)
    }

    /// Looks for an item with the given label.
    pub fn find_subtree(&mut self, label: &str) -> Option<&mut MenuTree> {
        self.root.find_subtree(label)
    }

    /// Returns the position of the item with the given label.
    ///
    /// Returns `None` if no such label was found.
    pub fn find_position(&mut self, label: &str) -> Option<usize> {
        self.root.find_position(label)
    }

    /// Remove the item at the given position.
    pub fn remove(&mut self, i: usize) {
        self.root.remove(i);
    }

    fn child_at(&self, x: usize) -> Option<usize> {
        if x == 0 {
            return None;
        }
        let mut offset = 1;

        for (i, child) in self.root.children.iter().enumerate() {
            offset += child.label().width() + 2;
            if x < offset {
                return Some(i);
            }
        }

        None
    }

    fn select_child(&mut self, open_only: bool) -> EventResult {
        match self.root.children[self.focus] {
            MenuItem::Leaf(_, ref cb) if !open_only => {
                // Go inactive after an action.
                self.state = State::Inactive;
                EventResult::Consumed(Some(cb.clone()))
            }
            MenuItem::Subtree(_, ref tree) => {
                // First, we need a new Rc to send the callback,
                // since we don't know when it will be called.
                let menu = Rc::clone(tree);

                self.state = State::Submenu;
                let offset = Vec2::new(
                    self.root.children[..self.focus]
                        .iter()
                        .map(|child| child.label().width() + 2)
                        .sum(),
                    if self.autohide { 1 } else { 0 },
                );
                // Since the closure will be called multiple times,
                // we also need a new Rc on every call.
                EventResult::with_cb(move |s| {
                    show_child(s, offset, Rc::clone(&menu))
                })
            }
            _ => EventResult::Ignored,
        }
    }
}

fn show_child(s: &mut Cursive, offset: Vec2, menu: Rc<MenuTree>) {
    // Adds a new layer located near the item title with the menu popup.
    // Also adds two key callbacks on this new view, to handle `left` and
    // `right` key presses.
    // (If the view itself listens for a `left` or `right` press, it will
    // consume it before our OnEventView. This means sub-menus can properly
    // be entered.)
    s.screen_mut().add_layer_at(
        Position::absolute(offset),
        OnEventView::new(
            MenuPopup::new(menu)
                .on_dismiss(|s| s.select_menubar())
                .on_action(|s| s.menubar().state = State::Inactive),
        ).on_event(Key::Right, |s| {
            s.pop_layer();
            s.select_menubar();
            // Act as if we sent "Right" then "Down"
            s.menubar().on_event(Event::Key(Key::Right)).process(s);
            if let EventResult::Consumed(Some(cb)) =
                s.menubar().on_event(Event::Key(Key::Down))
            {
                cb(s);
            }
        })
            .on_event(Key::Left, |s| {
                s.pop_layer();
                s.select_menubar();
                // Act as if we sent "Left" then "Down"
                s.menubar().on_event(Event::Key(Key::Left)).process(s);
                if let EventResult::Consumed(Some(cb)) =
                    s.menubar().on_event(Event::Key(Key::Down))
                {
                    cb(s);
                }
            }),
    );
}

impl View for Menubar {
    fn draw(&self, printer: &Printer) {
        // Draw the bar at the top
        printer.with_color(ColorStyle::primary(), |printer| {
            printer.print_hline((0, 0), printer.size.x, " ");
        });

        // TODO: draw the rest
        let mut offset = 1;
        for (i, item) in self.root.children.iter().enumerate() {
            let title = item.label();

            // We don't want to show HighlightInactive when we're not selected,
            // because it's ugly on the menubar.
            let selected =
                (self.state != State::Inactive) && (i == self.focus);
            printer.with_selection(selected, |printer| {
                printer.print((offset, 0), &format!(" {} ", title));
            });
            offset += title.width() + 2;
        }
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Key(Key::Esc) => {
                self.hide();
                return EventResult::with_cb(|s| s.clear());
            }
            Event::Key(Key::Left) => loop {
                if self.focus > 0 {
                    self.focus -= 1;
                } else {
                    self.focus = self.root.len() - 1;
                }
                if !self.root.children[self.focus].is_delimiter() {
                    break;
                }
            },
            Event::Key(Key::Right) => loop {
                if self.focus + 1 < self.root.len() {
                    self.focus += 1;
                } else {
                    self.focus = 0;
                }
                if !self.root.children[self.focus].is_delimiter() {
                    break;
                }
            },
            Event::Key(Key::Down) => {
                return self.select_child(true);
            }
            Event::Key(Key::Enter) => {
                return self.select_child(false);
            }
            Event::Mouse {
                event: MouseEvent::Press(btn),
                position,
                offset,
            }
                if position.fits(offset) && position.y == offset.y =>
            {
                if let Some(child) = position
                    .checked_sub(offset)
                    .and_then(|pos| self.child_at(pos.x))
                {
                    if !self.root.children[child].is_delimiter() {
                        self.focus = child;
                        if btn == MouseButton::Left {
                            return self.select_child(true);
                        }
                    }
                }
            }
            Event::Mouse {
                event: MouseEvent::Release(btn),
                position,
                offset,
            }
                if position.fits(offset) && position.y == offset.y =>
            {
                if let Some(child) = position
                    .checked_sub(offset)
                    .and_then(|pos| self.child_at(pos.x))
                {
                    if self.focus == child
                        && btn == MouseButton::Left
                        && self.root.children[child].is_leaf()
                    {
                        return self.select_child(false);
                    }
                }
            }
            Event::Mouse {
                event: MouseEvent::Press(_),
                ..
            } => {
                self.hide();
                return EventResult::with_cb(|s| s.clear());
            }
            _ => return EventResult::Ignored,
        }
        EventResult::Consumed(None)
    }

    fn take_focus(&mut self, _: direction::Direction) -> bool {
        self.state = State::Selected;
        true
    }

    fn required_size(&mut self, _: Vec2) -> Vec2 {
        // TODO: scroll the options if the screen is too small?

        // We add 2 to the length of every label for marin.
        // Also, we add 1 at the beginning.
        // (See the `draw()` method)
        let width = self
            .root
            .children
            .iter()
            .map(|item| item.label().len() + 2)
            .sum();

        Vec2::new(width, 1)
    }

    fn important_area(&self, _: Vec2) -> Rect {
        if self.root.is_empty() {
            return Rect::from((0, 0));
        }

        // X position is 1 (margin before the first item) + sum of widths
        // And each item has a 2 cells padding.
        let x = 1 + self.root.children[..self.focus]
            .iter()
            .map(|child| child.label().width() + 2)
            .sum::<usize>();

        let width = self.root.children[self.focus].label().width();

        Rect::from_size((x, 0), (width, 1))
    }
}
<|endoftext|>