Skip to content

Allow constructing custom values for open enumerations - #217

Open
kubukoz wants to merge 1 commit into
neandertech:mainfrom
kubukoz:open-enum-custom-values
Open

kubukoz wants to merge 1 commit into
neandertech:mainfrom
kubukoz:open-enum-custom-values

Conversation

@kubukoz

@kubukoz kubukoz commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

The LSP spec marks eight enumerations with supportsCustomValues, meaning a peer may legally send a value outside the set the spec defines. The generated companions only exposed the predefined entries, and entry is protected, so there was no way to construct such a value at all.

The root cause was upstream of the generator: supportsCustomValues was never decoded — langoustine.meta.Enumeration simply had no such field, so the renderer had no way to know which enumerations were open.

What this does

Adds the field to langoustine.meta.Enumeration, and has the generator mix a CustomStringValues / CustomIntValues / CustomUIntValues trait into the companions that declare it. Each exposes a public apply:

val custom = CodeActionKind("mytool.fixAll")  // now compiles
val known  = CodeActionKind.QuickFix          // still works
CodeActionKind.ALL                            // still lists the predefined values

Enumerations that are closed in the spec stay closed. Affects CodeActionKind, ErrorCodes, FoldingRangeKind, LSPErrorCodes, PositionEncodingKind, SemanticTokenModifiers, SemanticTokenTypes and WatchKind.

ALL is unchanged in both content and visibility.

Also here

A .gitattributes marking the checked-in generated sources and the vendored spec files as linguist-generated, so they collapse in diffs and stay out of language statistics — which already helps in this PR's own diff.

Note for review

The Custom*Values traits are private[lsp], matching the existing StringEnum / IntEnum / UIntEnum. The inherited apply is still public and callable from user code — covered by the new CustomEnumValuesTest — while the internal raw extension stays internal. That is also why the test asserts on underlying values by round-tripping through the JSON codecs rather than calling raw.

Testing

tests/test (40 passed), testsNative/test (27 passed), scalafmtCheckAll and headerCheck all pass. JS tests could not run locally — node isn't installed on this machine — so those are left to CI; the module does compile.


#216 (update to LSP 3.18) is based on this branch. That upgrade is what made the gap concrete: 3.18 turns TextDocumentItem.languageId into LanguageKind rather than a bare String, so without this PR there would be no way to express a custom language id.

🤖 Generated with Claude Code

The LSP spec marks eight enumerations with `supportsCustomValues`,
meaning a peer may legally send a value outside the set the spec defines.
The generated companions only exposed the predefined entries, and `entry`
is `protected`, so there was no way to build such a value.

The `supportsCustomValues` flag was being dropped entirely on decode, so
add it to `langoustine.meta.Enumeration` and have the generator mix a
`CustomStringValues` / `CustomIntValues` / `CustomUIntValues` trait into
the companions that declare it. Each provides a public `apply`, so e.g.
`CodeActionKind("mytool.fixAll")` now works, while enumerations that are
closed in the spec stay closed.

Affects CodeActionKind, ErrorCodes, FoldingRangeKind, LSPErrorCodes,
PositionEncodingKind, SemanticTokenModifiers, SemanticTokenTypes and
WatchKind.

`ALL` is unchanged and still lists the predefined values.

Also add a `.gitattributes` marking the checked-in generated sources and
the vendored spec files as `linguist-generated`, so they collapse in
diffs and stay out of language stats.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kubukoz
kubukoz marked this pull request as ready for review September 7, 2026 23:32
@mergify

mergify Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant