Serenity Operating System
1/*
2 * Copyright (c) 2021, Dylan Katz <dykatz@uw.edu>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <AK/Debug.h>
9#include <LibGfx/Palette.h>
10#include <LibSQL/AST/Lexer.h>
11#include <LibSQL/AST/SyntaxHighlighter.h>
12
13namespace SQL::AST {
14
15static Syntax::TextStyle style_for_token_type(Gfx::Palette const& palette, TokenType type)
16{
17 switch (Token::category(type)) {
18 case TokenCategory::Keyword:
19 return { palette.syntax_keyword(), true };
20 case TokenCategory::Identifier:
21 return { palette.syntax_identifier(), false };
22 case TokenCategory::Number:
23 return { palette.syntax_number(), false };
24 case TokenCategory::Blob:
25 case TokenCategory::String:
26 return { palette.syntax_string(), false };
27 case TokenCategory::Operator:
28 return { palette.syntax_operator(), false };
29 case TokenCategory::Punctuation:
30 return { palette.syntax_punctuation(), false };
31 case TokenCategory::Invalid:
32 default:
33 return { palette.base_text(), false };
34 }
35}
36
37bool SyntaxHighlighter::is_identifier(u64 token) const
38{
39 auto sql_token = static_cast<TokenType>(static_cast<size_t>(token));
40 return sql_token == TokenType::Identifier;
41}
42
43void SyntaxHighlighter::rehighlight(Palette const& palette)
44{
45 auto text = m_client->get_text();
46
47 Lexer lexer(text);
48
49 Vector<GUI::TextDocumentSpan> spans;
50
51 auto append_token = [&](Token const& token) {
52 if (token.value().is_empty())
53 return;
54 GUI::TextDocumentSpan span;
55 span.range.set_start({ token.start_position().line - 1, token.start_position().column - 1 });
56 span.range.set_end({ token.end_position().line - 1, token.end_position().column - 1 });
57 auto style = style_for_token_type(palette, token.type());
58 span.attributes.color = style.color;
59 span.attributes.bold = style.bold;
60 span.data = static_cast<u64>(token.type());
61 spans.append(span);
62
63 dbgln_if(SYNTAX_HIGHLIGHTING_DEBUG, "{} @ '{}' {}:{} - {}:{}",
64 token.name(),
65 token.value(),
66 span.range.start().line(), span.range.start().column(),
67 span.range.end().line(), span.range.end().column());
68 };
69
70 for (;;) {
71 auto token = lexer.next();
72 append_token(token);
73 if (token.type() == TokenType::Eof)
74 break;
75 }
76
77 m_client->do_set_spans(move(spans));
78
79 m_has_brace_buddies = false;
80 highlight_matching_token_pair();
81
82 m_client->do_update();
83}
84
85Vector<SyntaxHighlighter::MatchingTokenPair> SyntaxHighlighter::matching_token_pairs_impl() const
86{
87 static Vector<SyntaxHighlighter::MatchingTokenPair> pairs;
88 if (pairs.is_empty()) {
89 pairs.append({ static_cast<u64>(TokenType::ParenOpen), static_cast<u64>(TokenType::ParenClose) });
90 }
91 return pairs;
92}
93
94bool SyntaxHighlighter::token_types_equal(u64 token1, u64 token2) const
95{
96 return static_cast<TokenType>(token1) == static_cast<TokenType>(token2);
97}
98
99}