async def sources(self, ctx, name=''): '''Print a list of all sources and their descriptions, or details on a specific source.''' name = name.lower() uname = name.upper() # Info on a specific source if name != '' and name in sources: embed = sources[name].embed() # bot takes credit for native sources embed.set_footer(text=self.bot.user.name, icon_url=self.bot.user.avatar_url) await ctx.send(embed=embed) # Info on a macro source elif name != '' and name in source_macros: await ctx.send(embed=source_macros[name].embed()) # Sources in a specific category elif uname != '' and uname in sources.categories: infos = [] infos.append('Sources in category {}:\n'.format(uname)) colW = len(max(sources, key=len)) + 2 for source in sources.categories[uname]: info = source.name.ljust(colW) if source.doc: info += source.small_doc infos.append(info) infos.append('') infos.append('Use >sources [source name] to see more info on a specific source.') infos.append('Use >source_macros for a list of user-defined sources.\n') await ctx.send(texttools.block_format('\n'.join(infos))) # List of categories else: infos = [] infos.append('Categories:\n') colW = len(max(sources.categories, key=len)) + 2 for category in sources.categories: info = category.ljust(colW) cat = sources.categories[category] MAX_PRINT = 8 if len(cat) > MAX_PRINT: info += ', '.join(s.name for s in cat[:MAX_PRINT - 1]) + '... (%d more)' % (len(cat) - MAX_PRINT + 1) else: info += ', '.join(s.name for s in cat) infos.append(info) infos.append('') infos.append('Use >sources [category name] for the list of sources in a specific category.') infos.append('Use >sources [source name] to see more info on a specific source.') infos.append('Use >source_macros for a list of user-defined sources.\n') await ctx.send(texttools.block_format('\n'.join(infos)))
async def spouts(self, ctx, name=''): '''Print a list of all spouts and their descriptions, or details on a specific source.''' name = name.lower() # Info on a specific spout if name != '' and name in spouts or name in pipes: embed = (spouts if name in spouts else pipes)[name].embed() # bot takes credit for native spouts embed.set_footer(text=self.bot.user.name, icon_url=self.bot.user.avatar_url) await ctx.send(embed=embed) # Info on all spouts else: infos = [] infos.append( 'Here\'s a list of spouts, use >spouts [spout name] to see more info on a specific one.' ) infos.append('') colW = len(max(spouts, key=len)) + 2 for name in spouts: spout = spouts[name] info = name + ' ' * (colW - len(name)) if spout.doc: info += spout.small_doc infos.append(info) text = texttools.block_format('\n'.join(infos)) await ctx.send(text)
async def word_gradient(self, ctx, w1: str, w2: str, n: int = 5): '''gradient between two words''' if n > 9: return text = '\n'.join( util.remove_duplicates([w1] + texttools.dist_gradient(w1, w2, n) + [w2])) await ctx.send(texttools.block_format(text))
def embed(self, ctx=None): title = self.name + (' `hidden`' if not self.visible else '') embed = Embed(title=self.kind + ' Macro: ' + title, description=(self.desc or ''), color=0x06ff83) ### Parameter list if self.signature: argstr = '\n'.join(str(self.signature[s]) for s in self.signature) embed.add_field(name='Parameters', value=argstr, inline=False) ### Script box embed.add_field(name='Script', value=texttools.block_format(self.code), inline=False) ### Author credit footer author = None if ctx: # Look for the author in the current Guild first if ctx.guild: author = ctx.guild.get_member(self.authorId) if not author: author = ctx.bot.get_user(self.authorId) if author: embed.set_footer(text=author.display_name, icon_url=author.avatar_url) else: embed.set_footer(text=self.authorName) return embed
async def _define(self, message, what, name, code, force=False): '''Define a macro.''' channel = message.channel what = what.lower() try: macros, visible, native, check = typedict[what] except: await self.what_complain(channel) return name = name.lower().split(' ')[0] if name in native or name in macros: await channel.send( 'A {0} called `{1}` already exists, try `>redefine {0}` instead.' .format(what, name)) return if not force and not await check(code, channel): MacroCommands.FORCE_MACRO_CACHE = ('new', message, what, name, code) await channel.send('Reply `>force_macro` to save it anyway.') return author = message.author macros[name] = Macro(macros.kind, name, code, author.name, author.id, visible=visible) await channel.send('Defined a new {} macro called `{}` as {}'.format( what, name, texttools.block_format(code)))
async def _redefine(self, message, what, name, code, force=False): '''Redefine an existing macro.''' channel = message.channel what = what.lower() try: macros, _, _, check = typedict[what] except: await self.what_complain(channel) return name = name.lower().split(' ')[0] if name not in macros: await self.not_found_complain(channel, what) return if not macros[name].authorised(message.author): await self.permission_complain(channel) return if not force and not await check(code, channel): MacroCommands.FORCE_MACRO_CACHE = ('edit', message, what, name, code) await channel.send('Reply `>force_macro` to save it anyway.') return macros[name].code = code macros.write() await channel.send('Redefined {} `{}` as {}'.format( what, name, texttools.block_format(code)))
async def _define(self, message, what, name, code): '''Define a macro.''' channel = message.channel what = what.lower() try: macros, visible, native = typedict[what] except: await self.what_complain(channel) return name = name.lower().split(' ')[0] if name in native or name in macros: await channel.send( 'A {0} called "{1}" already exists, try `>redefine {0}` instead.' .format(what, name)) return author = message.author macros[name] = Macro(name, code, author.name, author.id, str(author.avatar_url), visible=visible) await channel.send('Defined a new {} macro called `{}` as {}'.format( what, name, texttools.block_format(code)))
def embed(self, ctx): desc = '{} in this channel'.format('Enabled' if ctx.channel in self.channels else 'Disabled') embed = Embed(title='Event: ' + self.name, description=desc, color=0x7628cc) ## On message embed.add_field(name='On message', value='`%s`' % self.patternstr, inline=True) ### List of the current server's channels it's enabled in channels = [ ch.mention for ch in ctx.guild.text_channels if ch.id in self.channels ] embed.add_field(name='Enabled channels', value=', '.join(channels) or 'None', inline=True) ## Script embed.add_field(name='Script', value=block_format(self.script), inline=False) return embed
def embed(self): title = self.name + (' `hidden`' if not self.visible else '') embed = Embed(title='Macro: ' + title, description=(self.desc or ''), color=0x06ff83) ### Arguments if self.signature: argstr = '\n'.join(str(self.signature[s]) for s in self.signature) embed.add_field(name='Arguments', value=argstr, inline=False) ### Script embed.add_field(name='Script', value=texttools.block_format(self.code), inline=False) ### Footer embed.set_footer(text=self.authorName, icon_url=self.authorAvatarURL) return embed
async def _macros(self, ctx, what, name): macros, *_ = typedict[what] # Info on a specific macro if name != '' and name in macros: await ctx.send(embed=macros[name].embed()) # Info on all of them else: if name == 'hidden': what2 = 'hidden ' + what filtered_macros = macros.hidden() elif name == 'mine' or name == 'my': what2 = 'your ' + what filtered_macros = [ m for m in macros if macros[m].authorId == ctx.author.id ] else: what2 = what filtered_macros = macros.visible() if not filtered_macros: await ctx.send( 'No {0} macros loaded. Try adding one using >define {0}.'. format(what2)) return infos = [] infos.append( 'Here\'s a list of all {what2} macros, use >{what}_macros [name] to see more info on a specific one.' .format(what2=what2, what=what)) infos.append('Use >{what}s for a list of native {what}s.\n'.format( what=what)) colW = len(max(filtered_macros, key=len)) + 2 for name in filtered_macros: macro = macros[name] info = name + ' ' * (colW - len(name)) if macro.desc is not None: info += macro.desc.split('\n')[0] infos.append(info) text = texttools.block_format('\n'.join(infos)) await ctx.send(text)
async def _redefine(self, message, what, name, code): '''Redefine an existing macro.''' channel = message.channel what = what.lower() try: macros, *_ = typedict[what] except: await self.what_complain(channel) return name = name.lower().split(' ')[0] if name not in macros: await self.not_found_complain(channel, what) return if not macros[name].authorised(message.author): await self.permission_complain(channel) return macros[name].code = code macros.write() await channel.send('Redefined {} `{}` as {}'.format( what, name, texttools.block_format(code)))
async def print(self, dest, output): ''' Nicely print the output in rows and columns and even with little arrows.''' # Don't apply any formatting if the output is just a single row and column. if len(output) == 1: if len(output[0]) == 1: if output[0][0].strip() != '': await dest.send(output[0][0]) else: await dest.send('`empty string`') return elif len(output[0]) == 0: await dest.send('`no output`') return rowCount = len(max(output, key=len)) rows = [''] * rowCount for c in range(len(output)): col = output[c] if len(col) == 0: continue colWidth = len(max(col, key=len)) for r in range(rowCount): if r < len(col): rows[r] += col[r] + ' ' * (colWidth - len(col[r])) else: rows[r] += ' ' * colWidth try: output[c+1][r] rows[r] += ' → ' except: rows[r] += ' ' pass # Remove unnecessary padding rows = [row.rstrip() for row in rows] output = texttools.block_format('\n'.join(rows)) await dest.send(output)
async def pipes(self, ctx, name=''): '''Print a list of all pipes and their descriptions, or details on a specific pipe.''' name = name.lower() uname = name.upper() ## Info on a specific pipe, spout or source if name != '' and name in pipes or name in spouts or name in sources: embed = (pipes if name in pipes else spouts if name in spouts else sources)[name].embed() embed.set_footer(text=self.bot.user.name, icon_url=self.bot.user.avatar_url) await ctx.send(embed=embed) ## Info on a pipe macro or source macro elif name != '' and name in pipe_macros or name in source_macros: embed = (pipe_macros if name in pipe_macros else source_macros)[name].embed(ctx) await ctx.send(embed=embed) ## List pipes in a specific category elif uname != '' and uname in pipes.categories: infos = [] infos.append('Pipes in category {}:\n'.format(uname)) category = pipes.categories[uname] colW = len(max((p.name for p in category), key=len)) + 3 for pipe in category: info = pipe.name.ljust(colW) if pipe.doc: info += pipe.small_doc infos.append(info) infos.append('') infos.append( 'Use >pipes [pipe name] to see more info on a specific pipe.') infos.append( 'Use >pipe_macros for a list of user-defined pipes.\n') await ctx.send(texttools.block_format('\n'.join(infos))) ## List all categories else: infos = [] infos.append('Categories:\n') colW = len(max(pipes.categories, key=len)) + 2 for category in pipes.categories: info = category.ljust(colW) cat = pipes.categories[category] MAX_PRINT = 8 if len(cat) > MAX_PRINT: info += ', '.join( p.name for p in cat[:MAX_PRINT - 1]) + '... (%d more)' % ( len(cat) - MAX_PRINT + 1) else: info += ', '.join(p.name for p in cat) infos.append(info) infos.append('') infos.append( 'Use >pipes [category name] for the list of pipes in a specific category.' ) infos.append( 'Use >pipes [pipe name] to see more info on a specific pipe.') infos.append( 'Use >pipe_macros for a list of user-defined pipes.\n') await ctx.send(texttools.block_format('\n'.join(infos)))
async def say_block(self, s, **kwargs): await self.say(texttools.block_format(s), **kwargs)
async def files(self, ctx, name: str = None): '''List all uploaded txt files, or show the contents of a specific file.''' categories = uploads.get_categories() #### Print a list of all categories if not name: lines = ['Categories:\n'] colW = len(max(categories, key=len)) + 2 for category in categories: line = category.ljust(colW) line += ', '.join(file.info.name for file in categories[category]) lines.append(line) lines.append('') lines.append('Use >file [name] for details on a specific file.') lines.append( 'Use >file [CATEGORY] for the list of files in that category.') for block in texttools.block_chunk_lines(lines): await ctx.send(block) return #### Print a list of files in a specific category if name.isupper() and name in categories: files = categories[name] lines = [f'Files under category {name}:'] described = [file for file in files if file.info.description] undescribed = [file for file in files if not file.info.description] if described: lines.append('') colW = len( max(described, key=lambda f: len(f.info.name)).info.name) + 2 for file in described: line = file.info.name.ljust(colW) desc = file.info.description.split('\n', 1)[0] line += desc if len(desc) <= 80 else desc[:75] + '(...)' lines.append(line) if undescribed: lines.append('\nWithout descriptions:') lines += texttools.line_chunk_list( [file.info.name for file in undescribed]) lines.append('') lines.append('Use >file [name] for details on a specific file.') for block in texttools.block_chunk_lines(lines): await ctx.send(block) return #### Print info on a specific file if name not in uploads: await ctx.send(f'No file by name `{name}` found!') return name = uploads[name] info = name.info lines = name.get() # TODO: make this a little File.embed() ? text = '**File:** ' + info.name text += ', **Uploader:** ' + info.author_name + '\n' text += '**Order:** ' + ('Sequential' if info.sequential else 'Random') text += ', **Split on:** ' + (('`' + repr(info.splitter)[1:-1] + '`') if not info.sentences else 'Sentences') text += ', **Entries:** ' + str(len(lines)) + '\n' text += '**Categories:** ' + (', '.join(info.categories) if info.categories else "(none)") text += ', **Editable:** ' + str(info.editable) + '\n' MAXLINES = 8 MAXCHARS = 600 print_lines = [] chars = 0 for line in lines: if len(line) + chars > MAXCHARS: if not print_lines: print_lines.append(line[:MAXCHARS - 40] + '(...)') if len(lines) > len(print_lines): print_lines.append('...%d more lines omitted' % (len(lines) - len(print_lines))) break print_lines.append(line) chars += len(line) if len(print_lines) > MAXLINES: print_lines[MAXLINES:] = [] print_lines.append('...%d more lines omitted' % (len(lines) - len(print_lines))) break text += texttools.block_format('\n'.join(print_lines)) await ctx.send(text)