SLOPSHOPPER

nerd-font

Works out once whether a Nerd Font is installed, with a setting to force it on or off, so mods that draw Nerd Font glyphs know when to fall back

process
A shopper browsing a rack in a slop shop
README

nerd-font

A Claude Code mod that other mods depend on to know whether they can draw Nerd Font icons. It works out the answer once a session, so every mod on screen draws the same way: attention-is-all-i-need's magnifying glass and copy-code's copy label either both use the icon or both fall back to plain characters.

How it decides

The mod API can't tell which font the terminal draws with, so the mod asks fontconfig instead. If any installed family that fc-list : family lists has "Nerd Font" in its name, the answer is yes. If there's no such family, or no fc-list, the answer is no.

A Nerd Font being installed doesn't mean your terminal uses it. If the guess is wrong, use the setting.

Setting

In /config, the Nerd Font glyphs row picks one of:

ValueIcons are drawn
auto (default)when fc-list finds a Nerd Font
onalways
offnever

A change there reloads the mod with the new value, and the mods that read the answer while drawing redraw. The value is kept in settings.json under pluginConfigs.

For mod authors

List nerd-font under dependencies in your plugin.json:

{ "dependencies": ["nerd-font"] }

Read the answer from $.state while drawing. Your drawing then redraws when the answer arrives or changes:

const nerdFont = { plugin: 'nerd-font', key: 'enabled' } as const

on('ui.render', { component: 'AbovePrompt', surface: 'terminal' }, async ($, e) => {
  const { value: hasNerdFont } = await $.state.get(nerdFont)
  const { Text } = $.ui.resolve(e)
  return <Text>{hasNerdFont ? '\u{F0349}' : '🔍'}</Text>
})

The value is undefined until the session's check has run, so treat anything but true as no. Claude Code lays this mod's contract into your mod's .claude-plugin/types/nerd-font/index.d.ts, so the key and its type are checked.

Install

/plugin install nerd-font --marketplace AH-Merii/claude-plugins
Source 2 files
hooks/register.ts 38 lines
1import type { EngineInterface as Engine, Register } from 'claude-code'
2
3const enabled = { plugin: 'nerd-font', key: 'enabled' } as const
4
5// Whether fontconfig lists a font family with "Nerd Font" in its name. The mod API can't tell which font the
6// terminal draws with, so an installed one is the best guess; the setting covers a terminal that doesn't use it.
7async function installed($: Engine) {
8  try {
9    const { stdout } = await $.process.run(['fc-list', ':', 'family'], { timeoutMs: 5000 })
10    return stdout.includes('Nerd Font')
11  } catch {
12    // No fc-list on this machine, or no processes on this surface: glyphs would show as empty boxes.
13    return false
14  }
15}
16
17export const register: Register = (on, options) => {
18  // The answer as last worked out; fonts don't change within a process, so it is checked once per load.
19  let answer: boolean | undefined
20
21  // Once a session, and again when the module reloads, as it does when the setting changes in /config.
22  on('session.start', async ($, e, next) => {
23    answer = options.glyphs === 'on' || (options.glyphs !== 'off' && (await installed($)))
24    await $.state.set(enabled, answer)
25    return next(e)
26  })
27
28  // A /clear starts a new session whose state starts empty, and no session.start fires for it; the settings-style
29  // SessionStart does, with source "clear", inside the new session.
30  on('classic.SessionStart', async ($, e, next) => {
31    const result = await next(e)
32    if (e.source === 'clear' && answer !== undefined) {
33      await $.state.set(enabled, answer)
34    }
35    return result
36  })
37}
38
types/index.d.ts 8 lines
1declare module 'claude-code' {
2  interface PluginState {
3    // Whether mods should draw Nerd Font glyphs: the user's setting, or else whether an installed font's family
4    // has "Nerd Font" in its name. Undefined until the session's check has run.
5    'nerd-font': { enabled: boolean }
6  }
7}
8