1
1
package com .devonfw .tools .ide .cli ;
2
2
3
+ import java .util .Objects ;
4
+
3
5
/**
4
- * A single argument of a {@code main} method from a command-line-interface (CLI).
6
+ * Represents an argument for a command-line-interface (CLI) and a chain to all its {@link #getNext(boolean)
7
+ * successors}.
5
8
*
6
9
* @since 1.0.0
7
10
* @see #getNext(boolean)
@@ -14,27 +17,63 @@ public class CliArgument {
14
17
*/
15
18
public static final String END_OPTIONS = "--" ;
16
19
17
- /** A dummy {@link CliArgument} to represent the end of the CLI arguments. */
18
- public static final CliArgument END = new CliArgument ("«end»" );
20
+ /** A {@link CliArgument} to represent the end of the CLI arguments. */
21
+ public static final CliArgument END = new CliArgument ();
22
+
23
+ static final String NAME_START = "«start»" ;
19
24
20
25
private final String arg ;
21
26
22
27
private String key ;
23
28
24
29
private String value ;
25
30
26
- private CliArgument next ;
31
+ final CliArgument next ;
32
+
33
+ private final boolean completion ;
34
+
35
+ private CliArgument () {
36
+
37
+ super ();
38
+ this .arg = "«end»" ;
39
+ this .next = null ;
40
+ this .completion = false ;
41
+ }
42
+
43
+ /**
44
+ * The constructor.
45
+ *
46
+ * @param arg the {@link #get() argument}.
47
+ * @param next the {@link #getNext() next}.
48
+ */
49
+ protected CliArgument (String arg , CliArgument next ) {
50
+
51
+ this (arg , next , false );
52
+ }
27
53
28
54
/**
29
55
* The constructor.
30
56
*
31
57
* @param arg the {@link #get() argument}.
58
+ * @param next the {@link #getNext() next}.
59
+ * @param completion the {@link #isCompletion() completion flag}.
32
60
*/
33
- protected CliArgument (String arg ) {
61
+ protected CliArgument (String arg , CliArgument next , boolean completion ) {
34
62
35
63
super ();
64
+ Objects .requireNonNull (arg );
65
+ Objects .requireNonNull (next );
36
66
this .arg = arg ;
37
- this .next = END ;
67
+ this .next = next ;
68
+ this .completion = completion ;
69
+ }
70
+
71
+ /**
72
+ * @return {@code true} if this is the argument to complete (should be the last one), {@code false} otherwise.
73
+ */
74
+ public boolean isCompletion () {
75
+
76
+ return this .completion ;
38
77
}
39
78
40
79
/**
@@ -61,6 +100,22 @@ public boolean isLongOption() {
61
100
return this .arg .startsWith ("--" );
62
101
}
63
102
103
+ /**
104
+ * @return {@code true} if this is a short option (e.g. "-b"), {@code false} otherwise.
105
+ */
106
+ public boolean isShortOption () {
107
+
108
+ return (this .arg .length () >= 2 ) && (this .arg .charAt (0 ) == '-' ) && (this .arg .charAt (1 ) != '-' );
109
+ }
110
+
111
+ /**
112
+ * @return {@code true} if this is a combined short option (e.g. "-bd"), {@code false} otherwise.
113
+ */
114
+ public boolean isCombinedShortOption () {
115
+
116
+ return (this .arg .length () > 2 ) && (this .arg .charAt (0 ) == '-' ) && (this .arg .charAt (1 ) != '-' );
117
+ }
118
+
64
119
/**
65
120
* @return {@code true} if {@link #END_OPTIONS}, {@code false} otherwise.
66
121
*/
@@ -70,37 +125,67 @@ public boolean isEndOptions() {
70
125
}
71
126
72
127
/**
73
- * @return {@code true} if this is the {@link #END}, {@code false} otherwise.
128
+ * @return {@code true} if this is the {@link #END} of the arguments , {@code false} otherwise.
74
129
*/
75
130
public boolean isEnd () {
76
131
77
- return (this == END );
132
+ return (this .next == null );
133
+ }
134
+
135
+ /**
136
+ * @return {@code true} if this is the start of the arguments, {@code false} otherwise.
137
+ */
138
+ public boolean isStart () {
139
+
140
+ return (this .arg == NAME_START ); // not using equals on purpose
141
+ }
142
+
143
+ /**
144
+ * @param successors the number of {@link #getNext() successors} expected.
145
+ * @return {@code true} if at least the given number of {@link #getNext() successors} are available, {@code false}
146
+ * otherwise.
147
+ */
148
+ public boolean hasMoreSuccessorsThan (int successors ) {
149
+
150
+ if (successors <= 0 ) {
151
+ return true ;
152
+ }
153
+ CliArgument current = this ;
154
+ while (current != END ) {
155
+ successors --;
156
+ if (successors == 0 ) {
157
+ return true ;
158
+ }
159
+ current = current .next ;
160
+ }
161
+ return false ;
162
+ }
163
+
164
+ /**
165
+ * @return the next {@link CliArgument} or {@code null} if this is the {@link #isEnd() end}.
166
+ * @see #getNext(boolean)
167
+ */
168
+ public CliArgument getNext () {
169
+
170
+ return this .next ;
78
171
}
79
172
80
173
/**
81
174
* @param splitShortOpts - if {@code true} then combined short options will be split (so instead of "-fbd" you will
82
175
* get "-f", "-b", "-d").
83
- * @return the next {@link CliArgument} or {@code null} if this is the last argument .
176
+ * @return the next {@link CliArgument} or {@code null} if this is the {@link #isEnd() end} .
84
177
*/
85
178
public CliArgument getNext (boolean splitShortOpts ) {
86
179
87
- if (splitShortOpts && (this .next != null )) {
180
+ if (splitShortOpts && (this .next != null ) && ! this . next . completion ) {
88
181
String option = this .next .arg ;
89
182
int len = option .length ();
90
183
if ((len > 2 ) && (option .charAt (0 ) == '-' ) && (option .charAt (1 ) != '-' )) {
91
- CliArgument first = null ;
92
- CliArgument current = null ;
93
- for (int i = 1 ; i < len ; i ++) {
94
- CliArgument shortOpt = new CliArgument ("-" + option .charAt (i ));
95
- shortOpt .next = this .next .next ;
96
- if (current == null ) {
97
- first = shortOpt ;
98
- } else {
99
- current .next = shortOpt ;
100
- }
101
- current = shortOpt ;
184
+ CliArgument current = this .next .next ;
185
+ for (int i = len - 1 ; i > 0 ; i --) {
186
+ current = new CliArgument ("-" + option .charAt (i ), current );
102
187
}
103
- return first ;
188
+ return current ;
104
189
}
105
190
}
106
191
return this .next ;
@@ -151,6 +236,9 @@ public String getArgs() {
151
236
}
152
237
StringBuilder sb = new StringBuilder ();
153
238
CliArgument current = this ;
239
+ if (current .isStart ()) {
240
+ current = current .next ;
241
+ }
154
242
String prefix = "\" " ;
155
243
while (!current .isEnd ()) {
156
244
sb .append (prefix );
@@ -162,55 +250,49 @@ public String getArgs() {
162
250
return sb .toString ();
163
251
}
164
252
253
+ private CliArgument createStart () {
254
+
255
+ assert (!isStart ());
256
+ return new CliArgument (NAME_START , this );
257
+ }
258
+
165
259
@ Override
166
260
public String toString () {
167
261
168
262
return this .arg ;
169
263
}
170
264
171
265
/**
172
- * @param args the command-line arguments from {@code main} method.
266
+ * @param args the command-line arguments (e.g. from {@code main} method) .
173
267
* @return the first {@link CliArgument} of the parsed arguments or {@code null} if for empty arguments.
174
268
*/
175
269
public static CliArgument of (String ... args ) {
176
270
177
- return of (true , args );
271
+ return of (false , args );
178
272
}
179
273
180
274
/**
181
- * @param splitShortOpt - to {@link #getNext(boolean) split combined short options} for the first argument.
182
- * @param args the command-line arguments from {@code main} method.
275
+ * @param args the command-line arguments (e.g. from {@code main} method).
183
276
* @return the first {@link CliArgument} of the parsed arguments or {@code null} if for empty arguments.
184
277
*/
185
- public static CliArgument of (boolean splitShortOpt , String ... args ) {
278
+ public static CliArgument ofCompletion (String ... args ) {
279
+
280
+ return of (true , args );
281
+ }
186
282
187
- CliArgument first = CliArgument .END ;
188
- CliArgument current = null ;
189
- for (int argsIndex = 0 ; argsIndex < args .length ; argsIndex ++) {
283
+ private static CliArgument of (boolean completion , String ... args ) {
284
+
285
+ CliArgument current = CliArgument .END ;
286
+ int last = args .length - 1 ;
287
+ for (int argsIndex = last ; argsIndex >= 0 ; argsIndex --) {
190
288
String arg = args [argsIndex ];
191
- CliArgument argument = new CliArgument (arg );
192
- if (current == null ) {
193
- first = argument ;
194
- current = argument ;
195
- if (splitShortOpt ) {
196
- CliArgument start = new CliArgument ("" );
197
- start .next = argument ;
198
- first = start .getNext (true );
199
- current = first ;
200
- while (!current .next .isEnd ()) {
201
- current = current .next ;
202
- }
203
- }
204
- } else {
205
- if (current .isEnd ()) {
206
- // should never happen, but if a bug leads us here it is severe
207
- throw new IllegalStateException ("Internal error!" );
208
- }
209
- current .next = argument ;
210
- current = argument ;
289
+ boolean completionArg = false ;
290
+ if (argsIndex == last ) {
291
+ completionArg = completion ;
211
292
}
293
+ current = new CliArgument (arg , current , completionArg );
212
294
}
213
- return first ;
295
+ return current . createStart () ;
214
296
}
215
297
216
298
/**
0 commit comments