1
2
3
4
5
6
7
8
9 package jline;
10
11 import java.text.MessageFormat;
12 import java.util.HashMap;
13 import java.util.Map;
14
15 import jline.internal.Configuration;
16 import jline.internal.Log;
17 import jline.internal.Preconditions;
18
19 import static jline.internal.Preconditions.checkNotNull;
20
21
22
23
24
25
26
27 public class TerminalFactory
28 {
29 public static final String JLINE_TERMINAL = "jline.terminal";
30
31 public static final String AUTO = "auto";
32
33 public static final String UNIX = "unix";
34
35 public static final String WIN = "win";
36
37 public static final String WINDOWS = "windows";
38
39 public static final String NONE = "none";
40
41 public static final String OFF = "off";
42
43 public static final String FALSE = "false";
44
45 private static Terminal term = null;
46
47 public static synchronized Terminal create() {
48 if (Log.TRACE) {
49
50 Log.trace(new Throwable("CREATE MARKER"));
51 }
52
53 String type = Configuration.getString(JLINE_TERMINAL, AUTO);
54 if ("dumb".equals(System.getenv("TERM"))) {
55 type = "none";
56 Log.debug("$TERM=dumb; setting type=", type);
57 }
58
59 Log.debug("Creating terminal; type=", type);
60
61 Terminal t;
62 try {
63 String tmp = type.toLowerCase();
64
65 if (tmp.equals(UNIX)) {
66 t = getFlavor(Flavor.UNIX);
67 }
68 else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
69 t = getFlavor(Flavor.WINDOWS);
70 }
71 else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
72 t = new UnsupportedTerminal();
73 }
74 else {
75 if (tmp.equals(AUTO)) {
76 String os = Configuration.getOsName();
77 Flavor flavor = Flavor.UNIX;
78 if (os.contains(WINDOWS)) {
79 flavor = Flavor.WINDOWS;
80 }
81 t = getFlavor(flavor);
82 }
83 else {
84 try {
85 t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
86 }
87 catch (Exception e) {
88 throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
89 }
90 }
91 }
92 }
93 catch (Exception e) {
94 Log.error("Failed to construct terminal; falling back to unsupported", e);
95 t = new UnsupportedTerminal();
96 }
97
98 Log.debug("Created Terminal: ", t);
99
100 try {
101 t.init();
102 }
103 catch (Throwable e) {
104 Log.error("Terminal initialization failed; falling back to unsupported", e);
105 return new UnsupportedTerminal();
106 }
107
108 return t;
109 }
110
111 public static synchronized void reset() {
112 term = null;
113 }
114
115 public static synchronized void resetIf(final Terminal t) {
116 if(t == term) {
117 reset();
118 }
119 }
120
121 public static enum Type
122 {
123 AUTO,
124 WINDOWS,
125 UNIX,
126 NONE
127 }
128
129 public static synchronized void configure(final String type) {
130 checkNotNull(type);
131 System.setProperty(JLINE_TERMINAL, type);
132 }
133
134 public static synchronized void configure(final Type type) {
135 checkNotNull(type);
136 configure(type.name().toLowerCase());
137 }
138
139
140
141
142
143 public static enum Flavor
144 {
145 WINDOWS,
146 UNIX
147 }
148
149 private static final Map<Flavor, Class<? extends Terminal>> FLAVORS = new HashMap<Flavor, Class<? extends Terminal>>();
150
151 static {
152 registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
153 registerFlavor(Flavor.UNIX, UnixTerminal.class);
154 }
155
156 public static synchronized Terminal get() {
157 if (term == null) {
158 term = create();
159 }
160 return term;
161 }
162
163 public static Terminal getFlavor(final Flavor flavor) throws Exception {
164 Class<? extends Terminal> type = FLAVORS.get(flavor);
165 if (type != null) {
166 return type.newInstance();
167 }
168
169 throw new InternalError();
170 }
171
172 public static void registerFlavor(final Flavor flavor, final Class<? extends Terminal> type) {
173 FLAVORS.put(flavor, type);
174 }
175
176 }