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.
17 package com
.intellij
.codeInsight
.completion
;
19 import com
.intellij
.codeInsight
.CodeInsightSettings
;
20 import com
.intellij
.codeInsight
.TailType
;
21 import com
.intellij
.codeInsight
.lookup
.Lookup
;
22 import com
.intellij
.codeInsight
.lookup
.LookupElement
;
23 import com
.intellij
.codeInsight
.lookup
.LookupItem
;
24 import com
.intellij
.featureStatistics
.FeatureUsageTracker
;
25 import com
.intellij
.openapi
.extensions
.Extensions
;
26 import com
.intellij
.openapi
.fileTypes
.FileType
;
27 import com
.intellij
.openapi
.util
.Key
;
28 import com
.intellij
.openapi
.util
.NotNullLazyValue
;
29 import com
.intellij
.openapi
.editor
.Document
;
30 import com
.intellij
.openapi
.editor
.Editor
;
31 import com
.intellij
.patterns
.ElementPattern
;
32 import static com
.intellij
.patterns
.PlatformPatterns
.character
;
33 import com
.intellij
.psi
.PsiElement
;
34 import com
.intellij
.psi
.PsiFile
;
35 import com
.intellij
.psi
.PsiDocumentManager
;
36 import com
.intellij
.psi
.filters
.TrueFilter
;
37 import com
.intellij
.util
.containers
.HashMap
;
38 import org
.jetbrains
.annotations
.NonNls
;
39 import org
.jetbrains
.annotations
.NotNull
;
40 import org
.jetbrains
.annotations
.Nullable
;
42 public class CompletionUtil
{
43 public static final Key
<TailType
> TAIL_TYPE_ATTR
= LookupItem
.TAIL_TYPE_ATTR
;
45 private static final CompletionData ourGenericCompletionData
= new CompletionData() {
47 final CompletionVariant variant
= new CompletionVariant(PsiElement
.class, TrueFilter
.INSTANCE
);
48 variant
.addCompletionFilter(TrueFilter
.INSTANCE
, TailType
.NONE
);
49 registerVariant(variant
);
52 private static final HashMap
<FileType
, NotNullLazyValue
<CompletionData
>> ourCustomCompletionDatas
= new HashMap
<FileType
, NotNullLazyValue
<CompletionData
>>();
54 public static final @NonNls String DUMMY_IDENTIFIER
= CompletionInitializationContext
.DUMMY_IDENTIFIER
;
55 public static final @NonNls String DUMMY_IDENTIFIER_TRIMMED
= DUMMY_IDENTIFIER
.trim();
57 public static boolean startsWith(String text
, String prefix
) {
58 //if (text.length() <= prefix.length()) return false;
59 return toLowerCase(text
).startsWith(toLowerCase(prefix
));
62 private static String
toLowerCase(String text
) {
63 CodeInsightSettings settings
= CodeInsightSettings
.getInstance();
64 switch (settings
.COMPLETION_CASE_SENSITIVE
) {
65 case CodeInsightSettings
.NONE
:
66 return text
.toLowerCase();
68 case CodeInsightSettings
.FIRST_LETTER
: {
69 StringBuffer buffer
= new StringBuffer();
70 buffer
.append(text
.toLowerCase());
71 if (buffer
.length() > 0) {
72 buffer
.setCharAt(0, text
.charAt(0));
74 return buffer
.toString();
82 public static CompletionData
getCompletionDataByElement(final PsiFile file
) {
84 final CompletionData mainData
= getCompletionDataByFileType(file
.getFileType());
85 return mainData
!= null ? mainData
: ourGenericCompletionData
;
88 public static void registerCompletionData(FileType fileType
, NotNullLazyValue
<CompletionData
> completionData
) {
89 ourCustomCompletionDatas
.put(fileType
, completionData
);
92 public static void registerCompletionData(FileType fileType
, final CompletionData completionData
) {
93 registerCompletionData(fileType
, new NotNullLazyValue
<CompletionData
>() {
95 protected CompletionData
compute() {
96 return completionData
;
102 public static CompletionData
getCompletionDataByFileType(FileType fileType
) {
103 for(CompletionDataEP ep
: Extensions
.getExtensions(CompletionDataEP
.EP_NAME
)) {
104 if (ep
.fileType
.equals(fileType
.getName())) {
105 return ep
.getHandler();
108 final NotNullLazyValue
<CompletionData
> lazyValue
= ourCustomCompletionDatas
.get(fileType
);
109 return lazyValue
== null ?
null : lazyValue
.getValue();
113 static boolean isOverwrite(final LookupElement item
, final char completionChar
) {
114 return completionChar
!= Lookup
.AUTO_INSERT_SELECT_CHAR
115 ? completionChar
== Lookup
.REPLACE_SELECT_CHAR
116 : item
.getUserData(LookupItem
.OVERWRITE_ON_AUTOCOMPLETE_ATTR
) != null;
120 public static boolean shouldShowFeature(final CompletionParameters parameters
, @NonNls final String id
) {
121 return FeatureUsageTracker
.getInstance().isToBeShown(id
, parameters
.getPosition().getProject());
124 public static String
findJavaIdentifierPrefix(final PsiElement insertedElement
, final int offset
) {
125 return findIdentifierPrefix(insertedElement
, offset
, character().javaIdentifierPart(), character().javaIdentifierStart());
128 public static String
findIdentifierPrefix(PsiElement insertedElement
, int offset
, ElementPattern
<Character
> idPart
,
129 ElementPattern
<Character
> idStart
) {
130 if(insertedElement
== null) return "";
131 final String text
= insertedElement
.getText();
132 final int offsetInElement
= offset
- insertedElement
.getTextRange().getStartOffset();
133 int start
= offsetInElement
- 1;
135 if (!idPart
.accepts(text
.charAt(start
))) break;
138 while (start
+ 1 < offsetInElement
&& !idStart
.accepts(text
.charAt(start
+ 1))) {
142 return text
.substring(start
+ 1, offsetInElement
).trim();
145 static InsertionContext
emulateInsertion(InsertionContext oldContext
, int newStart
, final LookupElement item
) {
146 final InsertionContext newContext
= newContext(oldContext
, item
);
147 emulateInsertion(item
, newStart
, newContext
);
151 private static InsertionContext
newContext(InsertionContext oldContext
, LookupElement forElement
) {
152 final Editor editor
= oldContext
.getEditor();
153 return new InsertionContext(new OffsetMap(editor
.getDocument()), Lookup
.AUTO_INSERT_SELECT_CHAR
, new LookupElement
[]{forElement
}, oldContext
.getFile(), editor
);
156 public static InsertionContext
newContext(InsertionContext oldContext
, LookupElement forElement
, int startOffset
, int tailOffset
) {
157 final InsertionContext context
= newContext(oldContext
, forElement
);
158 setOffsets(context
, startOffset
, tailOffset
);
162 public static void emulateInsertion(LookupElement item
, int offset
, InsertionContext context
) {
163 setOffsets(context
, offset
, offset
);
165 final Editor editor
= context
.getEditor();
166 final Document document
= editor
.getDocument();
167 final String lookupString
= item
.getLookupString();
169 document
.insertString(offset
, lookupString
);
170 editor
.getCaretModel().moveToOffset(context
.getTailOffset());
171 PsiDocumentManager
.getInstance(context
.getProject()).commitDocument(document
);
172 item
.handleInsert(context
);
175 private static void setOffsets(InsertionContext context
, int offset
, final int tailOffset
) {
176 final OffsetMap offsetMap
= context
.getOffsetMap();
177 offsetMap
.addOffset(CompletionInitializationContext
.START_OFFSET
, offset
);
178 offsetMap
.addOffset(CompletionInitializationContext
.IDENTIFIER_END_OFFSET
, tailOffset
);
179 offsetMap
.addOffset(CompletionInitializationContext
.SELECTION_END_OFFSET
, tailOffset
);
180 context
.setTailOffset(tailOffset
);