You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
6.5 KiB

  1. """Keyboard information script.
  2. Compile an info.json for a particular keyboard and pretty-print it.
  3. """
  4. import json
  5. import platform
  6. from milc import cli
  7. from qmk.json_encoders import InfoJSONEncoder
  8. from qmk.constants import COL_LETTERS, ROW_LETTERS
  9. from qmk.decorators import automagic_keyboard, automagic_keymap
  10. from qmk.keyboard import keyboard_completer, keyboard_folder, render_layouts, render_layout
  11. from qmk.keymap import locate_keymap
  12. from qmk.info import info_json
  13. from qmk.path import is_keyboard
  14. platform_id = platform.platform().lower()
  15. def show_keymap(kb_info_json, title_caps=True):
  16. """Render the keymap in ascii art.
  17. """
  18. keymap_path = locate_keymap(cli.config.info.keyboard, cli.config.info.keymap)
  19. if keymap_path and keymap_path.suffix == '.json':
  20. if title_caps:
  21. cli.echo('{fg_blue}Keymap "%s"{fg_reset}:', cli.config.info.keymap)
  22. else:
  23. cli.echo('{fg_blue}keymap_%s{fg_reset}:', cli.config.info.keymap)
  24. keymap_data = json.load(keymap_path.open(encoding='utf-8'))
  25. layout_name = keymap_data['layout']
  26. for layer_num, layer in enumerate(keymap_data['layers']):
  27. if title_caps:
  28. cli.echo('{fg_cyan}Layer %s{fg_reset}:', layer_num)
  29. else:
  30. cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num)
  31. print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, layer))
  32. def show_layouts(kb_info_json, title_caps=True):
  33. """Render the layouts with info.json labels.
  34. """
  35. for layout_name, layout_art in render_layouts(kb_info_json, cli.config.info.ascii).items():
  36. title = layout_name.title() if title_caps else layout_name
  37. cli.echo('{fg_cyan}%s{fg_reset}:', title)
  38. print(layout_art) # Avoid passing dirty data to cli.echo()
  39. def show_matrix(kb_info_json, title_caps=True):
  40. """Render the layout with matrix labels in ascii art.
  41. """
  42. for layout_name, layout in kb_info_json['layouts'].items():
  43. # Build our label list
  44. labels = []
  45. for key in layout['layout']:
  46. if 'matrix' in key:
  47. row = ROW_LETTERS[key['matrix'][0]]
  48. col = COL_LETTERS[key['matrix'][1]]
  49. labels.append(row + col)
  50. else:
  51. labels.append('')
  52. # Print the header
  53. if title_caps:
  54. cli.echo('{fg_blue}Matrix for "%s"{fg_reset}:', layout_name)
  55. else:
  56. cli.echo('{fg_blue}matrix_%s{fg_reset}:', layout_name)
  57. print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, labels))
  58. def print_friendly_output(kb_info_json):
  59. """Print the info.json in a friendly text format.
  60. """
  61. cli.echo('{fg_blue}Keyboard Name{fg_reset}: %s', kb_info_json.get('keyboard_name', 'Unknown'))
  62. cli.echo('{fg_blue}Manufacturer{fg_reset}: %s', kb_info_json.get('manufacturer', 'Unknown'))
  63. if 'url' in kb_info_json:
  64. cli.echo('{fg_blue}Website{fg_reset}: %s', kb_info_json.get('url', ''))
  65. if kb_info_json.get('maintainer', 'qmk') == 'qmk':
  66. cli.echo('{fg_blue}Maintainer{fg_reset}: QMK Community')
  67. else:
  68. cli.echo('{fg_blue}Maintainer{fg_reset}: %s', kb_info_json['maintainer'])
  69. cli.echo('{fg_blue}Keyboard Folder{fg_reset}: %s', kb_info_json.get('keyboard_folder', 'Unknown'))
  70. cli.echo('{fg_blue}Layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys())))
  71. if 'width' in kb_info_json and 'height' in kb_info_json:
  72. cli.echo('{fg_blue}Size{fg_reset}: %s x %s' % (kb_info_json['width'], kb_info_json['height']))
  73. cli.echo('{fg_blue}Processor{fg_reset}: %s', kb_info_json.get('processor', 'Unknown'))
  74. cli.echo('{fg_blue}Bootloader{fg_reset}: %s', kb_info_json.get('bootloader', 'Unknown'))
  75. if 'layout_aliases' in kb_info_json:
  76. aliases = [f'{key}={value}' for key, value in kb_info_json['layout_aliases'].items()]
  77. cli.echo('{fg_blue}Layout aliases:{fg_reset} %s' % (', '.join(aliases),))
  78. if cli.config.info.layouts:
  79. show_layouts(kb_info_json, True)
  80. if cli.config.info.matrix:
  81. show_matrix(kb_info_json, True)
  82. if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file':
  83. show_keymap(kb_info_json, True)
  84. def print_text_output(kb_info_json):
  85. """Print the info.json in a plain text format.
  86. """
  87. for key in sorted(kb_info_json):
  88. if key == 'layouts':
  89. cli.echo('{fg_blue}layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys())))
  90. else:
  91. cli.echo('{fg_blue}%s{fg_reset}: %s', key, kb_info_json[key])
  92. if cli.config.info.layouts:
  93. show_layouts(kb_info_json, False)
  94. if cli.config.info.matrix:
  95. show_matrix(kb_info_json, False)
  96. if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file':
  97. show_keymap(kb_info_json, False)
  98. @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.')
  99. @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
  100. @cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.')
  101. @cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.')
  102. @cli.argument('-f', '--format', default='friendly', arg_only=True, help='Format to display the data in (friendly, text, json) (Default: friendly).')
  103. @cli.argument('--ascii', action='store_true', default='windows' in platform_id, help='Render layout box drawings in ASCII only.')
  104. @cli.subcommand('Keyboard information.')
  105. @automagic_keyboard
  106. @automagic_keymap
  107. def info(cli):
  108. """Compile an info.json for a particular keyboard and pretty-print it.
  109. """
  110. # Determine our keyboard(s)
  111. if not cli.config.info.keyboard:
  112. cli.log.error('Missing parameter: --keyboard')
  113. cli.subcommands['info'].print_help()
  114. return False
  115. if not is_keyboard(cli.config.info.keyboard):
  116. cli.log.error('Invalid keyboard: "%s"', cli.config.info.keyboard)
  117. return False
  118. # Build the info.json file
  119. kb_info_json = info_json(cli.config.info.keyboard)
  120. # Output in the requested format
  121. if cli.args.format == 'json':
  122. print(json.dumps(kb_info_json, cls=InfoJSONEncoder))
  123. elif cli.args.format == 'text':
  124. print_text_output(kb_info_json)
  125. elif cli.args.format == 'friendly':
  126. print_friendly_output(kb_info_json)
  127. else:
  128. cli.log.error('Unknown format: %s', cli.args.format)
  129. return False