DefaultParser implements Parser { public ParsedLine parse(final String line, final int cursor, ParseContext context) { List<String> words = new LinkedList<>(); StringBuilder current = new StringBuilder(); int wordCursor = -1; int wordIndex = -1; int quoteStart = -1; int rawWordCursor = -1; int rawWordLength = -1; int rawWordStart = 0; BracketChecker bracketChecker = new BracketChecker(cursor); boolean quotedWord = false; for (int i = 0; (line != null) && (i < line.length()); i++) { if (i == cursor) { wordIndex = words.size(); wordCursor = current.length(); rawWordCursor = i - rawWordStart; } if (quoteStart < 0 && isQuoteChar(line, i)) { quoteStart = i; if (current.length()==0) { quotedWord = true; if (context == ParseContext.SPLIT_LINE) { current.append(line.charAt(i)); } } else { current.append(line.charAt(i)); } } else if (quoteStart >= 0 && line.charAt(quoteStart) == line.charAt(i) && !isEscaped(line, i)) { if (!quotedWord || context == ParseContext.SPLIT_LINE) { current.append(line.charAt(i)); } else if (rawWordCursor >= 0 && rawWordLength < 0) { rawWordLength = i - rawWordStart + 1; } quoteStart = -1; quotedWord = false; } else if (quoteStart < 0 && isDelimiter(line, i)) { if (current.length() > 0) { words.add(current.toString()); current.setLength(0); if (rawWordCursor >= 0 && rawWordLength < 0) { rawWordLength = i - rawWordStart; } } rawWordStart = i + 1; } else { if (!isEscapeChar(line, i)) { current.append(line.charAt(i)); if (quoteStart < 0) { bracketChecker.check(line, i); } } else if (context == ParseContext.SPLIT_LINE) { current.append(line.charAt(i)); } } } if (current.length() > 0 || cursor == line.length()) { words.add(current.toString()); if (rawWordCursor >= 0 && rawWordLength < 0) { rawWordLength = line.length() - rawWordStart; } } if (cursor == line.length()) { wordIndex = words.size() - 1; wordCursor = words.get(words.size() - 1).length(); rawWordCursor = cursor - rawWordStart; rawWordLength = rawWordCursor; } if (context != ParseContext.COMPLETE && context != ParseContext.SPLIT_LINE) { if (eofOnEscapedNewLine && isEscapeChar(line, line.length() - 1)) { throw new EOFError(-1, -1, "Escaped new line", "newline"); } if (eofOnUnclosedQuote && quoteStart >= 0) { throw new EOFError(-1, -1, "Missing closing quote", line.charAt(quoteStart) == '\'' ? "quote" : "dquote"); } 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()); } } String openingQuote = quotedWord ? line.substring(quoteStart, quoteStart + 1) : null; return new ArgumentList(line, words, wordIndex, wordCursor, cursor, openingQuote, rawWordCursor, rawWordLength); }  DefaultParser quoteChars(final char[] chars); DefaultParser escapeChars(final char[] chars); DefaultParser eofOnUnclosedQuote(boolean eofOnUnclosedQuote); DefaultParser eofOnUnclosedBracket(Bracket... brackets); DefaultParser eofOnEscapedNewLine(boolean eofOnEscapedNewLine); DefaultParser regexVariable(String regexVariable); DefaultParser regexCommand(String regexCommand); DefaultParser commandGroup(int commandGroup); void setQuoteChars(final char[] chars); char[] getQuoteChars(); void setEscapeChars(final char[] chars); char[] getEscapeChars(); void setEofOnUnclosedQuote(boolean eofOnUnclosedQuote); boolean isEofOnUnclosedQuote(); void setEofOnEscapedNewLine(boolean eofOnEscapedNewLine); boolean isEofOnEscapedNewLine(); void setEofOnUnclosedBracket(Bracket... brackets); void setRegexVariable(String regexVariable); void setRegexCommand(String regexCommand); void setCommandGroup(int commandGroup); @Override boolean validCommandName(String name); @Override boolean validVariableName(String name); @Override String getCommand(final String line); @Override String getVariable(final String line); ParsedLine parse(final String line, final int cursor, ParseContext context); boolean isDelimiter(final CharSequence buffer, final int pos); boolean isQuoted(final CharSequence buffer, final int pos); boolean isQuoteChar(final CharSequence buffer, final int pos); @Override boolean isEscapeChar(char ch); boolean isEscapeChar(final CharSequence buffer, final int pos); boolean isEscaped(final CharSequence buffer, final int pos); boolean isDelimiterChar(CharSequence buffer, int pos);  }
@Test public void testEscapedWord() { DefaultParser parser = new DefaultParser(); CompletingParsedLine line = (CompletingParsedLine) parser.parse("foo second\\ param \"quoted param\"", 15); assertNotNull(line); assertNotNull(line.words()); assertEquals("foo second\\ param \"quoted param\"", line.line()); assertEquals(15, line.cursor()); assertEquals(3, line.words().size()); assertEquals("second param", line.word()); assertEquals(10, line.wordCursor()); assertEquals(11, line.rawWordCursor()); assertEquals(13, line.rawWordLength()); }
@Test public void testQuotedWord() { DefaultParser parser = new DefaultParser(); CompletingParsedLine line = (CompletingParsedLine) parser.parse("foo second\\ param \"quoted param\"", 20); assertNotNull(line); assertNotNull(line.words()); assertEquals("foo second\\ param \"quoted param\"", line.line()); assertEquals(20, line.cursor()); assertEquals(3, line.words().size()); assertEquals("quoted param", line.word()); assertEquals(1, line.wordCursor()); assertEquals(2, line.rawWordCursor()); assertEquals(14, line.rawWordLength()); }
@Test public void testSplitLine() { DefaultParser parser = new DefaultParser(); CompletingParsedLine line = (CompletingParsedLine) parser.parse("foo second\\ param \"quoted param\"", 0, ParseContext.SPLIT_LINE); assertNotNull(line); assertNotNull(line.words()); assertEquals("foo", line.words().get(0)); assertEquals("second\\ param", line.words().get(1)); assertEquals("\"quoted param\"", line.words().get(2)); }