diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-25 08:08:19 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-25 08:08:19 +0900 |
| commit | 199bd1ea9c452a540a8011114e3cee2c44e30ff7 (patch) | |
| tree | 831dea24c0fd594e591109078178a30d578bf2c1 | |
| parent | d2aa71281c6a95ad112e1371ab7ddd912a4d99c3 (diff) | |
| download | nur-packages-199bd1ea9c452a540a8011114e3cee2c44e30ff7.tar.gz nur-packages-199bd1ea9c452a540a8011114e3cee2c44e30ff7.tar.zst nur-packages-199bd1ea9c452a540a8011114e3cee2c44e30ff7.zip | |
feat(nvim-setcellwidths-table-for-udev-gothic): new
| -rw-r--r-- | default.nix | 1 | ||||
| -rw-r--r-- | pkgs/nvim-setcellwidths-table-for-udev-gothic/default.nix | 31 | ||||
| -rw-r--r-- | pkgs/nvim-setcellwidths-table-for-udev-gothic/main.py | 137 |
3 files changed, 169 insertions, 0 deletions
diff --git a/default.nix b/default.nix index 2f4443e..aded4de 100644 --- a/default.nix +++ b/default.nix @@ -6,6 +6,7 @@ hgrep = pkgs.callPackage ./pkgs/hgrep { }; git-helpers = pkgs.callPackage ./pkgs/git-helpers { }; + nvim-setcellwidths-table-for-udev-gothic = pkgs.callPackage ./pkgs/nvim-setcellwidths-table-for-udev-gothic { }; reparojson = pkgs.callPackage ./pkgs/reparojson { }; term-banner = pkgs.callPackage ./pkgs/term-banner { }; term-clock = pkgs.callPackage ./pkgs/term-clock { }; diff --git a/pkgs/nvim-setcellwidths-table-for-udev-gothic/default.nix b/pkgs/nvim-setcellwidths-table-for-udev-gothic/default.nix new file mode 100644 index 0000000..18df323 --- /dev/null +++ b/pkgs/nvim-setcellwidths-table-for-udev-gothic/default.nix @@ -0,0 +1,31 @@ +{ + lib, + stdenv, + python3, + udev-gothic, +}: + +stdenv.mkDerivation { + pname = "nvim-setcellwidths-table-for-udev-gothic"; + version = "1.0.0"; + + src = ./.; + + nativeBuildInputs = [ + (python3.withPackages (ps: [ ps.fonttools ])) + ]; + + buildPhase = '' + python main.py ${udev-gothic}/share/fonts/udev-gothic/UDEVGothic35-Regular.ttf > setcellwidths.lua + ''; + + installPhase = '' + mkdir -p $out + cp setcellwidths.lua $out + ''; + + meta = with lib; { + description = "Generate setcellwidths() table for udev-gothic font"; + license = licenses.ofl; + }; +} diff --git a/pkgs/nvim-setcellwidths-table-for-udev-gothic/main.py b/pkgs/nvim-setcellwidths-table-for-udev-gothic/main.py new file mode 100644 index 0000000..483d826 --- /dev/null +++ b/pkgs/nvim-setcellwidths-table-for-udev-gothic/main.py @@ -0,0 +1,137 @@ +import argparse +from collections.abc import Generator +from fontTools.ttLib import TTFont +from pathlib import Path +import unicodedata + +def ambiguous_codepoints() -> Generator[int]: + for cp in range(0x00000, 0x30000): + try: + char = chr(cp) + eaw = unicodedata.east_asian_width(char) + if eaw == 'A': + yield cp + except (ValueError, UnicodeEncodeError): + continue + +def get_glyph_width(font: TTFont, codepoint: int) -> int | None: + cmap = font.getBestCmap() + if cmap is None: + return None + + glyph_name = cmap.get(codepoint) + if glyph_name is None: + return None + + if 'hmtx' not in font: + return None + + hmtx = font['hmtx'] + if glyph_name not in hmtx.metrics: + return None + + width, _ = hmtx.metrics[glyph_name] + return width + +def get_reference_widths(font: TTFont) -> tuple[int | None, int | None]: + halfwidth_ref = None + for cp in [0x0041, 0x0030, 0x0061]: + w = get_glyph_width(font, cp) + if w is not None and w > 0: + halfwidth_ref = w + break + + fullwidth_ref = None + for cp in [0xFF21, 0x3042, 0x6F22, 0x4E00]: + w = get_glyph_width(font, cp) + if w is not None and w > 0: + fullwidth_ref = w + break + + return halfwidth_ref, fullwidth_ref + +def classify_width(width: int, half_ref: int, full_ref: int) -> str: + if width <= (half_ref + full_ref) / 2: + return "half" + else: + return "full" + +def analyze_font(font_path: str) -> dict: + font = TTFont(font_path) + + stats = { + "half": [], + "full": [], + } + + half_ref, full_ref = get_reference_widths(font) + if half_ref is None or full_ref is None: + return stats + + for cp in ambiguous_codepoints(): + width = get_glyph_width(font, cp) + if width is None: + continue + + classification = classify_width(width, half_ref, full_ref) + stats[classification].append(cp) + + font.close() + return stats + +def merge_ranges(codepoints: list[int]) -> list[tuple[int, int]]: + if not codepoints: + return [] + sorted_cps = sorted(codepoints) + ranges = [] + start = sorted_cps[0] + end = sorted_cps[0] + for cp in sorted_cps[1:]: + if cp == end + 1: + end = cp + else: + ranges.append((start, end)) + start = cp + end = cp + ranges.append((start, end)) + return ranges + +def generate_table(stats: dict) -> str: + prefix = [ + "local M = {}", + "", + "function M.setcellwidths()", + " vim.fn.setcellwidths({", + ] + table = [] + for start, end in merge_ranges(stats["full"]): + chars = ", ".join("%s (U+%04X)" % (chr(cp), cp) for cp in range(start, end + 1)) + table.append(" -- %s" % chars) + table.append(" {%#06x, %#06x, 2}," % (start, end)) + suffix = [ + " })", + "end", + "", + "return M", + ] + return "\n".join(prefix + table + suffix) + +def main(): + parser = argparse.ArgumentParser( + description='Generate Neovim setcellwidths() table' + ) + parser.add_argument('font', help='Font file path') + + args = parser.parse_args() + + if not Path(args.font).exists(): + print(f"Font file not found: {args.font}") + return 1 + + stats = analyze_font(args.font) + table = generate_table(stats) + print(table) + return 0 + +if __name__ == '__main__': + exit(main()) |
