mirror of
				https://github.com/LadybirdBrowser/ladybird.git
				synced 2025-11-03 23:00:58 +00:00 
			
		
		
		
	
		
			
	
	
		
			148 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			148 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								#include <LibGUI/CppLexer.h>
							 | 
						||
| 
								 | 
							
								#include <LibGUI/CppSyntaxHighlighter.h>
							 | 
						||
| 
								 | 
							
								#include <LibGUI/TextEditor.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace GUI {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct TextStyle {
							 | 
						||
| 
								 | 
							
								    Color color;
							 | 
						||
| 
								 | 
							
								    const Gfx::Font* font { nullptr };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static TextStyle style_for_token_type(CppToken::Type type)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    switch (type) {
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::Keyword:
							 | 
						||
| 
								 | 
							
								        return { Color::Black, &Gfx::Font::default_bold_fixed_width_font() };
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::KnownType:
							 | 
						||
| 
								 | 
							
								        return { Color::from_rgb(0x929200), &Gfx::Font::default_bold_fixed_width_font() };
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::Identifier:
							 | 
						||
| 
								 | 
							
								        return { Color::from_rgb(0x000092) };
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::DoubleQuotedString:
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::SingleQuotedString:
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::Number:
							 | 
						||
| 
								 | 
							
								        return { Color::from_rgb(0x920000) };
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::PreprocessorStatement:
							 | 
						||
| 
								 | 
							
								        return { Color::from_rgb(0x009292) };
							 | 
						||
| 
								 | 
							
								    case CppToken::Type::Comment:
							 | 
						||
| 
								 | 
							
								        return { Color::from_rgb(0x009200) };
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return { Color::Black };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CppSyntaxHighlighter::rehighlight()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(m_editor);
							 | 
						||
| 
								 | 
							
								    auto text = m_editor->text();
							 | 
						||
| 
								 | 
							
								    CppLexer lexer(text);
							 | 
						||
| 
								 | 
							
								    auto tokens = lexer.lex();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Vector<GUI::TextDocumentSpan> spans;
							 | 
						||
| 
								 | 
							
								    for (auto& token : tokens) {
							 | 
						||
| 
								 | 
							
								#ifdef DEBUG_SYNTAX_HIGHLIGHTING
							 | 
						||
| 
								 | 
							
								        dbg() << token.to_string() << " @ " << token.m_start.line << ":" << token.m_start.column << " - " << token.m_end.line << ":" << token.m_end.column;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        GUI::TextDocumentSpan span;
							 | 
						||
| 
								 | 
							
								        span.range.set_start({ token.m_start.line, token.m_start.column });
							 | 
						||
| 
								 | 
							
								        span.range.set_end({ token.m_end.line, token.m_end.column });
							 | 
						||
| 
								 | 
							
								        auto style = style_for_token_type(token.m_type);
							 | 
						||
| 
								 | 
							
								        span.color = style.color;
							 | 
						||
| 
								 | 
							
								        span.font = style.font;
							 | 
						||
| 
								 | 
							
								        span.is_skippable = token.m_type == CppToken::Type::Whitespace;
							 | 
						||
| 
								 | 
							
								        span.data = (void*)token.m_type;
							 | 
						||
| 
								 | 
							
								        spans.append(span);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    m_editor->document().set_spans(spans);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_has_brace_buddies = false;
							 | 
						||
| 
								 | 
							
								    highlight_matching_token_pair();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_editor->update();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CppSyntaxHighlighter::highlight_matching_token_pair()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(m_editor);
							 | 
						||
| 
								 | 
							
								    auto& document = m_editor->document();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    enum class Direction {
							 | 
						||
| 
								 | 
							
								        Forward,
							 | 
						||
| 
								 | 
							
								        Backward,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    auto find_span_of_type = [&](int i, CppToken::Type type, CppToken::Type not_type, Direction direction) {
							 | 
						||
| 
								 | 
							
								        int nesting_level = 0;
							 | 
						||
| 
								 | 
							
								        bool forward = direction == Direction::Forward;
							 | 
						||
| 
								 | 
							
								        for (forward ? ++i : --i; forward ? (i < document.spans().size()) : (i >= 0); forward ? ++i : --i) {
							 | 
						||
| 
								 | 
							
								            auto& span = document.spans().at(i);
							 | 
						||
| 
								 | 
							
								            auto span_token_type = (CppToken::Type)((uintptr_t)span.data);
							 | 
						||
| 
								 | 
							
								            if (span_token_type == not_type) {
							 | 
						||
| 
								 | 
							
								                ++nesting_level;
							 | 
						||
| 
								 | 
							
								            } else if (span_token_type == type) {
							 | 
						||
| 
								 | 
							
								                if (nesting_level-- <= 0)
							 | 
						||
| 
								 | 
							
								                    return i;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return -1;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    auto make_buddies = [&](int index0, int index1) {
							 | 
						||
| 
								 | 
							
								        auto& buddy0 = const_cast<GUI::TextDocumentSpan&>(document.spans()[index0]);
							 | 
						||
| 
								 | 
							
								        auto& buddy1 = const_cast<GUI::TextDocumentSpan&>(document.spans()[index1]);
							 | 
						||
| 
								 | 
							
								        m_has_brace_buddies = true;
							 | 
						||
| 
								 | 
							
								        m_brace_buddies[0].index = index0;
							 | 
						||
| 
								 | 
							
								        m_brace_buddies[1].index = index1;
							 | 
						||
| 
								 | 
							
								        m_brace_buddies[0].span_backup = buddy0;
							 | 
						||
| 
								 | 
							
								        m_brace_buddies[1].span_backup = buddy1;
							 | 
						||
| 
								 | 
							
								        buddy0.background_color = Color::DarkCyan;
							 | 
						||
| 
								 | 
							
								        buddy1.background_color = Color::DarkCyan;
							 | 
						||
| 
								 | 
							
								        buddy0.color = Color::White;
							 | 
						||
| 
								 | 
							
								        buddy1.color = Color::White;
							 | 
						||
| 
								 | 
							
								        m_editor->update();
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    struct MatchingTokenPair {
							 | 
						||
| 
								 | 
							
								        CppToken::Type open;
							 | 
						||
| 
								 | 
							
								        CppToken::Type close;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    MatchingTokenPair pairs[] = {
							 | 
						||
| 
								 | 
							
								        { CppToken::Type::LeftCurly, CppToken::Type::RightCurly },
							 | 
						||
| 
								 | 
							
								        { CppToken::Type::LeftParen, CppToken::Type::RightParen },
							 | 
						||
| 
								 | 
							
								        { CppToken::Type::LeftBracket, CppToken::Type::RightBracket },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < document.spans().size(); ++i) {
							 | 
						||
| 
								 | 
							
								        auto& span = const_cast<GUI::TextDocumentSpan&>(document.spans().at(i));
							 | 
						||
| 
								 | 
							
								        auto token_type = (CppToken::Type)((uintptr_t)span.data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (auto& pair : pairs) {
							 | 
						||
| 
								 | 
							
								            if (token_type == pair.open && span.range.start() == m_editor->cursor()) {
							 | 
						||
| 
								 | 
							
								                auto buddy = find_span_of_type(i, pair.close, pair.open, Direction::Forward);
							 | 
						||
| 
								 | 
							
								                if (buddy != -1)
							 | 
						||
| 
								 | 
							
								                    make_buddies(i, buddy);
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        auto right_of_end = span.range.end();
							 | 
						||
| 
								 | 
							
								        right_of_end.set_column(right_of_end.column() + 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (auto& pair : pairs) {
							 | 
						||
| 
								 | 
							
								            if (token_type == pair.close && right_of_end == m_editor->cursor()) {
							 | 
						||
| 
								 | 
							
								                auto buddy = find_span_of_type(i, pair.open, pair.close, Direction::Backward);
							 | 
						||
| 
								 | 
							
								                if (buddy != -1)
							 | 
						||
| 
								 | 
							
								                    make_buddies(i, buddy);
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CppSyntaxHighlighter::~CppSyntaxHighlighter()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 |