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

devonfw / IDEasy / 11663000464

04 Nov 2024 11:07AM UTC coverage: 66.948%. Remained the same
11663000464

Pull #738

github

web-flow
Merge d78dfd285 into 15910e5eb
Pull Request #738: #168: Removed BuiltIns TODO entry

2421 of 3958 branches covered (61.17%)

Branch coverage included in aggregate %.

6311 of 9085 relevant lines covered (69.47%)

3.06 hits per line

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

3.7
cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java
1
package com.devonfw.tools.ide.commandlet;
2

3
import java.io.IOException;
4
import java.util.Iterator;
5

6
import org.fusesource.jansi.AnsiConsole;
7
import org.jline.reader.Completer;
8
import org.jline.reader.EndOfFileException;
9
import org.jline.reader.LineReader;
10
import org.jline.reader.LineReaderBuilder;
11
import org.jline.reader.MaskingCallback;
12
import org.jline.reader.Parser;
13
import org.jline.reader.UserInterruptException;
14
import org.jline.reader.impl.DefaultParser;
15
import org.jline.reader.impl.completer.AggregateCompleter;
16
import org.jline.reader.impl.completer.StringsCompleter;
17
import org.jline.terminal.Terminal;
18
import org.jline.terminal.TerminalBuilder;
19
import org.jline.widget.AutosuggestionWidgets;
20

21
import com.devonfw.tools.ide.cli.CliArgument;
22
import com.devonfw.tools.ide.cli.CliArguments;
23
import com.devonfw.tools.ide.completion.IdeCompleter;
24
import com.devonfw.tools.ide.context.AbstractIdeContext;
25
import com.devonfw.tools.ide.context.IdeContext;
26
import com.devonfw.tools.ide.property.BooleanProperty;
27
import com.devonfw.tools.ide.property.KeywordProperty;
28
import com.devonfw.tools.ide.property.Property;
29

30
/**
31
 * {@link Commandlet} for internal interactive shell with build-in auto-completion and help.
32
 */
