]> git.cworth.org Git - turbot/blob - turbot/help.py
dbecfe36be3a5251c165fa5c9d8b8a7063a8df72
[turbot] / turbot / help.py
1 overview = """
2 *Turbot help*
3 Here is an overview of commands that Turbot makes available. You can
4 actually get at all functionality by just typing `/hunt` and then
5 clicking buttons that are provided in the result. But many operations
6 will be much more efficient by using a special-purpose command, (such
7 as `/solved SOLUTION`).
8
9 Type `/help <command-name>` for more details on any command below.
10
11 *Hunt creation and editing*
12     `/new [hunt]`: Create a new hunt (from any channel)
13     `/edit [hunt]`: Edit the current hunt (in a hunt or puzzle channel)
14
15 *Puzzle creation and editing* (in a puzzle channel unless specified)
16     `/new [puzzle]`: Create a new puzzle (in a hunt or puzzle channel)
17     `/edit [puzzle]`: Edit the current puzzle
18     `/state <update>`: Capture the current state
19     `/solved <solution>`: Mark current puzzle solved
20     `/tag [+ADD_TAG|-REMOVE_TAG]`: Tag/untag current puzzle
21
22 *Hunt overview and searching for puzzles*
23     `/hunt <search_terms>`: Search for puzzles (in a hunt/puzzle channel)
24     `/round <search_terms>`: Show puzzles in current round (puzzle channel)
25     `/puzzle`: Display state of current puzzle (puzzle channel)
26
27 *Solving support* (from any channel)
28     `/rot [*|COUNT] <text_to_rotate>`: Perform a Caesar shift on text
29 """
30
31 commands = {
32     "edit": {
33         "summary": "Edit the puzzle or hunt for the current channel",
34         "usage": "`/edit`, `/edit hunt`, `/edit puzzle`",
35         "details": ("This command will bring up a dialog window where you " +
36                     "can edit the current hunt or puzzle. With `/edit` " +
37                     "alone it will edit whatever is associated with the " +
38                     "current channel (hunt or puzzle). With `/edit hunt` " +
39                     "you can edit the hunt from a puzzle channel.")
40     },
41     "hunt": {
42         "summary": "Search for and display puzzles in the current hunt",
43         "usage": "`/hunt [unsolved|solved|all] [meta|plain] <search_terms>`",
44         "details": ("With `/hunt` alone, this command will display all " +
45                     "unsolved puzzles in the current hunt. All output from " +
46                     "`/hunt` is entirely private to you, so you do not need " +
47                     "to worry about cluttering up the channel's chat " +
48                     "traffic with this command." +
49                     "\n\n" +
50                     "The output for each puzzle will include all of the " +
51                     "information displayed by the `/puzzle` command so see " +
52                     "`/help puzzle` for details." +
53                     "\n\n"
54                     "An initial argument can be used to instead display " +
55                     "only `solved` puzzles or `all` puzzles (both unsolved " +
56                     "and solved). Additional arguments are search terms. " +
57                     "Only puzzles that match all provided terms will be " +
58                     " displayed. The terms can match the puzzle title, " +
59                     " round title, puzzle URL, puzzle type (`meta` or " +
60                     "`plain`), tags, or a puzzle's solution." +
61                     "\n\n" +
62                     "Use quotation marks in search terms to search for a " +
63                     "phrase such as `/hunt \"good times\"`." +
64                     "\n\n" +
65                     "Search terms can include regular expression syntax." +
66                     "\n\n" +
67                     "This command also supports `/hunt new` and " +
68                     "`/hunt edit` which are identical to `/new hunt` " +
69                     "and `/edit hunt` so see `/help new` or `/help edit`" +
70                     "for details.")
71     },
72     "new": {
73         "summary": "Create a new puzzle (or a new hunt)",
74         "usage": "`/new`, `/new puzzle`, `/new hunt`",
75         "details": ("With `/new` alone, this command will bring up a " +
76                     "dialog window where you will be prompted for " +
77                     "information to create a new puzzle. The only field " +
78                     "required for a new puzzle is the puzzle's name " +
79                     "but any additional information you have will be " +
80                     "useful to add (such as an external URL for the puzzle.)" +
81                     "\n\n" +
82                     "A puzzle can be marked as a meta-puzzle and can be " +
83                     "assigned to one or more rounds. If the round(s) for " +
84                     "this puzzle already exist, simply click on them in " +
85                     "the \"Round(s)\" field. If this is the first puzzle " +
86                     "for a new round, then type the name of the round in " +
87                     "the \"New round(s)\" field." +
88                     "\n\n" +
89                     "For the new puzzle, Turbot will create a Slack channel " +
90                     "and a shared spreadsheet for the puzzle. It will also " +
91                     "announce the new puzzle in the hunt's channel, where " +
92                     "members of the hunt can click to join the puzzle's " +
93                     "channel and then click through to the puzzle's sheet." +
94                     "\n\n" +
95                     "This command can also be issued as `/new hunt` from " +
96                     "any channel to create an entirely new hunt.")
97     },
98     "puzzle": {
99         "summary": "Display the status of the current puzzle",
100         "usage": "`/puzzle`, `/puzzle new`, `/puzzle edit",
101         "details": ("When you issue `/puzzle` alone in a puzzle channel, " +
102                     "Turbot will reply (privately to you) with all the " +
103                     "information it has about the current puzzle. For all " +
104                     "puzzles this includes the solved status (either an " +
105                     "unchecked or checked checkbox), the puzzle title, " +
106                     "links to the puzzle's external web page and sheet, " +
107                     "the rounds of the puzzle, and tags, and the puzzle's " +
108                     "state string." +
109                     "\n\n" +
110                     "If this is a meta-puzzle the output will also include " +
111                     "the names (and solutions where known) of all other " +
112                     "puzzles in the same round as the current puzzle." +
113                     "\n\n" +
114                     "This command also support `/puzzle new` and " +
115                     "`/puzzle edit` which are identical to `/new puzzle` " +
116                     "and `/edit puzzle` so see `/help new` and `/help edit` " +
117                     "for details.")
118     },
119     "round": {
120         "summary": "Display puzzles in the same round as the current puzzle",
121         "usage": "`/round [unsolved|solved|all] [meta|plain] <search_terms>`",
122         "details": ("The `/round` command can be issued from any puzzle " +
123                     "channel and will display (by default) all puzzles " +
124                     "belonging to the same round(s) as the current puzzle." +
125                     "\n\n"
126                     "To filter to only solved or unsolved puzzles, issue " +
127                     "`/round solved` or `/round unsolved` instead." +
128                     "\n\n" +
129                     "This command also supports all of the same options as " +
130                     "the `/hunt` command for searching/filtering which " +
131                     "puzzles to display. So see `/help hunt` for details.")
132     },
133     "rot": {
134         "summary": "Perform a Caesar shift rotation on some text",
135         "usage": "`/rot TEXT`, `/rot * TEXT`, `/rot COUNT TEXT`",
136         "details": ("This command performs a Caesar shift rotation on the " +
137                     "text you provide to the command. An initial numeric " +
138                     "argument indicates how many places through the " +
139                     "alphabet each character should be rotated." +
140                     "\n\n" +
141                     "If the numeric argument is omitted, or is the " +
142                     "character `*` this command will emit every possible " +
143                     "rotation of the provided text." +
144                     "\n\n"
145                     "Note: Unlike commands such as `/hunt` or `/puzzle` the " +
146                     "output from `/rot` will be presented to the current " +
147                     "channel rather than privately to you. The idea behind " +
148                     "this is that others working on the same puzzle might " +
149                     "benefit from this output as well." +
150                     "\n\n" +
151                     "If you would like to execute this command privately, " +
152                     "may issue it in a direct-message conversation with " +
153                     "Turbot.")
154     },
155     "state": {
156         "summary": "Updates the state of this puzzle",
157         "usage": "`/state <WHERE THINGS STAND>`",
158         "details": ("This command allows you to capture a high-level " +
159                     "description of the state of a puzzle. This is " +
160                     "particularly useful when you are switching away from " +
161                     "a puzzle to let the next solvers know the state of " +
162                     "things." +
163                     "\n\n" +
164                     "Turbot will present the state string in every view it " +
165                     "generates for the puzzle." +
166                     "\n\n" +
167                     "An example state string might be something like: " +
168                     "`/state Grid is filled, but we need help on extraction`" +
169                     " or similar.")
170     },
171     "solved": {
172         "summary": "Record the solution of a puzzle",
173         "usage": "`/solved SOLUTION HERE`",
174         "details": ("Once you've submitted a solution to the hunt's website " +
175                     "and it has been confirmed, issue the `/solved` command " +
176                     "so that Turbot knows the puzzle is solved. Turbot will " +
177                     "report to the hunt's channel that the puzzle has been " +
178                     "solved.")
179     },
180     "tag": {
181         "summary": "Add or remove a tag to a puzzle",
182         "usage": "`/tag NEW_TAG`",
183         "details": ("This command allows you to add brief descriptive tags " +
184                     "to a puzzle. This might include puzzle types, specific " +
185                     "domain knowledge, or metadata from the puzzle’s " +
186                     "presentation which might be used elsewhere." +
187                     "\n\n" +
188                     "Tags can only consist of letters, numbers, and the " +
189                     "underscore character `_`." +
190                     "\n\n" +
191                     "You can also add a tag by typing `/tag +TAG_TO_ADD` " +
192                     "and remove a tag with `/tag -TAG_TO_REMOVE`.")
193     }
194 }
195
196 def turbot_help(args):
197     """The top-level implementation of the Turbot help system
198
199     With empty args, gives a summary of available commands.
200
201     With any command name, gives detailed help on that command.
202     """
203
204     if not args:
205         return overview
206
207     # We only look at the first word here
208     command = args.split(" ", 1)[0]
209
210     # Ignore any slash prefix the user may have given
211     if command[0] == '/':
212         command = command[1:]
213
214     if command not in commands:
215         valid = list(commands.keys())
216         valid.sort()
217         return "Unknown command: {}. Valid commands are: {}".format(
218             command, ", ".join(valid))
219
220     dict = commands[command]
221     return ("*Help on `/{}`*".format(command) +
222             "\n`/{}`: {}".format(command, dict["summary"]) +
223             "\nUsage: {}".format(dict["usage"]) +
224             "\n\n{}".format(dict["details"]))