0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-02 04:38:21 -05:00

feat(cli/repl): add regex based syntax highlighter (#7811)

This commit adds a simple regex replace based highlighter 
to the REPL editor.

It tries to match the color palette of Deno.inspect()
This commit is contained in:
Casper Beyer 2020-10-13 22:23:02 +08:00 committed by GitHub
parent 0dcaea72ae
commit bbf7b2ee72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::colors;
use crate::inspector::InspectorSession;
use crate::program_state::ProgramState;
use crate::worker::MainWorker;
@ -7,19 +8,24 @@ use crate::worker::Worker;
use deno_core::error::AnyError;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use regex::Captures;
use regex::Regex;
use rustyline::error::ReadlineError;
use rustyline::highlight::Highlighter;
use rustyline::validate::MatchingBracketValidator;
use rustyline::validate::ValidationContext;
use rustyline::validate::ValidationResult;
use rustyline::validate::Validator;
use rustyline::Editor;
use rustyline_derive::{Completer, Helper, Highlighter, Hinter};
use rustyline_derive::{Completer, Helper, Hinter};
use std::borrow::Cow;
use std::sync::Arc;
use std::sync::Mutex;
// Provides syntax specific helpers to the editor like validation for multi-line edits.
#[derive(Completer, Helper, Highlighter, Hinter)]
#[derive(Completer, Helper, Hinter)]
struct Helper {
highlighter: LineHighlighter,
validator: MatchingBracketValidator,
}
@ -32,6 +38,82 @@ impl Validator for Helper {
}
}
impl Highlighter for Helper {
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()
}
}
struct LineHighlighter {
regex: Regex,
}
impl LineHighlighter {
fn new() -> Self {
let regex = Regex::new(
r#"(?x)
(?P<comment>(?:/\*[\s\S]*?\*/|//[^\n]*)) |
(?P<string>(?:"([^"\\]|\\.)*"|'([^'\\]|\\.)*'|`([^`\\]|\\.)*`)) |
(?P<regexp>/(?:(?:\\/|[^\n/]))*?/[gimsuy]*) |
(?P<number>\d+(?:\.\d+)*(?:e[+-]?\d+)*n?) |
(?P<boolean>\b(?:true|false)\b) |
(?P<null>\b(?:null)\b) |
(?P<undefined>\b(?:undefined)\b) |
(?P<keyword>\b(?:await|async|var|let|for|if|else|in|of|class|const|function|yield|return|with|case|break|switch|import|export|new|while|do|throw|catch)\b) |
"#,
)
.unwrap();
Self { regex }
}
}
impl Highlighter for LineHighlighter {
fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> {
self
.regex
.replace_all(&line.to_string(), |caps: &Captures<'_>| {
if let Some(cap) = caps.name("comment") {
format!("{}", colors::gray(cap.as_str()))
} else if let Some(cap) = caps.name("string") {
format!("{}", colors::green(cap.as_str()))
} else if let Some(cap) = caps.name("regexp") {
format!("{}", colors::red(cap.as_str()))
} else if let Some(cap) = caps.name("number") {
format!("{}", colors::yellow(cap.as_str()))
} else if let Some(cap) = caps.name("boolean") {
format!("{}", colors::yellow(cap.as_str()))
} else if let Some(cap) = caps.name("null") {
format!("{}", colors::yellow(cap.as_str()))
} else if let Some(cap) = caps.name("undefined") {
format!("{}", colors::gray(cap.as_str()))
} else if let Some(cap) = caps.name("keyword") {
format!("{}", colors::cyan(cap.as_str()))
} else {
caps[0].to_string()
}
})
.to_string()
.into()
}
}
async fn post_message_and_poll(
worker: &mut Worker,
session: &mut InspectorSession,
@ -116,6 +198,7 @@ pub async fn run(
}
let helper = Helper {
highlighter: LineHighlighter::new(),
validator: MatchingBracketValidator::new(),
};