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

Using TreeMap instead of LinkedHashMap, to sort subcommands alphabeti… #805

Closed

Conversation

frontfact
Copy link
Contributor

Using TreeMap instead of LinkedHashMap, to sort subcommands alphabetically in usage message.

Tell me if that breaks something.

Below is a snippet to toy with the expected behaviour (with/without ordering).

`
public class TestApplication {

@Command(name = "alpha")
public static class Alpha implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		return 0;
	}
}

@Command(name = "bravo")
public static class Bravo implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		return 0;
	}
}

@Command(name = "charlie")
public static class Charlie implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		return 0;
	}
}

@Command(name = "$",
		subcommands = {
			Charlie.class,
			Bravo.class,
			Alpha.class,
			HelpCommand.class
		})
public static class RootCommand implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		throw new UnsupportedOperationException();
	}
}

public static void main(String[] args) {
	CommandLine rootCommand = new CommandLine(new RootCommand());
	rootCommand.usage(System.out);
}

}
`

@remkop
Copy link
Owner

remkop commented Sep 6, 2019

Hi @frontfact, thank you for the PR!

To be honest, I’m not sure that this is a good change:
With the current implementation (using LinkedHashMap), applications have control over the order in which subcommands are listed. Applications that want to list subcommands alphabetically can simply list them in that order. They also have the option to list subcommands in a different order.

Your proposal would limit applications to only alphabetical order, which doesn’t seem to be a good thing. Or am I missing something?

@frontfact
Copy link
Contributor Author

Hi

Applications that want to list subcommands alphabetically can simply list them in that order

Unfortunately, this is not possible in my case: I have 2 different applications that share common commands. I cannot list commands in the alphabetical order.

They also have the option to list subcommands in a different order

I did not see that, can you tell me how to do that ? Or point me to the documentation section explaining how to achieve alphabetical ordering of subcommands.

Thank you very much

@remkop
Copy link
Owner

remkop commented Sep 6, 2019

I thought subcommands are listed in the order that they are declared. So you can control the ordering, no?

@frontfact
Copy link
Contributor Author

Yes, I see.
To be clear, my project has a shared library that initializes common commands first, then each tool initializes additionnal commands or sub-commands. This is why I can't order commands alphabetically in source code, and wanted them to be sorted at runtime.

Thank you for your time, have a nice day!

@remkop
Copy link
Owner

remkop commented Sep 6, 2019

Ok, I see now.
We can find a solution for your use case. Give me a few minutes.

@remkop
Copy link
Owner

remkop commented Sep 6, 2019

I believe that we can meet your requirements with a custom IHelpSectionRenderer.

This ticket has an (fairly complex) example.

A custom IHelpSectionRenderer that simply sorts the commands by name should be easier than that example. I’ll take a closer look when I get back behind my computer.

@remkop
Copy link
Owner

remkop commented Sep 6, 2019

@frontfact, I found an easier solution: you can subclass Help and override the Help.subcommands() method to return a sorted map.

Here is a full example:

import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Help;
import picocli.CommandLine.HelpCommand;
import picocli.CommandLine.IHelpFactory;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Spec;

import java.util.Map;
import java.util.TreeMap;

/**
 * This class has subcommands that are not declared alphabetically.
 * We want the help for this class to show the subcommands alphabetically.
 */
@Command(name = "alphabetic",
        description = "a command that shows subcommands sorted alphabetically",
        subcommands = {Charlie.class, Bravo.class, Alpha.class, HelpCommand.class})
public class AlphabeticSubcommands implements Runnable {

    @Spec CommandSpec spec;

    @Override
    public void run() {
        spec.commandLine().usage(System.out);
    }

    public static void main(String[] args) {
        CommandLine commandLine = new CommandLine(new AlphabeticSubcommands());
        commandLine.setHelpFactory(new IHelpFactory() {
            @Override
            public Help create(CommandSpec commandSpec, Help.ColorScheme colorScheme) {
                return new Help(commandSpec, colorScheme) {
                    /**
                     * Returns a sorted map of the subcommands.
                     */
                    @Override
                    protected Map<String, Help> subcommands() {
                        return new TreeMap<>(super.subcommands());
                    }
                };
            }
        });
        commandLine.execute(args);
    }
}

@Command(name = "charlie", description = "my name starts with C")
class Charlie implements Runnable {
    public void run() {}
}

@Command(name = "bravo", description = "my name starts with B")
class Bravo implements Runnable {
    public void run() {}
}

@Command(name = "alpha", description = "my name starts with A")
class Alpha implements Runnable {
    public void run() {}
}

Output:

 Usage: alphabetic [COMMAND]
a command that shows subcommands sorted alphabetically
Commands:
  alpha    my name starts with A
  bravo    my name starts with B
  charlie  my name starts with C
  help     Displays help information about the specified command

Does this meet your requirements?

remkop added a commit that referenced this pull request Sep 6, 2019
@frontfact
Copy link
Contributor Author

That works perfectly, thank you very much !

@remkop
Copy link
Owner

remkop commented Sep 6, 2019

Great, glad to hear that!
Please star the project on GitHub if you like it! 😉

@remkop remkop closed this Sep 6, 2019
@frontfact frontfact deleted the subcommands-alphabetical-order branch September 6, 2019 16:32
@remkop remkop added this to the 4.0.4 milestone Sep 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants