Serenity Operating System
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}