CppSyntaxHighlighter.cpp 4.8 KB

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