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

devonfw / IDEasy / 12181235589

05 Dec 2024 01:58PM UTC coverage: 66.902% (-0.02%) from 66.917%
12181235589

push

github

web-flow
#508: enabled autocompletion for commandlet options (#833)

2527 of 4130 branches covered (61.19%)

Branch coverage included in aggregate %.

6577 of 9478 relevant lines covered (69.39%)

3.06 hits per line

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

87.12
cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java
1
package com.devonfw.tools.ide.commandlet;
2

3
import java.util.Collection;
4
import java.util.Collections;
5
import java.util.HashMap;
6
import java.util.Iterator;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.NoSuchElementException;
10

11
import com.devonfw.tools.ide.cli.CliArgument;
12
import com.devonfw.tools.ide.cli.CliArguments;
13
import com.devonfw.tools.ide.completion.CompletionCandidateCollector;
14
import com.devonfw.tools.ide.context.IdeContext;
15
import com.devonfw.tools.ide.property.KeywordProperty;
16
import com.devonfw.tools.ide.property.Property;
17
import com.devonfw.tools.ide.tool.androidstudio.AndroidStudio;
18
import com.devonfw.tools.ide.tool.aws.Aws;
19
import com.devonfw.tools.ide.tool.az.Azure;
20
import com.devonfw.tools.ide.tool.docker.Docker;
21
import com.devonfw.tools.ide.tool.dotnet.DotNet;
22
import com.devonfw.tools.ide.tool.eclipse.Eclipse;
23
import com.devonfw.tools.ide.tool.gcviewer.GcViewer;
24
import com.devonfw.tools.ide.tool.gh.Gh;
25
import com.devonfw.tools.ide.tool.graalvm.GraalVm;
26
import com.devonfw.tools.ide.tool.gradle.Gradle;
27
import com.devonfw.tools.ide.tool.helm.Helm;
28
import com.devonfw.tools.ide.tool.intellij.Intellij;
29
import com.devonfw.tools.ide.tool.jasypt.Jasypt;
30
import com.devonfw.tools.ide.tool.java.Java;
31
import com.devonfw.tools.ide.tool.jmc.Jmc;
32
import com.devonfw.tools.ide.tool.kotlinc.Kotlinc;
33
import com.devonfw.tools.ide.tool.kotlinc.KotlincNative;
34
import com.devonfw.tools.ide.tool.kubectl.KubeCtl;
35
import com.devonfw.tools.ide.tool.lazydocker.LazyDocker;
36
import com.devonfw.tools.ide.tool.mvn.Mvn;
37
import com.devonfw.tools.ide.tool.node.Node;
38
import com.devonfw.tools.ide.tool.npm.Npm;
39
import com.devonfw.tools.ide.tool.oc.Oc;
40
import com.devonfw.tools.ide.tool.pgadmin.PgAdmin;
41
import com.devonfw.tools.ide.tool.quarkus.Quarkus;
42
import com.devonfw.tools.ide.tool.sonar.Sonar;
43
import com.devonfw.tools.ide.tool.terraform.Terraform;
44
import com.devonfw.tools.ide.tool.tomcat.Tomcat;
45
import com.devonfw.tools.ide.tool.vscode.Vscode;
46

47
/**
48
 * Implementation of {@link CommandletManager}.
49
 */
