Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support recognizing abbreviated options and commands #10

Closed
remkop opened this issue Feb 4, 2017 · 4 comments · Fixed by #1047
Closed

Support recognizing abbreviated options and commands #10

remkop opened this issue Feb 4, 2017 · 4 comments · Fixed by #1047
Labels
theme: parser An issue or change related to the parser type: enhancement ✨
Milestone

Comments

@remkop
Copy link
Owner

remkop commented Feb 4, 2017

http://bailando.berkeley.edu/papers/psb03.pdf

@remkop remkop modified the milestone: 0.4.0 advanced option parsing Feb 5, 2017
@remkop remkop changed the title Support recognizing abbreviated options Support recognizing abbreviated options and commands Jul 11, 2018
@remkop remkop modified the milestones: backlog, 3.3 Jul 11, 2018
@remkop
Copy link
Owner Author

remkop commented Jul 11, 2018

Micronaut does this:

// Apply command name expansion (rA for run-app, tA for test-app etc.)
cmd = commandsByName.values().find() { Command c ->
    ScriptNameResolver.resolvesTo(commandName, c.name)
}

where

class ScriptNameResolver {
    /**
     * Matches a camelCase scriptName to a potential scriptFileName in canonical form.<p>
     * The following scriptNames match FooBar: FB, FoB, FBa
     */
    static boolean resolvesTo(String scriptName, String scriptFileName) {
        def scriptFileNameTokens = NameUtils.getNameFromScript(scriptFileName).findAll(/[A-Z][a-z]+/)
        def scriptNameTokens = NameUtils.getNameFromScript(scriptName).findAll(/[A-Z][a-z]*/)

        if (scriptFileNameTokens.size() != scriptNameTokens.size()) return false
        for (int i = 0; i < scriptNameTokens.size(); i++) {
            String str = scriptNameTokens[i]
            if (!scriptFileNameTokens[i].startsWith(str)) return false
        }
        true
    }
}

and

//NameUtils
public static String getNameFromScript(String scriptName) {
    return getClassNameForLowerCaseHyphenSeparatedName(scriptName);
}
/**
 * Converts foo-bar into FooBar. Empty and null strings are returned as-is.
 *
 * @param name The lower case hyphen separated name
 * @return The class name equivalent.
 */
private static String getClassNameForLowerCaseHyphenSeparatedName(String name) {
    // Handle null and empty strings.
    if (isBlank(name)) {
        return name;
    }

    if (name.indexOf('-') == -1) {
        return name.substring(0, 1).toUpperCase() + name.substring(1);
    }

    StringBuilder buf = new StringBuilder();
    String[] tokens = name.split("-");
    for (String token : tokens) {
        if (token == null || token.length() == 0) {
            continue;
        }
        buf.append(token.substring(0, 1).toUpperCase())
            .append(token.substring(1));
    }
    return buf.toString();
}

@remkop remkop modified the milestones: 3.3, 3.2.1 Jul 13, 2018
@remkop remkop modified the milestones: 3.4, 3.6 Aug 3, 2018
@remkop remkop modified the milestones: 3.6, 3.7 Aug 26, 2018
@remkop remkop modified the milestones: 3.7, 3.8 Oct 19, 2018
@remkop remkop modified the milestones: 4.2, 4.3 Feb 11, 2020
@remkop remkop added the theme: parser An issue or change related to the parser label Apr 2, 2020
@remkop remkop modified the milestones: 4.3, 4.4 Apr 14, 2020
@NewbieOrange
Copy link
Contributor

Hi, any idea or suggestion about how this should be implemented? I saw your code snippet in #732, is that the preferred behaviour of this feature?

@remkop
Copy link
Owner Author

remkop commented May 15, 2020

Yes, the code in #732 is a good start for how I think this should work.

Basically, options and commands can be abbreviated at word boundaries:

  • --this-is-some-option can be abbreviated as --t-i-s-o, or --this-i-s or --t, or (without hyphens) as --tISO or --tIS, etc.
  • --someCamelCaseOption can be appreviated as --sCCO, or --sC, or --s-c-c-o, etc.

Note that the code in #732 is just a proof of concept to explore this problem. If there is a better (shorter, clearer) way to do this that is fine.

The Map passed to the match function could perhaps also be a Set. I think the logic looks mainly at the keys and returns the (full) key that matches the specified abbreviated key. Once we have the full key, we can then get the CommandLine or OptionSpec from the map in CommandSpec.

Note that the code to loop over the characters in the string is incorrect: see https://stackoverflow.com/questions/1527856/how-can-i-iterate-through-the-unicode-codepoints-of-a-java-string (instead of i++ the variable should be incremented by Character.charCount(codepoint)).

@NewbieOrange
Copy link
Contributor

Created a draft PR #1047.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: parser An issue or change related to the parser type: enhancement ✨
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants