Merge branch 'master' of git@git.labs.intellij.net:idea/community into tool-window
[fedora-idea.git] / platform / platform-impl / src / com / intellij / application / options / ReplacePathToMacroMap.java
blob8f34803712a6ad245531b2171e45ddff915685b1
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.application.options;
18 import com.intellij.openapi.components.PathMacroMap;
19 import com.intellij.openapi.util.text.StringUtil;
20 import com.intellij.util.StringBuilderSpinAllocator;
21 import org.jetbrains.annotations.NonNls;
23 import java.util.*;
25 /**
26 * @author Eugene Zhuravlev
27 * Date: Dec 6, 2004
29 public class ReplacePathToMacroMap extends PathMacroMap {
30 private List<String> myPathsIndex = null;
32 private static final Comparator<Map.Entry<String, String>> PATHS_COMPARATOR = new Comparator<Map.Entry<String, String>>() {
33 public int compare(final Map.Entry<String, String> o1, final Map.Entry<String, String> o2) {
34 int idx1 = getIndex(o1);
35 int idx2 = getIndex(o2);
37 if (idx1 != idx2) return idx1 - idx2;
39 return o2.getKey().length() - o1.getKey().length();
42 private int getIndex(final Map.Entry<String, String> s) {
43 if (s.getValue().indexOf("..") >= 0) return 3;
45 if (s.getValue().indexOf("$MODULE_DIR$") >= 0) return 1;
46 if (s.getValue().indexOf("$PROJECT_DIR$") >= 0) return 1;
47 return 2;
51 @NonNls private static final String[] PROTOCOLS = new String[]{"file", "jar"};
53 public void addMacroReplacement(String path, String macroName) {
54 final String p = quotePath(path);
55 final String m = "$" + macroName + "$";
57 put(p, m);
58 for (String protocol : PROTOCOLS) {
59 put(protocol + ":" + p, protocol + ":" + m);
60 put(protocol + ":/" + p, protocol + "://" + m);
61 put(protocol + "://" + p, protocol + "://" + m);
65 public String substitute(String text, boolean caseSensitive) {
66 for (final String path : getPathIndex()) {
67 final String macro = get(path);
68 text = replacePathMacro(text, path, macro, caseSensitive);
70 return text;
73 private static String replacePathMacro(String text,
74 String path,
75 final String macro,
76 boolean caseSensitive) {
77 if (text.length() < path.length() || path.length() == 0) {
78 return text;
81 boolean startsWith;
83 if (caseSensitive) {
84 startsWith = text.startsWith(path);
86 else {
87 startsWith = StringUtil.startsWithIgnoreCase(text, path);
90 if (!startsWith) return text;
92 final StringBuilder newText = StringBuilderSpinAllocator.alloc();
93 try {
94 //check that this is complete path (ends with "/" or "!/")
95 int endOfOccurence = path.length();
96 final boolean isWindowsRoot = path.endsWith(":/");
97 if (!isWindowsRoot &&
98 endOfOccurence < text.length() &&
99 text.charAt(endOfOccurence) != '/' &&
100 !text.substring(endOfOccurence).startsWith("!/")) {
101 return text;
104 newText.append(macro);
105 newText.append(text.substring(endOfOccurence));
107 return newText.toString();
109 finally {
110 StringBuilderSpinAllocator.dispose(newText);
114 @Override
115 public String substituteRecursively(String text, final boolean caseSensitive) {
116 for (final String path : getPathIndex()) {
117 final String macro = get(path);
118 text = replacePathMacroRecursively(text, path, macro, caseSensitive);
120 return text;
123 private static String replacePathMacroRecursively(String text,
124 String path,
125 final String macro,
126 boolean caseSensitive) {
127 if (text.length() < path.length()) {
128 return text;
131 if (path.length() == 0) return text;
133 final StringBuilder newText = StringBuilderSpinAllocator.alloc();
134 try {
135 final boolean isWindowsRoot = path.endsWith(":/");
136 int i = 0;
137 while (i < text.length()) {
138 int occurrenceOfPath = caseSensitive ? text.indexOf(path, i) : StringUtil.indexOfIgnoreCase(text, path, i);
139 if (occurrenceOfPath >= 0) {
140 int endOfOccurence = occurrenceOfPath + path.length();
141 if (!isWindowsRoot &&
142 endOfOccurence < text.length() &&
143 text.charAt(endOfOccurence) != '/' &&
144 text.charAt(endOfOccurence) != '\"' &&
145 text.charAt(endOfOccurence) != ' ' &&
146 !text.substring(endOfOccurence).startsWith("!/")) {
147 newText.append(text.substring(i, endOfOccurence));
148 i = endOfOccurence;
149 continue;
152 if (occurrenceOfPath < 0) {
153 if (newText.length() == 0) {
154 return text;
156 newText.append(text.substring(i));
157 break;
159 else {
160 newText.append(text.substring(i, occurrenceOfPath));
161 newText.append(macro);
162 i = occurrenceOfPath + path.length();
165 return newText.toString();
167 finally {
168 StringBuilderSpinAllocator.dispose(newText);
172 public List<String> getPathIndex() {
173 if (myPathsIndex == null || myPathsIndex.size() != size()) {
175 final Set<Map.Entry<String, String>> entrySet = entries();
176 Map.Entry<String, String>[] entries = entrySet.toArray(new Map.Entry[entrySet.size()]);
177 Arrays.sort(entries, PATHS_COMPARATOR);
178 myPathsIndex = new ArrayList<String>(entries.length);
180 for (Map.Entry<String, String> entry : entries) {
181 myPathsIndex.add(entry.getKey());
184 return myPathsIndex;
187 public boolean equals(Object obj) {
188 if (obj == this) return true;
189 if (!(obj instanceof ReplacePathToMacroMap)) return false;
191 return myMacroMap.equals(((ReplacePathToMacroMap)obj).myMacroMap);
194 public int hashCode() {
195 return myMacroMap.hashCode();