Skip to content

Commit

Permalink
Merge pull request #354 from mattirn/indentation
Browse files Browse the repository at this point in the history
New line automatic indentation after open bracket
  • Loading branch information
mattirn committed Oct 11, 2019
2 parents 95b6a65 + 3025f70 commit ca0278a
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 36 deletions.
3 changes: 3 additions & 0 deletions builtins/src/test/java/org/jline/example/Example.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.jline.builtins.Widgets.ArgDesc;
import org.jline.keymap.KeyMap;
import org.jline.reader.*;
import org.jline.reader.LineReader.Option;
import org.jline.reader.LineReader.SuggestionType;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.DefaultParser.Bracket;
Expand Down Expand Up @@ -313,6 +314,8 @@ public void complete(LineReader reader, ParsedLine line, List<Candidate> candida
.completer(completer)
.parser(parser)
.variable(LineReader.SECONDARY_PROMPT_PATTERN, "%M%P > ")
.variable(LineReader.INDENTATION, 2)
.option(Option.INSERT_BRACKET, true)
.build();
AutopairWidgets autopairWidgets = new AutopairWidgets(reader);
AutosuggestionWidgets autosuggestionWidgets = new AutosuggestionWidgets(reader);
Expand Down
16 changes: 16 additions & 0 deletions reader/src/main/java/org/jline/reader/EOFError.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,33 @@ public class EOFError extends SyntaxError {
private static final long serialVersionUID = 1L;

private final String missing;
private final int openBrackets;
private final String nextClosingBracket;

public EOFError(int line, int column, String message) {
this(line, column, message, null);
}

public EOFError(int line, int column, String message, String missing) {
this(line, column, message, missing, 0, null);
}

public EOFError(int line, int column, String message, String missing, int openBrackets, String nextClosingBracket) {
super(line, column, message);
this.missing = missing;
this.openBrackets = openBrackets;
this.nextClosingBracket = nextClosingBracket;
}

public String getMissing() {
return missing;
}

public int getOpenBrackets(){
return openBrackets;
}

public String getNextClosingBracket() {
return nextClosingBracket;
}
}
8 changes: 8 additions & 0 deletions reader/src/main/java/org/jline/reader/LineReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,11 @@ public interface LineReader {
*/
String HISTORY_FILE_SIZE = "history-file-size";

/**
* New line automatic indentation after opening/closing bracket.
*/
String INDENTATION = "indentation";

Map<String, KeyMap<Binding>> defaultKeyMaps();

enum Option {
Expand Down Expand Up @@ -418,6 +423,9 @@ enum Option {

/** if history search is fully case insensitive */
CASE_INSENSITIVE_SEARCH,

/** Automatic insertion of closing bracket */
INSERT_BRACKET,
;

private final boolean def;
Expand Down
92 changes: 59 additions & 33 deletions reader/src/main/java/org/jline/reader/impl/DefaultParser.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2018, the original author or authors.
* Copyright (c) 2002-2019, the original author or authors.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
Expand All @@ -17,8 +17,8 @@
import org.jline.reader.Parser;

public class DefaultParser implements Parser {
public enum Bracket {

public enum Bracket {
ROUND, // ()
CURLY, // {}
SQUARE, // []
Expand All @@ -32,11 +32,11 @@ public enum Bracket {
private boolean eofOnUnclosedQuote;

private boolean eofOnEscapedNewLine;

private char[] openingBrackets = null;

private char[] closingBrackets = null;

//
// Chainable setters
//
Expand All @@ -56,11 +56,11 @@ public DefaultParser eofOnUnclosedQuote(boolean eofOnUnclosedQuote) {
return this;
}

public DefaultParser eofOnUnclosedBracket(Bracket... brackets){
public DefaultParser eofOnUnclosedBracket(Bracket... brackets) {
setEofOnUnclosedBracket(brackets);
return this;
}

public DefaultParser eofOnEscapedNewLine(boolean eofOnEscapedNewLine) {
this.eofOnEscapedNewLine = eofOnEscapedNewLine;
return this;
Expand Down Expand Up @@ -102,7 +102,7 @@ public boolean isEofOnEscapedNewLine() {
return eofOnEscapedNewLine;
}

public void setEofOnUnclosedBracket(Bracket... brackets){
public void setEofOnUnclosedBracket(Bracket... brackets) {
if (brackets == null) {
openingBrackets = null;
closingBrackets = null;
Expand Down Expand Up @@ -134,7 +134,7 @@ public void setEofOnUnclosedBracket(Bracket... brackets){
}
}
}

public ParsedLine parse(final String line, final int cursor, ParseContext context) {
List<String> words = new LinkedList<>();
StringBuilder current = new StringBuilder();
Expand All @@ -144,7 +144,7 @@ public ParsedLine parse(final String line, final int cursor, ParseContext contex
int rawWordCursor = -1;
int rawWordLength = -1;
int rawWordStart = 0;
BracketChecker bracketChecker = new BracketChecker();
BracketChecker bracketChecker = new BracketChecker(cursor);
boolean quotedWord = false;

for (int i = 0; (line != null) && (i < line.length()); i++) {
Expand Down Expand Up @@ -174,7 +174,7 @@ public ParsedLine parse(final String line, final int cursor, ParseContext contex
rawWordLength = i - rawWordStart + 1;
}
quoteStart = -1;
quotedWord = false;
quotedWord = false;
} else if (quoteStart < 0 && isDelimiter(line, i)) {
// Delimiter
if (current.length() > 0) {
Expand All @@ -188,7 +188,7 @@ public ParsedLine parse(final String line, final int cursor, ParseContext contex
} else {
if (!isEscapeChar(line, i)) {
current.append(line.charAt(i));
if (quoteStart < 0) {
if (quoteStart < 0) {
bracketChecker.check(line, i);
}
}
Expand Down Expand Up @@ -217,11 +217,18 @@ public ParsedLine parse(final String line, final int cursor, ParseContext contex
throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\''
? "quote" : "dquote");
}
if (bracketChecker.isOpeningBracketMissing()) {
throw new EOFError(-1, -1, "Missing opening bracket", "missing: " + bracketChecker.getMissingOpeningBracket());
}
if (bracketChecker.isClosingBracketMissing()) {
throw new EOFError(-1, -1, "Missing closing brackets", "add: " + bracketChecker.getMissingClosingBrackets());
if (bracketChecker.isClosingBracketMissing() || bracketChecker.isOpeningBracketMissing()) {
String message = null;
String missing = null;
if(bracketChecker.isClosingBracketMissing()) {
message = "Missing closing brackets";
missing = "add: " + bracketChecker.getMissingClosingBrackets();
} else {
message = "Missing opening bracket";
missing = "missing: " + bracketChecker.getMissingOpeningBracket();
}
throw new EOFError(-1, -1, message, missing,
bracketChecker.getOpenBrackets(), bracketChecker.getNextClosingBracket());
}
}

Expand Down Expand Up @@ -347,10 +354,15 @@ private boolean isRawQuoteChar(char key) {
private class BracketChecker {
private int missingOpeningBracket = -1;
private List<Integer> nested = new ArrayList<>();

public BracketChecker(){}

public void check(final CharSequence buffer, final int pos){
private int openBrackets = 0;
private int cursor;
private String nextClosingBracket;

public BracketChecker(int cursor) {
this.cursor = cursor;
}

public void check(final CharSequence buffer, final int pos) {
if (openingBrackets == null || pos < 0) {
return;
}
Expand All @@ -366,25 +378,31 @@ public void check(final CharSequence buffer, final int pos){
missingOpeningBracket = bid;
}
}
}
}
if (cursor > pos) {
openBrackets = nested.size();
if (nested.size() > 0) {
nextClosingBracket = String.valueOf(closingBrackets[nested.get(nested.size() - 1)]);
}
}
}
public boolean isOpeningBracketMissing(){

public boolean isOpeningBracketMissing() {
return missingOpeningBracket != -1;
}
public String getMissingOpeningBracket(){

public String getMissingOpeningBracket() {
if (!isOpeningBracketMissing()) {
return null;
}
return Character.toString(openingBrackets[missingOpeningBracket]);
}

public boolean isClosingBracketMissing(){
public boolean isClosingBracketMissing() {
return !nested.isEmpty();
}

public String getMissingClosingBrackets(){
public String getMissingClosingBrackets() {
if (!isClosingBracketMissing()) {
return null;
}
Expand All @@ -394,15 +412,23 @@ public String getMissingClosingBrackets(){
}
return out.toString();
}

private int bracketId(final char[] brackets, final CharSequence buffer, final int pos){

public int getOpenBrackets() {
return openBrackets;
}

public String getNextClosingBracket() {
return nested.size() > 1 ? nextClosingBracket : null;
}

private int bracketId(final char[] brackets, final CharSequence buffer, final int pos) {
for (int i=0; i < brackets.length; i++) {
if (buffer.charAt(pos) == brackets[i]) {
return i;
}
}
return -1;
}
return -1;
}
}

/**
Expand Down Expand Up @@ -552,4 +578,4 @@ public int rawWordLength() {
}
}

}
}
45 changes: 42 additions & 3 deletions reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public class LineReaderImpl implements LineReader, Flushable
public static final String DEFAULT_COMPLETION_STYLE_DESCRIPTION = "90"; // dark gray
public static final String DEFAULT_COMPLETION_STYLE_GROUP = "35;1"; // magenta
public static final String DEFAULT_COMPLETION_STYLE_SELECTION = "7"; // inverted
public static final int DEFAULT_INDENTATION = 0;

private static final int MIN_ROWS = 3;

Expand Down Expand Up @@ -259,7 +260,6 @@ protected enum BellType {
protected String keyMap;

protected int smallTerminalOffset = 0;

/*
* accept-and-infer-next-history, accept-and-hold & accept-line-and-down-history
*/
Expand Down Expand Up @@ -2158,6 +2158,7 @@ protected boolean insertClose(String s) {

long blink = getLong(BLINK_MATCHING_PAREN, DEFAULT_BLINK_MATCHING_PAREN);
if (blink <= 0) {
removeIndentation();
return true;
}

Expand All @@ -2168,11 +2169,31 @@ protected boolean insertClose(String s) {
redisplay();

peekCharacter(blink);

int blinkPosition = buf.cursor();
buf.cursor(closePosition);

if (blinkPosition != closePosition - 1) {
removeIndentation();
}
return true;
}

private void removeIndentation(){
int indent = getInt(INDENTATION, DEFAULT_INDENTATION);
if (indent > 0) {
buf.move(-1);
for (int i = 0; i < indent; i++) {
buf.move(-1);
if (buf.currChar() == ' ') {
buf.delete();
} else {
break;
}
}
endOfLine();
}
}

protected boolean viMatchBracket() {
return doViMatchBracket();
}
Expand Down Expand Up @@ -2921,6 +2942,7 @@ protected boolean acceptAndInferNextHistory() {

protected boolean acceptLine() {
parsedLine = null;
int curPos = 0;
if (!isSet(Option.DISABLE_EVENT_EXPANSION)) {
try {
String str = buf.toString();
Expand All @@ -2937,9 +2959,19 @@ protected boolean acceptLine() {
}
}
try {
curPos = buf.cursor();
parsedLine = parser.parse(buf.toString(), buf.cursor(), ParseContext.ACCEPT_LINE);
} catch (EOFError e) {
buf.write("\n");
StringBuilder sb = new StringBuilder("\n");
indention(e.getOpenBrackets(), sb);
int curMove = sb.length();
if (isSet(Option.INSERT_BRACKET) && e.getOpenBrackets() > 1 && e.getNextClosingBracket() != null) {
sb.append('\n');
indention(e.getOpenBrackets() - 1, sb);
sb.append(e.getNextClosingBracket());
}
buf.write(sb.toString());
buf.cursor(curPos + curMove);
return true;
} catch (SyntaxError e) {
// do nothing
Expand All @@ -2949,6 +2981,13 @@ protected boolean acceptLine() {
return true;
}

void indention(int nb, StringBuilder sb) {
int indent = getInt(INDENTATION, DEFAULT_INDENTATION)*nb;
for (int i = 0; i < indent; i++) {
sb.append(' ');
}
}

protected boolean selfInsert() {
for (int count = this.count; count > 0; count--) {
putString(getLastBinding());
Expand Down

0 comments on commit ca0278a

Please sign in to comment.