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

org.jboss.aesh.cl.parser.AeshCommandLineCompletionParser Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed 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.jboss.aesh.cl.parser;

import org.jboss.aesh.cl.CommandLine;
import org.jboss.aesh.cl.completer.CompleterData;
import org.jboss.aesh.cl.completer.DefaultValueOptionCompleter;
import org.jboss.aesh.cl.internal.OptionType;
import org.jboss.aesh.cl.internal.ProcessedOption;
import org.jboss.aesh.cl.validator.OptionValidatorException;
import org.jboss.aesh.complete.CompleteOperation;
import org.jboss.aesh.console.InvocationProviders;
import org.jboss.aesh.console.command.Command;
import org.jboss.aesh.console.command.completer.CompleterInvocation;
import org.jboss.aesh.parser.Parser;
import org.jboss.aesh.terminal.TerminalString;

import java.util.List;

/**
 * @author Ståle W. Pedersen
 */
public class AeshCommandLineCompletionParser implements CommandLineCompletionParser {

    private final AeshCommandLineParser parser;

    public AeshCommandLineCompletionParser(AeshCommandLineParser parser) {
        this.parser = parser;
    }


    /**
     * 1. find the last "word"
     *   if it starts with '-', we need to check if its a value or name
     * @param line buffer
     * @return ParsedCompleteObject
     */
    @Override
    public ParsedCompleteObject findCompleteObject(String line, int cursor) throws CommandLineParserException {
        if(cursor < line.length()) {
            line = line.substring(0, cursor);
        }

        parser.clear();
        //first we check if it could be a param
        if(Parser.findIfWordEndWithSpace(line)) {
            return endsWithSpace(line);
        }
        //lastly we'll check if we can find an option
        else
            return optionFinder(line);
    }

    private ParsedCompleteObject endsWithSpace(String line) throws CommandLineParserException {
        CommandLine cl = parser.parse(line, true);
        //check if we try to complete just after the command name
        if(parser.isGroupCommand()) {
            if (line.trim().equals(parser.getProcessedCommand().getName() + " " +
                    cl.getParser().getProcessedCommand().getName())) {
                if (cl.getParser().getProcessedCommand().getArgument() == null) {
                    //basically an empty string except command name
                    return new ParsedCompleteObject(true, "", 0, cl.getParser().getCompletionParser());
                }
                return new ParsedCompleteObject(null, "", cl.getParser().getProcessedCommand().getArgument().getType(),
                        false, getCorrectCompletionParser(line));
            }
        }
        else if(line.trim().equals(cl.getParser().getProcessedCommand().getName())) {
            if(cl.getParser().getProcessedCommand().getArgument() == null) {
                //basically an empty string except command name
                return new ParsedCompleteObject(true, "", 0, cl.getParser().getCompletionParser());
            }
            return new ParsedCompleteObject(null, "", cl.getParser().getProcessedCommand().getArgument().getType(),
                    false, getCorrectCompletionParser(line));
        }
        //else we try to complete an option,an option value or arguments
        String lastWord = Parser.findEscapedSpaceWordCloseToEnd(line.trim());
        if(lastWord.startsWith("-")) {
            int offset = lastWord.length();
            while(lastWord.startsWith("-"))
                lastWord = lastWord.substring(1);
            if(lastWord.length() == 0)
                return new ParsedCompleteObject(false, null, offset, getCorrectCompletionParser(line));
            else if(cl.getParser().getProcessedCommand().findOptionNoActivatorCheck(lastWord) != null ||
                    cl.getParser().getProcessedCommand().findLongOptionNoActivatorCheck(lastWord) != null)
                return findCompleteObjectValue(line, true);
            else
                return new ParsedCompleteObject(false, null, offset, getCorrectCompletionParser(line));
        }
        //last word is a value, need to find out what option its a value for
        else {
            return findCompleteObjectValue(line, true);
        }
    }

