1 /*
   2  * Copyright (c) 2002-2012, 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 jline;
  10 
  11 import jline.internal.Log;
  12 import jline.internal.TerminalLineSettings;
  13 
  14 /**
  15  * Terminal that is used for unix platforms. Terminal initialization
  16  * is handled by issuing the <em>stty</em> command against the
  17  * <em>/dev/tty</em> file to disable character echoing and enable
  18  * character input. All known unix systems (including
  19  * Linux and Macintosh OS X) support the <em>stty</em>), so this
  20  * implementation should work for an reasonable POSIX system.
  21  *
  22  * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
  23  * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
  24  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  25  * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
  26  * @since 2.0
  27  */
  28 public class UnixTerminal
  29     extends TerminalSupport
  30 {
  31     private final TerminalLineSettings settings = new TerminalLineSettings();
  32 
  33     public UnixTerminal() throws Exception {
  34         super(true);
  35     }
  36 
  37     protected TerminalLineSettings getSettings() {
  38         return settings;
  39     }
  40 
  41     /**
  42      * Remove line-buffered input by invoking "stty -icanon min 1"
  43      * against the current terminal.
  44      */
  45     @Override
  46     public void init() throws Exception {
  47         super.init();
  48 
  49         setAnsiSupported(true);
  50 
  51         // Set the console to be character-buffered instead of line-buffered.
  52         // Make sure we're distinguishing carriage return from newline.
  53         // Allow ctrl-s keypress to be used (as forward search)
  54         settings.set("-icanon min 1 -icrnl -inlcr -ixon");
  55         settings.set("dsusp undef");
  56 
  57         setEchoEnabled(false);
  58     }
  59 
  60     /**
  61      * Restore the original terminal configuration, which can be used when
  62      * shutting down the console reader. The ConsoleReader cannot be
  63      * used after calling this method.
  64      */
  65     @Override
  66     public void restore() throws Exception {
  67         settings.restore();
  68         super.restore();
  69     }
  70 
  71     /**
  72      * Returns the value of <tt>stty columns</tt> param.
  73      */
  74     @Override
  75     public int getWidth() {
  76         int w = settings.getProperty("columns");
  77         return w < 1 ? DEFAULT_WIDTH : w;
  78     }
  79 
  80     /**
  81      * Returns the value of <tt>stty rows>/tt> param.
  82      */
  83     @Override
  84     public int getHeight() {
  85         int h = settings.getProperty("rows");
  86         return h < 1 ? DEFAULT_HEIGHT : h;
  87     }
  88 
  89     @Override
  90     public synchronized void setEchoEnabled(final boolean enabled) {
  91         try {
  92             if (enabled) {
  93                 settings.set("echo");
  94             }
  95             else {
  96                 settings.set("-echo");
  97             }
  98             super.setEchoEnabled(enabled);
  99         }
 100         catch (Exception e) {
 101             if (e instanceof InterruptedException) {
 102                 Thread.currentThread().interrupt();
 103             }
 104             Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo", e);
 105         }
 106     }
 107 
 108     public void disableInterruptCharacter()
 109     {
 110         try {
 111             settings.set("intr undef");
 112         }
 113         catch (Exception e) {
 114             if (e instanceof InterruptedException) {
 115                 Thread.currentThread().interrupt();
 116             }
 117             Log.error("Failed to disable interrupt character", e);
 118         }
 119     }
 120 
 121     public void enableInterruptCharacter()
 122     {
 123         try {
 124             settings.set("intr ^C");
 125         }
 126         catch (Exception e) {
 127             if (e instanceof InterruptedException) {
 128                 Thread.currentThread().interrupt();
 129             }
 130             Log.error("Failed to enable interrupt character", e);
 131         }
 132     }
 133 }