| 1753 | } |
| 1754 | |
| 1755 | bool reshade::imgui::code_editor::find_and_scroll_to_text(const std::string_view text, bool backwards, bool with_selection) |
| 1756 | { |
| 1757 | if (text.empty()) |
| 1758 | return false; // Cannot search for empty text |
| 1759 | |
| 1760 | const auto compare_c = [this](utf8::utfchar32_t clhs, utf8::utfchar32_t crhs) { |
| 1761 | return _search_case_sensitive ? clhs == crhs : std::tolower(clhs) == std::tolower(crhs); |
| 1762 | }; |
| 1763 | |
| 1764 | // Start search at the cursor position |
| 1765 | text_pos match_pos_beg, search_pos = backwards != with_selection ? _select_beg : _select_end; |
| 1766 | |
| 1767 | const utf8::unchecked::iterator<std::string_view::iterator> text_begin(text.begin()); |
| 1768 | const utf8::unchecked::iterator<std::string_view::iterator> text_end(text.end()); |
| 1769 | |
| 1770 | if (backwards) |
| 1771 | { |
| 1772 | // Start searching at the character before the current cursor position |
| 1773 | if (search_pos.column != 0) |
| 1774 | { |
| 1775 | search_pos.column -= 1; |
| 1776 | } |
| 1777 | else if (search_pos.line != 0) |
| 1778 | { |
| 1779 | search_pos.line -= 1; |
| 1780 | search_pos.column = _lines[search_pos.line].size(); |
| 1781 | } |
| 1782 | |
| 1783 | const utf8::unchecked::iterator<std::string_view::iterator> match_last = std::prev(text_end); |
| 1784 | utf8::unchecked::iterator<std::string_view::iterator> match_offset = match_last; |
| 1785 | |
| 1786 | while (true) |
| 1787 | { |
| 1788 | if (!_lines[search_pos.line].empty()) |
| 1789 | { |
| 1790 | // Trim column index to the last character in the line (rather than the actual end) |
| 1791 | search_pos.column = std::min(search_pos.column, _lines[search_pos.line].size() - 1); |
| 1792 | |
| 1793 | while (true) |
| 1794 | { |
| 1795 | if (compare_c(_lines[search_pos.line][search_pos.column].c, *match_offset)) |
| 1796 | { |
| 1797 | if (match_offset == match_last) // Keep track of end of the match |
| 1798 | match_pos_beg = search_pos; |
| 1799 | |
| 1800 | // All characters matching means the text was found, so select it and return |
| 1801 | if (match_offset == text_begin) |
| 1802 | { |
| 1803 | if (!_search_whole_word || (match_pos_beg.column + 1 >= _lines[match_pos_beg.line].size() || _lines[match_pos_beg.line][match_pos_beg.column + 1].col != _lines[match_pos_beg.line][match_pos_beg.column].col)) |
| 1804 | { |
| 1805 | _select_beg = search_pos; |
| 1806 | _select_end = text_pos(match_pos_beg.line, match_pos_beg.column + 1); |
| 1807 | _cursor_pos = _select_beg; |
| 1808 | _scroll_to_cursor = true; |
| 1809 | return true; |
| 1810 | } |
| 1811 | else |
| 1812 | { |