Exemplo n.º 1
0
 def _print_target_help(self, target_alias: str,
                        show_advanced: bool) -> None:
     self._print_title(f"`{target_alias}` target")
     tinfo = self._all_help_info.name_to_target_type_info[target_alias]
     if tinfo.description:
         formatted_desc = "\n".join(
             hard_wrap(tinfo.description, width=self._width))
         print(formatted_desc)
     print(f"\n\nActivated by {self.maybe_magenta(tinfo.provider)}")
     print("Valid fields:")
     for field in sorted(tinfo.fields, key=lambda x:
                         (-x.required, x.alias)):
         print()
         print(self.maybe_magenta(field.alias))
         indent = "    "
         required_or_default = "required" if field.required else f"default: {field.default}"
         if field.provider not in ["", tinfo.provider]:
             print(self.maybe_cyan(f"{indent}from: {field.provider}"))
         print(self.maybe_cyan(f"{indent}type: {field.type_hint}"))
         print(self.maybe_cyan(f"{indent}{required_or_default}"))
         if field.description:
             formatted_desc = "\n".join(
                 hard_wrap(field.description,
                           indent=len(indent),
                           width=self._width))
             print("\n" + formatted_desc)
     print()
Exemplo n.º 2
0
 def add_option(ohis, *, category=None):
     lines.append("")
     goal_or_subsystem = "goal" if oshi.is_goal else "subsystem"
     display_scope = f"`{oshi.scope}` {goal_or_subsystem}" if oshi.scope else "Global"
     if category:
         title = f"{display_scope} {category} options"
         lines.append(self.maybe_green(f"{title}\n{'-' * len(title)}"))
     else:
         # The basic options section gets the description and options scope info.
         # No need to repeat those in the advanced section.
         title = f"{display_scope} options"
         lines.append(
             self.maybe_green(f"{title}\n{'-' * len(title)}\n"))
         lines.extend(hard_wrap(oshi.description, width=self._width))
         lines.append(" ")
         lines.append(
             f"Activated by {self.maybe_magenta(oshi.provider)}")
         config_section = f"[{oshi.scope or 'GLOBAL'}]"
         lines.append(
             f"Config section: {self.maybe_magenta(config_section)}")
     lines.append(" ")
     if not ohis:
         lines.append("None available.")
         return
     for ohi in ohis:
         lines.extend([*self.format_option(ohi), ""])
Exemplo n.º 3
0
 def _print_api_type_help(self, name: str, show_advanced: bool) -> None:
     self._print_title(f"`{name}` api type")
     type_info = self._all_help_info.name_to_api_type_info[name]
     print("\n".join(
         hard_wrap(type_info.documentation or "Undocumented.",
                   width=self._width)))
     print()
     self._print_table({
         "activated by":
         type_info.provider,
         "union type":
         type_info.union_type,
         "union members":
         "\n".join(type_info.union_members) if type_info.is_union else None,
         "dependencies":
         "\n".join(type_info.dependencies) if show_advanced else None,
         "dependees":
         "\n".join(type_info.dependees) if show_advanced else None,
         f"returned by {pluralize(len(type_info.returned_by_rules), 'rule')}":
         "\n".join(type_info.returned_by_rules) if show_advanced else None,
         f"consumed by {pluralize(len(type_info.consumed_by_rules), 'rule')}":
         "\n".join(type_info.consumed_by_rules) if show_advanced else None,
         f"used in {pluralize(len(type_info.used_in_rules), 'rule')}":
         "\n".join(type_info.used_in_rules) if show_advanced else None,
     })
     print()
     if not show_advanced:
         print(
             self.maybe_green(
                 f"Include API types and rules dependency information by running "
                 f"`{bin_name()} help-advanced {name}`.\n"))
Exemplo n.º 4
0
 def _print_target_help(self, target_alias: str) -> None:
     self._print_title(target_alias)
     tinfo = self._all_help_info.name_to_target_type_info[target_alias]
     if tinfo.description:
         formatted_desc = "\n".join(hard_wrap(tinfo.description))
         print(formatted_desc)
     print("\n\nValid fields:")
     for field in sorted(tinfo.fields, key=lambda x: x.alias):
         print()
         print(self.maybe_magenta(field.alias))
         indent = "    "
         required_or_default = "required" if field.required else f"default: {field.default}"
         print(self.maybe_cyan(f"{indent}type: {field.type_hint}"))
         print(self.maybe_cyan(f"{indent}{required_or_default}"))
         if field.description:
             formatted_desc = "\n".join(
                 hard_wrap(field.description, indent=len(indent)))
             print(formatted_desc)
     print()
