mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-06-08 00:07:45 +02:00
99 lines
3.6 KiB
Python
99 lines
3.6 KiB
Python
"""
|
|
Menu handler input and readline tab completion.
|
|
Exports: READLINE_* constants, basic_input_prompt, input_prompt, simple_path_completer, _shell_path_completer, _simple_path_completer.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import glob
|
|
|
|
from .ui_colors import COLOR_PROMPT, COLOR_RESET
|
|
|
|
READLINE_AVAILABLE = False
|
|
READLINE_HAS_PROMPT = False
|
|
READLINE_HAS_DISPLAY_HOOK = False
|
|
|
|
try:
|
|
import readline
|
|
READLINE_AVAILABLE = True
|
|
logging.debug("Readline imported for tab completion")
|
|
if hasattr(readline, 'set_prompt'):
|
|
READLINE_HAS_PROMPT = True
|
|
logging.debug("Readline has set_prompt capability")
|
|
else:
|
|
logging.debug("Readline does not have set_prompt capability, will use fallback")
|
|
try:
|
|
readline.parse_and_bind('tab: complete')
|
|
logging.debug("Readline tab completion successfully configured")
|
|
except Exception as e:
|
|
logging.warning(f"Error configuring readline tab completion: {e}. Tab completion may be limited.")
|
|
if hasattr(readline, 'set_completion_display_matches_hook'):
|
|
READLINE_HAS_DISPLAY_HOOK = True
|
|
logging.debug("Readline has completion display hook capability")
|
|
|
|
def custom_display_completions(substitution, matches, longest_match_length):
|
|
print()
|
|
try:
|
|
import shutil
|
|
term_width = shutil.get_terminal_size().columns
|
|
except (ImportError, AttributeError):
|
|
term_width = 80
|
|
items_per_line = max(1, term_width // (longest_match_length + 2))
|
|
for i, match in enumerate(matches):
|
|
print(f"{match:<{longest_match_length + 2}}", end='' if (i + 1) % items_per_line else '\n')
|
|
if len(matches) % items_per_line != 0:
|
|
print()
|
|
current_input = readline.get_line_buffer()
|
|
print(f"{COLOR_PROMPT}> {COLOR_RESET}{current_input}", end='', flush=True)
|
|
|
|
try:
|
|
readline.set_completion_display_matches_hook(custom_display_completions)
|
|
logging.debug("Custom completion display hook successfully set")
|
|
except Exception as e:
|
|
logging.warning(f"Error setting completion display hook: {e}. Using default display behavior.")
|
|
READLINE_HAS_DISPLAY_HOOK = False
|
|
else:
|
|
logging.debug("Readline doesn't have completion display hook capability, using default")
|
|
except ImportError:
|
|
logging.warning("readline not available. Tab completion for paths will be disabled.")
|
|
except Exception as e:
|
|
logging.warning(f"Error initializing readline: {e}. Tab completion for paths will be disabled.")
|
|
|
|
|
|
def basic_input_prompt(message, **kwargs):
|
|
return input(message)
|
|
|
|
|
|
input_prompt = basic_input_prompt
|
|
|
|
|
|
def _shell_path_completer(text, state):
|
|
"""Shell-like pathname completer for readline. Expands ~, handles absolute/relative paths."""
|
|
expanded = os.path.expanduser(os.path.expandvars(text))
|
|
if os.path.isdir(expanded):
|
|
pattern = os.path.join(expanded, '*')
|
|
else:
|
|
pattern = expanded + '*'
|
|
matches = glob.glob(pattern)
|
|
matches = [m + ('/' if os.path.isdir(m) else '') for m in matches]
|
|
if not text:
|
|
matches = glob.glob('*')
|
|
matches = [m + ('/' if os.path.isdir(m) else '') for m in matches]
|
|
try:
|
|
return matches[state]
|
|
except IndexError:
|
|
return None
|
|
|
|
|
|
def _simple_path_completer(text, state):
|
|
"""Simple pathname completer for readline. Prefix matching on path components."""
|
|
matches = glob.glob(text + '*')
|
|
matches = [f + ('/' if os.path.isdir(f) else '') for f in matches]
|
|
try:
|
|
return matches[state]
|
|
except IndexError:
|
|
return None
|
|
|
|
|
|
simple_path_completer = _simple_path_completer
|