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

Camelcade / Perl5-IDEA / #525521587

22 Jun 2025 12:31PM UTC coverage: 82.36% (-0.02%) from 82.376%
#525521587

Pull #3015

github

web-flow
Merge 94f6ba619 into 160c56274
Pull Request #3015: Eap6 build with v2 module structure

30866 of 37477 relevant lines covered (82.36%)

0.82 hits per line

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

44.0
/plugin/debugger/src/main/java/com/perl5/lang/perl/debugger/ui/PerlScriptsPanel.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.debugger.ui;
18

19
import com.intellij.ide.actions.OpenFileAction;
20
import com.intellij.openapi.application.ApplicationManager;
21
import com.intellij.openapi.project.Project;
22
import com.intellij.openapi.util.text.StringUtil;
23
import com.intellij.openapi.vfs.VfsUtil;
24
import com.intellij.openapi.vfs.VirtualFile;
25
import com.intellij.openapi.vfs.VirtualFileManager;
26
import com.intellij.ui.SimpleListCellRenderer;
27
import com.intellij.ui.SortedListModel;
28
import com.intellij.ui.components.JBList;
29
import com.intellij.ui.components.JBScrollPane;
30
import com.perl5.lang.perl.debugger.PerlDebugThread;
31
import com.perl5.lang.perl.debugger.PerlRemoteFileSystem;
32
import com.perl5.lang.perl.debugger.protocol.PerlLoadedFileDescriptor;
33
import com.perl5.lang.perl.fileTypes.PerlFileTypeScript;
34
import org.jetbrains.annotations.NotNull;
35
import org.jetbrains.annotations.Nullable;
36

37
import javax.swing.*;
38
import java.awt.*;
39
import java.awt.event.MouseAdapter;
40
import java.awt.event.MouseEvent;
41
import java.io.File;
42
import java.util.Arrays;
43
import java.util.Collections;
44
import java.util.Comparator;
45
import java.util.List;
46

47

48
public class PerlScriptsPanel extends JPanel {
49
  private static final Comparator<PerlLoadedFileDescriptor> compareEntries =
1✔
50
    (o1, o2) -> StringUtil.compare(o1.getPresentableName(), o2.getPresentableName(), false);
1✔
51
  private final @NotNull Project myProject;
52
  private final PerlDebugThread myDebugThread;
53
  private final SortedListModel<PerlLoadedFileDescriptor> myModel = SortedListModel.create(compareEntries);
1✔
54

55
  public PerlScriptsPanel(@NotNull Project project, PerlDebugThread debugThread) {
56
    super(new BorderLayout());
1✔
57
    init();
1✔
58
    myProject = project;
1✔
59
    myDebugThread = debugThread;
1✔
60
  }
1✔
61

62

63
  private @Nullable VirtualFile getVirtualFileByName(String virtualFileName) {
64
    VirtualFile result = VfsUtil.findFileByIoFile(new File(virtualFileName), false);
×
65

66
    if (result != null) {
×
67
      return result;
×
68
    }
69

70
    return VirtualFileManager.getInstance().findFileByUrl(PerlRemoteFileSystem.PROTOCOL_PREFIX + virtualFileName);
×
71
  }
72

73
  private void init() {
74
    add(new JBScrollPane(createList()), BorderLayout.CENTER);
1✔
75
  }
1✔
76

77
  @SuppressWarnings("ExtractMethodRecommender")
78
  private @NotNull JBList<PerlLoadedFileDescriptor> createList() {
79
    final JBList<PerlLoadedFileDescriptor> jbList = new JBList<>(myModel);
1✔
80
    jbList.setCellRenderer(new SimpleListCellRenderer<>() {
1✔
81
      @Override
82
      public void customize(@NotNull JList list, PerlLoadedFileDescriptor fileDescriptor, int index, boolean selected, boolean hasFocus) {
83
        String remotePath = fileDescriptor.getPath();
×
84
        String localPath = myDebugThread.getDebugProfileState().mapPathToLocal(remotePath);
×
85
        VirtualFile virtualFile = getVirtualFileByName(localPath);
×
86

87
        setIcon(PerlFileTypeScript.INSTANCE.getIcon());
×
88
        setText(fileDescriptor.getPresentableName());
×
89

90
        if (virtualFile != null) {
×
91
          setText(fileDescriptor.getPresentableName());
×
92
          setIcon(virtualFile.getFileType().getIcon());
×
93
        }
94
      }
×
95
    });
96
    jbList.addMouseListener(new MouseAdapter() {
1✔
97
      @Override
98
      public void mouseClicked(MouseEvent e) {
99
        if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
×
100
          PerlLoadedFileDescriptor fileDescriptor = jbList.getSelectedValue();
×
101
          String remotePath = fileDescriptor.getPath();
×
102
          String localPath = myDebugThread.getDebugProfileState().mapPathToLocal(remotePath);
×
103
          VirtualFile selectedVirtualFile = getVirtualFileByName(localPath);
×
104
          if (selectedVirtualFile == null) {
×
105
            selectedVirtualFile = myDebugThread.loadRemoteSource(remotePath);
×
106
          }
107

108
          if (selectedVirtualFile != null) {
×
109
            OpenFileAction.openFile(selectedVirtualFile, myProject);
×
110
          }
111
        }
112
      }
×
113
    });
114
    return jbList;
1✔
115
  }