Exemplo n.º 5
0
def test_hard_wrap() -> None:
    assert hard_wrap("Hello world!", width=6) == ["Hello", "world!"]

    # Indents play into the width.
    assert hard_wrap("Hello world!", width=6, indent=2) == ["  Hell", "  o wo", "  rld!"]
    assert hard_wrap("Hello world!", width=8, indent=2) == ["  Hello", "  world!"]

    # Preserve prior newlines.
    assert hard_wrap("- 1\n- 2\n\n") == ["- 1", "- 2", ""]
    assert hard_wrap("Hello world!\n\n- 1 some text\n- 2\n\nHola mundo!", width=6) == [
        "Hello",
        "world!",
        "",
        "- 1",
        "some",
        "text",
        "- 2",
        "",
        "Hola",
        "mundo!",
    ]
Exemplo n.º 6
0
 def _print_table(self,
                  table: Dict[str, Optional[str]],
                  indent: int = 0) -> None:
     longest_key = max(
         len(key) for key, value in table.items() if value is not None)
     for key, value in table.items():
         if value is None:
             continue
         print(
             self.maybe_cyan(f"{key:{longest_key}}:"),
             self.maybe_magenta(f"\n{' ':{longest_key+2}}".join(
                 hard_wrap(value, width=self._width - longest_key - 2))),
         )
Exemplo n.º 7
0
 def _print_api_type_help(self, output_type: str,
                          show_advanced: bool) -> None:
     self._print_title(f"`{output_type}` API type")
     rule_infos = self._all_help_info.rule_output_type_to_rule_infos[
         output_type]
     if rule_infos[0].output_desc:
         print("\n".join(
             hard_wrap(rule_infos[0].output_desc, width=self._width)))
         print()
     print(f"Returned by {pluralize(len(rule_infos), 'rule')}:")
     for rule_info in rule_infos:
         print()
         print(self.maybe_magenta(rule_info.name))
         indent = "    "
         print(self.maybe_cyan(f"{indent}activated by"), rule_info.provider)
         if rule_info.input_types:
             print(
                 self.maybe_cyan(
                     f"{indent}{pluralize(len(rule_info.input_types), 'input')}:"
                 ),
                 ", ".join(rule_info.input_types),
             )
         else:
             print(self.maybe_cyan(f"{indent}no inputs"))
         if show_advanced and rule_info.input_gets:
             print(f"\n{indent}".join(
                 hard_wrap(
                     self.maybe_cyan(
                         f"{pluralize(len(rule_info.input_gets), 'get')}: ")
                     + ", ".join(rule_info.input_gets),
                     indent=4,
                     width=self._width - 4,
                 )))
         if rule_info.description:
             print(f"{indent}{rule_info.description}")
         if rule_info.help:
             print("\n" + "\n".join(
                 hard_wrap(rule_info.help, indent=4, width=self._width)))
     print()
Exemplo n.º 8
0
 def _print_rule_help(self, rule_name: str, show_advanced: bool) -> None:
     rule = self._all_help_info.name_to_rule_info[rule_name]
     title = f"`{rule_name}` rule"
     self._print_title(title)
     if rule.description:
         print(rule.description + "\n")
     print("\n".join(
         hard_wrap(rule.documentation or "Undocumented.",
                   width=self._width)))
     print()
     self._print_table({
         "activated by":
         rule.provider,
         "returns":
         rule.output_type,
         f"takes {pluralize(len(rule.input_types), 'input')}":
         ", ".join(rule.input_types),
         f"awaits {pluralize(len(rule.input_gets), 'get')}":
         "\n".join(rule.input_gets) if show_advanced else None,
     })
     print()
