Skip to content

Semantic Tokens ​

clice classifies every token of a document with its own token-kind vocabulary, which is richer than the standard LSP token types and consistent across all clice replies. Clients that prefer standard LSP kinds can map them through configuration.

Lexical Tokens ​

Kinds derived from the token stream itself, independent of the AST.

Supported

Comments

Line, block and documentation comments receive comment tokens

Supported

Literals

Numbers, characters and strings receive literal tokens

Supported

Keywords

Alternative operator spellings and contextual specifiers retain keyword tokens

Supported

Preprocessor directives

#if chains keep directive kinds; disabled branches keep lexical kinds; pragma arguments stay plain

Supported

Inactive regions

Tokens in untaken branches keep their lexical kinds and carry the inactive modifier; unclassified tokens become plain identifier carriers, so even a lone } line dims

Supported

Header names

Quoted and angled include filenames receive string tokens

Supported

Inactive preamble regions

Untaken branches among the leading directives dim the same way

Unsupported

Literal prefixes and suffixes

Literal prefixes, suffixes and separators do not receive distinct tokens yet

Unsupported

Escape sequences

Escape sequences are not highlighted distinctly inside literals yet

Unsupportedclangd#1421

Declarator vs operator disambiguation

Declarator and expression operators do not receive distinct token kinds yet

Supported

Primitive token type

Built-in types use a distinct token kind instead of plain keyword

Unsupported

Bracket token types

Matching brackets do not receive pair-specific token kinds yet

Declarations ​

Names classified by the declaration they define or reference.

Supported

Namespaces

Namespace definitions, references, nesting and aliases receive namespace tokens

Supported

Types

Type definitions and references keep their respective type kinds

Supported

Functions and methods

Function declarations, definitions and calls receive function tokens

Supported

Variables

Variable declarations and references keep their respective variable kinds

Supported

Templates

Template parameters receive type or variable kinds, and template names carry templated

Supported

Concepts

Concept definitions and constraint uses receive concept tokens

Supported

Labels

Labels and their goto references receive label tokens

Supported

Structured bindings

Structured binding names receive variable tokens at definition and use

