Skip to content

Commit

Permalink
less command: added key mappings for pattern line edit
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Jul 18, 2019
1 parent b33ea92 commit 6e12b27
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 14 deletions.
181 changes: 167 additions & 14 deletions builtins/src/main/java/org/jline/builtins/Less.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

import static org.jline.keymap.KeyMap.alt;
import static org.jline.keymap.KeyMap.ctrl;
import static org.jline.keymap.KeyMap.del;
import static org.jline.keymap.KeyMap.key;

public class Less {
Expand Down Expand Up @@ -87,6 +88,8 @@ public class Less {

protected int nbEof;

protected List<String> patterns = new ArrayList<String>();
protected int patternId = -1;
protected String pattern;
protected String displayPattern;

Expand Down Expand Up @@ -433,21 +436,146 @@ else if (buffer.length() > 0 && (buffer.charAt(0) == '/' || buffer.charAt(0) ==
}

private boolean search() throws IOException, InterruptedException {
// TODO add edit line key bindings
KeyMap<Operation> searchKeyMap = new KeyMap<>();
searchKeyMap.setUnicode(Operation.INSERT);
for (char i = 32; i < 256; i++) {
searchKeyMap.bind(Operation.INSERT, Character.toString(i));
}
searchKeyMap.bind(Operation.RIGHT, key(terminal, Capability.key_right), alt('l'));
searchKeyMap.bind(Operation.LEFT, key(terminal, Capability.key_left), alt('h'));
searchKeyMap.bind(Operation.NEXT_WORD, alt('w'));
searchKeyMap.bind(Operation.PREV_WORD, alt('b'));
searchKeyMap.bind(Operation.HOME, key(terminal, Capability.key_home), alt('0'));
searchKeyMap.bind(Operation.END, key(terminal, Capability.key_end), alt('$'));
searchKeyMap.bind(Operation.BACKSPACE, del());
searchKeyMap.bind(Operation.DELETE, alt('x'));
searchKeyMap.bind(Operation.DELETE_WORD, alt('X'));
searchKeyMap.bind(Operation.DELETE_LINE, ctrl('U'));
searchKeyMap.bind(Operation.UP, key(terminal, Capability.key_up), alt('k'));
searchKeyMap.bind(Operation.DOWN, key(terminal, Capability.key_down), alt('j'));
searchKeyMap.bind(Operation.ACCEPT, "\r");

boolean forward = true;
message = null;
int curPos = buffer.length();
final int begPos = curPos;
final char type = buffer.charAt(0);
String currentBuffer = "";
while (true) {
checkInterrupted();
int c = terminal.reader().read();
message = null;
if (c == '\r') {
switch (bindingReader.readBinding(searchKeyMap)) {
case INSERT:
buffer.insert(curPos++, bindingReader.getLastBinding());
break;
case BACKSPACE:
if (curPos > begPos) {
buffer.deleteCharAt(--curPos);
}
break;
case NEXT_WORD:
int newPos = buffer.length();
for (int i = curPos; i < buffer.length(); i++) {
if (buffer.charAt(i) == ' ') {
newPos = i + 1;
break;
}
}
curPos = newPos;
break;
case PREV_WORD:
newPos = begPos;
for (int i = curPos - 2; i > begPos; i--) {
if (buffer.charAt(i) == ' ') {
newPos = i + 1;
break;
}
}
curPos = newPos;
break;
case HOME:
curPos = begPos;
break;
case END:
curPos = buffer.length();
break;
case DELETE:
if (curPos >= begPos && curPos < buffer.length()) {
buffer.deleteCharAt(curPos);
}
break;
case DELETE_WORD:
while (true) {
if(curPos < buffer.length() && buffer.charAt(curPos) != ' '){
buffer.deleteCharAt(curPos);
} else {
break;
}
}
while (true) {
if(curPos - 1 >= begPos) {
if (buffer.charAt(curPos - 1) != ' ') {
buffer.deleteCharAt(--curPos);
} else {
buffer.deleteCharAt(--curPos);
break;
}
} else {
break;
}
}
break;
case DELETE_LINE:
buffer.setLength(1);
curPos = 1;
break;
case LEFT:
if (curPos > begPos) {
curPos--;
}
break;
case RIGHT:
if (curPos < buffer.length()) {
curPos++;
}
break;
case UP:
patternId++;
if (patternId >= 0 && patternId < patterns.size()) {
if (patternId == 0) {
currentBuffer = buffer.toString();
}
buffer.setLength(0);
buffer.append(type);
buffer.append(patterns.get(patternId));
curPos = buffer.length();
} else if (patternId >= patterns.size()) {
patternId = patterns.size() - 1;
}
break;
case DOWN:
if (patterns.size() > 0) {
patternId--;
buffer.setLength(0);
if (patternId < 0) {
patternId = -1;
buffer.append(currentBuffer);
} else {
buffer.append(type);
buffer.append(patterns.get(patternId));
}
curPos = buffer.length();
}
break;
case ACCEPT:
try {
if (buffer.charAt(0) == '&') {
displayPattern = buffer.length() > 1 ? buffer.toString().substring(1) : null;
String _pattern = buffer.toString().substring(1);
if (type == '&') {
displayPattern = _pattern.length() > 0 ? _pattern : null;
getPattern(true);
} else {
pattern = buffer.toString().substring(1);
pattern = _pattern;
getPattern();
if (buffer.charAt(0) == '/') {
if (type == '/') {
moveToNextMatch();
} else {
if (lines.size() - firstLineToDisplay <= size.getRows() ) {
Expand All @@ -459,13 +587,17 @@ private boolean search() throws IOException, InterruptedException {
forward = false;
}
}
if (_pattern.length() > 0 && !patterns.contains(_pattern)) {
patterns.add(_pattern);
}
patternId = -1;
buffer.setLength(0);
} catch (PatternSyntaxException e) {
String str = e.getMessage();
if (str.indexOf('\n') > 0) {
str = str.substring(0, str.indexOf('\n'));
}
if (buffer.charAt(0) == '&') {
if (type == '&') {
displayPattern = null;
} else {
pattern = null;
Expand All @@ -477,10 +609,8 @@ private boolean search() throws IOException, InterruptedException {
message = null;
}
return forward;
} else {
buffer.append((char) c);
}
display(false);
display(false, curPos);
}
}

Expand Down Expand Up @@ -733,6 +863,10 @@ private boolean toBeDisplayed(AttributedString curLine, Pattern dpCompiled) {
}

synchronized boolean display(boolean oneScreen) throws IOException {
return display(oneScreen, null);
}

synchronized boolean display(boolean oneScreen, Integer curPos) throws IOException {
List<AttributedString> newLines = new ArrayList<>();
int width = size.getColumns() - (printLineNumbers ? 8 : 0);
int height = size.getRows();
Expand Down Expand Up @@ -818,7 +952,11 @@ synchronized boolean display(boolean oneScreen) throws IOException {
newLines.add(msg.toAttributedString());

display.resize(size.getRows(), size.getColumns());
display.update(newLines, -1);
if (curPos == null) {
display.update(newLines, -1);
} else {
display.update(newLines, size.cursorPos(size.getRows() - 1, curPos + 1));
}
return false;
}

Expand Down Expand Up @@ -949,8 +1087,23 @@ protected enum Operation {
DELETE_FILE,

//
CHAR
CHAR,

// Edit pattern
INSERT,
RIGHT,
LEFT,
NEXT_WORD,
PREV_WORD,
HOME,
END,
BACKSPACE,
DELETE,
DELETE_WORD,
DELETE_LINE,
ACCEPT,
UP,
DOWN
}

static class InterruptibleInputStream extends FilterInputStream {
Expand Down
19 changes: 19 additions & 0 deletions builtins/src/main/resources/org/jline/builtins/less-help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,22 @@
Chop (truncate) long lines rather than wrapping.
-x [N[,...]] --tabs=[N[,...]]
Set tab stops (from command line).

---------------------------------------------------------------------------

PATTERN EDITING

These keys can be used to edit pattern

RightArrow ... ESC-l ... Move cursor right one character.
LeftArrow .... ESC-h ... Move cursor left one character.
.............. ESC-w ... Move cursor right one word.
.............. ESC-b ... Move cursor left one word.
HOME ......... ESC-0 ... Move cursor to start of line.
END .......... ESC-$ ... Move cursor to end of line.
BACKSPACE .............. Delete char to left of cursor.
DELETE ....... ESC-x ... Delete char under cursor.
.............. ESC-X ... Delete word under cursor.
ctrl-U ................. Delete entire line.
UpArrow ...... ESC-k ... Retrieve previous pattern.
DownArrow .... ESC-j ... Retrieve next pattern.

1 comment on commit 6e12b27

@mattirn
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.