#!/usr/bin/env python3 import argparse import jinja2 import re TEMPLATE = """\ /// /// Icon images. /// // // GENERATED BY xpm2rs.py -- DO NOT EDIT! // #[repr(u8)] #[derive(Clone, Copy, Debug)] pub enum XpmColor { Transparent = 0, Black = 1, White = 2, } #[derive(Clone)] pub struct XpmImage { pub width: usize, pub height: usize, pub bitmap: &'static [XpmColor], } pub struct Icons { {%- for icon in icons %} pub {{ icon.name }}: XpmImage, {%- endfor %} } pub const ICONS: Icons = Icons { {%- for icon in icons %} {{ icon.comment }} {{ icon.name }}: XpmImage { width: {{ icon.width }}, height: {{ icon.height }}, #[rustfmt::skip] bitmap: &[ {%- for bit in icon.bitmap -%} XpmColor::{{ bit }}, {%- endfor -%} ], }, {%- endfor %} }; """ COLORS = { "black": "Black", "white": "White", "none": "Transparent", } def parse_xpm(xpm: str): state = "start" for line in xpm.splitlines(): if state == "start": if m := re.match(r'static char \* (?P.+)_xpm\[\] = {', line): name = m.groupdict()["name"] state = "size" elif state == "size": d = re.match(r'"(?P\d+) (?P\d+) (?P\d+) \d+",', line).groupdict() width = int(d["width"]) height = int(d["height"]) num_colors = int(d["num_colors"]) height_remaining = height colors = {} state = "colors" elif state == "colors": d = re.match(r'"(?P.)\tc (?P[a-zA-Z]+)",', line).groupdict() colors[d["char"]] = COLORS[d["color"].lower()] num_colors -= 1 if num_colors <= 0: bitmap = [] comment = "" state = "bitmap" elif state == "bitmap": if height_remaining == 0: break else: for ch in re.match(r'"(?P[^"]+)"(,|};)', line).groupdict()["row"]: bitmap.append(colors[ch]) comment += ch comment += "\n" height_remaining -= 1 else: assert "unreachable" return { "name": name, "width": width, "height": height, "bitmap": bitmap, "comment": "\n".join(map(lambda l: f" // \"{l}\"", comment.strip("\n").splitlines())), } def main(): parser = argparse.ArgumentParser() parser.add_argument("xpm_files", nargs="+") args = parser.parse_args() icons = [] for path in args.xpm_files: icons.append(parse_xpm(open(path).read())) print(jinja2.Template(TEMPLATE).render(icons=icons)) if __name__ == "__main__": main()