Merge branch 'CmdHelp_clickable_topics' of https://github.com/davewiththenicehat/evennia into davewiththenicehat-CmdHelp_clickable_topics

This commit is contained in:
Griatch 2021-06-20 11:09:48 +02:00
commit 16667f1372
3 changed files with 75 additions and 31 deletions

View file

@ -28,6 +28,7 @@ from evennia.help.utils import help_search_with_index, parse_entry_for_subcatego
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS) COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED
DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
HELP_CLICKABLE_TOPICS = settings.HELP_CLICKABLE_TOPICS
# limit symbol import for API # limit symbol import for API
__all__ = ("CmdHelp", "CmdSetHelp") __all__ = ("CmdHelp", "CmdSetHelp")
@ -97,6 +98,9 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
# separator between subtopics: # separator between subtopics:
subtopic_separator_char = r"/" subtopic_separator_char = r"/"
# should topics disply their help entry when clicked
clickable_topics = HELP_CLICKABLE_TOPICS
def msg_help(self, text): def msg_help(self, text):
""" """
messages text to the caller, adding an extra oob argument to indicate messages text to the caller, adding an extra oob argument to indicate
@ -121,21 +125,22 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
self.msg(text=(text, {"type": "help"})) self.msg(text=(text, {"type": "help"}))
def format_help_entry(self, topic="", help_text="", aliases=None, suggested=None, def format_help_entry(self, topic="", help_text="", aliases=None, suggested=None,
subtopics=None): subtopics=None, click_topics=True):
""" """This visually formats the help entry.
This visually formats the help entry.
This method can be overriden to customize the way a help This method can be overriden to customize the way a help
entry is displayed. entry is displayed.
Args: Args:
title (str): The title of the help entry. title (str, optional): The title of the help entry.
help_text (str): Text of the help entry. help_text (str, optional): Text of the help entry.
aliases (list): List of help-aliases (displayed in header). aliases (list, optional): List of help-aliases (displayed in header).
suggested (list): Strings suggested reading (based on title). suggested (list, optional): Strings suggested reading (based on title).
subtopics (list): A list of strings - the subcategories available subtopics (list, optional): A list of strings - the subcategories available
for this entry. for this entry.
click_topics (bool, optional): Should help topics be clickable. Default is True.
Returns the formatted string, ready to be sent. Returns:
help_message (str): Help entry formated for console.
""" """
separator = "|C" + "-" * self.client_width() + "|n" separator = "|C" + "-" * self.client_width() + "|n"
@ -153,7 +158,13 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
help_text = "\n" + dedent(help_text.strip('\n')) if help_text else "" help_text = "\n" + dedent(help_text.strip('\n')) if help_text else ""
if subtopics: if subtopics:
subtopics = [f"|w{topic}/{subtop}|n" for subtop in subtopics] if click_topics:
subtopics = [
f"|lchelp {topic}/{subtop}|lt|w{topic}/{subtop}|n|le"
for subtop in subtopics
]
else:
subtopics = [f"|w{topic}/{subtop}|n" for subtop in subtopics]
subtopics = ( subtopics = (
"\n|CSubtopics:|n\n {}".format( "\n|CSubtopics:|n\n {}".format(
"\n ".join(format_grid(subtopics, width=self.client_width()))) "\n ".join(format_grid(subtopics, width=self.client_width())))
@ -162,7 +173,10 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
subtopics = '' subtopics = ''
if suggested: if suggested:
suggested = [f"|w{sug}|n" for sug in suggested] if click_topics:
suggested = [f"|lchelp {sug}|lt|w{sug}|n|le" for sug in suggested]
else:
suggested = [f"|w{sug}|n" for sug in suggested]
suggested = ( suggested = (
"\n|COther topic suggestions:|n\n{}".format( "\n|COther topic suggestions:|n\n{}".format(
"\n ".join(format_grid(suggested, width=self.client_width()))) "\n ".join(format_grid(suggested, width=self.client_width())))
@ -176,9 +190,9 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
return "\n".join(part.rstrip() for part in partorder if part) return "\n".join(part.rstrip() for part in partorder if part)
def format_help_index(self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False): def format_help_index(self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False,
""" click_topics=True):
Output a category-ordered g for displaying the main help, grouped by """Output a category-ordered g for displaying the main help, grouped by
category. category.
Args: Args:
@ -190,14 +204,15 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
be titled with the category name or not. While pointless in a be titled with the category name or not. While pointless in a
general index, the title should probably show when explicitly general index, the title should probably show when explicitly
listing the category itself. listing the category itself.
click_topics (bool, optional): Should help topics be clickable. Default is True.
Returns: Returns:
str: The help index organized into a grid. str: The help index organized into a grid.
The input are the Notes
pre-loaded help files for commands and database-helpfiles The input are the pre-loaded help files for commands and database-helpfiles
respectively. You can override this method to return a respectively. You can override this method to return a custom display of the list of
custom display of the list of commands and topics. commands and topics.
""" """
def _group_by_category(help_dict): def _group_by_category(help_dict):
@ -207,7 +222,16 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
if len(help_dict) == 1 and not title_lone_category: if len(help_dict) == 1 and not title_lone_category:
# don't list categories if there is only one # don't list categories if there is only one
for category in help_dict: for category in help_dict:
# gather and sort the entries from the help dictionary
entries = sorted(set(help_dict.get(category, []))) entries = sorted(set(help_dict.get(category, [])))
# make the help topics clickable
if click_topics:
entries = [
f'|lchelp {entry}|lt{entry}|le' for entry in entries
]
# add the entries to the grid
grid.extend(entries) grid.extend(entries)
else: else:
# list the categories # list the categories
@ -222,7 +246,16 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
) )
verbatim_elements.append(len(grid) - 1) verbatim_elements.append(len(grid) - 1)
# gather and sort the entries from the help dictionary
entries = sorted(set(help_dict.get(category, []))) entries = sorted(set(help_dict.get(category, [])))
# make the help topics clickable
if click_topics:
entries = [
f'|lchelp {entry}|lt{entry}|le' for entry in entries
]
# add the entries to the grid
grid.extend(entries) grid.extend(entries)
return grid, verbatim_elements return grid, verbatim_elements
@ -449,6 +482,7 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
""" """
caller = self.caller caller = self.caller
query, subtopics, cmdset = self.topic, self.subtopics, self.cmdset query, subtopics, cmdset = self.topic, self.subtopics, self.cmdset
clickable_topics = self.clickable_topics
if not query: if not query:
# list all available help entries, grouped by category. We want to # list all available help entries, grouped by category. We want to
@ -470,7 +504,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
# generate the index and display # generate the index and display
output = self.format_help_index(cmd_help_by_category, output = self.format_help_index(cmd_help_by_category,
file_db_help_by_category) file_db_help_by_category,
click_topics=clickable_topics)
self.msg_help(output) self.msg_help(output)
return return
@ -526,7 +561,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
output = self.format_help_entry( output = self.format_help_entry(
topic=None, # this will give a no-match style title topic=None, # this will give a no-match style title
help_text=help_text, help_text=help_text,
suggested=suggestions suggested=suggestions,
click_topics=clickable_topics
) )
self.msg_help(output) self.msg_help(output)
@ -542,7 +578,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
if category_lower == topic.help_category] if category_lower == topic.help_category]
output = self.format_help_index({category: cmds_in_category}, output = self.format_help_index({category: cmds_in_category},
{category: topics_in_category}, {category: topics_in_category},
title_lone_category=True) title_lone_category=True,
click_topics=clickable_topics)
self.msg_help(output) self.msg_help(output)
return return
@ -596,7 +633,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
output = self.format_help_entry( output = self.format_help_entry(
topic=topic, topic=topic,
help_text=f"No help entry found for '{checked_topic}'", help_text=f"No help entry found for '{checked_topic}'",
subtopics=subtopic_index subtopics=subtopic_index,
click_topics=clickable_topics
) )
self.msg_help(output) self.msg_help(output)
return return
@ -616,7 +654,8 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
help_text=help_text, help_text=help_text,
aliases=aliases if not subtopics else None, aliases=aliases if not subtopics else None,
subtopics=subtopic_index, subtopics=subtopic_index,
suggested=suggested suggested=suggested,
click_topics=clickable_topics
) )
self.msg_help(output) self.msg_help(output)

