Skip to content
This repository was archived by the owner on Nov 29, 2025. It is now read-only.
This repository was archived by the owner on Nov 29, 2025. It is now read-only.

Feature Request: Custom face rules for token type + modifier combinations #2

@Cianidos

Description

@Cianidos

Problem

Currently, semantic token faces are applied in two layers:

  1. Token type face (e.g., "function", "type")
  2. Modifier faces (e.g., "readonly", "definition") (they applied later and have precedence)

This works well for simple cases, but becomes inflexible when you want different
highlighting for specific combinations. For example:

  • A function with definition modifier should use font-lock-function-name-face (as it set for "definition")
  • A type with definition modifier might need different highlighting than font-lock-function-name-face
  • A struct with definition should look distinct from other struct usages

Currently, whichever face is applied last wins, making it impossible to have
fine-grained control over these combinations without forking.

Proposed Solution

Add a new configuration option: eglot-semantic-tokens-custom-faces that allows
matching specific combinations of token types and modifiers:

(setq eglot-semantic-tokens-custom-faces
      '(
        ;; Token type : modifiers : face
        (("function") ("definition") font-lock-function-name-face)
        (("type" "class" "struct" "enum") ("definition") font-lock-type-face)
        (("variable") ("readonly" "static") font-lock-constant-face)
        (("parameter") ("readonly") font-lock-variable-name-face)
        ))

These rules would be evaluated before falling back to the standard type/modifier
faces, allowing users to define exceptions and special cases without code changes.

Benefits

  • More fine-grained control over semantic highlighting
  • No need to fork or modify eglot.el for custom rules
  • Backwards compatible—existing type/modifier configuration still works
  • Enables language-specific highlighting patterns

Alternative

Could also use a predicate function for maximum flexibility:

(lambda (token-type modifiers) ...)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions