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

Camelcade / Perl5-IDEA / #525521543

22 May 2025 09:13AM UTC coverage: 82.34% (+0.1%) from 82.228%
#525521543

push

github

hurricup
Improved localization handling

Still imperfect, but good enough

0 of 2 new or added lines in 1 file covered. (0.0%)

113 existing lines in 7 files now uncovered.

30912 of 37542 relevant lines covered (82.34%)

0.82 hits per line

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

95.51
/plugin/core/src/main/java/com/perl5/lang/perl/idea/project/PerlNamesCache.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.project;
18

19
import com.intellij.ide.lightEdit.LightEdit;
20
import com.intellij.openapi.Disposable;
21
import com.intellij.openapi.application.ApplicationManager;
22
import com.intellij.openapi.application.ReadAction;
23
import com.intellij.openapi.diagnostic.Logger;
24
import com.intellij.openapi.progress.ProgressManager;
25
import com.intellij.openapi.project.DumbService;
26
import com.intellij.openapi.project.Project;
27
import com.intellij.openapi.roots.ModuleRootEvent;
28
import com.intellij.openapi.roots.ModuleRootListener;
29
import com.intellij.psi.PsiManager;
30
import com.intellij.psi.PsiTreeChangeAdapter;
31
import com.intellij.psi.PsiTreeChangeEvent;
32
import com.intellij.util.messages.MessageBusConnection;
33
import com.intellij.util.ui.update.MergingUpdateQueue;
34
import com.intellij.util.ui.update.Update;
35
import com.perl5.lang.perl.psi.stubs.namespaces.PerlLightNamespaceIndex;
36
import com.perl5.lang.perl.psi.stubs.namespaces.PerlNamespaceIndex;
37
import com.perl5.lang.perl.psi.stubs.subsdeclarations.PerlSubDeclarationIndex;
38
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlLightSubDefinitionsIndex;
39
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlSubDefinitionsIndex;
40
import com.perl5.lang.perl.util.PerlPackageUtil;
41
import com.perl5.lang.perl.util.PerlTimeLogger;
42
import org.jetbrains.annotations.NotNull;
43
import org.jetbrains.annotations.TestOnly;
44

45
import java.util.Collection;
46
import java.util.Collections;
47
import java.util.HashSet;
48
import java.util.Set;
49
import java.util.concurrent.atomic.AtomicBoolean;
50

51

52
public class PerlNamesCache implements Disposable {
53
  private static final Logger LOG = Logger.getInstance(PerlNamesCache.class);
1✔
54
  private final MergingUpdateQueue myQueue = new MergingUpdateQueue("Perl names cache updater", 1000, true, null, this, null, false);
1✔
55
  private final Project myProject;
56
  private final AtomicBoolean myIsUpdating = new AtomicBoolean(false);
1✔
57
  private volatile Set<String> myKnownSubs = Collections.emptySet();
1✔
58
  private volatile Set<String> myKnownNamespaces = Collections.emptySet();
1✔
59

60
  public PerlNamesCache(Project project) {
1✔
61
    myProject = project;
1✔
62
    if (LightEdit.owns(myProject) || project.isDefault()) {
1✔
UNCOV
63
      return;
×
64
    }
65
    MessageBusConnection connection = project.getMessageBus().connect(this);
1✔
66
    connection.subscribe(ModuleRootListener.TOPIC, new ModuleRootListener() {
1✔
67
      @Override
68
      public void rootsChanged(@NotNull ModuleRootEvent event) {
69
        queueUpdate();
1✔
70
      }
1✔
71
    });
72
    connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
1✔
73
      @Override
74
      public void exitDumbMode() {
75
        queueUpdate();
1✔
76
      }
1✔
77
    });
78
    PsiManager.getInstance(myProject).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
1✔
79
      @Override
80
      public void childAdded(@NotNull PsiTreeChangeEvent event) {
81
        queueUpdate();
1✔
82
      }
1✔
83

84
      @Override
85
      public void childRemoved(@NotNull PsiTreeChangeEvent event) {
86
        queueUpdate();
1✔
87
      }
1✔
88

89
      @Override
90
      public void childReplaced(@NotNull PsiTreeChangeEvent event) {
91
        queueUpdate();
1✔
92
      }
1✔
93

94
      @Override
95
      public void childMoved(@NotNull PsiTreeChangeEvent event) {
UNCOV
96
        queueUpdate();
×
97
      }
×
98

99
      @Override
100
      public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
101
        queueUpdate();
1✔
102
      }
1✔
103

104
      @Override
105
      public void propertyChanged(@NotNull PsiTreeChangeEvent event) {
106
        queueUpdate();
1✔
107
      }
1✔
108
    }, this);
109
  }
1✔
110

111
  private void queueUpdate() {
112
    if (!myProject.isDefault()) {
1✔
113
      myQueue.queue(Update.create(this, this::doUpdateSingleThread));
1✔
114
    }
115
  }
