IDEA-170592 Choose Content to Paste Dialog (Ctrl+Shift+V) only highlights the first match per line

following IDEA-CR-20578
This commit is contained in:
Dmitry Batrak
2017-04-25 20:31:04 +03:00
parent f2c10b131b
commit ce3dcaa816
4 changed files with 65 additions and 32 deletions
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.codeStyle;
import com.intellij.openapi.util.TextRange;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
class AllOccurrencesMatcher extends FixingLayoutMatcher {
AllOccurrencesMatcher(@NotNull String pattern, @NotNull NameUtil.MatchingCaseSensitivity options, String hardSeparators) {
super(pattern, options, hardSeparators);
}
@Nullable
@Override
public FList<TextRange> matchingFragments(@NotNull String name) {
FList<TextRange> match = super.matchingFragments(name);
if (!ContainerUtil.isEmpty(match)) {
List<FList<TextRange>> allMatchesReversed = new ArrayList<FList<TextRange>>();
int lastOffset = 0;
while (!ContainerUtil.isEmpty(match)) {
FList<TextRange> reversedWithAbsoluteOffsets = FList.emptyList();
for (TextRange r : match) {
reversedWithAbsoluteOffsets = reversedWithAbsoluteOffsets.prepend(r.shiftRight(lastOffset));
}
allMatchesReversed.add(reversedWithAbsoluteOffsets);
lastOffset = reversedWithAbsoluteOffsets.get(0).getEndOffset();
match = super.matchingFragments(name.substring(lastOffset));
}
match = FList.emptyList();
for (int i = allMatchesReversed.size() - 1; i >= 0; i--) {
for (TextRange range : allMatchesReversed.get(i)) {
match = match.prepend(range);
}
}
}
return match;
}
}
@@ -31,11 +31,10 @@ public class FixingLayoutMatcher extends MinusculeMatcher {
@Nullable
private final MinusculeMatcher myFixedMatcher;
FixingLayoutMatcher(@NotNull String pattern, @NotNull NameUtil.MatchingCaseSensitivity options, String hardSeparators,
boolean matchAllOccurrences) {
super(pattern, options, hardSeparators, matchAllOccurrences);
FixingLayoutMatcher(@NotNull String pattern, @NotNull NameUtil.MatchingCaseSensitivity options, String hardSeparators) {
super(pattern, options, hardSeparators);
String s = fixPattern(pattern);
myFixedMatcher = s == null ? null : new MinusculeMatcher(s, options, hardSeparators, matchAllOccurrences);
myFixedMatcher = s == null ? null : new MinusculeMatcher(s, options, hardSeparators);
}
@Nullable
@@ -17,7 +17,6 @@ package com.intellij.psi.codeStyle;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
import com.intellij.util.io.IOUtil;
import com.intellij.util.text.Matcher;
@@ -25,10 +24,8 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
/**
* Tells whether a string matches a specific pattern. Allows for lowercase camel-hump matching.
@@ -59,7 +56,6 @@ public class MinusculeMatcher implements Matcher {
private final char[] toLowerCase;
private final char[] myMeaningfulCharacters;
private final int myMinNameLength;
private final boolean myMatchAllOccurrences;
/**
* Constructs a matcher by a given pattern.
@@ -67,11 +63,8 @@ public class MinusculeMatcher implements Matcher {
* @param options case sensitivity settings
* @param hardSeparators A string of characters (empty by default). Lowercase humps don't work for parts separated by any of these characters.
* Need either an explicit uppercase letter or the same separator character in prefix
* @param matchAllOccurrences if <code>true</code>, all pattern matches will be reported by {@link #matchingFragments(String)} method,
* otherwise, only first match will be reported
*/
MinusculeMatcher(@NotNull String pattern, @NotNull NameUtil.MatchingCaseSensitivity options, @NotNull String hardSeparators,
boolean matchAllOccurrences) {
MinusculeMatcher(@NotNull String pattern, @NotNull NameUtil.MatchingCaseSensitivity options, @NotNull String hardSeparators) {
myOptions = options;
myPattern = StringUtil.trimEnd(pattern, "* ").toCharArray();
myHardSeparators = hardSeparators;
@@ -100,7 +93,6 @@ public class MinusculeMatcher implements Matcher {
myHasDots = hasDots(i);
myMeaningfulCharacters = meaningful.toString().toCharArray();
myMinNameLength = myMeaningfulCharacters.length / 2;
myMatchAllOccurrences = matchAllOccurrences;
}
private static boolean isWordSeparator(char c) {
@@ -264,24 +256,7 @@ public class MinusculeMatcher implements Matcher {
MatchingState state = myMatchingState.get();
state.initializeState(isAscii, length);
try {
FList<TextRange> match = matchWildcards(name, 0, 0, state);
if (myMatchAllOccurrences && !ContainerUtil.isEmpty(match)) {
List<FList<TextRange>> allMatchesReversed = new ArrayList<FList<TextRange>>();
while (!ContainerUtil.isEmpty(match)) {
match = FList.createFromReversed(match);
allMatchesReversed.add(match);
int lastOffset = match.get(0).getEndOffset();
match = matchWildcards(name, 0, lastOffset, state);
}
match = FList.emptyList();
for (int i = allMatchesReversed.size() - 1; i >= 0; i--) {
for (TextRange range : allMatchesReversed.get(i)) {
match = match.prepend(range);
}
}
}
return match;
return matchWildcards(name, 0, 0, state);
}
finally {
state.releaseState();
@@ -436,7 +436,8 @@ public class NameUtil {
}
public MinusculeMatcher build() {
return new FixingLayoutMatcher(pattern, caseSensitivity, separators, matchAllOccurrences);
return matchAllOccurrences ? new AllOccurrencesMatcher(pattern, caseSensitivity, separators)
: new FixingLayoutMatcher(pattern, caseSensitivity, separators);
}
}