• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Camelcade / Perl5-IDEA / #525521553

27 May 2025 10:24AM UTC coverage: 82.286% (-0.03%) from 82.32%
#525521553

push

github

hurricup
Removed redundant implementations, moved up to the abstract class

1 of 1 new or added line in 1 file covered. (100.0%)

128 existing lines in 30 files now uncovered.

30886 of 37535 relevant lines covered (82.29%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.02
/plugin/core/src/main/java/com/perl5/lang/perl/idea/completion/util/PerlPackageCompletionUtil.java
1
/*
2
 * Copyright 2015-2025 Alexandr Evstigneev
3
 *
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
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
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.
15
 */
16

17
package com.perl5.lang.perl.idea.completion.util;
18

19
import com.intellij.codeInsight.AutoPopupController;
20
import com.intellij.codeInsight.completion.InsertHandler;
21
import com.intellij.codeInsight.lookup.Lookup;
22
import com.intellij.codeInsight.lookup.LookupElement;
23
import com.intellij.codeInsight.lookup.LookupElementBuilder;
24
import com.intellij.openapi.diagnostic.Logger;
25
import com.intellij.openapi.project.Project;
26
import com.intellij.openapi.util.text.StringUtil;
27
import com.intellij.openapi.vfs.VirtualFile;
28
import com.intellij.psi.PsiElement;
29
import com.intellij.psi.PsiFile;
30
import com.intellij.psi.search.GlobalSearchScope;
31
import com.intellij.util.ObjectUtils;
32
import com.intellij.util.Processor;
33
import com.perl5.PerlIcons;
34
import com.perl5.lang.perl.fileTypes.PerlFileTypePackage;
35
import com.perl5.lang.perl.idea.completion.providers.processors.PerlCompletionProcessor;
36
import com.perl5.lang.perl.idea.completion.providers.processors.PerlSimpleDelegatingCompletionProcessor;
37
import com.perl5.lang.perl.internals.PerlFeaturesTable;
38
import com.perl5.lang.perl.internals.PerlVersion;
39
import com.perl5.lang.perl.psi.PerlNamespaceDefinitionElement;
40
import com.perl5.lang.perl.psi.impl.PerlFileImpl;
41
import com.perl5.lang.perl.psi.references.PerlBuiltInNamespacesService;
42
import com.perl5.lang.perl.util.PerlPackageUtil;
43
import com.perl5.lang.perl.util.PerlTimeLogger;
44
import org.jetbrains.annotations.NotNull;
45
import org.jetbrains.annotations.Nullable;
46

47
import javax.swing.*;
48
import java.util.Collection;
49
import java.util.List;
50
import java.util.Map;
51

52
import static com.perl5.PerlIcons.PACKAGE_GUTTER_ICON;
53
import static com.perl5.lang.perl.util.PerlPackageUtil.__PACKAGE__;
54

55

56
public class PerlPackageCompletionUtil {
×
57
  private static final Logger LOG = Logger.getInstance(PerlPackageCompletionUtil.class);
1✔
58

59
  public static final InsertHandler<LookupElement> COMPLETION_REOPENER = (context, item) -> {
1✔
60
    if (context.getCompletionChar() != Lookup.AUTO_INSERT_SELECT_CHAR) {
1✔
61
      AutoPopupController.getInstance(context.getProject()).scheduleAutoPopup(context.getEditor());
1✔
62
    }
63
  };
1✔
64

65
  public static boolean processNamespaceLookupElement(@NotNull PerlNamespaceDefinitionElement namespaceDefinition,
66
                                                      @NotNull PerlCompletionProcessor completionProcessor,
67
                                                      boolean appendNamespaceSeparator) {
68
    String namespaceName = namespaceDefinition.getNamespaceName();
1✔
69
    if (StringUtil.isEmpty(namespaceName)) {
1✔
70
      return completionProcessor.result();
×
71
    }
72
    return processPackageLookupElement(
1✔
73
      namespaceDefinition, namespaceName, namespaceDefinition.getIcon(0), completionProcessor, appendNamespaceSeparator);
1✔
74
  }
75

76
  /**
77
   * @return true iff we should process
78
   */
79
  public static boolean processPackageLookupElement(@Nullable Object lookupObject,
80
                                                    @NotNull String packageName,
81
                                                    @Nullable Icon icon,
82
                                                    @NotNull PerlCompletionProcessor completionProcessor,
83
                                                    boolean appendNamespaceSeparator) {
84
    if (!completionProcessor.matches(packageName)) {
1✔
85
      return completionProcessor.result();
1✔
86
    }
87
    if (appendNamespaceSeparator) {
1✔
88
      packageName += PerlPackageUtil.NAMESPACE_SEPARATOR;
1✔
89
    }
90

91
    LookupElementBuilder result = LookupElementBuilder.create(ObjectUtils.notNull(lookupObject, packageName), packageName);
1✔
92

93
    if (PerlPackageUtil.isBuiltIn(packageName)) {
1✔
94
      result = result.withBoldness(true);
1✔
95
    }
96

97
    if (PerlPackageUtil.isPragma(packageName)) {
1✔
98
      result = result.withIcon(PerlIcons.PRAGMA_GUTTER_ICON);
1✔
99
    }
100
    else {
101
      result = result.withIcon(icon == null ? PACKAGE_GUTTER_ICON : icon);
1✔
102
    }
103

104
    if (appendNamespaceSeparator) {
1✔
105
      result = result.withInsertHandler(COMPLETION_REOPENER);
1✔
106
    }
107

108
    return completionProcessor.process(result);
1✔
109
  }
110

111
  /**
112
   * @return package lookup element with automatic re-opening auto-compeltion
113
   */
114
  @SuppressWarnings("UnusedReturnValue")
115
  public static boolean processPackageLookupElementWithAutocomplete(@Nullable PerlNamespaceDefinitionElement namespaceDefinitionElement,
116
                                                                    @NotNull String packageName,
117
                                                                    @Nullable Icon icon,
118
                                                                    @NotNull PerlCompletionProcessor completionProcessor) {
119
    return processPackageLookupElement(
1✔
120
      namespaceDefinitionElement, packageName, icon,
121
      new PerlSimpleDelegatingCompletionProcessor(completionProcessor) {
1✔
122
        @Override
123
        public void addElement(@NotNull LookupElementBuilder lookupElement) {
124
          super.addElement(lookupElement.withInsertHandler(COMPLETION_REOPENER).withTailText("..."));
1✔
125
        }
1✔
126
      }, false);
127
  }
128

129
  @SuppressWarnings("UnusedReturnValue")
130
  public static boolean processAllNamespacesNames(@NotNull PerlCompletionProcessor completionProcessor) {
131
    return processAllNamespacesNames(completionProcessor, false, true);
1✔
132
  }
133

134
  public static boolean processAllNamespacesNames(@NotNull PerlCompletionProcessor completionProcessor,
135
                                                  boolean appendNamespaceSeparator,
136
                                                  boolean addPackageTag) {
137
    PsiElement element = completionProcessor.getLeafElement();
1✔
138
    final Project project = element.getProject();
1✔
139

140
    Processor<PerlNamespaceDefinitionElement> namespaceProcessor =
1✔
141
      namespace -> processNamespaceLookupElement(namespace, completionProcessor, appendNamespaceSeparator);
1✔
142
    PerlBuiltInNamespacesService.getInstance(project).processNamespaces(namespaceProcessor);
1✔
143
    if (addPackageTag &&
1✔
144
        !PerlPackageCompletionUtil.processPackageLookupElement(null, __PACKAGE__, PACKAGE_GUTTER_ICON, completionProcessor, false)) {
1✔
UNCOV
145
      return false;
×
146
    }
147
    return processFirstNamespaceForEachName(completionProcessor, project, element.getResolveScope(), namespaceProcessor);
1✔
148
  }
149

150
  /**
151
   * Iterates all namespaces in {@code project} and {@code searchScope}, and processes the first element with each name with
152
   * {@code namespaceProcessor}
153
   */
154
  public static boolean processFirstNamespaceForEachName(@NotNull PerlCompletionProcessor completionProcessor,
155
                                                         @NotNull Project project,
156
                                                         @NotNull GlobalSearchScope searchScope,
157
                                                         @NotNull Processor<PerlNamespaceDefinitionElement> namespaceProcessor) {
158
    PerlTimeLogger logger = PerlTimeLogger.create(LOG);
1✔
159
    Collection<String> names = PerlPackageUtil.getKnownNamespaceNames(searchScope);
1✔
160
    logger.debug("Collected all namespaces names: ", names.size());
1✔
161
    for (String packageName : names) {
1✔
162
      if (!completionProcessor.matches(packageName)) {
1✔
163
        continue;
1✔
164
      }
165
      PerlPackageUtil.processNamespaces(packageName, project, searchScope, namespace -> {
1✔
166
        String name = namespace.getNamespaceName();
1✔
167
        if (StringUtil.isNotEmpty(name)) {
1✔
168
          char firstChar = name.charAt(0);
1✔
169
          if (firstChar == '_' || Character.isLetterOrDigit(firstChar)) {
1✔
170
            namespaceProcessor.process(namespace);
1✔
171
            completionProcessor.register(namespace.getNamespaceName());
1✔
172
            return false;
1✔
173
          }
174
        }
UNCOV
175
        return false;
×
176
      });
177
      if (!completionProcessor.result()) {
1✔
UNCOV
178
        LOG.debug("Processor is full");
×
UNCOV
179
        return false;
×
180
      }
181
    }
1✔
182
    logger.debug("Collected namespaces from indexes");
1✔
183

184
    return completionProcessor.result();
1✔
185
  }
186

187
  public static void fillWithAllPackageFiles(@NotNull PerlCompletionProcessor completionProcessor) {
188
    PerlPackageUtil.processPackageFilesForPsiElement(completionProcessor.getLeafElement(), (packageName, file) ->
1✔
189
      PerlPackageCompletionUtil.processPackageLookupElement(file, packageName, null, completionProcessor, false));
1✔
190
  }
1✔
191

192
  public static void fillWithVersionNumbers(@NotNull PerlCompletionProcessor completionProcessor) {
193
    for (Map.Entry<String, List<String>> entry : PerlFeaturesTable.AVAILABLE_FEATURES_BUNDLES.entrySet()) {
1✔
194
      String version = entry.getKey();
1✔
195
      if (StringUtil.startsWith(version, "5")) {
1✔
196
        String lookupString = "v" + version;
1✔
197
        if (completionProcessor.matches(lookupString)) {
1✔
198
          completionProcessor.process(
1✔
199
            LookupElementBuilder.create(new PerlVersion(lookupString), lookupString).withTypeText(StringUtil.join(entry.getValue(), " "))
1✔
200
          );
201
        }
202
      }
203
    }
1✔
204
  }
1✔
205

206
  public static void fillWithNamespaceNameSuggestions(@NotNull PerlCompletionProcessor completionProcessor) {
207
    PsiFile originalFile = completionProcessor.getOriginalFile();
1✔
208

209
    VirtualFile virtualFile = originalFile.getViewProvider().getVirtualFile();
1✔
210
    if (virtualFile.getFileType() != PerlFileTypePackage.INSTANCE) {
1✔
UNCOV
211
      return;
×
212
    }
213
    completionProcessor.processSingle(LookupElementBuilder.create(virtualFile, virtualFile.getNameWithoutExtension()));
1✔
214
    if (!(originalFile instanceof PerlFileImpl perlFile)) {
1✔
UNCOV
215
      return;
×
216
    }
217
    String packageName = perlFile.getFilePackageName();
1✔
218
    if (packageName != null) {
1✔
UNCOV
219
      completionProcessor.processSingle(LookupElementBuilder.create(originalFile, packageName));
×
220
    }
221
  }
1✔
222
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc