diff options
author | Anton Leherbauer | 2015-01-27 15:09:11 +0000 |
---|---|---|
committer | Anton Leherbauer | 2015-01-28 08:50:25 +0000 |
commit | 53c5808e0091ec7cdd04db2f90bb9b4b2e2eda7c (patch) | |
tree | f5c5e0ee18cff44b265922552e368f81639a3065 | |
parent | 7ff9715a558f381fa72c4233966bb4b0a91ef7a5 (diff) | |
download | org.eclipse.tm-53c5808e0091ec7cdd04db2f90bb9b4b2e2eda7c.tar.gz org.eclipse.tm-53c5808e0091ec7cdd04db2f90bb9b4b2e2eda7c.tar.xz org.eclipse.tm-53c5808e0091ec7cdd04db2f90bb9b4b2e2eda7c.zip |
Bug 458402 - [terminal] Add support for scroll up/down and scroll region
Change-Id: If3c955663f664d34d01ada0763de2eec7b36b7d4
Signed-off-by: Anton Leherbauer <anton.leherbauer@windriver.com>
5 files changed, 257 insertions, 12 deletions
diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java index 9ed477ffa..0a65fd7ba 100644 --- a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java @@ -10,6 +10,7 @@ * Martin Oberhuber (Wind River) - [168197] Fix Terminal for CDC-1.1/Foundation-1.1 * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region *******************************************************************************/ package org.eclipse.tm.internal.terminal.emulator; @@ -1307,4 +1308,74 @@ public class VT100EmulatorBackendTest extends TestCase { assertEquals("abc123", new String(term.getChars(0))); } + public void testScrollRegion() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(8, 6); + vt100.appendString("123"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("456"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("789"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("abc"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("def"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("ghi"); + + // test scroll within region + vt100.setCursorLine(1); + vt100.setScrollRegion(1, 4); + vt100.scrollUp(1); + assertEquals("123", new String(term.getChars(0))); + assertEquals("789", new String(term.getChars(1))); + assertEquals("abc", new String(term.getChars(2))); + assertEquals("def", new String(term.getChars(3))); + assertNull(term.getChars(4)); + assertEquals("ghi", new String(term.getChars(5))); + vt100.scrollDown(1); + assertEquals("123", new String(term.getChars(0))); + assertNull(term.getChars(1)); + assertEquals("789", new String(term.getChars(2))); + assertEquals("abc", new String(term.getChars(3))); + assertEquals("def", new String(term.getChars(4))); + assertEquals("ghi", new String(term.getChars(5))); + + // test scroll without region + vt100.setScrollRegion(-1, -1); + vt100.scrollDown(1); + assertNull(term.getChars(0)); + assertEquals("123", new String(term.getChars(1))); + assertNull(term.getChars(2)); + assertEquals("789", new String(term.getChars(3))); + assertEquals("abc", new String(term.getChars(4))); + assertEquals("def", new String(term.getChars(5))); + assertEquals("ghi", new String(term.getChars(6))); + vt100.scrollUp(1); + assertEquals("123", new String(term.getChars(0))); + assertNull(term.getChars(1)); + assertEquals("789", new String(term.getChars(2))); + assertEquals("abc", new String(term.getChars(3))); + assertEquals("def", new String(term.getChars(4))); + assertEquals("ghi", new String(term.getChars(5))); + + // test scroll by newline + vt100.setScrollRegion(1, 4); + vt100.setCursorLine(4); + vt100.processNewline(); + assertEquals("123", new String(term.getChars(0))); + assertEquals("789", new String(term.getChars(1))); + assertEquals("abc", new String(term.getChars(2))); + assertEquals("def", new String(term.getChars(3))); + assertNull(term.getChars(4)); + assertEquals("ghi", new String(term.getChars(5))); + } + } diff --git a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java index ef38f82e0..aff90891b 100644 --- a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java +++ b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/IVT100EmulatorBackend.java @@ -9,13 +9,13 @@ * Michael Scharf (Wind River) - initial API and implementation * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region *******************************************************************************/ package org.eclipse.tm.internal.terminal.emulator; import org.eclipse.tm.terminal.model.Style; /** - * @author toni * */ public interface IVT100EmulatorBackend { @@ -197,4 +197,26 @@ public interface IVT100EmulatorBackend { * @param enable whether to enable insert mode */ void setInsertMode(boolean enable); + + /** + * Set scrolling region. Negative values reset the scroll region. + * + * @param top top line of scroll region + * @param bottom bottom line of scroll region + */ + void setScrollRegion(int top, int bottom); + + /** + * Scroll text upwards. + * + * @param lines number of lines to scroll + */ + void scrollUp(int lines); + + /** + * Scroll text downwards. + * + * @param lines number of lines to scroll + */ + void scrollDown(int lines); } diff --git a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java index c108986e1..78531437e 100644 --- a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java +++ b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java @@ -9,6 +9,7 @@ * Michael Scharf (Wind River) - initial API and implementation * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region *******************************************************************************/ package org.eclipse.tm.internal.terminal.emulator; @@ -157,4 +158,19 @@ public class VT100BackendTraceDecorator implements IVT100EmulatorBackend { fBackend.setInsertMode(enable); } + public void setScrollRegion(int top, int bottom) { + fWriter.println("setScrollRegion("+top+','+bottom+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setScrollRegion(top, bottom); + } + + public void scrollUp(int lines) { + fWriter.println("scrollUp("+lines+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.scrollUp(lines); + } + + public void scrollDown(int lines) { + fWriter.println("scrollDown("+lines+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.scrollDown(lines); + } + } diff --git a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java index cc9e6cfa4..eba03390c 100644 --- a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java +++ b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java @@ -23,6 +23,7 @@ * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode * Anton Leherbauer (Wind River) - [458398] Add support for normal/application cursor keys mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region *******************************************************************************/ package org.eclipse.tm.internal.terminal.emulator; @@ -77,6 +78,12 @@ public class VT100Emulator implements ControlListener { */ private static final int ANSISTATE_EXPECTING_DEC_PRIVATE_COMMAND = 4; + /** + * This is a character processing state: We've seen one of ()*+-./ after an escape + * character. Expecting a character set designation character. + */ + private static final int ANSISTATE_EXPECTING_CHARSET_DESIGNATION = 5; + /** * This field holds the current state of the Finite TerminalState Automaton (FSA) @@ -341,6 +348,16 @@ public class VT100Emulator implements ControlListener { ansiOsCommand.delete(0, ansiOsCommand.length()); break; + case ')': + case '(': + case '*': + case '+': + case '-': + case '.': + case '/': + ansiState = ANSISTATE_EXPECTING_CHARSET_DESIGNATION; + break; + case '7': // Save cursor position and character attributes @@ -413,6 +430,12 @@ public class VT100Emulator implements ControlListener { } break; + case ANSISTATE_EXPECTING_CHARSET_DESIGNATION: + if (character != '%') + ansiState = ANSISTATE_INITIAL; + // Character set designation commands are ignored + break; + default: // This should never happen! If it does happen, it means there is a // bug in the FSA. For robustness, we return to the initial @@ -483,6 +506,11 @@ public class VT100Emulator implements ControlListener { processAnsiCommand_D(); break; + case 'd': + // Line Position Absolute [row] (default = [1,column]) (VPA). + processAnsiCommand_d(); + break; + case 'E': // Move cursor to first column of Nth next line (default 1). processAnsiCommand_E(); @@ -548,16 +576,19 @@ public class VT100Emulator implements ControlListener { processAnsiCommand_P(); break; + case 'r': + // Set Scrolling Region. + processAnsiCommand_r(); + break; + case 'S': // Scroll up. - // Emacs, vi, and GNU readline don't seem to use this command, so we ignore - // it for now. + processAnsiCommand_S(); break; case 'T': // Scroll down. - // Emacs, vi, and GNU readline don't seem to use this command, so we ignore - // it for now. + processAnsiCommand_T(); break; case 'X': @@ -647,6 +678,14 @@ public class VT100Emulator implements ControlListener { } /** + * This method moves the cursor to a specific row. + */ + private void processAnsiCommand_d() { + // Line Position Absolute [row] (default = [1,column]) (VPA). + text.setCursorLine(getAnsiParameter(0) - 1); + } + + /** * This method moves the cursor to the first column of the Nth next line, * where N is specified by the ANSI parameter (default 1). */ @@ -967,17 +1006,63 @@ public class VT100Emulator implements ControlListener { text.deleteCharacters(getAnsiParameter(0)); } + /** + * Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM). + */ + private void processAnsiCommand_r() { + int top = 0; + int bottom = 0; + if (ansiParameters[0].length() > 0 && ansiParameters[1].length() > 0) { + top = getAnsiParameter(0); + bottom = getAnsiParameter(1); + } + text.setScrollRegion(top-1, bottom-1); + } + + /** + * Scroll up n lines (default = 1 line). + */ + private void processAnsiCommand_S() { + text.scrollUp(getAnsiParameter(0)); + } + + /** + * Scroll down n lines (default = 1 line). + */ + private void processAnsiCommand_T() { + text.scrollDown(getAnsiParameter(0)); + } + private void processDecPrivateCommand_h() { - if (getAnsiParameter(0) == 1) { + int param = getAnsiParameter(0); + switch (param) { + case 1: // Enable Application Cursor Keys (DECCKM) terminal.enableApplicationCursorKeys(true); + break; + case 47: + // Use Alternate Screen Buffer (ignored). + break; + default: + Logger.log("Unsupported command parameter: CSI ?" + param + 'h'); //$NON-NLS-1$ + break; } } private void processDecPrivateCommand_l() { - if (getAnsiParameter(0) == 1) { + int param = getAnsiParameter(0); + switch (param) { + case 1: // Enable Normal Cursor Keys (DECCKM) terminal.enableApplicationCursorKeys(false); + break; + case 47: + // Use Normal Screen Buffer (ignored, but reset scroll region). + text.setScrollRegion(-1, -1); + break; + default: + Logger.log("Unsupported command parameter: CSI ?" + param + 'l'); //$NON-NLS-1$ + break; } } diff --git a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java index 2387d20f6..36140d600 100644 --- a/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java +++ b/terminal/plugins/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java @@ -10,6 +10,7 @@ * Anton Leherbauer (Wind River) - [206329] Changing terminal size right after connect does not scroll properly * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region *******************************************************************************/ package org.eclipse.tm.internal.terminal.emulator; @@ -21,6 +22,28 @@ import org.eclipse.tm.terminal.model.Style; */ public class VT100EmulatorBackend implements IVT100EmulatorBackend { + private static class ScrollRegion { + static final ScrollRegion FULL_WINDOW = new ScrollRegion(0, Integer.MAX_VALUE-1); + private final int fTop; + private final int fBottom; + ScrollRegion(int top, int bottom) { + fTop = top; + fBottom = bottom; + } + boolean contains(int line) { + return line >= fTop && line <= fBottom; + } + int getTopLine() { + return fTop; + } + int getBottomLine() { + return fBottom; + } + int getHeight() { + return fBottom - fTop + 1; + } + } + /** * This field holds the number of the column in which the cursor is * logically positioned. The leftmost column on the screen is column 0, and @@ -62,6 +85,8 @@ public class VT100EmulatorBackend implements IVT100EmulatorBackend { int fColumns; final private ITerminalTextData fTerminal; private boolean fVT100LineWrapping; + private ScrollRegion fScrollRegion = ScrollRegion.FULL_WINDOW; + public VT100EmulatorBackend(ITerminalTextData terminal) { fTerminal=terminal; } @@ -210,7 +235,7 @@ public class VT100EmulatorBackend implements IVT100EmulatorBackend { return; assert n>0; int line=toAbsoluteLine(fCursorLine); - int nLines=fTerminal.getHeight()-line; + int nLines=Math.min(fTerminal.getHeight()-line, fScrollRegion.getBottomLine()-fCursorLine+1); fTerminal.scroll(line, nLines, n); } } @@ -240,13 +265,12 @@ public class VT100EmulatorBackend implements IVT100EmulatorBackend { return; assert n>0; int line=toAbsoluteLine(fCursorLine); - int nLines=fTerminal.getHeight()-line; + int nLines=Math.min(fTerminal.getHeight()-line, fScrollRegion.getBottomLine()-fCursorLine+1); fTerminal.scroll(line, nLines, -n); } } private boolean isCusorInScrollingRegion() { - // TODO Auto-generated method stub - return true; + return fScrollRegion.contains(fCursorLine); } /* (non-Javadoc) @@ -333,7 +357,9 @@ public class VT100EmulatorBackend implements IVT100EmulatorBackend { * MUST be called from a synchronized block! */ private void doNewline() { - if(fCursorLine+1>=fLines) { + if (fCursorLine == fScrollRegion.getBottomLine()) + scrollUp(1); + else if (fCursorLine+1>=fLines) { int h=fTerminal.getHeight(); fTerminal.addLine(); if(h!=fTerminal.getHeight()) @@ -440,4 +466,29 @@ public class VT100EmulatorBackend implements IVT100EmulatorBackend { public void setInsertMode(boolean enable) { fInsertMode = enable; } + + public void setScrollRegion(int top, int bottom) { + if (top < 0 || bottom < 0) + fScrollRegion = ScrollRegion.FULL_WINDOW; + else if (top < bottom) + fScrollRegion = new ScrollRegion(top, bottom); + } + + public void scrollUp(int n) { + assert n>0; + synchronized (fTerminal) { + int line = toAbsoluteLine(fScrollRegion.getTopLine()); + int nLines = Math.min(fTerminal.getHeight()-line, fScrollRegion.getHeight()); + fTerminal.scroll(line, nLines, -n); + } + } + + public void scrollDown(int n) { + assert n>0; + synchronized (fTerminal) { + int line = toAbsoluteLine(fScrollRegion.getTopLine()); + int nLines = Math.min(fTerminal.getHeight()-line, fScrollRegion.getHeight()); + fTerminal.scroll(line, nLines, n); + } + } } |