/*
* Licensed to Luca Cavanna (the "Author") under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.shell.console;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import jline.console.ConsoleReader;
import jline.console.completer.Completer;
import jline.console.completer.CompletionHandler;
import jline.console.history.FileHistory;
import jline.console.history.History;
import org.elasticsearch.common.base.Function;
import org.elasticsearch.common.collect.Iterators;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.name.Named;
import org.elasticsearch.shell.ShellSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <code>Console</code> implementation that depends on JLine for the input.
*
* @author Luca Cavanna
*/
public class JLineConsole extends AbstractConsole {
private static final Logger logger = LoggerFactory.getLogger(JLineConsole.class);
private final ConsoleReader reader;
private final FileHistory fileHistory;
/**
* Constructor for the JLineConsole
* @param appName the application name
* @param in the <code>InputStream</code> to read input from
* @param out the <code>PrintStream</code> to print output to
* @param completerHolder holds an optional JLine completer to auto-complete commands
*/
@Inject
JLineConsole(@Named("appName") String appName,
@Named("shellInput") InputStream in, @Named("shellOutput") PrintStream out,
ShellSettings shellSettings, CompleterHolder completerHolder) {
super(out);
try {
this.reader = new ConsoleReader(appName, in, out, null);
this.reader.setExpandEvents(false);
String userHome = System.getProperty("user.home");
if (userHome != null && userHome.length()>0) {
this.fileHistory = new FileHistory(new File(userHome, ShellSettings.HISTORY_FILE));
this.reader.setHistory(fileHistory);
} else {
this.fileHistory = null;
}
Integer maxSuggestions = shellSettings.settings().getAsInt(ShellSettings.SUGGESTIONS_MAX, 100);
this.reader.setAutoprintThreshold(maxSuggestions);
reader.setBellEnabled(false);
if (completerHolder.completer != null) {
reader.addCompleter(completerHolder.completer);
}
if (completerHolder.completionHandler != null) {
reader.setCompletionHandler(completerHolder.completionHandler);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
static class CompleterHolder {
@Inject(optional=true) Completer completer;
@Inject(optional=true) CompletionHandler completionHandler;
}
/**
* Reads a line using the JLine {@link ConsoleReader}
* @param prompt the prompt to be printed
* @return the line read
* @throws IOException in case of problems while reading the line
*/
@Override
public String readLine(String prompt) throws IOException {
String line = reader.readLine(prompt);
logger.debug("Read line {}", line);
return line;
}
@Override
public Iterator<CharSequence> getHistoryEntries() {
if (fileHistory == null) {
return new ArrayList<CharSequence>().iterator();
}
return Iterators.transform(fileHistory.iterator(), new Function<History.Entry, CharSequence>() {
@Override
public CharSequence apply(jline.console.history.History.Entry entry) {
return entry.value();
}
});
}
@Override
public void shutdown() {
super.shutdown();
if (fileHistory != null) {
try {
fileHistory.flush();
} catch (IOException e) {
logger.error("Error while flushing the history to file {}", fileHistory.getFile().getAbsolutePath(), e);
}
}
//Calling shutdown breaks the shutdown hook, which waits for it forever
//reader.shutdown();
}
}