Module: TokenReel::Fonts
- Defined in:
- lib/token_reel/fonts.rb
Overview
Picks and validates the monospace font ImageMagick renders text with. This matters more than it sounds: the whole layout (column wrapping, cursor placement, and the per-span x-offsets syntax highlighting draws at) assumes every glyph is the same width, which is only true if the font actually resolves to a real monospace font. ImageMagick silently falls back to some default font (and only warns on stderr, without failing) when asked for a font name it doesn't know -- so guessing a hardcoded name and trusting it works is how you end up with misaligned, overlapping text.
Constant Summary collapse
- CANDIDATES =
Common monospace font names, in priority order, as ImageMagick tends to expose them across Linux/macOS/Windows installs.
%w[ DejaVu-Sans-Mono Menlo-Regular Consolas Liberation-Mono Courier-New Monaco Andale-Mono PT-Mono Noto-Sans-Mono Ubuntu-Mono Cascadia-Mono JetBrains-Mono JetBrainsMono-Regular Fira-Code FiraCode-Regular Hack-Regular Courier fixed ].freeze
Class Method Summary collapse
- .autodetect ⇒ Object
- .available ⇒ Object
-
.resolve!(name) ⇒ Object
name == nil means "pick one for me".
Class Method Details
.autodetect ⇒ Object
40 41 42 43 44 45 46 |
# File 'lib/token_reel/fonts.rb', line 40 def self.autodetect CANDIDATES.find { |name| available.include?(name) } || raise(RenderError, "no monospace font found on this system; install one of " \ "#{CANDIDATES.first(4).join(', ')}, etc., or pass --font NAME " \ "with an exact name from `#{Renderer.convert_binary} -list font`") end |
.available ⇒ Object
23 24 25 26 |
# File 'lib/token_reel/fonts.rb', line 23 def self.available @available ||= `#{Shellwords.escape(Renderer.convert_binary)} -list font 2>/dev/null` .scan(/^\s*Font:\s*(\S+)/).flatten end |
.resolve!(name) ⇒ Object
name == nil means "pick one for me". A name the caller passed in explicitly is validated against what ImageMagick actually knows, rather than trusted -- see the module comment for why.
31 32 33 34 35 36 37 38 |
# File 'lib/token_reel/fonts.rb', line 31 def self.resolve!(name) return autodetect if name.nil? return name if available.include?(name) raise RenderError, "font #{name.inspect} not found via `#{Renderer.convert_binary} -list font` " \ "(pass --font with an exact name from that list, or omit --font to auto-detect)" end |