Serenity Operating System
1/*
2 * Copyright (c) 2020, the SerenityOS developers.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <LibGUI/CppLexer.h>
28#include <LibGUI/CppSyntaxHighlighter.h>
29#include <LibGUI/TextEditor.h>
30#include <LibGfx/Font.h>
31#include <LibGfx/Palette.h>
32
33namespace GUI {
34
35static TextStyle style_for_token_type(Gfx::Palette palette, CppToken::Type type)
36{
37 switch (type) {
38 case CppToken::Type::Keyword:
39 return { palette.syntax_keyword(), &Gfx::Font::default_bold_fixed_width_font() };
40 case CppToken::Type::KnownType:
41 return { palette.syntax_type(), &Gfx::Font::default_bold_fixed_width_font() };
42 case CppToken::Type::Identifier:
43 return { palette.syntax_identifier() };
44 case CppToken::Type::DoubleQuotedString:
45 case CppToken::Type::SingleQuotedString:
46 return { palette.syntax_string() };
47 case CppToken::Type::Integer:
48 case CppToken::Type::Float:
49 return { palette.syntax_number() };
50 case CppToken::Type::IncludePath:
51 return { palette.syntax_preprocessor_value() };
52 case CppToken::Type::EscapeSequence:
53 return { palette.syntax_keyword(), &Gfx::Font::default_bold_fixed_width_font() };
54 case CppToken::Type::PreprocessorStatement:
55 case CppToken::Type::IncludeStatement:
56 return { palette.syntax_preprocessor_statement() };
57 case CppToken::Type::Comment:
58 return { palette.syntax_comment() };
59 default:
60 return { palette.base_text() };
61 }
62}
63
64bool CppSyntaxHighlighter::is_identifier(void* token) const
65{
66 auto cpp_token = static_cast<GUI::CppToken::Type>(reinterpret_cast<size_t>(token));
67 return cpp_token == GUI::CppToken::Type::Identifier;
68}
69
70bool CppSyntaxHighlighter::is_navigatable(void* token) const
71{
72 auto cpp_token = static_cast<GUI::CppToken::Type>(reinterpret_cast<size_t>(token));
73 return cpp_token == GUI::CppToken::Type::IncludePath;
74}
75
76void CppSyntaxHighlighter::rehighlight(Gfx::Palette palette)
77{
78 ASSERT(m_editor);
79 auto text = m_editor->text();
80 CppLexer lexer(text);
81 auto tokens = lexer.lex();
82
83 Vector<GUI::TextDocumentSpan> spans;
84 for (auto& token : tokens) {
85#ifdef DEBUG_SYNTAX_HIGHLIGHTING
86 dbg() << token.to_string() << " @ " << token.m_start.line << ":" << token.m_start.column << " - " << token.m_end.line << ":" << token.m_end.column;
87#endif
88 GUI::TextDocumentSpan span;
89 span.range.set_start({ token.m_start.line, token.m_start.column });
90 span.range.set_end({ token.m_end.line, token.m_end.column });
91 auto style = style_for_token_type(palette, token.m_type);
92 span.color = style.color;
93 span.font = style.font;
94 span.is_skippable = token.m_type == CppToken::Type::Whitespace;
95 span.data = reinterpret_cast<void*>(token.m_type);
96 spans.append(span);
97 }
98 m_editor->document().set_spans(spans);
99
100 m_has_brace_buddies = false;
101 highlight_matching_token_pair();
102
103 m_editor->update();
104}
105
106Vector<SyntaxHighlighter::MatchingTokenPair> CppSyntaxHighlighter::matching_token_pairs() const
107{
108 static Vector<SyntaxHighlighter::MatchingTokenPair> pairs;
109 if (pairs.is_empty()) {
110 pairs.append({ reinterpret_cast<void*>(CppToken::Type::LeftCurly), reinterpret_cast<void*>(CppToken::Type::RightCurly) });
111 pairs.append({ reinterpret_cast<void*>(CppToken::Type::LeftParen), reinterpret_cast<void*>(CppToken::Type::RightParen) });
112 pairs.append({ reinterpret_cast<void*>(CppToken::Type::LeftBracket), reinterpret_cast<void*>(CppToken::Type::RightBracket) });
113 }
114 return pairs;
115}
116
117bool CppSyntaxHighlighter::token_types_equal(void* token1, void* token2) const
118{
119 return static_cast<GUI::CppToken::Type>(reinterpret_cast<size_t>(token1)) == static_cast<GUI::CppToken::Type>(reinterpret_cast<size_t>(token2));
120}
121
122CppSyntaxHighlighter::~CppSyntaxHighlighter()
123{
124}
125
126}