Skip to content

Docs Phase 1: rich function reference in CM6 hover and docs pane #313

Description

@BorisTyshkevich

Parent: #60

Goal

Use the connected ClickHouse server's available system.functions metadata to provide version-exact function and aggregate-function documentation in the CodeMirror 6 editor.

This phase upgrades the existing compact CM6 hover and adds a persistent non-modal documentation pane. It does not add non-function entity kinds or system.documentation Markdown rendering.

Version and capability policy

system.functions and portions of its documentation metadata exist in releases earlier than 26.6. Therefore this phase must not use a hard serverVersion >= 26.6 gate.

The parsed server version may be recorded for diagnostics and tests, but actual table and column availability is authoritative.

  • Detect system.functions and each required/optional column once per connection through system.columns or one silent best-effort probe.
  • Build queries only from columns confirmed available.
  • Missing rich columns degrade field-by-field; they do not make the whole source unavailable.
  • Missing table, denied access, or incompatible required shape becomes cached unavailable for that connection.
  • Transient auth/network failure remains retryable.
  • Do not infer that all rich fields exist merely because the server is 26.6 or newer.
  • Do not skip system.functions merely because the server is older than 26.6.

The 26.6 hard lower bound applies only to system.documentation in #315.

Current foundation

The CM6 adapter already owns hoverTooltip(hoverSourceFor(app)), completion info, syntax-tree literal suppression, and lazy catalog documentation lookup. SchemaCatalogService already owns reference loading and a per-connection documentation cache.

Extend those seams; do not add a second editor hover implementation or move documentation state into the full App controller.

Documentation contracts

Add neutral contracts under src/core/doc-types.ts or equivalent:

type DocKind = 'function' | 'aggregate-function';

interface DocTarget {
  kind: DocKind;
  name: string;
}

type DocLookup<T> =
  | { status: 'found'; value: T }
  | { status: 'missing' }
  | { status: 'unavailable' };

interface DocSummary {
  target: DocTarget;
  title: string;
  signature: string;
  summary: string;
  introducedIn?: string;
  aliasTo?: string;
}

interface DocEntry extends DocSummary {
  description?: string;
  arguments?: string;
  parameters?: string;
  returnedValue?: string;
  examples?: string;
  categories: string[];
  deterministic?: boolean | null;
  higherOrder?: boolean | null;
}

missing is a successful no-match and is cacheable. unavailable is an unsupported or denied capability and is cacheable. Transient failure creates no durable lookup entry.

Catalog and loader ownership

Replace the function-name-only entityDoc() seam with target-aware methods on SchemaCatalogService:

docSummary(target: DocTarget): Promise<DocLookup<DocSummary>>;
docEntry(target: DocTarget): Promise<DocLookup<DocEntry>>;

Requirements:

  • capability-detect system.functions and its columns once per connection;
  • cache by kind:name, not name alone;
  • deduplicate concurrent requests;
  • tie every request to a connection generation so an old response cannot repopulate caches after reconnect/invalidate;
  • invalidate() clears capabilities, summaries, entries, and pending generations;
  • keep bulk reference loading small; full bodies/examples remain lazy;
  • no SQL runs from the editor keystroke path;
  • normalize rows before they reach UI code.

Function and alias resolution

  • Use is_aggregate when available to distinguish scalar and aggregate functions.
  • Function lookup is case-insensitive using the current exact/lower/upper behavior.
  • When alias_to is available and non-empty, show Alias of <canonical>.
  • Canonical navigation must prevent alias cycles and missing-target recursion.
  • User-defined or partially documented functions degrade to current signature/summary behavior.

CM6 hover and completion info

Extend hoverSourceFor() in src/editor/codemirror-adapter.ts.

Hover remains compact:

  • signature;
  • one-line summary;
  • optional since vX badge;
  • optional alias notice;
  • accessible Open reference button.

Continue suppressing hover inside comments, strings, and quoted identifiers through the CM6 syntax tree. Do not issue SQL until CM6 materializes tooltip/info UI or the pane is explicitly opened. Async results must verify the tooltip and editor are still live before updating DOM.

Completion infoFor() may show the same summary and action. Hover and completion info must share rendering helpers.

Keyboard command

Register F1 in the CM6 keymap as Open reference for symbol.

  • Use selection.main.head.
  • Return false when no function target resolves.
  • Prevent browser default only when handled.
  • Tooltip, completion, and F1 call the same application action.
  • Add F1 to the shortcuts dialog.

The Phase 1 classifier handles function-call/known-function recognition and literal suppression only. It is pure and issues no SQL.

Documentation pane

Add a Workbench-owned, persistent, non-modal right-side pane.

  • no backdrop or focus trap;
  • editor remains usable;
  • one pane instance, with new targets replacing content;
  • bounded resize;
  • close button and Escape while focus is inside;
  • restore initiating editor focus where possible;
  • labelled role="complementary" or region;
  • distinct loading, unavailable, missing, and transient-error states;
  • retry for transient failure.

Do not require the schema graph's bottom detail pane to share this geometry.

Entry rendering

Render available structured fields directly: title, kind, signature, introduced version, categories, description, arguments, aggregate parameters, returned value, deterministic/higher-order badges, and copyable examples.

Extract reusable ClickHouse CM6 language/dialect construction so examples use the same SQL highlighting. Build DOM nodes, never innerHTML; preserve text and copy examples exactly.

Fallback behavior

On any server version where the table or fields are absent or denied:

  • retain current server/built-in completion and highlighting;
  • retain current compact signature/first-line description where available;
  • hide unsupported rich sections;
  • show no capability toast or banner.

Tests

Cover version-independent capability detection, partial-column query construction, denied/old/custom-server fallback, row normalization, alias cycles, lookup caching semantics, concurrent deduplication, reconnect stale-response rejection, compact hover, literal suppression, stale tooltip cleanup, F1 handling, completion/hover parity, pane lifecycle, example copy/highlighting, and no request during ordinary typing.

Include explicit cases for:

  • pre-26.6 server with usable system.functions metadata;
  • 26.6+ server missing one or more optional columns;
  • version string unavailable but capability probe succeeds;
  • 26.6+ access denied.

Acceptance criteria

  • Function docs are capability-gated by actual system.functions table/columns, not a 26.6 version check.
  • Pre-26.6 servers use every supported function metadata field.
  • Missing optional columns degrade field-by-field.
  • CM6 hover stays compact and exposes Open reference.
  • F1 opens the same entry.
  • The pane renders all available structured fields and copyable examples.
  • Cache keys include kind/name and are reconnect-safe.
  • Unsupported/denied sources degrade silently.
  • No SQL runs per keystroke.
  • No unsafe HTML or new Markdown dependency is introduced.
  • Unit, integration, CM6, and browser accessibility tests pass.

Non-goals

  • formats, engines, data types, settings, table functions, or other kinds;
  • system.documentation;
  • general Markdown parsing;
  • schema-tree documentation actions;
  • latest public-doc links;
  • replacing autocomplete or CM6;
  • one universal geometry component for all detail panes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions