diff --git a/src/app/services/spec-dataset-hints.ts b/src/app/services/spec-dataset-hints.ts index 64a9c70..7bdd77d 100644 --- a/src/app/services/spec-dataset-hints.ts +++ b/src/app/services/spec-dataset-hints.ts @@ -10,8 +10,11 @@ * - **Hover** — a column's inferred type + cardinality/range (from the stored * profile); over a `calculate`/`filter`/`expr` string, a live validity check * via core/expr-validate. Monaco merges these with the schema's own hovers. - * - **Inlay hints** — a faint `: ` beside each `field`, annotation without - * touching the text. + * - **Inlay hints** — a faint `·` beside each `field` (the column's + * raw type: number/string/date/boolean), annotation without touching the text. + * Deliberately the *data* type, not the encoding `type` — they share the line, + * so a `: quantitative` here would read as annotating the adjacent `"type"`, + * which the hint never describes. * * All three read the active draft's bound dataset (services/active-dataset) and * the cursor's JSON context (core/spec-cursor) at provide-time via `getState()` — @@ -22,10 +25,8 @@ */ import * as monaco from 'monaco-editor/esm/vs/editor/edcore.main'; -import { defaultFieldType } from '@core/chart-builder'; import { validateExpression } from '@core/expr-validate'; import { stringValueAtOffset, valueKeyAtOffset } from '@core/spec-cursor'; -import type { ColumnType } from '@core/type-inference'; import { useSnippetStore } from '../stores/SnippetStore'; import { availableFieldsAt, @@ -40,15 +41,14 @@ const FIELD_KEYS = new Set(['field', 'groupby']); /** Property values that hold a Vega expression (where the validity check fires). */ const EXPR_KEYS = new Set(['calculate', 'filter', 'expr']); -/** A short type label for a source field; null type (derived) is shown elsewhere. */ -const typeLabel = (type: ColumnType): string => defaultFieldType(type); - /** Markdown hover for a field hint: type + stats for source, a note for derived. */ function fieldHoverContents(hint: FieldHint, info: DataInfo): { value: string }[] { if (hint.derived || hint.type === null) { return [{ value: `**${hint.name}** · _derived by a transform_` }]; } - const lines = [`**${hint.name}** · \`${typeLabel(hint.type)}\``]; + // The column's raw data type (number/string/date/boolean) — same vocabulary as + // the inlay hint, not the Vega-Lite encoding `type` the user declares. + const lines = [`**${hint.name}** · \`${hint.type}\``]; const stat = info.columnStats.find((s) => s.name === hint.name); if (stat) { if (stat.numericExtent) @@ -91,7 +91,7 @@ export function configureSpecDatasetHints(): void { kind: f.derived ? monaco.languages.CompletionItemKind.Variable : monaco.languages.CompletionItemKind.Field, - detail: f.derived || f.type === null ? 'derived field' : typeLabel(f.type), + detail: f.derived || f.type === null ? 'derived field' : f.type, insertText: f.name, range, })), @@ -167,7 +167,11 @@ export function configureSpecDatasetHints(): void { if (!type) continue; // unknown or derived (no type to annotate) hints.push({ position: { lineNumber: line, column: match.index + match[0].length + 1 }, - label: `: ${typeLabel(type)}`, + // The column's raw data type (number/string/date/boolean), not the + // Vega-Lite encoding `type`: a `: quantitative` here would read as an + // annotation of the adjacent `"type"`, which the hint never describes. + // The leading `·` marks it as a data fact about the field, not JSON syntax. + label: `·${type}`, kind: monaco.languages.InlayHintKind.Type, paddingLeft: true, });