Skip to content

Commit

Permalink
bug: Fix shell completion requiring system-wide update
Browse files Browse the repository at this point in the history
- Check and remove for now old configuration from files
(in future versions we should remove this hotfix)
- Add new configuration that checks if the CLI
program is detected in the environment
  • Loading branch information
KAUTH committed Dec 28, 2023
1 parent d7626dc commit 4c4b804
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 3 deletions.
41 changes: 38 additions & 3 deletions auto_click_auto/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

from .constants import ShellType
from .exceptions import ShellEnvVarNotFoundError, ShellTypeNotSupportedError
from .utils import add_shell_configuration, create_file, detect_shell
from .utils import (
add_shell_configuration,
create_file,
detect_shell,
remove_shell_configuration,
)

if TYPE_CHECKING:
import typing_extensions as te
Expand Down Expand Up @@ -77,9 +82,24 @@ def enable_click_shell_completion(
f'eval \"$({click_env_var}={shell.value}_source '
f'{program_name})\"'
)
safe_eval_command =(
f"command -v {program_name} > /dev/null 2>&1 && "
f"{eval_command}"
)

old_config_string = (
"# Shell completion configuration for the Click Python " +
"package\n" + f"{eval_command}"
)
remove_shell_configuration(
shell_config_file=shell_config_file,
config_string=old_config_string,
verbose=verbose
)

add_shell_configuration(
shell_config_file=shell_config_file,
config_string=eval_command,
config_string=safe_eval_command,
verbose=verbose,
)

Expand All @@ -97,9 +117,24 @@ def enable_click_shell_completion(
command = (
f"{click_env_var}={shell.value}_source {program_name} | source"
)
safe_command = (
f"command -v {program_name} > /dev/null 2>&1 && "
f"{command}"
)

old_config_string = (
"# Shell completion configuration for the Click Python " +
"package\n" + f"{command}"
)
remove_shell_configuration(
shell_config_file=completer_script_path,
config_string=old_config_string,
verbose=verbose,
)

add_shell_configuration(
shell_config_file=completer_script_path,
config_string=command,
config_string=safe_command,
verbose=verbose,
)

Expand Down
81 changes: 81 additions & 0 deletions auto_click_auto/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,87 @@ def check_strings_in_file(file_path: str, search_strings: List[str]) -> bool:
)


def remove_shell_configuration(
shell_config_file: str,
config_string: str,
verbose: Optional[bool] = False
) -> None:
"""
Remove the given string from the specified shell configuration file.
This function is used to clean files from configuration added by
`auto-click-auto`.
:param shell_config_file: The shell configuration file to remove the string
from.
:param config_string: The desired configuration string to be removed. This
string will be split based on the newline characters and used to match
them in their order. The last splitted text will be searched for with and
without newline.
:param verbose: `True` to print whether the configuration is removed from
the file, `False` otherwise.
"""

delimiter = "\n"
lines_to_remove = config_string.split(delimiter)
number_lines_to_remove = len(lines_to_remove)

if number_lines_to_remove == 0:
return None

try:
strings_in_file = check_strings_in_file(
file_path=shell_config_file, search_strings=lines_to_remove
)
except ShellConfigurationFileNotFoundError as err:
if verbose is True:
print(err)

return None

# Check if any of the strings exist, independent of order, and exit early
# if not.
if strings_in_file is False:
return None

with open(shell_config_file) as file:
lines = file.readlines()

lines_to_remove_with_delimeter = [
line + delimiter for line in lines_to_remove
]
# Keep the delimeter for the last splitted part.
lines_to_remove_ends_without_delimeter = [
line + delimiter
if index < (number_lines_to_remove - 1) else line
for index, line in enumerate(lines_to_remove)
]

new_lines = [""]
i = 0

while i < len(lines):
if (
lines[i:i + number_lines_to_remove] ==
lines_to_remove_with_delimeter
or
lines[i:i + number_lines_to_remove] ==
lines_to_remove_ends_without_delimeter
):
# Skip the lines that match the sequence.
i += number_lines_to_remove
print(
"Removing old tab autocomplete configuration from " +
f"{shell_config_file} ..."
)
else:
new_lines.append(lines[i])
i += 1

if len(new_lines) > 0:
with open(shell_config_file, 'w') as file:
file.writelines(new_lines)


def add_shell_configuration(
shell_config_file: str,
config_string: str,
Expand Down

0 comments on commit 4c4b804

Please sign in to comment.