The opening [ deliberately carries no token; only the binding names themselves are highlighted.

Supportedclangd#868

Lambda init-captures

Lambda init-captures receive variable tokens

Supported

Deduction guides

Deduction guides and their guided templates receive type tokens

Supportedclangd#316

Explicit instantiation

Explicit class instantiations highlight template names and written arguments

Supported

Variable templates

Variable template declarations, definitions and specializations receive variable tokens

Supported

Out-of-line member definitions

Qualified names keep method kinds and modifiers

Supported

Alias templates

The alias name carries the type kind and the templated modifier

Supported

Template template parameters

Template-template parameters receive type tokens at declaration and use

Supported

Friend declarations

Befriended names resolve to their targets; inline friends define

Supported

Function explicit instantiation directives

Identifiers in a function explicit-instantiation directive are painted

Supported

Variable explicit instantiation directives

Identifiers in a variable explicit-instantiation directive are painted

Supported

Explicit instantiation member bodies

A dependent name paints as its actual resolution: agreeing kinds keep the modifiers all instantiations share, disagreeing kinds paint a conflict

References ​

Reference sites retain the semantic kind of the declaration they resolve to, including names reached through language-specific lookup rules.

Supportedclangd#122

Member initializer lists

Member initializer lists highlight initialized names as fields

Supportedclangd#2619

Using declarations

The introduced name keeps its target's kind

Supportedclangd#213

sizeof...

The pack parameter keeps its type-parameter token

Supportedclangd#1283

using enum

Using declarations highlight enum names at the using site

Dependent names

Dependent names resolve through known primary templates

Dependent members of a known template (Box<T>) resolve to the primary template's declarations and keep their kinds. Members of a bare template parameter have no candidate declaration and currently get no token; heuristic coloring for such names remains open.

Supported

Lambda captures

By-copy and by-reference captures reference the captured variable; this stays a keyword

Supported

Range-based for

Range-for variables keep variable tokens at definitions and uses

Supported

Enum underlying types

The enum-base reference keeps its type kind

Partial

Dependent using declarations

Dependent using declarations remain unpainted

The introduced name and its uses currently get no token; the reserved dependent-name modifier is not emitted yet.

Modules ​

Supported

Module declarations

Module declarations tokenize contextual keywords, dotted names and private fragments

Supported

Module partitions

Module declarations tokenize partition names

Supported

module and import as identifiers

Contextual keywords keep their semantic kinds outside module declarations

Token Modifiers ​

Supported

Declaration vs definition

Declaration and definition modifiers distinguish the two sites

Supported

Static

Static members and locals carry the static modifier

Supported

Readonly

Const values and methods, plus enum members, carry the readonly modifier

Readonly is currently value-based: a pointer to const counts as readonly even though the pointer itself can change.

Supported

Virtual and abstract

Virtual methods and abstract classes carry virtual or abstract modifiers

Supported

Deprecated

Deprecated declarations and uses carry the deprecated modifier

Supported

Default library

Symbols from system headers carry the default-library modifier

Unsupportedclangd#352

Scope modifiers

Symbols do not carry function, class, file or global scope modifiers yet

Unsupportedclangd#839

Mutable reference and pointer

Mutable reference and pointer arguments do not carry a modifier yet

Unsupported

Deduced

Deduced types do not carry a dedicated modifier yet

Unsupportedclangd#1521

User-defined operators

Overloaded operators do not differ from built-in operators yet

Conflict & Ambiguity ​

C++ allows structurally different entities to share one name. When a single written name refers to entities of different kinds at once, no single token type is correct; such names receive the dedicated conflict token type, which clients typically display in a neutral color.

Supported

Type vs function

A name naming both renders as conflict

Supported

Type vs variable

A name naming both renders as conflict

Supported

Same-kind overload sets

A name naming only functions is no conflict

Supported

Injected class name

An injected class name keeps its class token when used as a constructor

The written name renders as the class; the constructor reference it implies paints nothing extra — the ( stays token-free.

Token Correctness ​

Shapes clice pins deliberately, including issues clangd got wrong.

Constructors and destructors

Constructors and destructors use method tokens with dedicated modifiers

A destructor name renders as two tokens: the ~ carries the method kind and the declaration/definition modifiers, the class name after it stays a reference to the class.

Supported

Anonymous parameters

Unnamed parameters produce no tokens

The punctuation after an unnamed parameter's type stays token-free.

Supported

Operator names

The operator keyword and call-site punctuation stay plain

An operator's written name is keyword plus punctuation, so no name token is painted: operator keeps its keyword classification and call sites emit nothing on the operator symbol.

Supported

Destructors of class templates

The ~ shape holds under templates

Supported

Conversion operators

Written as keywords, converting uses paint nothing extra

Supported

Pseudo-destructor on a template parameter

The ~ paints nothing; the type name keeps its kind

Supported

Defaulted and deleted members

Special-member names keep their definition tokens

Attributes ​

Unsupportedclangd#2209

Attribute names

Attribute names and their expressions do not receive semantic tokens yet

Macros ​

Tokens inside macro definition bodies keep their lexical kinds; highlighting them from their expansions belongs to a future expansion-preview feature.

Supported

Macro definition and expansion

Macro definitions and expansions receive semantic tokens

Supported

Expansion sites and arguments

Expansion names are macros, written arguments keep their semantics, definition bodies stay lexical

Unsupportedclangd#2649

Object-like vs function-like macros

Object-like and function-like macros do not receive distinct token kinds yet

Other Known Gaps ​

Curated issues without a fixture yet:

  • auto parameters must not be highlighted as template type parameters (clangd#1390)
  • Nested name specifier in a pointer-to-member should get a token (clangd#2235)
  • ::new should keep the new keyword highlighted (clangd#1627)
  • co_yield / co_await lose highlighting when the coroutine return type is a template (clangd#2437)
  • Token modifiers should apply to operands of overloaded operators (clangd#2547)
  • Dependent template names (obj.template get<int>()), members imported from a dependent base via using, and dependent names with mixed-kind overload sets (clangd#484, clangd#686, clangd#1057)

Inactive Code Regions ​

Every token inside an untaken preprocessor branch carries the inactive modifier while keeping its lexical kind, so editors dim the region by styling the modifier without losing the syntax colors underneath. Tokens without a classification in dead code — bare identifiers and plain punctuation — are emitted as the unstyled identifier type, giving the whole region token coverage. The clice VS Code extension renders the regions dimmed out of the box; other editors style the modifier directly (e.g. @lsp.mod.inactive in Neovim).

  • Dim inactive preprocessor branches (clangd#132)
  • Correct inactive boundaries with #elif chains (clangd#602)
  • Preserve syntax highlighting within inactive regions (clangd#1664)
  • Keep inactive regions distinct from comments (clangd#1545)
  • Unreachable code dimming (clangd#1828)

Format String Highlighting ​

  • std::format / std::print placeholder highlighting (clangd#1709)
  • Highlight invalid format specifiers as errors

Protocol Support ​

  • Full document semantic tokens (textDocument/semanticTokens/full)
  • UTF-16 delta-encoded token positions
  • Range-based semantic tokens (textDocument/semanticTokens/range) — only compute tokens for the visible viewport, critical for large files
  • Delta updates (textDocument/semanticTokens/full/delta) — send only changes since the previous response