Files
@ 8092a1881a49
Branch filter:
Location: majic-scripts/utils/mapping_generator.py - annotation
8092a1881a49
3.7 KiB
text/x-python
[thebuggenie_hg_remote.py] Fixed linter errors:
- Mostly spacing-related.
- Use the range function instead of xrange (Python 2.7 -> Python 3.x).
- Script probably will not run correctly under Python 3.x, but at
least the linter will not get in the way when working on other
Python code in the project.
- Mostly spacing-related.
- Use the range function instead of xrange (Python 2.7 -> Python 3.x).
- Script probably will not run correctly under Python 3.x, but at
least the linter will not get in the way when working on other
Python code in the project.
f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 f3d3009808f7 | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 Branko Majic
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
import shutil
import math
import click
from defusedxml import ElementTree
# Allow use of short option for showing help.
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.group(context_settings=CONTEXT_SETTINGS)
def cli():
"""
Generate input mapping cheatsheets for input devices using specially-crafted scalable vector graphics (SVG)
templates.
To prepare a template, create an SVG using Inkscape, and assign custom IDs to text elements that should be managed
by the mapping generator.
"""
pass
@cli.command()
@click.argument('template', type=click.File('r'))
@click.option('--search', '-s', default='', help='only show matching mappings')
def info(template, search):
"""
Shows information about the passed-in SVG template. This currently includes:
- List of mappable elements.
"""
template_tree = ElementTree.fromstring(template.read())
namespaces = {
'svg': 'http://www.w3.org/2000/svg',
}
# Inkscape default ID starts with string 'text' unless user assigns custom ID.
mappable_elements = [
e for e in template_tree.findall('.//svg:text', namespaces) if not e.get('id').startswith('text')
]
matched_mappables = sorted([e.get('id') for e in mappable_elements if search in e.get('id')])
if not mappable_elements:
click.echo('No mappables found in the specified template. Please check that you have specified correct file.')
elif not matched_mappables:
click.echo('Search term did not match any mappable in the specified template.')
else:
# Show mappables in multiple columns, while enforcing a minimum column height (element count). For example, if
# there are only 5 mappables, show them in a single column instead of splitting them up into multiple ones.
terminal_size = shutil.get_terminal_size((80, 20))
column_spacing = 4
row_threshold = math.floor(terminal_size.lines * 0.5)
column_width = max([len(m) for m in matched_mappables])
columns = math.floor((terminal_size.columns) / (column_width + column_spacing))
page_threshold = row_threshold * columns
# Expand the list with blank strings in order to have exact number of 'cells' when printing to
# screeen. Simplifies the code dealing with printing a bit and avoid invalid index access.
if len(matched_mappables) <= row_threshold:
rows = len(matched_mappables)
elif len(matched_mappables) <= page_threshold:
rows = row_threshold
matched_mappables.extend([''] * (page_threshold - len(matched_mappables)))
else:
rows = math.ceil(len(matched_mappables) / columns)
matched_mappables.extend([''] * (columns * rows - len(matched_mappables)))
click.echo('Mappables:\n')
for i in range(rows):
click.echo((" " * column_spacing).join([f'{m:<{column_width}}' for m in matched_mappables[i::rows]]))
if __name__ == '__main__':
cli()
|