src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java
branchJDK-8200758-branch
changeset 57072 29604aafa0fc
parent 57071 94e9270166f0
parent 52979 7384e00d5860
child 57076 687505381ca4
equal deleted inserted replaced
57071:94e9270166f0 57072:29604aafa0fc
     1 /*
       
     2  * Copyright (c) 2002-2016, the original author or authors.
       
     3  *
       
     4  * This software is distributable under the BSD license. See the terms of the
       
     5  * BSD license in the documentation provided with this software.
       
     6  *
       
     7  * http://www.opensource.org/licenses/bsd-license.php
       
     8  */
       
     9 package jdk.internal.jline;
       
    10 
       
    11 import java.text.MessageFormat;
       
    12 import java.util.HashMap;
       
    13 import java.util.Map;
       
    14 
       
    15 import jdk.internal.jline.internal.Configuration;
       
    16 import jdk.internal.jline.internal.Log;
       
    17 import static jdk.internal.jline.internal.Preconditions.checkNotNull;
       
    18 
       
    19 /**
       
    20  * Creates terminal instances.
       
    21  *
       
    22  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
       
    23  * @since 2.0
       
    24  */
       
    25 public class TerminalFactory
       
    26 {
       
    27     public static final String JLINE_TERMINAL = "jline.terminal";
       
    28 
       
    29     public static final String AUTO = "auto";
       
    30 
       
    31     public static final String UNIX = "unix";
       
    32 
       
    33     public static final String OSV = "osv";
       
    34 
       
    35     public static final String WIN = "win";
       
    36 
       
    37     public static final String WINDOWS = "windows";
       
    38 
       
    39     public static final String FREEBSD = "freebsd";
       
    40 
       
    41     public static final String NONE = "none";
       
    42 
       
    43     public static final String OFF = "off";
       
    44 
       
    45     public static final String FALSE = "false";
       
    46 
       
    47     private static Terminal term = null;
       
    48 
       
    49     public static synchronized Terminal create() {
       
    50         return create(null);
       
    51     }
       
    52 
       
    53     public static synchronized Terminal create(String ttyDevice) {
       
    54         if (Log.TRACE) {
       
    55             //noinspection ThrowableInstanceNeverThrown
       
    56             Log.trace(new Throwable("CREATE MARKER"));
       
    57         }
       
    58 
       
    59         String defaultType = "dumb".equals(System.getenv("TERM")) ? NONE : AUTO;
       
    60         String type  = Configuration.getString(JLINE_TERMINAL, defaultType);
       
    61 
       
    62         Log.debug("Creating terminal; type=", type);
       
    63 
       
    64         Terminal t;
       
    65         try {
       
    66             String tmp = type.toLowerCase();
       
    67 
       
    68             if (tmp.equals(UNIX)) {
       
    69                 t = getFlavor(Flavor.UNIX);
       
    70             }
       
    71             else if (tmp.equals(OSV)) {
       
    72                 t = getFlavor(Flavor.OSV);
       
    73             }
       
    74             else if (tmp.equals(WIN) || tmp.equals(WINDOWS)) {
       
    75                 t = getFlavor(Flavor.WINDOWS);
       
    76             }
       
    77             else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
       
    78                 if (System.getenv("INSIDE_EMACS") != null) {
       
    79                     // emacs requires ansi on and echo off
       
    80                     t = new UnsupportedTerminal(true, false);
       
    81                 } else  {
       
    82                     // others the other way round
       
    83                     t = new UnsupportedTerminal(false, true);
       
    84                 }
       
    85             }
       
    86             else {
       
    87                 if (tmp.equals(AUTO)) {
       
    88                     String os = Configuration.getOsName();
       
    89                     Flavor flavor = Flavor.UNIX;
       
    90                     if (os.contains(WINDOWS)) {
       
    91                         flavor = Flavor.WINDOWS;
       
    92                     } else if (System.getenv("OSV_CPUS") != null) {
       
    93                         flavor = Flavor.OSV;
       
    94                     }
       
    95                     t = getFlavor(flavor, ttyDevice);
       
    96                 }
       
    97                 else {
       
    98                     try {
       
    99                         @SuppressWarnings("deprecation")
       
   100                         Object o = Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
       
   101                         t = (Terminal) o;
       
   102                     }
       
   103                     catch (Exception e) {
       
   104                         throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
       
   105                     }
       
   106                 }
       
   107             }
       
   108         }
       
   109         catch (Exception e) {
       
   110             Log.error("Failed to construct terminal; falling back to unsupported", e);
       
   111             t = new UnsupportedTerminal();
       
   112         }
       
   113 
       
   114         Log.debug("Created Terminal: ", t);
       
   115 
       
   116         try {
       
   117             t.init();
       
   118         }
       
   119         catch (Throwable e) {
       
   120             Log.error("Terminal initialization failed; falling back to unsupported", e);
       
   121             return new UnsupportedTerminal();
       
   122         }
       
   123 
       
   124         return t;
       
   125     }
       
   126 
       
   127     public static synchronized void reset() {
       
   128         term = null;
       
   129     }
       
   130 
       
   131     public static synchronized void resetIf(final Terminal t) {
       
   132         if(t == term) {
       
   133             reset();
       
   134         }
       
   135     }
       
   136 
       
   137     public static enum Type
       
   138     {
       
   139         AUTO,
       
   140         WINDOWS,
       
   141         UNIX,
       
   142         OSV,
       
   143         NONE
       
   144     }
       
   145 
       
   146     public static synchronized void configure(final String type) {
       
   147         checkNotNull(type);
       
   148         System.setProperty(JLINE_TERMINAL, type);
       
   149     }
       
   150 
       
   151     public static synchronized void configure(final Type type) {
       
   152         checkNotNull(type);
       
   153         configure(type.name().toLowerCase());
       
   154     }
       
   155 
       
   156     //
       
   157     // Flavor Support
       
   158     //
       
   159 
       
   160     public static enum Flavor
       
   161     {
       
   162         WINDOWS,
       
   163         UNIX,
       
   164         OSV
       
   165     }
       
   166 
       
   167     private static final Map<Flavor, TerminalConstructor> FLAVORS = new HashMap<>();
       
   168 
       
   169     static {
       
   170         registerFlavor(Flavor.WINDOWS, ttyDevice -> new WindowsTerminal());
       
   171         registerFlavor(Flavor.UNIX, ttyDevice -> new UnixTerminal(ttyDevice));
       
   172         registerFlavor(Flavor.OSV, ttyDevice -> new OSvTerminal());
       
   173     }
       
   174 
       
   175     public static synchronized Terminal get(String ttyDevice) {
       
   176         // The code is assuming we've got only one terminal per process.
       
   177         // Continuing this assumption, if this terminal is already initialized,
       
   178         // we don't check if it's using the same tty line either. Both assumptions
       
   179         // are a bit crude. TODO: check single terminal assumption.
       
   180         if (term == null) {
       
   181             term = create(ttyDevice);
       
   182         }
       
   183         return term;
       
   184     }
       
   185 
       
   186     public static synchronized Terminal get() {
       
   187         return get(null);
       
   188     }
       
   189 
       
   190     public static Terminal getFlavor(final Flavor flavor) throws Exception {
       
   191         return getFlavor(flavor, null);
       
   192     }
       
   193 
       
   194     @SuppressWarnings("deprecation")
       
   195     public static Terminal getFlavor(final Flavor flavor, String ttyDevice) throws Exception {
       
   196         TerminalConstructor factory = FLAVORS.get(flavor);
       
   197         if (factory != null) {
       
   198             return factory.createTerminal(ttyDevice);
       
   199         } else {
       
   200             throw new InternalError();
       
   201         }
       
   202     }
       
   203 
       
   204     public static void registerFlavor(final Flavor flavor, final TerminalConstructor factory) {
       
   205         FLAVORS.put(flavor, factory);
       
   206     }
       
   207 
       
   208     public interface TerminalConstructor {
       
   209         public Terminal createTerminal(String str) throws Exception;
       
   210     }
       
   211 }