22//DEPS eu.maveniverse.maven.mima:context:2.4.15 eu.maveniverse.maven.mima.runtime:standalone-static:2.4.15
33//DEPS info.picocli:picocli:4.7.6
44//DEPS com.google.code.gson:gson:2.11.0
5+ //DEPS org.jline:jline-console-ui:3.26.2 org.jline:jline-terminal-jni:3.26.2
56//DEPS org.slf4j:slf4j-api:2.0.13 org.slf4j:slf4j-simple:2.0.13
67//SOURCES Jpm.java json/AppInfo.java util/FileUtils.java util/ResolverUtils.java util/SearchUtils.java
78//SOURCES util/SearchResult.java util/SyncStats.java util/Version.java
1617import java .util .stream .Collectors ;
1718import org .codejive .jpm .util .SyncStats ;
1819import org .codejive .jpm .util .Version ;
20+ import org .jline .consoleui .prompt .ConsolePrompt ;
21+ import org .jline .consoleui .prompt .ListResult ;
22+ import org .jline .consoleui .prompt .PromptResultItemIF ;
23+ import org .jline .consoleui .prompt .builder .ListPromptBuilder ;
24+ import org .jline .consoleui .prompt .builder .PromptBuilder ;
25+ import org .jline .terminal .Terminal ;
26+ import org .jline .terminal .TerminalBuilder ;
1927import picocli .CommandLine ;
2028import picocli .CommandLine .Command ;
2129import picocli .CommandLine .Mixin ;
@@ -74,6 +82,12 @@ static class Sync implements Callable<Integer> {
7482 @ Mixin QuietMixin quietMixin ;
7583 @ Mixin CopyMixin copyMixin ;
7684
85+ @ Option (
86+ names = {"-i" , "--interactive" },
87+ description = "Interactively search and select artifacts to install" ,
88+ defaultValue = "false" )
89+ private boolean interactive ;
90+
7791 @ Option (
7892 names = {"-m" , "--max" },
7993 description = "Maximum number of results to return" ,
@@ -82,22 +96,135 @@ static class Sync implements Callable<Integer> {
8296
8397 @ Parameters (
8498 paramLabel = "artifactPattern" ,
85- description = "Partial or full artifact name to search for." )
99+ description = "Partial or full artifact name to search for." ,
100+ defaultValue = "" )
86101 private String artifactPattern ;
87102
88103 @ Override
89104 public Integer call () throws Exception {
90- String [] artifactNames =
91- Jpm .builder ()
92- .directory (copyMixin .directory )
93- .noLinks (copyMixin .noLinks )
94- .build ()
95- .search (artifactPattern , Math .min (max , 200 ));
96- if (artifactNames .length > 0 ) {
97- Arrays .stream (artifactNames ).forEach (System .out ::println );
105+ if (interactive || artifactPattern == null || artifactPattern .isEmpty ()) {
106+ try (Terminal terminal = TerminalBuilder .builder ().build ()) {
107+ while (true ) {
108+ ConsolePrompt prompt = new ConsolePrompt (terminal );
109+ if (artifactPattern == null || artifactPattern .isEmpty ()) {
110+ artifactPattern = askString (prompt , "Search for:" );
111+ }
112+ String [] artifactNames = search (artifactPattern );
113+ PromptBuilder promptBuilder = prompt .getPromptBuilder ();
114+ addSelectItem (promptBuilder , "Select artifact:" , artifactNames );
115+ addSelectArtifactAction (promptBuilder );
116+ Map <String , PromptResultItemIF > result =
117+ prompt .prompt (promptBuilder .build ());
118+ String selectedArtifact = getSelectedId (result , "item" );
119+ String artifactAction = getSelectedId (result , "action" );
120+ if ("install" .equals (artifactAction )) {
121+ SyncStats stats =
122+ Jpm .builder ()
123+ .directory (copyMixin .directory )
124+ .noLinks (copyMixin .noLinks )
125+ .build ()
126+ .install (new String [] {selectedArtifact });
127+ if (!quietMixin .quiet ) {
128+ printStats (stats );
129+ }
130+ } else if ("copy" .equals (artifactAction )) {
131+ SyncStats stats =
132+ Jpm .builder ()
133+ .directory (copyMixin .directory )
134+ .noLinks (copyMixin .noLinks )
135+ .build ()
136+ .copy (new String [] {selectedArtifact }, false );
137+ if (!quietMixin .quiet ) {
138+ printStats (stats );
139+ }
140+ } else if ("version" .equals (artifactAction )) {
141+ artifactPattern = selectedArtifact ;
142+ continue ;
143+ } else { // quit
144+ break ;
145+ }
146+ String finalAction = selectFinalAction (prompt );
147+ if ("quit" .equals (finalAction )) {
148+ break ;
149+ }
150+ artifactPattern = null ;
151+ }
152+ }
153+ } else {
154+ String [] artifactNames = search (artifactPattern );
155+ if (artifactNames .length > 0 ) {
156+ Arrays .stream (artifactNames ).forEach (System .out ::println );
157+ }
98158 }
99159 return 0 ;
100160 }
161+
162+ String [] search (String artifactPattern ) throws IOException {
163+ return Jpm .builder ()
164+ .directory (copyMixin .directory )
165+ .noLinks (copyMixin .noLinks )
166+ .build ()
167+ .search (artifactPattern , Math .min (max , 200 ));
168+ }
169+
170+ String askString (ConsolePrompt prompt , String message ) throws IOException {
171+ PromptBuilder promptBuilder = prompt .getPromptBuilder ();
172+ promptBuilder .createInputPrompt ().name ("input" ).message (message ).addPrompt ();
173+ Map <String , PromptResultItemIF > result = prompt .prompt (promptBuilder .build ());
174+ return result .get ("input" ).getResult ();
175+ }
176+
177+ void addSelectItem (PromptBuilder promptBuilder , String message , String [] items )
178+ throws IOException {
179+ ListPromptBuilder artifactsList =
180+ promptBuilder .createListPrompt ().name ("item" ).message (message ).pageSize (10 );
181+ for (String artifactName : items ) {
182+ artifactsList .newItem (artifactName ).text (artifactName ).add ();
183+ }
184+ artifactsList .addPrompt ();
185+ }
186+
187+ void addSelectArtifactAction (PromptBuilder promptBuilder ) throws IOException {
188+ promptBuilder
189+ .createListPrompt ()
190+ .name ("action" )
191+ .message ("What to do:" )
192+ .newItem ("install" )
193+ .text ("Install artifact" )
194+ .add ()
195+ .newItem ("copy" )
196+ .text ("Copy artifact" )
197+ .add ()
198+ .newItem ("version" )
199+ .text ("Select different version" )
200+ .add ()
201+ .newItem ("quit" )
202+ .text ("Quit" )
203+ .add ()
204+ .addPrompt ();
205+ }
206+
207+ String selectFinalAction (ConsolePrompt prompt ) throws IOException {
208+ PromptBuilder promptBuilder = prompt .getPromptBuilder ();
209+ promptBuilder
210+ .createListPrompt ()
211+ .name ("action" )
212+ .message ("What to do:" )
213+ .newItem ("again" )
214+ .text ("Search again" )
215+ .add ()
216+ .newItem ("quit" )
217+ .text ("Quit" )
218+ .add ()
219+ .addPrompt ();
220+ Map <String , PromptResultItemIF > result = prompt .prompt (promptBuilder .build ());
221+ return getSelectedId (result , "action" );
222+ }
223+
224+ private static String getSelectedId (
225+ Map <String , PromptResultItemIF > result , String itemName ) {
226+ return ((ListResult ) result .get (itemName )).getSelectedId ();
227+ }
101228 }
102229
103230 @ Command (
0 commit comments