diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-04-05 18:33:12 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-05 16:11:13 +0200 |
commit | d077637fd6a3ccd854a7ae62784a760998e7448b (patch) | |
tree | 7ab401845f3174463b9accb17ee437402457a368 /Userland | |
parent | 7b54274ac5bf6893933eb110a30bdc7d671454c5 (diff) | |
download | serenity-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.cpp | 122 |
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>(); |