Changeset View
Changeset View
Standalone View
Standalone View
src/search/katesearchbar.cpp
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | |||||
44 | 44 | | |||
45 | #include <QVBoxLayout> | 45 | #include <QVBoxLayout> | ||
46 | #include <QCheckBox> | 46 | #include <QCheckBox> | ||
47 | #include <QComboBox> | 47 | #include <QComboBox> | ||
48 | #include <QCompleter> | 48 | #include <QCompleter> | ||
49 | #include <QShortcut> | 49 | #include <QShortcut> | ||
50 | #include <QStringListModel> | 50 | #include <QStringListModel> | ||
51 | 51 | | |||
52 | #include <memory> | ||||
53 | #include <vector> | ||||
54 | | ||||
52 | // Turn debug messages on/off here | 55 | // Turn debug messages on/off here | ||
53 | // #define FAST_DEBUG_ENABLE | 56 | // #define FAST_DEBUG_ENABLE | ||
54 | 57 | | |||
55 | #ifdef FAST_DEBUG_ENABLE | 58 | #ifdef FAST_DEBUG_ENABLE | ||
56 | # define FAST_DEBUG(x) qCDebug(LOG_KTE) << x | 59 | # define FAST_DEBUG(x) qCDebug(LOG_KTE) << x | ||
57 | #else | 60 | #else | ||
58 | # define FAST_DEBUG(x) | 61 | # define FAST_DEBUG(x) | ||
59 | #endif | 62 | #endif | ||
▲ Show 20 Lines • Show All 738 Lines • ▼ Show 20 Line(s) | 800 | { | |||
798 | // don't let selectionChanged signal mess around in this routine | 801 | // don't let selectionChanged signal mess around in this routine | ||
799 | disconnect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | 802 | disconnect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | ||
800 | 803 | | |||
801 | const SearchOptions enabledOptions = searchOptions(SearchForward); | 804 | const SearchOptions enabledOptions = searchOptions(SearchForward); | ||
802 | 805 | | |||
803 | const bool regexMode = enabledOptions.testFlag(Regex); | 806 | const bool regexMode = enabledOptions.testFlag(Regex); | ||
804 | const bool multiLinePattern = regexMode ? KateRegExp(searchPattern()).isMultiLine() : false; | 807 | const bool multiLinePattern = regexMode ? KateRegExp(searchPattern()).isMultiLine() : false; | ||
805 | 808 | | |||
806 | KTextEditor::MovingRange *workingRange = m_view->doc()->newMovingRange(inputRange); | 809 | std::unique_ptr<KTextEditor::MovingRange> workingRange(m_view->doc()->newMovingRange(inputRange)); | ||
807 | QList<Range> highlightRanges; | | |||
808 | int matchCounter = 0; | 810 | int matchCounter = 0; | ||
809 | 811 | | |||
812 | // we highlight all ranges of a replace, up to some hard limit | ||||
813 | // e.g. if you replace 100000 things, rendering will break down otherwise ;=) | ||||
814 | const int maxHighlightings = 65536; | ||||
815 | std::vector<Range> highlightRanges; | ||||
anthonyfieroni: You can preserve say 1024 i think. | |||||
If it's not an issue at all, I prefer to have limits that are realistic. If it scales well for, say 4096, then 4096 is the better choice. dhaumann: If it's not an issue at all, I prefer to have limits that are realistic. If it scales well for… | |||||
Actually, on a decent machine, 64k things work. cullmann: Actually, on a decent machine, 64k things work.
The issue with corner cases like this test is… | |||||
816 | | ||||
817 | // reuse match object to avoid massive moving range creation | ||||
818 | KateMatch match(m_view->doc(), enabledOptions); | ||||
819 | | ||||
810 | bool block = m_view->selection() && m_view->blockSelection(); | 820 | bool block = m_view->selection() && m_view->blockSelection(); | ||
811 | int line = inputRange.start().line(); | 821 | int line = inputRange.start().line(); | ||
812 | do { | 822 | do { | ||
813 | if (block) { | 823 | if (block) { | ||
814 | workingRange = m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(inputRange, line)); | 824 | workingRange.reset(m_view->doc()->newMovingRange(m_view->doc()->rangeOnLine(inputRange, line))); | ||
815 | } | 825 | } | ||
816 | 826 | | |||
817 | for (;;) { | 827 | for (;;) { | ||
818 | KateMatch match(m_view->doc(), enabledOptions); | | |||
819 | match.searchText(*workingRange, searchPattern()); | 828 | match.searchText(*workingRange, searchPattern()); | ||
820 | if (!match.isValid()) { | 829 | if (!match.isValid()) { | ||
821 | break; | 830 | break; | ||
822 | } | 831 | } | ||
823 | bool const originalMatchEmpty = match.isEmpty(); | 832 | bool const originalMatchEmpty = match.isEmpty(); | ||
824 | 833 | | |||
825 | // Work with the match | 834 | // Work with the match | ||
835 | Range lastRange; | ||||
826 | if (replacement != nullptr) { | 836 | if (replacement != nullptr) { | ||
827 | if (matchCounter == 0) { | 837 | if (matchCounter == 0) { | ||
828 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->startEditing(); | 838 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->startEditing(); | ||
829 | } | 839 | } | ||
830 | 840 | | |||
831 | // Replace | 841 | // Replace | ||
832 | const Range afterReplace = match.replace(*replacement, false, ++matchCounter); | 842 | lastRange = match.replace(*replacement, false, ++matchCounter); | ||
843 | } else { | ||||
844 | lastRange = match.range(); | ||||
845 | ++matchCounter; | ||||
846 | } | ||||
833 | 847 | | |||
834 | // Highlight and continue after adjusted match | 848 | // remember ranges if limit not reached | ||
835 | //highlightReplacement(*afterReplace); | 849 | if (matchCounter < maxHighlightings) { | ||
836 | highlightRanges << afterReplace; | 850 | highlightRanges.push_back(lastRange); | ||
837 | } else { | 851 | } else { | ||
838 | // Highlight and continue after original match | 852 | highlightRanges.clear(); | ||
Why you clear highlights, you can break and continue with stored ones no? anthonyfieroni: Why you clear highlights, you can break and continue with stored ones no? | |||||
839 | //highlightMatch(match); | | |||
840 | highlightRanges << match.range(); | | |||
841 | matchCounter++; | | |||
842 | } | 853 | } | ||
843 | 854 | | |||
844 | // Continue after match | 855 | // Continue after match | ||
845 | if (highlightRanges.last().end() >= workingRange->end()) { | 856 | if (lastRange.end() >= workingRange->end()) { | ||
846 | break; | 857 | break; | ||
847 | } | 858 | } | ||
848 | KTextEditor::DocumentCursor workingStart(m_view->doc(), highlightRanges.last().end()); | 859 | | ||
860 | KTextEditor::DocumentCursor workingStart(m_view->doc(), lastRange.end()); | ||||
849 | if (originalMatchEmpty) { | 861 | if (originalMatchEmpty) { | ||
850 | // Can happen for regex patterns like "^". | 862 | // Can happen for regex patterns like "^". | ||
851 | // If we don't advance here we will loop forever... | 863 | // If we don't advance here we will loop forever... | ||
852 | workingStart.move(1); | 864 | workingStart.move(1); | ||
853 | } else if (regexMode && !multiLinePattern && workingStart.atEndOfLine()) { | 865 | } else if (regexMode && !multiLinePattern && workingStart.atEndOfLine()) { | ||
854 | // single-line regexps might match the naked line end | 866 | // single-line regexps might match the naked line end | ||
855 | // therefore we better advance to the next line | 867 | // therefore we better advance to the next line | ||
856 | workingStart.move(1); | 868 | workingStart.move(1); | ||
Show All 11 Lines | |||||
868 | // After last match | 880 | // After last match | ||
869 | if (matchCounter > 0) { | 881 | if (matchCounter > 0) { | ||
870 | if (replacement != nullptr) { | 882 | if (replacement != nullptr) { | ||
871 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->finishEditing(); | 883 | static_cast<KTextEditor::DocumentPrivate *>(m_view->document())->finishEditing(); | ||
872 | } | 884 | } | ||
873 | } | 885 | } | ||
874 | 886 | | |||
875 | // Add ScrollBarMarks | 887 | // Add ScrollBarMarks | ||
888 | if (!highlightRanges.empty()) { | ||||
876 | KTextEditor::MarkInterface* iface = qobject_cast<KTextEditor::MarkInterface*>(m_view->document()); | 889 | KTextEditor::MarkInterface* iface = qobject_cast<KTextEditor::MarkInterface*>(m_view->document()); | ||
877 | if (iface) { | 890 | if (iface) { | ||
878 | iface->setMarkDescription(KTextEditor::MarkInterface::SearchMatch, i18n("SearchHighLight")); | 891 | iface->setMarkDescription(KTextEditor::MarkInterface::SearchMatch, i18n("SearchHighLight")); | ||
879 | iface->setMarkPixmap(KTextEditor::MarkInterface::SearchMatch, QIcon().pixmap(0,0)); | 892 | iface->setMarkPixmap(KTextEditor::MarkInterface::SearchMatch, QIcon().pixmap(0,0)); | ||
880 | foreach (Range r, highlightRanges) { | 893 | for (const Range &r : highlightRanges) { | ||
881 | iface->addMark(r.start().line(), KTextEditor::MarkInterface::SearchMatch); | 894 | iface->addMark(r.start().line(), KTextEditor::MarkInterface::SearchMatch); | ||
882 | } | 895 | } | ||
883 | } | 896 | } | ||
897 | } | ||||
884 | 898 | | |||
885 | // Add highlights | 899 | // Add highlights | ||
886 | if (replacement == nullptr) | 900 | if (replacement == nullptr) { | ||
887 | foreach (Range r, highlightRanges) { | 901 | for (const Range &r : highlightRanges) { | ||
888 | highlightMatch(r); | 902 | highlightMatch(r); | ||
889 | } | 903 | } | ||
890 | else | 904 | } else { | ||
891 | foreach (Range r, highlightRanges) { | 905 | for (const Range &r : highlightRanges) { | ||
892 | highlightReplacement(r); | 906 | highlightReplacement(r); | ||
893 | } | 907 | } | ||
894 | 908 | } | |||
895 | delete workingRange; | | |||
896 | 909 | | |||
897 | // restore connection | 910 | // restore connection | ||
898 | connect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | 911 | connect(m_view, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(updateSelectionOnly())); | ||
899 | 912 | | |||
900 | return matchCounter; | 913 | return matchCounter; | ||
901 | } | 914 | } | ||
902 | 915 | | |||
903 | void KateSearchBar::replaceAll() | 916 | void KateSearchBar::replaceAll() | ||
▲ Show 20 Lines • Show All 750 Lines • Show Last 20 Lines |
You can preserve say 1024 i think.