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     */
007    package jline;
008    
009    import 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     */
019    public 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            return Terminal.class.getResourceAsStream("keybindings.properties");
179        }
180    }