1 module diggler.defaultcommands;
2 
3 import diggler.attribute;
4 import diggler.bot;
5 import diggler.context;
6 import diggler.command;
7 
8 final class DefaultCommands : ICommandSet
9 {
10 	Bot bot;
11 	Context _context;
12 	alias _context this;
13 	Command helpCommand;
14 	Bot.HelpCommand helpConfig;
15 
16 	this(Bot bot, Bot.HelpCommand helpConfig)
17 	{
18 		this.bot = bot;
19 		this.helpConfig = helpConfig;
20 		this.helpCommand = Command.create!help(&help);
21 	}
22 
23 	@usage("show usage information for commands.")
24 	void help(string commandName = null)
25 	{
26 		import std.array;
27 		import std.algorithm : filter, map, joiner, reduce, sort;
28 		import std.range : chain;
29 		import irc.util : values;
30 		import diggler.util : pluralize;
31 
32 		if(commandName.empty)
33 		{
34 			if(helpConfig == Bot.HelpCommand.simple)
35 			{
36 				import std.experimental.allocator : makeArray;
37 				import std.experimental.allocator.mallocator : Mallocator;
38 				import std.experimental.allocator.showcase : StackFront;
39 				StackFront!(2048, Mallocator) alloc;
40 				reply("Commands: %s", alloc.makeArray!string(bot.commandSets.map!(set => set.commandNames).joiner).sort().joiner(", "));
41 			}
42 			else
43 			{
44 				auto namedSets = bot.commandSets.filter!(set => set.category);
45 
46 				foreach(cmdSet; namedSets)
47 				{
48 					string[] commands = cmdSet.commandNames;
49 					if(!commands.empty)
50 					{
51 						auto commandList = commands.joiner(", ");
52 						reply(`%s %s %s: %s`, commands.length, cmdSet.category, pluralize!"command"(commands.length), commandList);
53 					}
54 				}
55 
56 				auto miscCommands = bot.commandSets
57 					.filter!(set => !set.category)
58 					.map!(set => cast(string[])set.commandNames);
59 
60 				auto numCommands = reduce!((sum, cmds) => sum + cmds.length)(0UL, miscCommands);
61 
62 				if(numCommands != 0)
63 				{
64 					auto disambiguation = namedSets.empty? "" : "miscellaneous ";
65 					reply("%s %s%s: %s", numCommands, disambiguation, pluralize!"command"(numCommands), miscCommands.joiner().joiner(", "));
66 				}
67 			}
68 		}
69 		else
70 		{
71 			foreach(cmdSet; bot.commandSets)
72 			{
73 				if(auto cmd = cmdSet.getCommand(commandName))
74 				{
75 					auto names = values(cmd.name)
76 						.chain(cmd.aliases)
77 						.joiner("|");
78 
79 					auto paramSummary =
80 						cmd.parameterInfo.map!(param => param.displayName)
81 						.joiner(" ");
82 
83 					immutable description = cmd.usage? cmd.usage : "no description available.";
84 
85 					string flags;
86 					if(cmd.channelOnly && cmd.adminOnly)
87 						flags = " [channel, admin]";
88 					else if(cmd.channelOnly)
89 						flags = " [channel]";
90 					else if(cmd.adminOnly)
91 						flags = " [admin]";
92 					else
93 						flags = "";
94 
95 					reply(`%s %s: %s%s`, names, paramSummary, description, flags);
96 
97 					return; // Shouldn't be any duplicates
98 				}
99 			}
100 
101 			reply(`The command "%s" does not appear to exist.`, commandName);
102 		}
103 	}
104 
105 	override string category()
106 	{
107 		return null;
108 	}
109 
110 	override ref Context context()
111 	{
112 		return _context;
113 	}
114 
115 	override void add(ref Command) {}
116 
117 	override Command* getCommand(in char[] name)
118 	{
119 		return name == "help"? &helpCommand : null;
120 	}
121 
122 	override string[] commandNames()
123 	{
124 		return null;
125 	}
126 }