    private ParsedCompleteObject optionFinder(String line) throws CommandLineParserException {
        String lastWord = Parser.findEscapedSpaceWordCloseToEnd(line);
        //last word might be an option
        if(lastWord.startsWith("-") ) {
            String secLastWord =
                    Parser.findEscapedSpaceWordCloseToEnd(
                            line.substring(0,line.length()-lastWord.length()));
            //second to last word also start with -
            if(secLastWord.startsWith("-")) {
                //do this for now
                return findCompleteObjectValue(line, false);
            }
            //the last word is an option (most likely)
            else {
                switch (lastWord) {
                    case "-":
                        return new ParsedCompleteObject(true, "", 1, getCorrectCompletionParser(line));
                    case "--":
                        return new ParsedCompleteObject(true, "", 2, getCorrectCompletionParser(line));
                    default:
                        //we have a complete shortName
                        if (!lastWord.startsWith("--") && lastWord.length() == 2)
                            return new ParsedCompleteObject(true,
                                    Parser.trimOptionName(lastWord), lastWord.length(), true, getCorrectCompletionParser(line));
                        else {
                            String optionName = Parser.trimOptionName(lastWord);
                            CommandLine cl = parser.parse(line, true);
                            if (cl.getParser().getProcessedCommand().hasUniqueLongOption(optionName))
                                return new ParsedCompleteObject(true, optionName, lastWord.length(), true, cl.getParser().getCompletionParser());
                            else
                                return new ParsedCompleteObject(true, optionName, lastWord.length(), false, cl.getParser().getCompletionParser());
                        }
                }
            }
        }
        else
            return findCompleteObjectValue(line, false);
    }

    /**
     * Only called when we know that the last word is an option value
     * If endsWithSpace is true we set the value to an empty string to indicate a value
     */
    private ParsedCompleteObject findCompleteObjectValue(String line, boolean endsWithSpace) throws CommandLineParserException {
        CommandLine cl = parser.parse(line, true);

        //the last word is an argument
        if(cl.getArgument() != null && !cl.getArgument().getValues().isEmpty()) {
            return new ParsedCompleteObject("", endsWithSpace ? "" :
                    cl.getArgument().getValues().get(cl.getArgument().getValues().size() - 1),
                    cl.getArgument().getType(), false, cl.getParser().getCompletionParser());
        }
        //get the last option
        else if (cl.getOptions() != null && cl.getOptions().size() > 0) {
            ProcessedOption po = cl.getOptions().get(cl.getOptions().size()-1);
            //options ends with a separator and thus status should be set accordingly
            if(po.getEndsWithSeparator())
                endsWithSpace = true;

            if(endsWithSpace && po.getValue() != null &&  po.getValue().length() > 0 &&
                    (po.getOptionType() == OptionType.NORMAL || po.getOptionType() == OptionType.BOOLEAN)) {
                if(cl.getArgument() == null)
                    return new ParsedCompleteObject(true, "", 0, cl.getParser().getCompletionParser());
                else
                    return new ParsedCompleteObject(true, cl.getParser().getCompletionParser());
            }
            else if(po.isLongNameUsed() || (po.getShortName() == null || po.getShortName().length() < 1))
                return new ParsedCompleteObject(po.getName(),
                        endsWithSpace ? "" : po.getValues().get(po.getValues().size()-1),
                        po.getType(), true, cl.getParser().getCompletionParser());
            else
                return new ParsedCompleteObject( po.getShortName(),
                        endsWithSpace ? "" : po.getValues().get(po.getValues().size()-1),
                        po.getType(), true, cl.getParser().getCompletionParser());
        }
        //probably something wrong with the parser
        else
            return new ParsedCompleteObject(true, "", 0, getCorrectCompletionParser(line));
    }

