All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.petals.cli.shell.completer.CommandCompleter Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/**
 * Copyright (c) 2010-2012 EBM WebSourcing, 2012-2016 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.cli.shell.completer;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.ow2.petals.cli.api.command.Command;

import jline.console.completer.Completer;
import jline.console.completer.StringsCompleter;

/**
 * @author Nicolas Oddoux - EBM WebSourcing
 */
public class CommandCompleter implements Completer {

    private final Map commands;

    public CommandCompleter(final Map commands) {
        this.commands = commands;
    }

    @Override
    public int complete(final String buffer, final int cursor, final List candidates) {
        if (this.commands != null) {
            // TODO handle quotes

            final String lineBegin = buffer.substring(0, cursor);
            final int lastSpaceIndex = lineBegin.lastIndexOf(" ");

            if (lastSpaceIndex == -1) {
                // first word of the line => completion for the command
                final String cmdName = lineBegin.substring(0, cursor);
                final Completer cmdCompleter = new StringsCompleter(this.commands.keySet());
                final int completionIndex = cmdCompleter.complete(cmdName, cursor, candidates);
                removeUselessSpace(buffer, cursor, candidates);
                return completionIndex;
            } else if (lastSpaceIndex == cursor - 1) {
                // the previous character is a space
                return completeOptionOrArgument(buffer, cursor, candidates, lineBegin, lastSpaceIndex, "");
            } else {
                // completion for the argument and the options
                final String lastWordToComplete = lineBegin.substring(lastSpaceIndex + 1, cursor);
                return completeOptionOrArgument(buffer, cursor, candidates, lineBegin, lastSpaceIndex,
                        lastWordToComplete);
            }
        } else {
            return -1;
        }
    }

    protected int completeOptionOrArgument(final String buffer, final int cursor, final List candidates,
            final String lineBegin, final int lastSpaceIndex, final String lastWordToComplete) {
        final int firstSpaceIndex = buffer.indexOf(" ");
        final String cmdName = buffer.substring(0, firstSpaceIndex);
        String lLineBegin = lineBegin;
        int lLastSpaceIndex = lastSpaceIndex;

        if (this.commands.containsKey(cmdName)) {
            final Command command = this.commands.get(cmdName);

            // looking for the previous option
            int optionArgNb = 0;
            int previousSpaceIndex = lLastSpaceIndex;
            String previousWord = null;
            do {
                lLineBegin = lLineBegin.substring(0, previousSpaceIndex);
                optionArgNb++;
                lLastSpaceIndex = previousSpaceIndex;
                previousSpaceIndex = lLineBegin.lastIndexOf(" ");

                if (previousSpaceIndex == -1) {
                    // there is no option in the previous words
                    return completeOptionPossibilityOrAgument(buffer, cursor, candidates, command,
                            lastWordToComplete);
                }

                previousWord = lLineBegin.substring(previousSpaceIndex + 1, lLastSpaceIndex);
            } while (!previousWord.startsWith("-"));

            final Options options = command.getOptions();
            if (options.hasOption(previousWord)) {
                // use short option to get the completer in the map
                final Option option = options.getOption(previousWord);
                if (option.getArgs() >= optionArgNb) {
                    return completeOptionValue(buffer, cursor, candidates, command,
                            option, lLastSpaceIndex);
                } else {
                    return completeOptionPossibilityOrAgument(buffer, cursor, candidates, command,
                            lastWordToComplete);
                }
            }
        }

        return -1;
    }

    protected static final int completeOptionValue(final String buffer, final int cursor,
            final List candidates, final Command command, final Option option, final int lastSpaceIndex) {

        final Map optionCompleters = command.getOptionCompleters();
        if (optionCompleters != null) {
            final Completer completer;
            if (option.getOpt() != null) {
                completer = optionCompleters.get(option.getOpt());
            } else if (option.getLongOpt() != null) {
                completer = optionCompleters.get(option.getLongOpt());
            } else {
                completer = null;
            }

            if (completer != null) {
                // use the option completer
                final String expressionToComplete = buffer.substring(lastSpaceIndex + 1, cursor);
                final int completionIndex = completer.complete(expressionToComplete, cursor, candidates);
                removeUselessSpace(buffer, cursor, candidates);
                return cursor - expressionToComplete.length() + completionIndex;
            } else {
                return -1;
            }
        } else {
            return -1;
        }
    }

    private static final int completeOptionPossibilityOrAgument(final String buffer, final int cursor,
            final List candidates, final Command command, final String lastWordToComplete) {
        if (lastWordToComplete.startsWith("-")) {
            // the last word is an option => use a string completer with all the possible options
            final Options options = command.getOptions();
            if (options != null) {
                final List optionStrings = new ArrayList<>();
                for (Object optionObj : options.getOptions()) {
                    final Option option = (Option) optionObj;
                    final String shortOption = option.getOpt();
                    if (shortOption != null) {
                        final String opt = "-" + shortOption;
                        optionStrings.add(opt);
                    }
                    final String longOpt = option.getLongOpt();
                    if (longOpt != null) {
                        final String opt = "--" + longOpt;
                        optionStrings.add(opt);
                    }
                }
                final Completer optionCompleter = new StringsCompleter(optionStrings);
                final int completionIndex = optionCompleter.complete(lastWordToComplete, cursor, candidates);
                removeUselessSpace(buffer, cursor, candidates);
                return cursor - lastWordToComplete.length() + completionIndex;
            }
        } else {
            // the last word is not an option => use the default completer
            final Completer completer = command.getDefaultCompleter();

            if (completer != null) {
                final int completionIndex = completer.complete(lastWordToComplete, cursor, candidates);
                removeUselessSpace(buffer, cursor, candidates);
                return cursor - lastWordToComplete.length() + completionIndex;
            }
        }

        return -1;
    }

    private static final void removeUselessSpace(final String buffer, final int cursor,
            final List candidates) {
        if (cursor < buffer.length() && candidates.size() == 1 && buffer.charAt(cursor) == ' ') {
            CharSequence candidate = candidates.get(0);
            candidate = candidate.subSequence(0, candidate.length() - 1);
            candidates.set(0, candidate);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy