EditableBufferedReader.java 4.69 KB
package pad.prac1;
import java.io.*;
import java.util.Scanner;
import java.util.regex.Pattern;


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 GOTO			= 0x48;
	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 EOF				= 0x04;
	public static final int LINE_FEED		= 0x0A;
	
	private Console console = new Console();
	private Line line = new Line(console);
	private boolean endOfFile 	= 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 void parseKey() throws IOException
	{
		Pattern pattern;
		Scanner scanner = new Scanner(System.in);
		pattern = Pattern.compile("(.{1})");
		if(scanner.findWithinHorizon(pattern,0) != null)
		{
			int character = (int)scanner.match().group(1).charAt(0);
			if(character >= 0x20 || character == EOF || character == BACKSPACE || character == RETURN_KEY)
			{
		        switch(character)
		        {
					case EOF:
						endOfFile = true;
					break;
					
					case BACKSPACE:
					case BACKSPACE_DEL:
						line.delChar(DEL_BACKWARD);
					break;
							
					case RETURN_KEY:
						character = LINE_FEED;
					default:
						line.addChar((char)character);
					break;
		        }
		        return;
			}
		}
        pattern = Pattern.compile("\\^\\[\\[(.{1}).*");
        if(scanner.findWithinHorizon(pattern,3) != null) //escape sequence
        {
        	int character = scanner.match().group(1).charAt(0);
        	switch(character)
        	{
		        case FORWARD:
					line.setCursorTo(line.getCursorPosition()+1);
				break;
					
				case BACKWARD:
					line.setCursorTo(line.getCursorPosition()-1);
				break;
				
				case DEL:
					line.delChar(DEL_FORWARD);
				break;
					
				case INSERT_KEY:
					line.toggleMode();
				break;
        	}
        	return;
        }
        pattern = Pattern.compile("\\^\\[O(\\w{1})");
        if(scanner.findWithinHorizon(pattern,3) != null) //HOME or END
        {
        	
        	int character = (int)scanner.match().group(1).charAt(0);
        	switch(character)
        	{
	        	case HOME:
					line.setCursorTo(1);
				break;
					
				case END:
					line.setCursorTo(line.length()+1);
				break;
        	}
        	return;
        }
	}
	
	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 "";
		}
		try
		{
			while(!endOfFile)
			{
				parseKey();
			}
		}
		catch(Exception e)
		{
			System.out.println("Error reading line");
			return "";
		}
		try 
		{
			unsetRaw();
		} 
		catch (Exception e) 
		{
			System.out.println("Couldn't unset raw mode");
			return "";
		}
		System.out.println("");
		return line.toString();
	}
}


/* 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
 */