]> git.argeo.org Git - lgpl/argeo-commons.git/blob - rcp/org.argeo.eclipse.ui.rcp/src/org/argeo/swt/desktop/MiniTerminal.java
The Equinox Jetty bundle should not be explicitly started anymore.
[lgpl/argeo-commons.git] / rcp / org.argeo.eclipse.ui.rcp / src / org / argeo / swt / desktop / MiniTerminal.java
1 package org.argeo.swt.desktop;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.io.OutputStream;
7 import java.net.InetAddress;
8 import java.net.UnknownHostException;
9 import java.nio.charset.Charset;
10 import java.nio.charset.StandardCharsets;
11 import java.nio.file.Files;
12 import java.nio.file.Path;
13 import java.nio.file.Paths;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.StringTokenizer;
18
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.events.KeyEvent;
21 import org.eclipse.swt.events.KeyListener;
22 import org.eclipse.swt.events.PaintEvent;
23 import org.eclipse.swt.events.PaintListener;
24 import org.eclipse.swt.graphics.Font;
25 import org.eclipse.swt.graphics.GC;
26 import org.eclipse.swt.graphics.Point;
27 import org.eclipse.swt.layout.GridData;
28 import org.eclipse.swt.layout.GridLayout;
29 import org.eclipse.swt.widgets.Canvas;
30 import org.eclipse.swt.widgets.Caret;
31 import org.eclipse.swt.widgets.Composite;
32 import org.eclipse.swt.widgets.Display;
33 import org.eclipse.swt.widgets.Shell;
34
35 public class MiniTerminal implements KeyListener, PaintListener {
36
37 private Canvas area;
38 private Caret caret;
39
40 private StringBuffer buf = new StringBuffer("");
41 private StringBuffer userInput = new StringBuffer("");
42 private List<String> history = new ArrayList<>();
43
44 private Point charExtent = null;
45 private int charsPerLine = 0;
46 private String[] lines = new String[0];
47 private List<String> logicalLines = new ArrayList<>();
48
49 private Font mono;
50 private Charset charset;
51
52 private Path currentDir;
53 private Path homeDir;
54 private String host = "localhost";
55 private String username;
56
57 private boolean running = false;
58 private OutputStream stdIn = null;
59
60 public MiniTerminal(Composite parent, int style) {
61 charset = StandardCharsets.UTF_8;
62
63 Display display = parent.getDisplay();
64 // Linux-specific
65 mono = new Font(display, "Monospace", 10, SWT.NONE);
66
67 parent.setLayout(new GridLayout());
68 area = new Canvas(parent, SWT.NONE);
69 area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
70 caret = new Caret(area, SWT.NONE);
71 area.setCaret(caret);
72
73 area.addKeyListener(this);
74 area.addPaintListener(this);
75
76 username = System.getProperty("user.name");
77 try {
78 host = InetAddress.getLocalHost().getHostName();
79 if (host.indexOf('.') > 0)
80 host = host.substring(0, host.indexOf('.'));
81 } catch (UnknownHostException e) {
82 host = "localhost";
83 }
84 homeDir = Paths.get(System.getProperty("user.home"));
85 currentDir = homeDir;
86
87 buf = new StringBuffer(prompt());
88 }
89
90 @Override
91 public void keyPressed(KeyEvent e) {
92 }
93
94 @Override
95 public void keyReleased(KeyEvent e) {
96 if (e.keyLocation != 0)
97 return;// weird characters
98 // System.out.println(e.character);
99 if (e.keyCode == 0xd) {// return
100 markLogicalLine();
101 if (!running)
102 processUserInput();
103 // buf.append(prompt());
104 } else if (e.keyCode == 0x8) {// delete
105 if (userInput.length() == 0)
106 return;
107 userInput.setLength(userInput.length() - 1);
108 if (!running && buf.length() > 0)
109 buf.setLength(buf.length() - 1);
110 } else {
111 // if (!running)
112 buf.append(e.character);
113 userInput.append(e.character);
114 }
115
116 if (area.isDisposed())
117 return;
118 area.redraw();
119 // System.out.println("Append " + e);
120
121 if (running) {
122 if (stdIn != null) {
123 try {
124 stdIn.write(Character.toString(e.character).getBytes(charset));
125 } catch (IOException e1) {
126 // TODO Auto-generated catch block
127 e1.printStackTrace();
128 }
129 }
130 }
131 }
132
133 protected String prompt() {
134 String fileName = currentDir.equals(homeDir) ? "~" : currentDir.getFileName().toString();
135 String end = username.equals("root") ? "]# " : "]$ ";
136 return "[" + username + "@" + host + " " + fileName + end;
137 }
138
139 private void displayPrompt() {
140 buf.append(prompt() + userInput);
141 }
142
143 protected void markLogicalLine() {
144 String str = buf.toString().trim();
145 logicalLines.add(str);
146 buf = new StringBuffer("");
147 }
148
149 private void processUserInput() {
150 String cmd = userInput.toString();
151 userInput = new StringBuffer("");
152 processUserInput(cmd);
153 history.add(cmd);
154 }
155
156 protected void processUserInput(String input) {
157 try {
158 StringTokenizer st = new StringTokenizer(input);
159 List<String> args = new ArrayList<>();
160 while (st.hasMoreTokens())
161 args.add(st.nextToken());
162 if (args.size() == 0) {
163 displayPrompt();
164 return;
165 }
166
167 // change directory
168 if (args.get(0).equals("cd")) {
169 if (args.size() == 1) {
170 setPath(homeDir);
171 } else {
172 Path newPath = currentDir.resolve(args.get(1));
173 if (!Files.exists(newPath) || !Files.isDirectory(newPath)) {
174 println(newPath + ": No such file or directory");
175 return;
176 }
177 setPath(newPath);
178 }
179 displayPrompt();
180 return;
181 }
182 // show current directory
183 else if (args.get(0).equals("pwd")) {
184 println(currentDir);
185 displayPrompt();
186 return;
187 }
188 // exit
189 else if (args.get(0).equals("exit")) {
190 println("logout");
191 area.getShell().dispose();
192 return;
193 }
194
195 ProcessBuilder pb = new ProcessBuilder(args);
196 pb.redirectErrorStream(true);
197 pb.directory(currentDir.toFile());
198 // Process process = Runtime.getRuntime().exec(input, null, currentPath.toFile());
199 Process process = pb.start();
200
201 stdIn = process.getOutputStream();
202 Thread readOut = new Thread("Read out") {
203 @Override
204 public void run() {
205 running = true;
206 try (BufferedReader in = new BufferedReader(
207 new InputStreamReader(process.getInputStream(), charset))) {
208 String line = null;
209 while ((line = in.readLine()) != null) {
210 println(line);
211 }
212 } catch (IOException e) {
213 println(e.getMessage());
214 }
215 stdIn = null;
216 displayPrompt();
217 running = false;
218 }
219 };
220 readOut.start();
221 } catch (IOException e) {
222 println(e.getMessage());
223 displayPrompt();
224 }
225 }
226
227 protected int linesForLogicalLine(char[] line) {
228 return line.length / charsPerLine + 1;
229 }
230
231 protected void println(Object line) {
232 buf.append(line);
233 markLogicalLine();
234 }
235
236 protected void refreshLines(int charPerLine, int nbrOfLines) {
237 if (lines.length != nbrOfLines) {
238 lines = new String[nbrOfLines];
239 Arrays.fill(lines, null);
240 }
241 if (this.charsPerLine != charPerLine)
242 this.charsPerLine = charPerLine;
243
244 int currentLine = nbrOfLines - 1;
245 // current line
246 if (buf.length() > 0) {
247 lines[currentLine] = buf.toString();
248 } else {
249 lines[currentLine] = "";
250 }
251 currentLine--;
252
253 logicalLines: for (int i = logicalLines.size() - 1; i >= 0; i--) {
254 char[] logicalLine = logicalLines.get(i).toCharArray();
255 int linesNeeded = linesForLogicalLine(logicalLine);
256 for (int j = linesNeeded - 1; j >= 0; j--) {
257 int from = j * charPerLine;
258 int to = j == linesNeeded - 1 ? from + charPerLine : Math.min(from + charPerLine, logicalLine.length);
259 lines[currentLine] = new String(Arrays.copyOfRange(logicalLine, from, to));
260 // System.out.println("Set line " + currentLine + " to : " + lines[currentLine]);
261 currentLine--;
262 if (currentLine < 0)
263 break logicalLines;
264 }
265 }
266 }
267
268 @Override
269 public void paintControl(PaintEvent e) {
270 GC gc = e.gc;
271 gc.setFont(mono);
272 if (charExtent == null)
273 charExtent = gc.textExtent("a");
274
275 Point areaSize = area.getSize();
276 int charPerLine = areaSize.x / charExtent.x;
277 int nbrOfLines = areaSize.y / charExtent.y;
278 refreshLines(charPerLine, nbrOfLines);
279
280 for (int i = 0; i < lines.length; i++) {
281 String line = lines[i];
282 if (line != null)
283 gc.drawString(line, 0, i * charExtent.y);
284 }
285 // String toDraw = buf.toString();
286 // gc.drawString(toDraw, 0, 0);
287 // area.setCaret(caret);
288 }
289
290 public void setPath(String path) {
291 this.currentDir = Paths.get(path);
292 }
293
294 public void setPath(Path path) {
295 this.currentDir = path;
296 }
297
298 public static void main(String[] args) {
299 Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
300 Shell shell = new Shell(display, SWT.SHELL_TRIM);
301
302 MiniTerminal miniBrowser = new MiniTerminal(shell, SWT.NONE);
303 String url = args.length > 0 ? args[0] : System.getProperty("user.home");
304 miniBrowser.setPath(url);
305
306 shell.open();
307 shell.setSize(new Point(800, 480));
308 while (!shell.isDisposed()) {
309 if (!display.readAndDispatch())
310 display.sleep();
311 }
312 }
313
314 }