116

117
  public void clear() {
118
    myModel.clear();
1✔
119
  }
1✔
120

121
  public void add(final PerlLoadedFileDescriptor value) {
122
    ApplicationManager.getApplication().invokeLater(() -> {
1✔
123
      if (myModel.indexOf(value) == -1) {
1✔
124
        myModel.add(value);
1✔
125
      }
126
    });
1✔
127
  }
1✔
128

129
  public void remove(final PerlLoadedFileDescriptor value) {
130
    ApplicationManager.getApplication().invokeLater(() -> {
1✔
131
      if (myModel.indexOf(value) != -1) {
1✔
132
        myModel.remove(value);
×
133
      }
134
    });
1✔
135
  }
1✔
136

137
  public void bulkChange(final List<? extends PerlLoadedFileDescriptor> toAdd, final List<? extends PerlLoadedFileDescriptor> toRemove) {
138
    // based on synthetic benchmarks, at 5000 items the performance of bulkChangeNow is definitely
139
    // better than the naive method; the exact number might still need some tweaking
140
    if (toAdd.size() + toRemove.size() < 5000) {
1✔
141
      for (PerlLoadedFileDescriptor value : toRemove) {
1✔
142
        remove(value);
1✔
143
      }
1✔
144
      for (PerlLoadedFileDescriptor value : toAdd) {
1✔
145
        add(value);
1✔
146
      }
1✔
147
    }
148
    else {
149
      ApplicationManager.getApplication().invokeLater(() -> bulkChangeNow(toAdd, toRemove));
×
150
    }
151
  }
1✔
152

153
  // so the naive version is good for "small" added/removed; where the exact value needs to be determined with benchmarks;
154
  // there is a slightly more detailed analysis in the commit message
155
  private void bulkChangeNow(final List<? extends PerlLoadedFileDescriptor> toAdd,
156
                             final List<? extends PerlLoadedFileDescriptor> toRemove) {
157
    List<PerlLoadedFileDescriptor> currentEntries = myModel.getItems();
×
158
    if (!toRemove.isEmpty()) {
×
159
      // first find all indices to be removed, then remove them in reverse order by overwriting with
160
      // the last element and then removing the last element
161
      int removeSize = toRemove.size();
×
162
      int[] indices = new int[removeSize];
×
163
      for (int i = 0; i < removeSize; ++i) {
×
164
        indices[i] = Collections.binarySearch(currentEntries, toRemove.get(i), compareEntries);
×
165
      }
166
      Arrays.sort(indices);
×
167
      int lastIndex = currentEntries.size() - 1;
×
168
      for (int i = removeSize - 1; i >= 0; --i) {
×
169
        int index = indices[i];
×
170
        if (index >= 0) {
×
171
          currentEntries.set(index, currentEntries.get(lastIndex));
×
172
          currentEntries.remove(lastIndex);
×
173
          --lastIndex;
×
174
        }
175
      }
176
    }
177
    currentEntries.addAll(toAdd);
×
178
    myModel.setAll(currentEntries);
×
179
  }
×
180
}
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