/* Copyright 2026 Marimo. All rights reserved. */ import type { EditorView } from "@codemirror/view"; import type { QuotePrefixKind } from "@marimo-team/smart-cells"; import { InfoIcon, PaintRollerIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Tooltip, TooltipProvider } from "@/components/ui/tooltip"; import { normalizeName } from "@/core/cells/names"; import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines"; import { useAutoGrowInputProps } from "@/hooks/useAutoGrowInputProps"; import { cellIdState } from "../../cells/state"; import { formatSQL } from "../../format"; import { languageAdapterState } from "../extension"; import { MarkdownLanguageAdapter } from "../languages/markdown"; import { SQLLanguageAdapter, updateSQLDialectFromConnection, } from "../languages/sql/sql"; import { type LanguageMetadata, languageMetadataField, updateLanguageMetadata, } from "../metadata"; import type { LanguageMetadataOf } from "../types"; import { getQuotePrefix, MarkdownQuotePrefixTooltip } from "./markdown"; import { SQLEngineSelect, SQLModeSelect } from "./sql"; const Divider = () =>
; export const LanguagePanelComponent: React.FC<{ view: EditorView; }> = ({ view }) => { const { spanProps, inputProps } = useAutoGrowInputProps({ minWidth: 50 }); const languageAdapter = view.state.field(languageAdapterState); const cellId = view.state.facet(cellIdState); let actions: React.ReactNode =
; let showDivider = false; // Send noop update code event, which will trigger an update to the new output variable name const triggerUpdate = (update: Partial) => { view.dispatch({ effects: updateLanguageMetadata.of(update), changes: { from: 0, to: view.state.doc.length, insert: view.state.doc.toString(), }, }); }; if (languageAdapter instanceof SQLLanguageAdapter) { type Metadata1 = LanguageMetadataOf; const metadata = view.state.field(languageMetadataField) as Metadata1; showDivider = true; const sanitizeAndTriggerUpdate = ( e: React.SyntheticEvent, ) => { // Normalize the name to a valid variable name const name = normalizeName(e.currentTarget.value, false); e.currentTarget.value = name; triggerUpdate({ dataframeName: name, }); }; const switchEngine = (engine: ConnectionName) => { triggerUpdate({ engine }); updateSQLDialectFromConnection(view, engine); }; actions = (
{metadata.engine === DUCKDB_ENGINE && }
); } if (languageAdapter instanceof MarkdownLanguageAdapter) { showDivider = true; type Metadata2 = LanguageMetadataOf; const metadata = view.state.field(languageMetadataField) as Metadata2; let { quotePrefix } = metadata; // Handle the case where the quote prefix is not set if (quotePrefix === undefined) { quotePrefix = "r"; triggerUpdate({ quotePrefix }); } const togglePrefix = ( prefix: QuotePrefixKind, checked: boolean | string, ) => { if (typeof checked !== "boolean") { return; } const newPrefix = getQuotePrefix({ currentQuotePrefix: quotePrefix, checked, prefix, }); triggerUpdate({ quotePrefix: newPrefix, }); }; actions = (
r { togglePrefix("r", checked); }} />
f { togglePrefix("f", checked); }} />
}>
); } return (
{actions} {showDivider && } {languageAdapter.type}
); };