Skip to content

Commit

Permalink
Mouse support, fixes #38
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Nov 17, 2016
1 parent 81c63ae commit fe83731
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 120 deletions.
97 changes: 95 additions & 2 deletions src/main/java/org/jline/builtins/Nano.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -366,7 +368,7 @@ boolean moveRight(int chars) {
return ret;
}

void moveDown(int lines) throws IOException {
void moveDown(int lines) {
cursorDown(lines);
ensureCursorVisible();
}
Expand Down Expand Up @@ -696,6 +698,16 @@ List<AttributedString> 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);
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1083,13 +1101,19 @@ public void run() throws IOException {
case MATCHING:
buffer.matching();
break;
case MOUSE_EVENT:
mouseEvent();
break;
default:
setMessage("Unsupported " + op.name().toLowerCase().replace('_', '-'));
break;
}
display();
}
} finally {
if (mouseSupport) {
terminal.trackMouse(Terminal.MouseTracking.Off);
}
terminal.puts(Capability.exit_ca_mode);
terminal.puts(Capability.keypad_local);
terminal.flush();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1162,6 +1187,9 @@ boolean write() throws IOException {
case BACKUP:
writeBackup = !writeBackup;
break;
case MOUSE_EVENT:
mouseEvent();
break;
}
editMessage = getWriteMessage();
display();
Expand Down Expand Up @@ -1298,13 +1326,17 @@ 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'));
readKeyMap.bind(Operation.EXECUTE, ctrl('X'));
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);
Expand Down Expand Up @@ -1358,6 +1390,9 @@ void read() {
case NEW_BUFFER:
readNewBuffer = !readNewBuffer;
break;
case MOUSE_EVENT:
mouseEvent();
break;
}
editMessage = getReadMessage();
display();
Expand Down Expand Up @@ -1492,6 +1527,9 @@ void help(String help) {
case CLEAR_SCREEN:
clearScreen();
break;
case MOUSE_EVENT:
mouseEvent();
break;
}
display();
}
Expand All @@ -1508,13 +1546,17 @@ void help(String help) {
void search() throws IOException {
KeyMap<Operation> 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'));
searchKeyMap.bind(Operation.ACCEPT, "\r");
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);
Expand Down Expand Up @@ -1561,6 +1603,9 @@ void search() throws IOException {
case LAST_LINE:
buffer.lastLine();
return;
case MOUSE_EVENT:
mouseEvent();
break;
}
editMessage = getSearchMessage();
display();
Expand Down Expand Up @@ -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"));
Expand All @@ -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<String> 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;
}
Expand Down Expand Up @@ -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'));

