SyntaxHighlighter.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright (c) 2021, Dylan Katz <dykatz@uw.edu>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Debug.h>
  7. #include <LibGUI/TextEditor.h>
  8. #include <LibGfx/Font.h>
  9. #include <LibGfx/Palette.h>
  10. #include <LibSQL/Lexer.h>
  11. #include <LibSQL/SyntaxHighlighter.h>
  12. namespace SQL {
  13. static Syntax::TextStyle style_for_token_type(const Gfx::Palette& palette, TokenType type)
  14. {
  15. switch (Token::category(type)) {
  16. case TokenCategory::Keyword:
  17. return { palette.syntax_keyword(), true };
  18. case TokenCategory::Identifier:
  19. return { palette.syntax_identifier(), false };
  20. case TokenCategory::Number:
  21. return { palette.syntax_number(), false };
  22. case TokenCategory::Blob:
  23. case TokenCategory::String:
  24. return { palette.syntax_string(), false };
  25. case TokenCategory::Operator:
  26. return { palette.syntax_operator(), false };
  27. case TokenCategory::Punctuation:
  28. return { palette.syntax_punctuation(), false };
  29. case TokenCategory::Invalid:
  30. default:
  31. return { palette.base_text(), false };
  32. }
  33. }
  34. bool SyntaxHighlighter::is_identifier(void* token) const
  35. {
  36. auto sql_token = static_cast<SQL::TokenType>(reinterpret_cast<size_t>(token));
  37. return sql_token == SQL::TokenType::Identifier;
  38. }
  39. void SyntaxHighlighter::rehighlight(const Palette& palette)
  40. {
  41. auto text = m_client->get_text();
  42. SQL::Lexer lexer(text);
  43. Vector<GUI::TextDocumentSpan> spans;
  44. auto append_token = [&](StringView str, const SQL::Token& token) {
  45. if (str.is_empty())
  46. return;
  47. GUI::TextPosition position { token.line_number() - 1, token.line_column() - 1 };
  48. for (size_t i = 0; i < str.length() - 1; ++i) {
  49. if (str[i] == '\n') {
  50. position.set_line(position.line() + 1);
  51. position.set_column(0);
  52. } else
  53. position.set_column(position.column() + 1);
  54. }
  55. GUI::TextDocumentSpan span;
  56. span.range.set_start({ token.line_number() - 1, token.line_column() - 1 });
  57. span.range.set_end({ position.line(), position.column() });
  58. auto style = style_for_token_type(palette, token.type());
  59. span.attributes.color = style.color;
  60. span.attributes.bold = style.bold;
  61. span.data = reinterpret_cast<void*>(static_cast<size_t>(token.type()));
  62. spans.append(span);
  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. bool was_eof = false;
  70. for (auto token = lexer.next(); !was_eof; token = lexer.next()) {
  71. append_token(token.value(), token);
  72. if (token.type() == SQL::TokenType::Eof)
  73. was_eof = true;
  74. }
  75. m_client->do_set_spans(move(spans));
  76. m_has_brace_buddies = false;
  77. highlight_matching_token_pair();
  78. m_client->do_update();
  79. }
  80. Vector<SyntaxHighlighter::MatchingTokenPair> SyntaxHighlighter::matching_token_pairs() const
  81. {
  82. static Vector<SyntaxHighlighter::MatchingTokenPair> pairs;
  83. if (pairs.is_empty()) {
  84. pairs.append({ reinterpret_cast<void*>(TokenType::ParenOpen), reinterpret_cast<void*>(TokenType::ParenClose) });
  85. }
  86. return pairs;
  87. }
  88. bool SyntaxHighlighter::token_types_equal(void* token1, void* token2) const
  89. {
  90. return static_cast<TokenType>(reinterpret_cast<size_t>(token1)) == static_cast<TokenType>(reinterpret_cast<size_t>(token2));
  91. }
  92. SyntaxHighlighter::~SyntaxHighlighter()
  93. {
  94. }
  95. }