Files
micronomicon/backend/uframe/keywords.py
2026-04-01 12:16:16 +02:00

261 lines
9.6 KiB
Python

"""µFrame Keyword Registrations — single source of truth for all DSL keywords.
Each keyword is registered here with its metadata (section, detail, snippet,
highlight values). The actual parse/measure/layout/paint/codegen functions
remain in their respective modules for now — this file serves as the
registry that the frontend reads via GET /api/dsl-meta.
To add a new keyword:
1. Define its IR node in ir.py
2. Add a register_keyword() call here
3. Add parse logic in parser.py
4. Add measure/layout/paint logic in their respective files
5. That's it — syntax highlighting and slash commands auto-update from the registry
"""
from uframe.registry import register_keyword, ALL_THEME_NAMES
from uframe.ir import (
Page, Box, Row, Col, Spacer, Pad,
Heading, Text, Label, Divider, Link, ListNode, ListItem,
Gauge, Sparkline, Status, Table,
Form, Field, Password, Radio, Checkbox, FormButton,
Let, Source, IfBlock, ForLoop, CacheControl, OnSubmit, StateDecl,
BigTitle,
ComponentDef, ComponentUse,
)
from uframe.themes import BUILTIN_THEMES
# ---------------------------------------------------------------------------
# Layout
# ---------------------------------------------------------------------------
register_keyword("page", node_class=Page, section="Layout",
detail='page "Title" 64', snippet='page "${title}" ${width:64}',
is_container=True)
register_keyword("box", node_class=Box, section="Layout",
detail='box light "Title"', snippet='box ${weight:light} "${title}"',
highlight_values=["light", "heavy", "double", "rounded"],
is_container=True)
register_keyword("row", node_class=Row, section="Layout",
detail="row [gap]", snippet="row ${gap:2}",
is_container=True)
register_keyword("col", node_class=Col, section="Layout",
detail="col [width]", snippet="col ${width}",
is_container=True)
register_keyword("spacer", node_class=Spacer, section="Layout",
detail="spacer [lines]", snippet="spacer",
is_leaf=True)
register_keyword("pad", node_class=Pad, section="Layout",
detail="pad t r b l", snippet="pad ${top:1} ${right:1} ${bottom:1} ${left:1}",
is_container=True)
# ---------------------------------------------------------------------------
# Content
# ---------------------------------------------------------------------------
register_keyword("heading", node_class=Heading, section="Content",
detail='heading 1 "Text"', snippet='heading ${level:1} "${text}"',
is_leaf=True)
register_keyword("text", node_class=Text, section="Content",
detail='text "Content"', snippet='text "${content}"',
is_leaf=True)
register_keyword("label", node_class=Label, section="Content",
detail='label "Key" "Value"', snippet='label "${key}" "${value}"',
is_leaf=True)
register_keyword("divider", node_class=Divider, section="Content",
detail="divider heavy", snippet="divider ${style:light}",
highlight_values=["light", "heavy", "double", "dash", "dot"],
is_leaf=True)
register_keyword("link", node_class=Link, section="Content",
detail='link "Text" "/path.mu"', snippet='link "${display}" "${dest}"',
is_leaf=True)
register_keyword("list", node_class=ListNode, section="Content",
detail="list bullet", snippet='list ${style:bullet}\n item "${entry}"',
highlight_values=["bullet", "dash", "number", "arrow"],
is_container=True)
register_keyword("item", node_class=ListItem, section="",
detail="", snippet="", # not shown in slash commands (child of list)
is_leaf=True)
# ---------------------------------------------------------------------------
# Data Visualization
# ---------------------------------------------------------------------------
register_keyword("gauge", node_class=Gauge, section="Data",
detail="gauge label val max width",
snippet='gauge "${label}" ${value} ${max:100} ${width:28} warn=${warn:75} crit=${crit:90}',
is_leaf=True)
register_keyword("sparkline", node_class=Sparkline, section="Data",
detail="sparkline label values width",
snippet='sparkline "${label}" "${values}" ${width:20}',
is_leaf=True)
register_keyword("status", node_class=Status, section="Data",
detail="status label state",
snippet='status "${label}" ${state:online}',
highlight_values=["online", "offline", "degraded", "unknown", "alert"],
is_leaf=True)
register_keyword("table", node_class=Table, section="Data",
detail="table + columns + rows",
snippet='table "Title"\n columns "Name" 20 | "Value" 10\n row "entry" | "data"',
is_leaf=True) # table handles its own children (columns/row pseudo-nodes)
register_keyword("columns", section="",
detail="", snippet="") # child of table, not shown in slash commands
# ---------------------------------------------------------------------------
# Big Text
# ---------------------------------------------------------------------------
register_keyword("bigtitle", node_class=BigTitle, section="Content",
detail='bigtitle "TEXT" block',
snippet='bigtitle "${text}" ${font:block}',
highlight_values=["block", "thin", "pixel"],
is_leaf=True)
# ---------------------------------------------------------------------------
# Style
# ---------------------------------------------------------------------------
register_keyword("align", section="Style",
detail="align center", snippet="align ${align:center}",
highlight_values=["left", "center", "right"],
is_style_directive=True)
register_keyword("color", section="Style",
detail="color hex", snippet="color ${hex}",
is_style_directive=True)
register_keyword("bg", section="Style",
detail="", snippet="",
is_style_directive=True)
register_keyword("bold", section="Style",
detail="bold", snippet="bold",
is_style_directive=True)
register_keyword("italic", section="Style",
detail="", snippet="",
is_style_directive=True)
register_keyword("underline", section="Style",
detail="", snippet="",
is_style_directive=True)
# ---------------------------------------------------------------------------
# Forms
# ---------------------------------------------------------------------------
register_keyword("form", node_class=Form, section="Form",
detail='form "name"', snippet='form "${name}"',
is_container=True)
register_keyword("field", node_class=Field, section="Form",
detail='field "name" 24 "placeholder"',
snippet='field "${name}" ${width:24} "${placeholder}"',
is_leaf=True)
register_keyword("password", node_class=Password, section="Form",
detail='password "name" 24 "placeholder"',
snippet='password "${name}" ${width:24} "${placeholder}"',
is_leaf=True)
register_keyword("radio", node_class=Radio, section="Form",
detail='radio "group" "A" | "B" | "C"',
snippet='radio "${group}" "${opt1}" | "${opt2}"',
is_leaf=True)
register_keyword("checkbox", node_class=Checkbox, section="Form",
detail='checkbox "name" "Label"',
snippet='checkbox "${name}" "${label}"',
is_leaf=True)
register_keyword("button", node_class=FormButton, section="Form",
detail='button "Label" "/action"',
snippet='button "${label}" "${dest}"',
is_leaf=True)
# ---------------------------------------------------------------------------
# Dynamic
# ---------------------------------------------------------------------------
register_keyword("let", node_class=Let, section="Dynamic",
detail='let name = "value"', snippet='let ${name} = "${value}"',
is_metadata=True)
register_keyword("source", node_class=Source, section="Dynamic",
detail='source name : shell "cmd"',
snippet='source ${name} : shell "${command}"',
highlight_values=["shell", "file", "json", "python", "rns", "param"],
is_metadata=True)
register_keyword("if", node_class=IfBlock, section="Dynamic",
detail="if $var > threshold", snippet="if ${condition}",
is_container=True)
register_keyword("elif", section="Dynamic",
detail="", snippet="")
register_keyword("else", section="Dynamic",
detail="", snippet="")
register_keyword("for", node_class=ForLoop, section="Dynamic",
detail="for item in $list", snippet='for ${var} in ${iterable}',
is_container=True)
register_keyword("cache", node_class=CacheControl, section="Dynamic",
detail="cache 0", snippet="cache ${seconds:0}",
is_metadata=True)
register_keyword("on_submit", node_class=OnSubmit, section="Dynamic",
detail='on_submit "form"', snippet='on_submit "${form_name}"',
is_container=True)
register_keyword("state", node_class=StateDecl, section="Dynamic",
detail='state "name" "/path.json"',
snippet='state "${name}" "${path}"',
is_metadata=True)
register_keyword("set", section="Dynamic", detail="", snippet="")
register_keyword("append", section="Dynamic", detail="", snippet="")
register_keyword("prepend", section="Dynamic", detail="", snippet="")
# ---------------------------------------------------------------------------
# Themes
# ---------------------------------------------------------------------------
register_keyword("theme", section="Theme",
detail="", snippet="",
is_style_directive=True)
# Register each built-in theme as a named entry
for _theme_name, _theme_def in BUILTIN_THEMES.items():
register_keyword(f"theme_{_theme_name}", section="Theme",
detail=f"{_theme_def.description}",
snippet=f"theme {_theme_name}")
ALL_THEME_NAMES.append(_theme_name)
# ---------------------------------------------------------------------------
# Components
# ---------------------------------------------------------------------------
register_keyword("component", node_class=ComponentDef, section="",
detail="", snippet="",
is_container=True)
register_keyword("use", section="",
detail="", snippet="")