Blame view

readline/src/pad/prac1/EditableBufferedReader.java 4.61 KB
Imanol-Mikel Barba Sabariego authored
1
2
3
4
5
6
package pad.prac1;
import java.io.*;


public class EditableBufferedReader extends BufferedReader 
{
7
8
9
10
	/*
	 * MODE DEFINITIONS
	 */
11
12
13
14
	public static final int DEL_BACKWARD 	= 0;
	public static final int DEL_FORWARD 	= 1;
	public static final int INSERT 			= 0;
	public static final int OVERWRITE 		= 1;
15
16
17
18
19
20

	/*
	 * TYPE DEFINITIONS
	 */

	public static final int ESCAPE_SEQUENCE = 0;
21
22
	public static final int PRINTABLE 		= 1;
	public static final int NON_PRINTABLE 	= 2;
23
24

	/* KEY DEFINITIONS
25
	 * 
26
27
28
29
30
31
32
33
34
35
36
	 * ESC (0x1B) starts an escape sequence
	 * ESC+[+C (0x1B 0x5B 0x43) Cursor Forward
	 * ESC+[+D (0x1B 0x5B 0x44) Cursor Backward
	 * ESC+[+2+~ (0x1B 0x5B 0x32 0x7E) Insert
	 * ESC+[+3+~ (0x1B 0x5B 0x33 0x7E) Delete forward
	 * ESC+O+H (0x1B 0x4F 0x48) Home
	 * ESC+O+F (0x1B 0x4F 0x46) End
	 */

	public static final int RETURN_KEY 		= 0x0D;
	public static final int BACKSPACE 		= 0x08;
37
	public static final int BACKSPACE_DEL 	= 0x7F;
38
39
	public static final int ESC 			= 0x1B;
	public static final int ESC_SEQ 		= 0x5B;
40
41
42
	public static final int FORWARD 		= 0x43;
	public static final int BACKWARD		= 0x44;
	public static final int DEL 			= 0x33;
43
44
45
46
	public static final int TILDE 			= 0x7E;
	public static final int HOME_END 		= 0x4F;
	public static final int HOME 			= 0x48;
	public static final int END 			= 0x46;
47
48
49
	public static final int INSERT_KEY		= 0x32;
	public static final int INS_SPACE		= 0x40;
	public static final int DEL_CHAR		= 0x50;
50
51
	public static final int EOF				= 0x04;
	public static final int LINE_FEED		= 0x0A;
Imanol-Mikel Barba Sabariego authored
52
53
54
55
	private Console console = new Console();
	private Line line = new Line(console);
	private boolean endOfFile 	= false;
56
Imanol-Mikel Barba Sabariego authored
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
	public EditableBufferedReader(Reader in)
	{
		super(in);
	}

	public EditableBufferedReader(Reader in, int sz)
	{
		super(in,sz);
	}

	private void setRaw() throws IOException, InterruptedException
	{
		String[] cmd = {"/bin/sh", "-c", "stty raw -echo </dev/tty"};
		Runtime.getRuntime().exec(cmd).waitFor();
	}

	private void unsetRaw() throws IOException, InterruptedException
	{
		String[] cmd = {"/bin/sh", "-c", "stty -raw echo </dev/tty"};
		Runtime.getRuntime().exec(cmd).waitFor();
	}
79
80
	private int parseKey(int key)
	{
81
82
83
84
85
86
		if(key < 0x20)
		{
			if(key == ESC)
			{
				return ESCAPE_SEQUENCE;
			}
87
			else if((key == BACKSPACE) || (key == RETURN_KEY) || (key == EOF))
88
89
90
91
92
			{
				return PRINTABLE;
			}
			return NON_PRINTABLE;
		}
93
94
95
		return PRINTABLE;
	}
Imanol-Mikel Barba Sabariego authored
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
	public int read() throws IOException
	{
		return super.read();
	}

	public String readLine()
	{
		try 
		{
			setRaw();
		} 
		catch (Exception e) 
		{
			System.out.println("Couldn't set terminal in raw mode");
			return "";
		}
112
		while(!endOfFile)
Imanol-Mikel Barba Sabariego authored
113
114
115
116
		{
			try 
			{
				int character = read();
117
				//System.err.print((String)(Integer.toHexString(character) + " ").toUpperCase());
118
				switch(parseKey(character))
Imanol-Mikel Barba Sabariego authored
119
				{
120
					case ESCAPE_SEQUENCE:
121
						switch(read())
122
						{
123
124
125
126
							case ESC_SEQ:
								switch(read())
								{
									case FORWARD:
127
										line.setCursorTo(line.getCursorPosition()+1);
128
129
130
									break;

									case BACKWARD:
131
										line.setCursorTo(line.getCursorPosition()-1);
132
133
									break;
134
135
136
									case DEL:
										if(read() == TILDE)
										{
137
											line.delChar(DEL_FORWARD);
138
										}
139
									break;
140
141
142
143
144
145

									case INSERT_KEY:
										if(read() == TILDE)
										{
											line.toggleMode();
										}
146
									break;
147
148
149
150
151
152
153
								}
							break;

							case HOME_END:
								switch(read())
								{
									case HOME:
154
										line.setCursorTo(1);
155
									break;
156
157

									case END:
158
										line.setCursorTo(line.length()+1);
159
									break;
160
161
								}
							break;
162
						}
163
					break;
164
165
166
167

					case PRINTABLE:
						switch(character)
						{
168
169
							case EOF:
								endOfFile = true;
170
							break;
171
172
173

							case BACKSPACE:
							case BACKSPACE_DEL:
174
								line.delChar(DEL_BACKWARD);
175
							break;
176
177
178

							case RETURN_KEY:
								character = LINE_FEED;
179
							default:
180
								line.addChar((char)character);
181
							break;
182
						}
183
					break;
184
185
186

					case NON_PRINTABLE:
						//ignore
187
					break;
Imanol-Mikel Barba Sabariego authored
188
189
190
191
				}
			} 
			catch (IOException e)
			{
192
				System.out.println("Error reading line");
Imanol-Mikel Barba Sabariego authored
193
194
195
196
197
198
199
200
201
202
203
204
				break;
			}
		}
		try 
		{
			unsetRaw();
		} 
		catch (Exception e) 
		{
			System.out.println("Couldn't unset raw mode");
			return "";
		}
205
		System.out.println("");
206
		return line.toString();
Imanol-Mikel Barba Sabariego authored
207
208
	}
}
209
210
211
212
213
214
215
216
217
218
219
220


/* TO-DO
 * 
 * up/down keys (needs text to work)
 * pgup pgdown keys (goesto penultima linea visible)
 * read terminal size
 * update size dynamically
 * long strings wrap down
 * cursor keys skip final \n on a line
 * careful if overwrite mode and final character is \n
 */