1   package com.atlassian.maven.plugins.amps.codegen.prompter;
2   
3   // This is a MODIFIED VERSION of org.codehaus.plexus.components.interactivity.DefaultPrompter which is under the MIT License
4   /*
5    * The MIT License
6    *
7    * Copyright (c) 2005, The Codehaus
8    *
9    * Permission is hereby granted, free of charge, to any person obtaining a copy of
10   * this software and associated documentation files (the "Software"), to deal in
11   * the Software without restriction, including without limitation the rights to
12   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13   * of the Software, and to permit persons to whom the Software is furnished to do
14   * so, subject to the following conditions:
15   *
16   * The above copyright notice and this permission notice shall be included in all
17   * copies or substantial portions of the Software.
18   *
19   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25   * SOFTWARE.
26   */
27  
28  import java.io.IOException;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import org.codehaus.plexus.components.interactivity.InputHandler;
33  import org.codehaus.plexus.components.interactivity.OutputHandler;
34  import org.codehaus.plexus.components.interactivity.Prompter;
35  import org.codehaus.plexus.components.interactivity.PrompterException;
36  import org.codehaus.plexus.util.StringUtils;
37  
38  import jline.ANSIBuffer;
39  
40  /**
41   * @since 3.5
42   */
43  public class PrettyPrompter implements Prompter
44  {
45  
46      //maven-cli-plugin uses an old version jline that has ansi codes in package scope.
47      //re-defining them in public here
48      public static final int OFF = 0;
49      public static final int BOLD = 1;
50      public static final int UNDERSCORE = 4;
51      public static final int BLINK = 5;
52      public static final int REVERSE = 7;
53      public static final int CONCEALED = 8;
54      public static final int FG_BLACK = 30;
55      public static final int FG_RED = 31;
56      public static final int FG_GREEN = 32;
57      public static final int FG_YELLOW = 33;
58      public static final int FG_BLUE = 34;
59      public static final int FG_MAGENTA = 35;
60      public static final int FG_CYAN = 36;
61      public static final int FG_WHITE = 37;
62      public static final char ESC = 27;
63  
64  
65      /**
66       * @requirement
67       */
68      private OutputHandler outputHandler;
69  
70      /**
71       * @requirement
72       */
73      private InputHandler inputHandler;
74  
75      private boolean useAnsiColor;
76  
77      public PrettyPrompter()
78      {
79          String mavencolor = System.getenv("MAVEN_COLOR");
80          if (mavencolor != null && !mavencolor.equals(""))
81          {
82              useAnsiColor = Boolean.parseBoolean(mavencolor);
83          } else
84          {
85              useAnsiColor = false;
86          }
87      }
88  
89      public String prompt(String message)
90              throws PrompterException
91      {
92          try
93          {
94              writePrompt(message);
95          } catch (IOException e)
96          {
97              throw new PrompterException("Failed to present prompt", e);
98          }
99  
100         try
101         {
102             return inputHandler.readLine();
103         } catch (IOException e)
104         {
105             throw new PrompterException("Failed to read user response", e);
106         }
107     }
108 
109     public String prompt(String message, String defaultReply)
110             throws PrompterException
111     {
112         try
113         {
114             writePrompt(formatMessage(message, null, defaultReply));
115         } catch (IOException e)
116         {
117             throw new PrompterException("Failed to present prompt", e);
118         }
119 
120         try
121         {
122             String line = inputHandler.readLine();
123 
124             if (StringUtils.isEmpty(line))
125             {
126                 line = defaultReply;
127             }
128 
129             return line;
130         } catch (IOException e)
131         {
132             throw new PrompterException("Failed to read user response", e);
133         }
134     }
135 
136     public String prompt(String message, List possibleValues, String defaultReply)
137             throws PrompterException
138     {
139         String formattedMessage = formatMessage(message, possibleValues, defaultReply);
140 
141         String line;
142 
143         do
144         {
145             try
146             {
147                 writePrompt(formattedMessage);
148             } catch (IOException e)
149             {
150                 throw new PrompterException("Failed to present prompt", e);
151             }
152 
153             try
154             {
155                 line = inputHandler.readLine();
156             } catch (IOException e)
157             {
158                 throw new PrompterException("Failed to read user response", e);
159             }
160 
161             if (StringUtils.isEmpty(line))
162             {
163                 line = defaultReply;
164             }
165 
166             if (line != null && !possibleValues.contains(line))
167             {
168                 try
169                 {
170                     String invalid = "Invalid selection.";
171                     if (useAnsiColor)
172                     {
173                         ANSIBuffer ansiBuffer = new ANSIBuffer();
174                         ansiBuffer.append(ANSIBuffer.ANSICodes
175                                 .attrib(FG_RED))
176                                 .append(ANSIBuffer.ANSICodes
177                                         .attrib(BOLD))
178                                 .append("Invalid selection.")
179                                 .append(ANSIBuffer.ANSICodes
180                                         .attrib(OFF));
181                         invalid = ansiBuffer.toString();
182                     }
183                     outputHandler.writeLine(invalid);
184                 } catch (IOException e)
185                 {
186                     throw new PrompterException("Failed to present feedback", e);
187                 }
188             }
189         }
190         while (line == null || !possibleValues.contains(line));
191 
192         return line;
193     }
194 
195     public String prompt(String message, List possibleValues)
196             throws PrompterException
197     {
198         return prompt(message, possibleValues, null);
199     }
200 
201     public String promptForPassword(String message)
202             throws PrompterException
203     {
204         try
205         {
206             writePrompt(message);
207         } catch (IOException e)
208         {
209             throw new PrompterException("Failed to present prompt", e);
210         }
211 
212         try
213         {
214             return inputHandler.readPassword();
215         } catch (IOException e)
216         {
217             throw new PrompterException("Failed to read user response", e);
218         }
219     }
220 
221     protected String formatMessage(String message, List possibleValues, String defaultReply)
222     {
223         if (useAnsiColor)
224         {
225             return formatAnsiMessage(message, possibleValues, defaultReply);
226         } else
227         {
228             return formatPlainMessage(message, possibleValues, defaultReply);
229         }
230     }
231 
232     private String formatAnsiMessage(String message, List possibleValues, String defaultReply)
233     {
234         ANSIBuffer formatted = new ANSIBuffer();
235 
236         formatted.append(message);
237 
238         if (possibleValues != null && !possibleValues.isEmpty())
239         {
240             formatted.append(" (");
241 
242             for (Iterator it = possibleValues.iterator(); it.hasNext(); )
243             {
244                 String possibleValue = (String) it.next();
245 
246                 formatted.attrib(possibleValue, BOLD);
247 
248                 if (it.hasNext())
249                 {
250                     formatted.append("/");
251                 }
252             }
253 
254             formatted.append(")");
255         }
256 
257         if (defaultReply != null)
258         {
259             formatted.append(ANSIBuffer.ANSICodes
260                     .attrib(FG_GREEN))
261                     .append(ANSIBuffer.ANSICodes
262                             .attrib(BOLD))
263                     .append(" [")
264                     .append(defaultReply)
265                     .append("]")
266                     .append(ANSIBuffer.ANSICodes
267                             .attrib(OFF));
268         }
269 
270         return formatted.toString();
271     }
272 
273     private String formatPlainMessage(String message, List possibleValues, String defaultReply)
274     {
275         StringBuffer formatted = new StringBuffer(message.length() * 2);
276 
277         formatted.append(message);
278 
279         if (possibleValues != null && !possibleValues.isEmpty())
280         {
281             formatted.append(" (");
282 
283             for (Iterator it = possibleValues.iterator(); it.hasNext(); )
284             {
285                 String possibleValue = (String) it.next();
286 
287                 formatted.append(possibleValue);
288 
289                 if (it.hasNext())
290                 {
291                     formatted.append('/');
292                 }
293             }
294 
295             formatted.append(')');
296         }
297 
298         if (defaultReply != null)
299         {
300             formatted.append(" [")
301                     .append(defaultReply)
302                     .append("]");
303         }
304 
305         return formatted.toString();
306     }
307 
308     private void writePrompt(String message)
309             throws IOException
310     {
311         outputHandler.write(message + ": ");
312     }
313 
314     public void showMessage(String message)
315             throws PrompterException
316     {
317         try
318         {
319             writePrompt(message);
320         } catch (IOException e)
321         {
322             throw new PrompterException("Failed to present prompt", e);
323         }
324 
325     }
326 
327 
328 }