CppSyntaxHighlighter.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include <LibGUI/CppLexer.h>
  2. #include <LibGUI/CppSyntaxHighlighter.h>
  3. #include <LibGUI/TextEditor.h>
  4. #include <LibGfx/Font.h>
  5. namespace GUI {
  6. struct TextStyle {
  7. Color color;
  8. const Gfx::Font* font { nullptr };
  9. };
  10. static TextStyle style_for_token_type(CppToken::Type type)
  11. {
  12. switch (type) {
  13. case CppToken::Type::Keyword:
  14. return { Color::Black, &Gfx::Font::default_bold_fixed_width_font() };
  15. case CppToken::Type::KnownType:
  16. return { Color::from_rgb(0x800080), &Gfx::Font::default_bold_fixed_width_font() };
  17. case CppToken::Type::Identifier:
  18. return { Color::from_rgb(0x092e64) };
  19. case CppToken::Type::DoubleQuotedString:
  20. case CppToken::Type::SingleQuotedString:
  21. case CppToken::Type::Number:
  22. return { Color::from_rgb(0x800000) };
  23. case CppToken::Type::PreprocessorStatement:
  24. return { Color::from_rgb(0x008080) };
  25. case CppToken::Type::Comment:
  26. return { Color::from_rgb(0x008000) };
  27. default:
  28. return { Color::Black };
  29. }
  30. }
  31. void CppSyntaxHighlighter::rehighlight()
  32. {
  33. ASSERT(m_editor);
  34. auto text = m_editor->text();
  35. CppLexer lexer(text);
  36. auto tokens = lexer.lex();
  37. Vector<GUI::TextDocumentSpan> spans;
  38. for (auto& token : tokens) {
  39. #ifdef DEBUG_SYNTAX_HIGHLIGHTING
  40. dbg() << token.to_string() << " @ " << token.m_start.line << ":" << token.m_start.column << " - " << token.m_end.line << ":" << token.m_end.column;
  41. #endif
  42. GUI::TextDocumentSpan span;
  43. span.range.set_start({ token.m_start.line, token.m_start.column });
  44. span.range.set_end({ token.m_end.line, token.m_end.column });
  45. auto style = style_for_token_type(token.m_type);
  46. span.color = style.color;
  47. span.font = style.font;
  48. span.is_skippable = token.m_type == CppToken::Type::Whitespace;
  49. span.data = (void*)token.m_type;
  50. spans.append(span);
  51. }
  52. m_editor->document().set_spans(spans);
  53. m_has_brace_buddies = false;
  54. highlight_matching_token_pair();
  55. m_editor->update();
  56. }
  57. void CppSyntaxHighlighter::highlight_matching_token_pair()
  58. {
  59. ASSERT(m_editor);
  60. auto& document = m_editor->document();
  61. enum class Direction {
  62. Forward,
  63. Backward,
  64. };
  65. auto find_span_of_type = [&](auto i, CppToken::Type type, CppToken::Type not_type, Direction direction) -> Optional<size_t> {
  66. size_t nesting_level = 0;
  67. bool forward = direction == Direction::Forward;
  68. for (forward ? ++i : --i; forward ? (i < document.spans().size()) : (i >= 0); forward ? ++i : --i) {
  69. auto& span = document.spans().at(i);
  70. auto span_token_type = (CppToken::Type)((FlatPtr)span.data);
  71. if (span_token_type == not_type) {
  72. ++nesting_level;
  73. } else if (span_token_type == type) {
  74. if (nesting_level-- <= 0)
  75. return i;
  76. }
  77. }
  78. return {};
  79. };
  80. auto make_buddies = [&](int index0, int index1) {
  81. auto& buddy0 = const_cast<GUI::TextDocumentSpan&>(document.spans()[index0]);
  82. auto& buddy1 = const_cast<GUI::TextDocumentSpan&>(document.spans()[index1]);
  83. m_has_brace_buddies = true;
  84. m_brace_buddies[0].index = index0;
  85. m_brace_buddies[1].index = index1;
  86. m_brace_buddies[0].span_backup = buddy0;
  87. m_brace_buddies[1].span_backup = buddy1;
  88. buddy0.background_color = Color::DarkCyan;
  89. buddy1.background_color = Color::DarkCyan;
  90. buddy0.color = Color::White;
  91. buddy1.color = Color::White;
  92. m_editor->update();
  93. };
  94. struct MatchingTokenPair {
  95. CppToken::Type open;
  96. CppToken::Type close;
  97. };
  98. MatchingTokenPair pairs[] = {
  99. { CppToken::Type::LeftCurly, CppToken::Type::RightCurly },
  100. { CppToken::Type::LeftParen, CppToken::Type::RightParen },
  101. { CppToken::Type::LeftBracket, CppToken::Type::RightBracket },
  102. };
  103. for (size_t i = 0; i < document.spans().size(); ++i) {
  104. auto& span = const_cast<GUI::TextDocumentSpan&>(document.spans().at(i));
  105. auto token_type = (CppToken::Type)((FlatPtr)span.data);
  106. for (auto& pair : pairs) {
  107. if (token_type == pair.open && span.range.start() == m_editor->cursor()) {
  108. auto buddy = find_span_of_type(i, pair.close, pair.open, Direction::Forward);
  109. if (buddy.has_value())
  110. make_buddies(i, buddy.value());
  111. return;
  112. }
  113. }
  114. auto right_of_end = span.range.end();
  115. right_of_end.set_column(right_of_end.column() + 1);
  116. for (auto& pair : pairs) {
  117. if (token_type == pair.close && right_of_end == m_editor->cursor()) {
  118. auto buddy = find_span_of_type(i, pair.open, pair.close, Direction::Backward);
  119. if (buddy.has_value())
  120. make_buddies(i, buddy.value());
  121. return;
  122. }
  123. }
  124. }
  125. }
  126. CppSyntaxHighlighter::~CppSyntaxHighlighter()
  127. {
  128. }
  129. }