1✔
116

117
  private void doUpdateSingleThread() {
118
    if (!DumbService.isDumb(myProject) && myIsUpdating.compareAndSet(false, true)) {
1✔
119
      try {
120
        doUpdateCache();
1✔
121
      }
122
      finally {
123
        myIsUpdating.set(false);
1✔
124
      }
1✔
125
    }
126
    else {
127
      queueUpdate();
1✔
128
    }
129
  }
1✔
130

131
  private void doUpdateCache() {
132
    if (LightEdit.owns(myProject)) {
1✔
UNCOV
133
      return;
×
134
    }
135
    ReadAction.nonBlocking(() -> {
1✔
136
      PerlTimeLogger logger = PerlTimeLogger.create(LOG);
1✔
137
      logger.debug("Starting to update names cache at");
1✔
138

139
      PerlSubDeclarationIndex subDeclarationIndex = PerlSubDeclarationIndex.getInstance();
1✔
140
      Collection<String> declarationsNames = subDeclarationIndex.getAllNames(myProject);
1✔
141
      Set<String> subsSet = new HashSet<>(declarationsNames);
1✔
142
      logger.debug("Got declarations names: ", declarationsNames.size());
1✔
143
      ProgressManager.checkCanceled();
1✔
144

145
      PerlSubDefinitionsIndex subDefinitionsIndex = PerlSubDefinitionsIndex.getInstance();
1✔
146
      Collection<String> definitionsNames = subDefinitionsIndex.getAllNames(myProject);
1✔
147
      subsSet.addAll(definitionsNames);
1✔
148
      logger.debug("Got definitions names: ", definitionsNames.size());
1✔
149
      ProgressManager.checkCanceled();
1✔
150

151
      PerlLightSubDefinitionsIndex lightSubDefinitionsIndex = PerlLightSubDefinitionsIndex.getInstance();
1✔
152
      Collection<String> lightDefinitionsNames = lightSubDefinitionsIndex.getAllNames(myProject);
1✔
153
      subsSet.addAll(lightDefinitionsNames);
1✔
154
      logger.debug("Got light definitions names: ", lightDefinitionsNames.size());
1✔
155
      ProgressManager.checkCanceled();
1✔
156
      myKnownSubs = Collections.unmodifiableSet(subsSet);
1✔
157

158
      Set<String> namespacesSet = new HashSet<>(PerlPackageUtil.CORE_PACKAGES_ALL);
1✔
159

160
      PerlNamespaceIndex namespaceIndex = PerlNamespaceIndex.getInstance();
1✔
161
      Collection<String> namespacesNames = namespaceIndex.getAllNames(myProject);
1✔
162
      namespacesSet.addAll(namespacesNames);
1✔
163
      logger.debug("Got namespaces names: ", namespacesNames.size());
1✔
164
      ProgressManager.checkCanceled();
1✔
165

166
      PerlLightNamespaceIndex lightNamespaceIndex = PerlLightNamespaceIndex.getInstance();
1✔
167
      Collection<String> lightNamespacesNames = lightNamespaceIndex.getAllNames(myProject);
1✔
168
      namespacesSet.addAll(lightNamespacesNames);
1✔
169
      logger.debug("Got light namespaces names: ", lightNamespacesNames.size());
1✔
170
      myKnownNamespaces = Collections.unmodifiableSet(namespacesSet);
1✔
171

172
      logger.debug("Names cache updated");
1✔
173
      return null;
1✔
174
    }).inSmartMode(myProject).expireWhen(myProject::isDisposed).executeSynchronously();
1✔
175
  }
1✔
176

177
  public void forceCacheUpdate() {
178
    var application = ApplicationManager.getApplication();
1✔
179
    application.assertIsNonDispatchThread();
1✔
180
    doUpdateCache();
1✔
181
  }
1✔
182

183
  @TestOnly
184
  public void cleanCache() {
185
    myKnownSubs = Collections.emptySet();
1✔
186
    myKnownNamespaces = Collections.emptySet();
1✔
187
  }
1✔
188

189
  @Override
190
  public void dispose() {
191
  }
1✔
192

193
  public Set<String> getSubsNamesSet() {
194
    return myKnownSubs;
1✔
195
  }
196

197
  public Set<String> getNamespacesNamesSet() {
198
    return myKnownNamespaces;
1✔
199
  }
200

201
  public static @NotNull PerlNamesCache getInstance(@NotNull Project project) {
202
    return project.getService(PerlNamesCache.class);
1✔
203
  }
204

205
  @TestOnly
206
  public void stopQueue() {
207
    myQueue.dispose();
1✔
208
  }
1✔
209

210
  @TestOnly
211
  public boolean isUpdating() { return myIsUpdating.get(); }
1✔
212
}
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