EditableBufferedReader.java 5.98 KB
package pad.prac1;
import java.io.*;


public class EditableBufferedReader extends BufferedReader 
{
	/*
	 * MODE DEFINITIONS
	 */
	
	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;
	
	/*
	 * TYPE DEFINITIONS
	 */
	
	public static final int ESCAPE_SEQUENCE = 0;
	public static final int PRINTABLE 		= 1;
	public static final int NON_PRINTABLE 	= 2;
	
	/* KEY DEFINITIONS
	 * 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;
	public static final int BACKSPACE_DEL 	= 0x7F;
	public static final int ESC 			= 0x1B;
	public static final int ESC_SEQ 		= 0x5B;
	public static final int FORWARD 		= 0x43;
	public static final int BACKWARD		= 0x44;
	public static final int DEL 			= 0x33;
	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;
	public static final int INSERT_KEY		= 0x32;
	public static final int INS_SPACE		= 0x40;
	public static final int DEL_CHAR		= 0x50;
	public static final int NUM_0			= 0x30;
	
	private Line line = new Line();
	private boolean returnKey 	= false;

	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();
	}
	
	private int parseKey(int key)
	{
		if(key < 0x20)
		{
			if(key == ESC)
			{
				return ESCAPE_SEQUENCE;
			}
			else if((key == BACKSPACE) || (key == RETURN_KEY))
			{
				return PRINTABLE;
			}
			return NON_PRINTABLE;
		}
		return PRINTABLE;
	}
	
	public void addChar(char c)
	{
		switch(line.getMode())
		{
			case INSERT:
				if(line.getCursorPosition() != line.length()+1)
				{
					insertSpace();
				}			
				System.out.print(c);
				line.insertCharAt(c, line.getCursorPosition()-1);
				line.setCursorPosition(line.getCursorPosition()+1);
				break;
				
			case OVERWRITE:
				if(line.getCursorPosition() != line.length()+1)
				{
					line.removeCharAt(line.getCursorPosition()-1);
				}
				System.out.print(c);
				line.insertCharAt(c, line.getCursorPosition()-1);
				line.setCursorPosition(line.getCursorPosition()+1);
			break;
		}
	}
	
	public void delChar(int mode)
	{
		switch(mode)
		{
			case DEL_BACKWARD:
				if(line.getCursorPosition() != 1)
				{
					System.out.print((char)BACKSPACE);
					deleteCharacter();
					line.removeCharAt(line.getCursorPosition()-2);
					line.setCursorPosition(line.getCursorPosition()-1);
				}
			break;
			case DEL_FORWARD:
				if(line.getCursorPosition() != (line.length()+1))
				{
					line.removeCharAt(line.getCursorPosition()-1);
					deleteCharacter();
				}
			break;
		}
	}
	
	private void insertSpace()
	{
		System.out.print((char)ESC);
		System.out.print((char)ESC_SEQ);
		System.out.print((char)INS_SPACE);
	}
	
	private void deleteCharacter()
	{
		System.out.print((char)ESC);
		System.out.print((char)ESC_SEQ);
		System.out.print((char)DEL_CHAR);
	}
	
	public void moveCursorTo(int pos)
	{
		if((pos <= line.length()+1) && (pos >= 1))
		{
			if(pos > line.getCursorPosition())
			{
				System.out.print((char)ESC);
				System.out.print((char)ESC_SEQ);
				System.out.print((char)(NUM_0+pos-line.getCursorPosition()));
				System.out.print((char)FORWARD);
			}
			
			else if(pos < line.getCursorPosition())
			{
				System.out.print((char)ESC);
				System.out.print((char)ESC_SEQ);
				System.out.print((char)(NUM_0-pos+line.getCursorPosition()));
				System.out.print((char)BACKWARD);
			}
			line.setCursorPosition(pos);
		}
	}
	
	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 "";
		}
		while(!returnKey)
		{
			try 
			{
				int character = read();
				switch(parseKey(character))
				{
					case ESCAPE_SEQUENCE:
						switch(read())
						{
							case ESC_SEQ:
								switch(read())
								{
									case FORWARD:
										moveCursorTo(line.getCursorPosition()+1);
									break;
										
									case BACKWARD:
										moveCursorTo(line.getCursorPosition()-1);
									break;
									
									case DEL:
										if(read() == TILDE)
										{
											delChar(DEL_FORWARD);
										}
									break;
										
									case INSERT_KEY:
										if(read() == TILDE)
										{
											line.toggleMode();
										}
									break;
								}
							break;
							
							case HOME_END:
								switch(read())
								{
									case HOME:
										moveCursorTo(1);
									break;
										
									case END:
										moveCursorTo(line.length()+1);
									break;
								}
							break;
						}
					break;
						
					case PRINTABLE:
						switch(character)
						{
							case RETURN_KEY:
								returnKey = true;
							break;
							
							case BACKSPACE:
							case BACKSPACE_DEL:
								delChar(DEL_BACKWARD);
							break;
															
							default:
								addChar((char)character);
							break;
						}
					break;
						
					case NON_PRINTABLE:
						//ignore
					break;
				}
				
			} 
			catch (IOException e)
			{
				System.out.println("Error reading line");
				break;
			}
		}
		try 
		{
			unsetRaw();
		} 
		catch (Exception e) 
		{
			System.out.println("Couldn't unset raw mode");
			return "";
		}
		System.out.println("");
		return line.toString();
	}
}