working product

This commit is contained in:
pika 2025-04-09 21:02:36 +02:00
parent 1ee311e561
commit 903fe0392c

View file

@ -94,147 +94,193 @@ def fetch_package_data(package):
return None
def print_table(output, headers, selected_pms, args):
"""Print formatted table with consistent alignment"""
"""Print formatted table with consistent alignment or list for small terminals"""
# Terminal dimensions
terminal_width = shutil.get_terminal_size().columns
min_col_width = 10
padding = 1 # Space on each side of the column content
# Calculate initial column widths based on content
pkg_col_width = max(
len(headers[0]),
max(len(pkg) for pkg in args.packages) if args.packages else min_col_width
) + (padding * 2)
# Calculate package availability for coloring
pkg_availability = {}
for pkg in args.packages:
versions = output.get(pkg, {})
available_count = sum(1 for pm in selected_pms if versions.get(pm, 'Not found') != 'Not found')
# Allocate remaining space proportionally to other columns
remaining_width = terminal_width - pkg_col_width - (3 * len(selected_pms)) # 3 chars for " | "
version_col_width = max(min_col_width, remaining_width // len(selected_pms))
if available_count == 0:
pkg_availability[pkg] = 'red' # Not available anywhere
elif available_count == len(selected_pms):
pkg_availability[pkg] = 'green' # Available everywhere
else:
pkg_availability[pkg] = 'yellow' # Available in some places
# Define column widths
col_widths = [pkg_col_width] + [version_col_width] * len(selected_pms)
# Determine minimum required widths
min_pkg_width = max(len(pkg) for pkg in args.packages) + 2
min_pm_width = 10
min_required_width = min_pkg_width + (min_pm_width * len(selected_pms)) + (3 * len(selected_pms))
# Adjust to fit terminal if needed
while sum(col_widths) + (3 * (len(col_widths) - 1)) > terminal_width and min(col_widths) > min_col_width:
max_idx = col_widths.index(max(col_widths))
col_widths[max_idx] -= 1
# If terminal is too narrow for the table, use list format instead
if terminal_width < min_required_width and len(selected_pms) > 1:
print_list_format(output, headers, selected_pms, args, pkg_availability)
return
# Calculate total table width for separators
# Calculate column widths
padding = 1 # Space on each side of content
# Package column width
pkg_col_width = min(min_pkg_width + 4, max(min_pkg_width, terminal_width // (len(selected_pms) + 3)))
# PM column widths (divide remaining space equally)
remaining_width = terminal_width - pkg_col_width - (3 * len(selected_pms))
pm_col_width = max(min_pm_width, remaining_width // len(selected_pms))
col_widths = [pkg_col_width] + [pm_col_width] * len(selected_pms)
# Print header row
header_cells = []
for i, header in enumerate(headers):
text = header.center(col_widths[i] - (2 * padding))
cell = " " * padding + colorize(text, 'header') + " " * padding
header_cells.append(cell)
print(" | ".join(header_cells))
# Print separator line
total_width = sum(col_widths) + (3 * (len(col_widths) - 1))
# Print headers (centered)
header_row = []
for idx, header in enumerate(headers):
header_text = header.center(col_widths[idx] - (padding * 2))
padded_header = " " * padding + colorize(header_text, 'header') + " " * padding
header_row.append(padded_header.ljust(col_widths[idx]))
print(" | ".join(header_row))
# Print main separator line
print("-" * total_width)
# Process and print each package row
for pkg_index, pkg in enumerate(args.packages):
versions = output.get(pkg, {pm: 'Not found' for pm in selected_pms})
# Print each package row
for pkg_idx, pkg in enumerate(args.packages):
versions = output.get(pkg, {})
# Prepare content for each cell
cells_content = []
# First collect all data for this package
package_data = []
# Package name (first column)
cells_content.append(colorize(pkg, 'bold'))
package_data.append([colorize(pkg, pkg_availability[pkg])])
# Version information (remaining columns)
# Version data for each package manager
for pm in selected_pms:
version = versions.get(pm, 'Not found')
color = 'green' if version != 'Not found' else 'red'
if 'AUR' in version: color = 'yellow'
# Apply color to the entire string at once
cells_content.append(colorize(version, color))
# Apply wrapping to each cell based on column width
wrapped_cells = []
for idx, content in enumerate(cells_content):
# Use raw text for wrapping calculation, but keep the colored text for display
raw_text = content
if colorize.is_tty:
# Remove ANSI color codes for length calculation
raw_text = re.sub(r'\033\[\d+m', '', content)
if version == 'Not found':
package_data.append([colorize('-', 'red')])
continue
avail_width = col_widths[idx] - (padding * 2)
# Extract version number and repositories
version_parts = []
match = re.match(r'(.*?)\s+\((.*)\)$', version)
# Wrap text without color codes
wrapped_lines = textwrap.wrap(
raw_text,
width=avail_width,
break_long_words=False,
break_on_hyphens=True
) or ['']
if match:
ver_num, repos = match.groups()
version_parts.append(colorize(ver_num, 'green'))
# If we have color codes, we need to re-apply coloring to each wrapped line
if colorize.is_tty:
color = None
if idx == 0: # Package name
color = 'bold'
else: # Version info
if 'Not found' in raw_text:
color = 'red'
elif 'AUR' in raw_text:
color = 'yellow'
else:
color = 'green'
# Format repositories
repo_lines = []
repo_text = "(" + repos + ")"
# Apply the same color to each wrapped line
wrapped_lines = [colorize(line, color) for line in wrapped_lines]
wrapped_cells.append(wrapped_lines)
# Determine how many lines this row needs
max_lines = max(len(cell) for cell in wrapped_cells)
# Print each line of the row
for line_idx in range(max_lines):
row_parts = []
for col_idx, cell_lines in enumerate(wrapped_cells):
if line_idx < len(cell_lines):
content = cell_lines[line_idx]
if line_idx > 0: # For continuation lines
# Indent continuation lines for better readability
# We can't simply add characters to colored text, need to handle differently
if colorize.is_tty:
# Need to extract the color codes and apply them after indent
plain_content = re.sub(r'\033\[\d+m', '', content)
color_prefix = content[:content.find(plain_content)]
color_suffix = COLORS['reset']
content = color_prefix + " " + plain_content + color_suffix
else:
content = " " + content
# Calculate proper padding with color codes
if colorize.is_tty:
plain_content = re.sub(r'\033\[\d+m', '', content)
color_parts = content.split(plain_content)
padded = " " * padding + content + " " * padding
# For colored text, we need to calculate padding differently
plain_padded = " " * padding + plain_content + " " * padding
padding_needed = col_widths[col_idx] - len(plain_padded)
if padding_needed > 0:
padded += " " * padding_needed
else:
padded = (" " * padding + content + " " * padding).ljust(col_widths[col_idx])
row_parts.append(padded)
# Wrap repository text if needed
avail_width = col_widths[len(package_data)] - (2 * padding)
if len(repo_text) <= avail_width:
repo_lines.append(colorize(repo_text, 'green'))
else:
# Empty space for this cell in this line
row_parts.append(" " * col_widths[col_idx])
# Handle wrapping for repositories
repo_parts = repos.split(', ')
current_line = "("
print(" | ".join(row_parts))
for repo in repo_parts:
if len(current_line) + len(repo) + 2 <= avail_width:
if current_line != "(":
current_line += ", "
current_line += repo
else:
if current_line != "(":
current_line += ")"
repo_lines.append(colorize(current_line, 'green'))
current_line = " " + repo
# Add a separator between packages (but not after the last one)
if pkg_index < len(args.packages) - 1:
# Use a lighter separator for between packages
if current_line != "(":
current_line += ")" if not current_line.startswith(" ") else ""
repo_lines.append(colorize(current_line, 'green'))
# Combined version and repo lines
package_data.append([version_parts[0]] + repo_lines)
else:
# Simple version string
package_data.append([colorize(version, 'green')])
# Determine max number of lines needed
max_lines = max(len(column) for column in package_data)
# Print all lines for this package
for line_idx in range(max_lines):
row_cells = []
for col_idx, col_data in enumerate(package_data):
if line_idx < len(col_data):
# Actual content
content = col_data[line_idx]
content_plain = re.sub(r'\033\[\d+m', '', content)
# Calculate padding
left_pad = padding
right_pad = max(0, col_widths[col_idx] - len(content_plain) - left_pad)
cell = " " * left_pad + content + " " * right_pad
else:
# Empty cell
cell = " " * col_widths[col_idx]
row_cells.append(cell)
print(" | ".join(row_cells))
# Add separator between packages
if pkg_idx < len(args.packages) - 1:
print("·" * total_width)
def print_list_format(output, headers, selected_pms, args, pkg_availability):
"""Print packages in a vertical list format for narrow terminals"""
terminal_width = shutil.get_terminal_size().columns
for pkg_idx, pkg in enumerate(args.packages):
pkg_color = pkg_availability[pkg]
versions = output.get(pkg, {})
# Print package header with color based on availability
print(f"\n{colorize('Package:', 'bold')} {colorize(pkg, pkg_color)}")
print("-" * min(40, terminal_width - 2))
# Print versions for each package manager
for pm in selected_pms:
pm_name = headers[selected_pms.index(pm) + 1] # Get friendly display name
version = versions.get(pm, 'Not found')
if version == 'Not found':
print(f"{colorize(pm_name, 'header')}: {colorize('-', 'red')}")
else:
# Extract version and repo information
match = re.match(r'(.*?)\s+\((.*)\)$', version)
if match:
ver_num, repos = match.groups()
# Handle long repository lists with wrapping
if len(pm_name) + len(ver_num) + len(repos) + 5 > terminal_width:
print(f"{colorize(pm_name, 'header')}: {colorize(ver_num, 'green')}")
# Wrap repositories with proper indentation
wrapper = textwrap.TextWrapper(
width=terminal_width - 4,
initial_indent=" ",
subsequent_indent=" "
)
wrapped = wrapper.fill(f"({repos})")
print(colorize(wrapped, 'green'))
else:
print(f"{colorize(pm_name, 'header')}: {colorize(ver_num, 'green')} ({repos})")
else:
print(f"{colorize(pm_name, 'header')}: {colorize(version, 'green')}")
# Add separator between packages
if pkg_idx < len(args.packages) - 1:
print("\n" + "-" * min(40, terminal_width - 2))
def main():
parser = argparse.ArgumentParser(description='Package search tool')
parser.add_argument('--all', action='store_true')