33
public final class ShellCommandlet extends Commandlet {
34

35
  private static final int AUTOCOMPLETER_MAX_RESULTS = 50;
36

37
  private static final int RC_EXIT = 987654321;
38

39
  /**
40
   * The constructor.
41
   *
42
   * @param context the {@link IdeContext}.
43
   */
44
  public ShellCommandlet(IdeContext context) {
45

46
    super(context);
3✔
47
    addKeyword(getName());
4✔
48
  }
1✔
49

50
  @Override
51
  public String getName() {
52

53
    return "shell";
2✔
54
  }
55

56
  @Override
57
  public boolean isIdeHomeRequired() {
58

59
    return false;
2✔
60
  }
61

62
  @Override
63
  public void run() {
64

65
    try {
66
      Parser parser = new DefaultParser();
×
67
      try (Terminal terminal = TerminalBuilder.builder().build()) {
×
68

69
        // initialize our own completer here and add exit as an autocompletion option
70
        Completer completer = new AggregateCompleter(
×
71
            new StringsCompleter("exit"), new IdeCompleter((AbstractIdeContext) this.context));
72

73
        LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(completer).parser(parser)
×
74
            .variable(LineReader.LIST_MAX, AUTOCOMPLETER_MAX_RESULTS).build();
×
75

76
        // Create autosuggestion widgets
77
        AutosuggestionWidgets autosuggestionWidgets = new AutosuggestionWidgets(reader);
×
78
        // Enable autosuggestions
79
        autosuggestionWidgets.enable();
×
80

81
        // TODO: implement TailTipWidgets, see: https://github.com/devonfw/IDEasy/issues/169
82

83
        String prompt = "ide> ";
×
84
        String rightPrompt = null;
×
85
        String line;
86

87
        AnsiConsole.systemInstall();
×
88
        while (true) {
89
          try {
90
            line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
×
91
            line = line.trim();
×
92
            if (line.equals("exit")) {
×
93
              return;
×
94
            }
95
            reader.getHistory().add(line);
×
96
            int rc = runCommand(line);
×
97
            if (rc == RC_EXIT) {
×
98
              return;
×
99
            }
100
          } catch (UserInterruptException e) {
×
101
            // Ignore CTRL+C
102
            return;
×
103
          } catch (EndOfFileException e) {
×
104
            // CTRL+D
105
            return;
×
106
          } finally {
107
            AnsiConsole.systemUninstall();
×
108
          }
×
109
        }
110

111
      } catch (IOException e) {
×
112
        throw new RuntimeException(e);
×
113
      }
114
    } catch (Exception e) {
×
115
      throw new RuntimeException("Unexpected error during interactive auto-completion", e);
×
116
    }
117
  }
118

119
  /**
120
   * Converts String of arguments to array and runs the command
121
   *
122
   * @param args String of arguments
123
   * @return status code
124
   */
125
  private int runCommand(String args) {
126

127
    if ("exit".equals(args) || "quit".equals(args)) {
×
128
      return RC_EXIT;
×
129
    }
130
    String[] arguments = args.split(" ", 0);
×
131
    CliArguments cliArgs = new CliArguments(arguments);
×
132
    cliArgs.next();
×
133
    return ((AbstractIdeContext) this.context).run(cliArgs);
×
134
  }
135

136
  /**
137
   * @param argument the current {@link CliArgument} (position) to match.
138
   * @param commandlet the potential {@link Commandlet} to match.
139
   * @return {@code true} if the given {@link Commandlet} matches to the given {@link CliArgument}(s) and those have been applied (set in the {@link Commandlet}
140
   *     and {@link Commandlet#validate() validated}), {@code false} otherwise (the {@link Commandlet} did not match and we have to try a different candidate).
141
   */
142
  private boolean apply(CliArgument argument, Commandlet commandlet) {
143

144
    this.context.trace("Trying to match arguments to commandlet {}", commandlet.getName());
×
145
    CliArgument currentArgument = argument;
×
146
    Iterator<Property<?>> valueIterator = commandlet.getValues().iterator();
×
147
    Property<?> currentProperty = null;
×
148
    boolean endOpts = false;
×
149
    while (!currentArgument.isEnd()) {
×
150
      if (currentArgument.isEndOptions()) {
×
151
        endOpts = true;
×
152
      } else {
153
        String arg = currentArgument.get();
×
154
        this.context.trace("Trying to match argument '{}'", currentArgument);
×
155
        if ((currentProperty != null) && (currentProperty.isExpectValue())) {
×
156
          currentProperty.setValueAsString(arg, this.context);
×
157
          if (!currentProperty.isMultiValued()) {
×
158
            currentProperty = null;
×
159
          }
160
        } else {
161
          Property<?> property = null;
×
162
          if (!endOpts) {
×
163
            property = commandlet.getOption(currentArgument.getKey());
×
164
          }
165
          if (property == null) {
×
166
            if (!valueIterator.hasNext()) {
×
167
              this.context.trace("No option or next value found");
×
168
              return false;
×
169
            }
170
            currentProperty = valueIterator.next();
×
171
            this.context.trace("Next value candidate is {}", currentProperty);
×
172
            if (currentProperty instanceof KeywordProperty keyword) {
×
173
              if (keyword.matches(arg)) {
×
174
                keyword.setValue(Boolean.TRUE);
×
175
                this.context.trace("Keyword matched");
×
176
              } else {
177
                this.context.trace("Missing keyword");
×
178
                return false;
×
179
              }
180
            } else {
181
              boolean success = currentProperty.assignValueAsString(arg, this.context, commandlet);
×
182
              if (!success && currentProperty.isRequired()) {
×
183
                return false;
×
184
              }
185
            }
186
            if ((currentProperty != null) && !currentProperty.isMultiValued()) {
×
187
              currentProperty = null;
×
188
            }
189
          } else {
190
            this.context.trace("Found option by name");
×
191
            String value = currentArgument.getValue();
×
192
            if (value != null) {
×
193
              property.setValueAsString(value, this.context);
×
194
            } else if (property instanceof BooleanProperty) {
×
195
              ((BooleanProperty) property).setValue(Boolean.TRUE);
×
196
            } else {
197
              currentProperty = property;
×
198
              if (property.isEndOptions()) {
×
199
                endOpts = true;
×
200
              }
201
              throw new UnsupportedOperationException("not implemented");
×
202
            }
203
          }
204
        }
205
      }
206
      currentArgument = currentArgument.getNext(!endOpts);
×
207
    }
208
    return commandlet.validate().isValid();
×
209
  }
210
}
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

© 2025 Coveralls, Inc