REAL SHOWCASE SOURCEcode-editor-clinical-dsl

1 个文件 · 81 行 · TypeScript

// ===== showcase/src/examples/components/code_editor.ts ===== import {  RenderButton,  RenderCodeEditor,  RenderPageHeader,  RenderStackPanel,  RenderText,  RenderWrapPanel,  type CodeEditorLanguageAdapter,  type CodeEditorSemanticToken,} from 'ds-ui' const source = ['规则 儿童禁用', '如果 患者.年龄 小于 18', '则 提醒 禁用该药品'].join('\n') function semanticTokens(value: string): CodeEditorSemanticToken[] {  const tokens: CodeEditorSemanticToken[] = []  value.split(/\r?\n/).forEach((line, lineIndex) => {    for (const [text, type] of [['规则', 'keyword'], ['如果', 'keyword'], ['则', 'keyword'], ['提醒', 'action'], ['患者', 'variable'], ['年龄', 'field'], ['小于', 'operator']] as const) {      const column = line.indexOf(text)      if (column >= 0) tokens.push({ type, range: { start: { line: lineIndex, column }, end: { line: lineIndex, column: column + text.length } } })    }  })  return tokens} function languageAdapter(): CodeEditorLanguageAdapter {  return {    getDiagnostics(value) {      if (value.includes('提醒')) return []      return [{ range: { start: { line: 2, column: 0 }, end: { line: 2, column: 2 } }, severity: 'warning', message: '规则动作建议包含提醒', source: 'clinical-dsl' }]    },    getSemanticTokens: value => semanticTokens(value),    getCompletions: () => [      { label: '患者.年龄', kind: 'field', detail: 'number' },      { label: '患者.诊断', kind: 'field', detail: 'string[]' },      { label: '医嘱.药品名称', kind: 'field', detail: 'string' },      { label: '提醒', kind: 'action', detail: 'action' },    ],    getHover(_value, position) {      return position.line === 1        ? {            label: '患者.年龄',            type: 'number',            detail: '患者字段',            documentation: '当前患者年龄,单位为岁。',            range: { start: { line: position.line, column: 3 }, end: { line: position.line, column: 8 } },          }        : null    },    formatDocument: value => value.split(/\r?\n/).map(line => line.trim()).filter(Boolean).join('\n'),  }} export function createCodeEditorExample(): RenderStackPanel {  const status = new RenderText('语言服务已接入:诊断、语义高亮、补全、Hover 和格式化。', { role: 'secondary' })  const editor = new RenderCodeEditor({    value: source,    language: 'clinical-dsl',    fontSize: 14,    lineHeight: 22,    folding: false,    diagnosticsDebounceMs: 0,    languageAdapter: languageAdapter(),    onDiagnosticsChange: diagnostics => { status.text = `诊断 ${diagnostics.length} 项` },  })  editor.height = 440  const actions = new RenderWrapPanel({ spacing: 8, runSpacing: 8 })  actions.addChild(new RenderButton({ label: '立即校验', onClick: () => { void editor.validateNow().then(items => { status.text = `校验完成:${items.length} 项诊断` }) } }))  actions.addChild(new RenderButton({ label: '触发补全', variant: 'primary', onClick: () => { void editor.triggerCompletion().then(items => { status.text = `语言服务返回 ${items.length} 个补全项` }) } }))  actions.addChild(new RenderButton({ label: '查看字段 Hover', onClick: () => { void editor.triggerHover({ line: 1, column: 6 }).then(hover => { status.text = hover?.documentation ?? '当前位置没有 Hover 信息' }) } }))  actions.addChild(new RenderButton({ label: '格式化', onClick: () => { void editor.formatDocument().then(changed => { status.text = changed ? '格式化结果已应用,可使用撤销恢复。' : '文档已经是格式化状态。' }) } }))   const panel = new RenderStackPanel({ orientation: 'vertical', spacing: 10, crossAxisAlignment: 'stretch' })  panel.addChild(new RenderPageHeader({ title: 'CodeEditor 临床规则 DSL', description: '编辑器负责输入和绘制,LanguageAdapter 提供诊断、补全、Hover、格式化与业务语义。' }))  panel.addChild(actions)  panel.addChild(status)  panel.addChild(editor, 1)  panel.padding = 14  return panel}