Package erjang.console

Source Code of erjang.console.TTYTextAreaDriverControl$Output

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2010 by Trifork
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

package erjang.console;

import java.awt.Color;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import kilim.Pausable;
import erjang.EBinary;
import erjang.EHandle;
import erjang.EObject;
import erjang.EPID;
import erjang.ERT;
import erjang.EString;
import erjang.driver.EDriverInstance;
import erjang.driver.IO;

public class TTYTextAreaDriverControl extends EDriverInstance implements
    KeyListener {

  /* The various opcodes. */
  static final int OP_PUTC = 0;
  static final int OP_MOVE = 1;
  static final int OP_INSC = 2;
  static final int OP_DELC = 3;
  static final int OP_BEEP = 4;
  /* Control op */
  static final int CTRL_OP_GET_WINSIZE = 100;
  static final int CTRL_OP_GET_UNICODE_STATE = 101;
  static final int CTRL_OP_SET_UNICODE_STATE = 102;

  static final int CONTROL_TAG = 0x10000000; /*
                         * Control character, value in
                         * first position
                         */
  static final int ESCAPED_TAG = 0x01000000; /*
                         * Escaped character, value in
                         * first position
                         */
  static final int TAG_MASK = 0xFF000000;

  static final int MAXSIZE = 1 << 16;

  private JTextPane area;
  private SimpleAttributeSet promptStyle;
  private SimpleAttributeSet inputStyle;
  private SimpleAttributeSet outputStyle;
  private SimpleAttributeSet resultStyle;
  private int startPos;
  private boolean utf8_mode = true;
  private Clipboard clipboard;
  private SimpleAttributeSet errorStyle;

  private static final int MAX_DOC_SIZE = 100000;

  public TTYTextAreaDriverControl(TTYTextAreaDriver driver, JTextPane text,
      String message) {
    super(driver);

    this.clipboard = text.getToolkit().getSystemClipboard();

    this.area = text;

    // inputJoin.send(Channel.EMPTY, null);

    text.addKeyListener(this);

    text.setAutoscrolls(true);
   
    // No editing before startPos
    if (text.getDocument() instanceof AbstractDocument)
      ((AbstractDocument) text.getDocument())
          .setDocumentFilter(new DocumentFilter() {
            public void insertString(
                DocumentFilter.FilterBypass fb, int offset,
                String string, AttributeSet attr)
                throws BadLocationException {
              if (offset >= startPos)
                super.insertString(fb, offset, string, attr);
            }

            public void remove(DocumentFilter.FilterBypass fb,
                int offset, int length)
                throws BadLocationException {
              if (offset >= startPos || offset == 0)
                super.remove(fb, offset, length);
            }

            public void replace(DocumentFilter.FilterBypass fb,
                int offset, int length, String text,
                AttributeSet attrs) throws BadLocationException {
              if (offset >= startPos)
                super.replace(fb, offset, length, text, attrs);
            }
          });

    promptStyle = new SimpleAttributeSet();
    StyleConstants.setForeground(promptStyle, new Color(0xa4, 0x00, 0x00));

    inputStyle = new SimpleAttributeSet();
    StyleConstants.setForeground(inputStyle, new Color(0x20, 0x4a, 0x87));

    outputStyle = new SimpleAttributeSet();
    StyleConstants.setForeground(outputStyle, Color.darkGray);

    errorStyle = new SimpleAttributeSet();
    StyleConstants.setForeground(errorStyle, Color.red);

    resultStyle = new SimpleAttributeSet();
    StyleConstants.setItalic(resultStyle, true);
    StyleConstants.setForeground(resultStyle, new Color(0x20, 0x4a, 0x87));

    if (message != null) {
      final MutableAttributeSet messageStyle = new SimpleAttributeSet();
      StyleConstants.setBackground(messageStyle, text.getForeground());
      StyleConstants.setForeground(messageStyle, text.getBackground());
      append(message, messageStyle);
    }

    startPos = text.getDocument().getLength();
  }

  public InputStream getInputStream() {
    return ERT.getInputStream();
  }

  public OutputStream getOutputStream() {
    return new Output(outputStyle);
  }

  public OutputStream getErrorStream() {
    return new Output(errorStyle);
  }

  class Output extends OutputStream {
   
    private AttributeSet style;

    public Output(AttributeSet style) {
      this.style = style;
    }
   
    @Override
    public void write(int b) throws IOException {
      String data = new String(new byte[] { (byte) b }, IO.UTF8);
      append(data, style);
    }
   
    @Override
    public void write(byte[] b, int off, int len) throws IOException {
      String data = new String(b,off,len,IO.UTF8);
      append(data, style);
    }
  }
 

 
  protected void append(final String toAppend, final AttributeSet style) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        try {
          Document doc = area.getDocument();
          doc.insertString(doc.getLength(), toAppend, style);
          area.setCaretPosition(doc.getLength());
//          area.select(area.getCaretPosition(), area.getCaretPosition());

          // Cut the document to fit into the MAX_DOC_SIZE.
          // See JRUBY-4237.
          int extra = doc.getLength() - MAX_DOC_SIZE;
          if (extra > 0) {
            int removeBytes = extra + MAX_DOC_SIZE / 10;
            doc.remove(0, removeBytes);
            startPos -= removeBytes;
          }
        } catch (BadLocationException e) {
        }
      }
    });
  }

  @Override
  protected void output(EHandle caller, ByteBuffer buf) throws IOException,
      Pausable {

    // if (lpos > MAXSIZE)
    // put_chars("\n");

    switch (buf.get()) {
    case OP_PUTC:
      put_chars(buf);
      break;
    case OP_MOVE:
      move_rel(buf.getShort());
      break;
    case OP_INSC:
      ins_chars(buf);
      break;
    case OP_DELC:
      del_chars(buf.getShort());
      break;
    case OP_BEEP:
      visible_beep();
      break;
    default:
      /* Unknown op, just ignore. */
      break;
    }
    return; /* TRUE; */
  }

  private void visible_beep() {
    {
      Color fg = area.getForeground();
      Color bg = area.getBackground();

      area.setForeground(bg);
      area.setBackground(fg);

      area.repaint();
      Toolkit.getDefaultToolkit().beep();

      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
      }

      area.setForeground(fg);
      area.setBackground(bg);
      area.repaint();
    }
  }

  private void del_chars(int i) {

    try {
      Document doc = area.getDocument();
      int offs = area.getCaretPosition() + i;
      doc.remove(offs, -i);
    } catch (BadLocationException e) {
    }

  }

  private void ins_chars(ByteBuffer buf) {
    final String string = new String(buf.array(), buf.arrayOffset()
        + buf.position(), buf.remaining(), IO.UTF8);

    SwingUtilities.invokeLater(new Runnable() {
      public void run() {

        try {
          Document doc = area.getDocument();
          int pos = area.getCaretPosition();
          doc.insertString(pos, string, inputStyle);
          area.setCaretPosition(pos + string.length());
          area.select(area.getCaretPosition(), area.getCaretPosition());

          // Cut the document to fit into the MAX_DOC_SIZE.
          // See JRUBY-4237.
          int extra = doc.getLength() - MAX_DOC_SIZE;
          if (extra > 0) {
            int removeBytes = extra + MAX_DOC_SIZE / 10;
            doc.remove(0, removeBytes);
            startPos -= removeBytes;
          }
        } catch (BadLocationException e) {
        }

      }
    });

  }

  private void move_rel(final int delta_pos) {
    if (delta_pos != 0) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          int curr = area.getCaretPosition();
          area.setCaretPosition(curr + delta_pos);         
          area.select(area.getCaretPosition(), area.getCaretPosition());
        }
      });
    }
  }

  private void put_chars(ByteBuffer buf) {
    String string = new String(buf.array(), buf.arrayOffset()
        + buf.position(), buf.remaining(), IO.UTF8);
    append(string, outputStyle);
  }

  private void put_chars(String string) {
    append(string, outputStyle);
  }

  @Override
  public void keyTyped(KeyEvent e) {
    e.consume();
  }

  @Override
  public void keyReleased(KeyEvent e) {
  }

  @Override
  public void keyPressed(KeyEvent event) {
    int code = event.getKeyCode();
    if (code == KeyEvent.VK_COPY
        || (code == KeyEvent.VK_C && event.isMetaDown())) {
      return;
    }

    if (code == KeyEvent.VK_PASTE
        || (code == KeyEvent.VK_V && event.isMetaDown())) {

      Transferable clipData = clipboard.getContents(clipboard);
      try {
        if (clipData.isDataFlavorSupported(DataFlavor.stringFlavor)) {
          String s = (String) (clipData
              .getTransferData(DataFlavor.stringFlavor));
          out(s);
        }
      } catch (Exception ufe) {
      }

      event.consume();
      return;
    }

    if (code == KeyEvent.VK_CUT
        || (code == KeyEvent.VK_X && event.isMetaDown())) {
      event.consume();
      visible_beep();
      return;
    }

   
   
    event.consume();
    switch (code) {
    case KeyEvent.VK_TAB:
      out('\t');
      return;
    case KeyEvent.VK_ESCAPE:
      out_byte((byte) 27);
      return;

    case KeyEvent.VK_LEFT:
      out_ctrl('b');
      return;
    case KeyEvent.VK_DELETE:
      out_ctrl('d');
      return;
    case KeyEvent.VK_RIGHT:
      out_ctrl('f');
      return;
    case KeyEvent.VK_BACK_SPACE:
      out_ctrl('h');
      return;
    case KeyEvent.VK_ENTER:
      out_ctrl('j');
      return;
    case KeyEvent.VK_DOWN:
      out_ctrl('n');
      return;
    case KeyEvent.VK_UP:
      out_ctrl('p');
      return;
    }

    if (event.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
    //  System.err.println("ignored key event: " + event);
      return;
    }

    if ((event.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
    //  System.err.println("ctrl event: " + event);
      if (code >= KeyEvent.VK_A && code <= KeyEvent.VK_Z) {
        out_ctrl('a' + code - KeyEvent.VK_A);
      }

    } else {
      out(event.getKeyChar());
    }
  }

  private void out_ctrl(int i) {
    if (i >= 'a' && i <= 'z') {
      out_byte((byte) ((i - 'a') + 1));
    }
  }

  private void out_byte(int b) {
    ByteBuffer buf = ByteBuffer.wrap(new byte[] { (byte) b });
    EObject out;

    if (task.send_binary_data()) {
      out = EBinary.make(buf);
    } else {
      out = EString.make(buf);
    }

    task.output_from_driver_b(out);
  }

  private void out(char ch) {
    String string = new String(new char[] { ch });
    out(string);
  }

  private void out(String string) {
    byte[] bytes = string.getBytes(IO.UTF8);
    ByteBuffer buf = ByteBuffer.wrap(bytes);

    // driver_output(bb);

    EObject out;

    if (task.send_binary_data()) {
      out = EBinary.make(buf);
    } else {
      out = EString.make(buf);
    }

    task.output_from_driver_b(out);
  }

  @Override
  protected ByteBuffer control(EPID pid, int command, ByteBuffer cmd)
      throws Pausable {

    if (command == CTRL_OP_GET_WINSIZE) {
      ByteBuffer rep = ByteBuffer.allocate(8);
      rep.order(ByteOrder.nativeOrder());

      rep.putInt(80);
      rep.putInt(25);
      return rep;

    } else if (command == CTRL_OP_GET_UNICODE_STATE) {
      ByteBuffer rep = ByteBuffer.allocate(1);
      rep.put((byte) (utf8_mode ? 1 : 0));
      return rep;

    } else if (command == CTRL_OP_SET_UNICODE_STATE && cmd.remaining() == 1) {
      ByteBuffer rep = ByteBuffer.allocate(1);
      rep.put((byte) (utf8_mode ? 1 : 0));
      utf8_mode = cmd.get() == 0 ? false : true;
      return rep;
    } else {
      return null;
    }

  }
}
TOP

Related Classes of erjang.console.TTYTextAreaDriverControl$Output

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.