View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.jline;
20  
21  import java.util.function.Consumer;
22  
23  import org.apache.maven.message.MessageBuilder;
24  import org.apache.maven.message.MessageBuilderFactory;
25  import org.jline.jansi.AnsiConsole;
26  import org.jline.terminal.Terminal;
27  import org.jline.terminal.TerminalBuilder;
28  
29  public class MessageUtils {
30  
31      static Terminal terminal;
32      static MessageBuilderFactory messageBuilderFactory = new JLineMessageBuilderFactory();
33      static boolean colorEnabled = true;
34      static Thread shutdownHook;
35      static final Object STARTUP_SHUTDOWN_MONITOR = new Object();
36  
37      public static void systemInstall(Terminal terminal) {
38          MessageUtils.terminal = terminal;
39      }
40  
41      public static void systemInstall() {
42          systemInstall(null, null);
43      }
44  
45      public static void systemInstall(Consumer<TerminalBuilder> builderConsumer, Consumer<Terminal> terminalConsumer) {
46          MessageUtils.terminal = new FastTerminal(
47                  () -> {
48                      TerminalBuilder builder = TerminalBuilder.builder()
49                              .name("Maven")
50                              .dumb(true)
51                              .systemOutput(TerminalBuilder.SystemOutput.SysOut)
52                              .color(true);
53                      if (builderConsumer != null) {
54                          builderConsumer.accept(builder);
55                      }
56                      return builder.build();
57                  },
58                  terminal -> {
59                      AnsiConsole.setTerminal(terminal);
60                      AnsiConsole.systemInstall();
61                      if (terminalConsumer != null) {
62                          terminalConsumer.accept(terminal);
63                      }
64                  });
65      }
66  
67      /**
68       * Waits for the terminal to finish installing on its background thread.
69       * <p>
70       * Terminal setup runs asynchronously and replaces {@code System.out}/{@code System.err} along
71       * the way. Call this before you redirect those streams yourself (for example for the {@code -l}
72       * log file), otherwise the late terminal install can overwrite your redirection and logs end up
73       * back on the console.
74       */
75      public static void awaitTerminalInitialization() {
76          if (terminal instanceof FastTerminal) {
77              ((FastTerminal) terminal).getTerminal();
78          }
79      }
80  
81      public static void registerShutdownHook() {
82          if (shutdownHook == null) {
83              shutdownHook = new Thread(() -> {
84                  synchronized (MessageUtils.STARTUP_SHUTDOWN_MONITOR) {
85                      MessageUtils.doSystemUninstall();
86                  }
87              });
88              Runtime.getRuntime().addShutdownHook(shutdownHook);
89          }
90      }
91  
92      public static void systemUninstall() {
93          doSystemUninstall();
94          if (shutdownHook != null) {
95              try {
96                  Runtime.getRuntime().removeShutdownHook(shutdownHook);
97              } catch (IllegalStateException var3) {
98                  // ignore
99              }
100         }
101     }
102 
103     private static void doSystemUninstall() {
104         try {
105             if (terminal instanceof FastTerminal) {
106                 // wait for the asynchronous systemInstall call before we uninstall to ensure a consistent state
107                 ((FastTerminal) terminal).getTerminal();
108             }
109             AnsiConsole.systemUninstall();
110         } finally {
111             terminal = null;
112         }
113     }
114 
115     public static void setColorEnabled(boolean enabled) {
116         colorEnabled = enabled;
117     }
118 
119     public static boolean isColorEnabled() {
120         return colorEnabled && terminal != null;
121     }
122 
123     public static int getTerminalWidth() {
124         return terminal != null ? terminal.getWidth() : -1;
125     }
126 
127     public static MessageBuilder builder() {
128         return messageBuilderFactory.builder();
129     }
130 
131     public static Terminal getTerminal() {
132         return terminal;
133     }
134 
135     /**
136      * Remove any ANSI code from a message (colors or other escape sequences).
137      *
138      * @param msg message eventually containing ANSI codes
139      * @return the message with ANSI codes removed
140      */
141     public static String stripAnsiCodes(String msg) {
142         return msg.replaceAll("\u001B\\[[;\\d]*[ -/]*[@-~]", "");
143     }
144 }