Skip to content

Add schema-driven frontmatter autocomplete to CM6 editor#16753

Closed
Mossaka wants to merge 2 commits intomainfrom
feat/cm6-autocomplete
Closed

Add schema-driven frontmatter autocomplete to CM6 editor#16753
Mossaka wants to merge 2 commits intomainfrom
feat/cm6-autocomplete

Conversation

@Mossaka
Copy link
Collaborator

@Mossaka Mossaka commented Feb 19, 2026

Summary

  • Wires the existing autocomplete.js (context parser + suggestion generator) into CodeMirror 6 as a CompletionSource
  • Adds autocomplete-data.json (57KB schema data) with all frontmatter keys, types, descriptions, and enum values
  • Autocomplete only activates inside the YAML frontmatter region (between --- delimiters) — no suggestions in the markdown body
  • Supports both key completion (e.g., typing en suggests engine) and value completion (e.g., after engine: suggests copilot, claude, codex, custom)

How it works

  1. autocomplete-data.json is fetched on page load (async, degrades gracefully if unavailable)
  2. On each keystroke in the frontmatter, parseFrontmatterContext() determines the cursor's nesting path, mode (key vs value), typed prefix, and sibling keys already present
  3. getSuggestions() walks the schema tree and returns matching suggestions, filtering out already-used siblings
  4. The CM6 adapter maps these to Completion objects with labels, type annotations, descriptions, and snippets

Testing

  • Type a frontmatter key like en → suggestions for engine, env appear
  • Type engine: then space → enum values (copilot, claude, codex, custom) appear
  • Ctrl+Space manually triggers autocomplete on empty frontmatter lines
  • Autocomplete does NOT trigger below the closing ---

🤖 Generated with Claude Code

Wire the existing autocomplete system (parseFrontmatterContext + getSuggestions)
into a CM6 CompletionSource so the playground editor suggests frontmatter keys
and enum values as you type between the --- delimiters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 19, 2026 04:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds schema-driven YAML frontmatter autocomplete to the CodeMirror 6 editor by loading a generated schema JSON at runtime and mapping existing context-parsing + suggestion logic into a CM6 CompletionSource.

Changes:

  • Integrates CM6 autocompletion with a frontmatter-only completion source.
  • Adds frontmatter context parsing + schema-driven suggestion generation utilities.
  • Introduces autocomplete-data.json containing the frontmatter schema (keys/types/descriptions/enums) used for suggestions.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
docs/public/editor/editor.js Loads schema JSON and wires a CM6 CompletionSource to provide frontmatter-only suggestions.
docs/public/editor/autocomplete.js Implements frontmatter context parsing and schema-driven suggestion generation (plus additional UI code).
docs/public/editor/autocomplete-data.json Adds the schema dataset used to drive key/value completions.
Comments suppressed due to low confidence (2)

docs/public/editor/autocomplete.js:111

  • Sibling-key collection uses trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/), which misses keys on list-item lines like - key: .... In arrays of objects this prevents siblings from including keys already present on the - key: line, so duplicate-key suggestions won’t be filtered.

Consider updating this regex (and the similar one in the backward path check) to accept an optional leading - list marker.

      // Check this is at the same nesting level by verifying same parent path
      // Simple heuristic: same indent = same level (works for well-formatted YAML)
      const keyMatch = trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/);
      if (keyMatch) {
        // Verify same parent: walk backward from line i to build its path

docs/public/editor/autocomplete.js:5

  • The module header comment says this autocomplete is for use “inside a plain <textarea>”, but in this PR the exported parser/suggestion functions are used by the CodeMirror 6 adapter. Updating the comment to reflect the current usage (or splitting textarea-specific UI into a separate module) would avoid confusion for future maintainers.
 * Frontmatter autocomplete for the gh-aw playground editor.
 *
 * Provides schema-driven suggestions for YAML frontmatter keys and values
 * inside a plain <textarea>.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to +86
// This line is a parent — extract its key
const keyMatch = trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parent-key extraction regex (trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/)) won’t match YAML keys that occur on list-item lines like - key: .... That can cause path construction to skip parents when the cursor is inside an array-of-objects item.

Consider allowing an optional leading list marker (e.g. ^(?:-\s+)?([a-zA-Z0-9_-]+)\s*:).

This issue also appears on line 107 of the same file.

Suggested change
// This line is a parent — extract its key
const keyMatch = trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/);
// This line is a parent — extract its key (optionally after a list marker)
const keyMatch = trimmed.match(/^(?:-\s+)?([a-zA-Z0-9_-]+)\s*:/);

Copilot uses AI. Check for mistakes.
Comment on lines +231 to +235
function getValueSuggestions(node, context, rootNode) {
if (!context.currentKey) return [];

const entry = node[context.currentKey];
if (!entry || !entry.enum) return [];
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getValueSuggestions takes a rootNode parameter but never uses it. Removing the unused parameter (and the corresponding argument passed from getSuggestions) would simplify the API and avoid confusion about intended behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +252 to +256
// ---------------------------------------------------------------------------

export class AutocompleteDropdown {
constructor(textarea) {
this.textarea = textarea;
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AutocompleteDropdown (and its DOM/event handling code) is exported here but isn’t referenced anywhere in the CM6 integration (only parseFrontmatterContext/getSuggestions are imported). Shipping unused UI code increases bundle size and maintenance surface.

Consider removing it or moving textarea-specific UI into a separate module that’s only loaded when needed.

This issue also appears on line 2 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +35
const doc = context.state.doc.toString();
const pos = context.pos;
const ctx = parseFrontmatterContext(doc, pos);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frontmatterCompletionSource converts the entire CM document to a string (context.state.doc.toString()) and then parseFrontmatterContext re-splits/scans the full text on every completion query. Since CM can query completion sources frequently (often per-keystroke), this is O(doc length) work that can cause noticeable lag on larger files.

Consider rewriting the context extraction to operate on state.doc/lineAt without materializing the full document each time, and/or caching frontmatter start/end positions and only scanning within the frontmatter range.

Copilot uses AI. Check for mistakes.
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.

2 participants