View file

@ -614,6 +614,9 @@ DEFAULT_HELP_CATEGORY = "general"
# File-based help entries. These are modules containing dicts defining help # File-based help entries. These are modules containing dicts defining help
# entries. They can be used together with in-database entries created in-game. # entries. They can be used together with in-database entries created in-game.
FILE_HELP_ENTRY_MODULES = ["world.help_entries"] FILE_HELP_ENTRY_MODULES = ["world.help_entries"]
# if topics listed in help should be clickable
# clickable links only work on clients that support MXP
HELP_CLICKABLE_TOPICS = False
###################################################################### ######################################################################
# FuncParser # FuncParser

View file

@ -1856,12 +1856,14 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
be inserted into the grid at the correct position and may be surrounded be inserted into the grid at the correct position and may be surrounded
by padding unless filling the entire line. This is useful for embedding by padding unless filling the entire line. This is useful for embedding
decorations in the grid, such as horizontal bars. decorations in the grid, such as horizontal bars.
ignore_ansi (bool, optional): Ignore ansi markups when calculating white spacing.
Returns: Returns:
list: The grid as a list of ready-formatted rows. We return it list: The grid as a list of ready-formatted rows. We return it
like this to make it easier to insert decorations between rows, such like this to make it easier to insert decorations between rows, such
as horizontal bars. as horizontal bars.
""" """
def _minimal_rows(elements): def _minimal_rows(elements):
""" """
Minimalistic distribution with minimal spacing, good for single-line Minimalistic distribution with minimal spacing, good for single-line
@ -1869,8 +1871,8 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
""" """
rows = [""] rows = [""]
for element in elements: for element in elements:
rowlen = len(rows[-1]) rowlen = display_len((rows[-1]))
elen = len(element) elen = display_len((element))
if rowlen + elen <= width: if rowlen + elen <= width:
rows[-1] += element rows[-1] += element
else: else:
@ -1882,8 +1884,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
Dynamic-space, good for making even columns in a multi-line grid but Dynamic-space, good for making even columns in a multi-line grid but
will look strange for a single line. will look strange for a single line.
""" """
wls = [display_len((elem)) for elem in elements]
wls = [len(elem) for elem in elements]
wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements] wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements]
if wls_percentile: if wls_percentile:
@ -1898,7 +1899,8 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
# one line per row, output directly since this is trivial # one line per row, output directly since this is trivial
# we use rstrip here to remove extra spaces added by sep # we use rstrip here to remove extra spaces added by sep
return [ return [
crop(element.rstrip(), width) + " " * max(0, width - len(element.rstrip())) crop(element.rstrip(), width) + " " \
* max(0, width - display_len((element.rstrip())))
for iel, element in enumerate(elements) for iel, element in enumerate(elements)
] ]
@ -1910,7 +1912,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
for ie, element in enumerate(elements): for ie, element in enumerate(elements):
wl = wls[ie] wl = wls[ie]
lrow = len(row) lrow = display_len((row))
# debug = row.replace(" ", ".") # debug = row.replace(" ", ".")
if lrow + wl > width: if lrow + wl > width:
@ -1949,7 +1951,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
if ie >= nelements - 1: if ie >= nelements - 1:
# last element, make sure to store # last element, make sure to store
row += " " * max(0, width - len(row)) row += " " * max(0, width - display_len((row)))
rows.append(row) rows.append(row)
return rows return rows
@ -1962,7 +1964,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
# add sep to all but the very last element # add sep to all but the very last element
elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]] elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]]
if sum(len(element) for element in elements) <= width: if sum(display_len((element)) for element in elements) <= width:
# grid fits in one line # grid fits in one line
return _minimal_rows(elements) return _minimal_rows(elements)
else: else: