SuggestionManager.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/ByteString.h>
  8. #include <AK/Forward.h>
  9. #include <AK/String.h>
  10. #include <AK/Utf32View.h>
  11. #include <AK/Utf8View.h>
  12. #include <LibLine/Style.h>
  13. namespace Line {
  14. struct CompletionSuggestion {
  15. private:
  16. struct ForSearchTag {
  17. };
  18. public:
  19. static constexpr ForSearchTag ForSearch {};
  20. // Intentionally not explicit. (To allow suggesting bare strings)
  21. CompletionSuggestion(ByteString const& completion)
  22. : CompletionSuggestion(completion, ""sv, {})
  23. {
  24. }
  25. CompletionSuggestion(StringView completion, ForSearchTag)
  26. : text(MUST(String::from_utf8(completion)))
  27. {
  28. }
  29. CompletionSuggestion(StringView completion, StringView trailing_trivia, StringView display_trivia = ""sv)
  30. : CompletionSuggestion(completion, trailing_trivia, display_trivia, {})
  31. {
  32. }
  33. CompletionSuggestion(StringView completion, StringView trailing_trivia, StringView display_trivia, Style style);
  34. bool operator==(CompletionSuggestion const& suggestion) const
  35. {
  36. return suggestion.text == text;
  37. }
  38. String text;
  39. String trailing_trivia;
  40. String display_trivia;
  41. Style style;
  42. size_t start_index { 0 };
  43. size_t input_offset { 0 };
  44. size_t static_offset { 0 };
  45. size_t invariant_offset { 0 };
  46. bool allow_commit_without_listing { true };
  47. Utf8View text_view() const { return text.code_points(); }
  48. Utf8View trivia_view() const { return trailing_trivia.code_points(); }
  49. Utf8View display_trivia_view() const { return display_trivia.code_points(); }
  50. StringView text_string() const { return text.bytes_as_string_view(); }
  51. StringView display_trivia_string() const { return display_trivia.bytes_as_string_view(); }
  52. bool is_valid { false };
  53. };
  54. class SuggestionManager {
  55. friend class Editor;
  56. public:
  57. void set_suggestions(Vector<CompletionSuggestion>&& suggestions);
  58. void set_current_suggestion_initiation_index(size_t start_index);
  59. size_t count() const { return m_suggestions.size(); }
  60. size_t display_length() const { return m_last_shown_suggestion_display_length; }
  61. size_t start_index() const { return m_last_displayed_suggestion_index; }
  62. size_t next_index() const { return m_next_suggestion_index; }
  63. void set_start_index(size_t index) const { m_last_displayed_suggestion_index = index; }
  64. ErrorOr<size_t> for_each_suggestion(Function<ErrorOr<IterationDecision>(CompletionSuggestion const&, size_t)>) const;
  65. enum CompletionMode {
  66. DontComplete,
  67. CompletePrefix,
  68. ShowSuggestions,
  69. CycleSuggestions,
  70. };
  71. class CompletionAttemptResult {
  72. public:
  73. CompletionMode new_completion_mode;
  74. ssize_t new_cursor_offset { 0 };
  75. struct {
  76. size_t start;
  77. size_t end;
  78. } offset_region_to_remove { 0, 0 }; // The region to remove as defined by [start, end) translated by (old_cursor + new_cursor_offset)
  79. // This bit of data will be removed, but restored if the suggestion is rejected.
  80. size_t static_offset_from_cursor { 0 };
  81. Vector<Utf8View> insert {};
  82. Optional<Style> style_to_apply {};
  83. bool avoid_committing_to_single_suggestion { false };
  84. };
  85. CompletionAttemptResult attempt_completion(CompletionMode, size_t initiation_start_index);
  86. void next();
  87. void previous();
  88. CompletionSuggestion const& suggest();
  89. CompletionSuggestion const& current_suggestion() const { return m_last_shown_suggestion; }
  90. bool is_current_suggestion_complete() const { return m_last_shown_suggestion_was_complete; }
  91. void reset()
  92. {
  93. m_last_shown_suggestion = ByteString::empty();
  94. m_last_shown_suggestion_display_length = 0;
  95. m_suggestions.clear();
  96. m_last_displayed_suggestion_index = 0;
  97. m_next_suggestion_index = 0;
  98. }
  99. private:
  100. SuggestionManager()
  101. {
  102. }
  103. Vector<CompletionSuggestion> m_suggestions;
  104. CompletionSuggestion m_last_shown_suggestion { ByteString::empty() };
  105. size_t m_last_shown_suggestion_display_length { 0 };
  106. bool m_last_shown_suggestion_was_complete { false };
  107. mutable size_t m_next_suggestion_index { 0 };
  108. size_t m_largest_common_suggestion_prefix_length { 0 };
  109. mutable size_t m_last_displayed_suggestion_index { 0 };
  110. size_t m_selected_suggestion_index { 0 };
  111. };
  112. }