mirror of
https://github.com/sethm/symon.git
synced 2025-03-26 21:30:30 +00:00
implement jterminal in source
This commit is contained in:
parent
18ce120984
commit
be72c2ff09
5
.settings/org.eclipse.core.resources.prefs
Normal file
5
.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,5 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/main/resources=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
encoding/<project>=UTF-8
|
5
.settings/org.eclipse.jdt.core.prefs
Normal file
5
.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,5 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
4
.settings/org.eclipse.m2e.core.prefs
Normal file
4
.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal;
|
||||
|
||||
/**
|
||||
* A {@link TerminalModel} which implements some common behaviour.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public abstract class AbstractTerminalModel implements TerminalModel {
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
int rows = getRows(), columns = getColumns();
|
||||
for (int column = 0; column < columns; column++) {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
setCell(column, row, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorBack(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
}
|
||||
int cursorColumn = getCursorColumn() - n;
|
||||
if (cursorColumn < 0) {
|
||||
cursorColumn = 0;
|
||||
}
|
||||
setCursorColumn(cursorColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorForward(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
}
|
||||
int columns = getColumns();
|
||||
int cursorColumn = getCursorColumn() + n;
|
||||
if (cursorColumn >= columns) {
|
||||
cursorColumn = columns - 1;
|
||||
}
|
||||
setCursorColumn(cursorColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorDown(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
}
|
||||
int bufferSize = getBufferSize();
|
||||
int cursorRow = getCursorRow() + n;
|
||||
if (cursorRow >= bufferSize) {
|
||||
cursorRow = bufferSize - 1;
|
||||
}
|
||||
setCursorRow(cursorRow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveCursorUp(int n) {
|
||||
if (n < 0) {
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
}
|
||||
int cursorRow = getCursorRow() - n;
|
||||
if (cursorRow < 0) {
|
||||
cursorRow = 0;
|
||||
}
|
||||
setCursorRow(cursorRow);
|
||||
}
|
||||
|
||||
}
|
||||
|
198
src/main/java/com/loomcom/symon/jterminal/JTerminal.java
Normal file
198
src/main/java/com/loomcom/symon/jterminal/JTerminal.java
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com>
|
||||
* Portions Copyright (c) 2009-2011 Graham Edgecombe
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal;
|
||||
|
||||
import com.loomcom.symon.jterminal.vt100.Vt100TerminalModel;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.AdjustmentEvent;
|
||||
import java.awt.event.AdjustmentListener;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollBar;
|
||||
|
||||
/**
|
||||
* Swing terminal emulation component
|
||||
* @author Seth J. Morabito
|
||||
*
|
||||
*/
|
||||
public class JTerminal extends JComponent {
|
||||
|
||||
private static final long serialVersionUID = 2871625194146986567L;
|
||||
|
||||
private int borderWidth = 0;
|
||||
|
||||
private JScrollBar scrollBar;
|
||||
|
||||
/**
|
||||
* The terminal emulation model
|
||||
*/
|
||||
private TerminalModel model;
|
||||
|
||||
/**
|
||||
* The font this terminal uses
|
||||
*/
|
||||
private Font font;
|
||||
|
||||
/**
|
||||
* The cell width in pixels
|
||||
*/
|
||||
private int cellWidth;
|
||||
|
||||
/**
|
||||
* The cell height in pixels
|
||||
*/
|
||||
private int cellHeight;
|
||||
|
||||
/**
|
||||
* Max descender for font
|
||||
*/
|
||||
private int maxDescender;
|
||||
|
||||
public JTerminal(Font font) {
|
||||
this(new Vt100TerminalModel(), font);
|
||||
}
|
||||
|
||||
public JTerminal(TerminalModel model, Font font) {
|
||||
setModel(model);
|
||||
setFont(font);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setBorderWidth(int borderWidth) {
|
||||
this.borderWidth = borderWidth;
|
||||
revalidate();
|
||||
}
|
||||
|
||||
public int getBorderWidth() {
|
||||
return borderWidth;
|
||||
}
|
||||
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
setCellWidthAndHeight(font);
|
||||
revalidate();
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setModel(TerminalModel model) {
|
||||
if (model == null) {
|
||||
throw new NullPointerException("model");
|
||||
}
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public TerminalModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void println(String str) {
|
||||
if (str == null) {
|
||||
throw new NullPointerException("str");
|
||||
}
|
||||
print(str.concat("\r\n"));
|
||||
}
|
||||
|
||||
public void print(String str) {
|
||||
model.print(str);
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(model.getColumns() * cellWidth + borderWidth * 2,
|
||||
model.getRows() * cellHeight + borderWidth * 2);
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
|
||||
public void paint(Graphics g) {
|
||||
g.setFont(font);
|
||||
|
||||
int width = model.getColumns();
|
||||
int height = model.getBufferSize();
|
||||
|
||||
g.setColor(model.getDefaultBackgroundColor());
|
||||
g.fillRect(0, 0, width * cellWidth + borderWidth * 2, height * cellHeight + borderWidth * 2);
|
||||
|
||||
int start = scrollBar == null ? 0 : scrollBar.getValue();
|
||||
for (int y = start; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
TerminalCell cell = model.getCell(x, y);
|
||||
boolean cursorHere = (model.getCursorRow() == y) && (model.getCursorColumn() == x);
|
||||
|
||||
if ((cursorHere) && (cell == null)) {
|
||||
cell = new TerminalCell(' ', model.getDefaultBackgroundColor(), model.getDefaultForegroundColor());
|
||||
}
|
||||
|
||||
if (cell != null) {
|
||||
int px = x * cellWidth + borderWidth;
|
||||
int py = (y - start) * cellHeight + borderWidth;
|
||||
|
||||
g.setColor(cursorHere ? cell.getForegroundColor() : cell.getBackgroundColor());
|
||||
g.fillRect(px, py, cellWidth, cellHeight);
|
||||
|
||||
g.setColor(cursorHere ? cell.getBackgroundColor() : cell.getForegroundColor());
|
||||
g.drawChars(new char[] { cell.getCharacter() }, 0, 1, px, py + cellHeight - maxDescender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setLayout(new BorderLayout(0, 0));
|
||||
|
||||
int rows = model.getRows();
|
||||
int bufferSize = model.getBufferSize();
|
||||
|
||||
if (bufferSize > rows) {
|
||||
scrollBar = new JScrollBar(1, 0, rows, 0, bufferSize + 1);
|
||||
scrollBar.addAdjustmentListener(new AdjustmentListener() {
|
||||
public void adjustmentValueChanged(AdjustmentEvent evt) {
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
add("After", scrollBar);
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void setCellWidthAndHeight(Font font) {
|
||||
FontMetrics metrics = getFontMetrics(font);
|
||||
cellWidth = metrics.charWidth('W');
|
||||
cellHeight = metrics.getHeight();
|
||||
maxDescender = metrics.getMaxDescent();
|
||||
}
|
||||
}
|
96
src/main/java/com/loomcom/symon/jterminal/TerminalCell.java
Normal file
96
src/main/java/com/loomcom/symon/jterminal/TerminalCell.java
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Represents a single terminal cell which contains a character, background
|
||||
* color and foreground color.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class TerminalCell {
|
||||
|
||||
/**
|
||||
* The character.
|
||||
*/
|
||||
private final char character;
|
||||
|
||||
/**
|
||||
* The background color.
|
||||
*/
|
||||
private final Color backgroundColor;
|
||||
|
||||
/**
|
||||
* The foreground color.
|
||||
*/
|
||||
private final Color foregroundColor;
|
||||
|
||||
/**
|
||||
* Creates a terminal cell with the specified character, background color
|
||||
* and foreground color.
|
||||
* @param character The character.
|
||||
* @param backgroundColor The background color.
|
||||
* @param foregroundColor The foreground color.
|
||||
* @throws NullPointerException if the background or foreground color(s)
|
||||
* are {@code null}.
|
||||
*/
|
||||
public TerminalCell(char character, Color backgroundColor, Color foregroundColor) {
|
||||
if (backgroundColor == null) {
|
||||
throw new NullPointerException("backgroundColor");
|
||||
}
|
||||
if (foregroundColor == null) {
|
||||
throw new NullPointerException("foregroundColor");
|
||||
}
|
||||
|
||||
this.character = character;
|
||||
this.backgroundColor = backgroundColor;
|
||||
this.foregroundColor = foregroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character.
|
||||
* @return The character.
|
||||
*/
|
||||
public char getCharacter() {
|
||||
return character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the background color.
|
||||
* @return The background color.
|
||||
*/
|
||||
public Color getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the foreground color.
|
||||
* @return The foreground color.
|
||||
*/
|
||||
public Color getForegroundColor() {
|
||||
return foregroundColor;
|
||||
}
|
||||
|
||||
}
|
||||
|
167
src/main/java/com/loomcom/symon/jterminal/TerminalModel.java
Normal file
167
src/main/java/com/loomcom/symon/jterminal/TerminalModel.java
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import com.loomcom.symon.jterminal.bell.BellStrategy;
|
||||
|
||||
/**
|
||||
* Model for terminals - defines methods for getting/setting cells, printing
|
||||
* text to a terminal and getting the size of the terminal and buffer.
|
||||
*/
|
||||
public interface TerminalModel {
|
||||
|
||||
/**
|
||||
* Gets the bell strategy.
|
||||
* @return The bell strategy.
|
||||
*/
|
||||
public BellStrategy getBellStrategy();
|
||||
|
||||
/**
|
||||
* Sets the bell strategy.
|
||||
* @param strategy The bell strategy.
|
||||
* @throws NullPointerException if the strategy is {@code null}.
|
||||
*/
|
||||
public void setBellStrategy(BellStrategy strategy);
|
||||
|
||||
/**
|
||||
* Clears the terminal.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Moves the cursor back n characters.
|
||||
* @param n The number of characters.
|
||||
* @throws IllegalArgumentException if n is not positive.
|
||||
*/
|
||||
public void moveCursorBack(int n);
|
||||
|
||||
/**
|
||||
* Moves the cursor forward n characters.
|
||||
* @param n The number of characters.
|
||||
* @throws IllegalArgumentException if n is not positive.
|
||||
*/
|
||||
public void moveCursorForward(int n);
|
||||
|
||||
/**
|
||||
* Moves the cursor down n characters.
|
||||
* @param n The number of characters.
|
||||
* @throws IllegalArgumentException if n is not positive.
|
||||
*/
|
||||
public void moveCursorDown(int n);
|
||||
|
||||
/**
|
||||
* Moves the cursor up n characters.
|
||||
* @param n The number of characters.
|
||||
* @throws IllegalArgumentException if n is not positive.
|
||||
*/
|
||||
public void moveCursorUp(int n);
|
||||
|
||||
/**
|
||||
* Sets a cell.
|
||||
* @param column The column.
|
||||
* @param row The row.
|
||||
* @param cell The cell.
|
||||
* @throws IndexOutOfBoundsException if the column and/or row number(s) are
|
||||
* out of bounds.
|
||||
*/
|
||||
public void setCell(int column, int row, TerminalCell cell);
|
||||
|
||||
/**
|
||||
* Gets a cell.
|
||||
* @param column The column.
|
||||
* @param row The row.
|
||||
* @return The cell.
|
||||
* @throws IndexOutOfBoundsException if the column and/or row number(s) are
|
||||
* out of bounds.
|
||||
*/
|
||||
public TerminalCell getCell(int column, int row);
|
||||
|
||||
/**
|
||||
* Prints the specified string to the terminal at the cursor position,
|
||||
* interpreting any escape sequences/special ASCII codes the model may
|
||||
* support. Lines will be wrapped if necessary.
|
||||
* @param str The string to print.
|
||||
* @throws NullPointerException if the string is {@code null}.
|
||||
*/
|
||||
public void print(String str);
|
||||
|
||||
/**
|
||||
* Gets the number of columns.
|
||||
* @return The number of columns.
|
||||
*/
|
||||
public int getColumns();
|
||||
|
||||
/**
|
||||
* Gets the number of rows.
|
||||
* @return The number of rows.
|
||||
*/
|
||||
public int getRows();
|
||||
|
||||
/**
|
||||
* Gets the buffer size.
|
||||
* @return The buffer size.
|
||||
*/
|
||||
public int getBufferSize();
|
||||
|
||||
/**
|
||||
* Gets the cursor row.
|
||||
* @return The cursor row.
|
||||
*/
|
||||
public int getCursorRow();
|
||||
|
||||
/**
|
||||
* Sets the cursor row.
|
||||
* @param row The cursor row.
|
||||
* @throws IllegalArgumentException if the row is out of the valid range.
|
||||
*/
|
||||
public void setCursorRow(int row);
|
||||
|
||||
/**
|
||||
* Gets the cursor column.
|
||||
* @return The cursor column.
|
||||
*/
|
||||
public int getCursorColumn();
|
||||
|
||||
/**
|
||||
* Sets the cursor column.
|
||||
* @param column The cursor column.
|
||||
* @throws IllegalArgumentException if the column is out of the valid range.
|
||||
*/
|
||||
public void setCursorColumn(int column);
|
||||
|
||||
/**
|
||||
* Gets the default background color.
|
||||
* @return The default background color.
|
||||
*/
|
||||
public Color getDefaultBackgroundColor();
|
||||
|
||||
/**
|
||||
* Gets the default foreground color.
|
||||
* @return The default foreground color.
|
||||
*/
|
||||
public Color getDefaultForegroundColor();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.bell;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
|
||||
/**
|
||||
* A {@link BellStrategy} which calls {@link Toolkit#beep()}.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class BeepBellStrategy implements BellStrategy {
|
||||
|
||||
@Override
|
||||
public void soundBell() {
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.bell;
|
||||
|
||||
/**
|
||||
* A 'strategy' used to sound the bell (US-ASCII character {@code 7}).
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public interface BellStrategy {
|
||||
|
||||
/**
|
||||
* Sounds the bell.
|
||||
*/
|
||||
public void soundBell();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.bell;
|
||||
|
||||
/**
|
||||
* A {@link BellStrategy} which does nothing.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class NopBellStrategy implements BellStrategy {
|
||||
|
||||
@Override
|
||||
public void soundBell() {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains bell strategy classes, which define how an application should
|
||||
* respond to the US-ASCII {@code BEL} character.
|
||||
*/
|
||||
package com.loomcom.symon.jterminal.bell;
|
||||
|
27
src/main/java/com/loomcom/symon/jterminal/package-info.java
Normal file
27
src/main/java/com/loomcom/symon/jterminal/package-info.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains core JTerminal classes.
|
||||
*/
|
||||
package com.loomcom.symon.jterminal;
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.vt100;
|
||||
|
||||
/**
|
||||
* Represents an ANSI control sequence.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class AnsiControlSequence {
|
||||
|
||||
/**
|
||||
* The command character.
|
||||
*/
|
||||
private final char command;
|
||||
|
||||
/**
|
||||
* The parameters.
|
||||
*/
|
||||
private final String[] parameters;
|
||||
|
||||
/**
|
||||
* Creates an ANSI control sequence with the specified command and
|
||||
* parameters.
|
||||
* @param command The command character.
|
||||
* @param parameters The parameters array.
|
||||
* @throws NullPointerException if the parameters array is {@code null}.
|
||||
*/
|
||||
public AnsiControlSequence(char command, String[] parameters) {
|
||||
if (parameters == null) {
|
||||
throw new NullPointerException("parameters");
|
||||
}
|
||||
this.command = command;
|
||||
if (parameters.length == 1 && parameters[0].equals("")) {
|
||||
this.parameters = new String[0];
|
||||
} else {
|
||||
this.parameters = parameters.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command character.
|
||||
* @return The command character.
|
||||
*/
|
||||
public char getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameters array.
|
||||
* @return The parameters array.
|
||||
*/
|
||||
public String[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.vt100;
|
||||
|
||||
/**
|
||||
* An interface which classes may use to listen to events from a
|
||||
* {@link AnsiControlSequenceParser}.
|
||||
*/
|
||||
public interface AnsiControlSequenceListener {
|
||||
|
||||
/**
|
||||
* Called when a control sequence has been parsed.
|
||||
* @param seq The control sequence.
|
||||
*/
|
||||
public void parsedControlSequence(AnsiControlSequence seq);
|
||||
|
||||
/**
|
||||
* Called when a string has been parsed.
|
||||
* @param str The string.
|
||||
*/
|
||||
public void parsedString(String str);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.vt100;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/**
|
||||
* A class which parses {@link AnsiControlSequence}s from {@link String}(s).
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class AnsiControlSequenceParser {
|
||||
|
||||
/**
|
||||
* The multi-byte control sequence introducer.
|
||||
*/
|
||||
private static final char[] MULTI_CSI = new char[] { 27, '[' };
|
||||
|
||||
/**
|
||||
* The single-byte control sequence introducer.
|
||||
*/
|
||||
private static final char SINGLE_CSI = 155;
|
||||
|
||||
/**
|
||||
* The buffer of data from the last call to {@link #parse()}. This is
|
||||
* populated with data if an escape sequence is not complete.
|
||||
*/
|
||||
private StringBuilder buffer = new StringBuilder();
|
||||
|
||||
/**
|
||||
* The ANSI control sequence listener.
|
||||
*/
|
||||
private final AnsiControlSequenceListener listener;
|
||||
|
||||
/**
|
||||
* Creates the ANSI control sequence parser.
|
||||
* @param listener The listener.
|
||||
*/
|
||||
public AnsiControlSequenceParser(AnsiControlSequenceListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified string.
|
||||
* @param str The string to parse.
|
||||
*/
|
||||
public void parse(String str) {
|
||||
if (buffer.length() > 0) {
|
||||
str = buffer.toString().concat(str);
|
||||
buffer = new StringBuilder();
|
||||
}
|
||||
Reader reader = new StringReader(str);
|
||||
try {
|
||||
try {
|
||||
parse(reader);
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses characters from the specified character reader.
|
||||
* @param reader The character reader.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
private void parse(Reader reader) throws IOException {
|
||||
StringBuilder text = new StringBuilder();
|
||||
int character;
|
||||
while ((character = reader.read()) != -1) {
|
||||
boolean introducedControlSequence = false;
|
||||
if (character == SINGLE_CSI) {
|
||||
introducedControlSequence = true;
|
||||
} else if (character == MULTI_CSI[0]) {
|
||||
int nextCharacter = reader.read();
|
||||
if (nextCharacter == -1) {
|
||||
buffer.append((char) character);
|
||||
break;
|
||||
} else if (nextCharacter == MULTI_CSI[1]) {
|
||||
introducedControlSequence = true;
|
||||
} else {
|
||||
text.append((char) character);
|
||||
text.append((char) nextCharacter);
|
||||
}
|
||||
} else {
|
||||
text.append((char) character);
|
||||
}
|
||||
|
||||
if (introducedControlSequence) {
|
||||
if (text.length() > 0) {
|
||||
listener.parsedString(text.toString());
|
||||
text = new StringBuilder();
|
||||
}
|
||||
parseControlSequence(reader);
|
||||
}
|
||||
}
|
||||
|
||||
if (text.length() > 0) {
|
||||
listener.parsedString(text.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a control sequence.
|
||||
* @param reader The character reader.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
private void parseControlSequence(Reader reader) throws IOException {
|
||||
boolean finishedSequence = false;
|
||||
StringBuilder parameters = new StringBuilder();
|
||||
int character;
|
||||
while ((character = reader.read()) != -1) {
|
||||
if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z')) {
|
||||
String[] array = parameters.toString().split(";");
|
||||
AnsiControlSequence seq = new AnsiControlSequence((char) character, array);
|
||||
listener.parsedControlSequence(seq);
|
||||
|
||||
finishedSequence = true;
|
||||
break;
|
||||
} else {
|
||||
parameters.append((char) character);
|
||||
}
|
||||
}
|
||||
if (!finishedSequence) {
|
||||
// not an ideal solution if they used the two byte CSI, but it's
|
||||
// easier and cleaner than keeping track of it
|
||||
buffer.append((char) SINGLE_CSI);
|
||||
buffer.append(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.vt100;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Contains colors used by the SGR ANSI escape sequence.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
final class SgrColor {
|
||||
|
||||
/**
|
||||
* An array of normal intensity colors.
|
||||
*/
|
||||
public static final Color[] COLOR_NORMAL = new Color[] {
|
||||
new Color(0, 0, 0),
|
||||
new Color(128, 0, 0),
|
||||
new Color(0, 128, 0),
|
||||
new Color(128, 128, 0),
|
||||
new Color(0, 0, 128),
|
||||
new Color(128, 0, 128),
|
||||
new Color(0, 128, 128),
|
||||
new Color(192, 192, 192)
|
||||
};
|
||||
|
||||
/**
|
||||
* An array of bright intensity colors.
|
||||
*/
|
||||
public static final Color[] COLOR_BRIGHT = new Color[] {
|
||||
new Color(128, 128, 128),
|
||||
new Color(255, 0, 0),
|
||||
new Color(0, 255, 0),
|
||||
new Color(255, 255, 0),
|
||||
new Color(0, 0, 255),
|
||||
new Color(0, 0, 255),
|
||||
new Color(255, 0, 255),
|
||||
new Color(0, 255, 255),
|
||||
new Color(255, 255, 255)
|
||||
};
|
||||
|
||||
/**
|
||||
* Default private constructor to prevent instantiation.
|
||||
*/
|
||||
private SgrColor() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,493 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon.jterminal.vt100;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import com.loomcom.symon.jterminal.AbstractTerminalModel;
|
||||
import com.loomcom.symon.jterminal.TerminalCell;
|
||||
import com.loomcom.symon.jterminal.TerminalModel;
|
||||
import com.loomcom.symon.jterminal.bell.BellStrategy;
|
||||
import com.loomcom.symon.jterminal.bell.NopBellStrategy;
|
||||
|
||||
/**
|
||||
* A VT100/ANSI-compatible terminal model.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class Vt100TerminalModel extends AbstractTerminalModel {
|
||||
|
||||
/**
|
||||
* A {@link AnsiControlSequenceListener} which modifies the
|
||||
* {@link TerminalModel} appropriately when an event happens.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
private class Vt100Listener implements AnsiControlSequenceListener {
|
||||
|
||||
/**
|
||||
* The saved cursor row.
|
||||
*/
|
||||
private int savedCursorRow = -1;
|
||||
|
||||
/**
|
||||
* The saved cursor column.
|
||||
*/
|
||||
private int savedCursorColumn = -1;
|
||||
|
||||
@Override
|
||||
public void parsedControlSequence(AnsiControlSequence seq) {
|
||||
char command = seq.getCommand();
|
||||
String[] parameters = seq.getParameters();
|
||||
|
||||
switch (command) {
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
int n = 1;
|
||||
if (parameters.length == 1) {
|
||||
n = Integer.parseInt(parameters[0]);
|
||||
}
|
||||
if (command == 'A') {
|
||||
moveCursorUp(n);
|
||||
} else if (command == 'B') {
|
||||
moveCursorDown(n);
|
||||
} else if (command == 'C') {
|
||||
moveCursorForward(n);
|
||||
} else if (command == 'D') {
|
||||
moveCursorBack(n);
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
case 'F':
|
||||
n = 1;
|
||||
if (parameters.length == 1) {
|
||||
n = Integer.parseInt(parameters[0]);
|
||||
}
|
||||
if (command == 'E') {
|
||||
moveCursorDown(n);
|
||||
} else if (command == 'F') {
|
||||
moveCursorUp(n);
|
||||
}
|
||||
setCursorColumn(0);
|
||||
break;
|
||||
case 'G':
|
||||
if (parameters.length == 1) {
|
||||
n = Integer.parseInt(parameters[0]);
|
||||
setCursorColumn(n - 1);
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
case 'f':
|
||||
if (parameters.length == 2) {
|
||||
n = 1;
|
||||
int m = 1;
|
||||
if (parameters[0].length() > 0) {
|
||||
n = Integer.parseInt(parameters[0]);
|
||||
}
|
||||
if (parameters[1].length() > 0) {
|
||||
m = Integer.parseInt(parameters[1]);
|
||||
}
|
||||
setCursorRow(n - 1);
|
||||
setCursorColumn(m - 1);
|
||||
}
|
||||
break;
|
||||
case 'J':
|
||||
n = 0;
|
||||
if (parameters.length == 1) {
|
||||
n = Integer.parseInt(parameters[0]);
|
||||
}
|
||||
if (n == 0) {
|
||||
int row = cursorRow;
|
||||
int column = cursorColumn;
|
||||
while(row < rows) {
|
||||
while(column < columns) {
|
||||
cells[row][column] = null;
|
||||
column++;
|
||||
}
|
||||
column = 0;
|
||||
row++;
|
||||
}
|
||||
} else if (n == 1) {
|
||||
int row = cursorRow;
|
||||
int column = cursorColumn;
|
||||
while(row >= 0) {
|
||||
while(column >= 0) {
|
||||
cells[row][column] = null;
|
||||
column--;
|
||||
}
|
||||
column = columns - 1;
|
||||
row--;
|
||||
}
|
||||
} else if (n == 2) {
|
||||
clear();
|
||||
}
|
||||
break;
|
||||
case 'K':
|
||||
n = 0;
|
||||
if (parameters.length == 1) {
|
||||
n = Integer.parseInt(parameters[0]);
|
||||
}
|
||||
if (n == 0) {
|
||||
for (int row = cursorRow; row < rows; row++) {
|
||||
cells[row][cursorColumn] = null;
|
||||
}
|
||||
} else if (n == 1) {
|
||||
for (int row = cursorRow; row >= 0; row--) {
|
||||
cells[row][cursorColumn] = null;
|
||||
}
|
||||
} else if (n == 2) {
|
||||
for (int column = 0; column < columns; column++) {
|
||||
cells[cursorRow][column] = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (parameters.length == 0) {
|
||||
parameters = new String[] { "0" };
|
||||
}
|
||||
for (String parameter : parameters) {
|
||||
if (parameter.equals("0")) {
|
||||
foregroundColor = DEFAULT_FOREGROUND_COLOR;
|
||||
backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
||||
backgroundBold = DEFAULT_BACKGROUND_BOLD;
|
||||
foregroundBold = DEFAULT_FOREGROUND_BOLD;
|
||||
} else if (parameter.equals("2")) {
|
||||
backgroundBold = true;
|
||||
foregroundBold = true;
|
||||
} else if (parameter.equals("22")) {
|
||||
backgroundBold = false;
|
||||
foregroundBold = false;
|
||||
} else if ((parameter.startsWith("3") || parameter.startsWith("4")) && parameter.length() == 2) {
|
||||
int color = Integer.parseInt(parameter.substring(1));
|
||||
if (parameter.startsWith("3")) {
|
||||
foregroundColor = color;
|
||||
} else if (parameter.startsWith("4")) {
|
||||
backgroundColor = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
if (savedCursorColumn != -1 && savedCursorRow != -1) {
|
||||
cursorColumn = savedCursorColumn;
|
||||
cursorRow = savedCursorRow;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
savedCursorColumn = cursorColumn;
|
||||
savedCursorRow = cursorRow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parsedString(String str) {
|
||||
for (char ch : str.toCharArray()) {
|
||||
switch (ch) {
|
||||
case '\0':
|
||||
continue;
|
||||
case '\r':
|
||||
cursorColumn = 0;
|
||||
continue;
|
||||
case '\n':
|
||||
cursorRow++;
|
||||
break;
|
||||
case '\t':
|
||||
while ((++cursorColumn % TAB_WIDTH) != 0);
|
||||
continue;
|
||||
case 127:
|
||||
if (cursorColumn > 0) {
|
||||
cells[cursorRow][--cursorColumn] = null;
|
||||
}
|
||||
continue;
|
||||
case 7:
|
||||
bellStrategy.soundBell();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cursorColumn >= columns) {
|
||||
cursorColumn = 0;
|
||||
cursorRow++;
|
||||
}
|
||||
|
||||
if (cursorRow >= bufferSize) {
|
||||
for (int i = 1; i < bufferSize; i++) {
|
||||
System.arraycopy(cells[i], 0, cells[i - 1], 0, columns);
|
||||
}
|
||||
for (int i = 0; i < columns; i++) {
|
||||
cells[bufferSize - 1][i] = null;
|
||||
}
|
||||
cursorRow--;
|
||||
}
|
||||
|
||||
Color back = backgroundBold ? SgrColor.COLOR_BRIGHT[backgroundColor] : SgrColor.COLOR_NORMAL[backgroundColor];
|
||||
Color fore = foregroundBold ? SgrColor.COLOR_BRIGHT[foregroundColor] : SgrColor.COLOR_NORMAL[foregroundColor];
|
||||
if (ch != '\n') {
|
||||
cells[cursorRow][cursorColumn++] = new TerminalCell(ch, back, fore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The default number of columns.
|
||||
*/
|
||||
private static final int DEFAULT_COLUMNS = 80;
|
||||
|
||||
/**
|
||||
* The default number of rows.
|
||||
*/
|
||||
private static final int DEFAULT_ROWS = 25;
|
||||
|
||||
/**
|
||||
* The tab width in characters.
|
||||
*/
|
||||
private static final int TAB_WIDTH = 8;
|
||||
|
||||
/**
|
||||
* The default foreground bold flag.
|
||||
*/
|
||||
private static final boolean DEFAULT_FOREGROUND_BOLD = false;
|
||||
|
||||
/**
|
||||
* The default background bold flag.
|
||||
*/
|
||||
private static final boolean DEFAULT_BACKGROUND_BOLD = false;
|
||||
|
||||
/**
|
||||
* The default foreground color.
|
||||
*/
|
||||
private static final int DEFAULT_FOREGROUND_COLOR = 7;
|
||||
|
||||
/**
|
||||
* The default background color.
|
||||
*/
|
||||
private static final int DEFAULT_BACKGROUND_COLOR = 0;
|
||||
|
||||
/**
|
||||
* The ANSI control sequence listener.
|
||||
*/
|
||||
private final AnsiControlSequenceListener listener = this.new Vt100Listener();
|
||||
|
||||
/**
|
||||
* The ANSI control sequence parser.
|
||||
*/
|
||||
private final AnsiControlSequenceParser parser = new AnsiControlSequenceParser(listener);
|
||||
|
||||
/**
|
||||
* The current bell strategy.
|
||||
*/
|
||||
private BellStrategy bellStrategy = new NopBellStrategy();
|
||||
|
||||
/**
|
||||
* The array of cells.
|
||||
*/
|
||||
private TerminalCell[][] cells;
|
||||
|
||||
/**
|
||||
* The number of columns.
|
||||
*/
|
||||
private int columns;
|
||||
|
||||
/**
|
||||
* The number of rows.
|
||||
*/
|
||||
private int rows;
|
||||
|
||||
/**
|
||||
* The buffer size.
|
||||
*/
|
||||
private int bufferSize;
|
||||
|
||||
/**
|
||||
* The cursor row.
|
||||
*/
|
||||
private int cursorRow = 0;
|
||||
|
||||
/**
|
||||
* The cursor column.
|
||||
*/
|
||||
private int cursorColumn = 0;
|
||||
|
||||
/**
|
||||
* The current foreground bold flag.
|
||||
*/
|
||||
private boolean foregroundBold = DEFAULT_FOREGROUND_BOLD;
|
||||
|
||||
/**
|
||||
* The current background bold flag.
|
||||
*/
|
||||
private boolean backgroundBold = DEFAULT_BACKGROUND_BOLD;
|
||||
|
||||
/**
|
||||
* The current foreground color.
|
||||
*/
|
||||
private int foregroundColor = DEFAULT_FOREGROUND_COLOR;
|
||||
|
||||
/**
|
||||
* The current background color.
|
||||
*/
|
||||
private int backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
||||
|
||||
/**
|
||||
* Creates the terminal model with the default number of columns and rows,
|
||||
* and the default buffer size.
|
||||
*/
|
||||
public Vt100TerminalModel() {
|
||||
this(DEFAULT_COLUMNS, DEFAULT_ROWS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the terminal model with the specified number of columns and
|
||||
* rows. The buffer size is set to the number of rows.
|
||||
* @param columns The number of columns.
|
||||
* @param rows The number of rows.
|
||||
* @throws IllegalArgumentException if the number of rows or columns is
|
||||
* negative.
|
||||
*/
|
||||
public Vt100TerminalModel(int columns, int rows) {
|
||||
this(columns, rows, rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the terminal model with the specified number of columns and rows
|
||||
* and the specified buffer size.
|
||||
* @param columns The number of columns.
|
||||
* @param rows The number of rows.
|
||||
* @param bufferSize The buffer size.
|
||||
* @throws IllegalArgumentException if the number of rows or columns is
|
||||
* negative, or if the buffer size is less than the number of rows.
|
||||
*/
|
||||
public Vt100TerminalModel(int columns, int rows, int bufferSize) {
|
||||
if (columns < 0 || rows < 0 || bufferSize < 0) {
|
||||
throw new IllegalArgumentException("Zero or positive values only allowed for columns, rows and buffer size.");
|
||||
}
|
||||
if (bufferSize < rows) {
|
||||
throw new IllegalArgumentException("The buffer is too small");
|
||||
}
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
this.bufferSize = bufferSize;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the terminal model.
|
||||
*/
|
||||
private void init() {
|
||||
cells = new TerminalCell[bufferSize][columns];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCursorRow() {
|
||||
return cursorRow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorRow(int row) {
|
||||
if (row < 0 || row >= bufferSize) {
|
||||
throw new IllegalArgumentException("row out of range");
|
||||
}
|
||||
cursorRow = row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCursorColumn() {
|
||||
return cursorColumn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorColumn(int column) {
|
||||
if (column < 0 || column >= columns) {
|
||||
throw new IllegalArgumentException("column out of range");
|
||||
}
|
||||
cursorColumn = column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TerminalCell getCell(int column, int row) {
|
||||
if (column < 0 || row < 0 || column >= columns || row >= bufferSize) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return cells[row][column];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCell(int column, int row, TerminalCell cell) {
|
||||
if (column < 0 || row < 0 || column >= columns || row >= bufferSize) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
cells[row][column] = cell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String str) {
|
||||
if (str == null) {
|
||||
throw new NullPointerException("str");
|
||||
}
|
||||
parser.parse(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BellStrategy getBellStrategy() {
|
||||
return bellStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBellStrategy(BellStrategy strategy) {
|
||||
if (strategy == null) {
|
||||
throw new NullPointerException("strategy");
|
||||
}
|
||||
this.bellStrategy = strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getDefaultBackgroundColor() {
|
||||
final int bg = DEFAULT_BACKGROUND_COLOR;
|
||||
return DEFAULT_BACKGROUND_BOLD ? SgrColor.COLOR_BRIGHT[bg] : SgrColor.COLOR_NORMAL[bg];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getDefaultForegroundColor() {
|
||||
final int fg = DEFAULT_FOREGROUND_COLOR;
|
||||
return DEFAULT_FOREGROUND_BOLD ? SgrColor.COLOR_BRIGHT[fg] : SgrColor.COLOR_NORMAL[fg];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains a terminal model roughly compatible with the VT100/ANSI standard.
|
||||
*/
|
||||
package com.loomcom.symon.jterminal.vt100;
|
||||
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.loomcom.symon.jterminal.vt100.AnsiControlSequenceParser;
|
||||
import com.loomcom.symon.jterminal.vt100.AnsiControlSequence;
|
||||
import com.loomcom.symon.jterminal.vt100.AnsiControlSequenceListener;
|
||||
|
||||
|
||||
/**
|
||||
* A test for the {@link AnsiControlSequenceParser} class.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class TestAnsiControlSequenceParser implements AnsiControlSequenceListener {
|
||||
|
||||
/**
|
||||
* The current parser.
|
||||
*/
|
||||
private AnsiControlSequenceParser parser;
|
||||
|
||||
/**
|
||||
* The list of objects returned through the
|
||||
* {@link AnsiControlSequenceListener} interface.
|
||||
*/
|
||||
private List<Object> objects = new ArrayList<Object>();
|
||||
|
||||
/**
|
||||
* Sets up the parser and object list.
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {
|
||||
objects.clear();
|
||||
parser = new AnsiControlSequenceParser(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a broken sequence with the single byte CSI.
|
||||
*/
|
||||
@Test
|
||||
public void testBrokenSingleSequence() {
|
||||
parser.parse(new String(new char[] { 155 }));
|
||||
parser.parse(new String(new char[] { 'u' }));
|
||||
|
||||
assertEquals(1, objects.size());
|
||||
|
||||
Object obj = objects.get(0);
|
||||
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||
|
||||
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||
String[] params = seq.getParameters();
|
||||
|
||||
assertEquals('u', seq.getCommand());
|
||||
assertEquals(0, params.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a broken sequence with the double byte CSI.
|
||||
*/
|
||||
@Test
|
||||
public void testBrokenDoubleSequence() {
|
||||
char[] ch1 = { 27 };
|
||||
char[] ch2 = { '[' };
|
||||
char[] ch3 = { '3', '0', ';' };
|
||||
char[] ch4 = { '4', '0', 'm' };
|
||||
|
||||
parser.parse(new String(ch1));
|
||||
parser.parse(new String(ch2));
|
||||
parser.parse(new String(ch3));
|
||||
parser.parse(new String(ch4));
|
||||
|
||||
assertEquals(1, objects.size());
|
||||
Object obj = objects.get(0);
|
||||
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||
|
||||
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||
String[] params = seq.getParameters();
|
||||
|
||||
assertEquals('m', seq.getCommand());
|
||||
assertEquals(2, params.length);
|
||||
assertEquals("30", params[0]);
|
||||
assertEquals("40", params[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an empty string.
|
||||
*/
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
parser.parse("");
|
||||
assertEquals(0, objects.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a sequence embedded within some text.
|
||||
*/
|
||||
@Test
|
||||
public void testTextAndSequence() {
|
||||
char[] ch = { 'h', 'i', 155, 'u', 'b', 'y', 'e' };
|
||||
parser.parse(new String(ch));
|
||||
|
||||
assertEquals(3, objects.size());
|
||||
|
||||
Object o1 = objects.get(0);
|
||||
Object o2 = objects.get(1);
|
||||
Object o3 = objects.get(2);
|
||||
|
||||
assertEquals(String.class, o1.getClass());
|
||||
assertEquals(AnsiControlSequence.class, o2.getClass());
|
||||
assertEquals(String.class, o3.getClass());
|
||||
|
||||
assertEquals("hi", o1);
|
||||
assertEquals("bye", o3);
|
||||
|
||||
AnsiControlSequence seq = (AnsiControlSequence) o2;
|
||||
String[] params = seq.getParameters();
|
||||
|
||||
assertEquals(0, params.length);
|
||||
assertEquals('u', seq.getCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests parameters within a sequence.
|
||||
*/
|
||||
@Test
|
||||
public void testParameters() {
|
||||
char[] ch = { 155, '3', '0', ';', '4', '0', 'm' };
|
||||
parser.parse(new String(ch));
|
||||
|
||||
assertEquals(1, objects.size());
|
||||
Object obj = objects.get(0);
|
||||
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||
|
||||
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||
String[] params = seq.getParameters();
|
||||
|
||||
assertEquals('m', seq.getCommand());
|
||||
assertEquals(2, params.length);
|
||||
assertEquals("30", params[0]);
|
||||
assertEquals("40", params[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with plain text.
|
||||
*/
|
||||
@Test
|
||||
public void testText() {
|
||||
parser.parse("Hello, World!");
|
||||
|
||||
assertEquals(1, objects.size());
|
||||
Object obj = objects.get(0);
|
||||
assertEquals(String.class, obj.getClass());
|
||||
assertEquals(obj, "Hello, World!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with a single byte CSI.
|
||||
*/
|
||||
@Test
|
||||
public void testSingleCsi() {
|
||||
char[] ch = { 155, '6', 'n' };
|
||||
parser.parse(new String(ch));
|
||||
|
||||
assertEquals(1, objects.size());
|
||||
Object obj = objects.get(0);
|
||||
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||
|
||||
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||
String[] params = seq.getParameters();
|
||||
assertEquals('n', seq.getCommand());
|
||||
assertEquals(1, params.length);
|
||||
assertEquals("6", params[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with a double byte CSI.
|
||||
*/
|
||||
@Test
|
||||
public void testDoubleCsi() {
|
||||
char[] ch = { 27, '[', 's' };
|
||||
parser.parse(new String(ch));
|
||||
|
||||
assertEquals(1, objects.size());
|
||||
Object obj = objects.get(0);
|
||||
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||
|
||||
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||
String[] params = seq.getParameters();
|
||||
assertEquals('s', seq.getCommand());
|
||||
assertEquals(0, params.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parsedControlSequence(AnsiControlSequence seq) {
|
||||
objects.add(seq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parsedString(String str) {
|
||||
objects.add(str);
|
||||
}
|
||||
|
||||
}
|
||||
|
233
src/test/java/com/loomcom/symon/TestVt100TerminalModel.java
Normal file
233
src/test/java/com/loomcom/symon/TestVt100TerminalModel.java
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.loomcom.symon;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.loomcom.symon.jterminal.TerminalCell;
|
||||
import com.loomcom.symon.jterminal.TerminalModel;
|
||||
import com.loomcom.symon.jterminal.bell.BellStrategy;
|
||||
import com.loomcom.symon.jterminal.vt100.Vt100TerminalModel;
|
||||
|
||||
/**
|
||||
* A test for the {@link Vt100TerminalModel} class.
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class TestVt100TerminalModel {
|
||||
|
||||
/**
|
||||
* The terminal model.
|
||||
*/
|
||||
private TerminalModel model;
|
||||
|
||||
/**
|
||||
* Sets up the terminal model.
|
||||
*/
|
||||
@Before
|
||||
public void setUp(){
|
||||
model = new Vt100TerminalModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the word wrapping.
|
||||
*/
|
||||
@Test
|
||||
public void testWordWrapping() {
|
||||
int width = model.getColumns();
|
||||
for (int i = 0; i < (width + 1); i++) {
|
||||
model.print("h");
|
||||
}
|
||||
assertEquals('h', model.getCell(0, 1).getCharacter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests special ASCII characters.
|
||||
*/
|
||||
@Test
|
||||
public void testSpecialCharacters() {
|
||||
model.print("\u0000");
|
||||
assertNull(model.getCell(0, 0));
|
||||
|
||||
model.print("a\rb\rc");
|
||||
assertEquals('c', model.getCell(0, 0).getCharacter());
|
||||
|
||||
model.print("\na");
|
||||
assertEquals('c', model.getCell(0, 0).getCharacter());
|
||||
assertEquals('a', model.getCell(1, 1).getCharacter());
|
||||
|
||||
model.print("\u007F");
|
||||
assertNull(model.getCell(0, 1));
|
||||
|
||||
model.print("A\tB");
|
||||
assertEquals('B', model.getCell(8, 1).getCharacter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the terminal scrolls once the buffer is full.
|
||||
*/
|
||||
@Test
|
||||
public void testBuffer() {
|
||||
model = new Vt100TerminalModel(model.getColumns(), 2, 2);
|
||||
model.print("This is line one.\r\n");
|
||||
model.print("This is line two. XXXXXX\r\n");
|
||||
model.print("And this is line three!");
|
||||
assertEquals('A', model.getCell(0, 1).getCharacter());
|
||||
assertNull(model.getCell(23, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the erase functionality.
|
||||
*/
|
||||
@Test
|
||||
public void testErase() {
|
||||
model.print("Hello");
|
||||
model.print("\u009B2J");
|
||||
for (int i = 0; i < 5; i++) {
|
||||
assertNull(model.getCell(i, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests moving the cursor.
|
||||
*/
|
||||
@Test
|
||||
public void testMoveCursor() {
|
||||
model.print("\u009B5B");
|
||||
assertEquals(5, model.getCursorRow());
|
||||
|
||||
model.print("\u009B3A");
|
||||
assertEquals(2, model.getCursorRow());
|
||||
|
||||
model.print("\u009B7C");
|
||||
assertEquals(7, model.getCursorColumn());
|
||||
|
||||
model.print("\u009B4D");
|
||||
assertEquals(3, model.getCursorColumn());
|
||||
|
||||
model.setCursorColumn(15);
|
||||
model.setCursorRow(0);
|
||||
|
||||
model.print("\u009B3E");
|
||||
assertEquals(0, model.getCursorColumn());
|
||||
assertEquals(3, model.getCursorRow());
|
||||
|
||||
model.setCursorColumn(7);
|
||||
|
||||
model.print("\u009BF");
|
||||
assertEquals(0, model.getCursorColumn());
|
||||
assertEquals(2, model.getCursorRow());
|
||||
|
||||
model.print("\u009B4;8H");
|
||||
assertEquals(3, model.getCursorRow());
|
||||
assertEquals(7, model.getCursorColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the SGR escape sequence.
|
||||
*/
|
||||
@Test
|
||||
public void testSgr() {
|
||||
model.print("\u009B2;33;41mX");
|
||||
|
||||
TerminalCell cell = model.getCell(0, 0);
|
||||
assertNotNull(cell);
|
||||
assertEquals('X', cell.getCharacter());
|
||||
|
||||
assertEquals(Color.RED, cell.getBackgroundColor());
|
||||
assertEquals(Color.YELLOW, cell.getForegroundColor());
|
||||
|
||||
model.print("\u009B0m\rX");
|
||||
|
||||
cell = model.getCell(0, 0);
|
||||
|
||||
assertNotNull(cell);
|
||||
assertEquals('X', cell.getCharacter());
|
||||
|
||||
assertEquals(model.getDefaultBackgroundColor(), cell.getBackgroundColor());
|
||||
assertEquals(model.getDefaultForegroundColor(), cell.getForegroundColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests saving and restoring the cursor.
|
||||
*/
|
||||
@Test
|
||||
public void testSaveAndRestoreCursor() {
|
||||
model.setCursorColumn(3);
|
||||
model.setCursorRow(17);
|
||||
|
||||
model.print("\u009Bs");
|
||||
|
||||
model.setCursorColumn(5);
|
||||
model.setCursorRow(23);
|
||||
|
||||
model.print("\u009Bu");
|
||||
|
||||
assertEquals(3, model.getCursorColumn());
|
||||
assertEquals(17, model.getCursorRow());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the printing of a simple message.
|
||||
*/
|
||||
@Test
|
||||
public void testPrint() {
|
||||
model.print("Hi");
|
||||
assertEquals('H', model.getCell(0, 0).getCharacter());
|
||||
assertEquals('i', model.getCell(1, 0).getCharacter());
|
||||
assertNull(model.getCell(2, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the bell is sounded.
|
||||
*/
|
||||
@Test
|
||||
public void testBell() {
|
||||
final int[] counter = new int[1];
|
||||
|
||||
BellStrategy strategy = new BellStrategy() {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.loomcom.symon.jterminal.bell.BellStrategy#soundBell()
|
||||
*/
|
||||
@Override
|
||||
public void soundBell() {
|
||||
counter[0]++;
|
||||
}
|
||||
};
|
||||
|
||||
model.setBellStrategy(strategy);
|
||||
|
||||
model.print("\u0007");
|
||||
assertEquals(1, counter[0]);
|
||||
|
||||
model.print("Hello, \u0007World!\u0007\r\n");
|
||||
assertEquals(3, counter[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user