Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix and improve CandidateCompletionHandler #215

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ public class CandidateListCompletionHandler
private boolean printSpaceAfterFullCompletion = true;
private boolean stripAnsi;

/**
* if true, existing text after cursor matchinga completion to insert
* will not be pushed back behind the completion, but replaced
* by the completion
*/
private boolean consumeMatchingSuffix = false;

public boolean getPrintSpaceAfterFullCompletion() {
return printSpaceAfterFullCompletion;
}
Expand All @@ -45,6 +52,14 @@ public void setPrintSpaceAfterFullCompletion(boolean printSpaceAfterFullCompleti
this.printSpaceAfterFullCompletion = printSpaceAfterFullCompletion;
}

public boolean getConsumeMatchingSuffix() {
return consumeMatchingSuffix;
}

public void setConsumeMatchingSuffix(boolean consumeMatchingSuffix) {
this.consumeMatchingSuffix = consumeMatchingSuffix;
}

public boolean isStripAnsi() {
return stripAnsi;
}
Expand All @@ -63,21 +78,7 @@ public boolean complete(final ConsoleReader reader, final List<CharSequence> can
// if there is only one completion, then fill in the buffer
if (candidates.size() == 1) {
String value = Ansi.stripAnsi(candidates.get(0).toString());

if (buf.cursor == buf.buffer.length()
&& printSpaceAfterFullCompletion
&& !value.endsWith(" ")) {
value += " ";
}

// fail if the only candidate is the same as the current buffer
if (value.equals(buf.toString())) {
return false;
}

setBuffer(reader, value, pos);

return true;
return completeSingleCandidate(reader, pos, buf, value);
}
else if (candidates.size() > 1) {
String value = getUnambiguousCompletions(candidates);
Expand All @@ -92,17 +93,94 @@ else if (candidates.size() > 1) {
return true;
}

public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
protected boolean completeSingleCandidate(ConsoleReader reader, int pos, CursorBuffer buf, String value) throws IOException {
// no insert if the only candidate is the same as the current buffer
if (buf.length() >= pos + value.length() &&
value.equals(buf.toString().substring(pos, pos + value.length()))) {
reader.setCursorPosition(pos + value.length());
} else {
setBuffer(reader, value, pos);
}

if (printSpaceAfterFullCompletion
&& !value.endsWith(" ")) {
doPrintSpaceAfterFullCOmpletion(reader);
}

return true;
}

/**
* This method is called after completing a candidate that
* does not end with a blank, when the option printSpaceAfterFullCompletion is true.
*
* The standard behavior is to insert a blank unless the next char is a blank,
* wherever the cursor is in the buffer, and to move the cursor beyond the
* inserted / existing blank.
*
* @param reader
* @throws IOException
*/
protected void doPrintSpaceAfterFullCOmpletion(ConsoleReader reader) throws IOException {
// at end of buffer or next char is not blank already
if ((reader.getCursorBuffer().cursor >= reader.getCursorBuffer().length() ||
reader.getCursorBuffer().buffer.toString().charAt(reader.getCursorBuffer().cursor) != ' ')) {
reader.putString(" ");
} else {
// if blank existed, move beyond it
reader.moveCursor(1);
}
}

public void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
IOException
{
if (getConsumeMatchingSuffix()) {
// consume only if prefix matches
int commonPrefixLength = greatestCommonPrefixLength(value,
reader.getCursorBuffer().buffer.toString().substring(offset));
if (commonPrefixLength == value.length()) {
// nothing to do other than advancing the cursor
reader.setCursorPosition(offset + value.length());
return;
}
}
int suffixStart = 0;
// backspace cursor to start of completion
while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) {
// empty
suffixStart++;
}

if (getConsumeMatchingSuffix()) {
int currentVirtualPos = offset;
String currentBuffer = reader.getCursorBuffer().buffer.toString();
while (
suffixStart < value.length() // value still has chars to delete
&& currentBuffer.length() > currentVirtualPos // buffer still has chars to delete
// character to delete matches value suffix
&& currentBuffer.charAt(currentVirtualPos) == value.charAt(suffixStart)
// do delete
&& reader.delete()) {
suffixStart ++;
currentVirtualPos++;
}
}

reader.putString(value);
reader.setCursorPosition(offset + value.length());
}

static int greatestCommonPrefixLength(final CharSequence a, final CharSequence b) {
int minLength = Math.min(a.length(), b.length());
int i = 0;
for (; i < minLength; i++) {
if (a.charAt(i) != b.charAt(i)) {
break;
}
}
return i;
}

/**
* Print out the candidates. If the size of the candidates is greater than the
* {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning.
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/jline/console/completer/CompletionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,13 @@
*/
public interface CompletionHandler
{
/**
* execute completion, by showing candidates as alternatives, and possibly
* inserting a candidate at position, removing all characters between
* position and current cursol location.
*
* @param position start position in buffer for candidates
* @throws IOException
*/
boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException;
}
8 changes: 7 additions & 1 deletion src/main/java/jline/internal/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ private static Properties initProperties() {

private static void loadProperties(final URL url, final Properties props) throws IOException {
Log.debug("Loading properties from: ", url);
InputStream input = url.openStream();
InputStream input;
try {
input = url.openStream();
} catch (IOException e) {
Log.debug("Could not load properties from " + url + " : " + e.getMessage());
return;
}
try {
props.load(new BufferedInputStream(input));
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/jline/console/ConsoleReaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ public void testComplete() throws Exception {

out.write("read and\033[D\033[D\t\n".getBytes());

assertEquals("read andnd", console.readLine());
assertEquals("read and ", console.readLine());

out.close();
}
Expand Down
Loading