Serenity Operating System
at master 115 lines 4.3 kB view raw
1/* 2 * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibGUI/INILexer.h> 9#include <LibGUI/INISyntaxHighlighter.h> 10#include <LibGfx/Palette.h> 11 12namespace GUI { 13 14static Syntax::TextStyle style_for_token_type(Gfx::Palette const& palette, IniToken::Type type) 15{ 16 switch (type) { 17 case IniToken::Type::LeftBracket: 18 case IniToken::Type::RightBracket: 19 case IniToken::Type::Section: 20 return { palette.syntax_keyword(), true }; 21 case IniToken::Type::Name: 22 return { palette.syntax_identifier() }; 23 case IniToken::Type::Value: 24 return { palette.syntax_string() }; 25 case IniToken::Type::Comment: 26 return { palette.syntax_comment() }; 27 case IniToken::Type::Equal: 28 return { palette.syntax_operator(), true }; 29 default: 30 return { palette.base_text() }; 31 } 32} 33 34bool IniSyntaxHighlighter::is_identifier(u64 token) const 35{ 36 auto ini_token = static_cast<GUI::IniToken::Type>(token); 37 return ini_token == GUI::IniToken::Type::Name; 38} 39 40void IniSyntaxHighlighter::rehighlight(Palette const& palette) 41{ 42 auto text = m_client->get_text(); 43 IniLexer lexer(text); 44 auto tokens = lexer.lex(); 45 46 Optional<IniToken> previous_section_token; 47 IniToken previous_token; 48 Vector<TextDocumentFoldingRegion> folding_regions; 49 50 Vector<GUI::TextDocumentSpan> spans; 51 for (auto& token : tokens) { 52 GUI::TextDocumentSpan span; 53 span.range.set_start({ token.m_start.line, token.m_start.column }); 54 span.range.set_end({ token.m_end.line, token.m_end.column }); 55 auto style = style_for_token_type(palette, token.m_type); 56 span.attributes.color = style.color; 57 span.attributes.bold = style.bold; 58 span.is_skippable = token.m_type == IniToken::Type::Whitespace; 59 span.data = static_cast<u64>(token.m_type); 60 spans.append(span); 61 62 if (token.m_type == IniToken::Type::RightBracket && previous_token.m_type == IniToken::Type::Section) { 63 previous_section_token = token; 64 } else if (token.m_type == IniToken::Type::LeftBracket) { 65 if (previous_section_token.has_value()) { 66 TextDocumentFoldingRegion region; 67 region.range.set_start({ previous_section_token->m_end.line, previous_section_token->m_end.column }); 68 // If possible, leave a blank line between sections. 69 // `end_line - start_line > 1` means the whitespace contains at least 1 blank line, 70 // so we can end the region 1 line before the end of that whitespace token. 71 // (Otherwise, we'd end the region at the start of the line that begins the next section.) 72 auto end_line = token.m_start.line; 73 if (previous_token.m_type == IniToken::Type::Whitespace 74 && (previous_token.m_end.line - previous_token.m_start.line > 1)) 75 end_line--; 76 region.range.set_end({ end_line, token.m_start.column }); 77 folding_regions.append(move(region)); 78 } 79 previous_section_token = token; 80 } 81 82 previous_token = token; 83 } 84 if (previous_section_token.has_value()) { 85 TextDocumentFoldingRegion region; 86 auto& end_token = tokens.last(); 87 region.range.set_start({ previous_section_token->m_end.line, previous_section_token->m_end.column }); 88 region.range.set_end({ end_token.m_end.line, end_token.m_end.column }); 89 folding_regions.append(move(region)); 90 } 91 92 m_client->do_set_spans(move(spans)); 93 m_client->do_set_folding_regions(move(folding_regions)); 94 95 m_has_brace_buddies = false; 96 highlight_matching_token_pair(); 97 98 m_client->do_update(); 99} 100 101Vector<IniSyntaxHighlighter::MatchingTokenPair> IniSyntaxHighlighter::matching_token_pairs_impl() const 102{ 103 static Vector<MatchingTokenPair> pairs; 104 if (pairs.is_empty()) { 105 pairs.append({ static_cast<u64>(IniToken::Type::LeftBracket), static_cast<u64>(IniToken::Type::RightBracket) }); 106 } 107 return pairs; 108} 109 110bool IniSyntaxHighlighter::token_types_equal(u64 token1, u64 token2) const 111{ 112 return static_cast<GUI::IniToken::Type>(token1) == static_cast<GUI::IniToken::Type>(token2); 113} 114 115}