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
;
26 * @author Eugene Zhuravlev
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;
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
+ "$";
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
);
73 private static String
replacePathMacro(String text
,
76 boolean caseSensitive
) {
77 if (text
.length() < path
.length() || path
.length() == 0) {
84 startsWith
= text
.startsWith(path
);
87 startsWith
= StringUtil
.startsWithIgnoreCase(text
, path
);
90 if (!startsWith
) return text
;
92 final StringBuilder newText
= StringBuilderSpinAllocator
.alloc();
94 //check that this is complete path (ends with "/" or "!/")
95 int endOfOccurence
= path
.length();
96 final boolean isWindowsRoot
= path
.endsWith(":/");
98 endOfOccurence
< text
.length() &&
99 text
.charAt(endOfOccurence
) != '/' &&
100 !text
.substring(endOfOccurence
).startsWith("!/")) {
104 newText
.append(macro
);
105 newText
.append(text
.substring(endOfOccurence
));
107 return newText
.toString();
110 StringBuilderSpinAllocator
.dispose(newText
);
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
);
123 private static String
replacePathMacroRecursively(String text
,
126 boolean caseSensitive
) {
127 if (text
.length() < path
.length()) {
131 if (path
.length() == 0) return text
;
133 final StringBuilder newText
= StringBuilderSpinAllocator
.alloc();
135 final boolean isWindowsRoot
= path
.endsWith(":/");
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
));
152 if (occurrenceOfPath
< 0) {
153 if (newText
.length() == 0) {
156 newText
.append(text
.substring(i
));
160 newText
.append(text
.substring(i
, occurrenceOfPath
));
161 newText
.append(macro
);
162 i
= occurrenceOfPath
+ path
.length();
165 return newText
.toString();
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());
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();