def show_thread(request, board_id, post_id): if not request.user.is_authenticated or request.user.username == "": return render(request, 'login.html', {}) try: post = Post.objects.get(pk=post_id) board = post.db_board if not board.access(request.user, access_type="read", default=False): context = {'board': board} return render(request, 'board_noperm.html', context) can_post = board.access(request.user, access_type="post", default=False) plaintext = ansi.strip_ansi(post.db_text) setattr(post, 'plaintext', plaintext) post.mark_read(request.user, True) replies = Post.objects.filter(db_parent=post).order_by('db_date_created') for r in replies: plaintext = ansi.strip_ansi(r.db_text) setattr(r, 'plaintext', plaintext) r.mark_read(request.user, True) form = ReplyForm() context = {'board': board, 'post': post, 'replies': replies, 'can_post': can_post, 'board_id': board, 'post_id': post, 'form': form} return render(request, 'thread.html', context) except (Post.DoesNotExist, Post.MultipleObjectsReturned): return Http404("Error accessing boards.")
def post_map(post_to_map, bulletin_board): """Returns dict of information about each individual post to add to context""" return { "id": post_to_map.id, "poster": bulletin_board.get_poster(post_to_map), "subject": ansi.strip_ansi(post_to_map.db_header), "date": post_to_map.db_date_created.strftime("%x"), "text": ansi.strip_ansi(post_to_map.db_message), }
def post_map(post_to_map, bulletin_board): """Returns dict of information about each individual post to add to context""" return { 'id': post_to_map.id, 'poster': bulletin_board.get_poster(post_to_map), 'subject': ansi.strip_ansi(post_to_map.db_header), 'date': post_to_map.db_date_created.strftime("%x"), 'text': ansi.strip_ansi(post_to_map.db_message) }
def post_map(post): """Returns dict of information about each individual post to add to context""" return { 'id': post.id, 'board': post.bulletin_board.key, 'poster': post.poster_name, 'subject': ansi.strip_ansi(post.db_header), 'date': post.db_date_created.strftime("%x"), 'text': ansi.strip_ansi(post.db_message) }
def trail(string, length=26, tail="...", dir="left", delim=" "): l = length - len(tail) if len(strip_ansi(string)) <= l: if dir.lower() == 'left': return string + delim * (length - len(strip_ansi(string))) else: return delim * (length - len(strip_ansi(string))) + string else: return string[:l] + tail
def _add_keys_choice(self): """Add the choices' keys if some choices don't have valid keys.""" # If choices have been added without keys, try to guess them for choice in self.choices: if not choice.key: title = strip_ansi(choice.title.strip()).lower() length = self.min_shortcut while length <= len(title): i = 0 while i < len(title) - length + 1: guess = title[i:i + length] if guess not in self.cmds: choice.key = guess break i += 1 if choice.key: break length += 1 if choice.key: self.cmds[choice.key] = choice else: raise ValueError( "Cannot guess the key for {}".format(choice))
def _add_keys_choice(self): """Add the choices' keys if some choices don't have valid keys.""" # If choices have been added without keys, try to guess them for choice in self.choices: if not choice.key: title = strip_ansi(choice.title.strip()).lower() length = self.min_shortcut while length <= len(title): i = 0 while i < len(title) - length + 1: guess = title[i:i + length] if guess not in self.cmds: choice.key = guess break i += 1 if choice.key: break length += 1 if choice.key: self.cmds[choice.key] = choice else: raise ValueError("Cannot guess the key for {}".format(choice))
def test_node_allocate_skills_above_ten(self): """test invalid skill allocation above 10""" archetypes.apply_archetype(self.char1, 'arcanist') traits = self.char1.traits traits.VIT.mod = 2 traits.DEX.mod = 2 traits.INT.mod = 3 traits.BM.base = 8 races.apply_race(self.char1, 'elf', 'spirit') archetypes.calculate_secondary_traits(self.char1.traits) archetypes.finalize_traits(self.char1.traits) skills.apply_skills(self.char1) self.session.execute_cmd('@charcreate Char') # -1's self.session.execute_cmd('9') self.session.execute_cmd('9') self.session.execute_cmd('9') # +1's self.session.execute_cmd('7') self.session.execute_cmd('7') self.assertEqual(self.char1.skills.appraise.plus, 1) # confirm error message last_msg = ansi.strip_ansi(self.session.msg.mock_calls[-1][1][0]) self.assertIn('Skills cannot be increased above ten.', last_msg) self.assertIn("Please allocate two '+1' counters.", last_msg)
def no_match(self, string): """A no match has been entered, perhaps an application name.""" string = string.strip() app = self.type.apps.get(string, "app") if not app: string = string.lower() matches = [] for app in self.type.apps: if type(app).folder == "app" and strip_ansi(app.display_name).lower().startswith(string): matches.append(app) # If only one match, just move there if len(matches) == 1: app = matches[0] elif len(matches) == 0: self.user.msg("|gNo app name matches these letters.|n") return True else: names = [type(app).display_name for app in matches] names.sort(key=lambda name: name.lower()) self.user.msg("Which app do you want to open? {}".format(", ".join(names))) return True screen = type(app).start_screen self.next(screen, app) return True
def wod_header(title=None, align="l", linecolor="W", textcolor="w", accentcolor="w"): ''' Shows a 78 character wide header. Optional header imbedded in it. :param title: String that will be shown in white over the header, optional. :param align: "l", "c", or "r" alignment. Only used if title is provided. :param linecolor: Single character color code, default is 'W' (Light grey) :param textcolor: Single character color code, default is 'w' (White) :param accentcolor: Single character color code, default is 'w' (White) ''' if title: fulltitle = "|%s===|%s|||%s %s |%s|||%s===" % ( linecolor, accentcolor, textcolor, title, accentcolor, linecolor) w = len(strip_ansi(fulltitle)) if align == "r": line = '|%s%s|n' % (linecolor, ANSIString(fulltitle).rjust( width=78, fillchar="=")) elif align == "c": line = '|%s%s|n' % (linecolor, ANSIString(fulltitle).center( width=78, fillchar="=")) else: line = '|%s%s|n' % (linecolor, ANSIString(fulltitle).ljust( width=78, fillchar="=")) else: line = '|%s%s|n' % (linecolor, pad('', width=78, fillchar='=')) return line
def test_node_allocate_skills_startover(self): """test starting over after allocating some skill counters""" archetypes.apply_archetype(self.char1, 'scout') traits = self.char1.traits traits.INT.mod = traits.DEX.mod = traits.CHA.mod = 1 traits.VIT.mod = 5 races.apply_race(self.char1, 'human', 'cunning') archetypes.calculate_secondary_traits(self.char1.traits) archetypes.finalize_traits(self.char1.traits) skills.apply_skills(self.char1) self.session.execute_cmd('@charcreate Char') # -1's self.session.execute_cmd('7') self.session.execute_cmd('8') self.session.execute_cmd('9') # +1's self.session.execute_cmd('4') self.session.execute_cmd('5') # start over self.session.execute_cmd('16') sk = self.char1.skills for s in sk.all: self.assertEqual(sk[s].minus, 0) self.assertEqual(sk[s].plus, 0) # confirm error message last_msg = ansi.strip_ansi(self.session.msg.mock_calls[-1][1][0]) self.assertIn("Please allocate three '-1' counters.", last_msg)
def func(self): caller = self.caller #if they use an =, we know something is wrong if self.rhs: syntax_error(caller, self.key) return #if the arg is "delete", we just delete their name colors and ignore everything else if self.args == "delete": del caller.db.colorname return #strip the ANSI from the submitted name and make sure they aren't trying to impostor someone else stripped = strip_ansi(self.args) #if the stripped name doesn't equal their name, error if stripped != caller.name: caller.msg( "That name doesn't match yours! Your name must not change, only add color codes." ) return if stripped == caller.name: caller.db.colorname = self.args caller.msg("Your name colors have been set to %s" % caller.db.colorname)
def func(self): """Redirect most inputs to the screen, if found.""" raw_string = self.raw_string.rstrip() if getattr(self, "screen", None) is None: main.error("The CmdSet doesn't have a screen attribute.") self.msg("An error occurred. Closing the interface...") self.caller.cmdset.delete(ComputerCmdSet) return screen = self.screen if screen.user is not self.caller: main.error( "The recorded screen has user {} while the CmdSet has caller {}" .format(screen.user, self.caller)) self.msg("An error occurred. Closing the interface...") self.caller.cmdset.delete(ComputerCmdSet) screen.close() return # Handle "back" and "quit" if raw_string.lower() == "back" and screen.can_back: # Move one step ahead if screen.previous: screen.back() else: self.msg("You cannot go back.") elif raw_string.lower() == "exit" and screen.can_quit: self.msg("You quit the interface of {}.".format( screen.obj.get_display_name(self.caller))) screen.close() screen.type.quit() else: ret = screen.no_match(strip_ansi(raw_string)) if not ret: screen.wrong_input(raw_string)
def log(self, message, caller=None): """ Log to a file specificially for this room. """ caller = f"[caller.key]: " if caller else "" logger.log_file(strip_ansi(f"{caller}{message.strip()}"), filename=self.tagcategory + ".log")
def test_node_welcome(self): """test welcome node output""" self.session.new_char = self.char1 (text, help), options = menunode_welcome_archetypes(self.session) opt_texts = [ansi.strip_ansi(o['desc']) for o in options] self.assertEqual(opt_texts, ['Arcanist', 'Scout', 'Warrior', 'Warrior-Scout', 'Warrior-Arcanist', 'Arcanist-Scout'])
def header(string, fill="|113-|n", length="78", lframe="|113[|n", rframe="|113]|n", just="left", offset=0): """ Create a header for different areas of the game. """ str_len = int(length) - round( len(strip_ansi(string)) + len(strip_ansi(lframe)) + len(strip_ansi(lframe))) - offset if just.lower() == "left": return fill * offset + lframe + string + rframe + fill * str_len + "\n" else: return fill * str_len + lframe + string + rframe + fill * offset + "\n"
def post_map(post, bulletin_board, read_posts_list): """Helper function to get dict of post information to add to context per post""" return { 'id': post.id, 'poster': bulletin_board.get_poster(post), 'subject': ansi.strip_ansi(post.db_header), 'date': post.db_date_created.strftime("%x"), 'unread': post not in read_posts_list }
def post_map(post, bulletin_board, read_posts_list): """Helper function to get dict of post information to add to context per post""" return { "id": post.id, "poster": bulletin_board.get_poster(post), "subject": ansi.strip_ansi(post.db_header), "date": post.db_date_created.strftime("%x"), "unread": post not in read_posts_list, }
def get_text(self): """Display the installed apps.""" string = dedent(""" AvenOS 12.0 [6G] [Bluetooth] [96%} """.lstrip("\n")) + "\n " i = 0 for app in self.type.apps: if i > 0 and i % 4 == 0: string = string.rstrip(" ") + "\n" + " " * 4 text = app.get_display_name() no_ansi_text = strip_ansi(text) string += "{name}".format(name=self.format_cmd(text, strip_ansi(app.display_name).lower(), upper=False)) string += " " * (15 - len(no_ansi_text)) string = string.rstrip(" ") + "\n\n" + dedent(""" Enter the first letters to open this app. Type |hEXIT|n to quit the interface." """.lstrip("\n")) return string
def _simple_form(self, form): cellsdict = {1: "Apple", 2: "Banana", 3: "Citrus", 4: "Durian"} formdict = {"FORMCHAR": 'x', "TABLECHAR": 'c', "FORM": form} form = evform.EvForm(form=formdict) form.map(cellsdict) form = ansi.strip_ansi(str(form)) # this is necessary since editors/black tend to strip lines spaces # from the end of lines for the comparison strings. form = "\n".join(line.rstrip() for line in form.split("\n")) return form
def test_node_allocate_traits_toomany(self): """test trait allocation node""" archetypes.apply_archetype(self.char1, 'warrior') self.session.execute_cmd('@charcreate Char') for i in list(range(5)): self.session.execute_cmd('1') self.assertEqual(self.char1.traits.STR.actual, 10) # confirm error message last_msg = ansi.strip_ansi(self.session.msg.mock_calls[-1][1][0]) self.assertIn('Cannot allocate more than 10 points to one trait!', last_msg)
def test_node_allocate_traits_toomany(self): """test trait allocation node""" archetypes.apply_archetype(self.char1, 'warrior') self.session.execute_cmd('@charcreate Char') for i in xrange(5): self.session.execute_cmd('1') self.assertEqual(self.char1.traits.STR.actual, 10) # confirm error message last_msg = ansi.strip_ansi(self.session.msg.mock_calls[-1][1][0]) self.assertIn('Cannot allocate more than 10 points to one trait!', last_msg)
def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): super().msg(text=ansi.strip_ansi(text), from_obj=from_obj, session=session, options=options**kwargs)
def fix_names(apps, schema_editor): from evennia.utils.ansi import strip_ansi from django.db.models import F, Q Agent = apps.get_model("dominion", "Agent") Agent.objects.all().update(colored_name=F('name')) for agent in Agent.objects.filter( Q(name__icontains='{') | Q(name__icontains='|') | Q(name__icontains='%')): agent.name = strip_ansi(agent.name) agent.save()
def color(entry, option_key="Color", **kwargs): """ The color should be just a color character, so 'r' if red color is desired. """ if not entry: raise ValueError(f"Nothing entered for a {option_key}!") test_str = strip_ansi(f"|{entry}|n") if test_str: raise ValueError(f"'{entry}' is not a valid {option_key}.") return entry
def sendLine(self, line): #parse_ansi(line, strip_ansi=True, xterm256=False, mxp=False) if self.header and self.ackSent == False: self.ackSent = True #print("UnrealPlugin sendLine: prefixing data with header: " + self.header) line = self.header + line line = line + "<EOF>" line = strip_ansi(line, parser=ANSI_PARSER) #print("UnrealPlugin sendLine: " + line) return self.transport.write(line)
def test_working(self): self.assertEqual(self.practitioner.anima, 100) self.assertFalse(self.practitioner.knows_node(self.node)) self.assertFalse(self.practitioner.knows_spell(self.spell)) self.practitioner.open_node( self.node, SkillNodeResonance.LEARN_FIAT, explanation="Learned by test fiat.", ) self.assertTrue(self.practitioner.knows_node(self.node)) self.assertEqual(self.practitioner.resonance_for_node(self.node), 0) self.practitioner.add_resonance_to_node(self.node, 10) self.assertEqual(self.practitioner.resonance_for_node(self.node), 10) self.assertTrue(self.practitioner.knows_spell(self.spell)) self.test_object.location = self.practitioner.character.location working = Working.objects.create( lead=self.practitioner, spell=self.spell, target_string=self.test_object.name, ) working.add_practitioner(self.practitioner, accepted=True) with patch( "world.magic.models.Working.successes", new_callable=PropertyMock(return_value=10), ) as fake_successes: self.assertEqual(working.validation_error(), None) from evennia.utils.ansi import strip_ansi with patch("typeclasses.scripts.combat.attacks.Attack"): working.perform(unsafe=False) working.finalize() self.assertEqual( strip_ansi(working.description_string()), " ID: 1 \n" " Participants: Char2 \n" " Lead: Char2 \n" " Alignment: Primal \n" " Type: Casting \n" " Spell: Test Spell \n" " Calculated: yes \n" " Performed: yes \n" " Available Primum: 100 \n" " Cost: 8 \n" " Danger Level: relatively safe \n" " Successes: 10 \n" " Result: Participants perceive: A spectacular glow. ", ) self.assertEqual( pending_magic_text(), "Char2 chants in Arvani and gestures expansively and energetically!\n" "As Char2 works magic, the effect spreading out from them resembles a test " "pattern atop static.\n" "Gazing at Test Object, you perceive: A spectacular glow.", ) self.assertEqual(self.practitioner.anima, 92)
def evtable_options_formatter(optionlist, caller=None): """ Formats the option list display. """ if not optionlist: return "" # column separation distance colsep = 4 nlist = len(optionlist) # get the widest option line in the table. table_width_max = -1 table = [] for key, desc in optionlist: if not (key or desc): continue table_width_max = max(table_width_max, max(m_len(p) for p in key.split("\n")) + max(m_len(p) for p in desc.split("\n")) + colsep) raw_key = strip_ansi(key) if raw_key != key: # already decorations in key definition table.append(ANSIString(" |lc%s|lt%s|le: %s" % (raw_key, key, desc))) else: # add a default white color to key table.append(ANSIString(" |lc%s|lt|w%s|n|le: %s" % (raw_key, raw_key, desc))) ncols = (_MAX_TEXT_WIDTH // table_width_max) + 1 # number of ncols nlastcol = nlist % ncols # number of elements left in last row # get the amount of rows needed (start with 4 rows) nrows = 4 while nrows * ncols < nlist: nrows += 1 ncols = nlist // nrows # number of full columns nlastcol = nlist % nrows # number of elements in last column # get the final column count ncols = ncols + 1 if nlastcol > 0 else ncols if ncols > 1: # only extend if longer than one column table.extend([" " for i in range(nrows - nlastcol)]) # build the actual table grid table = [table[icol * nrows : (icol * nrows) + nrows] for icol in range(0, ncols)] # adjust the width of each column for icol in range(len(table)): col_width = max(max(m_len(p) for p in part.split("\n")) for part in table[icol]) + colsep table[icol] = [pad(part, width=col_width + colsep, align="l") for part in table[icol]] # format the table into columns return unicode(EvTable(table=table, border="none"))
def at_pre_cmd(self): """ This hook is called before self.parse() on all commands """ from typeclasses.characters import Character if type(self.caller) != Character: return command = self.cmdstring + self.args echo = "\n{icon} |220" + ansi.strip_ansi(command) + "\n\n" return self.caller.msg(echo, icon="graf62")
def func(self): """Run the spoof command""" caller = self.caller if not self.args: caller.execute_cmd('help spoof') return if 'self' in self.switches: caller.msg(self.args) return else: # Strip any markup to secure the spoof. spoof = ansi.strip_ansi(self.args) # calling the speech hook on the location. # An NPC would know who spoofed. spoof = caller.location.at_say(caller, spoof) caller.location.msg_contents(spoof, options={'raw': True})
def strip_ansi(text): """Stripping out old ansi from a string""" from evennia.utils.ansi import strip_ansi text = strip_ansi(text) text = text.replace('%r', '').replace('%R', '').replace('%t', '').replace( '%T', '').replace('%b', '') text = text.replace('%cr', '').replace('%cR', '').replace('%cg', '').replace( '%cG', '').replace('%cy', '') text = text.replace('%cY', '').replace('%cb', '').replace('%cB', '').replace( '%cm', '').replace('%cM', '') text = text.replace('%cc', '').replace('%cC', '').replace('%cw', '').replace( '%cW', '').replace('%cx', '') text = text.replace('%cX', '').replace('%ch', '').replace('%cn', '') return text
def test_node_allocate_skills_below_one(self): """test invalid skill allocation below 1""" archetypes.apply_archetype(self.char1, 'scout') traits = self.char1.traits traits.INT.mod = traits.DEX.mod = traits.CHA.mod = 1 traits.VIT.mod = 5 races.apply_race(self.char1, 'human', 'cunning') archetypes.calculate_secondary_traits(self.char1.traits) archetypes.finalize_traits(self.char1.traits) skills.apply_skills(self.char1) self.session.execute_cmd('@charcreate Char') self.session.execute_cmd('15') self.session.execute_cmd('15') self.assertEqual(self.char1.skills.leadership.minus, 1) # confirm error message last_msg = ansi.strip_ansi(self.session.msg.mock_calls[-1][1][0]) self.assertIn('Skills cannot be reduced below one.', last_msg) self.assertIn("Please allocate two '-1' counters.", last_msg)
def test_node_equip_insuff_funds(self): """test insufficient funds messaging""" archetypes.apply_archetype(self.char1, 'scout') traits = self.char1.traits traits.INT.mod = traits.DEX.mod = traits.CHA.mod = 1 traits.VIT.mod = 5 races.apply_race(self.char1, 'human', 'cunning') archetypes.calculate_secondary_traits(self.char1.traits) archetypes.finalize_traits(self.char1.traits) skills.apply_skills(self.char1) skills.finalize_skills(self.char1.skills) # check insufficient funds self.session.execute_cmd('@charcreate Char') self.session.execute_cmd('4') self.session.execute_cmd('3') self.session.execute_cmd('y') messages = [ansi.strip_ansi(args[0]) for n, args, kw in self.session.msg.mock_calls] self.assertIn("You do not have enough money to buy a brigandine.", messages)
def _depth_first(menu, tree, visited, indent): # we are in a given node here nodename = menu.nodename options = menu.test_options if isinstance(options, dict): options = (options, ) # run validation tests for this node compare_text = self.expected_node_texts.get(nodename, None) if compare_text is not None: compare_text = ansi.strip_ansi(compare_text.strip()) node_text = menu.test_nodetext self.assertIsNotNone( bool(node_text), "node: {}: node-text is None, which was not expected.".format(nodename)) if isinstance(node_text, tuple): node_text, helptext = node_text node_text = ansi.strip_ansi(node_text.strip()) self.assertTrue( node_text.startswith(compare_text), "\nnode \"{}\':\nOutput:\n{}\n\nExpected (startswith):\n{}".format( nodename, node_text, compare_text)) compare_options_count = self.expected_node_options_count.get(nodename, None) if compare_options_count is not None: self.assertEqual( len(options), compare_options_count, "Not the right number of options returned from node {}.".format(nodename)) compare_options = self.expected_node_options.get(nodename, None) if compare_options: self.assertEqual( options, compare_options, "Options returned from node {} does not match.".format(nodename)) self._debug_output(indent, "*{}".format(nodename)) subtree = [] if not options: # an end node if nodename not in visited: visited.append(nodename) subtree = nodename else: for inum, optdict in enumerate(options): key, desc, execute, goto = optdict.get("key", ""), optdict.get("desc", None),\ optdict.get("exec", None), optdict.get("goto", None) # prepare the key to pass to the menu if isinstance(key, (tuple, list)) and len(key) > 1: key = key[0] if key == "_default": key = "test raw input" if not key: key = str(inum + 1) backup_menu = copy.copy(menu) # step the menu menu.parse_input(key) # from here on we are likely in a different node nodename = menu.nodename if menu.close_menu.called: # this was an end node self._debug_output(indent, " .. menu exited! Back to previous node.") menu = backup_menu menu.close_menu = MagicMock() visited.append(nodename) subtree.append(nodename) elif nodename not in visited: visited.append(nodename) subtree.append(nodename) _depth_first(menu, subtree, visited, indent + 2) #self._debug_output(indent, " -> arrived at {}".format(nodename)) else: subtree.append(nodename) #self._debug_output( indent, " -> arrived at {} (circular call)".format(nodename)) self._debug_output(indent, "-- {} ({}) -> {}".format(key, desc, goto)) if subtree: tree.append(subtree)
def goto(self, nodename, raw_string): """ Run a node by name Args: nodename (str): Name of node. raw_string (str): The raw default string entered on the previous node (only used if the node accepts it as an argument) """ try: # execute the node, make use of the returns. nodetext, options = self._execute_node(nodename, raw_string) except EvMenuError: return if self._persistent: self.caller.attributes.add("_menutree_saved_startnode", (nodename, raw_string)) # validation of the node return values helptext = "" if hasattr(nodetext, "__iter__"): if len(nodetext) > 1: nodetext, helptext = nodetext[:2] else: nodetext = nodetext[0] nodetext = "" if nodetext is None else str(nodetext) options = [options] if isinstance(options, dict) else options # this will be displayed in the given order display_options = [] # this is used for lookup self.options = {} self.default = None if options: for inum, dic in enumerate(options): # fix up the option dicts keys = make_iter(dic.get("key")) if "_default" in keys: keys = [key for key in keys if key != "_default"] desc = dic.get("desc", dic.get("text", _ERR_NO_OPTION_DESC).strip()) goto, execute = dic.get("goto", None), dic.get("exec", None) self.default = (goto, execute) else: keys = list(make_iter(dic.get("key", str(inum+1).strip()))) + [str(inum+1)] desc = dic.get("desc", dic.get("text", _ERR_NO_OPTION_DESC).strip()) goto, execute = dic.get("goto", None), dic.get("exec", None) if keys: display_options.append((keys[0], desc)) for key in keys: if goto or execute: self.options[strip_ansi(key).strip().lower()] = (goto, execute) self.nodetext = self._format_node(nodetext, display_options) # handle the helptext if helptext: self.helptext = helptext elif options: self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT else: self.helptext = _HELP_NO_OPTIONS if self.auto_quit else _HELP_NO_OPTIONS_NO_QUIT self.display_nodetext()
def func(self): """Basic pose, power pose, room posing - all in one""" cmd = self.cmdstring opt = self.switches args = unicode(self.args).strip() lhs, rhs = self.lhs, self.rhs char = self.character account = self.account here = char.location if char else None power = True if self.cmdstring == 'ppose' or self.cmdstring == 'pp' or self.cmdstring == 'p:' else False def parse_pose(text): return_text = [] for each in text.split(): match = None new_each = each word_end = '' if each.startswith('/'): # A possible substitution to test if each.endswith('/'): # Skip this one, it's /italic/ return_text.append(new_each) continue search_word = each[1:] if search_word.startswith('/'): # Skip this one, it's being escaped new_each = each[1:] else: # Marked for substitution, try to find a match if "'" in each: # Test for possessive or contraction: 's (apostrophe before end of grouping) pass if each[-1] in ".,!?": search_word, word_end = search_word[:-1], each[-1] match = char.search(search_word, quiet=True) return_text.append(new_each if not match else (match[0].get_display_name(char) + word_end)) return ' '.join(return_text) raw_pose = rhs if rhs and power else args raw_pose = parse_pose(raw_pose) non_space_chars = ['®', '©', '°', '·', '~', '@', '-', "'", '’', ',', ';', ':', '.', '?', '!', '…'] magnet = True if raw_pose and raw_pose[0] in non_space_chars or cmd == ";" else False doing = True if 'do' in cmd or 'rp' in cmd else False pose = ('' if magnet else '|_') + (ansi.strip_ansi(raw_pose) if doing else raw_pose) # ---- Setting Room poses as a doing message ---------- if doing: # Pose will have no markup when posing on the room, to minimize shenanigans. target = char # Initially assume the setting character is the target. if not args and 'reset' not in opt: has_pose = char.db.messages and char.db.messages.get('pose') if has_pose: # If target has poses set, display them to the setter. char.msg("Current pose reads: '%s'" % target.get_display_name(char, pose=True)) default_pose = target.db.messages and target.db.messages.get('pose_default') or None if default_pose: char.msg('Default pose is \'%s%s\'' % (char.get_display_name(char), default_pose)) else: char.msg('Default pose not set.') else: char.msg('No pose has been set.|/Usage: rp <pose-text> OR pose <obj> = <pose-text>') return if len(pose) > 60: # Pose length in characters, not counting the poser's name. char.msg('Your pose is too long.') return if rhs: # pose something else other than self. target = char.search(lhs) # Search for a reference to the target. if not target: return if pose: self.set_doing(char, pose, target) # Try to set the pose of the target. else: # pose self. target = char if 'reset' in opt: # Clears current temp doing, reverts it to default. pose = target.db.messages and target.db.messages.get('pose_default', '') if not target.db.messages: target.db.messages = {} target.db.messages['pose'] = pose elif 'default' in opt: # Sets doing pose default. self.set_doing(char, pose, target, True) # True means "set default", not temp doing. char.msg("Default pose is now: '%s%s'" % (target.get_display_name(char), pose)) return # Nothing more to do. Default never poses to room, just sets doing message. elif not rhs: self.set_doing(char, pose) # Setting temp doing message on the setter... if args and not ('silent' in opt or 'quiet' in opt) and char is target: # Allow set without posing account.execute_cmd(';%s' % pose) # pose to the room like a normal pose would. char.msg("Pose now set to: '%s'" % target.get_display_name(char, pose=True)) # Display name with pose. else: # ---- Action pose, not static Room Pose. --------------------- if '|/' in pose: pose = pose.split('|/', 1)[0] if 'magnet' in opt: char.msg("Pose magnet glyphs are %s." % non_space_chars) if not (here and char): if args: account.execute_cmd('pub :%s' % pose) else: account.msg('Usage: pose <message> to pose to public channel.') return if args: if power and self.rhs and 'o' not in self.switches: char.ndb.power_pose = pose account.execute_cmd(self.rhs) else: ooc = 'ooc' in self.switches prepend_ooc = '[OOC] ' if ooc else '' here.msg_contents(('%s{char}%s' % (prepend_ooc, escape_braces(pose)), {'type': 'pose', 'ooc': ooc}), from_obj=char, mapping=dict(char=char)) else: account.execute_cmd('help pose')
def _format_node(self, nodetext, optionlist): """ Format the node text + option section Args: nodetext (str): The node text optionlist (list): List of (key, desc) pairs. Returns: string (str): The options section, including all needed spaces. Notes: This will adjust the columns of the options, first to use a maxiumum of 4 rows (expanding in columns), then gradually growing to make use of the screen space. """ # # handle the node text # nodetext = dedent(nodetext).strip() nodetext_width_max = max(m_len(line) for line in nodetext.split("\n")) if not optionlist: # return the node text "naked". separator1 = "_" * nodetext_width_max + "\n\n" if nodetext_width_max else "" separator2 = "\n" if nodetext_width_max else "" + "_" * nodetext_width_max return separator1 + nodetext + separator2 # # handle the options # # column separation distance colsep = 4 nlist = len(optionlist) # get the widest option line in the table. table_width_max = -1 table = [] for key, desc in optionlist: table_width_max = max(table_width_max, max(m_len(p) for p in key.split("\n")) + max(m_len(p) for p in desc.split("\n")) + colsep) raw_key = strip_ansi(key) if raw_key != key: # already decorations in key definition table.append(ANSIString(" {lc%s{lt%s{le: %s" % (raw_key, key, desc))) else: # add a default white color to key table.append(ANSIString(" {lc%s{lt{w%s{n{le: %s" % (raw_key, raw_key, desc))) ncols = (_MAX_TEXT_WIDTH // table_width_max) + 1 # number of ncols nlastcol = nlist % ncols # number of elements left in last row # get the amount of rows needed (start with 4 rows) nrows = 4 while nrows * ncols < nlist: nrows += 1 ncols = nlist // nrows # number of full columns nlastcol = nlist % nrows # number of elements in last column # get the final column count ncols = ncols + 1 if nlastcol > 0 else ncols if ncols > 1: # only extend if longer than one column table.extend([" " for i in xrange(nrows-nlastcol)]) # build the actual table grid table = [table[icol*nrows:(icol*nrows) + nrows] for icol in xrange(0, ncols)] # adjust the width of each column total_width = 0 for icol in xrange(len(table)): col_width = max(max(m_len(p) for p in part.split("\n")) for part in table[icol]) + colsep table[icol] = [pad(part, width=col_width + colsep, align="l") for part in table[icol]] total_width += col_width # format the table into columns table = EvTable(table=table, border="none") # build the page total_width = max(total_width, nodetext_width_max) separator1 = "_" * total_width + "\n\n" if nodetext_width_max else "" separator2 = "\n" + "_" * total_width + "\n\n" if total_width else "" return separator1 + nodetext + separator2 + unicode(table)
def _debug_output(self, indent, msg): if self.debug_output: print(" " * indent + ansi.strip_ansi(msg))
def func(self): """Run the spoof command""" char = self.character here = char.location opt = self.switches args = self.args to_self = 'self' in opt or not here if not args: self.account.execute_cmd('help spoof') return # Optionally strip any markup /or/ just escape it, stripped = ansi.strip_ansi(args) spoof = stripped if 'strip' in opt else args.replace('|', '||') if 'indent' in opt: indent = 20 if self.rhs: args = self.lhs.strip() indent = re.sub("[^0123456789]", '', self.rhs) or 20 indent = int(indent) if to_self: char.msg(' ' * indent + args.rstrip()) else: here.msg_contents(text=(' ' * indent + escape_braces(args.rstrip()), {'type': 'spoof'})) elif 'right' in opt or 'center' in opt or 'news' in opt: if self.rhs is not None: # Equals sign exists. parameters = '' if not self.rhs else self.rhs.split() args = self.lhs.strip() if len(parameters) > 1: if len(parameters) == 2: outside, inside = self.rhs.split() else: outside, inside = [parameters[0], parameters[1]] outside = re.sub("[^0123456789]", '', outside) or 0 inside = re.sub("[^0123456789]", '', inside) or 0 outside, inside = [int(max(outside, inside)), int(min(outside, inside))] else: outside, inside = [72, 20] else: outside, inside = [72, min(int(self.rhs or 72), 20)] block = 'r' if 'right' in opt else 'f' block = 'c' if 'center' in opt else block for text in justify(args, width=outside, align=block, indent=inside).split('\n'): if to_self: char.msg(text.rstrip()) else: here.msg_contents(text=(escape_braces(text.rstrip()), {'type': 'spoof'})) else: if 'strip' in opt: # Optionally strip any markup or escape it, if to_self: char.msg(spoof.rstrip(), options={'raw': True}) else: here.msg_contents(text=(escape_braces(spoof.rstrip()), {'type': 'spoof'}), options={'raw': True}) elif 'dot' in opt: # Leave leading spacing intact, remove leading dot. spoof = args.lstrip('.') if to_self: char.msg(spoof.rstrip(), options={'raw': True}) else: here.msg_contents(text=(escape_braces(spoof.rstrip()), {'type': 'spoof'}), options={'raw': True}) else: if to_self: char.msg(args.rstrip()) else: here.msg_contents(text=(escape_braces(spoof.rstrip()), {'type': 'spoof'}))