001    /*
002     * Copyright (c) 2002-2006, 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         *  <p>Configure and return the {@link Terminal} instance for the
031         *  current platform. This will initialize any system settings
032         *  that are required for the console to be able to handle
033         *  input correctly, such as setting tabtop, buffered input, and
034         *  character echo.</p>
035         *
036         *  <p>This class will use the Terminal implementation specified in the
037         *  <em>jline.terminal</em> system property, or, if it is unset, by
038         *  detecting the operating system from the <em>os.name</em>
039         *  system property and instantiateing either the
040         *  {@link WindowsTerminal} or {@link UnixTerminal}.
041         *
042         *  @see #initializeTerminal
043         */
044        public static synchronized Terminal setupTerminal() {
045            if (term != null) {
046                return term;
047            }
048    
049            final Terminal t;
050    
051            String os = System.getProperty("os.name").toLowerCase();
052            String termProp = System.getProperty("jline.terminal");
053    
054            if ((termProp != null) && (termProp.length() > 0)) {
055                try {
056                    t = (Terminal) Class.forName(termProp).newInstance();
057                } catch (Exception e) {
058                    throw (IllegalArgumentException) new IllegalArgumentException(e
059                                                                                  .toString())
060                          .fillInStackTrace();
061                }
062            } else if (os.indexOf("windows") != -1) {
063                t = new WindowsTerminal();
064            } else {
065                t = new UnixTerminal();
066            }
067    
068            try {
069                t.initializeTerminal();
070            } catch (Exception e) {
071                e.printStackTrace();
072    
073                return term = new UnsupportedTerminal();
074            }
075    
076            return term = t;
077        }
078    
079        /**
080         *  Returns true if the current console supports ANSI
081         *  codes.
082         */
083        public boolean isANSISupported() {
084            return true;
085        }
086    
087        /**
088         *  Read a single character from the input stream. This might
089         *  enable a terminal implementation to better handle nuances of
090         *  the console.
091         */
092        public int readCharacter(final InputStream in) throws IOException {
093            return in.read();
094        }
095    
096        /**
097         *  Reads a virtual key from the console. Typically, this will
098         *  just be the raw character that was entered, but in some cases,
099         *  multiple input keys will need to be translated into a single
100         *  virtual key.
101         *
102         *  @param  in  the InputStream to read from
103         *  @return  the virtual key (e.g., {@link ConsoleOperations#VK_UP})
104         */
105        public int readVirtualKey(InputStream in) throws IOException {
106            return readCharacter(in);
107        }
108    
109        /**
110         *  Initialize any system settings
111         *  that are required for the console to be able to handle
112         *  input correctly, such as setting tabtop, buffered input, and
113         *  character echo.
114         */
115        public abstract void initializeTerminal() throws Exception;
116    
117        /**
118         *  Returns the current width of the terminal (in characters)
119         */
120        public abstract int getTerminalWidth();
121    
122        /**
123         *  Returns the current height of the terminal (in lines)
124         */
125        public abstract int getTerminalHeight();
126    
127        /**
128         *  Returns true if this terminal is capable of initializing the
129         *  terminal to use jline.
130         */
131        public abstract boolean isSupported();
132    
133        /**
134         *  Returns true if the terminal will echo all characters type.
135         */
136        public abstract boolean getEcho();
137    
138        /**
139         *  Invokes before the console reads a line with the prompt and mask.
140         */
141        public void beforeReadLine(ConsoleReader reader, String prompt,
142                                   Character mask) {
143        }
144    
145        /**
146         *  Invokes after the console reads a line with the prompt and mask.
147         */
148        public void afterReadLine(ConsoleReader reader, String prompt,
149                                  Character mask) {
150        }
151    }