Expand All @@ -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 {
Expand All @@ -1946,6 +2036,7 @@ enum Operation {
WRAP,
NUMBERS,
SMOOTH_SCROLLING,
MOUSE_SUPPORT,
ONE_MORE_LINE,
CLEAR_SCREEN,

Expand Down Expand Up @@ -2015,7 +2106,9 @@ enum Operation {
AUTO_INDENT,
CUT_TO_END_TOGGLE,
TABS_TO_SPACE,
UNCUT
UNCUT,

MOUSE_EVENT
}

}
74 changes: 43 additions & 31 deletions src/main/java/org/jline/builtins/Tmux.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -67,10 +68,12 @@ public class Tmux {
private final AtomicInteger paneId = new AtomicInteger();

private final Map<String, String> serverOptions = new HashMap<>();
private final KeyMap<Object> keyMap = new KeyMap<>();

private static final Object UNMAPPED = new Object();
private KeyMap<Object> keyMap;

enum Binding {
Discard, SelfInsert, Mouse
}

public Tmux(Terminal terminal, PrintStream err, Consumer<Terminal> runner) throws IOException {
InfoCmp.setDefaultInfoCmp("screen", SCREEN_CAPS);
Expand All @@ -84,16 +87,25 @@ public Tmux(Terminal terminal, PrintStream err, Consumer<Terminal> runner) throw
term = (colors != null && colors >= 256) ? "screen-256color" : "screen";
// Setup defaults bindings
serverOptions.put(OPT_PREFIX, "`");
keyMap.setUnicode(UNMAPPED);
keyMap.bind(UNMAPPED, KeyMap.range("^@-^?"));
keyMap.bind(CMD_SEND_PREFIX, serverOptions.get(OPT_PREFIX));
keyMap.bind(CMD_SEND_PREFIX, serverOptions.get(OPT_PREFIX));
keyMap.bind(CMD_SPLIT_WINDOW, "\"");
keyMap.bind(CMD_SPLIT_WINDOW + " -h", "%");
keyMap.bind(CMD_SELECT_PANE + " -U", KeyMap.key(terminal, Capability.key_up));
keyMap.bind(CMD_SELECT_PANE + " -L", KeyMap.key(terminal, Capability.key_left));
keyMap.bind(CMD_SELECT_PANE + " -R", KeyMap.key(terminal, Capability.key_right));
keyMap.bind(CMD_SELECT_PANE + " -D", KeyMap.key(terminal, Capability.key_down));
keyMap = createKeyMap(serverOptions.get(OPT_PREFIX));
}

protected KeyMap<Object> createKeyMap(String prefix) {
KeyMap<Object> keyMap = new KeyMap<>();
keyMap.setUnicode(Binding.SelfInsert);
keyMap.setNomatch(Binding.SelfInsert);
for (int i = 0; i < 255; i++) {
keyMap.bind(Binding.Discard, prefix + (char)(i));
}
keyMap.bind(Binding.Mouse, KeyMap.key(terminal, Capability.key_mouse));
keyMap.bind(CMD_SEND_PREFIX, prefix + prefix);
keyMap.bind(CMD_SPLIT_WINDOW, prefix + "\"");
keyMap.bind(CMD_SPLIT_WINDOW + " -h", prefix + "%");
keyMap.bind(CMD_SELECT_PANE + " -U", prefix + KeyMap.key(terminal, Capability.key_up));
keyMap.bind(CMD_SELECT_PANE + " -L", prefix + KeyMap.key(terminal, Capability.key_left));
keyMap.bind(CMD_SELECT_PANE + " -R", prefix + KeyMap.key(terminal, Capability.key_right));
keyMap.bind(CMD_SELECT_PANE + " -D", prefix + KeyMap.key(terminal, Capability.key_down));
return keyMap;
}

public void run() throws IOException {
Expand All @@ -103,6 +115,7 @@ public void run() throws IOException {
Attributes attributes = terminal.enterRawMode();
terminal.puts(Capability.enter_ca_mode);
terminal.puts(Capability.keypad_xmit);
terminal.trackMouse(Terminal.MouseTracking.Any);
terminal.flush();
try {
// Create first pane
Expand All @@ -116,6 +129,7 @@ public void run() throws IOException {
// Redraw loop
redrawLoop();
} finally {
terminal.trackMouse(Terminal.MouseTracking.Off);
terminal.puts(Capability.keypad_local);
terminal.puts(Capability.exit_ca_mode);
terminal.flush();
Expand Down Expand Up @@ -153,26 +167,24 @@ private void setDirty() {

private void inputLoop() {
try {
int c;
while ((c = terminal.reader().read()) >= 0) {
String pfx = serverOptions.get(OPT_PREFIX);
if (pfx != null && c == pfx.charAt(0)) {
// escape sequences
Object b = new BindingReader(terminal.reader()).readBinding(keyMap);
if (b instanceof String) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
try (PrintStream pout = new PrintStream(out);
PrintStream perr = new PrintStream(err)) {
execute(pout, perr, (String) b);
} catch (Exception e) {
// TODO: log
}
}
} else {
String s = new String(Character.toChars(c));
active.getMasterInputOutput().write(s.getBytes());
BindingReader reader = new BindingReader(terminal.reader());
while (running.get()) {
Object b = reader.readBinding(keyMap);
if (b == Binding.SelfInsert) {
active.getMasterInputOutput().write(reader.getLastBinding().getBytes());
active.getMasterInputOutput().flush();
} else if (b == Binding.Mouse) {
MouseEvent event = terminal.readMouseEvent();
//System.err.println(event.toString());
} else if (b instanceof String) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
try (PrintStream pout = new PrintStream(out);
PrintStream perr = new PrintStream(err)) {
execute(pout, perr, (String) b);
} catch (Exception e) {
// TODO: log
}
}
}
} catch (IOException e) {
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/jline/reader/LineReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ public interface LineReader {
String WHAT_CURSOR_POSITION = "what-cursor-position";
String YANK = "yank";
String YANK_POP = "yank-pop";
String MOUSE = "mouse";

//
// KeyMap names
Expand Down Expand Up @@ -341,7 +342,8 @@ enum Option {
AUTO_FRESH_LINE,
AUTO_PARAM_SLASH(true),
AUTO_REMOVE_SLASH(true),
INSERT_TAB(true);
INSERT_TAB(true),
MOUSE;

private final boolean def;

Expand Down
Loading

0 comments on commit fe83731

Please sign in to comment.