alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (ArgumentCompleter.java)

This example Scala source code file (ArgumentCompleter.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

abstractargumentdelimiter, argumentcompleter, argumentdelimiter, argumentdelimiter, argumentlist, charsequence, charsequence, completer, linkedlist, list, list, string, string, util, whitespaceargumentdelimiter

The Scala ArgumentCompleter.java source code

/*
 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
 *
 * This software is distributable under the BSD license. See the terms of the
 * BSD license in the documentation provided with this software.
 */

package scala.tools.jline.console.completer;

import scala.tools.jline.internal.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
 * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator argument.
 * This can be used instead of the individual completers having to know about argument parsing semantics.
 *
 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux
 * @author <a href="mailto:jason@planet57.com">Jason Dillon
 * @since 2.3
 */
public class ArgumentCompleter
    implements Completer
{
    private final ArgumentDelimiter delimiter;

    private final List<Completer> completers = new ArrayList();

    private boolean strict = true;

    /**
     * Create a new completer with the specified argument delimiter.
     *
     * @param delimiter     The delimiter for parsing arguments
     * @param completers    The embedded completers
     */
    public ArgumentCompleter(final ArgumentDelimiter delimiter, final Collection<Completer> completers) {
        assert delimiter != null;
        this.delimiter = delimiter;
        assert completers != null;
        this.completers.addAll(completers);
    }

    /**
     * Create a new completer with the specified argument delimiter.
     *
     * @param delimiter     The delimiter for parsing arguments
     * @param completers    The embedded completers
     */
    public ArgumentCompleter(final ArgumentDelimiter delimiter, final Completer... completers) {
        this(delimiter, Arrays.asList(completers));
    }

    /**
     * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
     *
     * @param completers    The embedded completers
     */
    public ArgumentCompleter(final Completer... completers) {
        this(new WhitespaceArgumentDelimiter(), completers);
    }

    /**
     * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
     *
     * @param completers    The embedded completers
     */
    public ArgumentCompleter(final List<Completer> completers) {
        this(new WhitespaceArgumentDelimiter(), completers);
    }

    /**
     * If true, a completion at argument index N will only succeed
     * if all the completions from 0-(N-1) also succeed.
     */
    public void setStrict(final boolean strict) {
        this.strict = strict;
    }

    /**
     * Returns whether a completion at argument index N will success
     * if all the completions from arguments 0-(N-1) also succeed.
     *
     * @return  True if strict.
     * @since 2.3
     */
    public boolean isStrict() {
        return this.strict;
    }

    /**
     * @since 2.3
     */
    public ArgumentDelimiter getDelimiter() {
        return delimiter;
    }

    /**
     * @since 2.3
     */
    public List<Completer> getCompleters() {
        return completers;
    }

    public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
        // buffer can be null
        assert candidates != null;

        ArgumentDelimiter delim = getDelimiter();
        ArgumentList list = delim.delimit(buffer, cursor);
        int argpos = list.getArgumentPosition();
        int argIndex = list.getCursorArgumentIndex();

        if (argIndex < 0) {
            return -1;
        }

        List<Completer> completers = getCompleters();
        Completer completer;

        // if we are beyond the end of the completers, just use the last one
        if (argIndex >= completers.size()) {
            completer = completers.get(completers.size() - 1);
        }
        else {
            completer = completers.get(argIndex);
        }

        // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
        for (int i = 0; isStrict() && (i < argIndex); i++) {
            Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
            String[] args = list.getArguments();
            String arg = (args == null || i >= args.length) ? "" : args[i];

            List<CharSequence> subCandidates = new LinkedList();

            if (sub.complete(arg, arg.length(), subCandidates) == -1) {
                return -1;
            }

            if (subCandidates.size() == 0) {
                return -1;
            }
        }

        int ret = completer.complete(list.getCursorArgument(), argpos, candidates);

        if (ret == -1) {
            return -1;
        }

        int pos = ret + list.getBufferPosition() - argpos;

        // Special case: when completing in the middle of a line, and the area under the cursor is a delimiter,
        // then trim any delimiters from the candidates, since we do not need to have an extra delimiter.
        //
        // E.g., if we have a completion for "foo", and we enter "f bar" into the buffer, and move to after the "f"
        // and hit TAB, we want "foo bar" instead of "foo  bar".

        if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
            for (int i = 0; i < candidates.size(); i++) {
                CharSequence val = candidates.get(i);

                while (val.length() > 0 && delim.isDelimiter(val, val.length() - 1)) {
                    val = val.subSequence(0, val.length() - 1);
                }

                candidates.set(i, val);
            }
        }

        Log.trace("Completing ", buffer, " (pos=", cursor, ") with: ", candidates, ": offset=", pos);

        return pos;
    }

    /**
     * The {@link ArgumentCompleter.ArgumentDelimiter} allows custom breaking up of a {@link String} into individual
     * arguments in order to dispatch the arguments to the nested {@link Completer}.
     *
     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux
     */
    public static interface ArgumentDelimiter
    {
        /**
         * Break the specified buffer into individual tokens that can be completed on their own.
         *
         * @param buffer    The buffer to split
         * @param pos       The current position of the cursor in the buffer
         * @return          The tokens
         */
        ArgumentList delimit(CharSequence buffer, int pos);

        /**
         * Returns true if the specified character is a whitespace parameter.
         *
         * @param buffer    The complete command buffer
         * @param pos       The index of the character in the buffer
         * @return          True if the character should be a delimiter
         */
        boolean isDelimiter(CharSequence buffer, int pos);
    }

    /**
     * Abstract implementation of a delimiter that uses the {@link #isDelimiter} method to determine if a particular
     * character should be used as a delimiter.
     *
     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux
     */
    public abstract static class AbstractArgumentDelimiter
        implements ArgumentDelimiter
    {
        // TODO: handle argument quoting and escape characters
        
        private char[] quoteChars = {'\'', '"'};

        private char[] escapeChars = {'\\'};

        public void setQuoteChars(final char[] chars) {
            this.quoteChars = chars;
        }

        public char[] getQuoteChars() {
            return this.quoteChars;
        }

        public void setEscapeChars(final char[] chars) {
            this.escapeChars = chars;
        }

        public char[] getEscapeChars() {
            return this.escapeChars;
        }

        public ArgumentList delimit(final CharSequence buffer, final int cursor) {
            List<String> args = new LinkedList();
            StringBuilder arg = new StringBuilder();
            int argpos = -1;
            int bindex = -1;

            for (int i = 0; (buffer != null) && (i <= buffer.length()); i++) {
                // once we reach the cursor, set the
                // position of the selected index
                if (i == cursor) {
                    bindex = args.size();
                    // the position in the current argument is just the
                    // length of the current argument
                    argpos = arg.length();
                }

                if ((i == buffer.length()) || isDelimiter(buffer, i)) {
                    if (arg.length() > 0) {
                        args.add(arg.toString());
                        arg.setLength(0); // reset the arg
                    }
                }
                else {
                    arg.append(buffer.charAt(i));
                }
            }

            return new ArgumentList(args.toArray(new String[args.size()]), bindex, argpos, cursor);
        }

        /**
         * Returns true if the specified character is a whitespace parameter. Check to ensure that the character is not
         * escaped by any of {@link #getQuoteChars}, and is not escaped by ant of the {@link #getEscapeChars}, and
         * returns true from {@link #isDelimiterChar}.
         *
         * @param buffer    The complete command buffer
         * @param pos       The index of the character in the buffer
         * @return          True if the character should be a delimiter
         */
        public boolean isDelimiter(final CharSequence buffer, final int pos) {
            return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
        }

        public boolean isQuoted(final CharSequence buffer, final int pos) {
            return false;
        }

        public boolean isEscaped(final CharSequence buffer, final int pos) {
            if (pos <= 0) {
                return false;
            }

            for (int i = 0; (escapeChars != null) && (i < escapeChars.length);
                 i++) {
                if (buffer.charAt(pos) == escapeChars[i]) {
                    return !isEscaped(buffer, pos - 1); // escape escape
                }
            }

            return false;
        }

        /**
         * Returns true if the character at the specified position if a delimiter. This method will only be called if
         * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by ant of the
         * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
         */
        public abstract boolean isDelimiterChar(CharSequence buffer, int pos);
    }

    /**
     * {@link ArgumentCompleter.ArgumentDelimiter} implementation that counts all whitespace (as reported by
     * {@link Character#isWhitespace}) as being a delimiter.
     *
     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux
     */
    public static class WhitespaceArgumentDelimiter
        extends AbstractArgumentDelimiter
    {
        /**
         * The character is a delimiter if it is whitespace, and the
         * preceding character is not an escape character.
         */
        @Override
        public boolean isDelimiterChar(final CharSequence buffer, final int pos) {
            return Character.isWhitespace(buffer.charAt(pos));
        }
    }

    /**
     * The result of a delimited buffer.
     *
     * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux
     */
    public static class ArgumentList
    {
        private String[] arguments;

        private int cursorArgumentIndex;

        private int argumentPosition;

        private int bufferPosition;

        /**
         * @param arguments             The array of tokens
         * @param cursorArgumentIndex   The token index of the cursor
         * @param argumentPosition      The position of the cursor in the current token
         * @param bufferPosition        The position of the cursor in the whole buffer
         */
        public ArgumentList(final String[] arguments, final int cursorArgumentIndex, final int argumentPosition, final int bufferPosition) {
            assert arguments != null;

            this.arguments = arguments;
            this.cursorArgumentIndex = cursorArgumentIndex;
            this.argumentPosition = argumentPosition;
            this.bufferPosition = bufferPosition;
        }

        public void setCursorArgumentIndex(final int i) {
            this.cursorArgumentIndex = i;
        }

        public int getCursorArgumentIndex() {
            return this.cursorArgumentIndex;
        }

        public String getCursorArgument() {
            if ((cursorArgumentIndex < 0) || (cursorArgumentIndex >= arguments.length)) {
                return null;
            }

            return arguments[cursorArgumentIndex];
        }

        public void setArgumentPosition(final int pos) {
            this.argumentPosition = pos;
        }

        public int getArgumentPosition() {
            return this.argumentPosition;
        }

        public void setArguments(final String[] arguments) {
            this.arguments = arguments;
        }

        public String[] getArguments() {
            return this.arguments;
        }

        public void setBufferPosition(final int pos) {
            this.bufferPosition = pos;
        }

        public int getBufferPosition() {
            return this.bufferPosition;
        }
    }
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala ArgumentCompleter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.