diff --git a/Userland/Libraries/LibWebView/SourceHighlighter.cpp b/Userland/Libraries/LibWebView/SourceHighlighter.cpp index 8da836d4475..bbc34c90caa 100644 --- a/Userland/Libraries/LibWebView/SourceHighlighter.cpp +++ b/Userland/Libraries/LibWebView/SourceHighlighter.cpp @@ -6,7 +6,11 @@ */ #include +#include +#include #include +#include +#include #include #include @@ -40,9 +44,15 @@ SourceHighlighterClient::SourceHighlighterClient(StringView source, Syntax::Lang Gfx::Palette dummy_palette { palette_impl }; switch (language) { + case Syntax::Language::CSS: + m_highlighter = make(); + break; case Syntax::Language::HTML: m_highlighter = make(); break; + case Syntax::Language::JavaScript: + m_highlighter = make(); + break; default: break; } @@ -111,24 +121,115 @@ String highlight_source(URL::URL const& url, StringView source) StringView SourceHighlighterClient::class_for_token(u64 token_type) const { - switch (static_cast(token_type)) { - case Web::HTML::AugmentedTokenKind::AttributeName: - return "attribute-name"sv; - case Web::HTML::AugmentedTokenKind::AttributeValue: - return "attribute-value"sv; - case Web::HTML::AugmentedTokenKind::OpenTag: - case Web::HTML::AugmentedTokenKind::CloseTag: - return "tag"sv; - case Web::HTML::AugmentedTokenKind::Comment: - return "comment"sv; - case Web::HTML::AugmentedTokenKind::Doctype: - return "doctype"sv; - case Web::HTML::AugmentedTokenKind::__Count: - default: - break; - } + auto class_for_css_token = [](u64 token_type) { + switch (static_cast(token_type)) { + case Web::CSS::Parser::Token::Type::Invalid: + case Web::CSS::Parser::Token::Type::BadString: + case Web::CSS::Parser::Token::Type::BadUrl: + return "invalid"sv; + case Web::CSS::Parser::Token::Type::Ident: + return "identifier"sv; + case Web::CSS::Parser::Token::Type::Function: + return "function"sv; + case Web::CSS::Parser::Token::Type::AtKeyword: + return "at-keyword"sv; + case Web::CSS::Parser::Token::Type::Hash: + return "hash"sv; + case Web::CSS::Parser::Token::Type::String: + return "string"sv; + case Web::CSS::Parser::Token::Type::Url: + return "url"sv; + case Web::CSS::Parser::Token::Type::Number: + case Web::CSS::Parser::Token::Type::Dimension: + case Web::CSS::Parser::Token::Type::Percentage: + return "number"sv; + case Web::CSS::Parser::Token::Type::Whitespace: + return "whitespace"sv; + case Web::CSS::Parser::Token::Type::Delim: + case Web::CSS::Parser::Token::Type::Colon: + case Web::CSS::Parser::Token::Type::Semicolon: + case Web::CSS::Parser::Token::Type::Comma: + case Web::CSS::Parser::Token::Type::OpenSquare: + case Web::CSS::Parser::Token::Type::CloseSquare: + case Web::CSS::Parser::Token::Type::OpenParen: + case Web::CSS::Parser::Token::Type::CloseParen: + case Web::CSS::Parser::Token::Type::OpenCurly: + case Web::CSS::Parser::Token::Type::CloseCurly: + return "delimiter"sv; + case Web::CSS::Parser::Token::Type::CDO: + case Web::CSS::Parser::Token::Type::CDC: + return "comment"sv; + case Web::CSS::Parser::Token::Type::EndOfFile: + default: + break; + } + return ""sv; + }; - return "unknown"sv; + auto class_for_js_token = [](u64 token_type) { + auto category = JS::Token::category(static_cast(token_type)); + switch (category) { + case JS::TokenCategory::Invalid: + return "invalid"sv; + case JS::TokenCategory::Number: + return "number"sv; + case JS::TokenCategory::String: + return "string"sv; + case JS::TokenCategory::Punctuation: + return "punctuation"sv; + case JS::TokenCategory::Operator: + return "operator"sv; + case JS::TokenCategory::Keyword: + return "keyword"sv; + case JS::TokenCategory::ControlKeyword: + return "control-keyword"sv; + case JS::TokenCategory::Identifier: + return "identifier"sv; + default: + break; + } + return ""sv; + }; + + switch (m_highlighter->language()) { + case Syntax::Language::CSS: + return class_for_css_token(token_type); + case Syntax::Language::JavaScript: + return class_for_js_token(token_type); + case Syntax::Language::HTML: { + // HTML has nested CSS and JS highlighters, so we have to decode their token types. + + // HTML + if (token_type < Web::HTML::SyntaxHighlighter::JS_TOKEN_START_VALUE) { + switch (static_cast(token_type)) { + case Web::HTML::AugmentedTokenKind::AttributeName: + return "attribute-name"sv; + case Web::HTML::AugmentedTokenKind::AttributeValue: + return "attribute-value"sv; + case Web::HTML::AugmentedTokenKind::OpenTag: + case Web::HTML::AugmentedTokenKind::CloseTag: + return "tag"sv; + case Web::HTML::AugmentedTokenKind::Comment: + return "comment"sv; + case Web::HTML::AugmentedTokenKind::Doctype: + return "doctype"sv; + case Web::HTML::AugmentedTokenKind::__Count: + default: + return ""sv; + } + } + + // JS + if (token_type < Web::HTML::SyntaxHighlighter::CSS_TOKEN_START_VALUE) { + return class_for_js_token(token_type - Web::HTML::SyntaxHighlighter::JS_TOKEN_START_VALUE); + } + + // CSS + return class_for_css_token(token_type - Web::HTML::SyntaxHighlighter::CSS_TOKEN_START_VALUE); + } + default: + return "unknown"sv; + } } static String generate_style() diff --git a/Userland/Libraries/LibWebView/SourceHighlighter.h b/Userland/Libraries/LibWebView/SourceHighlighter.h index 48735ff4f3d..c7966de2f41 100644 --- a/Userland/Libraries/LibWebView/SourceHighlighter.h +++ b/Userland/Libraries/LibWebView/SourceHighlighter.h @@ -84,6 +84,8 @@ constexpr inline StringView HTML_HIGHLIGHTER_STYLE = R"~~~( --name-color: orange; --value-color: deepskyblue; --internal-color: darkgrey; + --string-color: goldenrod; + --error-color: red; } } @@ -94,6 +96,8 @@ constexpr inline StringView HTML_HIGHLIGHTER_STYLE = R"~~~( --name-color: darkorange; --value-color: blue; --internal-color: dimgrey; + --string-color: darkgoldenrod; + --error-color: darkred; } } @@ -118,6 +122,19 @@ constexpr inline StringView HTML_HIGHLIGHTER_STYLE = R"~~~( .internal { color: var(--internal-color); } + .invalid { + color: var(--error-color); + text-decoration: currentColor wavy underline; + } + .at-keyword, .function, .keyword, .control-keyword, .url { + color: var(--keyword-color); + } + .number, .hash { + color: var(--value-color); + } + .string { + color: var(--string-color); + } )~~~"sv; }