    @Override
    @SuppressWarnings("unchecked")
    public void injectValuesAndComplete(ParsedCompleteObject completeObject,
                                        CompleteOperation completeOperation,
                                        InvocationProviders invocationProviders) {

        if(completeObject.doDisplayOptions()) {
            //got the whole name, just add a space
            if(completeObject.isCompleteOptionName()) {
                completeOperation.addCompletionCandidate("");
            }
            else {
                //we have partial/full name
                if(completeObject.getName() != null && completeObject.getName().length() > 0) {
                    String rest = completeOperation.getBuffer().substring(0, completeOperation.getBuffer().lastIndexOf( completeObject.getName()));
                    List words = Parser.findAllWords(rest).getWords();
                    try {
                        parser.getCommandPopulator().populateObject(parser.parse(words, true), invocationProviders,
                                completeOperation.getAeshContext(), false);
                    }
                    //this should be ignored at some point
                    catch (CommandLineParserException | OptionValidatorException ignored) { }
                    List optionNamesWithDash = parser.getProcessedCommand().findPossibleLongNamesWitdDash(completeObject.getName());
                    if(optionNamesWithDash.size() > 0) {
                        //only one param
                        if(optionNamesWithDash.size() == 1) {
                            completeOperation.addCompletionCandidate( optionNamesWithDash.get(0));
                            completeOperation.setOffset( completeOperation.getCursor() - 2 - completeObject.getName().length());
                        }
                        //multiple params
                        else {
                            completeOperation.addCompletionCandidatesTerminalString(optionNamesWithDash);
                            completeOperation.setOffset( completeOperation.getCursor() - 2 - completeObject.getName().length());
                        }

                    }
                }
                else {
                    try {
                        List words = Parser.findAllWords(completeOperation.getBuffer()).getWords();
                        if(words.get(words.size()-1).equals("--") || words.get(words.size()-1).equals("-"))
                            words.remove(words.size()-1);
                        parser.getCommandPopulator().populateObject(parser.parse(words, true),
                                invocationProviders, completeOperation.getAeshContext(), false);
                    }
                    //this should be ignored at some point
                    catch (CommandLineParserException | OptionValidatorException ignored) { }
                    List optionNamesWithDash = parser.getProcessedCommand().getOptionLongNamesWithDash();

                    if(optionNamesWithDash.size() > 1)
                        completeOperation.addCompletionCandidatesTerminalString(optionNamesWithDash);
                    else if(optionNamesWithDash.size() == 1) {
                        int count = 0;
                        if(completeOperation.getCursor() < completeOperation.getBuffer().length()) {
                            String line = completeOperation.getBuffer().substring(0, completeOperation.getCursor());
                            while(line.substring(0, line.length()-count).endsWith("-"))
                                count++;
                        }
                        else {
                            while(completeOperation.getBuffer().substring(0, completeOperation.getBuffer().length()-count).endsWith("-"))
                                count++;
                        }
                        completeOperation.addCompletionCandidate(optionNamesWithDash.get(0));
                        completeOperation.setOffset( completeOperation.getCursor() - count);
                    }

                }
            }
        }
        //complete option value
        else if(completeObject.isOption()) {
            ProcessedOption currentOption = parser.getProcessedCommand().findOption(completeObject.getName());
            if(currentOption == null)
                currentOption = parser.getProcessedCommand().findLongOptionNoActivatorCheck(completeObject.getName());

            //split the line on the option name. populate the object, then call the options completer
            String displayName = currentOption.getDisplayName();
            //this shouldnt happen
            if(displayName == null) {
                return;
            }
            String rest = completeOperation.getBuffer().substring(0, completeOperation.getBuffer().lastIndexOf( displayName));

            try {
                List words = Parser.findAllWords(rest).getWords();
                parser.getCommandPopulator().populateObject(parser.parse(words, true),
                        invocationProviders, completeOperation.getAeshContext(), false);
            }
            //this should be ignored at some point
            catch (CommandLineParserException | OptionValidatorException ignored) { }

            if(currentOption.getCompleter() != null &&
                    currentOption.getActivator().isActivated(parser.getProcessedCommand())) {
                CompleterInvocation completions =
                        invocationProviders.getCompleterProvider().enhanceCompleterInvocation(
                                new CompleterData(completeOperation.getAeshContext(), completeObject.getValue(), parser.getCommand()));

                currentOption.getCompleter().complete(completions);
                completeOperation.addCompletionCandidatesTerminalString(completions.getCompleterValues());
                completionSetOffSet(completeObject, completeOperation, completions);
                completeOperation.setIgnoreOffset(completions.doIgnoreOffset());
                completeOperation.setIgnoreStartsWith(completions.isIgnoreStartsWith());

                if(completions.getCompleterValues().size() == 1) {
                    //if the contain spaces we need to add the number of spaces to the size
                    // of the value.length since they are chopped off during parsing
                    if(completeObject.getValue().indexOf(Parser.SPACE_CHAR) > 0) {
                        completeOperation.setOffset( completeOperation.getCursor() -
                                (completeObject.getOffset() + Parser.findNumberOfSpacesInWord(completeObject.getValue())));
                    }
                    if(completeOperation.getCompletionCandidates().get(0).containSpaces())
                        completeOperation.getCompletionCandidates().get(0).switchSpacesToEscapedSpaces();

                    completeOperation.doAppendSeparator( completions.isAppendSpace());
                }
            }
            //only try to complete default values if completer is null
            else if(currentOption.getDefaultValues().size() > 0) {
                CompleterInvocation completions =
                        invocationProviders.getCompleterProvider().enhanceCompleterInvocation(
                                new CompleterData(completeOperation.getAeshContext(), completeObject.getValue(), parser.getCommand()));
                new DefaultValueOptionCompleter(currentOption.getDefaultValues()).complete(completions);
                completeOperation.addCompletionCandidatesTerminalString(completions.getCompleterValues());
                completionSetOffSet(completeObject, completeOperation, completions);
                completeOperation.setIgnoreOffset(completions.doIgnoreOffset());
                completeOperation.setIgnoreStartsWith(completions.isIgnoreStartsWith());

                if(completions.getCompleterValues().size() == 1) {
                    //if the contain spaces we need to add the number of spaces to the size
                    // of the value.length since they are chopped off during parsing
                    if(completeObject.getValue().indexOf(Parser.SPACE_CHAR) > 0) {
                        completeOperation.setOffset( completeOperation.getCursor() -
                                (completeObject.getOffset() + Parser.findNumberOfSpacesInWord(completeObject.getValue())));
                    }
                    if(completeOperation.getCompletionCandidates().get(0).containSpaces())
                        completeOperation.getCompletionCandidates().get(0).switchSpacesToEscapedSpaces();

                    completeOperation.doAppendSeparator( completions.isAppendSpace());
                }
            }
        }
        else if(completeObject.isArgument()) {
            String lastWord = Parser.findEscapedSpaceWordCloseToEnd(completeOperation.getBuffer());
            String rest = completeOperation.getBuffer().substring(0, completeOperation.getBuffer().length() - lastWord.length());
            try {
                List words = Parser.findAllWords(rest).getWords();
                parser.getCommandPopulator().populateObject(parser.parse(words, true),
                        invocationProviders, completeOperation.getAeshContext(), false);
            }
            catch (CommandLineParserException | OptionValidatorException ignored) { }

            if(parser.getProcessedCommand().getArgument() != null &&
                    parser.getProcessedCommand().getArgument().getCompleter() != null) {
                CompleterInvocation completions =
                        invocationProviders.getCompleterProvider().enhanceCompleterInvocation(
                                new CompleterData(completeOperation.getAeshContext(), completeObject.getValue(), parser.getCommand()));
                parser.getProcessedCommand().getArgument().getCompleter().complete(completions);
                completeOperation.addCompletionCandidatesTerminalString(completions.getCompleterValues());
                completionSetOffSet(completeObject, completeOperation, completions);
                completeOperation.setIgnoreOffset(completions.doIgnoreOffset());
                completeOperation.setIgnoreStartsWith(completions.isIgnoreStartsWith());

                if(completions.getCompleterValues().size() == 1) {
                    if(completeObject.getValue().indexOf(Parser.SPACE_CHAR) > 0) {
                        completeOperation.setOffset( completeOperation.getCursor() -
                                (completeObject.getOffset() + Parser.findNumberOfSpacesInWord(completeObject.getValue())));
                    }
                    if(completeOperation.getCompletionCandidates().get(0).containSpaces())
                        completeOperation.getCompletionCandidates().get(0).switchSpacesToEscapedSpaces();

                    completeOperation.doAppendSeparator( completions.isAppendSpace());
                }

            }
            else if(parser.getProcessedCommand().containsArgumentWithDefaultValues()) {
                CompleterInvocation completions =
                        invocationProviders.getCompleterProvider().enhanceCompleterInvocation(
                                new CompleterData(completeOperation.getAeshContext(), completeObject.getValue(), parser.getCommand()));
                new DefaultValueOptionCompleter( parser.getProcessedCommand().getArgument().getDefaultValues()).complete(completions);
                completeOperation.addCompletionCandidatesTerminalString(completions.getCompleterValues());
                completionSetOffSet(completeObject, completeOperation, completions);
                completeOperation.setIgnoreOffset(completions.doIgnoreOffset());
                completeOperation.setIgnoreStartsWith(completions.isIgnoreStartsWith());

                if(completions.getCompleterValues().size() == 1) {
                    if(completeObject.getValue().indexOf(Parser.SPACE_CHAR) > 0) {
                        completeOperation.setOffset( completeOperation.getCursor() -
                                (completeObject.getOffset() + Parser.findNumberOfSpacesInWord(completeObject.getValue())));
                    }
                    if(completeOperation.getCompletionCandidates().get(0).containSpaces())
                        completeOperation.getCompletionCandidates().get(0).switchSpacesToEscapedSpaces();

                }
                completeOperation.doAppendSeparator( completions.isAppendSpace());
            }
        }
    }

    private void completionSetOffSet(ParsedCompleteObject completeObject, CompleteOperation completeOperation, CompleterInvocation completions) {
        if(completions.getOffset() > 0)
            completeOperation.setOffset( completeOperation.getCursor() - completions.getOffset());
        else if(completeObject.getValue() != null)
            completeOperation.setOffset( completeOperation.getCursor() - completeObject.getValue().length());
    }

    private CommandLineCompletionParser getCorrectCompletionParser(String line) {
        if(!parser.isGroupCommand())
            return this;
        else {
            String childLine = line.trim().substring(parser.getProcessedCommand().getName().length());
            String child = Parser.findFirstWord(childLine);
            CommandLineParser childParser = parser.getChildParser(child);
            if(childParser != null)
                return childParser.getCompletionParser();
            else
                return this;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy