Serenity Operating System
at master 116 lines 4.7 kB view raw
1/* 2 * Copyright (c) 2020-2022, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Debug.h> 8#include <LibCpp/Lexer.h> 9#include <LibCpp/SyntaxHighlighter.h> 10#include <LibGUI/TextEditor.h> 11#include <LibGfx/Font/Font.h> 12#include <LibGfx/Palette.h> 13 14namespace Cpp { 15 16static Syntax::TextStyle style_for_token_type(Gfx::Palette const& palette, Cpp::Token::Type type) 17{ 18 switch (type) { 19 case Cpp::Token::Type::Keyword: 20 return { palette.syntax_keyword(), true }; 21 case Cpp::Token::Type::KnownType: 22 return { palette.syntax_type(), true }; 23 case Cpp::Token::Type::Identifier: 24 return { palette.syntax_identifier(), false }; 25 case Cpp::Token::Type::DoubleQuotedString: 26 case Cpp::Token::Type::SingleQuotedString: 27 case Cpp::Token::Type::RawString: 28 return { palette.syntax_string(), false }; 29 case Cpp::Token::Type::Integer: 30 case Cpp::Token::Type::Float: 31 return { palette.syntax_number(), false }; 32 case Cpp::Token::Type::IncludePath: 33 return { palette.syntax_preprocessor_value(), false }; 34 case Cpp::Token::Type::EscapeSequence: 35 return { palette.syntax_keyword(), true }; 36 case Cpp::Token::Type::PreprocessorStatement: 37 case Cpp::Token::Type::IncludeStatement: 38 return { palette.syntax_preprocessor_statement(), false }; 39 case Cpp::Token::Type::Comment: 40 return { palette.syntax_comment(), false }; 41 default: 42 return { palette.base_text(), false }; 43 } 44} 45 46bool SyntaxHighlighter::is_identifier(u64 token) const 47{ 48 auto cpp_token = static_cast<Cpp::Token::Type>(token); 49 return cpp_token == Cpp::Token::Type::Identifier; 50} 51 52bool SyntaxHighlighter::is_navigatable(u64 token) const 53{ 54 auto cpp_token = static_cast<Cpp::Token::Type>(token); 55 return cpp_token == Cpp::Token::Type::IncludePath; 56} 57 58void SyntaxHighlighter::rehighlight(Palette const& palette) 59{ 60 auto text = m_client->get_text(); 61 Cpp::Lexer lexer(text); 62 63 Vector<Token> folding_region_start_tokens; 64 Vector<GUI::TextDocumentFoldingRegion> folding_regions; 65 Vector<GUI::TextDocumentSpan> spans; 66 lexer.lex_iterable([&](auto token) { 67 // FIXME: The +1 for the token end column is a quick hack due to not wanting to modify the lexer (which is also used by the parser). Maybe there's a better way to do this. 68 dbgln_if(SYNTAX_HIGHLIGHTING_DEBUG, "{} @ {}:{} - {}:{}", token.type_as_deprecated_string(), token.start().line, token.start().column, token.end().line, token.end().column + 1); 69 GUI::TextDocumentSpan span; 70 span.range.set_start({ token.start().line, token.start().column }); 71 span.range.set_end({ token.end().line, token.end().column + 1 }); 72 auto style = style_for_token_type(palette, token.type()); 73 span.attributes.color = style.color; 74 span.attributes.bold = style.bold; 75 span.is_skippable = token.type() == Cpp::Token::Type::Whitespace; 76 span.data = static_cast<u64>(token.type()); 77 spans.append(span); 78 79 if (token.type() == Token::Type::LeftCurly) { 80 folding_region_start_tokens.append(token); 81 } else if (token.type() == Token::Type::RightCurly) { 82 if (!folding_region_start_tokens.is_empty()) { 83 auto start_token = folding_region_start_tokens.take_last(); 84 GUI::TextDocumentFoldingRegion folding_region; 85 folding_region.range.set_start({ start_token.end().line, start_token.end().column }); 86 folding_region.range.set_end({ token.start().line, token.start().column }); 87 folding_regions.append(move(folding_region)); 88 } 89 } 90 }); 91 m_client->do_set_spans(move(spans)); 92 m_client->do_set_folding_regions(move(folding_regions)); 93 94 m_has_brace_buddies = false; 95 highlight_matching_token_pair(); 96 97 m_client->do_update(); 98} 99 100Vector<SyntaxHighlighter::MatchingTokenPair> SyntaxHighlighter::matching_token_pairs_impl() const 101{ 102 static Vector<SyntaxHighlighter::MatchingTokenPair> pairs; 103 if (pairs.is_empty()) { 104 pairs.append({ static_cast<u64>(Cpp::Token::Type::LeftCurly), static_cast<u64>(Cpp::Token::Type::RightCurly) }); 105 pairs.append({ static_cast<u64>(Cpp::Token::Type::LeftParen), static_cast<u64>(Cpp::Token::Type::RightParen) }); 106 pairs.append({ static_cast<u64>(Cpp::Token::Type::LeftBracket), static_cast<u64>(Cpp::Token::Type::RightBracket) }); 107 } 108 return pairs; 109} 110 111bool SyntaxHighlighter::token_types_equal(u64 token1, u64 token2) const 112{ 113 return static_cast<Cpp::Token::Type>(token1) == static_cast<Cpp::Token::Type>(token2); 114} 115 116}