Skip to content

Commit

Permalink
Fix quote parsing and escaping, fixes #331
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed Nov 26, 2018
1 parent dfedc72 commit 7783c03
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 34 deletions.
54 changes: 25 additions & 29 deletions reader/src/main/java/org/jline/reader/impl/DefaultParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,37 +110,25 @@ public ParsedLine parse(final String line, final int cursor, ParseContext contex
if (quoteStart < 0 && isQuoteChar(line, i)) {
// Start a quote block
quoteStart = i;
} else if (quoteStart >= 0) {
// In a quote block
if (line.charAt(quoteStart) == line.charAt(i) && !isEscaped(line, i)) {
// End the block; arg could be empty, but that's fine
} else if (quoteStart >= 0 && line.charAt(quoteStart) == line.charAt(i) && !isEscaped(line, i)) {
// End quote block
quoteStart = -1;
if (rawWordCursor >= 0 && rawWordLength < 0) {
rawWordLength = i - rawWordStart + 1;
}
} else if (quoteStart < 0 && isDelimiter(line, i)) {
// Delimiter
if (current.length() > 0) {
words.add(current.toString());
current.setLength(0);
quoteStart = -1;
current.setLength(0); // reset the arg
if (rawWordCursor >= 0 && rawWordLength < 0) {
rawWordLength = i - rawWordStart + 1;
}
} else {
if (!isEscapeChar(line, i)) {
// Take the next character
current.append(line.charAt(i));
rawWordLength = i - rawWordStart;
}
}
rawWordStart = i + 1;
} else {
// Not in a quote block
if (isDelimiter(line, i)) {
if (current.length() > 0) {
words.add(current.toString());
current.setLength(0); // reset the arg
if (rawWordCursor >= 0 && rawWordLength < 0) {
rawWordLength = i - rawWordStart;
}
}
rawWordStart = i + 1;
} else {
if (!isEscapeChar(line, i)) {
current.append(line.charAt(i));
}
if (!isEscapeChar(line, i)) {
current.append(line.charAt(i));
}
}
}
Expand Down Expand Up @@ -373,6 +361,7 @@ public String line() {
public CharSequence escape(CharSequence candidate, boolean complete) {
StringBuilder sb = new StringBuilder(candidate);
Predicate<Integer> needToBeEscaped;
String quote = openingQuote;
if (escapeChars != null) {
// Completion is protected by an opening quote:
// Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does.
Expand All @@ -390,11 +379,18 @@ public CharSequence escape(CharSequence candidate, boolean complete) {
sb.insert(i++, escapeChars[0]);
}
}
} else if (openingQuote == null) {
for (int i = 0; i < sb.length(); i++) {
if (isDelimiterChar(sb, i)) {
quote = "'";
break;
}
}
}
if (openingQuote != null) {
sb.insert(0, openingQuote);
if (quote != null) {
sb.insert(0, quote);
if (complete) {
sb.append(openingQuote);
sb.append(quote);
}
}
return sb;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ public void testEscapedQuotes() {
assertEquals(Arrays.asList("'1", "2", "3"), delimited.words());

delimited = parser.parse("'1 '2\\' 3", 0);
assertEquals(Arrays.asList("1 ", "2'", "3"), delimited.words());
assertEquals(Arrays.asList("1 2'", "3"), delimited.words());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
package org.jline.reader.completer;

import org.jline.reader.LineReader;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.ReaderTestSupport;
import org.jline.reader.impl.completer.StringsCompleter;
Expand All @@ -34,13 +35,30 @@ public void test1() throws Exception {

@Test
public void escapeCharsNull() throws Exception {
DefaultParser dp = (DefaultParser)reader.getParser();
DefaultParser dp = (DefaultParser) reader.getParser();
dp.setEscapeChars(null);
reader.setVariable(LineReader.ERRORS, 0);
reader.setParser(dp);
reader.setCompleter(new StringsCompleter("foo bar", "bar"));

assertBuffer("foo bar ", new TestBuffer("f").tab());
assertBuffer("bar ", new TestBuffer("b").tab());
assertBuffer("'foo bar' ", new TestBuffer("f").tab());
assertBuffer("'foo bar' ", new TestBuffer("'f").tab());
assertBuffer("foo'b", new TestBuffer("foo'b").tab());
assertBuffer("bar'f", new TestBuffer("bar'f").tab());
}


@Test
public void escapeChars() throws Exception {
DefaultParser dp = (DefaultParser) reader.getParser();
dp.setEscapeChars(new char[] { '\\' });
reader.setVariable(LineReader.ERRORS, 0);
reader.setParser(dp);
reader.setCompleter(new StringsCompleter("foo bar", "bar"));

assertBuffer("foo\\ bar ", new TestBuffer("f").tab());
assertBuffer("'bar' ", new TestBuffer("'b").tab());
assertBuffer("'bar'f", new TestBuffer("'bar'f").tab());
assertBuffer("bar'f", new TestBuffer("bar'f").tab());
}

}

0 comments on commit 7783c03

Please sign in to comment.