blob: 74081d16ed72c90bb2186e91f67f68c4f6c959a2 [file] [log] [blame]
/*
* Copyright 2000-2009 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.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class NameUtil {
private static final Function<String,String> LOWERCASE_MAPPING = new Function<String, String>() {
@Override
public String fun(final String s) {
return s.toLowerCase();
}
};
private static final int MAX_LENGTH = 40;
private NameUtil() {}
public static List<String> nameToWordsLowerCase(String name){
return ContainerUtil.map(nameToWords(name), LOWERCASE_MAPPING);
}
public static String[] nameToWords(String name){
ArrayList<String> array = new ArrayList<String>();
int index = 0;
while(index < name.length()){
int wordStart = index;
int upperCaseCount = 0;
int lowerCaseCount = 0;
int digitCount = 0;
int specialCount = 0;
while(index < name.length()){
char c = name.charAt(index);
if (Character.isDigit(c)){
if (upperCaseCount > 0 || lowerCaseCount > 0 || specialCount > 0) break;
digitCount++;
}
else if (Character.isUpperCase(c)){
if (lowerCaseCount > 0 || digitCount > 0 || specialCount > 0) break;
upperCaseCount++;
}
else if (Character.isLowerCase(c)){
if (digitCount > 0 || specialCount > 0) break;
if (upperCaseCount > 1) {
index--;
break;
}
lowerCaseCount++;
}
else{
if (upperCaseCount > 0 || lowerCaseCount > 0 || digitCount > 0) break;
specialCount++;
}
index++;
}
String word = name.substring(wordStart, index);
if (!StringUtil.isEmptyOrSpaces(word)) {
array.add(word);
}
}
return ArrayUtil.toStringArray(array);
}
public static String buildRegexp(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) {
return buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, false);
}
public static String buildRegexp(String pattern,
int exactPrefixLen,
boolean allowToUpper,
boolean allowToLower,
boolean lowerCaseWords,
boolean forCompletion) {
final int eol = pattern.indexOf('\n');
if (eol != -1) {
pattern = pattern.substring(0, eol);
}
if (pattern.length() >= MAX_LENGTH) {
pattern = pattern.substring(0, MAX_LENGTH);
}
@NonNls final StringBuilder buffer = new StringBuilder();
final boolean endsWithSpace = !forCompletion && StringUtil.endsWithChar(pattern, ' ');
if (!forCompletion) {
pattern = pattern.trim();
}
exactPrefixLen = Math.min(exactPrefixLen, pattern.length());
/*final boolean uppercaseOnly = containsOnlyUppercaseLetters(pattern.substring(exactPrefixLen));
if (uppercaseOnly) {
allowToLower = false;
}*/
boolean prevIsUppercase = false;
if (exactPrefixLen > 0) {
char c = pattern.charAt(exactPrefixLen - 1);
prevIsUppercase = Character.isUpperCase(c) || Character.isDigit(c);
}
for (int i = 0; i != exactPrefixLen; ++i) {
final char c = pattern.charAt(i);
if (Character.isLetterOrDigit(c)) {
buffer.append(c);
}
else {
// for standard RegExp engine
// buffer.append("\\u");
// buffer.append(Integer.toHexString(c + 0x20000).substring(1));
// for OROMATCHER RegExp engine
buffer.append("\\").append(c);
//buffer.append(Integer.toHexString(c + 0x20000).substring(2));
}
}
if (exactPrefixLen == 0) {
buffer.append("_*"); // ignore leading underscores
}
boolean firstIdentifierLetter = exactPrefixLen == 0;
boolean lastIsUppercase = false;
for (int i = exactPrefixLen; i < pattern.length(); i++) {
final char c = pattern.charAt(i);
lastIsUppercase = false;
if (Character.isLetterOrDigit(c)) {
prevIsUppercase = false;
// This logic allows to use uppercase letters only to catch the name like PDM for PsiDocumentManager
if (Character.isUpperCase(c) || Character.isDigit(c)) {
prevIsUppercase = true;
lastIsUppercase = true;
buffer.append('(');
if (!firstIdentifierLetter) {
buffer.append("[a-z\\s0-9\\$]*");
}
buffer.append(c);
if (allowToLower) {
buffer.append('|');
buffer.append(Character.toLowerCase(c));
}
if (!firstIdentifierLetter) {
buffer.append("|[A-Za-z\\s0-9\\$]*[_-]+[");
buffer.append(c);
buffer.append(Character.toLowerCase(c));
buffer.append("]");
}
buffer.append(')');
}
else if (Character.isLowerCase(c) && allowToUpper) {
buffer.append('[');
buffer.append(c);
buffer.append(Character.toUpperCase(c));
buffer.append(']');
if (lowerCaseWords) {
buffer.append("([a-z\\s0-9\\$]*[-_]+)?");
}
}
else {
buffer.append(c);
}
firstIdentifierLetter = false;
}
else if (c == '*') {
buffer.append(".*");
firstIdentifierLetter = true;
}
else if (c == '.') {
if (!firstIdentifierLetter) {
buffer.append("[a-z\\s0-9\\$]*\\.");
}
else {
buffer.append("\\.");
}
firstIdentifierLetter = true;
}
else if (c == ' ') {
buffer.append("([a-z\\s0-9\\$_-]*[\\ _-]+)+");
firstIdentifierLetter = true;
}
else {
if (c == ':' || prevIsUppercase) {
buffer.append("[A-Za-z\\s0-9\\$]*");
}
firstIdentifierLetter = true;
// for standard RegExp engine
// buffer.append("\\u");
// buffer.append(Integer.toHexString(c + 0x20000).substring(1));
// for OROMATCHER RegExp engine
buffer.append("\\").append(c);
//buffer.append(Integer.toHexString(c + 0x20000).substring(3));
}
}
if (!endsWithSpace) {
buffer.append(".*");
}
else if (lastIsUppercase) {
buffer.append("[a-z\\s0-9\\$]*");
}
//System.out.println("rx = " + buffer.toString());
return buffer.toString();
}
/**
* Splits an identifier into words, separated with underscores or upper-case characters
* (camel-case).
*
* @param name the identifier to split.
* @return the array of strings into which the identifier has been split.
*/
public static String[] splitNameIntoWords(@NotNull String name) {
final String[] underlineDelimited = name.split("_");
List<String> result = new ArrayList<String>();
for (String word : underlineDelimited) {
addAllWords(word, result);
}
return ArrayUtil.toStringArray(result);
}
public static List<String> getSuggestionsByName(String name,
String prefix,
String suffix,
boolean upperCaseStyle,
boolean preferLongerNames, boolean isArray) {
ArrayList<String> answer = new ArrayList<String>();
String[] words = nameToWords(name);
for (int step = 0; step < words.length; step++) {
int wordCount = preferLongerNames ? words.length - step : step + 1;
String startWord = words[words.length - wordCount];
char c = startWord.charAt(0);
if( c == '_' || !Character.isJavaIdentifierStart( c ) )
{
continue;
}
answer.add(compoundSuggestion(prefix, upperCaseStyle, words, wordCount, startWord, c, isArray, false) + suffix);
answer.add(compoundSuggestion(prefix, upperCaseStyle, words, wordCount, startWord, c, isArray, true) + suffix);
}
return answer;
}
private static String compoundSuggestion(String prefix,
boolean upperCaseStyle,
String[] words,
int wordCount,
String startWord,
char c,
boolean isArray,
boolean skip_) {
StringBuilder buffer = new StringBuilder();
buffer.append(prefix);
if (upperCaseStyle) {
startWord = StringUtil.toUpperCase(startWord);
}
else {
if (prefix.isEmpty() || StringUtil.endsWithChar(prefix, '_')) {
startWord = startWord.toLowerCase();
}
else {
startWord = Character.toUpperCase(c) + startWord.substring(1);
}
}
buffer.append(startWord);
for (int i = words.length - wordCount + 1; i < words.length; i++) {
String word = words[i];
String prevWord = words[i - 1];
if (upperCaseStyle) {
word = StringUtil.toUpperCase(word);
if (prevWord.charAt(prevWord.length() - 1) != '_' && word.charAt(0) != '_') {
word = "_" + word;
}
}
else {
if (prevWord.charAt(prevWord.length() - 1) == '_') {
word = word.toLowerCase();
}
if (skip_) {
if (word.equals("_")) continue;
if (prevWord.equals("_")) {
word = StringUtil.capitalize(word);
}
}
}
buffer.append(word);
}
String suggestion = buffer.toString();
if (isArray) {
suggestion = StringUtil.pluralize(suggestion);
if (upperCaseStyle) {
suggestion = StringUtil.toUpperCase(suggestion);
}
}
return suggestion;
}
static boolean isWordStart(char p) {
return Character.isUpperCase(p) || Character.isDigit(p);
}
static int nextWord(String text, int start) {
if (!Character.isLetterOrDigit(text.charAt(start))) {
return start + 1;
}
int i = start;
while (i < text.length() && Character.isDigit(text.charAt(i))) i++;
if (i > start) {
// digits form a separate hump
return i;
}
while (i < text.length() && Character.isUpperCase(text.charAt(i))) i++;
if (i > start + 1) {
// several consecutive uppercase letter form a hump
if (i == text.length() || !Character.isLetter(text.charAt(i))) {
return i;
}
return i - 1;
}
while (i < text.length() && Character.isLetter(text.charAt(i)) && !Character.isUpperCase(text.charAt(i))) i++;
return i;
}
private static void addAllWords(String text, List<String> result) {
int start = 0;
while (start < text.length()) {
int next = nextWord(text, start);
result.add(text.substring(start, next));
start = next;
}
}
/**
* @deprecated use com.intellij.util.text.Matcher
*/
public interface Matcher {
boolean matches(String name);
}
@SuppressWarnings("UnusedDeclaration")
@Deprecated
public static com.intellij.util.text.Matcher buildCompletionMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) {
MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE;
return buildMatcher(pattern, options);
}
public static com.intellij.util.text.Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) {
MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE;
return buildMatcher(pattern, options);
}
@SuppressWarnings("UnusedParameters")
@Deprecated
public static com.intellij.util.text.Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower, boolean lowerCaseWords) {
MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE;
return buildMatcher(pattern, options);
}
public static MinusculeMatcher buildMatcher(@NotNull String pattern, @NotNull MatchingCaseSensitivity options) {
return new MinusculeMatcher(pattern, options);
}
public enum MatchingCaseSensitivity {
NONE, FIRST_LETTER, ALL
}
}