summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-04-05 18:33:12 +0430
committerAndreas Kling <kling@serenityos.org>2020-04-05 16:11:13 +0200
commitd077637fd6a3ccd854a7ae62784a760998e7448b (patch)
tree7ab401845f3174463b9accb17ee437402457a368 /Userland
parent7b54274ac5bf6893933eb110a30bdc7d671454c5 (diff)
downloadserenity-d077637fd6a3ccd854a7ae62784a760998e7448b.zip
JS Repl: Add live syntax highlighting
This patchset adds live syntax highlighting to the js repl. It is turned off by default and can be enabled via the -s flag.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/js.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/Userland/js.cpp b/Userland/js.cpp
index a41565dd44..ea21e8314a 100644
--- a/Userland/js.cpp
+++ b/Userland/js.cpp
@@ -350,6 +350,7 @@ int main(int argc, char** argv)
{
bool gc_on_every_allocation = false;
bool print_last_result = false;
+ bool syntax_highlight = false;
bool test_mode = false;
const char* script_path = nullptr;
@@ -357,6 +358,7 @@ int main(int argc, char** argv)
args_parser.add_option(dump_ast, "Dump the AST", "dump-ast", 'A');
args_parser.add_option(print_last_result, "Print last result", "print-last-result", 'l');
args_parser.add_option(gc_on_every_allocation, "GC on every allocation", "gc-on-every-allocation", 'g');
+ args_parser.add_option(syntax_highlight, "Enable live syntax highlighting", "syntax-highlight", 's');
args_parser.add_option(test_mode, "Run the interpretter with added functionality for the test harness", "test-mode", 't');
args_parser.add_positional_argument(script_path, "Path to script file", "script", Core::ArgsParser::Required::No);
args_parser.parse(argc, argv);
@@ -371,6 +373,126 @@ int main(int argc, char** argv)
editor = make<Line::Editor>();
editor->initialize();
+ if (syntax_highlight)
+ editor->on_display_refresh = [](Line::Editor& editor) {
+ editor.strip_styles();
+ StringBuilder builder;
+ builder.append({ editor.buffer().data(), editor.buffer().size() });
+ // FIXME: The lexer returns weird position information without this
+ builder.append(" ");
+ String str = builder.build();
+
+ JS::Lexer lexer(str, false);
+ for (JS::Token token = lexer.next(); token.type() != JS::TokenType::Eof; token = lexer.next()) {
+ auto length = token.value().length();
+ auto start = token.line_column() - 2;
+ auto end = start + length;
+
+ switch (token.type()) {
+ case JS::TokenType::Invalid:
+ case JS::TokenType::Eof:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Red), Line::Style::Underline });
+ break;
+ case JS::TokenType::NumericLiteral:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Magenta) });
+ break;
+ case JS::TokenType::StringLiteral:
+ case JS::TokenType::RegexLiteral:
+ case JS::TokenType::UnterminatedStringLiteral:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Red) });
+ break;
+ case JS::TokenType::BracketClose:
+ case JS::TokenType::BracketOpen:
+ case JS::TokenType::Caret:
+ case JS::TokenType::Comma:
+ case JS::TokenType::CurlyClose:
+ case JS::TokenType::CurlyOpen:
+ case JS::TokenType::ParenClose:
+ case JS::TokenType::ParenOpen:
+ case JS::TokenType::Semicolon:
+ case JS::TokenType::Period:
+ break;
+ case JS::TokenType::Ampersand:
+ case JS::TokenType::AmpersandEquals:
+ case JS::TokenType::Asterisk:
+ case JS::TokenType::AsteriskAsteriskEquals:
+ case JS::TokenType::AsteriskEquals:
+ case JS::TokenType::DoubleAmpersand:
+ case JS::TokenType::DoubleAsterisk:
+ case JS::TokenType::DoublePipe:
+ case JS::TokenType::DoubleQuestionMark:
+ case JS::TokenType::Equals:
+ case JS::TokenType::EqualsEquals:
+ case JS::TokenType::EqualsEqualsEquals:
+ case JS::TokenType::ExclamationMark:
+ case JS::TokenType::ExclamationMarkEquals:
+ case JS::TokenType::ExclamationMarkEqualsEquals:
+ case JS::TokenType::GreaterThan:
+ case JS::TokenType::GreaterThanEquals:
+ case JS::TokenType::LessThan:
+ case JS::TokenType::LessThanEquals:
+ case JS::TokenType::Minus:
+ case JS::TokenType::MinusEquals:
+ case JS::TokenType::MinusMinus:
+ case JS::TokenType::Percent:
+ case JS::TokenType::PercentEquals:
+ case JS::TokenType::Pipe:
+ case JS::TokenType::PipeEquals:
+ case JS::TokenType::Plus:
+ case JS::TokenType::PlusEquals:
+ case JS::TokenType::PlusPlus:
+ case JS::TokenType::QuestionMark:
+ case JS::TokenType::QuestionMarkPeriod:
+ case JS::TokenType::ShiftLeft:
+ case JS::TokenType::ShiftLeftEquals:
+ case JS::TokenType::ShiftRight:
+ case JS::TokenType::ShiftRightEquals:
+ case JS::TokenType::Slash:
+ case JS::TokenType::SlashEquals:
+ case JS::TokenType::Tilde:
+ case JS::TokenType::UnsignedShiftRight:
+ case JS::TokenType::UnsignedShiftRightEquals:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Magenta) });
+ break;
+ case JS::TokenType::NullLiteral:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Yellow), Line::Style::Bold });
+ break;
+ case JS::TokenType::BoolLiteral:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Green), Line::Style::Bold });
+ break;
+ case JS::TokenType::Class:
+ case JS::TokenType::Const:
+ case JS::TokenType::Delete:
+ case JS::TokenType::Function:
+ case JS::TokenType::In:
+ case JS::TokenType::Instanceof:
+ case JS::TokenType::Interface:
+ case JS::TokenType::Let:
+ case JS::TokenType::New:
+ case JS::TokenType::Typeof:
+ case JS::TokenType::Var:
+ case JS::TokenType::Void:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Blue), Line::Style::Bold });
+ break;
+ case JS::TokenType::Await:
+ case JS::TokenType::Catch:
+ case JS::TokenType::Do:
+ case JS::TokenType::Else:
+ case JS::TokenType::Finally:
+ case JS::TokenType::For:
+ case JS::TokenType::If:
+ case JS::TokenType::Return:
+ case JS::TokenType::Try:
+ case JS::TokenType::While:
+ case JS::TokenType::Yield:
+ editor.stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Cyan), Line::Style::Italic });
+ break;
+ case JS::TokenType::Identifier:
+ default:
+ break;
+ }
+ }
+ };
repl(*interpreter);
} else {
auto interpreter = JS::Interpreter::create<JS::GlobalObject>();