50
public class CommandletManagerImpl implements CommandletManager {
51

52
  private final IdeContext context;
53

54
  private final Map<Class<? extends Commandlet>, Commandlet> commandletTypeMap;
55

56
  private final Map<String, Commandlet> commandletNameMap;
57

58
  private final Map<String, Commandlet> firstKeywordMap;
59

60
  private final Collection<Commandlet> commandlets;
61

62
  /**
63
   * The constructor.
64
   *
65
   * @param context the {@link IdeContext}.
66
   */
67
  public CommandletManagerImpl(IdeContext context) {
68

69
    super();
2✔
70
    this.context = context;
3✔
71
    this.commandletTypeMap = new HashMap<>();
5✔
72
    this.commandletNameMap = new HashMap<>();
5✔
73
    this.firstKeywordMap = new HashMap<>();
5✔
74
    this.commandlets = Collections.unmodifiableCollection(this.commandletTypeMap.values());
6✔
75
    add(new HelpCommandlet(context));
6✔
76
    add(new EnvironmentCommandlet(context));
6✔
77
    add(new CompleteCommandlet(context));
6✔
78
    add(new ShellCommandlet(context));
6✔
79
    add(new InstallCommandlet(context));
6✔
80
    add(new VersionSetCommandlet(context));
6✔
81
    add(new VersionGetCommandlet(context));
6✔
82
    add(new VersionListCommandlet(context));
6✔
83
    add(new EditionGetCommandlet(context));
6✔
84
    add(new EditionSetCommandlet(context));
6✔
85
    add(new EditionListCommandlet(context));
6✔
86
    add(new VersionCommandlet(context));
6✔
87
    add(new StatusCommandlet(context));
6✔
88
    add(new RepositoryCommandlet(context));
6✔
89
    add(new UninstallCommandlet(context));
6✔
90
    add(new UpdateCommandlet(context));
6✔
91
    add(new CreateCommandlet(context));
6✔
92
    add(new BuildCommandlet(context));
6✔
93
    add(new InstallPluginCommandlet(context));
6✔
94
    add(new UninstallPluginCommandlet(context));
6✔
95
    add(new Gh(context));
6✔
96
    add(new Helm(context));
6✔
97
    add(new Java(context));
6✔
98
    add(new Node(context));
6✔
99
    add(new Npm(context));
6✔
100
    add(new Mvn(context));
6✔
101
    add(new GcViewer(context));
6✔
102
    add(new Gradle(context));
6✔
103
    add(new Eclipse(context));
6✔
104
    add(new Terraform(context));
6✔
105
    add(new Oc(context));
6✔
106
    add(new Quarkus(context));
6✔
107
    add(new Kotlinc(context));
6✔
108
    add(new KotlincNative(context));
6✔
109
    add(new KubeCtl(context));
6✔
110
    add(new Tomcat(context));
6✔
111
    add(new Vscode(context));
6✔
112
    add(new Azure(context));
6✔
113
    add(new Aws(context));
6✔
114
    add(new Jmc(context));
6✔
115
    add(new DotNet(context));
6✔
116
    add(new Intellij(context));
6✔
117
    add(new Jasypt(context));
6✔
118
    add(new Docker(context));
6✔
119
    add(new Sonar(context));
6✔
120
    add(new AndroidStudio(context));
6✔
121
    add(new GraalVm(context));
6✔
122
    add(new PgAdmin(context));
6✔
123
    add(new LazyDocker(context));
6✔
124
  }
1✔
125

126
  /**
127
   * @param commandlet the {@link Commandlet} to add.
128
   */
129
  protected void add(Commandlet commandlet) {
130

131
    boolean hasRequiredProperty = false;
2✔
132
    List<Property<?>> properties = commandlet.getProperties();
3✔
133
    int propertyCount = properties.size();
3✔
134
    String keyword = commandlet.getKeyword();
3✔
135
    if (keyword != null) {
2!
136
      this.firstKeywordMap.putIfAbsent(keyword, commandlet);
6✔
137
    }
138
    for (int i = 0; i < propertyCount; i++) {
5!
139
      Property<?> property = properties.get(i);
5✔
140
      if (property.isRequired()) {
3!
141
        hasRequiredProperty = true;
2✔
142
        break;
1✔
143
      }
144
    }
145
    if (!hasRequiredProperty) {
2!
146
      throw new IllegalStateException("Commandlet " + commandlet + " must have at least one mandatory property!");
×
147
    }
148
    this.commandletTypeMap.put(commandlet.getClass(), commandlet);
7✔
149
    Commandlet duplicate = this.commandletNameMap.put(commandlet.getName(), commandlet);
8✔
150
    if (duplicate != null) {
2!
151
      throw new IllegalStateException("Commandlet " + commandlet + " has the same name as " + duplicate);
×
152
    }
153
  }
1✔
154

155
  @Override
156
  public Collection<Commandlet> getCommandlets() {
157

158
    return this.commandlets;
3✔
159
  }
160

161
  @Override
162
  public <C extends Commandlet> C getCommandlet(Class<C> commandletType) {
163

164
    Commandlet commandlet = this.commandletTypeMap.get(commandletType);
6✔
165
    if (commandlet == null) {
2!
166
      throw new IllegalStateException("Commandlet for type " + commandletType + " is not registered!");
×
167
    }
168
    return commandletType.cast(commandlet);
5✔
169
  }
170

171
  @Override
172
  public Commandlet getCommandlet(String name) {
173

174
    return this.commandletNameMap.get(name);
6✔
175
  }
176

177
  @Override
178
  public Commandlet getCommandletByFirstKeyword(String keyword) {
179

180
    return this.firstKeywordMap.get(keyword);
6✔
181
  }
182

183
  @Override
184
  public Iterator<Commandlet> findCommandlet(CliArguments arguments, CompletionCandidateCollector collector) {
185

186
    CliArgument current = arguments.current();
3✔
187
    if (current.isEnd()) {
3!
188
      return Collections.emptyIterator();
×
189
    }
190
    String keyword = current.get();
3✔
191
    Commandlet commandlet = getCommandletByFirstKeyword(keyword);
4✔
192
    if ((commandlet == null) && (collector == null)) {
4!
193
      return Collections.emptyIterator();
×
194
    }
195
    return new CommandletFinder(commandlet, arguments.copy(), collector);
9✔
196
  }
197

198
  private final class CommandletFinder implements Iterator<Commandlet> {
1✔
199

200
    private final Commandlet firstCandidate;
201

202
    private final Iterator<Commandlet> commandletIterator;
203

204
    private final CliArguments arguments;
205

206
    private final CompletionCandidateCollector collector;
207

208
    private Commandlet next;
209

210
    private CommandletFinder(Commandlet firstCandidate, CliArguments arguments, CompletionCandidateCollector collector) {
5✔
211

212
      this.firstCandidate = firstCandidate;
3✔
213
      this.commandletIterator = getCommandlets().iterator();
5✔
214
      this.arguments = arguments;
3✔
215
      this.collector = collector;
3✔
216
      if (isSuitable(firstCandidate)) {
4✔
217
        this.next = firstCandidate;
4✔
218
      } else {
219
        this.next = findNext();
4✔
220
      }
221
    }
1✔
222

223
    @Override
224
    public boolean hasNext() {
225

226
      return this.next != null;
7✔
227
    }
228

229
    @Override
230
    public Commandlet next() {
231

232
      if (this.next == null) {
3!
233
        throw new NoSuchElementException();
×
234
      }
235
      Commandlet result = this.next;
3✔
236
      this.next = findNext();
4✔
237
      return result;
2✔
238
    }
239

240
    private boolean isSuitable(Commandlet commandlet) {
241

242
      return (commandlet != null) && (!commandlet.isIdeHomeRequired() || (context.getIdeHome() != null));
14!
243
    }
244

245
    private Commandlet findNext() {
246
      while (this.commandletIterator.hasNext()) {
4✔
247
        Commandlet cmd = this.commandletIterator.next();
5✔
248
        if ((cmd != this.firstCandidate) && isSuitable(cmd)) {
8!
249
          List<Property<?>> properties = cmd.getProperties();
3✔
250
          // validation should already be done in add method and could be removed here...
251
          if (properties.isEmpty()) {
3!
252
            assert false : cmd.getClass().getSimpleName() + " has no properties!";
×
253
          } else {
254
            Property<?> property = properties.get(0);
5✔
255
            if (property instanceof KeywordProperty) {
3!
256
              boolean matches = property.apply(arguments.copy(), context, cmd, this.collector);
12✔
257
              if (matches) {
2✔
258
                return cmd;
2✔
259
              }
260
            } else {
1✔
261
              assert false : cmd.getClass().getSimpleName() + " is invalid as first property must be keyword property but is " + property;
×
262
            }
263
          }
264
        }
265
      }
1✔
266
      return null;
2✔
267
    }
268
  }
269
}
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