src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java
changeset 53333 fd6de53a0d6e
parent 53332 ab474ef0a0ac
parent 53010 086dfcfc3731
child 53334 b94283cb226b
equal deleted inserted replaced
53332:ab474ef0a0ac 53333:fd6de53a0d6e
     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.util.HashMap;
       
    12 import java.util.HashSet;
       
    13 import java.util.Map;
       
    14 import java.util.Set;
       
    15 
       
    16 import jdk.internal.jline.internal.Configuration;
       
    17 import jdk.internal.jline.internal.InfoCmp;
       
    18 import jdk.internal.jline.internal.Log;
       
    19 import jdk.internal.jline.internal.TerminalLineSettings;
       
    20 
       
    21 import static jdk.internal.jline.internal.Preconditions.checkNotNull;
       
    22 
       
    23 /**
       
    24  * Terminal that is used for unix platforms. Terminal initialization
       
    25  * is handled by issuing the <em>stty</em> command against the
       
    26  * <em>/dev/tty</em> file to disable character echoing and enable
       
    27  * character input. All known unix systems (including
       
    28  * Linux and Macintosh OS X) support the <em>stty</em>), so this
       
    29  * implementation should work for an reasonable POSIX system.
       
    30  *
       
    31  * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
       
    32  * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
       
    33  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
       
    34  * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
       
    35  * @since 2.0
       
    36  */
       
    37 public class UnixTerminal
       
    38     extends TerminalSupport
       
    39     implements Terminal2
       
    40 {
       
    41     private final TerminalLineSettings settings;
       
    42     private final String type;
       
    43     private String intr;
       
    44     private String lnext;
       
    45     private Set<String> bools = new HashSet<String>();
       
    46     private Map<String, Integer> ints = new HashMap<String, Integer>();
       
    47     private Map<String, String> strings = new HashMap<String, String>();
       
    48 
       
    49     public UnixTerminal() throws Exception {
       
    50         this(TerminalLineSettings.DEFAULT_TTY, null);
       
    51     }
       
    52 
       
    53     public UnixTerminal(String ttyDevice) throws Exception {
       
    54         this(ttyDevice, null);
       
    55     }
       
    56 
       
    57     public UnixTerminal(String ttyDevice, String type) throws Exception {
       
    58         super(true);
       
    59         checkNotNull(ttyDevice);
       
    60         this.settings = TerminalLineSettings.getSettings(ttyDevice);
       
    61         if (type == null) {
       
    62             type = System.getenv("TERM");
       
    63         }
       
    64         this.type = type;
       
    65         parseInfoCmp();
       
    66     }
       
    67 
       
    68     public TerminalLineSettings getSettings() {
       
    69         return settings;
       
    70     }
       
    71 
       
    72     /**
       
    73      * Remove line-buffered input by invoking "stty -icanon min 1"
       
    74      * against the current terminal.
       
    75      */
       
    76     @Override
       
    77     public void init() throws Exception {
       
    78         super.init();
       
    79 
       
    80         setAnsiSupported(true);
       
    81 
       
    82         // Set the console to be character-buffered instead of line-buffered.
       
    83         // Make sure we're distinguishing carriage return from newline.
       
    84         // Allow ctrl-s keypress to be used (as forward search)
       
    85         //
       
    86         // Please note that FreeBSD does not seem to support -icrnl and thus
       
    87         // has to be handled separately. Otherwise the console will be "stuck"
       
    88         // and will neither accept input nor print anything to stdout.
       
    89         if (Configuration.getOsName().contains(TerminalFactory.FREEBSD)) {
       
    90             settings.set("-icanon min 1 -inlcr -ixon");
       
    91         } else {
       
    92             settings.set("-icanon min 1 -icrnl -inlcr -ixon");
       
    93         }
       
    94         settings.undef("dsusp");
       
    95 
       
    96         setEchoEnabled(false);
       
    97 
       
    98         parseInfoCmp();
       
    99     }
       
   100 
       
   101     /**
       
   102      * Restore the original terminal configuration, which can be used when
       
   103      * shutting down the console reader. The ConsoleReader cannot be
       
   104      * used after calling this method.
       
   105      */
       
   106     @Override
       
   107     public void restore() throws Exception {
       
   108         settings.restore();
       
   109         super.restore();
       
   110     }
       
   111 
       
   112     /**
       
   113      * Returns the value of <tt>stty columns</tt> param.
       
   114      */
       
   115     @Override
       
   116     public int getWidth() {
       
   117         int w = settings.getProperty("columns");
       
   118         return w < 1 ? DEFAULT_WIDTH : w;
       
   119     }
       
   120 
       
   121     /**
       
   122      * Returns the value of <tt>stty rows>/tt> param.
       
   123      */
       
   124     @Override
       
   125     public int getHeight() {
       
   126         int h = settings.getProperty("rows");
       
   127         return h < 1 ? DEFAULT_HEIGHT : h;
       
   128     }
       
   129 
       
   130     @Override
       
   131     public boolean hasWeirdWrap() {
       
   132         return getBooleanCapability("auto_right_margin")
       
   133                 && getBooleanCapability("eat_newline_glitch");
       
   134     }
       
   135 
       
   136     @Override
       
   137     public synchronized void setEchoEnabled(final boolean enabled) {
       
   138         try {
       
   139             if (enabled) {
       
   140                 settings.set("echo");
       
   141             }
       
   142             else {
       
   143                 settings.set("-echo");
       
   144             }
       
   145             super.setEchoEnabled(enabled);
       
   146         }
       
   147         catch (Exception e) {
       
   148             if (e instanceof InterruptedException) {
       
   149                 Thread.currentThread().interrupt();
       
   150             }
       
   151             Log.error("Failed to ", enabled ? "enable" : "disable", " echo", e);
       
   152         }
       
   153     }
       
   154 
       
   155     public void disableInterruptCharacter()
       
   156     {
       
   157         try {
       
   158             intr = getSettings().getPropertyAsString("intr");
       
   159             if ("<undef>".equals(intr)) {
       
   160                 intr = null;
       
   161             }
       
   162             settings.undef("intr");
       
   163         }
       
   164         catch (Exception e) {
       
   165             if (e instanceof InterruptedException) {
       
   166                 Thread.currentThread().interrupt();
       
   167             }
       
   168             Log.error("Failed to disable interrupt character", e);
       
   169         }
       
   170     }
       
   171 
       
   172     public void enableInterruptCharacter()
       
   173     {
       
   174         try {
       
   175             if (intr != null) {
       
   176                 settings.set("intr", intr);
       
   177             }
       
   178         }
       
   179         catch (Exception e) {
       
   180             if (e instanceof InterruptedException) {
       
   181                 Thread.currentThread().interrupt();
       
   182             }
       
   183             Log.error("Failed to enable interrupt character", e);
       
   184         }
       
   185     }
       
   186 
       
   187     public void disableLitteralNextCharacter()
       
   188     {
       
   189         try {
       
   190             lnext = getSettings().getPropertyAsString("lnext");
       
   191             if ("<undef>".equals(lnext)) {
       
   192                 lnext = null;
       
   193             }
       
   194             settings.undef("lnext");
       
   195         }
       
   196         catch (Exception e) {
       
   197             if (e instanceof InterruptedException) {
       
   198                 Thread.currentThread().interrupt();
       
   199             }
       
   200             Log.error("Failed to disable litteral next character", e);
       
   201         }
       
   202     }
       
   203 
       
   204     public void enableLitteralNextCharacter()
       
   205     {
       
   206         try {
       
   207             if (lnext != null) {
       
   208                 settings.set("lnext", lnext);
       
   209             }
       
   210         }
       
   211         catch (Exception e) {
       
   212             if (e instanceof InterruptedException) {
       
   213                 Thread.currentThread().interrupt();
       
   214             }
       
   215             Log.error("Failed to enable litteral next character", e);
       
   216         }
       
   217     }
       
   218 
       
   219     public boolean getBooleanCapability(String capability) {
       
   220         return bools.contains(capability);
       
   221     }
       
   222 
       
   223     public Integer getNumericCapability(String capability) {
       
   224         return ints.get(capability);
       
   225     }
       
   226 
       
   227     public String getStringCapability(String capability) {
       
   228         return strings.get(capability);
       
   229     }
       
   230 
       
   231     private void parseInfoCmp() {
       
   232         String capabilities = null;
       
   233         if (type != null) {
       
   234             try {
       
   235                 capabilities = InfoCmp.getInfoCmp(type);
       
   236             } catch (Exception e) {
       
   237             }
       
   238         }
       
   239         if (capabilities == null) {
       
   240             capabilities = InfoCmp.getAnsiCaps();
       
   241         }
       
   242         InfoCmp.parseInfoCmp(capabilities, bools, ints, strings);
       
   243     }
       
   244 }