diff --git a/README.md b/README.md
index a59772bba..181a82ee9 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ JLine is distributed under the [BSD License](http://www.opensource.org/licenses/
Documentation
-------------
-* [wiki](https://github.com/jline/jline2/wiki)
+* [wiki](https://github.com/jline/jline3/wiki)
Forums
------
@@ -39,7 +39,7 @@ Use the following definition to use JLine in your maven project:
org.jline
jline
- 3.0.0.M2
+ 3.0.1
Building
diff --git a/demo/jline-gogo.bat b/demo/jline-gogo.bat
new file mode 100755
index 000000000..b72066134
--- /dev/null
+++ b/demo/jline-gogo.bat
@@ -0,0 +1,80 @@
+@echo off
+
+set DIRNAME=%~dp0%
+set ROOTDIR=%DIRNAME%\..
+set TARGETDIR=%ROOTDIR%\target
+
+set JLINE_VERSION=3.0.2-SNAPSHOT
+set JANSI_VERSION=1.14
+set JNA_VERSION=4.2.2
+set GOGO_RUNTIME_VERSION=1.0.0
+set GOGO_JLINE_VERSION=1.0.0
+
+rem initialization
+if not exist %TARGETDIR%\jline-%JLINE_VERSION%.jar (
+ echo Build jline with maven before running the demo
+ goto END
+)
+if not exist %TARGETDIR%\lib (
+ mkdir %TARGETDIR%\lib
+)
+
+rem JLINE
+set cp=%TARGETDIR%\jline-%JLINE_VERSION%.jar
+
+rem JANSI
+if not exist %TARGETDIR%\lib\jansi-%JANSI_VERSION%.jar (
+ echo "Downloading Jansi..."
+ %DIRNAME%\wget.exe -O %TARGETDIR%\lib\jansi-%JANSI_VERSION%.jar http://repo1.maven.org/maven2/org/fusesource/jansi/jansi/%JANSI_VERSION%/jansi-%JANSI_VERSION%.jar
+)
+
+rem JNA
+if not exist %TARGETDIR%\lib\jna-%JNA_VERSION%.jar (
+ echo "Downloading JNA..."
+ %DIRNAME%\wget.exe -O %TARGETDIR%\lib\jna-%JNA_VERSION%.jar http://repo1.maven.org/maven2/net/java/dev/jna/jna/%JNA_VERSION%/jna-%JNA_VERSION%.jar
+)
+
+rem Gogo Runtime
+if not exist %TARGETDIR%\lib\org.apache.felix.gogo.runtime-%GOGO_RUNTIME_VERSION%.jar (
+ echo "Downloading Gogo Runtime..."
+ %DIRNAME%\wget.exe -O %TARGETDIR%\lib\org.apache.felix.gogo.runtime-%GOGO_RUNTIME_VERSION%.jar http://repo1.maven.org/maven2/org/apache/felix/org.apache.felix.gogo.runtime/%GOGO_RUNTIME_VERSION%/org.apache.felix.gogo.runtime-%GOGO_RUNTIME_VERSION%.jar
+)
+set cp=%cp%;%TARGETDIR%\lib\org.apache.felix.gogo.runtime-%GOGO_RUNTIME_VERSION%.jar
+
+rem Gogo JLine
+if not exist %TARGETDIR%\lib\org.apache.felix.gogo.jline-%GOGO_JLINE_VERSION%.jar (
+ echo "Downloading Gogo JLine..."
+ %DIRNAME%\wget.exe -O %TARGETDIR%\lib\org.apache.felix.gogo.jline-%GOGO_JLINE_VERSION%.jar http://repo1.maven.org/maven2/org/apache/felix/org.apache.felix.gogo.jline/%GOGO_JLINE_VERSION%/org.apache.felix.gogo.jline-%GOGO_JLINE_VERSION%.jar
+)
+set cp=%cp%;%TARGETDIR%\lib\org.apache.felix.gogo.jline-%GOGO_JLINE_VERSION%.jar
+
+
+set opts=
+:RUN_LOOP
+ if "%1" == "jansi" goto :EXECUTE_JANSI
+ if "%1" == "jna" goto :EXECUTE_JNA
+ if "%1" == "debug" goto :EXECUTE_DEBUG
+ goto :EXECUTE
+
+:EXECUTE_JANSI
+ set cp=%cp%;%TARGETDIR%/lib/jansi-%JANSI_VERSION%.jar
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_JNA
+ set cp=%cp%;%TARGETDIR%/lib/jna-%JNA_VERSION%.jar
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_DEBUG
+ set opts=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE
+rem Launch gogo shell
+echo "Classpath: %cp%"
+echo "Launching Gogo JLine..."
+java -cp %cp% %opts% org.apache.felix.gogo.jline.Main
+
+:END
\ No newline at end of file
diff --git a/demo/jline-gogo.sh b/demo/jline-gogo.sh
new file mode 100755
index 000000000..b8d4fea6d
--- /dev/null
+++ b/demo/jline-gogo.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+realpath() {
+ OURPWD=${PWD}
+ cd "$(dirname "${1}")"
+ LINK=$(readlink "$(basename "${1}")")
+ while [ "${LINK}" ]; do
+ cd "$(dirname "${LINK}")"
+ LINK=$(readlink "$(basename "${1}")")
+ done
+ REALPATH="${PWD}/$(basename "${1}")"
+ cd "${OURPWD}"
+ echo "${REALPATH}"
+}
+
+REALNAME=$(realpath "$0")
+DIRNAME=$(dirname "${REALNAME}")
+PROGNAME=$(basename "${REALNAME}")
+ROOTDIR=${DIRNAME}/..
+TARGETDIR=${ROOTDIR}/target
+
+if [ ! -e ${TARGETDIR} ] ; then
+ echo "Build jline with maven before running the demo"
+ exit
+fi;
+if [ ! -e ${TARGETDIR}/lib ] ; then
+ mkdir ${TARGETDIR}/lib
+fi;
+
+JLINE_VERSION=$(ls ${TARGETDIR}/jline-*-SNAPSHOT.jar | sed -e 's#.*/jline-## ; s#SNAPSHOT.*#SNAPSHOT#')
+JANSI_VERSION=$(cat ${ROOTDIR}/pom.xml| grep jansi.version\> | sed -e 's#^.*## ; s# | sed -e 's#^.*## ; s#1.8
1.8
+ 4.2.2
1.14
1.0.3
@@ -109,7 +110,7 @@
net.java.dev.jna
jna
- 4.2.2
+ ${jna.version}
true
diff --git a/src/main/java/org/jline/builtins/Nano.java b/src/main/java/org/jline/builtins/Nano.java
index bf6ffbcb5..ff4a6dc55 100644
--- a/src/main/java/org/jline/builtins/Nano.java
+++ b/src/main/java/org/jline/builtins/Nano.java
@@ -44,6 +44,7 @@
import org.jline.terminal.Attributes.ControlChar;
import org.jline.terminal.Attributes.InputFlag;
import org.jline.terminal.Attributes.LocalFlag;
+import org.jline.terminal.MouseEvent;
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
import org.jline.terminal.Terminal.Signal;
@@ -78,6 +79,7 @@ public class Nano {
public boolean printLineNumbers = true;
public boolean wrapping;
public boolean smoothScrolling = true;
+ public boolean mouseSupport = false;
public boolean oneMoreLine = true;
public boolean constantCursor;
public int tabs = 4;
@@ -366,7 +368,7 @@ boolean moveRight(int chars) {
return ret;
}
- void moveDown(int lines) throws IOException {
+ void moveDown(int lines) {
cursorDown(lines);
ensureCursorVisible();
}
@@ -696,6 +698,16 @@ List getDisplayedLines(int nbLines) {
return newLines;
}
+ public void moveTo(int x, int y) {
+ if (printLineNumbers) {
+ x = Math.max(x - 8, 0);
+ }
+ line = firstLineToDisplay;
+ offsetInLine = offsetInLineToDisplay;
+ wantedColumn = x;
+ cursorDown(y);
+ }
+
public int getDisplayedCursor() {
int rwidth = size.getColumns();
int cursor = (printLineNumbers ? 8 : 0);
@@ -965,6 +977,9 @@ public void run() throws IOException {
display.clear();
display.reset();
display.resize(size.getRows(), size.getColumns());
+ if (mouseSupport) {
+ terminal.trackMouse(Terminal.MouseTracking.Normal);
+ }
this.shortcuts = standardShortcuts();
@@ -1020,6 +1035,9 @@ public void run() throws IOException {
case SMOOTH_SCROLLING:
smoothScrolling();
break;
+ case MOUSE_SUPPORT:
+ mouseSupport();
+ break;
case ONE_MORE_LINE:
oneMoreLine();
break;
@@ -1083,6 +1101,9 @@ public void run() throws IOException {
case MATCHING:
buffer.matching();
break;
+ case MOUSE_EVENT:
+ mouseEvent();
+ break;
default:
setMessage("Unsupported " + op.name().toLowerCase().replace('_', '-'));
break;
@@ -1090,6 +1111,9 @@ public void run() throws IOException {
display();
}
} finally {
+ if (mouseSupport) {
+ terminal.trackMouse(Terminal.MouseTracking.Off);
+ }
terminal.puts(Capability.exit_ca_mode);
terminal.puts(Capability.keypad_local);
terminal.flush();
@@ -1117,6 +1141,7 @@ boolean write() throws IOException {
writeKeyMap.bind(Operation.ACCEPT, "\r");
writeKeyMap.bind(Operation.CANCEL, ctrl('C'));
writeKeyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
+ writeKeyMap.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
editMessage = getWriteMessage();
editBuffer.setLength(0);
@@ -1162,6 +1187,9 @@ boolean write() throws IOException {
case BACKUP:
writeBackup = !writeBackup;
break;
+ case MOUSE_EVENT:
+ mouseEvent();
+ break;
}
editMessage = getWriteMessage();
display();
@@ -1298,6 +1326,9 @@ void read() {
for (char i = 32; i < 256; i++) {
readKeyMap.bind(Operation.INSERT, Character.toString(i));
}
+ for (char i = 'A'; i <= 'Z'; i++) {
+ readKeyMap.bind(Operation.DO_LOWER_CASE, alt(i));
+ }
readKeyMap.bind(Operation.BACKSPACE, del());
readKeyMap.bind(Operation.NEW_BUFFER, alt('f'));
readKeyMap.bind(Operation.TO_FILES, ctrl('T'));
@@ -1305,6 +1336,7 @@ void read() {
readKeyMap.bind(Operation.ACCEPT, "\r");
readKeyMap.bind(Operation.CANCEL, ctrl('C'));
readKeyMap.bind(Operation.HELP, ctrl('G'), key(terminal, Capability.key_f1));
+ readKeyMap.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
editMessage = getReadMessage();
editBuffer.setLength(0);
@@ -1358,6 +1390,9 @@ void read() {
case NEW_BUFFER:
readNewBuffer = !readNewBuffer;
break;
+ case MOUSE_EVENT:
+ mouseEvent();
+ break;
}
editMessage = getReadMessage();
display();
@@ -1492,6 +1527,9 @@ void help(String help) {
case CLEAR_SCREEN:
clearScreen();
break;
+ case MOUSE_EVENT:
+ mouseEvent();
+ break;
}
display();
}
@@ -1508,6 +1546,9 @@ void help(String help) {
void search() throws IOException {
KeyMap searchKeyMap = new KeyMap<>();
searchKeyMap.setUnicode(Operation.INSERT);
+ for (char i = 'A'; i <= 'Z'; i++) {
+ searchKeyMap.bind(Operation.DO_LOWER_CASE, alt(i));
+ }
searchKeyMap.bind(Operation.CASE_SENSITIVE, alt('c'));
searchKeyMap.bind(Operation.BACKWARDS, alt('b'));
searchKeyMap.bind(Operation.REGEXP, alt('r'));
@@ -1515,6 +1556,7 @@ void search() throws IOException {
searchKeyMap.bind(Operation.CANCEL, ctrl('C'));
searchKeyMap.bind(Operation.FIRST_LINE, ctrl('Y'));
searchKeyMap.bind(Operation.LAST_LINE, ctrl('V'));
+ searchKeyMap.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
editMessage = getSearchMessage();
editBuffer.setLength(0);
@@ -1561,6 +1603,9 @@ void search() throws IOException {
case LAST_LINE:
buffer.lastLine();
return;
+ case MOUSE_EVENT:
+ mouseEvent();
+ break;
}
editMessage = getSearchMessage();
display();
@@ -1709,6 +1754,12 @@ void smoothScrolling() {
setMessage("Smooth scrolling " + (smoothScrolling ? "enabled" : "disabled"));
}
+ void mouseSupport() throws IOException {
+ mouseSupport = !mouseSupport;
+ setMessage("Mouse support " + (mouseSupport ? "enabled" : "disabled"));
+ terminal.trackMouse(mouseSupport ? Terminal.MouseTracking.Normal : Terminal.MouseTracking.Off);
+ }
+
void constantCursor() {
constantCursor = !constantCursor;
setMessage("Constant cursor position display " + (constantCursor ? "enabled" : "disabled"));
@@ -1729,6 +1780,42 @@ void clearScreen() {
resetDisplay();
}
+ void mouseEvent() {
+ MouseEvent event = terminal.readMouseEvent();
+ if (event.getModifiers().isEmpty() && event.getType() == MouseEvent.Type.Released
+ && event.getButton() == MouseEvent.Button.Button1) {
+ int x = event.getX();
+ int y = event.getY();
+ int hdr = buffer.computeHeader().size();
+ int ftr = computeFooter().size();
+ if (y < hdr) {
+ // nothing
+ } else if (y < size.getRows() - ftr) {
+ buffer.moveTo(x, y - hdr);
+ } else {
+ int cols = (shortcuts.size() + 1) / 2;
+ int cw = size.getColumns() / cols;
+ int l = y - (size.getRows() - ftr) - 1;
+ int si = l * cols + x / cw;
+ String shortcut = null;
+ Iterator it = shortcuts.keySet().iterator();
+ while (si-- >= 0 && it.hasNext()) { shortcut = it.next(); }
+ if (shortcut != null) {
+ shortcut = shortcut.replaceAll("M-", "\\\\E");
+ String seq = KeyMap.translate(shortcut);
+ bindingReader.runMacro(seq);
+ }
+ }
+ }
+ else if (event.getType() == MouseEvent.Type.Wheel) {
+ if (event.getButton() == MouseEvent.Button.WheelDown) {
+ buffer.moveDown(1);
+ } else if (event.getButton() == MouseEvent.Button.WheelUp) {
+ buffer.moveUp(1);
+ }
+ }
+ }
+
public String getTitle() {
return title;
}
@@ -1914,6 +2001,7 @@ protected void bindKeys() {
keys.bind(Operation.CONSTANT_CURSOR, alt('c'));
keys.bind(Operation.ONE_MORE_LINE, alt('o'));
keys.bind(Operation.SMOOTH_SCROLLING, alt('s'));
+ keys.bind(Operation.MOUSE_SUPPORT, alt('m'));
keys.bind(Operation.WHITESPACE, alt('p'));
keys.bind(Operation.HIGHLIGHT, alt('y'));
@@ -1932,6 +2020,8 @@ protected void bindKeys() {
keys.bind(Operation.DOWN, key(terminal, Capability.key_down));
keys.bind(Operation.RIGHT, key(terminal, Capability.key_right));
keys.bind(Operation.LEFT, key(terminal, Capability.key_left));
+
+ keys.bind(Operation.MOUSE_EVENT, key(terminal, Capability.key_mouse));
}
enum Operation {
@@ -1946,6 +2036,7 @@ enum Operation {
WRAP,
NUMBERS,
SMOOTH_SCROLLING,
+ MOUSE_SUPPORT,
ONE_MORE_LINE,
CLEAR_SCREEN,
@@ -2015,7 +2106,9 @@ enum Operation {
AUTO_INDENT,
CUT_TO_END_TOGGLE,
TABS_TO_SPACE,
- UNCUT
+ UNCUT,
+
+ MOUSE_EVENT
}
}
diff --git a/src/main/java/org/jline/builtins/Tmux.java b/src/main/java/org/jline/builtins/Tmux.java
index b3e52d296..954f3d18f 100644
--- a/src/main/java/org/jline/builtins/Tmux.java
+++ b/src/main/java/org/jline/builtins/Tmux.java
@@ -28,6 +28,7 @@
import org.jline.reader.ParsedLine;
import org.jline.reader.impl.DefaultParser;
import org.jline.terminal.Attributes;
+import org.jline.terminal.MouseEvent;
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
import org.jline.terminal.Terminal.Signal;
@@ -67,10 +68,12 @@ public class Tmux {
private final AtomicInteger paneId = new AtomicInteger();
private final Map serverOptions = new HashMap<>();
- private final KeyMap