blob: 1ddf9d2604119394b2ac99138319c4383053c2c6 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2016, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.r.core;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.text.core.SearchPattern;;
@NonNullByDefault
public class RSearchPattern extends SearchPattern {
private static final int NOT_CHECKED= -1;
private int minCharCount;
public RSearchPattern(final int rules, final String pattern) {
super(rules, pattern);
}
@Override
protected void onPatternChanged(final String pattern) {
this.minCharCount= NOT_CHECKED;
}
private int getR1MinCharCount() {
int count= this.minCharCount;
if (count == NOT_CHECKED) {
final char[] pattern= getPatternChars();
if (pattern.length > 0) {
count= 1;
for (int i= 1; i < pattern.length; i++) {
final char c= pattern[i];
if (c != '.' && c != '_') {
count++;
}
}
}
else {
count= 0;
}
this.minCharCount= count;
}
return count;
}
@Override
public int matches(final String name) {
final int allowedRules= getRules();
final char[] patternChars= getPatternChars();
char[] nameChars= null;
final int minCharCount= getR1MinCharCount();
final int lDiff= name.length() - minCharCount;
if (lDiff >= 0) {
if ((allowedRules & PREFIX_MATCH) != 0
&& (isR1PrefixMatch(patternChars, 0, patternChars.length,
name, 0, name.length() ) )) {
return PREFIX_MATCH;
}
if (lDiff > 0 && patternChars.length > 0) {
if ((allowedRules & SUBSTRING_MATCH) != 0
&& isR1SubstringMatch(patternChars, 0, patternChars.length, minCharCount,
nameChars= getNameChars(name), 1, nameChars.length )) {
return SUBSTRING_MATCH;
}
}
}
return 0;
}
protected boolean isR1PrefixMatch(final char[] pattern, final int patternStart, final int patternEnd,
final String name, final int nameStart, final int nameEnd) {
if (nameEnd - nameStart == 0) {
return false;
}
if (patternEnd - patternStart == 0) {
return (name.charAt(nameStart) != '.');
}
char patternChar= pattern[patternStart];
char nameChar= Character.toLowerCase(name.charAt(nameStart));
if (nameChar != patternChar) {
return false;
}
int patternIdx= patternStart;
int nameIdx= nameStart;
while (true) {
if (nameChar == patternChar) {
if (++patternIdx >= patternEnd) {
return true;
}
if (++nameIdx < nameEnd) {
patternChar= pattern[patternIdx];
nameChar= Character.toLowerCase(name.charAt(nameIdx));
continue;
}
}
else if (patternChar == '.' || patternChar == '_') {
if (++patternIdx >= patternEnd) {
return true;
}
patternChar= pattern[patternIdx];
continue;
}
else if (nameChar == '.' || nameChar == '_') {
if (++nameIdx < nameEnd) {
nameChar= Character.toLowerCase(name.charAt(nameIdx));
continue;
}
}
return false;
}
}
protected boolean isR1PrefixMatch(final char[] pattern, final int patternStart, final int patternEnd,
final char[] name, final int nameStart, final int nameEnd) {
if (nameEnd - nameStart == 0) {
return false;
}
if (patternEnd - patternStart == 0) {
return (name[nameStart] != '.');
}
char patternChar= pattern[patternStart];
char nameChar= name[nameStart];
if (nameChar != patternChar) {
return false;
}
int patternIdx= patternStart;
int nameIdx= nameStart;
while (true) {
if (nameChar == patternChar) {
if (++patternIdx >= patternEnd) {
return true;
}
if (++nameIdx < nameEnd) {
patternChar= pattern[patternIdx];
nameChar= name[nameIdx];
continue;
}
}
else if (patternChar == '.' || patternChar == '_') {
if (++patternIdx >= patternEnd) {
return true;
}
patternChar= pattern[patternIdx];
continue;
}
else if (nameChar == '.' || nameChar == '_') {
if (++nameIdx < nameEnd) {
nameChar= name[nameIdx];
continue;
}
}
return false;
}
}
protected boolean isR1SubstringMatch(final char[] pattern, final int patternStart, final int patternEnd,
final int minCharCount,
final char[] name, final int nameStart, final int nameEnd) {
final int nameLastStart= nameEnd - minCharCount;
ITER_SUB: for (int nameCurrentStart= nameStart; nameCurrentStart <= nameLastStart; ) {
int patternIdx= patternStart;
int nameIdx= nameCurrentStart;
char patternChar= pattern[patternIdx];
char nameChar= name[nameIdx];
if (nameChar == patternChar) {
while (true) {
if (nameChar == patternChar) {
if (++patternIdx >= patternEnd) {
return true;
}
if (++nameIdx < nameEnd) {
patternChar= pattern[patternIdx];
nameChar= name[nameIdx];
continue;
}
}
else if (patternChar == '.' || patternChar == '_') {
if (++patternIdx >= patternEnd) {
return true;
}
patternChar= pattern[patternIdx];
continue;
}
else if (nameChar == '.' || nameChar == '_') {
if (++nameIdx < nameEnd) {
nameChar= name[nameIdx];
continue;
}
}
break;
}
}
nameCurrentStart++;
continue ITER_SUB;
}
return false;
}
@Override
public int @Nullable [] getMatchingRegions(final String name, final int matchRule) {
final char[] patternChars;
final char[] nameChars;
switch (matchRule) {
case EXACT_MATCH:
case PREFIX_MATCH:
return getR1PrefixMatches(patternChars= getPatternChars(), 0, patternChars.length,
name, 0, name.length() );
case SUBSTRING_MATCH:
this.tmpRegions.clear();
addR1SubstringMatches(patternChars= getPatternChars(), 0, patternChars.length,
getR1MinCharCount(),
nameChars= getNameChars(name), 0, nameChars.length );
return this.tmpRegions.toArray();
default:
return null;
}
}
private int @Nullable [] getR1PrefixMatches(final char[] pattern, final int patternStart, final int patternEnd,
final String name, final int nameStart, final int nameEnd) {
if (patternEnd - patternStart == 0) {
return null;
}
if (patternEnd - patternStart == 1) {
return new int[] { nameStart, nameStart + 1 };
}
char patternChar= pattern[patternStart];
char nameChar= patternChar; // Character.toLowerCase(name.charAt(nameStart));
int patternIdx= patternStart;
int nameIdx= nameStart;
int matchEnd= nameIdx;
while (true) {
// if (nameChar == patternChar) {
// matchEnd= nameIdx + 1;
// if (++patternIdx >= patternEnd) {
// return new int[] { nameStart, matchEnd };
// }
// if (++nameIdx < nameEnd) {
// patternChar= pattern[patternIdx];
// nameChar= Character.toLowerCase(name.charAt(nameIdx));
// continue;
// }
// }
// else if (patternChar == '.' || patternChar == '_') {
// if (++patternIdx >= patternEnd) {
// return new int[] { nameStart, matchEnd };
// }
// patternChar= pattern[patternIdx];
// continue;
// }
// else if (nameChar == '.' || nameChar == '_') {
// if (++nameIdx < nameEnd) {
// nameChar= Character.toLowerCase(name.charAt(nameIdx));
// continue;
// }
// }
if (nameChar != patternChar) {
if (patternChar == '.' || patternChar == '_') {
if (++patternIdx >= patternEnd) {
return new int[] { nameStart, matchEnd };
}
patternChar= pattern[patternIdx];
continue;
}
else if (nameChar == '.' || nameChar == '_') {
if (++nameIdx < nameEnd) {
nameChar= name.charAt(nameIdx);
continue;
}
throw new IllegalArgumentException();
}
}
matchEnd= nameIdx + 1;
if (++patternIdx >= patternEnd) {
return new int[] { nameStart, matchEnd };
}
if (++nameIdx < nameEnd) {
patternChar= pattern[patternIdx];
nameChar= name.charAt(nameIdx);
continue;
}
}
}
private void addR1SubstringMatches(final char[] pattern, final int patternStart, final int patternEnd,
final int minCharCount,
final char[] name, final int nameStart, final int nameEnd) {
if (patternEnd - patternStart == 0) {
return;
}
final int nameLastStart= nameEnd - minCharCount;
ITER_SUB: for (int nameCurrentStart= nameStart; nameCurrentStart <= nameLastStart; ) {
int patternIdx= patternStart;
int nameIdx= nameCurrentStart;
int matchEnd= nameIdx;
char patternChar= pattern[patternIdx];
char nameChar= name[nameIdx];
if (nameChar == patternChar) {
while (true) {
if (nameChar == patternChar) {
matchEnd= nameIdx + 1;
if (++patternIdx >= patternEnd) {
this.tmpRegions.add(nameCurrentStart);
this.tmpRegions.add(matchEnd);
nameCurrentStart= matchEnd;
continue ITER_SUB;
}
if (++nameIdx < nameEnd) {
patternChar= pattern[patternIdx];
nameChar= name[nameIdx];
continue;
}
}
else if (patternChar == '.' || patternChar == '_') {
if (++patternIdx >= patternEnd) {
this.tmpRegions.add(nameCurrentStart);
this.tmpRegions.add(matchEnd);
nameCurrentStart= matchEnd;
continue ITER_SUB;
}
patternChar= pattern[patternIdx];
continue;
}
else if (nameChar == '.' || nameChar == '_') {
if (++nameIdx < nameEnd) {
nameChar= name[nameIdx];
continue;
}
}
break;
}
}
nameCurrentStart++;
continue ITER_SUB;
}
}
}