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

org.jline.style.InterpolationHelper Maven / Gradle / Ivy

There is a newer version: 3.26.3
Show newest version
/*
 * Copyright (c) 2002-2017, the original author or authors.
 *
 * This software is distributable under the BSD license. See the terms of the
 * BSD license in the documentation provided with this software.
 *
 * http://www.opensource.org/licenses/bsd-license.php
 */
package org.jline.style;

import java.util.function.Function;

/**
 * Interpolation.
 * Borrowed and adapted from Apache Felix Utils module.
 */
public final class InterpolationHelper {

    private InterpolationHelper() {
    }

    private static final char ESCAPE_CHAR = '\\';
    private static final String DELIM_START = "@{";
    private static final String DELIM_STOP = "}";
    private static final String MARKER = "@__";


    public static String substVars(String val,
                                   Function callback,
                                   boolean defaultsToEmptyString)
            throws IllegalArgumentException {
        return unescape(doSubstVars(val, callback, defaultsToEmptyString));
    }

    private static String doSubstVars(String val,
                                      Function callback,
                                      boolean defaultsToEmptyString)
            throws IllegalArgumentException {
        // Assume we have a value that is something like:
        // "leading @{foo.@{bar}} middle @{baz} trailing"

        // Find the first ending '}' variable delimiter, which
        // will correspond to the first deepest nested variable
        // placeholder.
        int startDelim;
        int stopDelim = -1;
        do {
            stopDelim = val.indexOf(DELIM_STOP, stopDelim + 1);
            while (stopDelim > 0 && val.charAt(stopDelim - 1) == ESCAPE_CHAR) {
                stopDelim = val.indexOf(DELIM_STOP, stopDelim + 1);
            }

            // Find the matching starting "@{" variable delimiter
            // by looping until we find a start delimiter that is
            // greater than the stop delimiter we have found.
            startDelim = val.indexOf(DELIM_START);
            while (stopDelim >= 0) {
                int idx = val.indexOf(DELIM_START, startDelim + DELIM_START.length());
                if ((idx < 0) || (idx > stopDelim)) {
                    break;
                } else if (idx < stopDelim) {
                    startDelim = idx;
                }
            }
        }
        while (startDelim >= 0 && stopDelim >= 0 && stopDelim < startDelim + DELIM_START.length());

        // If we do not have a start or stop delimiter, then just
        // return the existing value.
        if ((startDelim < 0) || (stopDelim < 0)) {
            return val;
        }

        // At this point, we have found a variable placeholder so
        // we must perform a variable substitution on it.
        // Using the start and stop delimiter indices, extract
        // the first, deepest nested variable placeholder.
        String variable = val.substring(startDelim + DELIM_START.length(), stopDelim);

        String substValue = null;
        // Get the value of the deepest nested variable placeholder.
        if (variable.length() > 0 && callback != null) {
            substValue = callback.apply(variable);
        }

        if (substValue == null) {
            if (defaultsToEmptyString) {
                substValue = "";
            } else {
                // alters the original token to avoid infinite recursion
                // altered tokens are reverted in unescape()
                substValue = MARKER + "{" + variable + "}";
            }
        }

        // Append the leading characters, the substituted value of
        // the variable, and the trailing characters to get the new
        // value.
        val = val.substring(0, startDelim) + substValue + val.substring(stopDelim + DELIM_STOP.length(), val.length());

        // Now perform substitution again, since there could still
        // be substitutions to make.
        val = doSubstVars(val, callback, defaultsToEmptyString);

        // Return the value.
        return val;
    }

    private static String unescape(String val) {
        val = val.replaceAll(MARKER, "@");
        int escape = val.indexOf(ESCAPE_CHAR);
        while (escape >= 0 && escape < val.length() - 1) {
            char c = val.charAt(escape + 1);
            if (c == '{' || c == '}' || c == ESCAPE_CHAR) {
                val = val.substring(0, escape) + val.substring(escape + 1);
            }
            escape = val.indexOf(ESCAPE_CHAR, escape + 1);
        }
        return val;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy