/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.antlr.works.editor.antlr4.completion;
import com.tvl.spi.editor.completion.CompletionItem;
import java.text.Collator;
import java.util.Locale;
import java.util.regex.Pattern;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.openide.util.Parameters;
/**
*
* @author Sam Harwell
*/
public class CompletionMatchEvaluator {
public static final int EXACT_CASE_SENSITIVE = 0x1000;
public static final int EXACT = 0x0800;
public static final int PREFIX_CASE_SENSITIVE = 0x0400;
public static final int PREFIX = 0x0200;
public static final int SUBSTRING = 0x0100;
public static final int WORD = 0x0080;
public static final int LETTER_ORDER = 0x0040;
public static final int VALID = 0x0020;
public static final int RECENTLY_USED_MASK = 0x001E;
public static final int CASE_SENSITIVE = 0x0001;
private static final Collator recentCompletionsCollator;
@NonNull
private final String evaluatedText;
@NonNull
private final String lowerCaseEvaluatedText;
@NullAllowed
private final Pattern caseSensitiveWordMatch;
@NullAllowed
private final Pattern caseInsensitiveWordMatch;
@NullAllowed
private final Pattern caseSensitiveLetterOrderMatch;
@NullAllowed
private final Pattern caseInsensitiveLetterOrderMatch;
static {
recentCompletionsCollator = Collator.getInstance(Locale.getDefault());
recentCompletionsCollator.setDecomposition(Collator.NO_DECOMPOSITION);
recentCompletionsCollator.setStrength(Collator.IDENTICAL);
}
public CompletionMatchEvaluator(@NonNull String evaluatedText) {
Parameters.notNull("evaluatedText", evaluatedText);
this.evaluatedText = evaluatedText;
this.lowerCaseEvaluatedText = evaluatedText.toLowerCase(Locale.getDefault());
this.caseSensitiveWordMatch = BaseCompletionController.getPrefixBoundaryPattern(evaluatedText, true);
this.caseInsensitiveWordMatch = BaseCompletionController.getPrefixBoundaryPattern(evaluatedText, false);
this.caseSensitiveLetterOrderMatch = BaseCompletionController.getLetterOrderPattern(evaluatedText, true);
this.caseInsensitiveLetterOrderMatch = BaseCompletionController.getLetterOrderPattern(evaluatedText, false);
}
public int getMatchStrength(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
CompletionMatchResult exact = isExactMatch(completionItem);
CompletionMatchResult prefix = isPrefixMatch(completionItem);
CompletionMatchResult substring = isSubstringMatch(completionItem);
CompletionMatchResult word = isWordBoundaryMatch(completionItem);
CompletionMatchResult letterOrder = isLetterOrderMatch(completionItem);
CompletionMatchResult valid = isValidMatch(completionItem);
int recent = getRecentlyUsed(completionItem);
boolean caseSensitive;
if (exact != CompletionMatchResult.None) {
caseSensitive = exact == CompletionMatchResult.MatchCaseSensitive;
} else if (prefix != CompletionMatchResult.None) {
caseSensitive = prefix == CompletionMatchResult.MatchCaseSensitive;
} else if (substring != CompletionMatchResult.None) {
caseSensitive = substring == CompletionMatchResult.MatchCaseSensitive;
} else if (word != CompletionMatchResult.None) {
caseSensitive = word == CompletionMatchResult.MatchCaseSensitive;
} else if (letterOrder != CompletionMatchResult.None) {
caseSensitive = letterOrder == CompletionMatchResult.MatchCaseSensitive;
} else if (valid != CompletionMatchResult.None) {
caseSensitive = valid == CompletionMatchResult.MatchCaseSensitive;
} else {
caseSensitive = false;
}
int strength = 0;
if (exact == CompletionMatchResult.MatchCaseSensitive) {
strength |= EXACT_CASE_SENSITIVE;
}
if (prefix == CompletionMatchResult.MatchCaseSensitive) {
strength |= PREFIX_CASE_SENSITIVE;
}
if (exact == CompletionMatchResult.Match) {
strength |= EXACT;
}
if (prefix == CompletionMatchResult.Match) {
strength |= PREFIX;
}
if (substring != CompletionMatchResult.None) {
strength |= SUBSTRING;
}
if (word != CompletionMatchResult.None) {
strength |= WORD;
}
if (letterOrder != CompletionMatchResult.None) {
strength |= LETTER_ORDER;
}
if (valid != CompletionMatchResult.None) {
strength |= VALID;
}
recent = Math.max(0, recent);
recent = Math.min(255, recent);
strength |= (recent << 1);
if (caseSensitive) {
strength |= CASE_SENSITIVE;
}
return strength;
}
protected @NonNull CompletionMatchResult isExactMatch(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
if (evaluatedText.isEmpty()) {
return CompletionMatchResult.None;
}
String insertText = completionItem.getInsertPrefix().toString();
if (evaluatedText.equals(insertText)) {
return CompletionMatchResult.MatchCaseSensitive;
}
insertText = insertText.toLowerCase(Locale.getDefault());
if (lowerCaseEvaluatedText.equals(insertText)) {
return CompletionMatchResult.Match;
}
return CompletionMatchResult.None;
}
protected @NonNull CompletionMatchResult isPrefixMatch(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
if (evaluatedText.isEmpty()) {
return CompletionMatchResult.MatchCaseSensitive;
}
String insertText = completionItem.getInsertPrefix().toString();
if (insertText.startsWith(evaluatedText)) {
return CompletionMatchResult.MatchCaseSensitive;
}
insertText = insertText.toLowerCase(Locale.getDefault());
if (insertText.startsWith(lowerCaseEvaluatedText)) {
return CompletionMatchResult.Match;
}
return CompletionMatchResult.None;
}
public @NonNull CompletionMatchResult isSubstringMatch(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
if (evaluatedText.isEmpty()) {
return CompletionMatchResult.MatchCaseSensitive;
}
String insertText = completionItem.getInsertPrefix().toString();
if (insertText.contains(evaluatedText)) {
return CompletionMatchResult.MatchCaseSensitive;
}
insertText = insertText.toLowerCase(Locale.getDefault());
if (insertText.contains(lowerCaseEvaluatedText)) {
return CompletionMatchResult.Match;
}
return CompletionMatchResult.None;
}
public @NonNull CompletionMatchResult isWordBoundaryMatch(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
if (evaluatedText.isEmpty() || caseSensitiveWordMatch == null || caseInsensitiveWordMatch == null) {
return CompletionMatchResult.None;
}
String insertText = completionItem.getInsertPrefix().toString();
if (caseInsensitiveWordMatch.matcher(insertText).matches()) {
if (caseSensitiveWordMatch.matcher(insertText).matches()) {
return CompletionMatchResult.MatchCaseSensitive;
}
return CompletionMatchResult.Match;
}
return CompletionMatchResult.None;
}
public @NonNull CompletionMatchResult isLetterOrderMatch(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
if (evaluatedText.isEmpty() || caseSensitiveLetterOrderMatch == null || caseInsensitiveLetterOrderMatch == null) {
return CompletionMatchResult.None;
}
String insertText = completionItem.getInsertPrefix().toString();
if (caseInsensitiveLetterOrderMatch.matcher(insertText).find()) {
if (caseSensitiveLetterOrderMatch.matcher(insertText).find()) {
return CompletionMatchResult.MatchCaseSensitive;
}
return CompletionMatchResult.Match;
}
return CompletionMatchResult.None;
}
public @NonNull CompletionMatchResult isValidMatch(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
return completionItem.getSortPriority() < 0 ? CompletionMatchResult.Match : CompletionMatchResult.None;
}
protected Collator getRecentCompletionsCollator() {
return recentCompletionsCollator;
}
public int getRecentlyUsed(@NonNull CompletionItem completionItem) {
Parameters.notNull("completionItem", completionItem);
return BaseCompletionController.getRecentCompletionWeight(completionItem.getInsertPrefix().toString(), getRecentCompletionsCollator());
}
}