mirror of
https://github.com/evennia/evennia.git
synced 2026-03-24 08:46:31 +01:00
764 lines
26 KiB
Python
764 lines
26 KiB
Python
"""
|
|
The help command. The basic idea is that help texts for commands
|
|
are best written by those that write the commands - the admins. So
|
|
command-help is all auto-loaded and searched from the current command
|
|
set. The normal, database-tied help system is used for collaborative
|
|
creation of other help topics such as RP help or game-world aides.
|
|
"""
|
|
|
|
import re
|
|
from django.conf import settings
|
|
from collections import defaultdict
|
|
from evennia.utils.utils import fill, dedent
|
|
from evennia.commands.command import Command
|
|
from evennia.help.models import HelpEntry
|
|
from evennia.utils import create, evmore
|
|
from evennia.utils.ansi import ANSIString
|
|
from evennia.utils.eveditor import EvEditor
|
|
from evennia.utils.utils import (
|
|
string_suggestions,
|
|
class_from_module,
|
|
inherits_from,
|
|
format_grid,
|
|
)
|
|
|
|
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
|
HELP_MORE = settings.HELP_MORE
|
|
CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
|
|
|
|
_RE_HELP_SUBTOPICS_START = re.compile(
|
|
r"^\s*?#\s*?help[- ]subtopics\s*?$", re.I + re.M)
|
|
_RE_HELP_SUBTOPIC_SPLIT = re.compile(r"^\s*?(\#{2,6}\s*?\w+?)$", re.M)
|
|
_RE_HELP_SUBTOPIC_PARSE = re.compile(
|
|
r"^(?P<nesting>\#{2,6})\s*?(?P<name>.*?)$", re.I + re.M)
|
|
|
|
# limit symbol import for API
|
|
__all__ = ("CmdHelp", "CmdSetHelp")
|
|
_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
|
|
_SEP = "|C" + "-" * _DEFAULT_WIDTH + "|n"
|
|
|
|
_LUNR = None
|
|
_LUNR_EXCEPTION = None
|
|
|
|
|
|
class HelpCategory:
|
|
def __init__(self, key):
|
|
self.key = key
|
|
|
|
@property
|
|
def search_index_entry(self):
|
|
return {
|
|
"key": str(self),
|
|
"aliases": "",
|
|
"category": self.key,
|
|
"tags": "",
|
|
"text": "",
|
|
}
|
|
|
|
def __str__(self):
|
|
return f"Category: {self.key}"
|
|
|
|
def __eq__(self, other):
|
|
return str(self).lower() == str(other).lower()
|
|
|
|
def __hash__(self):
|
|
return id(self)
|
|
|
|
|
|
def help_search_with_index(query, candidate_entries, suggestion_maxnum=5):
|
|
"""
|
|
Lunr-powered fast index search and suggestion wrapper
|
|
"""
|
|
global _LUNR, _LUNR_EXCEPTION
|
|
if not _LUNR:
|
|
# we have to delay-load lunr because it messes with logging if it's imported
|
|
# before twisted's logging has been set up
|
|
from lunr import lunr as _LUNR
|
|
from lunr.exceptions import QueryParseError as _LUNR_EXCEPTION
|
|
|
|
indx = [cnd.search_index_entry for cnd in candidate_entries]
|
|
mapping = {indx[ix]["key"]: cand for ix, cand in enumerate(candidate_entries)}
|
|
|
|
search_index = _LUNR(
|
|
ref="key",
|
|
fields=[
|
|
{"field_name": "key", "boost": 10},
|
|
{"field_name": "aliases", "boost": 9},
|
|
{"field_name": "category", "boost": 8},
|
|
{"field_name": "tags", "boost": 5},
|
|
{"field_name": "text", "boost": 1},
|
|
],
|
|
documents=indx,
|
|
)
|
|
try:
|
|
matches = search_index.search(query)[:suggestion_maxnum]
|
|
except _LUNR_EXCEPTION:
|
|
# this is a user-input problem
|
|
matches = []
|
|
|
|
# matches (objs), suggestions (strs)
|
|
return (
|
|
[mapping[match["ref"]] for match in matches],
|
|
[str(match["ref"]) for match in matches], # + f" (score {match['score']})") # good debug
|
|
)
|
|
|
|
|
|
def parse_entry_for_subcategories(entry):
|
|
"""
|
|
Parse a command docstring for special sub-category blocks:
|
|
|
|
Args:
|
|
entry (str): A help entry to parse
|
|
|
|
Returns:
|
|
dict: The dict is a mapping that splits the entry into subcategories. This
|
|
will always hold a key `None` for the main help entry and
|
|
zero or more keys holding the subcategories. Each is itself
|
|
a dict with a key `None` for the main text of that subcategory
|
|
followed by any sub-sub-categories down to a max-depth of 5.
|
|
|
|
Example:
|
|
::
|
|
|
|
'''
|
|
Main topic text
|
|
|
|
# HELP-SUBCATEGORIES
|
|
|
|
## foo
|
|
|
|
A subcategory of the main entry, accessible as `help topic foo`
|
|
(or using /, like `help topic/foo`)
|
|
|
|
## bar
|
|
|
|
Another subcategory, accessed as `help topic bar`
|
|
(or `help topic/bar`)
|
|
|
|
### moo
|
|
|
|
A subcategory of bar, accessed as `help bar moo`
|
|
(or `help bar/moo`)
|
|
|
|
#### dum
|
|
|
|
A subcategory of moo, accessed `help bar moo dum`
|
|
(or `help bar/moo/dum`)
|
|
|
|
'''
|
|
|
|
This will result in this returned entry structure:
|
|
::
|
|
|
|
{
|
|
None: "Main topic text":
|
|
"foo": {
|
|
None: "main topic/foo text"
|
|
},
|
|
"bar": {
|
|
None: "Main topic/bar text",
|
|
"moo": {
|
|
None: "topic/bar/moo text"
|
|
"dum": {
|
|
None: "topic/bar/moo/dum text"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Apart from making
|
|
sub-categories at the bottom of the entry.
|
|
|
|
This will be applied both to command docstrings and database-based help
|
|
entries.
|
|
|
|
"""
|
|
topic, *subtopics = _RE_HELP_SUBTOPICS_START.split(entry, maxsplit=1)
|
|
structure = {None: topic.strip()}
|
|
subtopics_index = []
|
|
|
|
if subtopics:
|
|
subctopics = subtopics[0]
|
|
else:
|
|
return structure
|
|
|
|
keypath = []
|
|
current_nesting = 0
|
|
subtopic = None
|
|
|
|
for part in _RE_HELP_SUBTOPIC_SPLIT.split(subtopics):
|
|
subtopic_match = _RE_HELP_SUBTOPIC_PARSE.match(part)
|
|
if subtopic_match:
|
|
# a new sub(-sub..) category starts.
|
|
mdict = subtopic_match.groupdict()
|
|
subtopic = mdict['name'].strip()
|
|
subtopic_index.append(subtopic)
|
|
new_nesting = len(mdict['nesting']) - 1
|
|
nestdiff = new_nesting - current_nesting
|
|
if nestdiff < 0:
|
|
# jumping back up in nesting
|
|
for _ in range(abs(nestdiff) + 1):
|
|
try:
|
|
keypath.pop()
|
|
except IndexError:
|
|
pass
|
|
keypath.append(subtopic)
|
|
current_nesting = new_nesting
|
|
else:
|
|
# an entry belonging to a subtopic - find the nested location
|
|
dct = structure
|
|
if not keypath and subtopic is not None:
|
|
structure[subtopic] = part.strip()
|
|
else:
|
|
for key in keypath:
|
|
if key in dct:
|
|
dct = dct[key]
|
|
else:
|
|
dct[key] = {
|
|
None: part.strip()
|
|
}
|
|
return structure, subtopic_index
|
|
|
|
|
|
class CmdHelp(COMMAND_DEFAULT_CLASS):
|
|
"""
|
|
View help or a list of topics
|
|
|
|
Usage:
|
|
help
|
|
help <topic, command or category>
|
|
help <topic> / <subtopic>
|
|
help <topic> / <subtopic> / <subsubtopic> ...
|
|
|
|
Use the help command alone to see an index of all help topics, organized by
|
|
category. Some long topics may offer additional sub-topics.
|
|
|
|
"""
|
|
|
|
key = "help"
|
|
aliases = ["?"]
|
|
locks = "cmd:all()"
|
|
arg_regex = r"\s|$"
|
|
|
|
# this is a special cmdhandler flag that makes the cmdhandler also pack
|
|
# the current cmdset with the call to self.func().
|
|
return_cmdset = True
|
|
|
|
# Help messages are wrapped in an EvMore call (unless using the webclient
|
|
# with separate help popups) If you want to avoid this, simply add
|
|
# 'HELP_MORE = False' in your settings/conf/settings.py
|
|
help_more = HELP_MORE
|
|
|
|
# suggestion cutoff, between 0 and 1 (1 => perfect match)
|
|
suggestion_cutoff = 0.6
|
|
|
|
# number of suggestions (set to 0 to remove suggestions from help)
|
|
suggestion_maxnum = 5
|
|
|
|
# separator between subtopics:
|
|
subtopic_separator_char = r"/"
|
|
|
|
def msg_help(self, text):
|
|
"""
|
|
messages text to the caller, adding an extra oob argument to indicate
|
|
that this is a help command result and could be rendered in a separate
|
|
help window
|
|
"""
|
|
if type(self).help_more:
|
|
usemore = True
|
|
|
|
if self.session and self.session.protocol_key in ("websocket", "ajax/comet",):
|
|
try:
|
|
options = self.account.db._saved_webclient_options
|
|
if options and options["helppopup"]:
|
|
usemore = False
|
|
except KeyError:
|
|
pass
|
|
|
|
if usemore:
|
|
evmore.msg(self.caller, text, session=self.session)
|
|
return
|
|
|
|
self.msg(text=(text, {"type": "help"}))
|
|
|
|
@staticmethod
|
|
def format_help_entry(topic="", help_text="", aliases=None, suggested=None,
|
|
subtopics=None):
|
|
"""
|
|
This visually formats the help entry.
|
|
This method can be overriden to customize the way a help
|
|
entry is displayed.
|
|
|
|
Args:
|
|
title (str): The title of the help entry.
|
|
help_text (str): Text of the help entry.
|
|
aliases (list): List of help-aliases (displayed in header).
|
|
suggested (list): Strings suggested reading (based on title).
|
|
subtopics (list): A list of strings - the subcategories to this entry.
|
|
|
|
Returns the formatted string, ready to be sent.
|
|
|
|
"""
|
|
start = f"{_SEP}\n"
|
|
title = f"|CHelp for |w{topic}|n" if topic else ""
|
|
aliases = (
|
|
" |C(aliases: {}|C)|n".format("|C,|n ".join(f"|w{ali}|n" for ali in aliases))
|
|
if aliases else ""
|
|
)
|
|
help_text = (
|
|
f"\n{dedent(help_text.rstrip())}" if help_text else ""
|
|
)
|
|
subtopics = (
|
|
"\nSubtopics (read with |whelp {} / subtopic): {}".format(
|
|
topic, "|C,|n ".join(f"|w{subtop}|n" for subtop in subtopics)
|
|
if subtopics else ""
|
|
)
|
|
)
|
|
suggested = (
|
|
"\n\n|CSuggested:|n {}".format(
|
|
fill("|C,|n ".join(f"|w{sug}|n" for sug in suggested))
|
|
)
|
|
if suggested else ""
|
|
)
|
|
end = f"\n{_SEP}"
|
|
|
|
return "".join((start, title, aliases, help_text, subtopics, suggested, end))
|
|
|
|
def format_help_index(self, cmd_help_dict=None, db_help_dict=None):
|
|
"""
|
|
Output a category-ordered g for displaying the main help, grouped by
|
|
category.
|
|
|
|
Args:
|
|
cmd_help_dict (dict): A dict `{"category": [topic, topic, ...]}` for
|
|
command-based help.
|
|
db_help_dict (dict): A dict `{"category": [topic, topic], ...]}` for
|
|
database-based help.
|
|
|
|
Returns:
|
|
str: The help index organized into a grid.
|
|
|
|
The input are the
|
|
pre-loaded help files for commands and database-helpfiles
|
|
respectively. You can override this method to return a
|
|
custom display of the list of commands and topics.
|
|
|
|
"""
|
|
category_clr = "|w"
|
|
topic_clr = "|G"
|
|
width = self.client_width()
|
|
grid = []
|
|
verbatim_elements = []
|
|
for category in sorted(set(list(cmd_help_dict.keys()) + list(db_help_dict.keys()))):
|
|
|
|
category_str = f"-- {category.title()} "
|
|
grid.append(
|
|
ANSIString(
|
|
category_clr + category_str + "-" * (width - len(category_str)) + topic_clr
|
|
)
|
|
)
|
|
verbatim_elements.append(len(grid) - 1)
|
|
|
|
entries = sorted(set(cmd_help_dict.get(category, []) + db_help_dict.get(category, [])))
|
|
grid.extend(entries)
|
|
|
|
gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements)
|
|
gridrows = ANSIString("\n").join(gridrows)
|
|
return gridrows
|
|
|
|
def check_show_help(self, cmd, caller):
|
|
"""
|
|
Helper method. If this return True, the given cmd
|
|
auto-help will be viewable in the help listing.
|
|
Override this to easily select what is shown to
|
|
the account. Note that only commands available
|
|
in the caller's merged cmdset are available.
|
|
|
|
Args:
|
|
cmd (Command): Command class from the merged cmdset
|
|
caller (Character, Account or Session): The current caller
|
|
executing the help command.
|
|
|
|
"""
|
|
# return only those with auto_help set and passing the cmd: lock
|
|
return cmd.auto_help and cmd.access(caller)
|
|
|
|
def should_list_cmd(self, cmd, caller):
|
|
"""
|
|
Should the specified command appear in the help table?
|
|
|
|
This method only checks whether a specified command should
|
|
appear in the table of topics/commands. The command can be
|
|
used by the caller (see the 'check_show_help' method) and
|
|
the command will still be available, for instance, if a
|
|
character type 'help name of the command'. However, if
|
|
you return False, the specified command will not appear in
|
|
the table. This is sometimes useful to "hide" commands in
|
|
the table, but still access them through the help system.
|
|
|
|
Args:
|
|
cmd: the command to be tested.
|
|
caller: the caller of the help system.
|
|
|
|
Return:
|
|
True: the command should appear in the table.
|
|
False: the command shouldn't appear in the table.
|
|
|
|
"""
|
|
return True
|
|
|
|
def parse(self):
|
|
"""
|
|
input is a string containing the command or topic to match.
|
|
|
|
The allowed syntax is
|
|
::
|
|
|
|
help <topic>[/<subtopic>[/<subtopic>[/...]]]
|
|
|
|
The database/command query is always for `<topic>`, and any subtopics
|
|
is then parsed from there. If a `<topic>` has spaces in it, it is
|
|
always matched before assuming the space begins a subtopic.
|
|
|
|
"""
|
|
# parse the query
|
|
|
|
if self.args:
|
|
self.subtopics = [part.strip().lower()
|
|
for part in self.args.split(self.subtopic_separator_char)]
|
|
self.topic = self.subtopics.pop(0)
|
|
else:
|
|
self.topic = ""
|
|
self.subtopics = []
|
|
|
|
def func(self):
|
|
"""
|
|
Run the dynamic help entry creator.
|
|
"""
|
|
caller = self.caller
|
|
query, subtopics, cmdset = self.topic, self.subtopics, self.cmdset
|
|
suggestion_cutoff = self.suggestion_cutoff
|
|
suggestion_maxnum = self.suggestion_maxnum
|
|
|
|
# removing doublets in cmdset, caused by cmdhandler
|
|
# having to allow doublet commands to manage exits etc.
|
|
cmdset.make_unique(caller)
|
|
|
|
# retrieve all available commands and database topics
|
|
all_cmds = [cmd for cmd in cmdset if self.check_show_help(cmd, caller)]
|
|
all_db_topics = [
|
|
topic for topic in HelpEntry.objects.all() if topic.access(caller, "view", default=True)
|
|
]
|
|
all_categories = list(set(
|
|
[HelpCategory(cmd.help_category) for cmd in all_cmds]
|
|
+ [HelpCategory(topic.help_category) for topic in all_db_topics]
|
|
)
|
|
)
|
|
|
|
if not query:
|
|
# list all available help entries, grouped by category. We want to
|
|
# build dictionaries {category: [topic, topic, ...], ...}
|
|
cmd_help_dict = defaultdict(list)
|
|
db_help_dict = defaultdict(list)
|
|
|
|
# Filter commands that should be reached by the help
|
|
# system, but not be displayed in the table, or be displayed differently.
|
|
for cmd in all_cmds:
|
|
if self.should_list_cmd(cmd, caller):
|
|
key = (cmd.auto_help_display_key
|
|
if hasattr(cmd, "auto_help_display_key") else cmd.key)
|
|
cmd_help_dict[cmd.help_category].append(key)
|
|
|
|
for db_topic in all_db_topics:
|
|
db_help_dict[db_topic.help_category].append(db_topic.key)
|
|
|
|
output = self.format_help_index(cmd_help_dict, db_help_dict)
|
|
self.msg_help(output)
|
|
|
|
return
|
|
|
|
# We have a query - try to find a specific topic/category using the
|
|
# Lunr search engine
|
|
|
|
# all available options
|
|
entries = [cmd for cmd in all_cmds if cmd] + list(HelpEntry.objects.all()) + all_categories
|
|
match, suggestions = None, None
|
|
|
|
for match_query in [f"{query}~1", f"{query}*"]:
|
|
# We first do an exact word-match followed by a start-by query
|
|
# the return of this will either be a HelpCategory, a Command or a HelpEntry.
|
|
matches, suggestions = help_search_with_index(
|
|
match_query, entries, suggestion_maxnum=self.suggestion_maxnum
|
|
)
|
|
if matches:
|
|
match = matches[0]
|
|
break
|
|
|
|
if not match:
|
|
# no exact matches found. Just give suggestions.
|
|
output = self.format_help_entry(
|
|
topic="",
|
|
help_text=f"No help entry found for '{query}'",
|
|
suggested=suggestions
|
|
)
|
|
self.msg_help(output)
|
|
return
|
|
|
|
if isinstance(match, HelpCategory):
|
|
# no subtopics for categories - these are just lists of topics
|
|
output = self.format_help_index(
|
|
{
|
|
match.key: [
|
|
cmd.key
|
|
for cmd in all_cmds
|
|
if match.key.lower() == cmd.help_category
|
|
]
|
|
},
|
|
{
|
|
match.key: [
|
|
topic.key
|
|
for topic in all_topics
|
|
if match.key.lower() == topic.help_category
|
|
]
|
|
},
|
|
)
|
|
self.msg_help(output)
|
|
return
|
|
|
|
if inherits_from(match, "evennia.commands.command.Command"):
|
|
# a command match
|
|
topic = match.key
|
|
help_text = match.get_help(caller, cmdset)
|
|
aliases = match.aliases,
|
|
suggested=suggestions[1:]
|
|
else:
|
|
# a database match
|
|
topic = match.key
|
|
help_text = match.entrytext
|
|
aliases = match.aliases.all()
|
|
suggested = suggestions[1:]
|
|
|
|
# parse for subtopics. The subtopic_map is a dict with the current topic/subtopic
|
|
# text is stored under a `None` key and all other keys are subtopic titles pointing
|
|
# to nested dicts.
|
|
|
|
subtopic_map = parse_entry_for_subcategories(help_text)
|
|
help_text = subtopic_map[None]
|
|
subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None]
|
|
|
|
if subtopics:
|
|
# if we asked for subtopics, parse the found topic_text to see if any match.
|
|
# the subtopics is a list describing the path through the subtopic_map.
|
|
for subtopic_query in subtopics:
|
|
subtopic_query_lower = subtopic_query.lower()
|
|
checked_topic = topic + f" / {subtopic_query.lower().capitalize()}"
|
|
subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None]
|
|
if subtopic_query_lower() in subtopic_index:
|
|
# keep stepping down into the tree
|
|
subtopic_map = subtopic_map.pop(subtopic_query)
|
|
topic = checked_topic
|
|
else:
|
|
output = self.format_help_entry(
|
|
topic=topic,
|
|
help_text=f"No help entry found for '{checked_topic}'",
|
|
subtopics=subtopic_index
|
|
)
|
|
self.msg_help(output)
|
|
return
|
|
# we reached the bottom of the topic tree
|
|
help_text = subtopic_map[None]
|
|
|
|
output = self.format_help_entry(
|
|
topic=topic,
|
|
help_text=help_text,
|
|
aliases=aliases if not subtopics else None,
|
|
subtopics=subtopic_index
|
|
)
|
|
|
|
self.msg_help(output)
|
|
|
|
|
|
def _loadhelp(caller):
|
|
entry = caller.db._editing_help
|
|
if entry:
|
|
return entry.entrytext
|
|
else:
|
|
return ""
|
|
|
|
|
|
def _savehelp(caller, buffer):
|
|
entry = caller.db._editing_help
|
|
caller.msg("Saved help entry.")
|
|
if entry:
|
|
entry.entrytext = buffer
|
|
|
|
|
|
def _quithelp(caller):
|
|
caller.msg("Closing the editor.")
|
|
del caller.db._editing_help
|
|
|
|
|
|
class CmdSetHelp(COMMAND_DEFAULT_CLASS):
|
|
"""
|
|
Edit the help database.
|
|
|
|
Usage:
|
|
help[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]
|
|
|
|
Switches:
|
|
edit - open a line editor to edit the topic's help text.
|
|
replace - overwrite existing help topic.
|
|
append - add text to the end of existing topic with a newline between.
|
|
extend - as append, but don't add a newline.
|
|
delete - remove help topic.
|
|
|
|
Examples:
|
|
sethelp throw = This throws something at ...
|
|
sethelp/append pickpocketing,Thievery = This steals ...
|
|
sethelp/replace pickpocketing, ,attr(is_thief) = This steals ...
|
|
sethelp/edit thievery
|
|
|
|
This command manipulates the help database. A help entry can be created,
|
|
appended/merged to and deleted. If you don't assign a category, the
|
|
"General" category will be used. If no lockstring is specified, default
|
|
is to let everyone read the help file.
|
|
|
|
"""
|
|
|
|
key = "sethelp"
|
|
switch_options = ("edit", "replace", "append", "extend", "delete")
|
|
locks = "cmd:perm(Helper)"
|
|
help_category = "Building"
|
|
|
|
def func(self):
|
|
"""Implement the function"""
|
|
|
|
switches = self.switches
|
|
lhslist = self.lhslist
|
|
|
|
if not self.args:
|
|
self.msg(
|
|
"Usage: sethelp[/switches] <topic>[;alias;alias][,category[,locks,..] = <text>"
|
|
)
|
|
return
|
|
|
|
nlist = len(lhslist)
|
|
topicstr = lhslist[0] if nlist > 0 else ""
|
|
if not topicstr:
|
|
self.msg("You have to define a topic!")
|
|
return
|
|
topicstrlist = topicstr.split(";")
|
|
topicstr, aliases = (
|
|
topicstrlist[0],
|
|
topicstrlist[1:] if len(topicstr) > 1 else [],
|
|
)
|
|
aliastxt = ("(aliases: %s)" % ", ".join(aliases)) if aliases else ""
|
|
old_entry = None
|
|
|
|
# check if we have an old entry with the same name
|
|
try:
|
|
for querystr in topicstrlist:
|
|
old_entry = HelpEntry.objects.find_topicmatch(querystr) # also search by alias
|
|
if old_entry:
|
|
old_entry = list(old_entry)[0]
|
|
break
|
|
category = lhslist[1] if nlist > 1 else old_entry.help_category
|
|
lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get()
|
|
except Exception:
|
|
old_entry = None
|
|
category = lhslist[1] if nlist > 1 else "General"
|
|
lockstring = ",".join(lhslist[2:]) if nlist > 2 else "view:all()"
|
|
category = category.lower()
|
|
|
|
if "edit" in switches:
|
|
# open the line editor to edit the helptext. No = is needed.
|
|
if old_entry:
|
|
topicstr = old_entry.key
|
|
if self.rhs:
|
|
# we assume append here.
|
|
old_entry.entrytext += "\n%s" % self.rhs
|
|
helpentry = old_entry
|
|
else:
|
|
helpentry = create.create_help_entry(
|
|
topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases,
|
|
)
|
|
self.caller.db._editing_help = helpentry
|
|
|
|
EvEditor(
|
|
self.caller,
|
|
loadfunc=_loadhelp,
|
|
savefunc=_savehelp,
|
|
quitfunc=_quithelp,
|
|
key="topic {}".format(topicstr),
|
|
persistent=True,
|
|
)
|
|
return
|
|
|
|
if "append" in switches or "merge" in switches or "extend" in switches:
|
|
# merge/append operations
|
|
if not old_entry:
|
|
self.msg("Could not find topic '%s'. You must give an exact name." % topicstr)
|
|
return
|
|
if not self.rhs:
|
|
self.msg("You must supply text to append/merge.")
|
|
return
|
|
if "merge" in switches:
|
|
old_entry.entrytext += " " + self.rhs
|
|
else:
|
|
old_entry.entrytext += "\n%s" % self.rhs
|
|
old_entry.aliases.add(aliases)
|
|
self.msg("Entry updated:\n%s%s" % (old_entry.entrytext, aliastxt))
|
|
return
|
|
if "delete" in switches or "del" in switches:
|
|
# delete the help entry
|
|
if not old_entry:
|
|
self.msg("Could not find topic '%s'%s." % (topicstr, aliastxt))
|
|
return
|
|
old_entry.delete()
|
|
self.msg("Deleted help entry '%s'%s." % (topicstr, aliastxt))
|
|
return
|
|
|
|
# at this point it means we want to add a new help entry.
|
|
if not self.rhs:
|
|
self.msg("You must supply a help text to add.")
|
|
return
|
|
if old_entry:
|
|
if "replace" in switches:
|
|
# overwrite old entry
|
|
old_entry.key = topicstr
|
|
old_entry.entrytext = self.rhs
|
|
old_entry.help_category = category
|
|
old_entry.locks.clear()
|
|
old_entry.locks.add(lockstring)
|
|
old_entry.aliases.add(aliases)
|
|
old_entry.save()
|
|
self.msg("Overwrote the old topic '%s'%s." % (topicstr, aliastxt))
|
|
else:
|
|
self.msg(
|
|
"Topic '%s'%s already exists. Use /replace to overwrite "
|
|
"or /append or /merge to add text to it." % (topicstr, aliastxt)
|
|
)
|
|
else:
|
|
# no old entry. Create a new one.
|
|
new_entry = create.create_help_entry(
|
|
topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases
|
|
)
|
|
if new_entry:
|
|
self.msg("Topic '%s'%s was successfully created." % (topicstr, aliastxt))
|
|
if "edit" in switches:
|
|
# open the line editor to edit the helptext
|
|
self.caller.db._editing_help = new_entry
|
|
EvEditor(
|
|
self.caller,
|
|
loadfunc=_loadhelp,
|
|
savefunc=_savehelp,
|
|
quitfunc=_quithelp,
|
|
key="topic {}".format(new_entry.key),
|
|
persistent=True,
|
|
)
|
|
return
|
|
else:
|
|
self.msg(
|
|
"Error when creating topic '%s'%s! Contact an admin." % (topicstr, aliastxt)
|
|
)
|