Skip to content

Commit

Permalink
Added keyword and operator colors and matching bracket validator to c…
Browse files Browse the repository at this point in the history
…li (#590)
  • Loading branch information
HalidOdat authored Jul 25, 2020
1 parent 795adc5 commit 24a72ea
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 3 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions boa_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ edition = "2018"
[dependencies]
Boa = { path = "../boa", features = ["serde"] }
rustyline = "6.2.0"
rustyline-derive = "0.3.1"
structopt = "0.3.15"
serde_json = "1.0.56"
colored = "2.0.0"
regex = "1"
lazy_static = "1.4.0"

[target.x86_64-unknown-linux-gnu.dependencies]
jemallocator = "0.3.2"
Expand Down
136 changes: 133 additions & 3 deletions boa_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,18 @@ use boa::{
syntax::ast::{node::StatementList, token::Token},
};
use colored::*;
use rustyline::{config::Config, error::ReadlineError, EditMode, Editor};
use lazy_static::lazy_static;
use regex::{Captures, Regex};
use rustyline::{
config::Config,
error::ReadlineError,
highlight::Highlighter,
validate::{MatchingBracketValidator, ValidationContext, ValidationResult, Validator},
EditMode, Editor,
};
use rustyline_derive::{Completer, Helper, Hinter};
use std::borrow::Cow;
use std::collections::HashSet;
use std::{fs::read_to_string, path::PathBuf};
use structopt::{clap::arg_enum, StructOpt};

Expand Down Expand Up @@ -206,10 +217,14 @@ pub fn main() -> Result<(), std::io::Error> {
})
.build();

let mut editor = Editor::<()>::with_config(config);
let mut editor = Editor::with_config(config);
let _ = editor.load_history(CLI_HISTORY);
editor.set_helper(Some(RLHelper {
highlighter: LineHighlighter,
validator: MatchingBracketValidator::new(),
}));

let readline = "> ".cyan().bold().to_string();
let readline = ">> ".cyan().bold().to_string();

loop {
match editor.readline(&readline) {
Expand Down Expand Up @@ -243,3 +258,118 @@ pub fn main() -> Result<(), std::io::Error> {

Ok(())
}

#[derive(Completer, Helper, Hinter)]
struct RLHelper {
highlighter: LineHighlighter,
validator: MatchingBracketValidator,
}

impl Validator for RLHelper {
fn validate(&self, ctx: &mut ValidationContext<'_>) -> Result<ValidationResult, ReadlineError> {
self.validator.validate(ctx)
}

fn validate_while_typing(&self) -> bool {
self.validator.validate_while_typing()
}
}

impl Highlighter for RLHelper {
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
hint.into()
}

fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
self.highlighter.highlight(line, pos)
}

fn highlight_candidate<'c>(
&self,
candidate: &'c str,
_completion: rustyline::CompletionType,
) -> Cow<'c, str> {
self.highlighter.highlight(candidate, 0)
}

fn highlight_char(&self, line: &str, _: usize) -> bool {
!line.is_empty()
}
}

lazy_static! {
static ref KEYWORDS: HashSet<&'static str> = {
let mut keywords = HashSet::new();
keywords.insert("break");
keywords.insert("case");
keywords.insert("catch");
keywords.insert("class");
keywords.insert("const");
keywords.insert("continue");
keywords.insert("default");
keywords.insert("delete");
keywords.insert("do");
keywords.insert("else");
keywords.insert("export");
keywords.insert("extends");
keywords.insert("finally");
keywords.insert("for");
keywords.insert("function");
keywords.insert("if");
keywords.insert("import");
keywords.insert("instanceof");
keywords.insert("new");
keywords.insert("return");
keywords.insert("super");
keywords.insert("switch");
keywords.insert("this");
keywords.insert("throw");
keywords.insert("try");
keywords.insert("typeof");
keywords.insert("var");
keywords.insert("void");
keywords.insert("while");
keywords.insert("with");
keywords.insert("yield");
keywords.insert("await");
keywords.insert("enum");
keywords.insert("let");
keywords
};
}

struct LineHighlighter;

impl Highlighter for LineHighlighter {
fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> {
let mut coloured = line.to_string();

let reg = Regex::new(
r"(?x)
(?P<identifier>[$A-z_]+[$A-z_0-9]*) |
(?P<op>[+\-/*%~^!&|=<>,.;:])",
)
.unwrap();

coloured = reg
.replace_all(&coloured, |caps: &Captures<'_>| {
if let Some(cap) = caps.name("identifier") {
match cap.as_str() {
"true" | "false" | "null" | "Infinity" => cap.as_str().purple().to_string(),
"undefined" => cap.as_str().truecolor(100, 100, 100).to_string(),
identifier if KEYWORDS.contains(identifier) => {
cap.as_str().yellow().bold().to_string()
}
_ => cap.as_str().to_string(),
}
} else if let Some(cap) = caps.name("op") {
cap.as_str().green().to_string()
} else {
caps[0].to_string()
}
})
.to_string();

coloured.into()
}
}

0 comments on commit 24a72ea

Please sign in to comment.