# Feature Log
User-facing feature decisions for rlsp-yaml, newest first.
Tiered by user impact, implementation feasibility, and
alignment with existing infrastructure.
<!--
Agent scope note (hidden from rendered docs):
This file is USER-FACING documentation. Entries describe
changes a user of the language server would notice — new
LSP capabilities, behavior changes visible in their
editor, settings that unlock new UX.
Do NOT add entries for:
- Internal refactors (e.g. "retrofit X to AST+formatter")
- Implementation rewrites that don't change user-visible
behavior (same quickfix titles, diagnostics, output)
- Test infrastructure, audits, boundary-check additions
- Memory or plan-file updates
Internal changes belong in git history and the
corresponding plan file under `.ai/plans/`.
-->
**Tiers:**
- **1** — High impact, feasible now
- **2** — Medium impact, moderate effort
- **3** — Valuable but higher effort
- **4** — Niche or high effort / low return
---
### `.editorconfig` Support for the Formatter [completed]
**Date:** 2026-05-20
**Description:** The formatter now reads `.editorconfig` files automatically. When a `.editorconfig` is present, `max_line_length` sets the print width, `end_of_line` controls line endings, and `insert_final_newline` controls whether a trailing newline is appended. Changes to `.editorconfig` files are picked up live without restarting the server. Users who prefer rlsp-yaml's workspace settings to take unconditional precedence can opt out via `formatRespectEditorconfig: false` (default `true`).
**Complexity:** Low
**Tier:** 1
---
### `formatEnable` Setting [completed]
**Date:** 2026-05-20
**Description:** New `formatEnable` setting (boolean, default `true`) lets users disable rlsp-yaml's built-in YAML formatter while keeping all other features active. When `false`, formatting requests (`textDocument/formatting`, `textDocument/rangeFormatting`, `textDocument/onTypeFormatting`) return no edits. Diagnostics, hover, completion, and code actions continue to work normally. Intended for users who prefer an external formatter (Prettier, dprint, etc.) but still want rlsp-yaml's diagnostics and code actions.
**Complexity:** Low
**Tier:** 1
---
### Zed Editor Extension [completed]
**Description:** rlsp-yaml is now available as a native Zed extension in the [Zed marketplace](https://zed.dev/extensions?query=rlsp-yaml). Install by searching for `rlsp-yaml` in Zed's extension panel — the extension bundles the server and requires no manual LSP configuration. Extension releases are published automatically when a new `rlsp-yaml` crate version is released.
**Complexity:** Low
**Tier:** 1
---
### Custom Tag Type Annotations [completed]
**Description:** The `customTags` setting (and the `$tags=` modeline) now accepts optional type annotations. Append ` scalar`, ` mapping`, or ` sequence` (case-insensitive) to any tag entry to declare the expected node structure. When a tagged node's actual structure doesn't match the declared type, the server emits a `tagTypeMismatch` warning diagnostic. Tags without a type annotation continue to suppress `unknownTag` warnings with no structure check. This format is compatible with the RedHat yaml-language-server `customTags` setting, so existing configurations migrate unchanged. When both workspace settings and a modeline declare the same tag name, the modeline wins.
**Complexity:** Low
**Tier:** 1
---
### Document Symbols [completed]
**Description:** `textDocument/documentSymbol` is now fully implemented, enabling outline view, breadcrumbs, and Go to Symbol in VS Code. YAML keys map to `SymbolKind` (`OBJECT` for mappings, `ARRAY` for sequences, `STRING`/`NUMBER`/`BOOLEAN`/`NULL` for scalars) using the parser's tag-URI output rather than heuristics, so `"42"` (quoted) correctly shows as `STRING` while `42` shows as `NUMBER`. Sequence items under mapping keys show as children with index labels `[0]`, `[1]`, etc.; when the first key of a mapping item is `name`, `id`, or `key`, its value is used as the item's display name and the index becomes the detail text (e.g. name `nginx`, detail `[0]`). Scalar value nodes show the value itself as detail text, truncated to 60 characters with an ellipsis suffix. Non-mapping root documents are now supported: a sequence root produces one symbol per item; a scalar root produces a single symbol whose name is the scalar value. Multi-document YAML files (two or more documents) wrap each document in a `NAMESPACE` symbol named `Document 1`, `Document 2`, etc.; single-document files produce a flat symbol list with no wrapper.
**Complexity:** Medium
**Tier:** 1
---
### Block-to-Flow Code Action Handles Nested Collections [completed]
**Description:** The "Convert block to flow style" code action now handles block collections that contain nested block collections — previously these inputs were silently skipped with no action offered. Supported shapes include: block mapping containing a block mapping value (`outer: {inner: {a: 1}}`), block sequence whose items are block mappings (the Kubernetes `containers:` shape: `containers: [{name: web, image: nginx}, {name: db, image: postgres}]`), block sequence whose items are block sequences, and arbitrarily deep nesting across all combinations. Anchors and tags on inner nested collections are preserved in the flow output.
**Complexity:** Low
**Comment:** The recursive style-flip is local to the code action — no formatter changes required. Comments inside a flipped subtree are not preserved, consistent with the existing flat block-to-flow behavior.
**Tier:** 2
---
### `invalidCharacter` Diagnostic Code [completed]
**Description:** YAML files containing non-printable characters (bytes or code points not in the YAML 1.2 c-printable or nb-json sets) now produce diagnostics with code `invalidCharacter` instead of the generic `yamlSyntax` code. Editors can use this code to distinguish character-set violations from grammar errors and apply different highlighting or suppression rules.
**Complexity:** Low
**Comment:** The parser already detected these violations; this change surfaces the distinction through to LSP clients with no new processing cost.
**Tier:** 2
### Code Actions Honor Formatter Settings [completed]
**Description:** All code actions now respect the user's formatter settings (`formatPrintWidth`, `formatSingleQuote`, `formatBracketSpacing`, `formatPreserveQuotes`) consistently with the document formatter. Previously, code actions used hardcoded defaults regardless of user configuration. The `Convert block to flow style` action's output now wraps at the user's configured `formatPrintWidth` (default 80) instead of a hardcoded value, and the action title no longer appends a `(long line)` suffix when the result is long — the formatter handles wrapping automatically.
**Complexity:** Low
**Comment:** Consistency between the formatter and code actions is the expected UX — users configuring `formatPrintWidth: 120` expect code-action output to also fit within 120 columns.
**Tier:** 1
### `formatIndentSequences` Option [completed]
**Description:** New formatter setting `formatIndentSequences` (boolean, default `true`) controls whether block sequences under mapping keys are indented. When `true` (the default), sequences are indented relative to their key (`key:\n - item`). When `false`, sequences are placed at the same indentation level as the key (`key:\n- item`). Existing users see no change — the default preserves the previous behavior.
**Complexity:** Low
**Comment:** The indentless style (YAML block sequence syntax per §8.2.1) is common in Docker Compose and Ansible. RedHat yaml-language-server has an equivalent `indentSequence` setting. Both styles are valid YAML 1.2.
**Tier:** 2
### Drop `use_tabs` Formatter Option [completed]
**Description:** The `use_tabs` formatter option has been removed. The formatter always uses space indentation for YAML. When the LSP client sends `insertSpaces: false` (editor configured for tab indentation), the setting is silently ignored and spaces are used instead.
**Complexity:** Low
**Comment:** YAML 1.2 §6.1 forbids tab characters for indentation — the project's own parser rejects tab-indented YAML on re-parse, producing a broken round-trip. RedHat yaml-language-server and Prettier both ignore `insertSpaces: false` for YAML; this change brings rlsp-yaml in line with the ecosystem. The underlying `rlsp-fmt` pretty-printer retains its `use_tabs` option for non-YAML consumers.
**Tier:** 1
### YAML 1.1 Compatibility Diagnostics [completed]
**Description:** Warn when plain scalars would be interpreted differently by YAML 1.1 parsers (Kubernetes, Ansible, GitLab CI, etc.). `yaml11Boolean` (warning) fires for the 16 YAML 1.1 boolean forms not in YAML 1.2 (`yes`, `no`, `on`, `off`, `y`, `n`, and case variants); `yaml11Octal` (info) fires for C-style octal literals (`0777`). Schema-aware variants (`schemaYaml11Boolean`, `schemaYaml11Octal`) escalate severity when the field is schema-typed as `string` — the 1.2 parser accepts the value but downstream 1.1 tools will silently corrupt it; `schemaType` messages are enhanced when a boolean-typed field receives a 1.1 boolean form. Quick fixes: quote value (universally safe, listed first) or convert to canonical 1.2 form (`true`/`false`, `0o777`). All four diagnostics are suppressed when `yamlVersion` is `"1.1"`. The VS Code extension now exposes `rlsp-yaml.yamlVersion` and `rlsp-yaml.validate` settings.
**Complexity:** Medium
**Comment:** Novel approach — parse as YAML 1.2 but warn about 1.1 ambiguities rather than switching the parser. Red Hat's yaml-language-server (issue #532, open since Aug 2021) requests similar quick fixes but provides no cross-version diagnostics. Suppression via `# rlsp-yaml-disable-next-line yaml11Boolean` or `# rlsp-yaml-disable-file yaml11Boolean`.
**Tier:** 1
### `$schema` Draft Detection [completed]
**Description:** Parse the `$schema` keyword to detect which JSON Schema draft a schema targets. Surface the draft in hover/code lens.
**Complexity:** Low
**Comment:** Parse the URI, map to a draft enum. Currently all keywords from all drafts are accepted unconditionally, which works but isn't strictly correct.
**Tier:** 1
### `$id` / `id` Base URI Resolution [completed]
**Description:** Parse `$id` (Draft-06+) and `id` (Draft-04) to establish base URIs for relative `$ref` resolution. Thread base URI through schema parsing.
**Complexity:** Medium-High
**Comment:** Foundational for remote `$ref` support. Nested schemas can override the parent's base URI. Requires threading base URI through `parse_schema_with_root`.
**Tier:** 1
### Remote `$ref` Resolution [completed]
**Description:** Resolve `$ref` URIs that point to external schema documents. Fetch, cache, and parse referenced schemas.
**Complexity:** Medium-High
**Comment:** Depends on `$id` for base URI resolution. Fetch infrastructure (`fetch_schema`, SSRF guards, caching) already exists. Work is in URI resolution and cross-document fragment lookup.
**Tier:** 1
### `format` Validation [completed]
**Description:** Validate string values against JSON Schema `format` keywords (date-time, email, uri, ipv4/v6, hostname, uuid, regex, etc.). Includes IDN/IRI formats via `idna` and `iri-string` crates.
**Complexity:** Medium
**Comment:** Most formats are simple regex or stdlib parses. IDN/IRI handled by external crates. Configurable via `formatValidation` setting (default true for Draft-04/07, annotation-only for 2019-09+).
**Tier:** 2
### `contentEncoding` / `contentMediaType` [completed]
**Description:** Validate encoded string content — decode via `contentEncoding` (base64, base32, base16) and check `contentMediaType` (application/json).
**Complexity:** Low
**Comment:** Uses `data_encoding` crate. Only `application/json` media type validated (decode + `serde_json::from_str`). Annotation-only in Draft 2019-09+.
**Tier:** 2
---
### String Constraints (`pattern`, `minLength`, `maxLength`) [completed]
**Description:** Validate string values against `pattern` regex, `minLength`, and `maxLength` from JSON Schema.
**Complexity:** Low
**Comment:** All three fields already parsed into `JsonSchema` struct but never checked in `schema_validation.rs`. Draft-04 keywords.
**Tier:** 1
### Numeric Constraints (`minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf`) [completed]
**Description:** Validate numeric values against bounds and divisibility constraints.
**Complexity:** Low
**Comment:** `minimum`/`maximum` already parsed but never validated. `exclusiveMinimum`/`exclusiveMaximum` need parsing (boolean in Draft-04, number in Draft-06+). `multipleOf` needs parsing. All Draft-04 keywords with Draft-06 evolution.
**Tier:** 1
### `const` Keyword [completed]
**Description:** Validate that a value matches a single fixed value specified by `const`.
**Complexity:** Low
**Comment:** Draft-06 keyword. Simple equality check against a single JSON value. Very common in real schemas — Kubernetes CRDs use `oneOf` + `const` patterns.
**Tier:** 1
### `not` Keyword [completed]
**Description:** Validate that a value does *not* match the given sub-schema.
**Complexity:** Low
**Comment:** Draft-04 keyword. Invert the validation result of a sub-schema. Straightforward composition — run validation, pass if diagnostics are produced.
**Tier:** 2
### `patternProperties` [completed]
**Description:** Match mapping keys against regex patterns and validate their values against corresponding schemas.
**Complexity:** Medium
**Comment:** Draft-04 keyword. Needs new field in `JsonSchema`, parsing, validation, and completion integration. Common in schemas that allow dynamic key names (e.g. Kubernetes labels, environment variables).
**Tier:** 2
### Array Constraints (`minItems`, `maxItems`, `uniqueItems`) [completed]
**Description:** Validate array length bounds and item uniqueness.
**Complexity:** Low
**Comment:** Draft-04 keywords. Need new fields in `JsonSchema` and straightforward validation checks on sequence length and item equality.
**Tier:** 2
### Object Cardinality (`minProperties`, `maxProperties`) [completed]
**Description:** Validate that a mapping has at least `minProperties` and at most `maxProperties` entries.
**Complexity:** Low
**Comment:** Draft-04 keywords. Mirror of `minItems`/`maxItems` for objects. New fields in `JsonSchema`, parsed in `parse_object_fields`, validated in `validate_mapping` via a `validate_mapping_constraints` helper.
**Tier:** 2
### `additionalItems` (Draft-04/07 Tuple Restriction) [completed]
**Description:** Restrict elements beyond a Draft-04/07 tuple prefix (`items` array form). `false` denies extra elements; a schema validates them.
**Complexity:** Low
**Comment:** Draft-04 keyword. Only active when `items` is an array (tuple mode) — suppressed when `prefixItems` (Draft 2020-12) is used instead. Reuses the `AdditionalProperties` enum. Validation extracted into a `validate_sequence` helper to keep `validate_node` under the line-length lint limit.
**Tier:** 2
### `dependencies` / `dependentRequired` / `dependentSchemas` [completed]
**Description:** Validate cross-property dependencies — when property A is present, require property B or validate against an additional schema.
**Complexity:** Medium
**Comment:** `dependencies` is Draft-04, split into `dependentRequired` and `dependentSchemas` in Draft 2019-09. Need to support both forms for backwards compatibility. Used in schemas with conditional requirements.
**Tier:** 2
### `propertyNames` [completed]
**Description:** Validate that all mapping keys match a given schema (typically a string schema with `pattern`).
**Complexity:** Low
**Comment:** Draft-06 keyword. Applies a schema to each key string in a mapping. Useful for enforcing key naming conventions.
**Tier:** 2
### `if` / `then` / `else` [completed]
**Description:** Conditional schema application — if a value matches the `if` schema, validate against `then`; otherwise validate against `else`.
**Complexity:** Medium
**Comment:** Draft-07 keyword. Used heavily in real-world schemas for polymorphic validation (e.g. "if type is X, require fields A and B"). Builds on existing composition validation infrastructure.
**Tier:** 2
### `contains` / `minContains` / `maxContains` [completed]
**Description:** Validate that an array contains at least one item matching a schema, with optional min/max count bounds.
**Complexity:** Medium
**Comment:** `contains` is Draft-06, `minContains`/`maxContains` added in Draft 2019-09. Needs sub-schema evaluation per array item with counting.
**Tier:** 2
### Color Provider [completed]
**Description:** Detect color values (hex codes, CSS named colors, RGB/HSL expressions) in YAML values and provide color picker integration via `textDocument/documentColor` and `textDocument/colorPresentation`.
**Complexity:** Medium
**Comment:** Format-agnostic LSP feature — applies to any YAML file with color values (theme configs, CI badge definitions, UI settings). Requires regex-based color detection and color format conversion.
**Tier:** 2
### `prefixItems` (Tuple Validation) [completed]
**Description:** Validate array items positionally — each array index validated against a different schema.
**Complexity:** Medium
**Comment:** Draft 2020-12 keyword replacing the Draft-04 tuple form of `items` (when `items` is an array). Needs new field and positional item validation logic.
**Tier:** 3
### `$anchor` / `$dynamicRef` / `$dynamicAnchor` [completed]
**Description:** Support named anchors and dynamic reference resolution across schema documents.
**Complexity:** High
**Comment:** Draft 2019-09 / 2020-12 keywords. `$anchor` names a schema location; `$dynamicRef`/`$dynamicAnchor` enable dynamic dispatch in recursive schemas. Requires changes to `$ref` resolution infrastructure.
**Tier:** 3
### `unevaluatedProperties` / `unevaluatedItems` [completed]
**Description:** Reject properties or items not evaluated by any sub-schema in `allOf`/`anyOf`/`oneOf`/`if`/`then`/`else`.
**Complexity:** High
**Comment:** Draft 2019-09 keywords. Requires tracking which properties/items were "evaluated" during composition — a cross-cutting concern that touches the entire validation walk. The hardest keywords to implement correctly.
**Tier:** 3
### `$vocabulary` [completed]
**Description:** Declare which JSON Schema vocabularies a schema uses, enabling vocabulary-aware validation.
**Complexity:** High
**Comment:** Draft 2019-09 keyword. Meta-schema feature that controls which keyword sets are recognized. Affects schema parsing — requires vocabulary registry and conditional keyword handling.
**Tier:** 3
---
### Proxy Support for Schema Fetching [completed]
**Description:** Allow users to configure an HTTP proxy for schema fetching, supporting corporate environments behind firewalls.
**Complexity:** Low
**Comment:** `ureq` supports proxy configuration. Added `httpProxy` setting plumbed through to the fetch layer.
**Tier:** 3
### Range Formatting [completed]
**Description:** Implement `textDocument/rangeFormatting` to format a selected region of a YAML document.
**Complexity:** Low
**Comment:** Depends on full document formatting infrastructure. Full document formatted internally, requested range lines returned as edits.
**Tier:** 3
### Formatter Conformance — 100% Round-Trip [completed]
**Description:** The formatter achieves 100% conformance on the
YAML Test Suite: all 351 stream cases and all 375 loader cases pass
after a format-then-parse round-trip. Formatted output re-parses to
an AST identical to the original.
**Complexity:** High
**Comment:** Conformance required fixing document marker handling,
block scalar edge cases, and quoting decisions for reserved keywords.
The `rlsp-yaml-parser` loader was extended with `explicit_start` and
`explicit_end` fields so the formatter can faithfully preserve `---`
and `...` markers.
**Tier:** 1
### Document Marker Handling in Formatter [completed]
**Description:** The formatter preserves explicit `---` document-start
and `...` document-end markers from the source. When the original
document used explicit markers, formatted output includes them; when
no markers were present, none are added. The `Document<Span>` AST
exposes `explicit_start` and `explicit_end` boolean fields populated
by the loader.
**Complexity:** Low
**Comment:** Required for formatter round-trip conformance — stripping
or adding markers changes the YAML document structure as observed by
strict parsers. Sourced from the parser AST rather than scanning raw
text.
**Tier:** 1
### Full Document Formatting [completed]
**Description:** Implement `textDocument/formatting` to reformat entire YAML documents using Wadler-Lindig pretty-printing engine.
**Complexity:** High
**Comment:** Built on `rlsp-fmt`, a workspace crate implementing the Wadler-Lindig algorithm. Configurable via `formatPrintWidth`, `formatSingleQuote`, and `formatPreserveQuotes` settings.
**Tier:** 3
### SchemaStore Integration [completed]
**Description:** Automatically fetch schema associations from SchemaStore so common file types validate without user configuration.
**Complexity:** Medium
**Comment:** Fetches SchemaStore catalog and matches filenames against `fileMatch` patterns. High user value — most YAML files have a schema on SchemaStore.
**Tier:** 3
### Kubernetes-Aware Schema Resolution [completed]
**Description:** Auto-detect Kubernetes manifests by inspecting `apiVersion` and `kind` fields and fetch the correct schema from yannh/kubernetes-json-schema.
**Complexity:** Medium
**Comment:** Motivated by redhat-developer/yaml-language-server#1213. Resolves version-specific schemas automatically using `kubernetesVersion` setting.
**Tier:** 3
### File Watcher Registration [completed]
**Description:** Register `workspace/didChangeWatchedFiles` capability so the server reacts to file changes without relying on the editor extension.
**Complexity:** Low
**Comment:** Registers for `**/*.yaml` and `**/*.yml` file patterns.
**Tier:** 3
### Schema Association Configuration [completed]
**Description:** More flexible file-to-schema mapping via workspace `schemas` setting with glob patterns.
**Complexity:** Medium
**Comment:** Maps schema URL to glob patterns. Combined with modeline and SchemaStore for multi-source schema resolution.
**Tier:** 3
### Semantic Highlighting [completed]
**Description:** Provide semantic tokens for richer syntax highlighting of keys, values, anchors, aliases, tags, and comments.
**Complexity:** High
**Comment:** Full SemanticTokensProvider protocol — token types, legends, delta encoding. 8 token types, 1 modifier.
**Tier:** 3
### Schema Disable via Modeline [completed]
**Description:** Allow users to disable schema validation for a specific file using `# yaml-language-server: $schema=none`.
**Complexity:** Low
**Comment:** Added sentinel value check to existing modeline parser.
**Tier:** 2
### Hover Formatting Improvements [completed]
**Description:** Format JSON examples in hover with proper indentation instead of single-line JSON stringify output.
**Complexity:** Low
**Comment:** Improved hover display with formatted schema sections, max 3 examples, truncated descriptions.
**Tier:** 2
### Multi-Required Snippet Completion [completed]
**Description:** When completing a key, offer a snippet that inserts all remaining required properties at once with placeholder values.
**Complexity:** Medium
**Comment:** Generates snippets with placeholders for all missing required properties in a single completion item.
**Tier:** 2
### Exclude Deprecated Properties from Completion [completed]
**Description:** Mark deprecated schema properties with strikethrough in completion results.
**Complexity:** Low
**Comment:** Checks the `deprecated` flag in JSON Schema during completion item construction.
**Tier:** 1
### Expected Properties in Diagnostic Messages [completed]
**Description:** List expected property names in "missing required property" diagnostics.
**Complexity:** Low
**Comment:** Enriched `schemaRequired` diagnostic message text with property name list.
**Tier:** 1
### Duplicate Key Detection [completed]
**Description:** Emit diagnostics when duplicate keys are found in a YAML mapping.
**Complexity:** Medium
**Comment:** Text-based detection (parsed ASTs deduplicate keys). Document-scoped with flow-style and sequence-item scope handling.
**Tier:** 1
### Tab-to-Spaces On-Type Formatting [won't implement]
**Description:** Convert tab characters to spaces on-type.
**Complexity:** Low
**Comment:** Most editors handle tab-to-spaces natively. Risk of conflicting with editor settings.
**Tier:** 4
### Multiple Schemas per File [won't implement]
**Description:** Support different schemas for different documents within a multi-document YAML file or sub-values within a document.
**Complexity:** High
**Comment:** Requires significant architecture changes for per-sub-value schema assignment.
**Tier:** 4
### Embedded Language Support [won't implement]
**Description:** Support syntax highlighting and validation for embedded languages (JSON, SQL, etc.) within YAML string values.
**Complexity:** High
**Comment:** Very high effort — language embedding, delegating to sub-LSPs. Niche use case.
**Tier:** 4
### Localized Validation Messages [won't implement]
**Description:** Internationalize diagnostic messages for user locale support.
**Complexity:** High
**Comment:** Cross-cutting concern touching every diagnostic string. High maintenance cost for a developer-focused tool.
**Tier:** 4