Exemplo n.º 9
0
    def _print_all_api_types(self) -> None:
        self._print_title("Plugin API Types")
        api_type_descriptions: Dict[str, Tuple[str, str]] = {}
        indent_api_summary = 0
        for api_info in self._all_help_info.name_to_api_type_info.values():
            name = api_info.name
            if name.startswith("_"):
                continue
            if api_info.is_union:
                name += " <union>"
            summary = (api_info.documentation or "").split("\n", 1)[0]
            api_type_descriptions[name] = (api_info.module, summary)
            indent_api_summary = max(indent_api_summary,
                                     len(name) + 2,
                                     len(api_info.module) + 2)

        for name, (module, summary) in api_type_descriptions.items():
            name = self.maybe_cyan(name.ljust(indent_api_summary))
            description_lines = hard_wrap(summary or " ",
                                          indent=indent_api_summary,
                                          width=self._width)
            # Juggle the description lines, to inject the api type module on the second line flushed
            # left just below the type name (potentially sharing the line with the second line of
            # the description that will be aligned to the right).
            if len(description_lines) > 1:
                # Place in front of the description line.
                description_lines[
                    1] = f"{module:{indent_api_summary}}{description_lines[1][indent_api_summary:]}"
            else:
                # There is no second description line.
                description_lines.append(module)
            # All description lines are indented, but the first line should be indented by the api
            # type name, so we strip that.
            description_lines[0] = description_lines[0][indent_api_summary:]
            description = "\n".join(description_lines)
            print(f"{name}{description}\n")
        api_help_cmd = f"{bin_name()} help [api_type/rule_name]"
        print(
            f"Use `{self.maybe_green(api_help_cmd)}` to get help for a specific API type or rule.\n"
        )
Exemplo n.º 10
0
    def format_option(self, ohi: OptionHelpInfo) -> List[str]:
        """Format the help output for a single option.

        :param ohi: Extracted information for option to print
        :return: Formatted help text for this option
        """
        def maybe_parens(s: Optional[str]) -> str:
            return f" ({s})" if s else ""

        def format_value(ranked_val: RankedValue, prefix: str,
                         left_padding: str) -> List[str]:
            if isinstance(ranked_val.value, (list, dict)):
                is_enum_list = (isinstance(ranked_val.value, list)
                                and len(ranked_val.value) > 0
                                and isinstance(ranked_val.value[0], Enum))
                normalized_val = ([
                    enum_elmt.value for enum_elmt in ranked_val.value
                ] if is_enum_list else ranked_val.value)
                val_lines = json.dumps(normalized_val,
                                       sort_keys=True,
                                       indent=4).split("\n")
            else:
                val_lines = [to_help_str(ranked_val.value)]
            val_lines[0] = f"{prefix}{val_lines[0]}"
            val_lines[
                -1] = f"{val_lines[-1]}{maybe_parens(ranked_val.details)}"
            val_lines = [
                self.maybe_cyan(f"{left_padding}{line}") for line in val_lines
            ]
            return val_lines

        indent = "      "
        arg_lines = [
            f"  {self.maybe_magenta(args)}" for args in ohi.display_args
        ]
        arg_lines.append(self.maybe_magenta(f"  {ohi.env_var}"))
        arg_lines.append(self.maybe_magenta(f"  {ohi.config_key}"))
        choices = "" if ohi.choices is None else f"one of: [{', '.join(ohi.choices)}]"
        choices_lines = [
            f"{indent}{'  ' if i != 0 else ''}{self.maybe_cyan(s)}"
            for i, s in enumerate(textwrap.wrap(f"{choices}", self._width))
        ]
        default_lines = format_value(RankedValue(Rank.HARDCODED, ohi.default),
                                     "default: ", indent)
        if not ohi.value_history:
            # Should never happen, but this keeps mypy happy.
            raise ValueError("No value history - options not parsed.")
        final_val = ohi.value_history.final_value
        curr_value_lines = format_value(final_val, "current value: ", indent)

        interesting_ranked_values = [
            rv for rv in reversed(ohi.value_history.ranked_values)
            if rv.rank not in (Rank.NONE, Rank.HARDCODED, final_val.rank)
        ]
        value_derivation_lines = [
            line for rv in interesting_ranked_values
            for line in format_value(rv, "overrode: ", f"{indent}    ")
        ]
        description_lines = hard_wrap(ohi.help,
                                      indent=len(indent),
                                      width=self._width)
        lines = [
            *arg_lines,
            *choices_lines,
            *default_lines,
            *curr_value_lines,
            *value_derivation_lines,
            *description_lines,
        ]
        if ohi.deprecated_message:
            maybe_colorize = self.maybe_red if ohi.deprecation_active else self.maybe_yellow
            lines.append(maybe_colorize(f"{indent}{ohi.deprecated_message}"))
            if ohi.removal_hint:
                lines.append(maybe_colorize(f"{indent}{ohi.removal_hint}"))
        return lines
Exemplo n.º 11
0
 def wrap(s: str) -> List[str]:
     return hard_wrap(s, indent=len(indent), width=self._width)