001/*
002 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
003 *
004 * This software is distributable under the BSD license. See the terms of the
005 * BSD license in the documentation provided with this software.
006 */
007package jline;
008
009import java.io.*;
010
011/**
012 *  Representation of the input terminal for a platform. Handles
013 *  any initialization that the platform may need to perform
014 *  in order to allow the {@link ConsoleReader} to correctly handle
015 *  input.
016 *
017 *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
018 */
019public abstract class Terminal implements ConsoleOperations {
020    private static Terminal term;
021
022    /**
023     *  @see #setupTerminal
024     */
025    public static Terminal getTerminal() {
026        return setupTerminal();
027    }
028
029    /** 
030     *  Reset the current terminal to null. 
031     */
032    public static void resetTerminal() {
033        term = null;
034    }
035
036    /**
037     *  <p>Configure and return the {@link Terminal} instance for the
038     *  current platform. This will initialize any system settings
039     *  that are required for the console to be able to handle
040     *  input correctly, such as setting tabtop, buffered input, and
041     *  character echo.</p>
042     *
043     *  <p>This class will use the Terminal implementation specified in the
044     *  <em>jline.terminal</em> system property, or, if it is unset, by
045     *  detecting the operating system from the <em>os.name</em>
046     *  system property and instantiating either the
047     *  {@link WindowsTerminalTest} or {@link UnixTerminal}.
048     *
049     *  @see #initializeTerminal
050     */
051    public static synchronized Terminal setupTerminal() {
052        if (term != null) {
053            return term;
054        }
055
056        final Terminal t;
057
058        String os = System.getProperty("os.name").toLowerCase();
059        String termProp = System.getProperty("jline.terminal");
060
061        if ((termProp != null) && (termProp.length() > 0)) {
062            try {
063                t = (Terminal) Class.forName(termProp).newInstance();
064            } catch (Exception e) {
065                throw (IllegalArgumentException) new IllegalArgumentException(e
066                    .toString()).fillInStackTrace();
067            }
068        } else if (os.indexOf("windows") != -1) {
069            t = new WindowsTerminal();
070        } else {
071            t = new UnixTerminal();
072        }
073
074        try {
075            t.initializeTerminal();
076        } catch (Exception e) {
077            e.printStackTrace();
078
079            return term = new UnsupportedTerminal();
080        }
081
082        return term = t;
083    }
084
085    /**
086     *  Returns true if the current console supports ANSI
087     *  codes.
088     */
089    public boolean isANSISupported() {
090        return true;
091    }
092
093    /**
094     *  Read a single character from the input stream. This might
095     *  enable a terminal implementation to better handle nuances of
096     *  the console.
097     */
098    public int readCharacter(final InputStream in) throws IOException {
099        return in.read();
100    }
101
102    /**
103     *  Reads a virtual key from the console. Typically, this will
104     *  just be the raw character that was entered, but in some cases,
105     *  multiple input keys will need to be translated into a single
106     *  virtual key.
107     *
108     *  @param  in  the InputStream to read from
109     *  @return  the virtual key (e.g., {@link ConsoleOperations#VK_UP})
110     */
111    public int readVirtualKey(InputStream in) throws IOException {
112        return readCharacter(in);
113    }
114
115    /**
116     *  Initialize any system settings
117     *  that are required for the console to be able to handle
118     *  input correctly, such as setting tabtop, buffered input, and
119     *  character echo.
120     */
121    public abstract void initializeTerminal() throws Exception;
122
123    /**
124     *  Returns the current width of the terminal (in characters)
125     */
126    public abstract int getTerminalWidth();
127
128    /**
129     *  Returns the current height of the terminal (in lines)
130     */
131    public abstract int getTerminalHeight();
132
133    /**
134     *  Returns true if this terminal is capable of initializing the
135     *  terminal to use jline.
136     */
137    public abstract boolean isSupported();
138
139    /**
140     *  Returns true if the terminal will echo all characters type.
141     */
142    public abstract boolean getEcho();
143
144    /**
145     *  Invokes before the console reads a line with the prompt and mask.
146     */
147    public void beforeReadLine(ConsoleReader reader, String prompt,
148                               Character mask) {
149    }
150
151    /**
152     *  Invokes after the console reads a line with the prompt and mask.
153     */
154    public void afterReadLine(ConsoleReader reader, String prompt,
155                              Character mask) {
156    }
157
158    /**
159     *  Returns false if character echoing is disabled.
160     */
161    public abstract boolean isEchoEnabled();
162
163
164    /**
165     *  Enable character echoing. This can be used to re-enable character
166     *  if the ConsoleReader is no longer being used.
167     */
168    public abstract void enableEcho();
169
170
171    /**
172     *  Disable character echoing. This can be used to manually re-enable
173     *  character if the ConsoleReader has been disabled.
174     */
175    public abstract void disableEcho();
176
177    public InputStream getDefaultBindings() {
178        // Mac bindings are slightly different from Unix/Linux.
179        // For instance, the Delete key behavior is different between them.
180        return Terminal.class.getResourceAsStream(
181                System.getProperty("os.name").toLowerCase().startsWith("mac") ?
182                    "keybindings-mac.properties" : "keybindings.properties");
183    }
184}