Skip to content

Commit

Permalink
Fix fish shell completions
Browse files Browse the repository at this point in the history
  • Loading branch information
goraje committed Nov 29, 2024
1 parent 88fcf83 commit b22f193
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 23 deletions.
41 changes: 40 additions & 1 deletion tests/test_completion/test_completion_complete.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,49 @@
import os
import subprocess
import sys
from importlib.machinery import ModuleSpec
from typing import Union
from unittest.mock import patch

import pytest
from typer._completion_classes import _sanitize_help_text

from docs_src.commands.help import tutorial001 as mod


@pytest.mark.parametrize(
"find_spec, help_text, expected",
[
(
ModuleSpec("rich", loader=None),
"help text without rich tags",
"help text without rich tags",
),
(
None,
"help text without rich tags",
"help text without rich tags",
),
(
ModuleSpec("rich", loader=None),
"help [bold]with[/] rich tags",
"help with rich tags",
),
(
None,
"help [bold]with[/] rich tags",
"help [bold]with[/] rich tags",
),
],
)
def test_sanitize_help_text(
find_spec: Union[ModuleSpec, None], help_text: str, expected: str
):
with patch("importlib.util.find_spec", return_value=find_spec) as mock_find_spec:
assert _sanitize_help_text(help_text) == expected
mock_find_spec.assert_called_once_with("rich")


def test_completion_complete_subcommand_bash():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, " "],
Expand Down Expand Up @@ -79,7 +118,7 @@ def test_completion_complete_subcommand_fish():
},
)
assert (
"delete Delete a user with USERNAME.\ndelete-all Delete ALL users in the database."
"delete\tDelete a user with USERNAME.\ndelete-all\tDelete ALL users in the database."
in result.stdout
)

Expand Down
16 changes: 13 additions & 3 deletions typer/_completion_classes.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib.util
import os
import re
import sys
Expand All @@ -21,6 +22,15 @@
shellingham = None


def _sanitize_help_text(text: str) -> str:
"""Sanitizes the help text by removing rich tags"""
if not importlib.util.find_spec("rich"):
return text
from . import rich_utils

return rich_utils.rich_render_text(text)


class BashComplete(click.shell_completion.BashComplete):
name = Shells.bash.value
source_template = COMPLETION_SCRIPT_BASH
Expand Down Expand Up @@ -93,7 +103,7 @@ def escape(s: str) -> str:
# the difference with and without escape
# return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}"
if item.help:
return f'"{escape(item.value)}":"{escape(item.help)}"'
return f'"{escape(item.value)}":"{_sanitize_help_text(escape(item.help))}"'
else:
return f'"{escape(item.value)}"'

Expand Down Expand Up @@ -139,7 +149,7 @@ def format_completion(self, item: click.shell_completion.CompletionItem) -> str:
# return f"{item.type},{item.value}
if item.help:
formatted_help = re.sub(r"\s", " ", item.help)
return f"{item.value}\t{formatted_help}"
return f"{item.value}\t{_sanitize_help_text(formatted_help)}"
else:
return f"{item.value}"

Expand Down Expand Up @@ -180,7 +190,7 @@ def get_completion_args(self) -> Tuple[List[str], str]:
return args, incomplete

def format_completion(self, item: click.shell_completion.CompletionItem) -> str:
return f"{item.value}:::{item.help or ' '}"
return f"{item.value}:::{_sanitize_help_text(item.help) if item.help else ' '}"


def completion_init() -> None:
Expand Down
14 changes: 1 addition & 13 deletions typer/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@
except ImportError: # pragma: no cover
shellingham = None

try:
import rich

except ImportError: # pragma: no cover
rich = None # type: ignore


_click_patched = False

Expand Down Expand Up @@ -147,13 +141,7 @@ def shell_complete(

# Typer override to print the completion help msg with Rich
if instruction == "complete":
if not rich: # pragma: no cover
click.echo(comp.complete())
else:
from . import rich_utils

rich_utils.print_with_rich(comp.complete())

click.echo(comp.complete())
return 0
# Typer override end

Expand Down
12 changes: 6 additions & 6 deletions typer/rich_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,12 +712,6 @@ def rich_abort_error() -> None:
console.print(ABORTED_TEXT, style=STYLE_ABORTED)


def print_with_rich(text: str) -> None:
"""Print richly formatted message."""
console = _get_rich_console()
console.print(text)


def rich_to_html(input_text: str) -> str:
"""Print the HTML version of a rich-formatted input string.
Expand All @@ -729,3 +723,9 @@ def rich_to_html(input_text: str) -> str:
console.print(input_text, overflow="ignore", crop=False)

return console.export_html(inline_styles=True, code_format="{code}").strip()


def rich_render_text(text: str) -> str:
"""Remove rich tags and render a pure text representation"""
console = _get_rich_console()
return "".join(segment.text for segment in console.render(text)).rstrip("\n")

0 comments on commit b22f193

Please sign in to comment.